diff --git a/OpenRA.Game/Traits/TraitsInterfaces.cs b/OpenRA.Game/Traits/TraitsInterfaces.cs index 1fa0b983f5..7653a6cb5c 100644 --- a/OpenRA.Game/Traits/TraitsInterfaces.cs +++ b/OpenRA.Game/Traits/TraitsInterfaces.cs @@ -171,6 +171,7 @@ namespace OpenRA.Traits public interface ISpeedModifier { int GetSpeedModifier(); } public interface IFirepowerModifier { int GetFirepowerModifier(); } public interface IReloadModifier { int GetReloadModifier(); } + public interface IPowerModifier { int GetPowerModifier(); } public interface ILoadsPalettes { void LoadPalettes(WorldRenderer wr); } public interface IPaletteModifier { void AdjustPalette(IReadOnlyDictionary b); } public interface IPips { IEnumerable GetPips(Actor self); } diff --git a/OpenRA.Mods.D2k/Widgets/BuildPaletteWidget.cs b/OpenRA.Mods.D2k/Widgets/BuildPaletteWidget.cs index fa0b685bfa..fe85d46592 100644 --- a/OpenRA.Mods.D2k/Widgets/BuildPaletteWidget.cs +++ b/OpenRA.Mods.D2k/Widgets/BuildPaletteWidget.cs @@ -16,8 +16,8 @@ using OpenRA.Graphics; using OpenRA.Mods.RA; using OpenRA.Mods.RA.Buildings; using OpenRA.Mods.RA.Orders; +using OpenRA.Mods.RA.Power; using OpenRA.Mods.RA.Render; -using OpenRA.Mods.RA.Widgets; using OpenRA.Network; using OpenRA.Primitives; using OpenRA.Traits; diff --git a/OpenRA.Mods.D2k/Widgets/Logic/IngameChromeLogic.cs b/OpenRA.Mods.D2k/Widgets/Logic/IngameChromeLogic.cs index a0fcd7f844..5525c2b28c 100644 --- a/OpenRA.Mods.D2k/Widgets/Logic/IngameChromeLogic.cs +++ b/OpenRA.Mods.D2k/Widgets/Logic/IngameChromeLogic.cs @@ -12,7 +12,7 @@ using System; using System.Drawing; using System.Linq; using OpenRA.Mods.RA; -using OpenRA.Mods.RA.Buildings; +using OpenRA.Mods.RA.Power; using OpenRA.Mods.RA.Widgets; using OpenRA.Mods.RA.Widgets.Logic; using OpenRA.Mods.D2k.Widgets; diff --git a/OpenRA.Mods.RA/AI/BaseBuilder.cs b/OpenRA.Mods.RA/AI/BaseBuilder.cs index e961e87144..ad0332d163 100644 --- a/OpenRA.Mods.RA/AI/BaseBuilder.cs +++ b/OpenRA.Mods.RA/AI/BaseBuilder.cs @@ -12,6 +12,7 @@ using System; using System.Collections.Generic; using System.Linq; using OpenRA.Mods.RA.Buildings; +using OpenRA.Mods.RA.Power; using OpenRA.Traits; namespace OpenRA.Mods.RA.AI diff --git a/OpenRA.Mods.RA/AI/HackyAI.cs b/OpenRA.Mods.RA/AI/HackyAI.cs index a5478d66d1..13dd7b0509 100644 --- a/OpenRA.Mods.RA/AI/HackyAI.cs +++ b/OpenRA.Mods.RA/AI/HackyAI.cs @@ -15,6 +15,7 @@ using OpenRA.Mods.RA.Activities; using OpenRA.Mods.RA.Air; using OpenRA.Mods.RA.Buildings; using OpenRA.Mods.RA.Move; +using OpenRA.Mods.RA.Power; using OpenRA.Primitives; using OpenRA.Support; using OpenRA.Traits; diff --git a/OpenRA.Mods.RA/Effects/PowerdownIndicator.cs b/OpenRA.Mods.RA/Effects/PowerdownIndicator.cs index dd8efd449f..d69d99b219 100644 --- a/OpenRA.Mods.RA/Effects/PowerdownIndicator.cs +++ b/OpenRA.Mods.RA/Effects/PowerdownIndicator.cs @@ -11,7 +11,7 @@ using System.Collections.Generic; using OpenRA.Effects; using OpenRA.Graphics; -using OpenRA.Mods.RA.Buildings; +using OpenRA.Mods.RA.Power; namespace OpenRA.Mods.RA.Effects { diff --git a/OpenRA.Mods.RA/InfiltrateForCash.cs b/OpenRA.Mods.RA/Infiltration/InfiltrateForCash.cs similarity index 97% rename from OpenRA.Mods.RA/InfiltrateForCash.cs rename to OpenRA.Mods.RA/Infiltration/InfiltrateForCash.cs index cdaca5db9c..928f8e85f3 100644 --- a/OpenRA.Mods.RA/InfiltrateForCash.cs +++ b/OpenRA.Mods.RA/Infiltration/InfiltrateForCash.cs @@ -12,7 +12,7 @@ using System; using OpenRA.Mods.RA.Effects; using OpenRA.Traits; -namespace OpenRA.Mods.RA +namespace OpenRA.Mods.RA.Infiltration { [Desc("This structure can be infiltrated causing funds to be stolen.")] class InfiltrateForCashInfo : ITraitInfo diff --git a/OpenRA.Mods.RA/InfiltrateForExploration.cs b/OpenRA.Mods.RA/Infiltration/InfiltrateForExploration.cs similarity index 95% rename from OpenRA.Mods.RA/InfiltrateForExploration.cs rename to OpenRA.Mods.RA/Infiltration/InfiltrateForExploration.cs index ec0a02adbf..1d08f8a28b 100644 --- a/OpenRA.Mods.RA/InfiltrateForExploration.cs +++ b/OpenRA.Mods.RA/Infiltration/InfiltrateForExploration.cs @@ -10,7 +10,7 @@ using OpenRA.Traits; -namespace OpenRA.Mods.RA +namespace OpenRA.Mods.RA.Infiltration { class InfiltrateForExplorationInfo : TraitInfo { } diff --git a/OpenRA.Mods.RA/Infiltration/InfiltrateForPowerOutage.cs b/OpenRA.Mods.RA/Infiltration/InfiltrateForPowerOutage.cs new file mode 100644 index 0000000000..6ec3dc40cd --- /dev/null +++ b/OpenRA.Mods.RA/Infiltration/InfiltrateForPowerOutage.cs @@ -0,0 +1,45 @@ +#region Copyright & License Information +/* + * Copyright 2007-2014 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 System.Linq; +using OpenRA.Mods.RA.Power; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA.Infiltration +{ + class InfiltrateForPowerOutageInfo : ITraitInfo + { + public readonly int Duration = 25 * 30; + + public object Create(ActorInitializer init) { return new InfiltrateForPowerOutage(init.self, this); } + } + + class InfiltrateForPowerOutage : INotifyCapture, INotifyInfiltrated + { + readonly InfiltrateForPowerOutageInfo info; + PowerManager playerPower; + + public InfiltrateForPowerOutage(Actor self, InfiltrateForPowerOutageInfo info) + { + this.info = info; + playerPower = self.Owner.PlayerActor.Trait(); + } + + public void Infiltrated(Actor self, Actor infiltrator) + { + playerPower.TriggerPowerOutage(info.Duration); + } + + public void OnCapture(Actor self, Actor captor, Player oldOwner, Player newOwner) + { + playerPower = self.Owner.PlayerActor.Trait(); + } + } +} \ No newline at end of file diff --git a/OpenRA.Mods.RA/InfiltrateForSupportPower.cs b/OpenRA.Mods.RA/Infiltration/InfiltrateForSupportPower.cs similarity index 96% rename from OpenRA.Mods.RA/InfiltrateForSupportPower.cs rename to OpenRA.Mods.RA/Infiltration/InfiltrateForSupportPower.cs index 6b6b7c80d4..a01c85de2d 100644 --- a/OpenRA.Mods.RA/InfiltrateForSupportPower.cs +++ b/OpenRA.Mods.RA/Infiltration/InfiltrateForSupportPower.cs @@ -11,7 +11,7 @@ using OpenRA.Primitives; using OpenRA.Traits; -namespace OpenRA.Mods.RA +namespace OpenRA.Mods.RA.Infiltration { class InfiltrateForSupportPowerInfo : ITraitInfo { diff --git a/OpenRA.Mods.RA/Infiltrates.cs b/OpenRA.Mods.RA/Infiltration/Infiltrates.cs similarity index 98% rename from OpenRA.Mods.RA/Infiltrates.cs rename to OpenRA.Mods.RA/Infiltration/Infiltrates.cs index efcefed314..ada7140a79 100644 --- a/OpenRA.Mods.RA/Infiltrates.cs +++ b/OpenRA.Mods.RA/Infiltration/Infiltrates.cs @@ -15,7 +15,7 @@ using OpenRA.Mods.RA.Activities; using OpenRA.Mods.RA.Orders; using OpenRA.Traits; -namespace OpenRA.Mods.RA +namespace OpenRA.Mods.RA.Infiltration { class InfiltratesInfo : ITraitInfo { diff --git a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj index 4b4d9f2794..58f4f5f7c5 100644 --- a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj +++ b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj @@ -119,7 +119,9 @@ - + + + @@ -166,15 +168,15 @@ - + - + - + @@ -240,7 +242,7 @@ - + @@ -289,6 +291,7 @@ + @@ -413,12 +416,12 @@ - - + + - + diff --git a/OpenRA.Mods.RA/Orders/PowerDownOrderGenerator.cs b/OpenRA.Mods.RA/Orders/PowerDownOrderGenerator.cs index 1b0969b323..703b246fad 100755 --- a/OpenRA.Mods.RA/Orders/PowerDownOrderGenerator.cs +++ b/OpenRA.Mods.RA/Orders/PowerDownOrderGenerator.cs @@ -11,7 +11,7 @@ using System.Collections.Generic; using System.Linq; using OpenRA.Graphics; -using OpenRA.Mods.RA.Buildings; +using OpenRA.Mods.RA.Power; namespace OpenRA.Mods.RA.Orders { diff --git a/OpenRA.Mods.RA/Player/ClassicProductionQueue.cs b/OpenRA.Mods.RA/Player/ClassicProductionQueue.cs index c25deaabfe..1a0dbd5452 100644 --- a/OpenRA.Mods.RA/Player/ClassicProductionQueue.cs +++ b/OpenRA.Mods.RA/Player/ClassicProductionQueue.cs @@ -11,6 +11,7 @@ using System.Collections.Generic; using System.Linq; using OpenRA.Mods.RA.Buildings; +using OpenRA.Mods.RA.Power; using OpenRA.Traits; namespace OpenRA.Mods.RA diff --git a/OpenRA.Mods.RA/Player/ProductionQueue.cs b/OpenRA.Mods.RA/Player/ProductionQueue.cs index fca8f15a63..e37a70ffdf 100644 --- a/OpenRA.Mods.RA/Player/ProductionQueue.cs +++ b/OpenRA.Mods.RA/Player/ProductionQueue.cs @@ -12,6 +12,7 @@ using System; using System.Collections.Generic; using System.Linq; using OpenRA.Mods.RA.Buildings; +using OpenRA.Mods.RA.Power; using OpenRA.Traits; namespace OpenRA.Mods.RA diff --git a/OpenRA.Mods.RA/Power/AffectedByPowerOutage.cs b/OpenRA.Mods.RA/Power/AffectedByPowerOutage.cs new file mode 100644 index 0000000000..4e733fccb4 --- /dev/null +++ b/OpenRA.Mods.RA/Power/AffectedByPowerOutage.cs @@ -0,0 +1,58 @@ +#region Copyright & License Information +/* + * Copyright 2007-2014 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 System.Drawing; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA.Power +{ + public class AffectedByPowerOutageInfo : ITraitInfo + { + public object Create(ActorInitializer init) { return new AffectedByPowerOutage(init.self); } + } + + public class AffectedByPowerOutage : INotifyCapture, ISelectionBar, IPowerModifier, IDisable + { + PowerManager playerPower; + + public AffectedByPowerOutage(Actor self) + { + playerPower = self.Owner.PlayerActor.Trait(); + } + + public float GetValue() + { + if (playerPower.PowerOutageRemainingTicks <= 0) + return 0; + + return (float)playerPower.PowerOutageRemainingTicks / playerPower.PowerOutageTotalTicks; + } + + public Color GetColor() + { + return Color.Yellow; + } + + public int GetPowerModifier() + { + return playerPower.PowerOutageRemainingTicks > 0 ? 0 : 100; + } + + public bool Disabled + { + get { return playerPower.PowerOutageRemainingTicks > 0; } + } + + public void OnCapture(Actor self, Actor captor, Player oldOwner, Player newOwner) + { + playerPower = newOwner.PlayerActor.Trait(); + } + } +} diff --git a/OpenRA.Mods.RA/CanPowerDown.cs b/OpenRA.Mods.RA/Power/CanPowerDown.cs similarity index 56% rename from OpenRA.Mods.RA/CanPowerDown.cs rename to OpenRA.Mods.RA/Power/CanPowerDown.cs index 0dedea60ee..081d46f334 100644 --- a/OpenRA.Mods.RA/CanPowerDown.cs +++ b/OpenRA.Mods.RA/Power/CanPowerDown.cs @@ -11,24 +11,22 @@ using OpenRA.Mods.RA.Effects; using OpenRA.Traits; -namespace OpenRA.Mods.RA.Buildings +namespace OpenRA.Mods.RA.Power { [Desc("The player can disable the power individually on this actor.")] public class CanPowerDownInfo : ITraitInfo, Requires { - public object Create(ActorInitializer init) { return new CanPowerDown(init); } + public object Create(ActorInitializer init) { return new CanPowerDown(init.self); } } - public class CanPowerDown : IResolveOrder, IDisable, INotifyCapture, ISync + public class CanPowerDown : IPowerModifier, IResolveOrder, IDisable, ISync { [Sync] bool disabled = false; - int normalPower = 0; - PowerManager PowerManager; + readonly Power power; - public CanPowerDown(ActorInitializer init) + public CanPowerDown(Actor self) { - PowerManager = init.self.Owner.PlayerActor.Trait(); - normalPower = init.self.Info.Traits.Get().Amount; + power = self.Trait(); } public bool Disabled { get { return disabled; } } @@ -38,18 +36,17 @@ namespace OpenRA.Mods.RA.Buildings if (order.OrderString == "PowerDown") { disabled = !disabled; - Sound.PlayNotification(self.World.Map.Rules, self.Owner, "Sounds", (disabled ? "EnablePower" : "DisablePower"), self.Owner.Country.Race); - PowerManager.UpdateActor(self, disabled ? 0 : normalPower); + Sound.PlayNotification(self.World.Map.Rules, self.Owner, "Sounds", disabled ? "EnablePower" : "DisablePower", self.Owner.Country.Race); + power.PlayerPower.UpdateActor(self); if (disabled) - self.World.AddFrameEndTask( - w => w.Add(new PowerdownIndicator(self))); + self.World.AddFrameEndTask(w => w.Add(new PowerdownIndicator(self))); } } - public void OnCapture(Actor self, Actor captor, Player oldOwner, Player newOwner) + public int GetPowerModifier() { - PowerManager = newOwner.PlayerActor.Trait(); + return disabled ? 0 : 100; } } } diff --git a/OpenRA.Mods.RA/Buildings/PowerManager.cs b/OpenRA.Mods.RA/Power/Player/PowerManager.cs old mode 100755 new mode 100644 similarity index 62% rename from OpenRA.Mods.RA/Buildings/PowerManager.cs rename to OpenRA.Mods.RA/Power/Player/PowerManager.cs index a4f40d757b..2ef7790bca --- a/OpenRA.Mods.RA/Buildings/PowerManager.cs +++ b/OpenRA.Mods.RA/Power/Player/PowerManager.cs @@ -9,20 +9,21 @@ #endregion using System.Collections.Generic; +using System.Linq; using OpenRA.Traits; -namespace OpenRA.Mods.RA.Buildings +namespace OpenRA.Mods.RA.Power { public class PowerManagerInfo : ITraitInfo, Requires { public readonly int AdviceInterval = 250; - public object Create(ActorInitializer init) { return new PowerManager(init, this); } + public object Create(ActorInitializer init) { return new PowerManager(init.self, this); } } public class PowerManager : ITick, ISync { + readonly Actor self; readonly PowerManagerInfo info; - readonly Player player; readonly DeveloperMode devMode; readonly Dictionary powerDrain = new Dictionary(); @@ -34,43 +35,56 @@ namespace OpenRA.Mods.RA.Buildings public int ExcessPower { get { return totalProvided - totalDrained; } } - public PowerManager(ActorInitializer init, PowerManagerInfo info) + public int PowerOutageRemainingTicks { get; private set; } + public int PowerOutageTotalTicks { get; private set; } + + public PowerManager(Actor self, PowerManagerInfo info) { + this.self = self; this.info = info; - player = init.self.Owner; - init.world.ActorAdded += ActorAdded; - init.world.ActorRemoved += ActorRemoved; + self.World.ActorAdded += UpdateActor; + self.World.ActorRemoved += RemoveActor; - devMode = init.self.Trait(); + devMode = self.Trait(); wasHackEnabled = devMode.UnlimitedPower; } - void ActorAdded(Actor a) + public void UpdateActor(Actor a) { - if (a.Owner != player) - return; + UpdateActors(new[] { a }); + } - var power = a.TraitOrDefault(); - if (power == null) - return; + public void UpdateActors(IEnumerable actors) + { + foreach (var a in actors) + { + if (a.Owner != self.Owner) + return; - powerDrain.Add(a, power.CurrentPower); + var power = a.TraitOrDefault(); + if (power == null) + return; + + powerDrain[a] = power.GetCurrentPower(); + } UpdateTotals(); } - void ActorRemoved(Actor a) + void RemoveActor(Actor a) { - if (a.Owner != player || !a.HasTrait()) + if (a.Owner != self.Owner || !a.HasTrait()) return; + powerDrain.Remove(a); UpdateTotals(); } - void UpdateTotals() + public void UpdateTotals() { totalProvided = 0; totalDrained = 0; + foreach (var kv in powerDrain) { var p = kv.Value; @@ -84,15 +98,6 @@ namespace OpenRA.Mods.RA.Buildings totalProvided = 1000000; } - public void UpdateActor(Actor a, int newPower) - { - if (a.Owner != player || !a.HasTrait()) - return; - - powerDrain[a] = newPower; - UpdateTotals(); - } - int nextPowerAdviceTime = 0; bool wasLowPower = false; bool wasHackEnabled; @@ -116,15 +121,34 @@ namespace OpenRA.Mods.RA.Buildings Sound.PlayNotification(self.World.Map.Rules, self.Owner, "Speech", "LowPower", self.Owner.Country.Race); nextPowerAdviceTime = info.AdviceInterval; } + + if (PowerOutageRemainingTicks > 0 && --PowerOutageRemainingTicks == 0) + UpdatePowerOutageActors(); } public PowerState PowerState { - get { + get + { if (PowerProvided >= PowerDrained) return PowerState.Normal; if (PowerProvided > PowerDrained / 2) return PowerState.Low; return PowerState.Critical; } } + + public void TriggerPowerOutage(int totalTicks) + { + PowerOutageTotalTicks = PowerOutageRemainingTicks = totalTicks; + UpdatePowerOutageActors(); + } + + void UpdatePowerOutageActors() + { + var actors = self.World.ActorsWithTrait() + .Select(tp => tp.Actor) + .Where(a => !a.IsDead() && a.IsInWorld && a.Owner == self.Owner); + + UpdateActors(actors); + } } } diff --git a/OpenRA.Mods.RA/Power.cs b/OpenRA.Mods.RA/Power/Power.cs similarity index 51% rename from OpenRA.Mods.RA/Power.cs rename to OpenRA.Mods.RA/Power/Power.cs index c09dbd4b30..946988874e 100644 --- a/OpenRA.Mods.RA/Power.cs +++ b/OpenRA.Mods.RA/Power/Power.cs @@ -9,55 +9,41 @@ #endregion using System; -using OpenRA.Mods.RA.Buildings; +using System.Linq; using OpenRA.Traits; -namespace OpenRA.Mods.RA +namespace OpenRA.Mods.RA.Power { public class PowerInfo : ITraitInfo { [Desc("If negative, it will drain power. If positive, it will provide power.")] public readonly int Amount = 0; - [Desc("Scale power amount with the current health.")] - public readonly bool ScaleWithHealth = false; - public object Create(ActorInitializer init) { return new Power(init.self, this); } } - public class Power : INotifyDamage, INotifyCapture + public class Power : INotifyCapture { readonly PowerInfo info; - readonly Lazy health; - PowerManager playerPower; + readonly Lazy powerModifiers; - public int CurrentPower + public PowerManager PlayerPower { get; private set; } + + public int GetCurrentPower() { - get - { - if (info.Amount <= 0 || health == null || !info.ScaleWithHealth) - return info.Amount; - - return info.Amount * health.Value.HP / health.Value.MaxHP; - } + return Util.ApplyPercentageModifiers(info.Amount, powerModifiers.Value.Select(m => m.GetPowerModifier())); } public Power(Actor self, PowerInfo info) { this.info = info; - health = Exts.Lazy(self.TraitOrDefault); - playerPower = self.Owner.PlayerActor.Trait(); - } - - public void Damaged(Actor self, AttackInfo e) - { - if (info.ScaleWithHealth) - playerPower.UpdateActor(self, CurrentPower); + PlayerPower = self.Owner.PlayerActor.Trait(); + powerModifiers = Exts.Lazy(() => self.TraitsImplementing().ToArray()); } public void OnCapture(Actor self, Actor captor, Player oldOwner, Player newOwner) { - playerPower = newOwner.PlayerActor.Trait(); + PlayerPower = newOwner.PlayerActor.Trait(); } } } diff --git a/OpenRA.Mods.RA/Buildings/RequiresPower.cs b/OpenRA.Mods.RA/Power/RequiresPower.cs old mode 100755 new mode 100644 similarity index 70% rename from OpenRA.Mods.RA/Buildings/RequiresPower.cs rename to OpenRA.Mods.RA/Power/RequiresPower.cs index 757e2769b3..0dfb71cb9b --- a/OpenRA.Mods.RA/Buildings/RequiresPower.cs +++ b/OpenRA.Mods.RA/Power/RequiresPower.cs @@ -10,7 +10,7 @@ using OpenRA.Traits; -namespace OpenRA.Mods.RA.Buildings +namespace OpenRA.Mods.RA.Power { class RequiresPowerInfo : ITraitInfo { @@ -19,21 +19,21 @@ namespace OpenRA.Mods.RA.Buildings class RequiresPower : IDisable, INotifyCapture { - PowerManager power; + PowerManager playerPower; - public RequiresPower( Actor self ) + public RequiresPower(Actor self) { - power = self.Owner.PlayerActor.Trait(); + playerPower = self.Owner.PlayerActor.Trait(); } public bool Disabled { - get { return power.PowerProvided < power.PowerDrained; } + get { return playerPower.PowerProvided < playerPower.PowerDrained; } } public void OnCapture(Actor self, Actor captor, Player oldOwner, Player newOwner) { - power = newOwner.PlayerActor.Trait(); + playerPower = newOwner.PlayerActor.Trait(); } } } diff --git a/OpenRA.Mods.RA/Power/ScalePowerWithHealth.cs b/OpenRA.Mods.RA/Power/ScalePowerWithHealth.cs new file mode 100644 index 0000000000..815bcf8a55 --- /dev/null +++ b/OpenRA.Mods.RA/Power/ScalePowerWithHealth.cs @@ -0,0 +1,42 @@ +#region Copyright & License Information +/* + * Copyright 2007-2014 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.RA.Power +{ + [Desc("Scale power amount with the current health.")] + public class ScalePowerWithHealthInfo : ITraitInfo, Requires, Requires + { + public object Create(ActorInitializer init) { return new ScalePowerWithHealth(init.self); } + } + + public class ScalePowerWithHealth : IPowerModifier, INotifyDamage + { + readonly Power power; + readonly Health health; + + public ScalePowerWithHealth(Actor self) + { + power = self.Trait(); + health = self.Trait(); + } + + public int GetPowerModifier() + { + return 100 * health.HP / health.MaxHP; + } + + public void Damaged(Actor self, AttackInfo e) + { + power.PlayerPower.UpdateActor(self); + } + } +} diff --git a/OpenRA.Mods.RA/Widgets/Logic/Ingame/IngamePowerBarLogic.cs b/OpenRA.Mods.RA/Widgets/Logic/Ingame/IngamePowerBarLogic.cs index 7fcd05e897..11e70d8fde 100644 --- a/OpenRA.Mods.RA/Widgets/Logic/Ingame/IngamePowerBarLogic.cs +++ b/OpenRA.Mods.RA/Widgets/Logic/Ingame/IngamePowerBarLogic.cs @@ -9,7 +9,7 @@ #endregion using System.Drawing; -using OpenRA.Mods.RA.Buildings; +using OpenRA.Mods.RA.Power; using OpenRA.Widgets; namespace OpenRA.Mods.RA.Widgets.Logic diff --git a/OpenRA.Mods.RA/Widgets/Logic/Ingame/IngamePowerCounterLogic.cs b/OpenRA.Mods.RA/Widgets/Logic/Ingame/IngamePowerCounterLogic.cs index b8c5cfdbaa..d509a41fe5 100644 --- a/OpenRA.Mods.RA/Widgets/Logic/Ingame/IngamePowerCounterLogic.cs +++ b/OpenRA.Mods.RA/Widgets/Logic/Ingame/IngamePowerCounterLogic.cs @@ -8,7 +8,7 @@ */ #endregion -using OpenRA.Mods.RA.Buildings; +using OpenRA.Mods.RA.Power; using OpenRA.Widgets; namespace OpenRA.Mods.RA.Widgets.Logic diff --git a/OpenRA.Mods.RA/Widgets/Logic/ObserverStatsLogic.cs b/OpenRA.Mods.RA/Widgets/Logic/ObserverStatsLogic.cs index 79c333bd9e..239faeba72 100644 --- a/OpenRA.Mods.RA/Widgets/Logic/ObserverStatsLogic.cs +++ b/OpenRA.Mods.RA/Widgets/Logic/ObserverStatsLogic.cs @@ -13,7 +13,7 @@ using System.Collections.Generic; using System.Drawing; using System.Linq; using OpenRA.Graphics; -using OpenRA.Mods.RA.Buildings; +using OpenRA.Mods.RA.Power; using OpenRA.Network; using OpenRA.Traits; using OpenRA.Widgets; diff --git a/OpenRA.Mods.RA/Widgets/Logic/ProductionTooltipLogic.cs b/OpenRA.Mods.RA/Widgets/Logic/ProductionTooltipLogic.cs index 7778a1c66e..b5b610d9f1 100644 --- a/OpenRA.Mods.RA/Widgets/Logic/ProductionTooltipLogic.cs +++ b/OpenRA.Mods.RA/Widgets/Logic/ProductionTooltipLogic.cs @@ -11,8 +11,7 @@ using System; using System.Drawing; using System.Linq; -using OpenRA.Mods.RA; -using OpenRA.Mods.RA.Buildings; +using OpenRA.Mods.RA.Power; using OpenRA.Traits; using OpenRA.Widgets; diff --git a/OpenRA.Utility/UpgradeRules.cs b/OpenRA.Utility/UpgradeRules.cs index ce95f9edab..60da52fa67 100644 --- a/OpenRA.Utility/UpgradeRules.cs +++ b/OpenRA.Utility/UpgradeRules.cs @@ -334,8 +334,8 @@ namespace OpenRA.Utility node.Key = "Units"; } - // Power from Building was moved out into its own trait - if (engineVersion < 20140802) + // Power from Building was moved out into Power and ScalePowerWithHealth traits + if (engineVersion < 20140823) { if (depth == 0) { @@ -350,11 +350,10 @@ namespace OpenRA.Utility buildingFields.Remove(power); var powerFields = new List { new MiniYamlNode("Amount", power.Value) }; - - if (FieldLoader.GetValue("Power", power.Value.Value) > 0) - powerFields.Add(new MiniYamlNode("ScaleWithHealth", "True")); - actorTraits.Add(new MiniYamlNode("Power", new MiniYaml("", powerFields))); + + if (FieldLoader.GetValue("Power", power.Value.Value) > 0) + actorTraits.Add(new MiniYamlNode("ScaleWithHealth", "")); } } } diff --git a/mods/cnc/rules/structures.yaml b/mods/cnc/rules/structures.yaml index 5b72869be3..dbc0931663 100644 --- a/mods/cnc/rules/structures.yaml +++ b/mods/cnc/rules/structures.yaml @@ -100,7 +100,7 @@ NUKE: Bib: Power: Amount: 100 - ScaleWithHealth: True + ScalePowerWithHealth: NUK2: Inherits: ^BaseBuilding @@ -125,7 +125,7 @@ NUK2: Bib: Power: Amount: 200 - ScaleWithHealth: True + ScalePowerWithHealth: PROC: Inherits: ^BaseBuilding diff --git a/mods/d2k/rules/structures.yaml b/mods/d2k/rules/structures.yaml index 4b8d606ccd..3c425a14d6 100644 --- a/mods/d2k/rules/structures.yaml +++ b/mods/d2k/rules/structures.yaml @@ -106,7 +106,7 @@ CONCRETEB: Sequence: idle-zaps Power: Amount: 100 - ScaleWithHealth: True + ScalePowerWithHealth: ^BARRACKS: Inherits: ^Building diff --git a/mods/ra/rules/infantry.yaml b/mods/ra/rules/infantry.yaml index 4b199dd07c..f26f89ae69 100644 --- a/mods/ra/rules/infantry.yaml +++ b/mods/ra/rules/infantry.yaml @@ -199,7 +199,7 @@ SPY: Cost: 500 DisguiseToolTip: Name: Spy - Description: Infiltrates enemy structures to gather \nintelligence. Exact effect depends on the \nbuilding infiltrated.\n Strong vs Nothing\n Weak vs Everything\n Special Ability: Disguised + Description: Infiltrates enemy structures for intel or\nsabotage. Exact effect depends on the\nbuilding infiltrated.\n Strong vs Nothing\n Weak vs Everything\n Special Ability: Disguised Selectable: Voice: SpyVoice Bounds: 12,17,0,-9 diff --git a/mods/ra/rules/structures.yaml b/mods/ra/rules/structures.yaml index 33c12c72e6..cbc35409ee 100644 --- a/mods/ra/rules/structures.yaml +++ b/mods/ra/rules/structures.yaml @@ -949,7 +949,12 @@ POWR: DeadBuildingState: Power: Amount: 100 - ScaleWithHealth: True + InfiltrateForPowerOutage: + AffectedByPowerOutage: + TargetableBuilding: + TargetTypes: Ground, C4, DetonateAttack, SpyInfiltrate + ScalePowerWithHealth: + DisabledOverlay: APWR: Inherits: ^Building @@ -978,7 +983,12 @@ APWR: DeadBuildingState: Power: Amount: 200 - ScaleWithHealth: True + InfiltrateForPowerOutage: + AffectedByPowerOutage: + TargetableBuilding: + TargetTypes: Ground, C4, DetonateAttack, SpyInfiltrate + ScalePowerWithHealth: + DisabledOverlay: STEK: Inherits: ^Building diff --git a/mods/ts/rules/structures.yaml b/mods/ts/rules/structures.yaml index 8186a97cdf..15c7bc9d5d 100644 --- a/mods/ts/rules/structures.yaml +++ b/mods/ts/rules/structures.yaml @@ -71,7 +71,12 @@ GAPOWR: Sequence: idle-plug Power: Amount: 100 - ScaleWithHealth: True + InfiltrateForPowerOutage: + AffectedByPowerOutage: + TargetableBuilding: + TargetTypes: Ground, C4, DetonateAttack, SpyInfiltrate + ScalePowerWithHealth: + DisabledOverlay: GAPILE: Inherits: ^Building @@ -222,7 +227,12 @@ NAPOWR: Sequence: idle-lights Power: Amount: 100 - ScaleWithHealth: True + InfiltrateForPowerOutage: + AffectedByPowerOutage: + TargetableBuilding: + TargetTypes: Ground, C4, DetonateAttack, SpyInfiltrate + ScalePowerWithHealth: + DisabledOverlay: NAAPWR: Inherits: ^Building @@ -251,7 +261,12 @@ NAAPWR: Sequence: idle-lights Power: Amount: 200 - ScaleWithHealth: True + InfiltrateForPowerOutage: + AffectedByPowerOutage: + TargetableBuilding: + TargetTypes: Ground, C4, DetonateAttack, SpyInfiltrate + ScalePowerWithHealth: + DisabledOverlay: NAHAND: Inherits: ^Building