diff --git a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj index af2393b511..f210809632 100644 --- a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj +++ b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj @@ -299,6 +299,7 @@ + diff --git a/OpenRA.Mods.Common/Traits/CustomBuildTimeValue.cs b/OpenRA.Mods.Common/Traits/CustomBuildTimeValue.cs index 4eae571a39..9c81615fc5 100644 --- a/OpenRA.Mods.Common/Traits/CustomBuildTimeValue.cs +++ b/OpenRA.Mods.Common/Traits/CustomBuildTimeValue.cs @@ -25,6 +25,8 @@ namespace OpenRA.Mods.Common.Traits public static class CustomBuildTimeValueExts { + const int FramesPerMin = 25 * 60; + public static int GetBuildTime(this ActorInfo a) { var csv = a.TraitInfoOrDefault(); @@ -32,11 +34,7 @@ namespace OpenRA.Mods.Common.Traits return csv.Value; var cost = a.HasTraitInfo() ? a.TraitInfo().Cost : 0; - var time = cost - * (25 * 60) /* frames per min */ - / 1000; - return - time; + return cost * FramesPerMin / 1000; } } } diff --git a/OpenRA.Mods.Common/Traits/Player/InsufficientFundsWarning.cs b/OpenRA.Mods.Common/Traits/Player/InsufficientFundsWarning.cs new file mode 100644 index 0000000000..e0c44a2e53 --- /dev/null +++ b/OpenRA.Mods.Common/Traits/Player/InsufficientFundsWarning.cs @@ -0,0 +1,53 @@ +#region Copyright & License Information +/* + * Copyright 2007-2016 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. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.Traits; + +namespace OpenRA.Mods.Common.Traits +{ + [Desc("Provides the player with an audible warning when they run out of money while producing.")] + public class InsufficientFundsWarningInfo : ITraitInfo, Requires + { + [Desc("The speech to play for the warning.")] + public readonly string Notification = "InsufficientFunds"; + + public object Create(ActorInitializer init) { return new InsufficientFundsWarning(this); } + } + + public class InsufficientFundsWarning : INotifyInsufficientFunds + { + readonly InsufficientFundsWarningInfo info; + + bool played; + + public InsufficientFundsWarning(InsufficientFundsWarningInfo info) + { + this.info = info; + } + + void INotifyInsufficientFunds.InsufficientFunds(Actor self) + { + Game.RunAfterTick(() => + { + if (played) + return; + + played = true; + var owner = self.Owner; + Game.Sound.PlayNotification(self.World.Map.Rules, owner, "Speech", info.Notification, owner.Faction.InternalName); + }); + } + + void INotifyInsufficientFunds.SufficientFunds(Actor self) + { + played = false; + } + } +} diff --git a/OpenRA.Mods.Common/Traits/Player/ProductionQueue.cs b/OpenRA.Mods.Common/Traits/Player/ProductionQueue.cs index 7fbb6b25a8..a7b3d2f86d 100644 --- a/OpenRA.Mods.Common/Traits/Player/ProductionQueue.cs +++ b/OpenRA.Mods.Common/Traits/Player/ProductionQueue.cs @@ -415,8 +415,12 @@ namespace OpenRA.Mods.Common.Traits public bool Started { get; private set; } public int Slowdown { get; private set; } + readonly INotifyInsufficientFunds[] insufficientFunds; + readonly Player owner; readonly PowerManager pm; + bool insufficientFundsPlayed; + public ProductionItem(ProductionQueue queue, string item, int cost, PowerManager pm, Action onComplete) { Item = item; @@ -425,6 +429,8 @@ namespace OpenRA.Mods.Common.Traits OnComplete = onComplete; Queue = queue; this.pm = pm; + owner = queue.Actor.Owner; + insufficientFunds = owner.PlayerActor.TraitsImplementing().ToArray(); } public void Tick(PlayerResources pr) @@ -435,6 +441,13 @@ namespace OpenRA.Mods.Common.Traits if (time > 0) RemainingTime = TotalTime = time; + // Don't play a QueuedAudio notification when we can't start building (because we don't have the money to) + // Also don't play it when the time to build is actually 0 (i.e. normally dev cheats) + // to prevent overlapping with the ReadyAudio notification + var initialCost = RemainingCost / RemainingTime; + if (time != 0 && initialCost != 0 && pr.Cash + pr.Resources > initialCost) + Game.Sound.PlayNotification(owner.World.Map.Rules, owner, "Speech", Queue.Info.QueuedAudio, owner.Faction.InternalName); + Started = true; } @@ -459,7 +472,22 @@ namespace OpenRA.Mods.Common.Traits var costThisFrame = RemainingCost / RemainingTime; if (costThisFrame != 0 && !pr.TakeCash(costThisFrame)) + { + if (!insufficientFundsPlayed) + { + insufficientFundsPlayed = true; + foreach (var funds in insufficientFunds) + funds.InsufficientFunds(owner.PlayerActor); + } + return; + } + + if (insufficientFundsPlayed) + insufficientFundsPlayed = false; + + foreach (var funds in insufficientFunds) + funds.SufficientFunds(owner.PlayerActor); RemainingCost -= costThisFrame; RemainingTime -= 1; diff --git a/OpenRA.Mods.Common/TraitsInterfaces.cs b/OpenRA.Mods.Common/TraitsInterfaces.cs index d20f43c58e..8f33c63572 100644 --- a/OpenRA.Mods.Common/TraitsInterfaces.cs +++ b/OpenRA.Mods.Common/TraitsInterfaces.cs @@ -124,4 +124,11 @@ namespace OpenRA.Mods.Common.Traits bool AdjacentWallCanConnect(Actor self, CPos wallLocation, string wallType, out CVec facing); void SetDirty(); } + + [RequireExplicitImplementation] + interface INotifyInsufficientFunds + { + void InsufficientFunds(Actor self); + void SufficientFunds(Actor self); + } } diff --git a/OpenRA.Mods.Common/Widgets/ProductionPaletteWidget.cs b/OpenRA.Mods.Common/Widgets/ProductionPaletteWidget.cs index 34bc7e568d..3ea99d1d53 100644 --- a/OpenRA.Mods.Common/Widgets/ProductionPaletteWidget.cs +++ b/OpenRA.Mods.Common/Widgets/ProductionPaletteWidget.cs @@ -233,7 +233,6 @@ namespace OpenRA.Mods.Common.Widgets { // Queue a new item Game.Sound.Play(TabClick); - Game.Sound.PlayNotification(World.Map.Rules, World.LocalPlayer, "Speech", CurrentQueue.Info.QueuedAudio, World.LocalPlayer.Faction.InternalName); World.IssueOrder(Order.StartProduction(CurrentQueue.Actor, icon.Name, handleCount)); return true; } diff --git a/mods/d2k/rules/player.yaml b/mods/d2k/rules/player.yaml index b074ca691d..d34531246a 100644 --- a/mods/d2k/rules/player.yaml +++ b/mods/d2k/rules/player.yaml @@ -86,3 +86,4 @@ Player: GlobalUpgradeManager: ResourceStorageWarning: AdviceInterval: 26 + InsufficientFundsWarning: diff --git a/mods/ra/rules/player.yaml b/mods/ra/rules/player.yaml index d79c8d0e33..e433ae8e8a 100644 --- a/mods/ra/rules/player.yaml +++ b/mods/ra/rules/player.yaml @@ -72,3 +72,4 @@ Player: Image: iconchevrons Sequence: veteran ResourceStorageWarning: + InsufficientFundsWarning: diff --git a/mods/ts/rules/player.yaml b/mods/ts/rules/player.yaml index 89a14b8942..141e5d8617 100644 --- a/mods/ts/rules/player.yaml +++ b/mods/ts/rules/player.yaml @@ -50,3 +50,4 @@ Player: PlayerStatistics: PlaceBeacon: ResourceStorageWarning: + InsufficientFundsWarning: