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/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; }