Entity: an equipped item keeps the hardpoint it occupies

The placement rule (HardpointAt) already finds the one hardpoint an item lies
in at equip; TryEquip threw that answer away and eighteen readers recomputed it
from the item's origin cell, which need not lie in the hardpoint (Soul's
scenarios batch-4 P30). EquippedItem.Hardpoint now carries the answer, null for
Tool gear and the hull, and every origin-cell lookup reads it instead:
FireControl.ArcFor, the eleven weapon managers, EntityInstance, ShipInstance
and ActionGameManager's articulation grouping. Entity.Hardpoints[,] stays the
per-cell map for armour and display.

TryFindSpace's hardpoint search tries every origin the fit rule can accept,
including ones up and left of the hardpoint, so a design whose shape lacks its
origin cell is found wherever ItemFits would place it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Meta Vens 2026-10-03 14:57:27 +02:00
commit 5ea59ac6b5
15 changed files with 45 additions and 33 deletions

View file

@ -1053,12 +1053,12 @@ public class ActionGameManager : MonoBehaviour
_articulationGroups = CurrentEntity.Equipment
.Where(item => item.Behaviors.Any(x => x.Data is WeaponData && !(x.Data is LauncherData)))
.GroupBy(item => ZoneRenderer.EntityInstances[CurrentEntity]
.GetBarrel(CurrentEntity.Hardpoints[item.Position.x, item.Position.y])
.GetBarrel(item.Hardpoint)
.GetComponentInParent<ArticulationPoint>()?.Group ?? -1)
.Select((group, index) => {
return (
group.Select(item => CurrentEntity.Hardpoints[item.Position.x, item.Position.y]).ToArray(),
group.Select(item => ZoneRenderer.EntityInstances[CurrentEntity].GetBarrel(CurrentEntity.Hardpoints[item.Position.x, item.Position.y])).ToArray(),
group.Select(item => item.Hardpoint).ToArray(),
group.Select(item => ZoneRenderer.EntityInstances[CurrentEntity].GetBarrel(item.Hardpoint)).ToArray(),
Crosshairs[index]
);
}).ToArray();

View file

@ -242,7 +242,7 @@ public class EntityInstance : MonoBehaviour
}
}
var hp = Entity.Hardpoints[item.Position.x, item.Position.y];
var hp = item.Hardpoint;
if (hp != null && item.Data.SoundBank != 0)
{
var hardpointTransform = EquipmentHardpoints.FirstOrDefault(x => x.name == hp.Transform);
@ -257,7 +257,7 @@ public class EntityInstance : MonoBehaviour
BarrelIndices = new Dictionary<HardpointData, int>();
foreach (var radiator in entity.GetBehaviors<Radiator>())
{
var hp = Entity.Hardpoints[radiator.Item.Position.x, radiator.Item.Position.y];
var hp = radiator.Item.Hardpoint;
if (hp != null && hp.Type == HardpointType.Radiator)
{
var mesh = RadiatorHardpoints.FirstOrDefault(x => x.name == hp.Transform);

View file

@ -67,7 +67,7 @@ public class ShipInstance : EntityInstance
var particles = Instantiate(EngineAssets.Load<ParticleSystem>(effectData.ParticlesPrefab), transform, false);
var particlesShape = particles.shape;
var thrusterHardpoint = ThrusterHardpoints
.FirstOrDefault(t => t.name == ship.Hardpoints[thruster.Item.Position.x, thruster.Item.Position.y].Transform);
.FirstOrDefault(t => t.name == thruster.Item.Hardpoint.Transform);
particlesShape.meshRenderer = thrusterHardpoint?.Emitter;
// if (!string.IsNullOrEmpty(thruster.Item.Data.SoundEffectTrigger) && thrusterHardpoint != null)
// {

View file

@ -11,7 +11,7 @@ public class ChargeEffectManager : MonoBehaviour
public void StartCharging(ChargedWeapon weapon, EquippedItem item, EntityInstance source)
{
var effect = EffectPrototype.Instantiate<WeaponChargeEffect>();
var hp = source.Entity.Hardpoints[item.Position.x, item.Position.y];
var hp = item.Hardpoint;
var barrel = source.GetBarrel(hp);
var t = effect.transform;
t.SetParent(barrel);

View file

@ -12,7 +12,7 @@ public class ConstantLaserManager : ConstantWeaponEffectManager
{
var p = LaserPrototype.Instantiate<ConstantLaser>();
p.SourceEntity = source.Entity;
var hp = source.Entity.Hardpoints[item.Position.x, item.Position.y];
var hp = item.Hardpoint;
var barrel = source.GetBarrel(hp);
p.Range = item.Evaluate(data.Range);
var t = p.transform;

View file

@ -13,7 +13,7 @@ public class ConstantLightningManager : ConstantWeaponEffectManager
{
var p = LightningPrototype.Instantiate<ConstantLightning>();
p.Source = source;
var hp = source.Entity.Hardpoints[item.Position.x, item.Position.y];
var hp = item.Hardpoint;
var barrel = source.GetBarrel(hp);
p.Barrel = barrel;
p.Range = item.Evaluate(data.Range);

View file

@ -13,7 +13,7 @@ public class ConstantParticleWeaponManager : ConstantWeaponEffectManager
var p = WeaponPrototype.Instantiate<ConstantParticleWeapon>();
p.Source = source;
p.Target = target;
var hp = source.Entity.Hardpoints[item.Position.x, item.Position.y];
var hp = item.Hardpoint;
var barrel = source.GetBarrel(hp);
var t = p.transform;
t.SetParent(barrel);

View file

@ -45,7 +45,7 @@ public class GuidedProjectileManager : InstantWeaponEffectManager
if (target != null) p.Target = target.transform;
else p.TargetPosition = () => burst;
p.Frequency = launcher.DodgeFrequency;
var hp = source.Entity.Hardpoints[item.Position.x, item.Position.y];
var hp = item.Hardpoint;
var barrel = source.GetBarrel(hp);
p.StartPosition = (p.transform.position = barrel.position).ToCultMath();
p.Range = weapon.Range;
@ -66,7 +66,7 @@ public class GuidedProjectileManager : InstantWeaponEffectManager
p.Source = source.transform;
p.SourceEntity = source.Entity;
p.Frequency = guidance.DodgeFrequency;
var hp = source.Entity.Hardpoints[item.Position.x, item.Position.y];
var hp = item.Hardpoint;
var barrel = source.GetBarrel(hp);
p.StartPosition = (p.transform.position = barrel.position).ToCultMath();
p.Range = weapon.Range;

View file

@ -7,7 +7,7 @@ public class HitscanManager : InstantWeaponEffectManager
{
var p = Prototype.Instantiate<HitscanEffect>();
p.SourceEntity = source.Entity;
var hp = source.Entity.Hardpoints[item.Position.x, item.Position.y];
var hp = item.Hardpoint;
var barrel = source.GetBarrel(hp);
var t = p.transform;
t.SetParent(barrel, false);

View file

@ -9,7 +9,7 @@ public class LaserManager : InstantWeaponEffectManager
public override void Fire(InstantWeapon weapon, EquippedItem item, EntityInstance source, EntityInstance target, int shotId)
{
var p = ProjectilePrototype.Instantiate<Laser>();
var hp = source.Entity.Hardpoints[item.Position.x, item.Position.y];
var hp = item.Hardpoint;
var barrel = source.GetBarrel(hp);
var t = p.transform;
t.SetParent(barrel);

View file

@ -9,7 +9,7 @@ public class LightningGunManager : InstantWeaponEffectManager
public override void Fire(InstantWeapon weapon, EquippedItem item, EntityInstance source, EntityInstance target, int shotId)
{
var p = Prototype.Instantiate<Lightning>();
var hp = source.Entity.Hardpoints[item.Position.x, item.Position.y];
var hp = item.Hardpoint;
var barrel = source.GetBarrel(hp);
p.ShotId = shotId;
p.Barrel = barrel;

View file

@ -13,7 +13,7 @@ public class MineManager : InstantWeaponEffectManager
public override void Fire(InstantWeapon weapon, EquippedItem item, EntityInstance source, EntityInstance target, int shotId)
{
var p = ProjectilePrototype.Instantiate<Mine>();
var hp = source.Entity.Hardpoints[item.Position.x, item.Position.y];
var hp = item.Hardpoint;
var barrel = source.GetBarrel(hp);
var angle = weapon.Spread / 2;
p.Source = source;

View file

@ -11,7 +11,7 @@ public class ProjectileManager : InstantWeaponEffectManager
public override void Fire(InstantWeapon weapon, EquippedItem item, EntityInstance source, EntityInstance target, int shotId)
{
var p = ProjectilePrototype.Instantiate<Projectile>();
var hp = source.Entity.Hardpoints[item.Position.x, item.Position.y];
var hp = item.Hardpoint;
var barrel = source.GetBarrel(hp);
var angle = weapon.Spread / 2;
p.ShotId = shotId;