Simplify CreateEffectWarhead code

Simplified and streamlined code,
based on past feedback and suggestions.

Note: The new methods will move to
Warhead later, once they're used by more
than one warhead.
This commit is contained in:
reaperrr
2019-06-30 16:59:43 +02:00
committed by teinarss
parent e0d53126d6
commit 4505053618
2 changed files with 43 additions and 69 deletions

View File

@@ -48,55 +48,43 @@ namespace OpenRA.Mods.Common.Warheads
static readonly BitSet<TargetableType> TargetTypeAir = new BitSet<TargetableType>("Air");
public ImpactType GetImpactType(World world, CPos cell, WPos pos, Actor firedBy)
/// <summary>Checks if there are any actors at impact position and if the warhead is valid against any of them.</summary>
ImpactActorType ActorTypeAtImpact(World world, WPos pos, Actor firedBy)
{
// Matching target actor
if (ImpactActors)
{
var targetType = GetDirectHitTargetType(world, cell, pos, firedBy, true);
if (targetType == ImpactTargetType.ValidActor)
return ImpactType.TargetHit;
if (targetType == ImpactTargetType.InvalidActor)
return ImpactType.None;
}
var anyInvalidActor = false;
var dat = world.Map.DistanceAboveTerrain(pos);
if (dat > AirThreshold)
return ImpactType.Air;
return ImpactType.Ground;
}
public ImpactTargetType GetDirectHitTargetType(World world, CPos cell, WPos pos, Actor firedBy, bool checkTargetValidity = false)
{
var victims = world.FindActorsOnCircle(pos, WDist.Zero);
var invalidHit = false;
foreach (var victim in victims)
// Check whether the impact position overlaps with an actor's hitshape
foreach (var victim in world.FindActorsOnCircle(pos, WDist.Zero))
{
if (!AffectsParent && victim == firedBy)
continue;
if (!victim.Info.HasTraitInfo<IHealthInfo>())
continue;
// If the impact position is within any HitShape, we have a direct hit
var activeShapes = victim.TraitsImplementing<HitShape>().Where(Exts.IsTraitEnabled);
var directHit = activeShapes.Any(i => i.DistanceFromEdge(victim, pos).Length <= 0);
// 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)
if (!activeShapes.Any(s => s.DistanceFromEdge(victim, pos).Length <= 0))
continue;
if (!checkTargetValidity || IsValidAgainst(victim, firedBy))
return ImpactTargetType.ValidActor;
if (IsValidAgainst(victim, firedBy))
return ImpactActorType.Valid;
// If we got here, it must be an invalid target
invalidHit = true;
anyInvalidActor = true;
}
// If there was at least a single direct hit, but none on valid target(s), we return InvalidActor
return invalidHit ? ImpactTargetType.InvalidActor : ImpactTargetType.NoActor;
return anyInvalidActor ? ImpactActorType.Invalid : ImpactActorType.None;
}
// ActorTypeAtImpact already checks AffectsParent beforehand, to avoid parent HitShape look-ups
// (and to prevent returning ImpactActorType.Invalid on AffectsParent=false)
public override bool IsValidAgainst(Actor victim, Actor firedBy)
{
var stance = firedBy.Owner.Stances[victim.Owner];
if (!ValidStances.HasStance(stance))
return false;
// A target type is valid if it is in the valid targets list, and not in the invalid targets list.
if (!IsValidTarget(victim.GetEnabledTargetTypes()))
return false;
return true;
}
public override void DoImpact(Target target, WarheadArgs args)
@@ -107,10 +95,15 @@ namespace OpenRA.Mods.Common.Warheads
var firedBy = args.SourceActor;
var pos = target.CenterPosition;
var world = firedBy.World;
var targetTile = world.Map.CellContaining(pos);
var isValid = IsValidImpact(pos, firedBy);
var actorAtImpact = ImpactActors ? ActorTypeAtImpact(world, pos, firedBy) : ImpactActorType.None;
if ((!world.Map.Contains(targetTile)) || (!isValid))
// Ignore the impact if there are only invalid actors within range
if (actorAtImpact == ImpactActorType.Invalid)
return;
// Ignore the impact if there are no valid actors and no valid terrain
// (impacts are allowed on valid actors sitting on invalid terrain!)
if (actorAtImpact == ImpactActorType.None && !IsValidAgainstTerrain(world, pos))
return;
var explosion = Explosions.RandomOrDefault(world.LocalRandom);
@@ -119,7 +112,7 @@ namespace OpenRA.Mods.Common.Warheads
if (ForceDisplayAtGroundLevel)
{
var dat = world.Map.DistanceAboveTerrain(pos);
pos = new WPos(pos.X, pos.Y, pos.Z - dat.Length);
pos -= new WVec(0, 0, dat.Length);
}
var palette = ExplosionPalette;
@@ -134,26 +127,15 @@ namespace OpenRA.Mods.Common.Warheads
Game.Sound.Play(SoundType.World, impactSound, pos);
}
public bool IsValidImpact(WPos pos, Actor firedBy)
/// <summary>Checks if the warhead is valid against the terrain at impact position.</summary>
bool IsValidAgainstTerrain(World world, WPos pos)
{
var world = firedBy.World;
var targetTile = world.Map.CellContaining(pos);
if (!world.Map.Contains(targetTile))
var cell = world.Map.CellContaining(pos);
if (!world.Map.Contains(cell))
return false;
var impactType = GetImpactType(world, targetTile, pos, firedBy);
switch (impactType)
{
case ImpactType.TargetHit:
return true;
case ImpactType.Air:
return IsValidTarget(TargetTypeAir);
case ImpactType.Ground:
var tileInfo = world.Map.GetTerrainInfo(targetTile);
return IsValidTarget(tileInfo.TargetTypes);
default:
return false;
}
var dat = world.Map.DistanceAboveTerrain(pos);
return IsValidTarget(dat > AirThreshold ? TargetTypeAir : world.Map.GetTerrainInfo(cell).TargetTypes);
}
}
}

View File

@@ -15,19 +15,11 @@ using OpenRA.Traits;
namespace OpenRA.Mods.Common.Warheads
{
public enum ImpactType
public enum ImpactActorType
{
None,
Ground,
Air,
TargetHit
}
public enum ImpactTargetType
{
NoActor,
ValidActor,
InvalidActor
Invalid,
Valid,
}
[Desc("Base warhead class. This can be used to derive other warheads from.")]