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..8953db64c6 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 @@ -166,12 +167,8 @@ namespace OpenRA.Mods.Common.Effects if (info.ContrailLength > 0) contrail.Update(pos); - var cell = world.Map.CellContaining(pos); - var height = world.Map.DistanceAboveTerrain(pos); - - 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 + var shouldExplode = ticks++ >= length // Flight length reached/exceeded + || (info.Blockable && BlocksProjectiles.AnyBlockingActorAt(world, pos)); // Hit a wall or other blocking obstacle if (shouldExplode) Explode(world); diff --git a/OpenRA.Mods.Common/Effects/Missile.cs b/OpenRA.Mods.Common/Effects/Missile.cs index 8740be76d1..c82d959a6b 100644 --- a/OpenRA.Mods.Common/Effects/Missile.cs +++ b/OpenRA.Mods.Common/Effects/Missile.cs @@ -20,7 +20,7 @@ using OpenRA.Traits; namespace OpenRA.Mods.Common.Effects { - class MissileInfo : IProjectileInfo + public class MissileInfo : IProjectileInfo { public readonly string Image = null; [SequenceReference("Image")] public readonly string Sequence = "idle"; @@ -81,7 +81,7 @@ namespace OpenRA.Mods.Common.Effects public IEffect Create(ProjectileArgs args) { return new Missile(this, args); } } - class Missile : IEffect, ISync + public class Missile : IEffect, ISync { readonly MissileInfo info; readonly ProjectileArgs args; @@ -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 + || (info.Blockable && BlocksProjectiles.AnyBlockingActorAt(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 diff --git a/OpenRA.Mods.Common/Traits/BlocksProjectiles.cs b/OpenRA.Mods.Common/Traits/BlocksProjectiles.cs index c41398abd6..249b2e8ea7 100644 --- a/OpenRA.Mods.Common/Traits/BlocksProjectiles.cs +++ b/OpenRA.Mods.Common/Traits/BlocksProjectiles.cs @@ -15,6 +15,20 @@ 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) { } + + public static bool AnyBlockingActorAt(World world, WPos pos) + { + return world.ActorMap.GetUnitsAt(world.Map.CellContaining(pos)) + .Any(a => a.TraitsImplementing().Any(Exts.IsTraitEnabled)); + } + } }