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:
@@ -48,55 +48,43 @@ namespace OpenRA.Mods.Common.Warheads
|
|||||||
|
|
||||||
static readonly BitSet<TargetableType> TargetTypeAir = new BitSet<TargetableType>("Air");
|
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
|
var anyInvalidActor = false;
|
||||||
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 dat = world.Map.DistanceAboveTerrain(pos);
|
// Check whether the impact position overlaps with an actor's hitshape
|
||||||
if (dat > AirThreshold)
|
foreach (var victim in world.FindActorsOnCircle(pos, WDist.Zero))
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
if (!AffectsParent && victim == firedBy)
|
if (!AffectsParent && victim == firedBy)
|
||||||
continue;
|
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 activeShapes = victim.TraitsImplementing<HitShape>().Where(Exts.IsTraitEnabled);
|
||||||
var directHit = activeShapes.Any(i => i.DistanceFromEdge(victim, pos).Length <= 0);
|
if (!activeShapes.Any(s => s.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)
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!checkTargetValidity || IsValidAgainst(victim, firedBy))
|
if (IsValidAgainst(victim, firedBy))
|
||||||
return ImpactTargetType.ValidActor;
|
return ImpactActorType.Valid;
|
||||||
|
|
||||||
// If we got here, it must be an invalid target
|
anyInvalidActor = true;
|
||||||
invalidHit = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there was at least a single direct hit, but none on valid target(s), we return InvalidActor
|
return anyInvalidActor ? ImpactActorType.Invalid : ImpactActorType.None;
|
||||||
return invalidHit ? ImpactTargetType.InvalidActor : ImpactTargetType.NoActor;
|
}
|
||||||
|
|
||||||
|
// 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)
|
public override void DoImpact(Target target, WarheadArgs args)
|
||||||
@@ -107,10 +95,15 @@ namespace OpenRA.Mods.Common.Warheads
|
|||||||
var firedBy = args.SourceActor;
|
var firedBy = args.SourceActor;
|
||||||
var pos = target.CenterPosition;
|
var pos = target.CenterPosition;
|
||||||
var world = firedBy.World;
|
var world = firedBy.World;
|
||||||
var targetTile = world.Map.CellContaining(pos);
|
var actorAtImpact = ImpactActors ? ActorTypeAtImpact(world, pos, firedBy) : ImpactActorType.None;
|
||||||
var isValid = IsValidImpact(pos, firedBy);
|
|
||||||
|
|
||||||
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;
|
return;
|
||||||
|
|
||||||
var explosion = Explosions.RandomOrDefault(world.LocalRandom);
|
var explosion = Explosions.RandomOrDefault(world.LocalRandom);
|
||||||
@@ -119,7 +112,7 @@ namespace OpenRA.Mods.Common.Warheads
|
|||||||
if (ForceDisplayAtGroundLevel)
|
if (ForceDisplayAtGroundLevel)
|
||||||
{
|
{
|
||||||
var dat = world.Map.DistanceAboveTerrain(pos);
|
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;
|
var palette = ExplosionPalette;
|
||||||
@@ -134,26 +127,15 @@ namespace OpenRA.Mods.Common.Warheads
|
|||||||
Game.Sound.Play(SoundType.World, impactSound, pos);
|
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 cell = world.Map.CellContaining(pos);
|
||||||
var targetTile = world.Map.CellContaining(pos);
|
if (!world.Map.Contains(cell))
|
||||||
if (!world.Map.Contains(targetTile))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var impactType = GetImpactType(world, targetTile, pos, firedBy);
|
var dat = world.Map.DistanceAboveTerrain(pos);
|
||||||
switch (impactType)
|
return IsValidTarget(dat > AirThreshold ? TargetTypeAir : world.Map.GetTerrainInfo(cell).TargetTypes);
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,19 +15,11 @@ using OpenRA.Traits;
|
|||||||
|
|
||||||
namespace OpenRA.Mods.Common.Warheads
|
namespace OpenRA.Mods.Common.Warheads
|
||||||
{
|
{
|
||||||
public enum ImpactType
|
public enum ImpactActorType
|
||||||
{
|
{
|
||||||
None,
|
None,
|
||||||
Ground,
|
Invalid,
|
||||||
Air,
|
Valid,
|
||||||
TargetHit
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum ImpactTargetType
|
|
||||||
{
|
|
||||||
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.")]
|
||||||
|
|||||||
Reference in New Issue
Block a user