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