Skip to content

Commit

Permalink
Move ValidRelations from Capturable to Captures
Browse files Browse the repository at this point in the history
To better match weapon definitions
  • Loading branch information
PunkPun committed Aug 7, 2023
1 parent 388222c commit 34a737f
Show file tree
Hide file tree
Showing 12 changed files with 134 additions and 82 deletions.
20 changes: 10 additions & 10 deletions OpenRA.Mods.Common/Activities/CaptureActor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ protected override void TickInner(Actor self, in Target target, bool targetIsDea
}

if (!targetIsDeadOrHiddenActor && target.Type != TargetType.FrozenActor &&
(enterCaptureManager == null || !enterCaptureManager.CanBeTargetedBy(enterActor, self, manager)))
(enterCaptureManager == null || !manager.CanTarget(enterCaptureManager)))
Cancel(self, true);
}

Expand All @@ -51,15 +51,15 @@ protected override bool TryStartEnter(Actor self, Actor targetActor)

// Make sure we can still capture the target before entering
// (but not before, because this may stop the actor in the middle of nowhere)
if (enterCaptureManager == null || !enterCaptureManager.CanBeTargetedBy(enterActor, self, manager))
if (enterCaptureManager == null || !manager.CanTarget(enterCaptureManager))
{
Cancel(self, true);
return false;
}

// StartCapture returns false when a capture delay is enabled
// We wait until it returns true before allowing entering the target
if (!manager.StartCapture(self, enterActor, enterCaptureManager, out var captures))
if (!manager.StartCapture(enterCaptureManager, out var captures))
return false;

if (!captures.Info.ConsumedByCapture)
Expand All @@ -80,11 +80,11 @@ protected override void OnEnterComplete(Actor self, Actor targetActor)
if (enterActor != targetActor)
return;

if (enterCaptureManager.BeingCaptured || !enterCaptureManager.CanBeTargetedBy(enterActor, self, manager))
if (enterCaptureManager.BeingCaptured || !manager.CanTarget(enterCaptureManager))
return;

// Prioritize capturing over sabotaging
var captures = manager.ValidCapturesWithLowestSabotageThreshold(self, enterActor, enterCaptureManager);
var captures = manager.ValidCapturesWithLowestSabotageThreshold(enterCaptureManager);
if (captures == null)
return;

Expand Down Expand Up @@ -134,25 +134,25 @@ void DoCapture(Actor self, Captures captures)

protected override void OnLastRun(Actor self)
{
CancelCapture(self);
CancelCapture();
base.OnLastRun(self);
}

protected override void OnActorDispose(Actor self)
{
CancelCapture(self);
CancelCapture();
base.OnActorDispose(self);
}

public override void Cancel(Actor self, bool keepQueue = false)
{
CancelCapture(self);
CancelCapture();
base.Cancel(self, keepQueue);
}

void CancelCapture(Actor self)
void CancelCapture()
{
manager.CancelCapture(self, enterActor, enterCaptureManager);
manager.CancelCapture(enterCaptureManager);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public void Capture(Actor target)
public bool CanCapture(Actor target)
{
var targetManager = target.TraitOrDefault<CaptureManager>();
return targetManager != null && targetManager.CanBeTargetedBy(target, Self, captureManager);
return targetManager != null && captureManager.CanTarget(targetManager);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ void QueueCaptureOrders(IBot bot)
if (captureManager == null)
return false;
return capturers.Any(tp => captureManager.CanBeTargetedBy(target, tp.Actor, tp.Trait));
return capturers.Any(tp => tp.Trait.CanTarget(captureManager));
})
.OrderByDescending(target => target.GetSellValue())
.Take(maximumCaptureTargetOptions);
Expand Down
3 changes: 0 additions & 3 deletions OpenRA.Mods.Common/Traits/Capturable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,6 @@ public class CapturableInfo : ConditionalTraitInfo, Requires<CaptureManagerInfo>
[Desc("CaptureTypes (from the Captures trait) that are able to capture this.")]
public readonly BitSet<CaptureType> Types = default;

[Desc("What player relationships the target's owner needs to be captured by this actor.")]
public readonly PlayerRelationship ValidRelationships = PlayerRelationship.Neutral | PlayerRelationship.Enemy;

[Desc("Cancel the actor's current activity when getting captured.")]
public readonly bool CancelActivity = false;

Expand Down
106 changes: 53 additions & 53 deletions OpenRA.Mods.Common/Traits/CaptureManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,32 +38,21 @@ public class CaptureManagerInfo : TraitInfo
[Desc("Should units friendly to the capturing actor auto-target this actor while it is being captured?")]
public readonly bool PreventsAutoTarget = true;

public override object Create(ActorInitializer init) { return new CaptureManager(this); }

public bool CanBeTargetedBy(FrozenActor frozenActor, Actor captor, Captures captures)
{
if (captures.IsTraitDisabled)
return false;

// TODO: FrozenActors don't yet have a way of caching conditions, so we can't filter disabled traits
// This therefore assumes that all Capturable traits are enabled, which is probably wrong.
// Actors with FrozenUnderFog should therefore not disable the Capturable trait.
var stance = captor.Owner.RelationshipWith(frozenActor.Owner);
return frozenActor.Info.TraitInfos<CapturableInfo>()
.Any(c => c.ValidRelationships.HasRelationship(stance) && captures.Info.CaptureTypes.Overlaps(c.Types));
}
public override object Create(ActorInitializer init) { return new CaptureManager(init.Self, this); }
}

public class CaptureManager : INotifyCreated, INotifyCapture, ITick, IDisableEnemyAutoTarget
{
readonly Actor self;
readonly CaptureManagerInfo info;

IMove move;
ICaptureProgressWatcher[] progressWatchers;

BitSet<CaptureType> allyCapturableTypes;
BitSet<CaptureType> neutralCapturableTypes;
BitSet<CaptureType> enemyCapturableTypes;
BitSet<CaptureType> capturesTypes;
BitSet<CaptureType> allyCapturesTypes;
BitSet<CaptureType> neutralCapturesTypes;
BitSet<CaptureType> enemyCapturesTypes;
BitSet<CaptureType> capturableTypes;

IEnumerable<Capturable> enabledCapturable;
IEnumerable<Captures> enabledCaptures;
Expand All @@ -81,8 +70,9 @@ public class CaptureManager : INotifyCreated, INotifyCapture, ITick, IDisableEne

public bool BeingCaptured { get; private set; }

public CaptureManager(CaptureManagerInfo info)
public CaptureManager(Actor self, CaptureManagerInfo info)
{
this.self = self;
this.info = info;
}

Expand All @@ -103,69 +93,77 @@ void INotifyCreated.Created(Actor self)
RefreshCapturable();
}

public void RefreshCapturable()
public void RefreshCaptures()
{
allyCapturableTypes = neutralCapturableTypes = enemyCapturableTypes = default;
foreach (var c in enabledCapturable)
allyCapturesTypes = neutralCapturesTypes = enemyCapturesTypes = default;
foreach (var c in enabledCaptures)
{
if (c.Info.ValidRelationships.HasRelationship(PlayerRelationship.Ally))
allyCapturableTypes = allyCapturableTypes.Union(c.Info.Types);
allyCapturesTypes = allyCapturesTypes.Union(c.Info.CaptureTypes);

if (c.Info.ValidRelationships.HasRelationship(PlayerRelationship.Neutral))
neutralCapturableTypes = neutralCapturableTypes.Union(c.Info.Types);
neutralCapturesTypes = neutralCapturesTypes.Union(c.Info.CaptureTypes);

if (c.Info.ValidRelationships.HasRelationship(PlayerRelationship.Enemy))
enemyCapturableTypes = enemyCapturableTypes.Union(c.Info.Types);
enemyCapturesTypes = enemyCapturesTypes.Union(c.Info.CaptureTypes);
}
}

public void RefreshCaptures()
public void RefreshCapturable()
{
capturesTypes = enabledCaptures.Aggregate(
capturableTypes = enabledCapturable.Aggregate(
default(BitSet<CaptureType>),
(a, b) => a.Union(b.Info.CaptureTypes));
(a, b) => a.Union(b.Info.Types));
}

public bool CanBeTargetedBy(Actor self, Actor captor, CaptureManager captorManager)
/// <summary>
/// Should only be called from the captor CaptureManager.
/// </summary>
public bool CanTarget(CaptureManager target)
{
var relationship = captor.Owner.RelationshipWith(self.Owner);
if (relationship.HasRelationship(PlayerRelationship.Enemy))
return captorManager.capturesTypes.Overlaps(enemyCapturableTypes);
return CanTarget(target.self.Owner, target.capturableTypes);
}

if (relationship.HasRelationship(PlayerRelationship.Neutral))
return captorManager.capturesTypes.Overlaps(neutralCapturableTypes);
/// <summary>
/// Should only be called from the captor CaptureManager.
/// </summary>
public bool CanTarget(FrozenActor target)
{
if (!target.Info.HasTraitInfo<CaptureManagerInfo>())
return false;

if (relationship.HasRelationship(PlayerRelationship.Ally))
return captorManager.capturesTypes.Overlaps(allyCapturableTypes);
// TODO: FrozenActors don't yet have a way of caching conditions, so we can't filter disabled traits
// This therefore assumes that all Capturable traits are enabled, which is probably wrong.
// Actors with FrozenUnderFog should therefore not disable the Capturable trait.
var targetTypes = target.Info.TraitInfos<CapturableInfo>().Aggregate(
default(BitSet<CaptureType>),
(a, b) => a.Union(b.Types));

return false;
return CanTarget(target.Owner, targetTypes);
}

public bool CanBeTargetedBy(Actor self, Actor captor, Captures captures)
bool CanTarget(Player target, BitSet<CaptureType> captureTypes)
{
if (captures.IsTraitDisabled)
return false;

var relationship = captor.Owner.RelationshipWith(self.Owner);
var relationship = self.Owner.RelationshipWith(target);
if (relationship.HasRelationship(PlayerRelationship.Enemy))
return captures.Info.CaptureTypes.Overlaps(enemyCapturableTypes);
return captureTypes.Overlaps(enemyCapturesTypes);

if (relationship.HasRelationship(PlayerRelationship.Neutral))
return captures.Info.CaptureTypes.Overlaps(neutralCapturableTypes);
return captureTypes.Overlaps(neutralCapturesTypes);

if (relationship.HasRelationship(PlayerRelationship.Ally))
return captures.Info.CaptureTypes.Overlaps(allyCapturableTypes);
return captureTypes.Overlaps(allyCapturesTypes);

return false;
}

public Captures ValidCapturesWithLowestSabotageThreshold(Actor self, Actor captee, CaptureManager capteeManager)
public Captures ValidCapturesWithLowestSabotageThreshold(CaptureManager target)
{
if (captee.IsDead)
if (target.self.IsDead)
return null;

foreach (var c in enabledCaptures.OrderBy(c => c.Info.SabotageThreshold))
if (capteeManager.CanBeTargetedBy(captee, self, c))
if (CanTarget(target))
return c;

return null;
Expand All @@ -182,18 +180,19 @@ void INotifyCapture.OnCapture(Actor self, Actor captor, Player oldOwner, Player
/// This method grants the capturing conditions on the captor and target and returns
/// true if the captor is able to start entering or false if it needs to wait.
/// </summary>
public bool StartCapture(Actor self, Actor target, CaptureManager targetManager, out Captures captures)
public bool StartCapture(CaptureManager targetManager, out Captures captures)
{
captures = null;

// Prevent a capture being restarted after it has been canceled during disposal
if (self.WillDispose)
return false;

var target = targetManager.self;
if (target != currentTarget)
{
if (currentTarget != null)
CancelCapture(self, currentTarget, currentTargetManager);
if (currentTargetManager != null)
CancelCapture(currentTargetManager);

targetManager.currentCaptors.Add(self);
currentTarget = target;
Expand All @@ -211,7 +210,7 @@ public bool StartCapture(Actor self, Actor target, CaptureManager targetManager,

captures = enabledCaptures
.OrderBy(c => c.Info.CaptureDelay)
.FirstOrDefault(c => targetManager.CanBeTargetedBy(target, self, c));
.FirstOrDefault(c => c.CaptureManager.CanTarget(targetManager));

if (captures == null)
return false;
Expand Down Expand Up @@ -246,11 +245,12 @@ public bool StartCapture(Actor self, Actor target, CaptureManager targetManager,
/// This method revokes the capturing conditions on the captor and target
/// and resets any capturing progress.
/// </summary>
public void CancelCapture(Actor self, Actor target, CaptureManager targetManager)
public void CancelCapture(CaptureManager targetManager)
{
if (currentTarget == null)
return;

var target = targetManager.self;
foreach (var w in progressWatchers)
w.Update(self, self, target, 0, 0);

Expand Down
18 changes: 10 additions & 8 deletions OpenRA.Mods.Common/Traits/Captures.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ public class CapturesInfo : ConditionalTraitInfo, Requires<CaptureManagerInfo>
[Desc("Experience granted to the capturing player.")]
public readonly int PlayerExperience = 0;

[Desc("What player relationships the target's owner needs to be captured by this actor.")]
public readonly PlayerRelationship ValidRelationships = PlayerRelationship.Neutral | PlayerRelationship.Enemy;

[Desc("Relationships that the structure's previous owner needs to have for the capturing player to receive Experience.")]
public readonly PlayerRelationship PlayerExperienceRelationships = PlayerRelationship.Enemy;

Expand All @@ -69,12 +72,12 @@ public class CapturesInfo : ConditionalTraitInfo, Requires<CaptureManagerInfo>

public class Captures : ConditionalTrait<CapturesInfo>, IIssueOrder, IResolveOrder, IOrderVoice
{
readonly CaptureManager captureManager;
public readonly CaptureManager CaptureManager;

public Captures(Actor self, CapturesInfo info)
: base(info)
{
captureManager = self.Trait<CaptureManager>();
CaptureManager = self.Trait<CaptureManager>();
}

public IEnumerable<IOrderTargeter> Orders
Expand Down Expand Up @@ -110,8 +113,8 @@ public void ResolveOrder(Actor self, Order order)
self.ShowTargetLines();
}

protected override void TraitEnabled(Actor self) { captureManager.RefreshCaptures(); }
protected override void TraitDisabled(Actor self) { captureManager.RefreshCaptures(); }
protected override void TraitEnabled(Actor self) { CaptureManager.RefreshCaptures(); }
protected override void TraitDisabled(Actor self) { CaptureManager.RefreshCaptures(); }

sealed class CaptureOrderTargeter : UnitOrderTargeter
{
Expand All @@ -125,8 +128,8 @@ public CaptureOrderTargeter(Captures captures)

public override bool CanTargetActor(Actor self, Actor target, TargetModifiers modifiers, ref string cursor)
{
var captureManager = target.TraitOrDefault<CaptureManager>();
if (captureManager == null || !captureManager.CanBeTargetedBy(target, self, captures))
var targetManager = target.TraitOrDefault<CaptureManager>();
if (targetManager == null || !captures.CaptureManager.CanTarget(targetManager))
{
cursor = captures.Info.EnterBlockedCursor;
return false;
Expand All @@ -147,8 +150,7 @@ public override bool CanTargetActor(Actor self, Actor target, TargetModifiers mo

public override bool CanTargetFrozenActor(Actor self, FrozenActor target, TargetModifiers modifiers, ref string cursor)
{
var captureManagerInfo = target.Info.TraitInfoOrDefault<CaptureManagerInfo>();
if (captureManagerInfo == null || !captureManagerInfo.CanBeTargetedBy(target, self, captures))
if (!captures.CaptureManager.CanTarget(target))
{
cursor = captures.Info.EnterBlockedCursor;
return false;
Expand Down

0 comments on commit 34a737f

Please sign in to comment.