diff --git a/Assets/Scripts/Gameplay/ActionGameManager.cs b/Assets/Scripts/Gameplay/ActionGameManager.cs index 1576e88b9..c1ee9cac4 100644 --- a/Assets/Scripts/Gameplay/ActionGameManager.cs +++ b/Assets/Scripts/Gameplay/ActionGameManager.cs @@ -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()?.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(); diff --git a/Assets/Scripts/Gameplay/EntityInstance.cs b/Assets/Scripts/Gameplay/EntityInstance.cs index f3d977c8c..40505efa3 100644 --- a/Assets/Scripts/Gameplay/EntityInstance.cs +++ b/Assets/Scripts/Gameplay/EntityInstance.cs @@ -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(); foreach (var radiator in entity.GetBehaviors()) { - 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); diff --git a/Assets/Scripts/Gameplay/ShipInstance.cs b/Assets/Scripts/Gameplay/ShipInstance.cs index 8a0b22b6e..a81668af4 100644 --- a/Assets/Scripts/Gameplay/ShipInstance.cs +++ b/Assets/Scripts/Gameplay/ShipInstance.cs @@ -67,7 +67,7 @@ public class ShipInstance : EntityInstance var particles = Instantiate(EngineAssets.Load(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) // { diff --git a/Assets/Scripts/Gameplay/Weapons/ChargeEffectManager.cs b/Assets/Scripts/Gameplay/Weapons/ChargeEffectManager.cs index f7aae8368..b7f8a2118 100644 --- a/Assets/Scripts/Gameplay/Weapons/ChargeEffectManager.cs +++ b/Assets/Scripts/Gameplay/Weapons/ChargeEffectManager.cs @@ -11,7 +11,7 @@ public class ChargeEffectManager : MonoBehaviour public void StartCharging(ChargedWeapon weapon, EquippedItem item, EntityInstance source) { var effect = EffectPrototype.Instantiate(); - 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); diff --git a/Assets/Scripts/Gameplay/Weapons/ConstantLaserManager.cs b/Assets/Scripts/Gameplay/Weapons/ConstantLaserManager.cs index 039e9344b..f4b860278 100644 --- a/Assets/Scripts/Gameplay/Weapons/ConstantLaserManager.cs +++ b/Assets/Scripts/Gameplay/Weapons/ConstantLaserManager.cs @@ -12,7 +12,7 @@ public class ConstantLaserManager : ConstantWeaponEffectManager { var p = LaserPrototype.Instantiate(); 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; diff --git a/Assets/Scripts/Gameplay/Weapons/ConstantLightningManager.cs b/Assets/Scripts/Gameplay/Weapons/ConstantLightningManager.cs index 111df4433..9c948172b 100644 --- a/Assets/Scripts/Gameplay/Weapons/ConstantLightningManager.cs +++ b/Assets/Scripts/Gameplay/Weapons/ConstantLightningManager.cs @@ -13,7 +13,7 @@ public class ConstantLightningManager : ConstantWeaponEffectManager { var p = LightningPrototype.Instantiate(); 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); diff --git a/Assets/Scripts/Gameplay/Weapons/ConstantParticleWeaponManager.cs b/Assets/Scripts/Gameplay/Weapons/ConstantParticleWeaponManager.cs index 8b0095975..2fbd177d6 100644 --- a/Assets/Scripts/Gameplay/Weapons/ConstantParticleWeaponManager.cs +++ b/Assets/Scripts/Gameplay/Weapons/ConstantParticleWeaponManager.cs @@ -13,7 +13,7 @@ public class ConstantParticleWeaponManager : ConstantWeaponEffectManager var p = WeaponPrototype.Instantiate(); 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); diff --git a/Assets/Scripts/Gameplay/Weapons/GuidedProjectileManager.cs b/Assets/Scripts/Gameplay/Weapons/GuidedProjectileManager.cs index e5eb74b79..a3302a93e 100644 --- a/Assets/Scripts/Gameplay/Weapons/GuidedProjectileManager.cs +++ b/Assets/Scripts/Gameplay/Weapons/GuidedProjectileManager.cs @@ -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; diff --git a/Assets/Scripts/Gameplay/Weapons/HitscanManager.cs b/Assets/Scripts/Gameplay/Weapons/HitscanManager.cs index 5075c3344..ada88e1f3 100644 --- a/Assets/Scripts/Gameplay/Weapons/HitscanManager.cs +++ b/Assets/Scripts/Gameplay/Weapons/HitscanManager.cs @@ -7,7 +7,7 @@ public class HitscanManager : InstantWeaponEffectManager { var p = Prototype.Instantiate(); 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); diff --git a/Assets/Scripts/Gameplay/Weapons/LaserManager.cs b/Assets/Scripts/Gameplay/Weapons/LaserManager.cs index de70054ac..9af0f4b99 100644 --- a/Assets/Scripts/Gameplay/Weapons/LaserManager.cs +++ b/Assets/Scripts/Gameplay/Weapons/LaserManager.cs @@ -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(); - 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); diff --git a/Assets/Scripts/Gameplay/Weapons/LightningGunManager.cs b/Assets/Scripts/Gameplay/Weapons/LightningGunManager.cs index 24689ee8f..eff757682 100644 --- a/Assets/Scripts/Gameplay/Weapons/LightningGunManager.cs +++ b/Assets/Scripts/Gameplay/Weapons/LightningGunManager.cs @@ -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(); - 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; diff --git a/Assets/Scripts/Gameplay/Weapons/MineManager.cs b/Assets/Scripts/Gameplay/Weapons/MineManager.cs index 303fab395..0e9347e28 100644 --- a/Assets/Scripts/Gameplay/Weapons/MineManager.cs +++ b/Assets/Scripts/Gameplay/Weapons/MineManager.cs @@ -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(); - 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; diff --git a/Assets/Scripts/Gameplay/Weapons/ProjectileManager.cs b/Assets/Scripts/Gameplay/Weapons/ProjectileManager.cs index c9fc2e13f..56cfdcf80 100644 --- a/Assets/Scripts/Gameplay/Weapons/ProjectileManager.cs +++ b/Assets/Scripts/Gameplay/Weapons/ProjectileManager.cs @@ -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(); - 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; diff --git a/Assets/Scripts/ServerShared/Entity.cs b/Assets/Scripts/ServerShared/Entity.cs index d0641b695..aeeee7efc 100644 --- a/Assets/Scripts/ServerShared/Entity.cs +++ b/Assets/Scripts/ServerShared/Entity.cs @@ -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; diff --git a/Assets/Scripts/ServerShared/FireControl.cs b/Assets/Scripts/ServerShared/FireControl.cs index 06c9d3ca5..7a3586803 100644 --- a/Assets/Scripts/ServerShared/FireControl.cs +++ b/Assets/Scripts/ServerShared/FireControl.cs @@ -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; }