diff --git a/OpenRA.Mods.Common/Effects/AreaBeam.cs b/OpenRA.Mods.Common/Effects/AreaBeam.cs index ec0ddfcadb..ad26a625dd 100644 --- a/OpenRA.Mods.Common/Effects/AreaBeam.cs +++ b/OpenRA.Mods.Common/Effects/AreaBeam.cs @@ -54,7 +54,7 @@ namespace OpenRA.Mods.Common.Effects public readonly bool Blockable = false; [Desc("Extra search radius beyond beam width. Required to ensure affecting actors with large health radius.")] - public readonly WDist TargetExtraSearchRadius = new WDist(2048); + public readonly WDist TargetExtraSearchRadius = new WDist(1536); [Desc("Should the beam be visuall rendered? False = Beam is invisible.")] public readonly bool RenderBeam = true; diff --git a/OpenRA.Mods.Common/Effects/Bullet.cs b/OpenRA.Mods.Common/Effects/Bullet.cs index 77efeafb56..f5dc31981d 100644 --- a/OpenRA.Mods.Common/Effects/Bullet.cs +++ b/OpenRA.Mods.Common/Effects/Bullet.cs @@ -50,6 +50,12 @@ namespace OpenRA.Mods.Common.Effects [Desc("Is this blocked by actors with BlocksProjectiles trait.")] public readonly bool Blockable = true; + [Desc("Width of projectile (used for finding blocking actors).")] + public readonly WDist Width = new WDist(1); + + [Desc("Extra search radius beyond path for blocking actors.")] + public readonly WDist TargetExtraSearchRadius = new WDist(1536); + [Desc("Arc in WAngles, two values indicate variable arc.")] public readonly WAngle[] Angle = { WAngle.Zero }; @@ -156,8 +162,19 @@ namespace OpenRA.Mods.Common.Effects if (anim != null) anim.Tick(); + var lastPos = pos; pos = WPos.LerpQuadratic(args.Source, target, angle, ticks, length); + // Check for walls or other blocking obstacles + var shouldExplode = false; + WPos blockedPos; + if (info.Blockable && BlocksProjectiles.AnyBlockingActorsBetween(world, lastPos, pos, info.Width, + info.TargetExtraSearchRadius, out blockedPos)) + { + pos = blockedPos; + shouldExplode = true; + } + if (!string.IsNullOrEmpty(info.Trail) && --smokeTicks < 0) { var delayedPos = WPos.LerpQuadratic(args.Source, target, angle, ticks - info.TrailDelay, length); @@ -168,8 +185,8 @@ namespace OpenRA.Mods.Common.Effects if (info.ContrailLength > 0) contrail.Update(pos); - var shouldExplode = ticks++ >= length // Flight length reached/exceeded - || (info.Blockable && BlocksProjectiles.AnyBlockingActorAt(world, pos)); // Hit a wall or other blocking obstacle + // Flight length reached / exceeded + shouldExplode |= ticks++ >= length; if (shouldExplode) Explode(world); diff --git a/OpenRA.Mods.Common/Effects/Missile.cs b/OpenRA.Mods.Common/Effects/Missile.cs index 262e5e100a..edb8a42b73 100644 --- a/OpenRA.Mods.Common/Effects/Missile.cs +++ b/OpenRA.Mods.Common/Effects/Missile.cs @@ -58,6 +58,12 @@ namespace OpenRA.Mods.Common.Effects [Desc("Is the missile blocked by actors with BlocksProjectiles: trait.")] public readonly bool Blockable = true; + [Desc("Width of projectile (used for finding blocking actors).")] + public readonly WDist Width = new WDist(1); + + [Desc("Extra search radius beyond path for blocking actors.")] + public readonly WDist TargetExtraSearchRadius = new WDist(1536); + [Desc("Maximum offset at the maximum range")] public readonly WDist Inaccuracy = WDist.Zero; @@ -773,8 +779,19 @@ namespace OpenRA.Mods.Common.Effects renderFacing = WAngle.ArcTan(move.Z - move.Y, move.X).Angle / 4 - 64; // Move the missile + var lastPos = pos; pos += move; + // Check for walls or other blocking obstacles + var shouldExplode = false; + WPos blockedPos; + if (info.Blockable && BlocksProjectiles.AnyBlockingActorsBetween(world, lastPos, pos, info.Width, + info.TargetExtraSearchRadius, out blockedPos)) + { + pos = blockedPos; + shouldExplode = true; + } + // Create the smoke trail effect if (!string.IsNullOrEmpty(info.TrailImage) && --ticksToNextSmoke < 0 && (state != States.Freefall || info.TrailWhenDeactivated)) { @@ -786,14 +803,10 @@ namespace OpenRA.Mods.Common.Effects contrail.Update(pos); var cell = world.Map.CellContaining(pos); - - // NOTE: High speeds might cause the missile to miss the target or fly through obstacles - // In that case, big moves should probably be decomposed into multiple smaller ones with hit checks var height = world.Map.DistanceAboveTerrain(pos); - var shouldExplode = (height.Length < 0) // Hit the ground - || (relTarDist < info.CloseEnough.Length) // Within range + shouldExplode |= height.Length < 0 // Hit the ground + || relTarDist < info.CloseEnough.Length // Within range || (info.ExplodeWhenEmpty && info.RangeLimit != 0 && ticks > info.RangeLimit) // Ran out of fuel - || (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 || (height.Length < info.AirburstAltitude.Length && relTarHorDist < info.CloseEnough.Length); // Airburst diff --git a/OpenRA.Mods.Common/Lint/CheckTargetHealthRadius.cs b/OpenRA.Mods.Common/Lint/CheckTargetHealthRadius.cs index 15eb1232b7..9ac4f990e5 100644 --- a/OpenRA.Mods.Common/Lint/CheckTargetHealthRadius.cs +++ b/OpenRA.Mods.Common/Lint/CheckTargetHealthRadius.cs @@ -10,6 +10,8 @@ using System; using System.Linq; +using OpenRA.GameRules; +using OpenRA.Mods.Common.Effects; using OpenRA.Mods.Common.Traits; using OpenRA.Mods.Common.Warheads; using OpenRA.Traits; @@ -48,6 +50,21 @@ namespace OpenRA.Mods.Common.Lint emitError("Actor type `{0}` has a health radius exceeding the victim scan radius of a warhead on `{1}`!" .F(actorInfo.Key, weaponInfo.Key)); } + + var bullet = weaponInfo.Value.Projectile as BulletInfo; + var missile = weaponInfo.Value.Projectile as MissileInfo; + var areabeam = weaponInfo.Value.Projectile as AreaBeamInfo; + + if (bullet == null && missile == null && areabeam == null) + continue; + + var targetExtraSearchRadius = bullet != null ? bullet.TargetExtraSearchRadius : + missile != null ? missile.TargetExtraSearchRadius : + areabeam != null ? areabeam.TargetExtraSearchRadius : WDist.Zero; + + if (healthTraits.Where(x => x.Shape.OuterRadius.Length > targetExtraSearchRadius.Length).Any()) + emitError("Actor type `{0}` has a health radius exceeding the victim scan radius of the projectile on `{1}`!" + .F(actorInfo.Key, weaponInfo.Key)); } } } diff --git a/mods/cnc/rules/civilian.yaml b/mods/cnc/rules/civilian.yaml index dbe3303e1f..5c4edd2b49 100644 --- a/mods/cnc/rules/civilian.yaml +++ b/mods/cnc/rules/civilian.yaml @@ -276,8 +276,6 @@ ARCO.Husk: BARB: Inherits: ^Wall - Health: - HP: 100 Armor: Type: Light Tooltip: @@ -292,8 +290,6 @@ BARB: WOOD: Inherits: ^Wall - Health: - HP: 100 Armor: Type: Wood Tooltip: diff --git a/mods/cnc/rules/defaults.yaml b/mods/cnc/rules/defaults.yaml index 1b2375ccc2..df5c3c6dbb 100644 --- a/mods/cnc/rules/defaults.yaml +++ b/mods/cnc/rules/defaults.yaml @@ -579,6 +579,11 @@ Guardable: FrozenUnderFog: ScriptTriggers: + Health: + HP: 100 + Shape: Rectangle + TopLeft: -512, -512 + BottomRight: 512, 512 ^Tree: Inherits@1: ^SpriteActor diff --git a/mods/cnc/rules/structures.yaml b/mods/cnc/rules/structures.yaml index 9bed45effe..f8fb9ee6c0 100644 --- a/mods/cnc/rules/structures.yaml +++ b/mods/cnc/rules/structures.yaml @@ -855,8 +855,6 @@ SBAG: BuildPaletteOrder: 20 Prerequisites: fact Queue: Defence.GDI - Health: - HP: 100 Armor: Type: Light LineBuild: @@ -880,8 +878,6 @@ CYCL: BuildPaletteOrder: 20 Prerequisites: fact Queue: Defence.Nod - Health: - HP: 100 Armor: Type: Light LineBuild: diff --git a/mods/d2k/rules/structures.yaml b/mods/d2k/rules/structures.yaml index dc37d9ae9a..8a1e8dfd02 100644 --- a/mods/d2k/rules/structures.yaml +++ b/mods/d2k/rules/structures.yaml @@ -613,6 +613,9 @@ wall: TerrainTypes: Rock, Concrete Health: HP: 2000 + Shape: Rectangle + TopLeft: -512, -512 + BottomRight: 512, 512 Armor: Type: none RevealsShroud: diff --git a/mods/ra/rules/defaults.yaml b/mods/ra/rules/defaults.yaml index 2e9849ad09..0769f52f55 100644 --- a/mods/ra/rules/defaults.yaml +++ b/mods/ra/rules/defaults.yaml @@ -501,6 +501,11 @@ Guardable: FrozenUnderFog: GpsRemoveFrozenActor: + Health: + HP: 100 + Shape: Rectangle + TopLeft: -512, -512 + BottomRight: 512, 512 ^TechBuilding: Inherits: ^BasicBuilding diff --git a/mods/ra/rules/structures.yaml b/mods/ra/rules/structures.yaml index 88e52554ee..121f83cc93 100644 --- a/mods/ra/rules/structures.yaml +++ b/mods/ra/rules/structures.yaml @@ -1664,8 +1664,6 @@ CYCL: Inherits: ^Wall Tooltip: Name: Chain-Link Barrier - Health: - HP: 100 Armor: Type: Wood LineBuild: @@ -1679,8 +1677,6 @@ BARB: Inherits: ^Wall Tooltip: Name: Barbed-Wire Fence - Health: - HP: 100 Armor: Type: Wood LineBuild: @@ -1694,8 +1690,6 @@ WOOD: Inherits: ^Wall Tooltip: Name: Wooden Fence - Health: - HP: 100 Armor: Type: Wood LineBuild: diff --git a/mods/ts/rules/defaults.yaml b/mods/ts/rules/defaults.yaml index 9161b90d82..32ed1eebf9 100644 --- a/mods/ts/rules/defaults.yaml +++ b/mods/ts/rules/defaults.yaml @@ -216,6 +216,9 @@ InitialDelay: 0 CloakDelay: 90 IsPlayerPalette: true + Health: + Shape: Circle + Radius: 363 ^BuildingPlug: AlwaysVisible: