diff --git a/OpenRA.Mods.Common/AI/BaseBuilder.cs b/OpenRA.Mods.Common/AI/BaseBuilder.cs index add3c688de..105c512c48 100644 --- a/OpenRA.Mods.Common/AI/BaseBuilder.cs +++ b/OpenRA.Mods.Common/AI/BaseBuilder.cs @@ -199,7 +199,7 @@ namespace OpenRA.Mods.Common.AI bool HasSufficientPowerForActor(ActorInfo actorInfo) { - return (actorInfo.TraitInfos().Where(i => i.EnabledByDefault) + return playerPower == null || (actorInfo.TraitInfos().Where(i => i.EnabledByDefault) .Sum(p => p.Amount) + playerPower.ExcessPower) >= minimumExcessPower; } @@ -212,7 +212,7 @@ namespace OpenRA.Mods.Common.AI a => a.TraitInfos().Where(i => i.EnabledByDefault).Sum(p => p.Amount)); // First priority is to get out of a low power situation - if (playerPower.ExcessPower < minimumExcessPower) + if (playerPower != null && playerPower.ExcessPower < minimumExcessPower) { if (power != null && power.TraitInfos().Where(i => i.EnabledByDefault).Sum(p => p.Amount) > 0) { @@ -318,7 +318,7 @@ namespace OpenRA.Mods.Common.AI // Will this put us into low power? var actor = world.Map.Rules.Actors[name]; - if (playerPower.ExcessPower < minimumExcessPower || !HasSufficientPowerForActor(actor)) + if (playerPower != null && (playerPower.ExcessPower < minimumExcessPower || !HasSufficientPowerForActor(actor))) { // Try building a power plant instead if (power != null && power.TraitInfos().Where(i => i.EnabledByDefault).Sum(pi => pi.Amount) > 0) diff --git a/OpenRA.Mods.Common/AI/HackyAI.cs b/OpenRA.Mods.Common/AI/HackyAI.cs index ecde59da1b..c4dbc7918b 100644 --- a/OpenRA.Mods.Common/AI/HackyAI.cs +++ b/OpenRA.Mods.Common/AI/HackyAI.cs @@ -330,7 +330,7 @@ namespace OpenRA.Mods.Common.AI { Player = p; IsEnabled = true; - playerPower = p.PlayerActor.Trait(); + playerPower = p.PlayerActor.TraitOrDefault(); playerResource = p.PlayerActor.Trait(); harvManager = new AIHarvesterManager(this, p); diff --git a/OpenRA.Mods.Common/Traits/Player/ClassicProductionQueue.cs b/OpenRA.Mods.Common/Traits/Player/ClassicProductionQueue.cs index ad8d0933d6..8f66ba0094 100644 --- a/OpenRA.Mods.Common/Traits/Player/ClassicProductionQueue.cs +++ b/OpenRA.Mods.Common/Traits/Player/ClassicProductionQueue.cs @@ -19,7 +19,7 @@ namespace OpenRA.Mods.Common.Traits [Desc("Attach this to the player actor (not a building!) to define a new shared build queue.", "Will only work together with the Production: trait on the actor that actually does the production.", "You will also want to add PrimaryBuildings: to let the user choose where new units should exit.")] - public class ClassicProductionQueueInfo : ProductionQueueInfo, Requires, Requires, Requires + public class ClassicProductionQueueInfo : ProductionQueueInfo, Requires, Requires { [Desc("If you build more actors of the same type,", "the same queue will get its build time lowered for every actor produced there.")] public readonly bool SpeedUp = false; diff --git a/OpenRA.Mods.Common/Traits/Player/ProductionQueue.cs b/OpenRA.Mods.Common/Traits/Player/ProductionQueue.cs index 75d39f7a6a..80a98fef4c 100644 --- a/OpenRA.Mods.Common/Traits/Player/ProductionQueue.cs +++ b/OpenRA.Mods.Common/Traits/Player/ProductionQueue.cs @@ -121,7 +121,6 @@ namespace OpenRA.Mods.Common.Traits self = init.Self; Info = info; playerResources = playerActor.Trait(); - playerPower = playerActor.Trait(); developerMode = playerActor.Trait(); Faction = init.Contains() ? init.Get() : self.Owner.Faction.InternalName; @@ -135,6 +134,11 @@ namespace OpenRA.Mods.Common.Traits void INotifyCreated.Created(Actor self) { + // Special case handling is required for the Player actor. + // Created is called before Player.PlayerActor is assigned, + // so we must query other player traits from self, knowing that + // it refers to the same actor as self.Owner.PlayerActor + playerPower = (self.Info.Name == "player" ? self : self.Owner.PlayerActor).TraitOrDefault(); productionTraits = self.TraitsImplementing().ToArray(); } @@ -152,7 +156,7 @@ namespace OpenRA.Mods.Common.Traits { ClearQueue(); - playerPower = newOwner.PlayerActor.Trait(); + playerPower = newOwner.PlayerActor.TraitOrDefault(); playerResources = newOwner.PlayerActor.Trait(); developerMode = newOwner.PlayerActor.Trait(); @@ -522,7 +526,7 @@ namespace OpenRA.Mods.Common.Traits { get { - return (pm.PowerState == PowerState.Normal) ? RemainingTime : + return (pm == null || pm.PowerState == PowerState.Normal) ? RemainingTime : RemainingTime * Queue.Info.LowPowerSlowdown; } } @@ -570,7 +574,7 @@ namespace OpenRA.Mods.Common.Traits if (Paused) return; - if (pm.PowerState != PowerState.Normal) + if (pm != null && pm.PowerState != PowerState.Normal) { if (--Slowdown <= 0) Slowdown = Queue.Info.LowPowerSlowdown; diff --git a/OpenRA.Mods.Common/Widgets/Logic/Ingame/ObserverStatsLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/Ingame/ObserverStatsLogic.cs index 6ad38bd85b..7f62567c82 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/Ingame/ObserverStatsLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/Ingame/ObserverStatsLogic.cs @@ -255,10 +255,13 @@ namespace OpenRA.Mods.Common.Widgets.Logic template.Get("CASH").GetText = () => "$" + (res.Cash + res.Resources); template.Get("EARNED_MIN").GetText = () => AverageEarnedPerMinute(res.Earned); - var powerRes = player.PlayerActor.Trait(); - var power = template.Get("POWER"); - power.GetText = () => powerRes.PowerDrained + "/" + powerRes.PowerProvided; - power.GetColor = () => GetPowerColor(powerRes.PowerState); + var powerRes = player.PlayerActor.TraitOrDefault(); + if (powerRes != null) + { + var power = template.Get("POWER"); + power.GetText = () => powerRes.PowerDrained + "/" + powerRes.PowerProvided; + power.GetColor = () => GetPowerColor(powerRes.PowerState); + } var stats = player.PlayerActor.TraitOrDefault(); if (stats == null) return template; diff --git a/OpenRA.Mods.Common/Widgets/Logic/Ingame/ProductionTooltipLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/Ingame/ProductionTooltipLogic.cs index 609bfba1ea..7db41fd9bd 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/Ingame/ProductionTooltipLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/Ingame/ProductionTooltipLogic.cs @@ -26,7 +26,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic { var world = player.World; var mapRules = world.Map.Rules; - var pm = player.PlayerActor.Trait(); + var pm = player.PlayerActor.TraitOrDefault(); var pr = player.PlayerActor.Trait(); widget.IsVisible = () => getTooltipIcon() != null && getTooltipIcon().Actor != null; @@ -51,7 +51,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic ActorInfo lastActor = null; Hotkey lastHotkey = Hotkey.Invalid; - var lastPowerState = pm.PowerState; + var lastPowerState = pm == null ? PowerState.Normal : pm.PowerState; tooltipContainer.BeforeRender = () => { @@ -64,7 +64,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic return; var hotkey = tooltipIcon.Hotkey != null ? tooltipIcon.Hotkey.GetValue() : Hotkey.Invalid; - if (actor == lastActor && hotkey == lastHotkey && pm.PowerState == lastPowerState) + if (actor == lastActor && hotkey == lastHotkey && (pm == null || pm.PowerState == lastPowerState)) return; var tooltip = actor.TraitInfos().FirstOrDefault(info => info.EnabledByDefault); @@ -92,19 +92,23 @@ namespace OpenRA.Mods.Common.Widgets.Logic requiresLabel.Text = prereqs.Any() ? requiresFormat.F(prereqs.JoinWith(", ")) : ""; var requiresSize = requiresFont.Measure(requiresLabel.Text); - var power = actor.TraitInfos().Where(i => i.EnabledByDefault).Sum(i => i.Amount); - powerLabel.Text = power.ToString(); - powerLabel.GetColor = () => ((pm.PowerProvided - pm.PowerDrained) >= -power || power > 0) - ? Color.White : Color.Red; - powerLabel.Visible = power != 0; - powerIcon.Visible = power != 0; - var powerSize = font.Measure(powerLabel.Text); + var powerSize = new int2(0, 0); + if (pm != null) + { + var power = actor.TraitInfos().Where(i => i.EnabledByDefault).Sum(i => i.Amount); + powerLabel.Text = power.ToString(); + powerLabel.GetColor = () => ((pm.PowerProvided - pm.PowerDrained) >= -power || power > 0) + ? Color.White : Color.Red; + powerLabel.Visible = power != 0; + powerIcon.Visible = power != 0; + powerSize = font.Measure(powerLabel.Text); + } var buildTime = tooltipIcon.ProductionQueue == null ? 0 : tooltipIcon.ProductionQueue.GetBuildTime(actor, buildable); - var timeMultiplier = pm.PowerState != PowerState.Normal ? tooltipIcon.ProductionQueue.Info.LowPowerSlowdown : 1; + var timeMultiplier = pm != null && pm.PowerState != PowerState.Normal ? tooltipIcon.ProductionQueue.Info.LowPowerSlowdown : 1; timeLabel.Text = formatBuildTime.Update(buildTime * timeMultiplier); - timeLabel.TextColor = (pm.PowerState != PowerState.Normal && tooltipIcon.ProductionQueue.Info.LowPowerSlowdown > 1) ? Color.Red : Color.White; + timeLabel.TextColor = (pm != null && pm.PowerState != PowerState.Normal && tooltipIcon.ProductionQueue.Info.LowPowerSlowdown > 1) ? Color.Red : Color.White; var timeSize = font.Measure(timeLabel.Text); costLabel.Text = cost.ToString(); @@ -127,7 +131,8 @@ namespace OpenRA.Mods.Common.Widgets.Logic lastActor = actor; lastHotkey = hotkey; - lastPowerState = pm.PowerState; + if (pm != null) + lastPowerState = pm.PowerState; }; }