diff --git a/OpenRA.Game/OpenRA.Game.csproj b/OpenRA.Game/OpenRA.Game.csproj index 5f735d978c..7164e71fec 100755 --- a/OpenRA.Game/OpenRA.Game.csproj +++ b/OpenRA.Game/OpenRA.Game.csproj @@ -1,4 +1,4 @@ - + Debug @@ -227,6 +227,7 @@ + diff --git a/OpenRA.Game/Traits/Player/ClassicProductionQueue.cs b/OpenRA.Game/Traits/Player/ClassicProductionQueue.cs index 8162e06b50..7492c72698 100644 --- a/OpenRA.Game/Traits/Player/ClassicProductionQueue.cs +++ b/OpenRA.Game/Traits/Player/ClassicProductionQueue.cs @@ -15,7 +15,7 @@ using OpenRA.FileFormats; namespace OpenRA.Traits { - public class ClassicProductionQueueInfo : ProductionQueueInfo, ITraitPrerequisite + public class ClassicProductionQueueInfo : ProductionQueueInfo, ITraitPrerequisite, ITraitPrerequisite, ITraitPrerequisite { public override object Create(ActorInitializer init) { return new ClassicProductionQueue(init.self, this); } } diff --git a/OpenRA.Game/Traits/Player/PlayerResources.cs b/OpenRA.Game/Traits/Player/PlayerResources.cs index 79da09457b..030deda103 100644 --- a/OpenRA.Game/Traits/Player/PlayerResources.cs +++ b/OpenRA.Game/Traits/Player/PlayerResources.cs @@ -45,17 +45,53 @@ namespace OpenRA.Traits public int OreCapacity; [Sync] public int DisplayOre; + + public float GetSiloFullness() { return (float)Ore / OreCapacity; } + + public void GiveOre(int num) + { + Ore += num; + + if (Ore > OreCapacity) + { + nextSiloAdviceTime = 0; + Ore = OreCapacity; + } + } - [Sync] - public int PowerProvided; - [Sync] - public int PowerDrained; + public bool TakeOre(int num) + { + if (Ore < num) return false; + Ore -= num; + + return true; + } + public void GiveCash(int num) + { + Cash += num; + } + + public bool TakeCash(int num) + { + if (Cash + Ore < num) return false; + + // Spend ore before cash + Ore -= num; + if (Ore < 0) + { + Cash += Ore; + Ore = 0; + } + + return true; + } + const float displayCashFracPerFrame = .07f; const int displayCashDeltaPerFrame = 37; int nextSiloAdviceTime = 0; - void TickOre(Actor self) + public void Tick(Actor self) { OreCapacity = self.World.Queries.OwnedBy[Owner].WithTrait() .Sum(a => a.Trait.Capacity); @@ -102,91 +138,5 @@ namespace OpenRA.Traits Sound.PlayToPlayer(self.Owner, eva.CashTickDown); } } - - int nextPowerAdviceTime = 0; - void TickPower() - { - var oldBalance = PowerProvided - PowerDrained; - - PowerProvided = 0; - PowerDrained = 0; - - var myBuildings = Owner.World.Queries.OwnedBy[Owner].WithTrait(); - - foreach (var a in myBuildings) - { - var q = a.Trait.GetPowerUsage(); - if (q > 0) - PowerProvided += q; - else - PowerDrained -= q; - } - - if (PowerProvided - PowerDrained < 0) - if (PowerProvided - PowerDrained != oldBalance) - nextPowerAdviceTime = 0; - - if (--nextPowerAdviceTime <= 0) - { - if (PowerProvided - PowerDrained < 0) - Owner.GiveAdvice(Rules.Info["world"].Traits.Get().LowPower); - - nextPowerAdviceTime = AdviceInterval; - } - } - - public PowerState GetPowerState() - { - if (PowerProvided >= PowerDrained) return PowerState.Normal; - if (PowerProvided > PowerDrained / 2) return PowerState.Low; - return PowerState.Critical; - } - - public float GetSiloFullness() { return (float)Ore / OreCapacity; } - - public void GiveOre(int num) - { - Ore += num; - - if (Ore > OreCapacity) - { - nextSiloAdviceTime = 0; - Ore = OreCapacity; - } - } - - public bool TakeOre(int num) - { - if (Ore < num) return false; - Ore -= num; - - return true; - } - - public void GiveCash(int num) - { - Cash += num; - } - - public bool TakeCash(int num) - { - if (Cash + Ore < num) return false; - - // Spend ore before cash - Ore -= num; - if (Ore < 0) - { - Cash += Ore; - Ore = 0; - } - - return true; - } - - public void Tick(Actor self) - { - TickPower(); - TickOre(self); - } } } diff --git a/OpenRA.Game/Traits/Player/PowerManager.cs b/OpenRA.Game/Traits/Player/PowerManager.cs new file mode 100644 index 0000000000..4b70d3e9cf --- /dev/null +++ b/OpenRA.Game/Traits/Player/PowerManager.cs @@ -0,0 +1,108 @@ +#region Copyright & License Information +/* + * Copyright 2007-2010 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 LICENSE. + */ +#endregion + +using System; +using System.Linq; +using System.Collections.Generic; + +namespace OpenRA.Traits +{ + public class PowerManagerInfo : ITraitInfo + { + public readonly int AdviceInterval = 250; + public object Create(ActorInitializer init) { return new PowerManager(init, this); } + } + + public class PowerManager : ITick + { + PowerManagerInfo Info; + Player Player; + + Dictionary PowerDrain = new Dictionary(); + [Sync] int totalProvided; + public int PowerProvided { get { return totalProvided; } } + + [Sync] int totalDrained; + public int PowerDrained { get { return totalDrained; } } + + public PowerManager(ActorInitializer init, PowerManagerInfo info) + { + Info = info; + Player = init.self.Owner; + + init.world.ActorAdded += ActorAdded; + init.world.ActorRemoved += ActorRemoved; + } + + public void ActorAdded(Actor a) + { + if (a.Owner != Player || !a.HasTrait()) + return; + + PowerDrain.Add(a, a.Trait().GetPowerUsage()); + UpdateTotals(); + } + + public void UpdateActor(Actor a, int newPower) + { + if (a.Owner != Player || !a.HasTrait()) + return; + + PowerDrain[a] = newPower; + UpdateTotals(); + } + + public void ActorRemoved(Actor a) + { + if (a.Owner != Player || !a.HasTrait()) + return; + + PowerDrain.Remove(a); + UpdateTotals(); + } + + void UpdateTotals() + { + foreach (var p in PowerDrain.Values) + { + if (p > 0) + totalProvided += p; + else + totalDrained -= p; + } + } + + int nextPowerAdviceTime = 0; + bool wasLowPower = false; + public void Tick(Actor self) + { + var lowPower = totalProvided < totalDrained; + if (lowPower && !wasLowPower) + nextPowerAdviceTime = 0; + wasLowPower = lowPower; + + + if (--nextPowerAdviceTime <= 0) + { + if (lowPower) + Player.GiveAdvice(Rules.Info["world"].Traits.Get().LowPower); + + nextPowerAdviceTime = Info.AdviceInterval; + } + } + + public PowerState GetPowerState() + { + if (PowerProvided >= PowerDrained) return PowerState.Normal; + if (PowerProvided > PowerDrained / 2) return PowerState.Low; + return PowerState.Critical; + } + } +} diff --git a/OpenRA.Game/Traits/Player/ProductionQueue.cs b/OpenRA.Game/Traits/Player/ProductionQueue.cs index 5ab1c0927a..3c6fa50ffb 100644 --- a/OpenRA.Game/Traits/Player/ProductionQueue.cs +++ b/OpenRA.Game/Traits/Player/ProductionQueue.cs @@ -26,6 +26,8 @@ namespace OpenRA.Traits { public readonly Actor self; public ProductionQueueInfo Info; + readonly PowerManager PlayerPower; + readonly PlayerResources PlayerResources; // TODO: sync these // A list of things we are currently building @@ -38,7 +40,9 @@ namespace OpenRA.Traits { this.self = self; this.Info = info; - + PlayerResources = playerActor.Trait(); + PlayerPower = playerActor.Trait(); + var ttc = playerActor.Trait(); foreach (var a in AllBuildables(Info.Type)) @@ -119,7 +123,7 @@ namespace OpenRA.Traits FinishProduction(); } if( Queue.Count > 0 ) - Queue[ 0 ].Tick( self.Owner ); + Queue[ 0 ].Tick( PlayerResources, PlayerPower ); } public void ResolveOrder( Actor self, Order order ) @@ -249,7 +253,6 @@ namespace OpenRA.Traits public bool Paused = false, Done = false; public Action OnComplete; - int slowdown = 0; public ProductionItem(ProductionQueue queue, string item, int time, int cost, Action onComplete) @@ -264,7 +267,7 @@ namespace OpenRA.Traits Log.Write("debug", "new ProductionItem: {0} time={1} cost={2}", item, time, cost); } - public void Tick(Player player) + public void Tick(PlayerResources pr, PowerManager pm) { if (Done) { @@ -274,7 +277,7 @@ namespace OpenRA.Traits if (Paused) return; - if (player.PlayerActor.Trait().GetPowerState() != PowerState.Normal) + if (pm.GetPowerState() != PowerState.Normal) { if (--slowdown <= 0) slowdown = Queue.Info.LowPowerSlowdown; @@ -283,7 +286,7 @@ namespace OpenRA.Traits } var costThisFrame = RemainingCost / RemainingTime; - if (costThisFrame != 0 && !player.PlayerActor.Trait().TakeCash(costThisFrame)) return; + if (costThisFrame != 0 && !pr.TakeCash(costThisFrame)) return; RemainingCost -= costThisFrame; RemainingTime -= 1; if (RemainingTime > 0) return; diff --git a/OpenRA.Game/Traits/SupportPower.cs b/OpenRA.Game/Traits/SupportPower.cs index e9c186b251..a4ea6cb78f 100644 --- a/OpenRA.Game/Traits/SupportPower.cs +++ b/OpenRA.Game/Traits/SupportPower.cs @@ -12,7 +12,7 @@ using System.Linq; namespace OpenRA.Traits { - public abstract class SupportPowerInfo : ITraitInfo, ITraitPrerequisite + public abstract class SupportPowerInfo : ITraitInfo, ITraitPrerequisite, ITraitPrerequisite { public readonly bool RequiresPower = true; public readonly bool OneShot = false; @@ -52,12 +52,14 @@ namespace OpenRA.Traits bool notifiedCharging; bool notifiedReady; + readonly PowerManager PlayerPower; public SupportPower(Actor self, SupportPowerInfo info) { Info = info; RemainingTime = TotalTime; Self = self; Owner = self.Owner; + PlayerPower = self.Trait(); effectivePrereq = Info.Prerequisites .Select(a => a.ToLowerInvariant()).ToArray(); @@ -98,7 +100,7 @@ namespace OpenRA.Traits bool IsPowered() { if (effectivePrereq.Count() == 0) - return Owner.PlayerActor.Trait().GetPowerState() == PowerState.Normal; + return PlayerPower.GetPowerState() == PowerState.Normal; // Takes 0.3ms on pchote's machine -- calling it every tick for every active special power is retarded var buildings = TechTree.GatherBuildings(Owner); diff --git a/OpenRA.Mods.RA/HackyAI.cs b/OpenRA.Mods.RA/HackyAI.cs index 229d88be77..5904631a43 100644 --- a/OpenRA.Mods.RA/HackyAI.cs +++ b/OpenRA.Mods.RA/HackyAI.cs @@ -32,6 +32,8 @@ namespace OpenRA.Mods.RA int ticks; Player p; PlayerResources playerResources; + PowerManager playerPower; + int2 baseCenter; XRandom random = new XRandom(); //we do not use the synced random number generator. @@ -70,6 +72,7 @@ namespace OpenRA.Mods.RA enabled = true; playerResources = p.PlayerActor.Trait(); + playerPower = p.PlayerActor.Trait(); } int GetPowerProvidedBy(ActorInfo building) @@ -90,7 +93,7 @@ namespace OpenRA.Mods.RA { var buildableThings = queue.BuildableItems(); - if (playerResources.PowerProvided <= playerResources.PowerDrained * 1.2) /* try to maintain 20% excess power */ + if (playerPower.PowerProvided <= playerPower.PowerDrained * 1.2) /* try to maintain 20% excess power */ { /* find the best thing we can build which produces power */ var best = buildableThings.Where(a => GetPowerProvidedBy(a) > 0) diff --git a/OpenRA.Mods.RA/OreRefinery.cs b/OpenRA.Mods.RA/OreRefinery.cs index 775ce7fdf6..3ca05b4168 100644 --- a/OpenRA.Mods.RA/OreRefinery.cs +++ b/OpenRA.Mods.RA/OreRefinery.cs @@ -33,7 +33,8 @@ namespace OpenRA.Mods.RA { readonly Actor self; readonly OreRefineryInfo Info; - readonly PlayerResources Player; + readonly PlayerResources PlayerResources; + readonly PowerManager PlayerPower; List LinkedHarv; [Sync] @@ -45,7 +46,9 @@ namespace OpenRA.Mods.RA { this.self = self; Info = info; - Player = self.Owner.PlayerActor.Trait (); + PlayerResources = self.Owner.PlayerActor.Trait(); + PlayerPower = self.Owner.PlayerActor.Trait(); + LinkedHarv = new List (); } @@ -63,7 +66,7 @@ namespace OpenRA.Mods.RA public void GiveOre (int amount) { if (!Info.LocalStorage) - Player.GiveOre(amount); + PlayerResources.GiveOre(amount); else { Ore += amount; @@ -80,14 +83,14 @@ namespace OpenRA.Mods.RA if (--nextProcessTime <= 0) { // Convert resources to cash int amount = Math.Min (Ore, Info.ProcessAmount); - amount = Math.Min (amount, Player.OreCapacity - Player.Ore); + amount = Math.Min (amount, PlayerResources.OreCapacity - PlayerResources.Ore); if (amount > 0) { Ore -= amount; - Player.GiveOre (amount); + PlayerResources.GiveOre (amount); } - nextProcessTime = (Player.GetPowerState() == PowerState.Normal)? + nextProcessTime = (PlayerPower.GetPowerState() == PowerState.Normal)? Info.ProcessTick : Info.LowPowerProcessTick ; } } diff --git a/OpenRA.Mods.RA/RequiresPower.cs b/OpenRA.Mods.RA/RequiresPower.cs index f60d06a278..bf0effc9dd 100644 --- a/OpenRA.Mods.RA/RequiresPower.cs +++ b/OpenRA.Mods.RA/RequiresPower.cs @@ -20,14 +20,16 @@ namespace OpenRA.Mods.RA class RequiresPower : IDisable { readonly Actor self; + readonly PowerManager power; public RequiresPower( Actor self ) { this.self = self; + power = self.Owner.PlayerActor.Trait(); } public bool Disabled { - get { return (self.Owner.PlayerActor.Trait().GetPowerState() != PowerState.Normal); } + get { return (power.GetPowerState() != PowerState.Normal); } } } } diff --git a/OpenRA.Mods.RA/Widgets/BuildPaletteWidget.cs b/OpenRA.Mods.RA/Widgets/BuildPaletteWidget.cs index 536126f37f..119e090204 100755 --- a/OpenRA.Mods.RA/Widgets/BuildPaletteWidget.cs +++ b/OpenRA.Mods.RA/Widgets/BuildPaletteWidget.cs @@ -46,7 +46,7 @@ namespace OpenRA.Mods.RA.Widgets public readonly string BuildPaletteOpen = "bleep13.aud"; public readonly string BuildPaletteClose = "bleep13.aud"; public readonly string TabClick = "ramenu1.aud"; - + public BuildPaletteWidget() : base() { } public override void Initialize() @@ -449,11 +449,12 @@ namespace OpenRA.Mods.RA.Widgets p.ToInt2() + new int2(5, 5), Color.White); var resources = pl.PlayerActor.Trait(); + var power = pl.PlayerActor.Trait(); DrawRightAligned("${0}".F(cost), pos + new int2(-5, 5), (resources.DisplayCash + resources.DisplayOre >= cost ? Color.White : Color.Red )); - var lowpower = resources.GetPowerState() != PowerState.Normal; + var lowpower = power.GetPowerState() != PowerState.Normal; var time = CurrentQueue.GetBuildTime(info.Name) * ((lowpower)? CurrentQueue.Info.LowPowerSlowdown : 1); DrawRightAligned(WorldUtils.FormatTime(time), pos + new int2(-5, 35), lowpower ? Color.Red: Color.White); @@ -461,7 +462,7 @@ namespace OpenRA.Mods.RA.Widgets var bi = info.Traits.GetOrDefault(); if (bi != null) DrawRightAligned("{1}{0}".F(bi.Power, bi.Power > 0 ? "+" : ""), pos + new int2(-5, 20), - ((resources.PowerProvided - resources.PowerDrained) >= -bi.Power || bi.Power > 0)? Color.White: Color.Red); + ((power.PowerProvided - power.PowerDrained) >= -bi.Power || bi.Power > 0)? Color.White: Color.Red); p += new int2(5, 35); if (!canBuildThis) diff --git a/OpenRA.Mods.RA/Widgets/PowerBinWidget.cs b/OpenRA.Mods.RA/Widgets/PowerBinWidget.cs index b854618365..ea62964c7e 100755 --- a/OpenRA.Mods.RA/Widgets/PowerBinWidget.cs +++ b/OpenRA.Mods.RA/Widgets/PowerBinWidget.cs @@ -29,11 +29,11 @@ namespace OpenRA.Mods.RA.Widgets { powerCollection = "power-" + world.LocalPlayer.Country.Race; - var resources = world.LocalPlayer.PlayerActor.Trait(); + var power = world.LocalPlayer.PlayerActor.Trait(); // Nothing to draw - if (resources.PowerProvided == 0 - && resources.PowerDrained == 0) + if (power.PowerProvided == 0 + && power.PowerDrained == 0) return; // Draw bar horizontally @@ -41,18 +41,18 @@ namespace OpenRA.Mods.RA.Widgets var barEnd = barStart + new float2(powerSize.Width, 0); float powerScaleBy = 100; - var maxPower = Math.Max(resources.PowerProvided, resources.PowerDrained); + var maxPower = Math.Max(power.PowerProvided, power.PowerDrained); while (maxPower >= powerScaleBy) powerScaleBy *= 2; // Current power supply - var powerLevelTemp = barStart.X + (barEnd.X - barStart.X) * (resources.PowerProvided / powerScaleBy); + var powerLevelTemp = barStart.X + (barEnd.X - barStart.X) * (power.PowerProvided / powerScaleBy); lastPowerProvidedPos = float2.Lerp(lastPowerProvidedPos.GetValueOrDefault(powerLevelTemp), powerLevelTemp, .3f); float2 powerLevel = new float2(lastPowerProvidedPos.Value, barStart.Y); var color = Color.LimeGreen; - if (resources.GetPowerState() == PowerState.Low) + if (power.GetPowerState() == PowerState.Low) color = Color.Orange; - if (resources.GetPowerState() == PowerState.Critical) + if (power.GetPowerState() == PowerState.Critical) color = Color.Red; var colorDark = Graphics.Util.Lerp(0.25f, color, Color.Black); @@ -75,7 +75,7 @@ namespace OpenRA.Mods.RA.Widgets // Power usage indicator var indicator = ChromeProvider.GetImage( powerCollection, "power-indicator"); - var powerDrainedTemp = barStart.X + (barEnd.X - barStart.X) * (resources.PowerDrained / powerScaleBy); + var powerDrainedTemp = barStart.X + (barEnd.X - barStart.X) * (power.PowerDrained / powerScaleBy); lastPowerDrainedPos = float2.Lerp(lastPowerDrainedPos.GetValueOrDefault(powerDrainedTemp), powerDrainedTemp, .3f); float2 powerDrainLevel = new float2(lastPowerDrainedPos.Value - indicator.size.X / 2, barStart.Y - 1); diff --git a/mods/cnc/rules/system.yaml b/mods/cnc/rules/system.yaml index 803dce8023..665022cc96 100644 --- a/mods/cnc/rules/system.yaml +++ b/mods/cnc/rules/system.yaml @@ -31,6 +31,7 @@ Player: SelectTargetSound: select1.aud UnitType: a10 ConquestVictoryConditions: + PowerManager: PlayerResources: InitialCash: 5000 ActorGroupProxy: diff --git a/mods/ra/rules/system.yaml b/mods/ra/rules/system.yaml index 9c82186bb0..b6ad1aafc2 100644 --- a/mods/ra/rules/system.yaml +++ b/mods/ra/rules/system.yaml @@ -92,6 +92,7 @@ Player: SelectTargetSound: slcttgt1.aud FlareType: flare ConquestVictoryConditions: + PowerManager: PlayerResources: InitialCash: 5000 ActorGroupProxy: