diff --git a/OpenRA.Game/Traits/TraitsInterfaces.cs b/OpenRA.Game/Traits/TraitsInterfaces.cs index 6e2278eb8b..96d4a0a8c5 100644 --- a/OpenRA.Game/Traits/TraitsInterfaces.cs +++ b/OpenRA.Game/Traits/TraitsInterfaces.cs @@ -299,8 +299,6 @@ namespace OpenRA.Traits public interface INotifyBecomingIdle { void OnBecomingIdle(Actor self); } public interface INotifyIdle { void TickIdle(Actor self); } - public interface IBlocksProjectilesInfo : ITraitInfo { } - public interface IBlocksProjectiles { } public interface IRenderInfantrySequenceModifier { bool IsModifyingSequence { get; } diff --git a/OpenRA.Mods.Common/Effects/Bullet.cs b/OpenRA.Mods.Common/Effects/Bullet.cs index 4adc33154f..aa8a3be3a3 100644 --- a/OpenRA.Mods.Common/Effects/Bullet.cs +++ b/OpenRA.Mods.Common/Effects/Bullet.cs @@ -16,6 +16,7 @@ using OpenRA.Effects; using OpenRA.GameRules; using OpenRA.Graphics; using OpenRA.Mods.Common.Graphics; +using OpenRA.Mods.Common.Traits; using OpenRA.Traits; namespace OpenRA.Mods.Common.Effects @@ -171,7 +172,7 @@ namespace OpenRA.Mods.Common.Effects var shouldExplode = height.Length <= 0 // Hit the ground || ticks++ >= length // Flight length reached/exceeded - || (info.Blockable && world.ActorMap.GetUnitsAt(cell).Any(a => a.Info.HasTraitInfo())); // Hit a wall or other blocking obstacle + || BlockedByActor(world, pos); // Hit a wall or other blocking obstacle if (shouldExplode) Explode(world); @@ -211,5 +212,11 @@ namespace OpenRA.Mods.Common.Effects args.Weapon.Impact(Target.FromPos(pos), args.SourceActor, args.DamageModifiers); } + + bool BlockedByActor(World world, WPos pos) + { + return info.Blockable && world.ActorMap.GetUnitsAt(world.Map.CellContaining(pos)) + .Any(a => a.TraitsImplementing().Any(Exts.IsTraitEnabled)); + } } } diff --git a/OpenRA.Mods.Common/Effects/Missile.cs b/OpenRA.Mods.Common/Effects/Missile.cs index 8740be76d1..1695636492 100644 --- a/OpenRA.Mods.Common/Effects/Missile.cs +++ b/OpenRA.Mods.Common/Effects/Missile.cs @@ -201,7 +201,7 @@ namespace OpenRA.Mods.Common.Effects var shouldExplode = (pos.Z < 0) // Hit the ground || (dist.LengthSquared < info.CloseEnough.LengthSquared) // Within range || (info.RangeLimit != 0 && ticks > info.RangeLimit) // Ran out of fuel - || (info.Blockable && world.ActorMap.GetUnitsAt(cell).Any(a => a.Info.HasTraitInfo())) // Hit a wall or other blocking obstacle + || BlockedByActor(world, pos) // Hit a wall or other blocking obstacle || !world.Map.Contains(cell) // This also avoids an IndexOutOfRangeException in GetTerrainInfo below. || (!string.IsNullOrEmpty(info.BoundToTerrainType) && world.Map.GetTerrainInfo(cell).Type != info.BoundToTerrainType); // Hit incompatible terrain @@ -223,6 +223,12 @@ namespace OpenRA.Mods.Common.Effects args.Weapon.Impact(Target.FromPos(pos), args.SourceActor, args.DamageModifiers); } + bool BlockedByActor(World world, WPos pos) + { + return info.Blockable && world.ActorMap.GetUnitsAt(world.Map.CellContaining(pos)) + .Any(a => a.TraitsImplementing().Any(Exts.IsTraitEnabled)); + } + public IEnumerable Render(WorldRenderer wr) { if (info.ContrailLength > 0) diff --git a/OpenRA.Mods.Common/Traits/BlocksProjectiles.cs b/OpenRA.Mods.Common/Traits/BlocksProjectiles.cs index c41398abd6..ac495d3179 100644 --- a/OpenRA.Mods.Common/Traits/BlocksProjectiles.cs +++ b/OpenRA.Mods.Common/Traits/BlocksProjectiles.cs @@ -15,6 +15,14 @@ namespace OpenRA.Mods.Common.Traits { // TODO: Add functionality like a customizable Height that is compared to projectile altitude [Desc("This actor blocks bullets and missiles with 'Blockable' property.")] - public class BlocksProjectilesInfo : TraitInfo, IBlocksProjectilesInfo { } - public class BlocksProjectiles : IBlocksProjectiles { } + public class BlocksProjectilesInfo : UpgradableTraitInfo + { + public override object Create(ActorInitializer init) { return new BlocksProjectiles(init.Self, this); } + } + + public class BlocksProjectiles : UpgradableTrait + { + public BlocksProjectiles(Actor self, BlocksProjectilesInfo info) + : base(info) { } + } }