Add support for capture delays and conditions.
CaptureDelay is defined per-trait, and the shortest delay will be used if multiple traits are enabled. CapturingCondition and BeingCapturedCondition are global, and are granted when any capture is in progress. The capture period is defined from when the unit reaches the cell next to the target, and either starts to wait or enter the target through to when the capture succeeds or fails.
This commit is contained in:
@@ -38,6 +38,13 @@ namespace OpenRA.Mods.Common.Activities
|
||||
return !actor.IsDead && !targetManager.BeingCaptured && targetManager.CanBeTargetedBy(actor, self, manager);
|
||||
}
|
||||
|
||||
protected override bool TryStartEnter(Actor self)
|
||||
{
|
||||
// CanEnter is only called when the actor is ready to start entering the target.
|
||||
// We can (ab)use this as a notification that the capture is starting.
|
||||
return manager.StartCapture(self, actor, targetManager);
|
||||
}
|
||||
|
||||
protected override void OnInside(Actor self)
|
||||
{
|
||||
if (!CanReserve(self))
|
||||
@@ -94,6 +101,23 @@ namespace OpenRA.Mods.Common.Activities
|
||||
});
|
||||
}
|
||||
|
||||
protected override void OnLastRun(Actor self)
|
||||
{
|
||||
CancelCapture(self);
|
||||
base.OnLastRun(self);
|
||||
}
|
||||
|
||||
protected override void OnActorDispose(Actor self)
|
||||
{
|
||||
CancelCapture(self);
|
||||
base.OnActorDispose(self);
|
||||
}
|
||||
|
||||
void CancelCapture(Actor self)
|
||||
{
|
||||
manager.CancelCapture(self, actor, targetManager);
|
||||
}
|
||||
|
||||
public override Activity Tick(Actor self)
|
||||
{
|
||||
if (!targetManager.CanBeTargetedBy(actor, self, manager))
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace OpenRA.Mods.Common.Activities
|
||||
public abstract class Enter : Activity
|
||||
{
|
||||
public enum ReserveStatus { None, TooFar, Pending, Ready }
|
||||
enum EnterState { ApproachingOrEntering, Inside, Exiting, Done }
|
||||
enum EnterState { ApproachingOrEntering, WaitingToEnter, Inside, Exiting, Done }
|
||||
|
||||
readonly IMove move;
|
||||
readonly int maxTries = 0;
|
||||
@@ -58,6 +58,12 @@ namespace OpenRA.Mods.Common.Activities
|
||||
protected virtual void Unreserve(Actor self, bool abort) { }
|
||||
protected virtual void OnInside(Actor self) { }
|
||||
|
||||
/// <summary>
|
||||
/// Called when the actor is ready to transition from approaching to entering the target.
|
||||
/// Return true to start entering, or false to wait in the WaitingToEnter state.
|
||||
/// </summary>
|
||||
protected virtual bool TryStartEnter(Actor self) { return true; }
|
||||
|
||||
protected bool TryGetAlternateTargetInCircle(
|
||||
Actor self, WDist radius, Action<Target> update, Func<Actor, bool> primaryFilter, Func<Actor, bool>[] preferenceFilters = null)
|
||||
{
|
||||
@@ -187,6 +193,10 @@ namespace OpenRA.Mods.Common.Activities
|
||||
break; // Reserved target -> start entering target
|
||||
}
|
||||
|
||||
// Can we enter yet?
|
||||
if (!TryStartEnter(self))
|
||||
return EnterState.WaitingToEnter;
|
||||
|
||||
// Entering
|
||||
isEnteringOrInside = true;
|
||||
savedPos = self.CenterPosition; // Save position of self, before entering, for returning on exit
|
||||
|
||||
@@ -20,10 +20,24 @@ namespace OpenRA.Mods.Common.Traits
|
||||
public sealed class CaptureType { CaptureType() { } }
|
||||
|
||||
[Desc("Manages Captures and Capturable traits on an actor.")]
|
||||
public class CaptureManagerInfo : TraitInfo<CaptureManager> { }
|
||||
public class CaptureManagerInfo : ITraitInfo
|
||||
{
|
||||
[GrantedConditionReference]
|
||||
[Desc("Condition granted when capturing an actor.")]
|
||||
public readonly string CapturingCondition = null;
|
||||
|
||||
[GrantedConditionReference]
|
||||
[Desc("Condition granted when being captured by another actor.")]
|
||||
public readonly string BeingCapturedCondition = null;
|
||||
|
||||
public virtual object Create(ActorInitializer init) { return new CaptureManager(this); }
|
||||
}
|
||||
|
||||
public class CaptureManager : INotifyCreated, INotifyCapture
|
||||
{
|
||||
readonly CaptureManagerInfo info;
|
||||
ConditionManager conditionManager;
|
||||
|
||||
BitSet<CaptureType> allyCapturableTypes;
|
||||
BitSet<CaptureType> neutralCapturableTypes;
|
||||
BitSet<CaptureType> enemyCapturableTypes;
|
||||
@@ -32,10 +46,24 @@ namespace OpenRA.Mods.Common.Traits
|
||||
IEnumerable<Capturable> enabledCapturable;
|
||||
IEnumerable<Captures> enabledCaptures;
|
||||
|
||||
// Related to a specific capture in process
|
||||
Actor currentTarget;
|
||||
CaptureManager currentTargetManager;
|
||||
int currentTargetDelay;
|
||||
int capturingToken = ConditionManager.InvalidConditionToken;
|
||||
int beingCapturedToken = ConditionManager.InvalidConditionToken;
|
||||
|
||||
public bool BeingCaptured { get; private set; }
|
||||
|
||||
public CaptureManager(CaptureManagerInfo info)
|
||||
{
|
||||
this.info = info;
|
||||
}
|
||||
|
||||
void INotifyCreated.Created(Actor self)
|
||||
{
|
||||
conditionManager = self.TraitOrDefault<ConditionManager>();
|
||||
|
||||
enabledCapturable = self.TraitsImplementing<Capturable>()
|
||||
.ToArray()
|
||||
.Where(Exts.IsTraitEnabled);
|
||||
@@ -121,5 +149,57 @@ namespace OpenRA.Mods.Common.Traits
|
||||
BeingCaptured = true;
|
||||
self.World.AddFrameEndTask(w => BeingCaptured = false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by CaptureActor when the activity is ready to enter and capture the target.
|
||||
/// 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)
|
||||
{
|
||||
if (target != currentTarget)
|
||||
{
|
||||
if (currentTarget != null)
|
||||
CancelCapture(self, currentTarget, currentTargetManager);
|
||||
|
||||
currentTarget = target;
|
||||
currentTargetManager = targetManager;
|
||||
currentTargetDelay = 0;
|
||||
}
|
||||
else
|
||||
currentTargetDelay += 1;
|
||||
|
||||
if (conditionManager != null && !string.IsNullOrEmpty(info.CapturingCondition) &&
|
||||
capturingToken == ConditionManager.InvalidConditionToken)
|
||||
capturingToken = conditionManager.GrantCondition(self, info.CapturingCondition);
|
||||
|
||||
if (targetManager.conditionManager != null && !string.IsNullOrEmpty(targetManager.info.BeingCapturedCondition) &&
|
||||
targetManager.beingCapturedToken == ConditionManager.InvalidConditionToken)
|
||||
targetManager.beingCapturedToken = targetManager.conditionManager.GrantCondition(target, targetManager.info.BeingCapturedCondition);
|
||||
|
||||
foreach (var c in enabledCaptures.OrderBy(c => c.Info.CaptureDelay))
|
||||
if (targetManager.CanBeTargetedBy(target, self, c) && c.Info.CaptureDelay <= currentTargetDelay)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by CaptureActor when the activity finishes or is cancelled
|
||||
/// 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)
|
||||
{
|
||||
if (capturingToken != ConditionManager.InvalidConditionToken)
|
||||
capturingToken = conditionManager.RevokeCondition(self, capturingToken);
|
||||
|
||||
if (targetManager.beingCapturedToken != ConditionManager.InvalidConditionToken)
|
||||
targetManager.beingCapturedToken = targetManager.conditionManager.RevokeCondition(self, targetManager.beingCapturedToken);
|
||||
|
||||
currentTarget = null;
|
||||
currentTargetManager = null;
|
||||
currentTargetDelay = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,9 @@ namespace OpenRA.Mods.Common.Traits
|
||||
[Desc("Sabotage damage expressed as a percentage of maximum target health.")]
|
||||
public readonly int SabotageHPRemoval = 50;
|
||||
|
||||
[Desc("Delay (in ticks) that to wait next to the target before initiating the capture.")]
|
||||
public readonly int CaptureDelay = 0;
|
||||
|
||||
[Desc("Experience granted to the capturing player.")]
|
||||
public readonly int PlayerExperience = 0;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user