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:
parent
2d39c83504
commit
5ea59ac6b5
15 changed files with 45 additions and 33 deletions
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
// {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -601,7 +601,7 @@ public abstract class Entity
|
|||
private void MapEntity()
|
||||
{
|
||||
var hullData = ItemManager.GetData(Hull) as HullData;
|
||||
EquippedHull = new EquippedItem(ItemManager, Hull, int2.zero, this);
|
||||
EquippedHull = new EquippedItem(ItemManager, Hull, int2.zero, this, null);
|
||||
Equipment.Add(EquippedHull);
|
||||
// A bare hull, one TryEquip never ran on, still updates: its ordered equipment is the hull alone.
|
||||
_orderedEquipment = Equipment.ToArray();
|
||||
|
|
@ -787,9 +787,11 @@ public abstract class Entity
|
|||
return item.EquippableItem;
|
||||
}
|
||||
|
||||
// Check whether the given item will fit when its origin is placed at the given coordinate
|
||||
private bool ItemFits(EquippableItemData itemData, HullData hullData, EquippableItem item, int2 hullCoord)
|
||||
// Check whether the given item will fit when its origin is placed at the given coordinate. For hardpoint gear,
|
||||
// hardpoint is the one hardpoint the item would occupy there (HardpointAt); Tool gear occupies none.
|
||||
private bool ItemFits(EquippableItemData itemData, HullData hullData, EquippableItem item, int2 hullCoord, out HardpointData hardpoint)
|
||||
{
|
||||
hardpoint = null;
|
||||
// Items without specific hardpoints on the ship can be freely rotated and placed anywhere
|
||||
if (itemData.HardpointType == HardpointType.Tool)
|
||||
{
|
||||
|
|
@ -806,7 +808,7 @@ public abstract class Entity
|
|||
}
|
||||
else
|
||||
{
|
||||
var hardpoint = HardpointAt(itemData, hullData, hullCoord);
|
||||
hardpoint = HardpointAt(itemData, hullData, hullCoord);
|
||||
if (hardpoint == null) return false;
|
||||
item.Rotation = hardpoint.Rotation;
|
||||
}
|
||||
|
|
@ -842,7 +844,7 @@ public abstract class Entity
|
|||
|
||||
var itemData = ItemManager.GetData(item);
|
||||
var hullData = ItemManager.GetData(Hull) as HullData;
|
||||
return ItemFits(itemData, hullData, item, hullCoord);
|
||||
return ItemFits(itemData, hullData, item, hullCoord, out _);
|
||||
}
|
||||
|
||||
public bool TryFindSpace(EquippableItem item, out int2 hullCoord)
|
||||
|
|
@ -862,7 +864,7 @@ public abstract class Entity
|
|||
{
|
||||
foreach (var hullCoord2 in hullData.InteriorCells.Coordinates)
|
||||
{
|
||||
if (ItemFits(itemData, hullData, item, hullCoord2))
|
||||
if (ItemFits(itemData, hullData, item, hullCoord2, out _))
|
||||
{
|
||||
hullCoord = hullCoord2;
|
||||
return true;
|
||||
|
|
@ -874,16 +876,21 @@ public abstract class Entity
|
|||
// Search the ship for an empty hardpoint that matches the type and shape of the item
|
||||
else
|
||||
{
|
||||
// Every offset within a hardpoint of the item's type, the same offsets the fit rule tries
|
||||
// Every origin the fit rule (HardpointData.TakesAt) can accept: the item, turned to the hardpoint's rotation,
|
||||
// may sit as far up and left as its own extent allows, so a design whose shape lacks its origin cell is
|
||||
// found wherever it fits, not only where its origin lies inside the hardpoint.
|
||||
foreach (var hardpoint in hullData.Hardpoints)
|
||||
{
|
||||
if(hardpoint.Type == itemData.HardpointType)
|
||||
{
|
||||
for (var x = 0; x < hardpoint.Shape.Width; x++)
|
||||
for (var y = 0; y < hardpoint.Shape.Height; y++)
|
||||
var turned = hardpoint.Rotation == ItemRotation.Clockwise || hardpoint.Rotation == ItemRotation.CounterClockwise
|
||||
? int2(itemData.Shape.Height, itemData.Shape.Width)
|
||||
: int2(itemData.Shape.Width, itemData.Shape.Height);
|
||||
for (var x = 1 - turned.x; x < hardpoint.Shape.Width; x++)
|
||||
for (var y = 1 - turned.y; y < hardpoint.Shape.Height; y++)
|
||||
{
|
||||
var hullCoord2 = hardpoint.Position + int2(x, y);
|
||||
if (ItemFits(itemData, hullData, item, hullCoord2))
|
||||
if (ItemFits(itemData, hullData, item, hullCoord2, out _))
|
||||
{
|
||||
hullCoord = hullCoord2;
|
||||
return true;
|
||||
|
|
@ -909,7 +916,7 @@ public abstract class Entity
|
|||
var itemData = ItemManager.GetData(item);
|
||||
var hullData = ItemManager.GetData(Hull) as HullData;
|
||||
|
||||
if (!ItemFits(itemData, hullData, item, hullCoord)) return false;
|
||||
if (!ItemFits(itemData, hullData, item, hullCoord, out var hardpoint)) return false;
|
||||
|
||||
EquippedItem equippedItem;
|
||||
if (itemData.HardpointType == HardpointType.Tool)
|
||||
|
|
@ -929,13 +936,13 @@ public abstract class Entity
|
|||
}
|
||||
else
|
||||
{
|
||||
equippedItem = new EquippedItem(ItemManager, item, hullCoord, this);
|
||||
equippedItem = new EquippedItem(ItemManager, item, hullCoord, this, null);
|
||||
Equipment.Add(equippedItem);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
equippedItem = new EquippedItem(ItemManager, item, hullCoord, this);
|
||||
equippedItem = new EquippedItem(ItemManager, item, hullCoord, this, hardpoint);
|
||||
Equipment.Add(equippedItem);
|
||||
}
|
||||
|
||||
|
|
@ -1358,6 +1365,10 @@ public class EquippedItem : IStatContext
|
|||
public float Wear { get; private set; }
|
||||
public Shape InsetShape { get; }
|
||||
public Entity Entity { get; }
|
||||
// The one hardpoint this item occupies, decided once at equip by the placement rule (Entity.HardpointAt);
|
||||
// null for Tool gear and the hull. The item's origin cell need not lie in it: Entity.Hardpoints[,] is a
|
||||
// per-cell map for armour and display, never an item lookup.
|
||||
public HardpointData Hardpoint { get; }
|
||||
public EquippableItemData Data { get; }
|
||||
public Lot Lot { get; }
|
||||
|
||||
|
|
@ -1454,11 +1465,12 @@ public class EquippedItem : IStatContext
|
|||
SetAudioParameter(metaObject.Id, v, true);
|
||||
}
|
||||
|
||||
public EquippedItem(ItemManager itemManager, EquippableItem item, int2 position, Entity entity)
|
||||
public EquippedItem(ItemManager itemManager, EquippableItem item, int2 position, Entity entity, HardpointData hardpoint)
|
||||
{
|
||||
ItemManager = itemManager;
|
||||
Data = ItemManager.GetData(item);
|
||||
Entity = entity;
|
||||
Hardpoint = hardpoint;
|
||||
EquippableItem = item;
|
||||
Lot = ItemManager.GetLot(item);
|
||||
Position = position;
|
||||
|
|
@ -1707,7 +1719,7 @@ public class EquippedCargoBay : EquippedItem
|
|||
}
|
||||
}
|
||||
|
||||
public EquippedCargoBay(ItemManager itemManager, EquippableItem item, int2 position, Entity entity, string name) : base(itemManager, item, position, entity)
|
||||
public EquippedCargoBay(ItemManager itemManager, EquippableItem item, int2 position, Entity entity, string name) : base(itemManager, item, position, entity, null)
|
||||
{
|
||||
Data = ItemManager.GetData(EquippableItem) as CargoBayData;
|
||||
Name = name;
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ public static class FireControl
|
|||
// GameplaySettings.FiringArc. Zero on the hardpoint means "use the default," not "no arc."
|
||||
public static float ArcFor(EquippedItem item)
|
||||
{
|
||||
var hardpoint = item.Entity.Hardpoints[item.Position.x, item.Position.y];
|
||||
var hardpoint = item.Hardpoint;
|
||||
var arc = hardpoint?.FiringArc ?? 0f;
|
||||
return arc > 0 ? arc : item.ItemManager.GameplaySettings.FiringArc;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue