diff --git a/OpenRA.Game/Traits/TraitsInterfaces.cs b/OpenRA.Game/Traits/TraitsInterfaces.cs index f5ec0eb634..a0fb5eeae0 100644 --- a/OpenRA.Game/Traits/TraitsInterfaces.cs +++ b/OpenRA.Game/Traits/TraitsInterfaces.cs @@ -59,11 +59,13 @@ namespace OpenRA.Traits { None = 0, Ground = 1, - Water = 2, - Air = 4, - GroundHit = 8, - WaterHit = 16, - AirHit = 32 + GroundHit = 2, + Water = 4, + WaterHit = 8, + Air = 16, + AirHit = 32, + TargetTerrain = 64, + TargetHit = 128 } public class AttackInfo diff --git a/OpenRA.Mods.Common/Warheads/CreateEffectWarhead.cs b/OpenRA.Mods.Common/Warheads/CreateEffectWarhead.cs index aed6e0510d..63d2401d7f 100644 --- a/OpenRA.Mods.Common/Warheads/CreateEffectWarhead.cs +++ b/OpenRA.Mods.Common/Warheads/CreateEffectWarhead.cs @@ -35,36 +35,44 @@ namespace OpenRA.Mods.Common.Warheads [Desc("What impact types should this effect NOT apply to.", "Overrides ValidImpactTypes.")] public readonly ImpactType InvalidImpactTypes = ImpactType.None; - public static ImpactType GetImpactType(World world, CPos cell, WPos pos) + public ImpactType GetImpactType(World world, CPos cell, WPos pos, Actor firedBy) { // Missiles need a margin because they sometimes explode a little above ground // due to their explosion check triggering slightly too early (because of CloseEnough). // TODO: Base ImpactType on target altitude instead of explosion altitude. var airMargin = new WDist(128); - var dat = world.Map.DistanceAboveTerrain(pos); - var isAir = dat.Length > airMargin.Length; - var isWater = dat.Length <= 0 && world.Map.GetTerrainInfo(cell).IsWater; - var isDirectHit = GetDirectHit(world, cell, pos); + // Matching target actor + if (ValidImpactTypes.HasFlag(ImpactType.TargetHit) && GetDirectHit(world, cell, pos, firedBy, true)) + return ImpactType.TargetHit; - if (isAir && !isDirectHit) - return ImpactType.Air; - else if (isWater && !isDirectHit) - return ImpactType.Water; - else if (isAir && isDirectHit) - return ImpactType.AirHit; - else if (isWater && isDirectHit) - return ImpactType.WaterHit; - else if (isDirectHit) + var dat = world.Map.DistanceAboveTerrain(pos); + var isDirectHit = GetDirectHit(world, cell, pos, firedBy); + + if (dat.Length > airMargin.Length) + return isDirectHit ? ImpactType.AirHit : ImpactType.Air; + + if (dat.Length <= 0 && world.Map.GetTerrainInfo(cell).IsWater) + return isDirectHit ? ImpactType.WaterHit : ImpactType.Water; + + if (isDirectHit) return ImpactType.GroundHit; + // Matching target terrain + if (ValidImpactTypes.HasFlag(ImpactType.TargetTerrain) + && IsValidTarget(world.Map.GetTerrainInfo(cell).TargetTypes)) + return ImpactType.TargetTerrain; + return ImpactType.Ground; } - public static bool GetDirectHit(World world, CPos cell, WPos pos) + public bool GetDirectHit(World world, CPos cell, WPos pos, Actor firedBy, bool checkTargetType = false) { foreach (var unit in world.ActorMap.GetActorsAt(cell)) { + if (checkTargetType && !IsValidAgainst(unit, firedBy)) + continue; + var healthInfo = unit.Info.TraitInfoOrDefault(); if (healthInfo == null) continue; @@ -105,7 +113,7 @@ namespace OpenRA.Mods.Common.Warheads if (!world.Map.Contains(targetTile)) return false; - var impactType = GetImpactType(world, targetTile, pos); + var impactType = GetImpactType(world, targetTile, pos, firedBy); if (!ValidImpactTypes.HasFlag(impactType) || InvalidImpactTypes.HasFlag(impactType)) return false;