New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement GrantPrerequisiteChargeDrainPower logic #16347
Merged
Merged
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
78d9e89
Fix DamageModifier crashes when an actor is demolished.
pchote 916fc8f
Add support for custom SupportPowerInstances.
pchote a26404e
Rename *Time to *Ticks and increase internal resolution.
pchote a74ff92
Allow support powers to override the icon overlay/tooltip labels.
pchote 9409d47
Add GrantPrerequisiteChargeDrainPower and DrainPrerequisitePowerOnDam…
pchote File filter
Filter by extension
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
#region Copyright & License Information | ||
/* | ||
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS) | ||
* This file is part of OpenRA, which is free software. It is made | ||
* available to you under the terms of the GNU General Public License | ||
* as published by the Free Software Foundation, either version 3 of | ||
* the License, or (at your option) any later version. For more | ||
* information, see COPYING. | ||
*/ | ||
#endregion | ||
|
||
using OpenRA.Mods.Common.Traits; | ||
using OpenRA.Traits; | ||
|
||
namespace OpenRA.Mods.Cnc.Traits | ||
{ | ||
[Desc("Converts damage to a charge level of a GrantPrerequisiteChargeDrainPower.")] | ||
public class DrainPrerequisitePowerOnDamageInfo : ConditionalTraitInfo | ||
{ | ||
[Desc("The OrderName of the GrantPrerequisiteChargeDrainPower to drain.")] | ||
public readonly string OrderName = "GrantPrerequisiteChargeDrainPowerInfoOrder"; | ||
|
||
[Desc("Damage is multiplied by this number when converting damage to drain ticks.")] | ||
public readonly int DamageMultiplier = 1; | ||
|
||
[Desc("Damage is divided by this number when converting damage to drain ticks.")] | ||
public readonly int DamageDivisor = 600; | ||
|
||
public override object Create(ActorInitializer init) { return new DrainPrerequisitePowerOnDamage(init.Self, this); } | ||
} | ||
|
||
public class DrainPrerequisitePowerOnDamage : ConditionalTrait<DrainPrerequisitePowerOnDamageInfo>, INotifyOwnerChanged, IDamageModifier | ||
{ | ||
SupportPowerManager spm; | ||
|
||
public DrainPrerequisitePowerOnDamage(Actor self, DrainPrerequisitePowerOnDamageInfo info) | ||
: base(info) { } | ||
|
||
protected override void Created(Actor self) | ||
{ | ||
base.Created(self); | ||
spm = self.Owner.PlayerActor.Trait<SupportPowerManager>(); | ||
} | ||
|
||
void INotifyOwnerChanged.OnOwnerChanged(Actor self, Player oldOwner, Player newOwner) | ||
{ | ||
spm = newOwner.PlayerActor.Trait<SupportPowerManager>(); | ||
} | ||
|
||
int IDamageModifier.GetDamageModifier(Actor self, Damage damage) | ||
{ | ||
if (!IsTraitDisabled && damage != null) | ||
{ | ||
var damageSubTicks = (int)(damage.Value * 100L * Info.DamageMultiplier / Info.DamageDivisor); | ||
|
||
SupportPowerInstance spi; | ||
if (spm.Powers.TryGetValue(Info.OrderName, out spi)) | ||
{ | ||
var dspi = spi as GrantPrerequisiteChargeDrainPower.DischargeableSupportPowerInstance; | ||
if (dspi != null) | ||
dspi.Discharge(damageSubTicks); | ||
} | ||
} | ||
|
||
return 100; | ||
} | ||
} | ||
} |
211 changes: 211 additions & 0 deletions
211
OpenRA.Mods.Cnc/Traits/SupportPowers/GrantPrerequisiteChargeDrainPower.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,211 @@ | ||
#region Copyright & License Information | ||
/* | ||
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS) | ||
* This file is part of OpenRA, which is free software. It is made | ||
* available to you under the terms of the GNU General Public License | ||
* as published by the Free Software Foundation, either version 3 of | ||
* the License, or (at your option) any later version. For more | ||
* information, see COPYING. | ||
*/ | ||
#endregion | ||
|
||
using System.Collections.Generic; | ||
using System.Linq; | ||
using OpenRA.Mods.Common.Traits; | ||
using OpenRA.Traits; | ||
|
||
namespace OpenRA.Mods.Cnc.Traits | ||
{ | ||
[Desc("Grants a prerequisite while discharging at a configurable rate.")] | ||
public class GrantPrerequisiteChargeDrainPowerInfo : SupportPowerInfo, ITechTreePrerequisiteInfo | ||
{ | ||
[Desc("Rate at which the power discharges compared to charging")] | ||
public readonly int DischargeModifier = 300; | ||
|
||
[FieldLoader.Require] | ||
[Desc("The prerequisite type that this provides.")] | ||
public readonly string Prerequisite = null; | ||
|
||
[Translate] | ||
[Desc("Label to display over the support power icon and in its tooltip while the power is active.")] | ||
public readonly string ActiveText = "ACTIVE"; | ||
|
||
[Translate] | ||
[Desc("Label to display over the support power icon and in its tooltip while the power is available but not active.")] | ||
public readonly string AvailableText = "READY"; | ||
|
||
IEnumerable<string> ITechTreePrerequisiteInfo.Prerequisites(ActorInfo info) | ||
{ | ||
yield return Prerequisite; | ||
} | ||
|
||
public override object Create(ActorInitializer init) { return new GrantPrerequisiteChargeDrainPower(init.Self, this); } | ||
} | ||
|
||
public class GrantPrerequisiteChargeDrainPower : SupportPower, ITechTreePrerequisite, INotifyOwnerChanged | ||
{ | ||
readonly GrantPrerequisiteChargeDrainPowerInfo info; | ||
TechTree techTree; | ||
bool active; | ||
|
||
public GrantPrerequisiteChargeDrainPower(Actor self, GrantPrerequisiteChargeDrainPowerInfo info) | ||
: base(self, info) | ||
{ | ||
this.info = info; | ||
} | ||
|
||
protected override void Created(Actor self) | ||
{ | ||
// Special case handling is required for the Player actor. | ||
// Created is called before Player.PlayerActor is assigned, | ||
// so we must query other player traits from self, knowing that | ||
// it refers to the same actor as self.Owner.PlayerActor | ||
var playerActor = self.Info.Name == "player" ? self : self.Owner.PlayerActor; | ||
|
||
techTree = playerActor.Trait<TechTree>(); | ||
|
||
base.Created(self); | ||
} | ||
|
||
void INotifyOwnerChanged.OnOwnerChanged(Actor self, Player oldOwner, Player newOwner) | ||
{ | ||
techTree = newOwner.PlayerActor.Trait<TechTree>(); | ||
active = false; | ||
} | ||
|
||
public override SupportPowerInstance CreateInstance(string key, SupportPowerManager manager) | ||
{ | ||
return new DischargeableSupportPowerInstance(key, info, manager); | ||
} | ||
|
||
public void Activate(Actor self, SupportPowerInstance instance) | ||
{ | ||
active = true; | ||
techTree.ActorChanged(self); | ||
} | ||
|
||
public void Deactivate(Actor self, SupportPowerInstance instance) | ||
{ | ||
active = false; | ||
techTree.ActorChanged(self); | ||
} | ||
|
||
IEnumerable<string> ITechTreePrerequisite.ProvidesPrerequisites | ||
{ | ||
get | ||
{ | ||
if (!active) | ||
yield break; | ||
|
||
yield return info.Prerequisite; | ||
} | ||
} | ||
|
||
public class DischargeableSupportPowerInstance : SupportPowerInstance | ||
{ | ||
// Whether the power is available to activate (even if not fully charged) | ||
bool available; | ||
|
||
// Whether the power is active right now | ||
// Note that this is fundamentally different to SupportPowerInstance.Active | ||
// which has a much closer meaning to available above. | ||
bool active; | ||
|
||
// Additional discharge rate accrued from damage | ||
int additionalDischargeSubTicks = 0; | ||
|
||
public DischargeableSupportPowerInstance(string key, GrantPrerequisiteChargeDrainPowerInfo info, SupportPowerManager manager) | ||
: base(key, info, manager) { } | ||
|
||
void Deactivate() | ||
{ | ||
active = false; | ||
notifiedCharging = false; | ||
|
||
// Fully depleting the charge disables the power until it is again fully charged | ||
if (!Active || remainingSubTicks >= TotalTicks * 100) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IMO not worth it. |
||
available = false; | ||
|
||
foreach (var p in Instances) | ||
((GrantPrerequisiteChargeDrainPower)p).Deactivate(p.Self, this); | ||
} | ||
|
||
public override void Tick() | ||
{ | ||
var orig = remainingSubTicks; | ||
base.Tick(); | ||
|
||
if (Ready) | ||
available = true; | ||
|
||
if (active && !Active) | ||
Deactivate(); | ||
|
||
if (active) | ||
{ | ||
remainingSubTicks = orig + ((GrantPrerequisiteChargeDrainPowerInfo)Info).DischargeModifier + additionalDischargeSubTicks; | ||
additionalDischargeSubTicks = 0; | ||
|
||
if (remainingSubTicks > TotalTicks * 100) | ||
{ | ||
remainingSubTicks = TotalTicks * 100; | ||
Deactivate(); | ||
} | ||
} | ||
} | ||
|
||
public void Discharge(int subTicks) | ||
{ | ||
additionalDischargeSubTicks += subTicks; | ||
} | ||
|
||
public override void Target() | ||
{ | ||
if (available && Active) | ||
Manager.Self.World.IssueOrder(new Order(Key, Manager.Self, false) { ExtraData = active ? 0U : 1U }); | ||
} | ||
|
||
public override void Activate(Order order) | ||
{ | ||
if (active && order.ExtraData == 0) | ||
{ | ||
Deactivate(); | ||
return; | ||
} | ||
|
||
if (!available || order.ExtraData != 1) | ||
return; | ||
|
||
var power = Instances.FirstOrDefault(i => !i.IsTraitPaused); | ||
if (power == null) | ||
return; | ||
|
||
active = true; | ||
|
||
// Only play the activation sound once! | ||
power.PlayLaunchSounds(); | ||
|
||
foreach (var p in Instances) | ||
((GrantPrerequisiteChargeDrainPower)p).Activate(p.Self, this); | ||
} | ||
|
||
public override string IconOverlayTextOverride() | ||
{ | ||
var info = Info as GrantPrerequisiteChargeDrainPowerInfo; | ||
if (info == null || !Active) | ||
return null; | ||
|
||
return active ? info.ActiveText : available ? info.AvailableText : null; | ||
} | ||
|
||
public override string TooltipTimeTextOverride() | ||
{ | ||
var info = Info as GrantPrerequisiteChargeDrainPowerInfo; | ||
if (info == null || !Active) | ||
return null; | ||
|
||
return active ? info.ActiveText : available ? info.AvailableText : null; | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Guard for overflow?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The overflow is already guarded by casting to a long with the
100L
.