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

View File

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

View File

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

View File

@@ -63,13 +63,13 @@ namespace OpenRA.Mods.Common.AI
if (!a.HasTrait<AttackBase>()) if (!a.HasTrait<AttackBase>())
return false; return false;
var targetable = target.TraitOrDefault<ITargetable>(); var targetTypes = target.TraitsImplementing<ITargetable>().Where(Exts.IsTraitEnabled).SelectMany(t => t.TargetTypes);
if (targetable == null) if (!targetTypes.Any())
return false; return false;
var arms = a.TraitsImplementing<Armament>(); var arms = a.TraitsImplementing<Armament>();
foreach (var arm in arms) foreach (var arm in arms)
if (arm.Weapon.IsValidTarget(targetable.TargetTypes)) if (arm.Weapon.IsValidTarget(targetTypes))
return true; return true;
return false; return false;

View File

@@ -125,14 +125,11 @@ namespace OpenRA.Mods.Common.AI
if (a == null) if (a == null)
return 0; return 0;
var targetable = a.TraitOrDefault<ITargetable>(); var targetable = a.TraitsImplementing<ITargetable>().Where(Exts.IsTraitEnabled);
if (targetable == null) if (!targetable.Any(t => t.TargetableBy(a, firedBy.PlayerActor)))
return 0; return 0;
if (!targetable.TargetableBy(a, firedBy.PlayerActor)) if (Types.Intersect(targetable.SelectMany(t => t.TargetTypes)).Any())
return 0;
if (Types.Intersect(targetable.TargetTypes).Any())
{ {
switch (TargetMetric) switch (TargetMetric)
{ {

View File

@@ -29,8 +29,7 @@ namespace OpenRA.Mods.Common.Activities
bool IsTargetable(Actor self, Actor viewer) bool IsTargetable(Actor self, Actor viewer)
{ {
var targetable = self.TraitOrDefault<ITargetable>(); return self.TraitsImplementing<ITargetable>().Any(t => t.IsTraitEnabled() && t.TargetableBy(self, viewer));
return targetable != null && targetable.TargetableBy(self, viewer);
} }
public override Activity Tick(Actor self) public override Activity Tick(Actor self)

View File

@@ -77,7 +77,7 @@ namespace OpenRA.Mods.Common.Orders
public override bool CanTargetActor(Actor self, Actor target, TargetModifiers modifiers, ref string cursor) public override bool CanTargetActor(Actor self, Actor target, TargetModifiers modifiers, ref string cursor)
{ {
return target.TraitsImplementing<ITargetable>().Any(t => t.TargetTypes.Intersect(targetTypes).Any()); return target.TraitsImplementing<ITargetable>().Any(t => t.IsTraitEnabled() && t.TargetTypes.Intersect(targetTypes).Any());
} }
public override bool CanTargetFrozenActor(Actor self, FrozenActor target, TargetModifiers modifiers, ref string cursor) public override bool CanTargetFrozenActor(Actor self, FrozenActor target, TargetModifiers modifiers, ref string cursor)

View File

@@ -35,8 +35,7 @@ namespace OpenRA.Mods.Common.Traits
{ {
get get
{ {
return IsTraitDisabled ? None return (self.CenterPosition.Z > 0) ? info.TargetTypes : info.GroundedTargetTypes;
: (self.CenterPosition.Z > 0 ? info.TargetTypes : info.GroundedTargetTypes);
} }
} }
} }

View File

@@ -57,8 +57,8 @@ namespace OpenRA.Mods.Common.Traits
if (info.ValidFactions.Any() && !info.ValidFactions.Contains(collector.Owner.Faction.InternalName)) if (info.ValidFactions.Any() && !info.ValidFactions.Contains(collector.Owner.Faction.InternalName))
return false; return false;
var targetable = collector.Info.Traits.GetOrDefault<ITargetableInfo>(); var targetable = collector.TraitsImplementing<ITargetable>();
if (targetable == null || !info.ValidTargets.Intersect(targetable.GetTargetTypes()).Any()) if (!info.ValidTargets.Intersect(targetable.SelectMany(t => t.TargetTypes)).Any())
return false; return false;
var positionable = collector.TraitOrDefault<IPositionable>(); var positionable = collector.TraitOrDefault<IPositionable>();

View File

@@ -46,7 +46,7 @@ namespace OpenRA.Mods.Common.Traits
return cloak.IsVisible(self, viewer.Owner); return cloak.IsVisible(self, viewer.Owner);
} }
public virtual string[] TargetTypes { get { return IsTraitDisabled ? None : Info.TargetTypes; } } public virtual string[] TargetTypes { get { return Info.TargetTypes; } }
public virtual IEnumerable<WPos> TargetablePositions(Actor self) public virtual IEnumerable<WPos> TargetablePositions(Actor self)
{ {

View File

@@ -9,6 +9,7 @@
#endregion #endregion
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using OpenRA.Traits; using OpenRA.Traits;
namespace OpenRA.Mods.Common.Warheads namespace OpenRA.Mods.Common.Warheads
@@ -58,8 +59,8 @@ namespace OpenRA.Mods.Common.Warheads
return false; return false;
// A target type is valid if it is in the valid targets list, and not in the invalid targets list. // A target type is valid if it is in the valid targets list, and not in the invalid targets list.
var targetable = victim.TraitOrDefault<ITargetable>(); var targetable = victim.TraitsImplementing<ITargetable>().Where(Exts.IsTraitEnabled);
if (targetable == null || !IsValidTarget(targetable.TargetTypes)) if (!IsValidTarget(targetable.SelectMany(t => t.TargetTypes)))
return false; return false;
return true; return true;
@@ -74,8 +75,8 @@ namespace OpenRA.Mods.Common.Warheads
return false; return false;
// A target type is valid if it is in the valid targets list, and not in the invalid targets list. // A target type is valid if it is in the valid targets list, and not in the invalid targets list.
var targetable = victim.Info.Traits.GetOrDefault<ITargetableInfo>(); var targetable = victim.Info.Traits.WithInterface<ITargetableInfo>();
if (targetable == null || !IsValidTarget(targetable.GetTargetTypes())) if (!IsValidTarget(targetable.SelectMany(t => t.GetTargetTypes())))
return false; return false;
return true; return true;

View File

@@ -79,8 +79,8 @@ namespace OpenRA.Mods.RA.Traits
else else
ai = order.TargetActor.Info; ai = order.TargetActor.Info;
var i = ai.Traits.GetOrDefault<ITargetableInfo>(); return ai.Traits.WithInterface<ITargetableInfo>()
return i != null && i.GetTargetTypes().Intersect(Info.Types).Any(); .SelectMany(t => t.GetTargetTypes()).Intersect(Info.Types).Any();
} }
public string VoicePhraseForOrder(Actor self, Order order) public string VoicePhraseForOrder(Actor self, Order order)
@@ -95,7 +95,8 @@ namespace OpenRA.Mods.RA.Traits
return; return;
var target = self.ResolveFrozenActorOrder(order, Color.Red); var target = self.ResolveFrozenActorOrder(order, Color.Red);
if (target.Type != TargetType.Actor) if (target.Type != TargetType.Actor
|| target.Actor.TraitsImplementing<ITargetable>().SelectMany(t => t.TargetTypes).Intersect(Info.Types).Any())
return; return;
if (!order.Queued) if (!order.Queued)

View File

@@ -34,8 +34,7 @@ namespace OpenRA.Mods.RA.Traits
{ {
get get
{ {
return IsTraitDisabled ? None return cloak.Cloaked ? info.CloakedTargetTypes : info.TargetTypes;
: (cloak.Cloaked ? info.CloakedTargetTypes : info.TargetTypes);
} }
} }
} }