Refactor PowerManager and RequiresPower to use conditions

Instead of Actor.IsDisabled.
Added INotifyPowerLevelChanged interface to do so as efficiently as possible.
This commit is contained in:
reaperrr
2017-08-04 13:28:02 +02:00
committed by Pavel Penev
parent 6c02e3f2b7
commit 786a0eb07f
6 changed files with 122 additions and 49 deletions

View File

@@ -24,7 +24,14 @@ using OpenRA.Widgets;
namespace OpenRA 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 enum WinState { Undefined, Won, Lost }
public class Player : IScriptBindable, IScriptNotifyBind, ILuaTableBinding, ILuaEqualityBinding, ILuaToStringBinding public class Player : IScriptBindable, IScriptNotifyBind, ILuaTableBinding, ILuaEqualityBinding, ILuaToStringBinding

View File

@@ -403,7 +403,7 @@
<Compile Include="Traits\Power\CanPowerDown.cs" /> <Compile Include="Traits\Power\CanPowerDown.cs" />
<Compile Include="Traits\Power\Player\PowerManager.cs" /> <Compile Include="Traits\Power\Player\PowerManager.cs" />
<Compile Include="Traits\Power\Power.cs" /> <Compile Include="Traits\Power\Power.cs" />
<Compile Include="Traits\Power\RequiresPower.cs" /> <Compile Include="Traits\Conditions\GrantConditionOnPowerState.cs" />
<Compile Include="Traits\Power\ScalePowerWithHealth.cs" /> <Compile Include="Traits\Power\ScalePowerWithHealth.cs" />
<Compile Include="Traits\Production.cs" /> <Compile Include="Traits\Production.cs" />
<Compile Include="Traits\ProductionFromMapEdge.cs" /> <Compile Include="Traits\ProductionFromMapEdge.cs" />

View File

@@ -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<GrantConditionOnPowerStateInfo>, 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<PowerManager>();
}
protected override void Created(Actor self)
{
base.Created(self);
conditionManager = self.TraitOrDefault<ConditionManager>();
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<PowerManager>();
Update(self);
}
}
}

View File

@@ -32,6 +32,7 @@ namespace OpenRA.Mods.Common.Traits
readonly DeveloperMode devMode; readonly DeveloperMode devMode;
readonly Dictionary<Actor, int> powerDrain = new Dictionary<Actor, int>(); readonly Dictionary<Actor, int> powerDrain = new Dictionary<Actor, int>();
[Sync] int totalProvided; [Sync] int totalProvided;
public int PowerProvided { get { return totalProvided; } } public int PowerProvided { get { return totalProvided; } }
@@ -43,6 +44,11 @@ namespace OpenRA.Mods.Common.Traits
public int PowerOutageRemainingTicks { get; private set; } public int PowerOutageRemainingTicks { get; private set; }
public int PowerOutageTotalTicks { 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) public PowerManager(Actor self, PowerManagerInfo info)
{ {
this.self = self; this.self = self;
@@ -86,10 +92,6 @@ namespace OpenRA.Mods.Common.Traits
totalDrained += amount; totalDrained += amount;
} }
int nextPowerAdviceTime = 0;
bool wasLowPower = false;
bool wasHackEnabled;
void ITick.Tick(Actor self) void ITick.Tick(Actor self)
{ {
if (wasHackEnabled != devMode.UnlimitedPower) if (wasHackEnabled != devMode.UnlimitedPower)
@@ -107,15 +109,21 @@ namespace OpenRA.Mods.Common.Traits
wasHackEnabled = devMode.UnlimitedPower; wasHackEnabled = devMode.UnlimitedPower;
} }
var lowPower = totalProvided < totalDrained; lowPower = ExcessPower < 0;
if (lowPower != wasLowPower)
UpdateRequiresPowerActors();
if (lowPower && !wasLowPower) if (lowPower && !wasLowPower)
nextPowerAdviceTime = 0; nextPowerAdviceTime = 0;
wasLowPower = lowPower; wasLowPower = lowPower;
if (--nextPowerAdviceTime <= 0) if (--nextPowerAdviceTime <= 0)
{ {
if (lowPower) if (lowPower)
Game.Sound.PlayNotification(self.World.Map.Rules, self.Owner, "Speech", info.SpeechNotification, self.Owner.Faction.InternalName); Game.Sound.PlayNotification(self.World.Map.Rules, self.Owner, "Speech", info.SpeechNotification, self.Owner.Faction.InternalName);
nextPowerAdviceTime = info.AdviceInterval; nextPowerAdviceTime = info.AdviceInterval;
} }
@@ -148,6 +156,15 @@ namespace OpenRA.Mods.Common.Traits
p.Trait.UpdateStatus(p.Actor); p.Trait.UpdateStatus(p.Actor);
} }
void UpdateRequiresPowerActors()
{
var traitPairs = self.World.ActorsWithTrait<INotifyPowerLevelChanged>()
.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) void IResolveOrder.ResolveOrder(Actor self, Order order)
{ {
if (devMode.Enabled && order.OrderString == "PowerOutage") if (devMode.Enabled && order.OrderString == "PowerOutage")

View File

@@ -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<RequiresPowerInfo>, IDisable, INotifyOwnerChanged
{
PowerManager playerPower;
public RequiresPower(Actor self, RequiresPowerInfo info)
: base(info)
{
playerPower = self.Owner.PlayerActor.Trait<PowerManager>();
}
public bool Disabled
{
get { return playerPower.PowerProvided < playerPower.PowerDrained && !IsTraitDisabled; }
}
public void OnOwnerChanged(Actor self, Player oldOwner, Player newOwner)
{
playerPower = newOwner.PlayerActor.Trait<PowerManager>();
}
}
}

View File

@@ -95,6 +95,9 @@ namespace OpenRA.Mods.Common.Traits
void AfterRepair(Actor self, Actor target); void AfterRepair(Actor self, Actor target);
} }
[RequireExplicitImplementation]
public interface INotifyPowerLevelChanged { void PowerLevelChanged(Actor self); }
public interface INotifyBuildingPlaced { void BuildingPlaced(Actor self); } public interface INotifyBuildingPlaced { void BuildingPlaced(Actor self); }
public interface INotifyNuke { void Launching(Actor self); } public interface INotifyNuke { void Launching(Actor self); }
public interface INotifyBurstComplete { void FiredBurst(Actor self, Target target, Armament a); } public interface INotifyBurstComplete { void FiredBurst(Actor self, Target target, Armament a); }