From 786a0eb07fcda955d7bed64c657023711e07957a Mon Sep 17 00:00:00 2001 From: reaperrr Date: Fri, 4 Aug 2017 13:28:02 +0200 Subject: [PATCH] Refactor PowerManager and RequiresPower to use conditions Instead of Actor.IsDisabled. Added INotifyPowerLevelChanged interface to do so as efficiently as possible. --- OpenRA.Game/Player.cs | 9 +- OpenRA.Mods.Common/OpenRA.Mods.Common.csproj | 2 +- .../Conditions/GrantConditionOnPowerState.cs | 88 +++++++++++++++++++ .../Traits/Power/Player/PowerManager.cs | 27 ++++-- .../Traits/Power/RequiresPower.cs | 42 --------- OpenRA.Mods.Common/TraitsInterfaces.cs | 3 + 6 files changed, 122 insertions(+), 49 deletions(-) create mode 100644 OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnPowerState.cs delete mode 100644 OpenRA.Mods.Common/Traits/Power/RequiresPower.cs diff --git a/OpenRA.Game/Player.cs b/OpenRA.Game/Player.cs index d1eff1f7c8..f80efc7d72 100644 --- a/OpenRA.Game/Player.cs +++ b/OpenRA.Game/Player.cs @@ -24,7 +24,14 @@ using OpenRA.Widgets; namespace OpenRA { - public enum PowerState { Normal, Low, Critical } + [Flags] + public enum PowerState + { + Normal = 1, + Low = 2, + Critical = 4 + } + public enum WinState { Undefined, Won, Lost } public class Player : IScriptBindable, IScriptNotifyBind, ILuaTableBinding, ILuaEqualityBinding, ILuaToStringBinding diff --git a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj index 3e4ca674ca..5388ce8430 100644 --- a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj +++ b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj @@ -403,7 +403,7 @@ - + diff --git a/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnPowerState.cs b/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnPowerState.cs new file mode 100644 index 0000000000..06a22e11ad --- /dev/null +++ b/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnPowerState.cs @@ -0,0 +1,88 @@ +#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 OpenRA.Traits; + +namespace OpenRA.Mods.Common.Traits +{ + [Desc("Grants condition as long as a valid power state is maintained.")] + public class GrantConditionOnPowerStateInfo : ConditionalTraitInfo + { + [FieldLoader.Require] + [GrantedConditionReference] + [Desc("Condition to grant.")] + public readonly string Condition = null; + + [FieldLoader.Require] + [Desc("PowerStates at which the condition is granted. Options are Normal, Low and Critical.")] + public readonly PowerState ValidPowerStates = PowerState.Low | PowerState.Critical; + + public override object Create(ActorInitializer init) { return new GrantConditionOnPowerState(init.Self, this); } + } + + public class GrantConditionOnPowerState : ConditionalTrait, INotifyOwnerChanged, INotifyPowerLevelChanged + { + PowerManager playerPower; + ConditionManager conditionManager; + int conditionToken = ConditionManager.InvalidConditionToken; + + bool validPowerState; + + public GrantConditionOnPowerState(Actor self, GrantConditionOnPowerStateInfo info) + : base(info) + { + playerPower = self.Owner.PlayerActor.Trait(); + } + + protected override void Created(Actor self) + { + base.Created(self); + + conditionManager = self.TraitOrDefault(); + + Update(self); + } + + protected override void TraitEnabled(Actor self) + { + Update(self); + } + + protected override void TraitDisabled(Actor self) + { + Update(self); + } + + void Update(Actor self) + { + if (conditionManager == null) + return; + + validPowerState = !IsTraitDisabled && Info.ValidPowerStates.HasFlag(playerPower.PowerState); + + if (validPowerState && conditionToken == ConditionManager.InvalidConditionToken) + conditionToken = conditionManager.GrantCondition(self, Info.Condition); + else if (!validPowerState && conditionToken != ConditionManager.InvalidConditionToken) + conditionToken = conditionManager.RevokeCondition(self, conditionToken); + } + + void INotifyPowerLevelChanged.PowerLevelChanged(Actor self) + { + Update(self); + } + + void INotifyOwnerChanged.OnOwnerChanged(Actor self, Player oldOwner, Player newOwner) + { + playerPower = newOwner.PlayerActor.Trait(); + Update(self); + } + } +} diff --git a/OpenRA.Mods.Common/Traits/Power/Player/PowerManager.cs b/OpenRA.Mods.Common/Traits/Power/Player/PowerManager.cs index db02bbfc59..0a8eb9ce58 100644 --- a/OpenRA.Mods.Common/Traits/Power/Player/PowerManager.cs +++ b/OpenRA.Mods.Common/Traits/Power/Player/PowerManager.cs @@ -32,6 +32,7 @@ namespace OpenRA.Mods.Common.Traits readonly DeveloperMode devMode; readonly Dictionary powerDrain = new Dictionary(); + [Sync] int totalProvided; public int PowerProvided { get { return totalProvided; } } @@ -43,6 +44,11 @@ namespace OpenRA.Mods.Common.Traits public int PowerOutageRemainingTicks { get; private set; } public int PowerOutageTotalTicks { get; private set; } + int nextPowerAdviceTime = 0; + bool lowPower = false; + bool wasLowPower = false; + bool wasHackEnabled; + public PowerManager(Actor self, PowerManagerInfo info) { this.self = self; @@ -86,10 +92,6 @@ namespace OpenRA.Mods.Common.Traits totalDrained += amount; } - int nextPowerAdviceTime = 0; - bool wasLowPower = false; - bool wasHackEnabled; - void ITick.Tick(Actor self) { if (wasHackEnabled != devMode.UnlimitedPower) @@ -107,15 +109,21 @@ namespace OpenRA.Mods.Common.Traits wasHackEnabled = devMode.UnlimitedPower; } - var lowPower = totalProvided < totalDrained; + lowPower = ExcessPower < 0; + + if (lowPower != wasLowPower) + UpdateRequiresPowerActors(); + if (lowPower && !wasLowPower) nextPowerAdviceTime = 0; + wasLowPower = lowPower; if (--nextPowerAdviceTime <= 0) { if (lowPower) Game.Sound.PlayNotification(self.World.Map.Rules, self.Owner, "Speech", info.SpeechNotification, self.Owner.Faction.InternalName); + nextPowerAdviceTime = info.AdviceInterval; } @@ -148,6 +156,15 @@ namespace OpenRA.Mods.Common.Traits p.Trait.UpdateStatus(p.Actor); } + void UpdateRequiresPowerActors() + { + var traitPairs = self.World.ActorsWithTrait() + .Where(p => !p.Actor.IsDead && p.Actor.IsInWorld && p.Actor.Owner == self.Owner); + + foreach (var p in traitPairs) + p.Trait.PowerLevelChanged(p.Actor); + } + void IResolveOrder.ResolveOrder(Actor self, Order order) { if (devMode.Enabled && order.OrderString == "PowerOutage") diff --git a/OpenRA.Mods.Common/Traits/Power/RequiresPower.cs b/OpenRA.Mods.Common/Traits/Power/RequiresPower.cs deleted file mode 100644 index 6e4fdfe3f3..0000000000 --- a/OpenRA.Mods.Common/Traits/Power/RequiresPower.cs +++ /dev/null @@ -1,42 +0,0 @@ -#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 OpenRA.Traits; - -namespace OpenRA.Mods.Common.Traits -{ - [Desc("Needs power to operate.")] - class RequiresPowerInfo : ConditionalTraitInfo, ITraitInfo - { - public override object Create(ActorInitializer init) { return new RequiresPower(init.Self, this); } - } - - class RequiresPower : ConditionalTrait, IDisable, INotifyOwnerChanged - { - PowerManager playerPower; - - public RequiresPower(Actor self, RequiresPowerInfo info) - : base(info) - { - playerPower = self.Owner.PlayerActor.Trait(); - } - - public bool Disabled - { - get { return playerPower.PowerProvided < playerPower.PowerDrained && !IsTraitDisabled; } - } - - public void OnOwnerChanged(Actor self, Player oldOwner, Player newOwner) - { - playerPower = newOwner.PlayerActor.Trait(); - } - } -} diff --git a/OpenRA.Mods.Common/TraitsInterfaces.cs b/OpenRA.Mods.Common/TraitsInterfaces.cs index 4755ede064..d15f15f790 100644 --- a/OpenRA.Mods.Common/TraitsInterfaces.cs +++ b/OpenRA.Mods.Common/TraitsInterfaces.cs @@ -95,6 +95,9 @@ namespace OpenRA.Mods.Common.Traits void AfterRepair(Actor self, Actor target); } + [RequireExplicitImplementation] + public interface INotifyPowerLevelChanged { void PowerLevelChanged(Actor self); } + public interface INotifyBuildingPlaced { void BuildingPlaced(Actor self); } public interface INotifyNuke { void Launching(Actor self); } public interface INotifyBurstComplete { void FiredBurst(Actor self, Target target, Armament a); }