Store Targetables in Actor.
This can be used to avoid several lookups for these traits, as well as allow Actor to provide specialised methods to deal with target types efficiently. This also reduces some code duplication.
This commit is contained in:
@@ -44,6 +44,7 @@ namespace OpenRA
|
||||
public Rectangle VisualBounds { get; private set; }
|
||||
public IEffectiveOwner EffectiveOwner { get; private set; }
|
||||
public IOccupySpace OccupiesSpace { get; private set; }
|
||||
public ITargetable[] Targetables { get; private set; }
|
||||
|
||||
public bool IsIdle { get { return currentActivity == null; } }
|
||||
public bool IsDead { get { return Disposed || (health != null && health.IsDead); } }
|
||||
@@ -107,6 +108,7 @@ namespace OpenRA
|
||||
disables = TraitsImplementing<IDisable>().ToArray();
|
||||
visibilityModifiers = TraitsImplementing<IVisibilityModifier>().ToArray();
|
||||
defaultVisibility = Trait<IDefaultVisibility>();
|
||||
Targetables = TraitsImplementing<ITargetable>().ToArray();
|
||||
}
|
||||
|
||||
Rectangle DetermineBounds()
|
||||
@@ -320,6 +322,30 @@ namespace OpenRA
|
||||
return defaultVisibility.IsVisible(this, player);
|
||||
}
|
||||
|
||||
public IEnumerable<string> GetAllTargetTypes()
|
||||
{
|
||||
foreach (var targetable in Targetables)
|
||||
foreach (var targetType in targetable.TargetTypes)
|
||||
yield return targetType;
|
||||
}
|
||||
|
||||
public IEnumerable<string> GetEnabledTargetTypes()
|
||||
{
|
||||
foreach (var targetable in Targetables)
|
||||
if (targetable.IsTraitEnabled())
|
||||
foreach (var targetType in targetable.TargetTypes)
|
||||
yield return targetType;
|
||||
}
|
||||
|
||||
public bool IsTargetableBy(Actor byActor)
|
||||
{
|
||||
foreach (var targetable in Targetables)
|
||||
if (targetable.IsTraitEnabled() && targetable.TargetableBy(this, byActor))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#region Scripting interface
|
||||
|
||||
Lazy<ScriptActorInterface> luaInterface;
|
||||
|
||||
@@ -127,8 +127,9 @@ namespace OpenRA.GameRules
|
||||
/// <summary>Checks if the weapon is valid against (can target) the actor.</summary>
|
||||
public bool IsValidAgainst(Actor victim, Actor firedBy)
|
||||
{
|
||||
var targetable = victim.TraitsImplementing<ITargetable>().Where(Exts.IsTraitEnabled);
|
||||
if (!IsValidTarget(targetable.SelectMany(t => t.TargetTypes)))
|
||||
var targetTypes = victim.GetEnabledTargetTypes();
|
||||
|
||||
if (!IsValidTarget(targetTypes))
|
||||
return false;
|
||||
|
||||
if (!Warheads.Any(w => w.IsValidAgainst(victim, firedBy)))
|
||||
|
||||
@@ -59,7 +59,7 @@ namespace OpenRA.Traits
|
||||
|
||||
CenterPosition = self.CenterPosition;
|
||||
Bounds = self.Bounds;
|
||||
TargetTypes = self.TraitsImplementing<ITargetable>().Where(Exts.IsTraitEnabled).SelectMany(t => t.TargetTypes).ToHashSet();
|
||||
TargetTypes = self.GetEnabledTargetTypes().ToHashSet();
|
||||
|
||||
UpdateVisibility();
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@ namespace OpenRA.Traits
|
||||
|
||||
TargetType type;
|
||||
Actor actor;
|
||||
IEnumerable<ITargetable> targetable;
|
||||
FrozenActor frozen;
|
||||
WPos pos;
|
||||
int generation;
|
||||
@@ -48,7 +47,6 @@ namespace OpenRA.Traits
|
||||
return new Target
|
||||
{
|
||||
actor = a,
|
||||
targetable = a.TraitsImplementing<ITargetable>(),
|
||||
type = TargetType.Actor,
|
||||
generation = a.Generation,
|
||||
};
|
||||
@@ -83,8 +81,7 @@ namespace OpenRA.Traits
|
||||
if (targeter == null || Type == TargetType.Invalid)
|
||||
return false;
|
||||
|
||||
var targeted = this.actor;
|
||||
if (targeted != null && !targetable.Any(t => t.IsTraitEnabled() && t.TargetableBy(targeted, targeter)))
|
||||
if (actor != null && !actor.IsTargetableBy(targeter))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
@@ -94,7 +91,24 @@ namespace OpenRA.Traits
|
||||
// TODO: either replace based on target type or put in singleton trait
|
||||
public bool RequiresForceFire
|
||||
{
|
||||
get { return targetable != null && targetable.Any(Exts.IsTraitEnabled) && targetable.Where(Exts.IsTraitEnabled).All(t => t.RequiresForceFire); }
|
||||
get
|
||||
{
|
||||
if (actor == null)
|
||||
return false;
|
||||
|
||||
var isTargetable = false;
|
||||
foreach (var targetable in actor.Targetables)
|
||||
{
|
||||
if (!targetable.IsTraitEnabled())
|
||||
continue;
|
||||
|
||||
isTargetable = true;
|
||||
if (!targetable.RequiresForceFire)
|
||||
return false;
|
||||
}
|
||||
|
||||
return isTargetable;
|
||||
}
|
||||
}
|
||||
|
||||
// Representative position - see Positions for the full set of targetable positions.
|
||||
@@ -126,8 +140,7 @@ namespace OpenRA.Traits
|
||||
switch (Type)
|
||||
{
|
||||
case TargetType.Actor:
|
||||
var targetable = actor.TraitsImplementing<ITargetable>().Where(Exts.IsTraitEnabled);
|
||||
if (!targetable.Any())
|
||||
if (!actor.Targetables.Any(Exts.IsTraitEnabled))
|
||||
return new[] { actor.CenterPosition };
|
||||
|
||||
var targetablePositions = actor.TraitOrDefault<ITargetablePositions>();
|
||||
|
||||
Reference in New Issue
Block a user