diff --git a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj index 9d7c5e8589..0f6bdf8672 100644 --- a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj +++ b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj @@ -332,6 +332,7 @@ + diff --git a/OpenRA.Mods.Common/Traits/CashTrickler.cs b/OpenRA.Mods.Common/Traits/CashTrickler.cs index bbc181e704..34df31a95a 100644 --- a/OpenRA.Mods.Common/Traits/CashTrickler.cs +++ b/OpenRA.Mods.Common/Traits/CashTrickler.cs @@ -9,58 +9,87 @@ */ #endregion +using System; using OpenRA.Mods.Common.Effects; using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits { [Desc("Lets the actor generate cash in a set periodic time.")] - class CashTricklerInfo : ITraitInfo + public class CashTricklerInfo : ConditionalTraitInfo { [Desc("Number of ticks to wait between giving money.")] - public readonly int Period = 50; + public readonly int Interval = 50; + [Desc("Amount of money to give each time.")] public readonly int Amount = 15; - [Desc("Whether to show the cash tick indicators (+$15 rising from actor).")] - public readonly bool ShowTicks = true; - [Desc("Amount of money awarded for capturing the actor.")] - public readonly int CaptureAmount = 0; - public object Create(ActorInitializer init) { return new CashTrickler(this); } + [Desc("Whether to show the cash tick indicators rising from the actor.")] + public readonly bool ShowTicks = true; + + [Desc("How long to show the cash tick indicator when enabled.")] + public readonly int DisplayDuration = 30; + + public override object Create(ActorInitializer init) { return new CashTrickler(this); } } - class CashTrickler : ITick, ISync, INotifyCapture + public class CashTrickler : ConditionalTrait, ITick, ISync, INotifyCreated, INotifyOwnerChanged { readonly CashTricklerInfo info; + PlayerResources resources; [Sync] int ticks; + public CashTrickler(CashTricklerInfo info) + : base(info) { this.info = info; } - public void Tick(Actor self) + void INotifyCreated.Created(Actor self) { + resources = self.Owner.PlayerActor.Trait(); + } + + void INotifyOwnerChanged.OnOwnerChanged(Actor self, Player oldOwner, Player newOwner) + { + resources = newOwner.PlayerActor.Trait(); + } + + void ITick.Tick(Actor self) + { + if (IsTraitDisabled) + return; + if (--ticks < 0) { - ticks = info.Period; - self.Owner.PlayerActor.Trait().GiveCash(info.Amount); - MaybeAddCashTick(self, info.Amount); + ticks = info.Interval; + ModifyCash(self, self.Owner, info.Amount); } } - public void OnCapture(Actor self, Actor captor, Player oldOwner, Player newOwner) + void AddCashTick(Actor self, int amount) { - if (info.CaptureAmount > 0) + self.World.AddFrameEndTask(w => w.Add( + new FloatingText(self.CenterPosition, self.Owner.Color.RGB, FloatingText.FormatCashTick(amount), info.DisplayDuration))); + } + + void ModifyCash(Actor self, Player newOwner, int amount) + { + if (amount < 0) { - newOwner.PlayerActor.Trait().GiveCash(info.CaptureAmount); - MaybeAddCashTick(self, info.CaptureAmount); - } - } + // Check whether the amount of cash to be removed would exceed available player cash, in that case only remove all the player cash + var drain = Math.Min(resources.Cash + resources.Resources, -amount); + resources.TakeCash(drain); - void MaybeAddCashTick(Actor self, int amount) - { - if (info.ShowTicks) - self.World.AddFrameEndTask(w => w.Add(new FloatingText(self.CenterPosition, self.Owner.Color.RGB, FloatingText.FormatCashTick(amount), 30))); + if (info.ShowTicks) + AddCashTick(self, -drain); + } + else + { + resources.GiveCash(amount); + if (info.ShowTicks) + AddCashTick(self, amount); + } } } } diff --git a/OpenRA.Mods.Common/Traits/GivesCashOnCapture.cs b/OpenRA.Mods.Common/Traits/GivesCashOnCapture.cs new file mode 100644 index 0000000000..3e6d572ac7 --- /dev/null +++ b/OpenRA.Mods.Common/Traits/GivesCashOnCapture.cs @@ -0,0 +1,70 @@ +#region Copyright & License Information +/* + * Copyright 2007-2017 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; +using OpenRA.Mods.Common.Effects; +using OpenRA.Traits; + +namespace OpenRA.Mods.Common.Traits +{ + [Desc("Lets the actor grant cash when captured.")] + public class GivesCashOnCaptureInfo : ConditionalTraitInfo + { + [Desc("Whether to show the cash tick indicators rising from the actor.")] + public readonly bool ShowTicks = true; + + [Desc("How long to show the Amount tick indicator when enabled.")] + public readonly int DisplayDuration = 30; + + [Desc("Amount of money awarded for capturing the actor.")] + public readonly int Amount = 0; + + public override object Create(ActorInitializer init) { return new GivesCashOnCapture(this); } + } + + public class GivesCashOnCapture : ConditionalTrait, INotifyCapture + { + readonly GivesCashOnCaptureInfo info; + + public GivesCashOnCapture(GivesCashOnCaptureInfo info) + : base(info) + { + this.info = info; + } + + void INotifyCapture.OnCapture(Actor self, Actor captor, Player oldOwner, Player newOwner) + { + if (IsTraitDisabled) + return; + + var resources = newOwner.PlayerActor.Trait(); + var amount = info.Amount; + + if (amount < 0) + { + // Check whether the amount of cash to be removed would exceed available player cash, in that case only remove all the player cash + amount = Math.Min(resources.Cash + resources.Resources, -amount); + resources.TakeCash(amount); + + // For correct cash tick display + amount = -amount; + } + else + resources.GiveCash(amount); + + if (!info.ShowTicks) + return; + + self.World.AddFrameEndTask(w => w.Add( + new FloatingText(self.CenterPosition, self.Owner.Color.RGB, FloatingText.FormatCashTick(amount), info.DisplayDuration))); + } + } +} diff --git a/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs b/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs index 6a3715c6f1..c200197044 100644 --- a/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs +++ b/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs @@ -719,6 +719,33 @@ namespace OpenRA.Mods.Common.UtilityCommands } } + // Capture bonus was decoupled from CashTrickler to a separate trait. + if (engineVersion < 20170108 && depth == 0) + { + var trickler = node.Value.Nodes.FirstOrDefault(n => n.Key == "CashTrickler"); + if (trickler != null) + { + var capture = trickler.Value.Nodes.FirstOrDefault(n => n.Key == "CaptureAmount"); + if (capture != null) + { + var gcoc = new MiniYamlNode("GivesCashOnCapture", ""); + gcoc.Value.Nodes.Add(capture); + trickler.Value.Nodes.Remove(capture); + + var show = trickler.Value.Nodes.FirstOrDefault(n => n.Key == "ShowTicks"); + if (show != null) + gcoc.Value.Nodes.Add(show); + + node.Value.Nodes.Add(gcoc); + RenameNodeKey(capture, "Amount"); + } + + var period = trickler.Value.Nodes.FirstOrDefault(n => n.Key == "Period"); + if (period != null) + period.Key = "Interval"; + } + } + UpgradeActorRules(modData, engineVersion, ref node.Value.Nodes, node, depth + 1); } diff --git a/mods/ra/maps/bomber-john/rules.yaml b/mods/ra/maps/bomber-john/rules.yaml index 2d92b36338..e4fd0104ac 100644 --- a/mods/ra/maps/bomber-john/rules.yaml +++ b/mods/ra/maps/bomber-john/rules.yaml @@ -91,7 +91,7 @@ MNLYR: Offset: 0,0 Facing: 96 CashTrickler: - Period: 150 + Interval: 150 Amount: 20 RenderSprites: Image: MNLY @@ -108,7 +108,7 @@ FTUR: MustBeDestroyed: RequiredForShortGame: true CashTrickler: - Period: 150 + Interval: 150 Amount: 30 ChronoshiftPower: Icon: chrono diff --git a/mods/ra/maps/fort-lonestar/rules.yaml b/mods/ra/maps/fort-lonestar/rules.yaml index 2c2183987f..7a6eb009b9 100644 --- a/mods/ra/maps/fort-lonestar/rules.yaml +++ b/mods/ra/maps/fort-lonestar/rules.yaml @@ -117,7 +117,7 @@ OILB: RevealsShroud: Range: 3c0 CashTrickler: - Period: 250 + Interval: 250 Amount: 50 MOBILETENT: diff --git a/mods/ra/rules/civilian.yaml b/mods/ra/rules/civilian.yaml index ddad7f75cf..22c3ae0d59 100644 --- a/mods/ra/rules/civilian.yaml +++ b/mods/ra/rules/civilian.yaml @@ -364,15 +364,16 @@ OILB: ExternalCapturableBar: EngineerRepairable: CashTrickler: - Period: 375 + Interval: 375 Amount: 100 - CaptureAmount: 100 Tooltip: Name: Oil Derrick Explodes: Weapon: BarrelExplode GpsDot: String: Oil + GivesCashOnCapture: + Amount: 100 BR1: Inherits: ^Bridge