Raname GrantConditionOnDeployWithCharge to GrantChargedConditionOnToggle

Also allow deploying without cancelling current activity, and make saboteurs use it

(cherry picked from commit 8b4478260e95170f392ef00c1b06b76dfc29bf2b)
This commit is contained in:
Gustas
2024-12-02 14:14:27 +02:00
committed by Pavel Penev
parent 2ccfa425b2
commit e0d893b736
3 changed files with 84 additions and 70 deletions

View File

@@ -17,13 +17,13 @@ using OpenRA.Traits;
namespace OpenRA.Mods.Common.Traits namespace OpenRA.Mods.Common.Traits
{ {
[Desc("Allow deploying on specified charge to grant a condition for a specified duration.")] [Desc("Grant a condition via player orders for a specified amount of time.")]
public class GrantConditionOnDeployWithChargeInfo : PausableConditionalTraitInfo, IRulesetLoaded public class GrantChargedConditionOnToggleInfo : PausableConditionalTraitInfo, IRulesetLoaded
{ {
[FieldLoader.Require] [FieldLoader.Require]
[GrantedConditionReference] [GrantedConditionReference]
[Desc("The condition to grant after deploying.")] [Desc("The condition to grant when enabled.")]
public readonly string DeployedCondition = null; public readonly string ActivatedCondition = null;
[GrantedConditionReference] [GrantedConditionReference]
[Desc("The condition to grant when charge is above " + nameof(ChargeThreshhold) + ".")] [Desc("The condition to grant when charge is above " + nameof(ChargeThreshhold) + ".")]
@@ -35,7 +35,7 @@ namespace OpenRA.Mods.Common.Traits
[Desc("Cooldown (in ticks) to reach full charge.")] [Desc("Cooldown (in ticks) to reach full charge.")]
public readonly int ChargeDuration = 500; public readonly int ChargeDuration = 500;
[Desc("The amount of charge that needs to be present for deploy to be issued. " + [Desc("The amount of charge that needs to be present to turn on the condition. " +
"If set to -1, threshold is set to full charge. " + "If set to -1, threshold is set to full charge. " +
"If activated without full charge " + nameof(ConditionDuration) + " is percentally smaller.")] "If activated without full charge " + nameof(ConditionDuration) + " is percentally smaller.")]
public readonly int ChargeThreshhold = -1; public readonly int ChargeThreshhold = -1;
@@ -43,30 +43,39 @@ namespace OpenRA.Mods.Common.Traits
[Desc("How long (in ticks) should the condition stay active?")] [Desc("How long (in ticks) should the condition stay active?")]
public readonly int ConditionDuration = 1; public readonly int ConditionDuration = 1;
[Desc("Can " + nameof(DeployedCondition) + " be canceled by followup deploy order?")] [Desc("Can " + nameof(ActivatedCondition) + " be turned off manually?")]
public readonly bool CanCancelCondition = false; public readonly bool CanCancelCondition = false;
[CursorReference] [Desc("Should we interrupt the current activity")]
[Desc("Cursor to display when able to (un)deploy the actor.")] public readonly bool CancelsCurrentActivity = false;
public readonly string DeployCursor = "deploy";
[CursorReference] [CursorReference]
[Desc("Cursor to display when unable to (un)deploy the actor.")] [Desc("Cursor to display when able to trigger a state change.")]
public readonly string DeployBlockedCursor = "deploy-blocked"; public readonly string Cursor = "deploy";
[Desc("Play a randomly selected sound from this list when deploying.")] [CursorReference]
public readonly string[] DeploySounds = null; [Desc("Cursor to display when unable to trigger a state change.")]
public readonly string BlockedCursor = "deploy-blocked";
[Desc("Play a randomly selected sound from this list when undeploying.")] [Desc("Play a randomly selected sound from this list when turning on.")]
public readonly string[] UndeploySounds = null; public readonly string[] ActivationSounds = null;
[Desc("Play a randomly selected sound from this list when turning off.")]
public readonly string[] DeactivattionSounds = null;
[VoiceReference] [VoiceReference]
public readonly string Voice = "Action"; public readonly string Voice = "Action";
public readonly Color ChargingColor = Color.Magenta; [Desc("Color of the charge bar when deactivated.")]
public readonly Color DeployedColor = Color.DarkMagenta; public readonly Color DeactivatedColor = Color.Magenta;
public override object Create(ActorInitializer init) { return new GrantConditionOnDeployWithCharge(this); } [Desc("Color of the charge bar when activated.")]
public readonly Color ActivatedColor = Color.DarkMagenta;
[Desc("Should the charge bar be displayed when not charged or the trait is disabled?")]
public readonly bool DisplayBarWhenEmpty = true;
public override object Create(ActorInitializer init) { return new GrantChargedConditionOnToggle(this); }
public override void RulesetLoaded(Ruleset rules, ActorInfo ai) public override void RulesetLoaded(Ruleset rules, ActorInfo ai)
{ {
@@ -80,37 +89,37 @@ namespace OpenRA.Mods.Common.Traits
} }
} }
public class GrantConditionOnDeployWithCharge : PausableConditionalTrait<GrantConditionOnDeployWithChargeInfo>, public class GrantChargedConditionOnToggle : PausableConditionalTrait<GrantChargedConditionOnToggleInfo>,
IIssueOrder, IResolveOrder, ITick, ISelectionBar, IOrderVoice, ISync, IIssueDeployOrder IIssueOrder, IResolveOrder, ITick, ISelectionBar, IOrderVoice, ISync, IIssueDeployOrder
{ {
[Sync] [Sync]
int chargeTick = 0; int chargeTick = 0;
bool deployed = false; bool isActive = false;
int deployedToken = Actor.InvalidConditionToken; int activatedToken = Actor.InvalidConditionToken;
int chargedToken = Actor.InvalidConditionToken; int chargedToken = Actor.InvalidConditionToken;
readonly int chargeThreshold; readonly int chargeThreshold;
readonly int deployedChargeThreshold; readonly int activatedChargeThreshold;
public GrantConditionOnDeployWithCharge(GrantConditionOnDeployWithChargeInfo info) public GrantChargedConditionOnToggle(GrantChargedConditionOnToggleInfo info)
: base(info) : base(info)
{ {
chargeTick = info.InitialCharge < 0 || info.InitialCharge >= info.ChargeDuration ? Info.ChargeDuration : info.InitialCharge; chargeTick = info.InitialCharge < 0 || info.InitialCharge >= info.ChargeDuration ? Info.ChargeDuration : info.InitialCharge;
// PERF: Cache the conversions. // PERF: Cache the conversions.
chargeThreshold = Info.ChargeThreshhold < 0 || Info.ChargeThreshhold > Info.ChargeDuration ? Info.ChargeDuration : Info.ChargeThreshhold; chargeThreshold = Info.ChargeThreshhold < 0 || Info.ChargeThreshhold > Info.ChargeDuration ? Info.ChargeDuration : Info.ChargeThreshhold;
deployedChargeThreshold = chargeThreshold * Info.ConditionDuration / Info.ChargeDuration; activatedChargeThreshold = chargeThreshold * Info.ConditionDuration / Info.ChargeDuration;
} }
protected override void TraitDisabled(Actor self) protected override void TraitDisabled(Actor self)
{ {
base.TraitDisabled(self); base.TraitDisabled(self);
if (deployed) if (isActive)
Undeploy(self); Deactivate(self);
// Reset charge. // Reset charge.
chargeTick = Info.InitialCharge < 0 || Info.InitialCharge > Info.ChargeDuration ? Info.ChargeDuration : Info.InitialCharge; chargeTick = Info.InitialCharge < 0 || Info.InitialCharge > Info.ChargeDuration ? Info.ChargeDuration : Info.InitialCharge;
@@ -120,7 +129,7 @@ namespace OpenRA.Mods.Common.Traits
public string VoicePhraseForOrder(Actor self, Order order) public string VoicePhraseForOrder(Actor self, Order order)
{ {
return order.OrderString == "DeployWithCharge" ? Info.Voice : null; return order.OrderString == "ActivateCondition" ? Info.Voice : null;
} }
public IEnumerable<IOrderTargeter> Orders public IEnumerable<IOrderTargeter> Orders
@@ -128,14 +137,14 @@ namespace OpenRA.Mods.Common.Traits
get get
{ {
if (!IsTraitDisabled) if (!IsTraitDisabled)
yield return new DeployOrderTargeter("DeployWithCharge", 5, yield return new DeployOrderTargeter("ActivateCondition", 5,
() => CanDeploy() ? Info.DeployCursor : Info.DeployBlockedCursor); () => CanToggle() ? Info.Cursor : Info.BlockedCursor);
} }
} }
public Order IssueOrder(Actor self, IOrderTargeter order, in Target target, bool queued) public Order IssueOrder(Actor self, IOrderTargeter order, in Target target, bool queued)
{ {
if (order.OrderID == "DeployWithCharge") if (order.OrderID == "ActivateCondition")
return new Order(order.OrderID, self, queued); return new Order(order.OrderID, self, queued);
return null; return null;
@@ -143,55 +152,60 @@ namespace OpenRA.Mods.Common.Traits
Order IIssueDeployOrder.IssueDeployOrder(Actor self, bool queued) Order IIssueDeployOrder.IssueDeployOrder(Actor self, bool queued)
{ {
return new Order("DeployWithCharge", self, queued); return new Order("ActivateCondition", self, queued);
} }
bool IIssueDeployOrder.CanIssueDeployOrder(Actor self, bool queued) { return queued || CanDeploy(); } bool IIssueDeployOrder.CanIssueDeployOrder(Actor self, bool queued) { return queued || CanToggle(); }
public void ResolveOrder(Actor self, Order order) public void ResolveOrder(Actor self, Order order)
{ {
if (order.OrderString == "DeployWithCharge") if (order.OrderString != "ActivateCondition")
self.QueueActivity(order.Queued, new DeployForGrantedConditionWithCharge(self, this)); return;
if (order.Queued || Info.CancelsCurrentActivity)
self.QueueActivity(order.Queued, new ToggleChargedCondition(self, this));
else if (CanToggle())
ToggleState(self);
} }
public bool CanDeploy() => !IsTraitDisabled && !IsTraitPaused && ((!deployed && chargeTick >= chargeThreshold) || (deployed && Info.CanCancelCondition)); public bool CanToggle() => !IsTraitDisabled && !IsTraitPaused && ((!isActive && chargeTick >= chargeThreshold) || (isActive && Info.CanCancelCondition));
public void TriggerDeploy(Actor self) public void ToggleState(Actor self)
{ {
if (deployed) if (isActive)
{ {
// Keep the percentage of the unused charge. // Keep the percentage of the unused charge.
chargeTick = chargeTick * Info.ChargeDuration / Info.ConditionDuration; chargeTick = chargeTick * Info.ChargeDuration / Info.ConditionDuration;
Undeploy(self); Deactivate(self);
} }
else else
{ {
// If deployed without full charge, reduce the deploy duration. // If activated without full charge, subtract from the activated duration.
chargeTick = chargeTick * Info.ConditionDuration / Info.ChargeDuration; chargeTick = chargeTick * Info.ConditionDuration / Info.ChargeDuration;
Deploy(self); Activate(self);
} }
} }
void Deploy(Actor self) void Activate(Actor self)
{ {
if (Info.DeploySounds != null && Info.DeploySounds.Length > 0) if (Info.ActivationSounds != null && Info.ActivationSounds.Length > 0)
Game.Sound.Play(SoundType.World, Info.DeploySounds, self.World, self.CenterPosition); Game.Sound.Play(SoundType.World, Info.ActivationSounds, self.World, self.CenterPosition);
if (deployedToken == Actor.InvalidConditionToken) if (activatedToken == Actor.InvalidConditionToken)
deployedToken = self.GrantCondition(Info.DeployedCondition); activatedToken = self.GrantCondition(Info.ActivatedCondition);
deployed = true; isActive = true;
} }
void Undeploy(Actor self) void Deactivate(Actor self)
{ {
if (Info.UndeploySounds != null && Info.UndeploySounds.Length > 0) if (Info.DeactivattionSounds != null && Info.DeactivattionSounds.Length > 0)
Game.Sound.Play(SoundType.World, Info.UndeploySounds, self.World, self.CenterPosition); Game.Sound.Play(SoundType.World, Info.DeactivattionSounds, self.World, self.CenterPosition);
if (deployedToken != Actor.InvalidConditionToken) if (activatedToken != Actor.InvalidConditionToken)
deployedToken = self.RevokeCondition(deployedToken); activatedToken = self.RevokeCondition(activatedToken);
deployed = false; isActive = false;
} }
void ITick.Tick(Actor self) void ITick.Tick(Actor self)
@@ -199,12 +213,12 @@ namespace OpenRA.Mods.Common.Traits
if (IsTraitDisabled || IsTraitPaused) if (IsTraitDisabled || IsTraitPaused)
return; return;
if (deployed) if (isActive)
{ {
if (chargeTick > 0) if (chargeTick > 0)
chargeTick--; chargeTick--;
else else
Undeploy(self); Deactivate(self);
} }
else else
{ {
@@ -214,7 +228,7 @@ namespace OpenRA.Mods.Common.Traits
if (Info.ChargedCondition != null) if (Info.ChargedCondition != null)
{ {
if (chargeTick < (deployed ? deployedChargeThreshold : chargeThreshold)) if (chargeTick < (isActive ? activatedChargeThreshold : chargeThreshold))
{ {
if (chargedToken != Actor.InvalidConditionToken) if (chargedToken != Actor.InvalidConditionToken)
chargedToken = self.RevokeCondition(chargedToken); chargedToken = self.RevokeCondition(chargedToken);
@@ -232,28 +246,28 @@ namespace OpenRA.Mods.Common.Traits
if (IsTraitDisabled) if (IsTraitDisabled)
return 0f; return 0f;
return deployed return isActive
? (float)chargeTick / Info.ConditionDuration ? (float)chargeTick / Info.ConditionDuration
: (float)chargeTick / Info.ChargeDuration; : (float)chargeTick / Info.ChargeDuration;
} }
Color ISelectionBar.GetColor() { return deployed ? Info.DeployedColor : Info.ChargingColor; } Color ISelectionBar.GetColor() { return isActive ? Info.ActivatedColor : Info.DeactivatedColor; }
bool ISelectionBar.DisplayWhenEmpty => false; bool ISelectionBar.DisplayWhenEmpty => Info.DisplayBarWhenEmpty;
} }
public class DeployForGrantedConditionWithCharge : Activity public class ToggleChargedCondition : Activity
{ {
readonly GrantConditionOnDeployWithCharge deploy; readonly GrantChargedConditionOnToggle toggle;
public DeployForGrantedConditionWithCharge(Actor self, GrantConditionOnDeployWithCharge deploy) public ToggleChargedCondition(Actor self, GrantChargedConditionOnToggle toggle)
{ {
this.deploy = deploy; this.toggle = toggle;
} }
protected override void OnFirstRun(Actor self) protected override void OnFirstRun(Actor self)
{ {
if (deploy.CanDeploy()) if (toggle.CanToggle())
deploy.TriggerDeploy(self); toggle.ToggleState(self);
} }
public override IEnumerable<TargetLineNode> TargetLineNodes(Actor self) public override IEnumerable<TargetLineNode> TargetLineNodes(Actor self)

View File

@@ -326,14 +326,14 @@ saboteur:
Flashes: 0 Flashes: 0
EnterBehaviour: Suicide EnterBehaviour: Suicide
-RevealOnFire: -RevealOnFire:
GrantConditionOnDeployWithCharge: GrantChargedConditionOnToggle:
DeployedCondition: deployed ActivatedCondition: cloaked
CanCancelCondition: true CanCancelCondition: true
ChargeDuration: 1250 ChargeDuration: 1250
ChargeThreshhold: 100 ChargeThreshhold: 100
ConditionDuration: 375 ConditionDuration: 375
Cloak: Cloak:
RequiresCondition: deployed RequiresCondition: cloaked
InitialDelay: 0 InitialDelay: 0
CloakDelay: 25 CloakDelay: 25
CloakSound: STEALTH1.WAV CloakSound: STEALTH1.WAV

View File

@@ -446,11 +446,11 @@ MOBILEMP:
RequiresCondition: !inside-tunnel RequiresCondition: !inside-tunnel
Range: 6c0 Range: 6c0
MaxHeightDelta: 3 MaxHeightDelta: 3
GrantConditionOnDeployWithCharge: GrantChargedConditionOnToggle:
Voice: Move Voice: Move
ChargeDuration: 750 ChargeDuration: 750
DeployedCondition: deployed ActivatedCondition: triggered
PauseOnCondition: empdisable PauseOnCondition: empdisable
FireWarheads: FireWarheads:
Weapons: MEMPulse Weapons: MEMPulse
RequiresCondition: deployed && !empdisable RequiresCondition: triggered && !empdisable