diff --git a/OpenRA.Mods.Cnc/Traits/AttackPopupTurreted.cs b/OpenRA.Mods.Cnc/Traits/AttackPopupTurreted.cs index 1d4f9f64ea..ced8857a80 100644 --- a/OpenRA.Mods.Cnc/Traits/AttackPopupTurreted.cs +++ b/OpenRA.Mods.Cnc/Traits/AttackPopupTurreted.cs @@ -62,7 +62,7 @@ namespace OpenRA.Mods.Cnc.Traits protected override bool CanAttack(Actor self, Target target) { - if (state == PopupState.Transitioning || !building.Value.BuildComplete) + if (state == PopupState.Transitioning || !building.BuildComplete) return false; if (!base.CanAttack(self, target)) diff --git a/OpenRA.Mods.Common/Traits/Air/AttackBomber.cs b/OpenRA.Mods.Common/Traits/Air/AttackBomber.cs index ca77832a04..09eb8cf124 100644 --- a/OpenRA.Mods.Common/Traits/Air/AttackBomber.cs +++ b/OpenRA.Mods.Common/Traits/Air/AttackBomber.cs @@ -54,7 +54,7 @@ namespace OpenRA.Mods.Common.Traits inAttackRange = false; - var f = facing.Value.Facing; + var f = facing.Facing; var delta = target.CenterPosition - self.CenterPosition; var facingToTarget = delta.HorizontalLengthSquared != 0 ? delta.Yaw.Facing : f; facingTarget = Math.Abs(facingToTarget - f) % 256 <= info.FacingTolerance; @@ -66,7 +66,7 @@ namespace OpenRA.Mods.Common.Traits continue; inAttackRange = true; - a.CheckFire(self, facing.Value, bombTarget); + a.CheckFire(self, facing, bombTarget); } // Guns only fire when approaching the target @@ -81,7 +81,7 @@ namespace OpenRA.Mods.Common.Traits var gunPos = self.CenterPosition - new WVec(0, a.MaxRange().Length / 2, 0).Rotate(WRot.FromFacing(f)); var gunHeight = self.World.Map.DistanceAboveTerrain(gunPos); - a.CheckFire(self, facing.Value, Target.FromPos(gunPos - new WVec(WDist.Zero, WDist.Zero, gunHeight))); + a.CheckFire(self, facing, Target.FromPos(gunPos - new WVec(WDist.Zero, WDist.Zero, gunHeight))); } } diff --git a/OpenRA.Mods.Common/Traits/Attack/AttackBase.cs b/OpenRA.Mods.Common/Traits/Attack/AttackBase.cs index da484f47b4..b9508be1b0 100644 --- a/OpenRA.Mods.Common/Traits/Attack/AttackBase.cs +++ b/OpenRA.Mods.Common/Traits/Attack/AttackBase.cs @@ -39,7 +39,7 @@ namespace OpenRA.Mods.Common.Traits public override abstract object Create(ActorInitializer init); } - public abstract class AttackBase : ConditionalTrait, IIssueOrder, IResolveOrder, IOrderVoice, ISync + public abstract class AttackBase : ConditionalTrait, INotifyCreated, IIssueOrder, IResolveOrder, IOrderVoice, ISync { readonly string attackOrderName = "Attack"; readonly string forceAttackOrderName = "ForceAttack"; @@ -47,9 +47,9 @@ namespace OpenRA.Mods.Common.Traits [Sync] public bool IsAttacking { get; internal set; } public IEnumerable Armaments { get { return getArmaments(); } } - protected Lazy facing; - protected Lazy building; - protected Lazy positionable; + protected IFacing facing; + protected Building building; + protected IPositionable positionable; protected Func> getArmaments; readonly Actor self; @@ -58,15 +58,23 @@ namespace OpenRA.Mods.Common.Traits : base(info) { this.self = self; + } - var armaments = Exts.Lazy(() => self.TraitsImplementing() - .Where(a => info.Armaments.Contains(a.Info.Name)).ToArray()); + void INotifyCreated.Created(Actor self) + { + facing = self.TraitOrDefault(); + building = self.TraitOrDefault(); + positionable = self.TraitOrDefault(); - getArmaments = () => armaments.Value; + getArmaments = InitializeGetArmaments(self); + } - facing = Exts.Lazy(() => self.TraitOrDefault()); - building = Exts.Lazy(() => self.TraitOrDefault()); - positionable = Exts.Lazy(() => self.Trait()); + protected virtual Func> InitializeGetArmaments(Actor self) + { + var armaments = self.TraitsImplementing() + .Where(a => Info.Armaments.Contains(a.Info.Name)).ToArray(); + + return () => armaments; } protected virtual bool CanAttack(Actor self, Target target) @@ -85,7 +93,7 @@ namespace OpenRA.Mods.Common.Traits return false; // Building is under construction or is being sold - if (building.Value != null && !building.Value.BuildComplete) + if (building != null && !building.BuildComplete) return false; if (Armaments.All(a => a.IsReloading)) @@ -100,7 +108,7 @@ namespace OpenRA.Mods.Common.Traits return; foreach (var a in armaments ?? Armaments) - a.CheckFire(self, facing.Value, target); + a.CheckFire(self, facing, target); } public IEnumerable Orders @@ -188,7 +196,7 @@ namespace OpenRA.Mods.Common.Traits if (IsTraitDisabled) return false; - if (Info.AttackRequiresEnteringCell && !positionable.Value.CanEnterCell(t.Actor.Location, null, false)) + if (Info.AttackRequiresEnteringCell && (positionable == null || !positionable.CanEnterCell(t.Actor.Location, null, false))) return false; // PERF: Avoid LINQ. diff --git a/OpenRA.Mods.Common/Traits/Attack/AttackFrontal.cs b/OpenRA.Mods.Common/Traits/Attack/AttackFrontal.cs index 9420483922..f8ff0c9c35 100644 --- a/OpenRA.Mods.Common/Traits/Attack/AttackFrontal.cs +++ b/OpenRA.Mods.Common/Traits/Attack/AttackFrontal.cs @@ -38,7 +38,7 @@ namespace OpenRA.Mods.Common.Traits if (!base.CanAttack(self, target)) return false; - var f = facing.Value.Facing; + var f = facing.Facing; var delta = target.CenterPosition - self.CenterPosition; var facingToTarget = delta.HorizontalLengthSquared != 0 ? delta.Yaw.Facing : f; diff --git a/OpenRA.Mods.Common/Traits/Attack/AttackGarrisoned.cs b/OpenRA.Mods.Common/Traits/Attack/AttackGarrisoned.cs index d8ba2d3a0c..fafddd3566 100644 --- a/OpenRA.Mods.Common/Traits/Attack/AttackGarrisoned.cs +++ b/OpenRA.Mods.Common/Traits/Attack/AttackGarrisoned.cs @@ -92,8 +92,11 @@ namespace OpenRA.Mods.Common.Traits paxFacing = new Dictionary(); paxPos = new Dictionary(); paxRender = new Dictionary(); + } - getArmaments = () => armaments; + protected override Func> InitializeGetArmaments(Actor self) + { + return () => armaments; } void INotifyPassengerEntered.OnPassengerEntered(Actor self, Actor passenger) @@ -117,7 +120,7 @@ namespace OpenRA.Mods.Common.Traits FirePort SelectFirePort(Actor self, WAngle targetYaw) { // Pick a random port that faces the target - var bodyYaw = facing.Value != null ? WAngle.FromFacing(facing.Value.Facing) : WAngle.Zero; + var bodyYaw = facing != null ? WAngle.FromFacing(facing.Facing) : WAngle.Zero; var indices = Enumerable.Range(0, Info.Ports.Length).Shuffle(self.World.SharedRandom); foreach (var i in indices) { @@ -155,7 +158,7 @@ namespace OpenRA.Mods.Common.Traits paxFacing[a.Actor].Facing = muzzleFacing; paxPos[a.Actor].SetVisualPosition(a.Actor, pos + PortOffset(self, port)); - var barrel = a.CheckFire(a.Actor, facing.Value, target); + var barrel = a.CheckFire(a.Actor, facing, target); if (barrel == null) continue; diff --git a/OpenRA.Mods.D2k/Traits/AttackSwallow.cs b/OpenRA.Mods.D2k/Traits/AttackSwallow.cs index 5bcabb4768..53e04f1a09 100644 --- a/OpenRA.Mods.D2k/Traits/AttackSwallow.cs +++ b/OpenRA.Mods.D2k/Traits/AttackSwallow.cs @@ -64,7 +64,7 @@ namespace OpenRA.Mods.D2k.Traits return; self.CancelActivity(); - self.QueueActivity(new SwallowActor(self, target, a, facing.Value)); + self.QueueActivity(new SwallowActor(self, target, a, facing)); } } }