Support multiple ITargetable traits
This commit is contained in:
@@ -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)))
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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>();
|
||||||
|
|||||||
@@ -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)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user