Support multiple ITargetable traits

This commit is contained in:
atlimit8
2015-07-13 15:22:39 -05:00
parent 4bd34e3ed3
commit f5c3575c5a
13 changed files with 39 additions and 38 deletions

View File

@@ -125,8 +125,8 @@ 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.TraitOrDefault<ITargetable>();
if (targetable == null || !IsValidTarget(targetable.TargetTypes))
var targetable = victim.TraitsImplementing<ITargetable>().Where(Exts.IsTraitEnabled);
if (!IsValidTarget(targetable.SelectMany(t => t.TargetTypes)))
return false;
if (!Warheads.Any(w => w.IsValidAgainst(victim, firedBy)))
@@ -138,8 +138,8 @@ namespace OpenRA.GameRules
/// <summary>Checks if the weapon is valid against (can target) the frozen actor.</summary>
public bool IsValidAgainst(FrozenActor victim, Actor firedBy)
{
var targetable = victim.Info.Traits.GetOrDefault<ITargetableInfo>();
if (targetable == null || !IsValidTarget(targetable.GetTargetTypes()))
var targetable = victim.Info.Traits.WithInterface<ITargetableInfo>();
if (!IsValidTarget(targetable.SelectMany(t => t.GetTargetTypes())))
return false;
if (!Warheads.Any(w => w.IsValidAgainst(victim, firedBy)))

View File

@@ -22,7 +22,7 @@ namespace OpenRA.Traits
TargetType type;
Actor actor;
ITargetable targetable;
IEnumerable<ITargetable> targetable;
FrozenActor frozen;
WPos pos;
int generation;
@@ -48,7 +48,7 @@ namespace OpenRA.Traits
return new Target
{
actor = a,
targetable = a.TraitOrDefault<ITargetable>(),
targetable = a.TraitsImplementing<ITargetable>(),
type = TargetType.Actor,
generation = a.Generation,
};
@@ -83,15 +83,18 @@ namespace OpenRA.Traits
if (targeter == null || Type == TargetType.Invalid)
return false;
if (targetable != null && !targetable.TargetableBy(actor, targeter))
var targeted = this.actor;
if (targeted != null && !targetable.Any(t => t.IsTraitEnabled() && t.TargetableBy(targeted, targeter)))
return false;
return true;
}
// Currently all or nothing.
// TODO: either replace based on target type or put in singleton trait
public bool RequiresForceFire
{
get { return targetable != null && targetable.RequiresForceFire; }
get { return targetable != null && targetable.Any(Exts.IsTraitEnabled) && targetable.Where(Exts.IsTraitEnabled).All(t => t.RequiresForceFire); }
}
// Representative position - see Positions for the full set of targetable positions.
@@ -123,12 +126,13 @@ namespace OpenRA.Traits
switch (Type)
{
case TargetType.Actor:
var targetable = actor.TraitOrDefault<ITargetable>();
if (targetable == null)
var targetable = actor.TraitsImplementing<ITargetable>().Where(Exts.IsTraitEnabled);
if (!targetable.Any())
return new[] { actor.CenterPosition };
var positions = targetable.TargetablePositions(actor);
return positions.Any() ? positions : new[] { actor.CenterPosition };
var targeted = this.actor;
var positions = targetable.SelectMany(t => t.TargetablePositions(targeted)).Distinct();
return positions.Any() ? positions : new[] { targeted.CenterPosition };
case TargetType.FrozenActor:
return new[] { frozen.CenterPosition };
case TargetType.Terrain:

View File

@@ -315,6 +315,7 @@ namespace OpenRA.Traits
public interface ITargetable
{
// Check IsTraitEnabled or !IsTraitDisabled first
string[] TargetTypes { get; }
IEnumerable<WPos> TargetablePositions(Actor self);
bool TargetableBy(Actor self, Actor byActor);