Refactor CreateEffectWarhead ImpactTypes

Use target validity to simplify ImpactTypes.
This commit is contained in:
reaperrr
2017-06-23 20:35:25 +02:00
committed by abcdefg30
parent efd8a9c1cb
commit cf5abc68ad
2 changed files with 59 additions and 47 deletions

View File

@@ -38,11 +38,8 @@ namespace OpenRA.Mods.Common.Warheads
[Desc("List of sounds that can be played on impact.")] [Desc("List of sounds that can be played on impact.")]
public readonly string[] ImpactSounds = new string[0]; public readonly string[] ImpactSounds = new string[0];
[Desc("What impact types should this effect apply to.")] [Desc("Consider explosion above this altitude an air explosion.")]
public readonly ImpactType ValidImpactTypes = ImpactType.Ground | ImpactType.Water | ImpactType.Air | ImpactType.GroundHit | ImpactType.WaterHit | ImpactType.AirHit; public readonly WDist AirThreshold = new WDist(128);
[Desc("What impact types should this effect NOT apply to.", "Overrides ValidImpactTypes.")]
public readonly ImpactType InvalidImpactTypes = ImpactType.None;
[Desc("Scan radius for victims around impact. If set to a negative value (default), it will automatically scale to the largest health shape.", [Desc("Scan radius for victims around impact. If set to a negative value (default), it will automatically scale to the largest health shape.",
"Custom overrides should not be necessary under normal circumstances.")] "Custom overrides should not be necessary under normal circumstances.")]
@@ -54,51 +51,57 @@ namespace OpenRA.Mods.Common.Warheads
VictimScanRadius = Util.MinimumRequiredVictimScanRadius(rules); VictimScanRadius = Util.MinimumRequiredVictimScanRadius(rules);
} }
static readonly string[] TargetTypeAir = new string[] { "Air" };
public ImpactType GetImpactType(World world, CPos cell, WPos pos, Actor firedBy) 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);
// Matching target actor // Matching target actor
if (ValidImpactTypes.HasFlag(ImpactType.TargetHit) && GetDirectHit(world, cell, pos, firedBy, true)) if (VictimScanRadius > WDist.Zero)
{
var targetType = GetDirectHitTargetType(world, cell, pos, firedBy, true);
if (targetType == ImpactTargetType.ValidActor)
return ImpactType.TargetHit; return ImpactType.TargetHit;
if (targetType == ImpactTargetType.InvalidActor)
return ImpactType.None;
}
var dat = world.Map.DistanceAboveTerrain(pos); var dat = world.Map.DistanceAboveTerrain(pos);
var isDirectHit = GetDirectHit(world, cell, pos, firedBy); if (dat > AirThreshold)
return ImpactType.Air;
if (dat.Length > airMargin.Length)
return isDirectHit ? ImpactType.AirHit : ImpactType.Air;
if (dat.Length <= airMargin.Length && 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; return ImpactType.Ground;
} }
public bool GetDirectHit(World world, CPos cell, WPos pos, Actor firedBy, bool checkTargetType = false) public ImpactTargetType GetDirectHitTargetType(World world, CPos cell, WPos pos, Actor firedBy, bool checkTargetValidity = false)
{ {
foreach (var victim in world.FindActorsInCircle(pos, VictimScanRadius)) var victims = world.FindActorsInCircle(pos, VictimScanRadius);
var invalidHit = false;
foreach (var victim in victims)
{ {
if (checkTargetType && !IsValidAgainst(victim, firedBy)) if (!AffectsParent && victim == firedBy)
continue;
if (!victim.Info.HasTraitInfo<HealthInfo>())
continue; continue;
// If the impact position is within any HitShape, we have a direct hit // If the impact position is within any HitShape, we have a direct hit
var activeShapes = victim.TraitsImplementing<HitShape>().Where(Exts.IsTraitEnabled); var activeShapes = victim.TraitsImplementing<HitShape>().Where(Exts.IsTraitEnabled);
if (activeShapes.Any(i => i.Info.Type.DistanceFromEdge(pos, victim).Length <= 0)) var directHit = activeShapes.Any(i => i.Info.Type.DistanceFromEdge(pos, victim).Length <= 0);
return true;
// If the warhead landed outside the actor's hit-shape(s), we need to skip the rest so it won't be considered an invalidHit
if (!directHit)
continue;
if (!checkTargetValidity || IsValidAgainst(victim, firedBy))
return ImpactTargetType.ValidActor;
// If we got here, it must be an invalid target
invalidHit = true;
} }
return false; // If there was at least a single direct hit, but none on valid target(s), we return InvalidActor
return invalidHit ? ImpactTargetType.InvalidActor : ImpactTargetType.NoActor;
} }
public override void DoImpact(Target target, Actor firedBy, IEnumerable<int> damageModifiers) public override void DoImpact(Target target, Actor firedBy, IEnumerable<int> damageModifiers)
@@ -143,10 +146,18 @@ namespace OpenRA.Mods.Common.Warheads
return false; return false;
var impactType = GetImpactType(world, targetTile, pos, firedBy); var impactType = GetImpactType(world, targetTile, pos, firedBy);
if (!ValidImpactTypes.HasFlag(impactType) || InvalidImpactTypes.HasFlag(impactType)) switch (impactType)
return false; {
case ImpactType.TargetHit:
return true; return true;
case ImpactType.Air:
return IsValidTarget(TargetTypeAir);
case ImpactType.Ground:
var tileInfo = world.Map.GetTerrainInfo(targetTile);
return IsValidTarget(tileInfo.TargetTypes);
default:
return false;
}
} }
} }
} }

View File

@@ -16,18 +16,19 @@ using OpenRA.Traits;
namespace OpenRA.Mods.Common.Warheads namespace OpenRA.Mods.Common.Warheads
{ {
[Flags]
public enum ImpactType public enum ImpactType
{ {
None = 0, None,
Ground = 1, Ground,
GroundHit = 2, Air,
Water = 4, TargetHit
WaterHit = 8, }
Air = 16,
AirHit = 32, public enum ImpactTargetType
TargetTerrain = 64, {
TargetHit = 128 NoActor,
ValidActor,
InvalidActor
} }
[Desc("Base warhead class. This can be used to derive other warheads from.")] [Desc("Base warhead class. This can be used to derive other warheads from.")]