From 4783b1f64692eba4f7893f87848504144204e871 Mon Sep 17 00:00:00 2001 From: atlimit8 Date: Sat, 4 Oct 2014 10:05:33 -0500 Subject: [PATCH 1/8] CaptureActor as Enter subclass & fixes 6658 --- OpenRA.Mods.RA/Activities/CaptureActor.cs | 49 +++++++++++++---------- OpenRA.Mods.RA/Activities/Enter.cs | 3 +- OpenRA.Mods.RA/Capturable.cs | 16 ++++++-- OpenRA.Mods.RA/Captures.cs | 2 +- 4 files changed, 43 insertions(+), 27 deletions(-) diff --git a/OpenRA.Mods.RA/Activities/CaptureActor.cs b/OpenRA.Mods.RA/Activities/CaptureActor.cs index 0e24d260c2..33f0af15b7 100644 --- a/OpenRA.Mods.RA/Activities/CaptureActor.cs +++ b/OpenRA.Mods.RA/Activities/CaptureActor.cs @@ -13,36 +13,45 @@ using OpenRA.Traits; namespace OpenRA.Mods.RA.Activities { - class CaptureActor : Activity + class CaptureActor : Enter { - Target target; + readonly Actor actor; + readonly Capturable capturable; + readonly CapturesInfo capturesInfo; - public CaptureActor(Target target) { this.target = target; } - - public override Activity Tick(Actor self) + public CaptureActor(Actor self, Actor target) + : base(self, target) { - if (IsCanceled || !target.IsValidFor(self)) - return NextActivity; + actor = target; + capturesInfo = self.Info.Traits.Get(); + capturable = target.Trait(); + } - if (target.Type != TargetType.Actor) - return NextActivity; + protected override bool CanReserve(Actor self) + { + return !capturable.BeingCaptured && capturable.Info.CanBeTargetedBy(self, actor.Owner); + } + + protected override void OnInside(Actor self) + { + if (actor.IsDead() || capturable.BeingCaptured) + return; - var actor = target.Actor; var b = actor.TraitOrDefault(); - if (b != null && b.Locked) - return NextActivity; - - var capturesInfo = self.Info.Traits.Get(); - var capturableInfo = actor.Info.Traits.Get(); - - var health = actor.Trait(); + if (b != null && !b.Lock()) + return; self.World.AddFrameEndTask(w => { - if (actor.IsDead()) + if (b != null && b.Locked) + b.Unlock(); + + if (actor.IsDead() || capturable.BeingCaptured) return; - var lowEnoughHealth = health.HP <= capturableInfo.CaptureThreshold * health.MaxHP; + var health = actor.Trait(); + + var lowEnoughHealth = health.HP <= capturable.Info.CaptureThreshold * health.MaxHP; if (!capturesInfo.Sabotage || lowEnoughHealth || actor.Owner.NonCombatant) { var oldOwner = actor.Owner; @@ -63,8 +72,6 @@ namespace OpenRA.Mods.RA.Activities self.Destroy(); }); - - return this; } } } diff --git a/OpenRA.Mods.RA/Activities/Enter.cs b/OpenRA.Mods.RA/Activities/Enter.cs index 9a699b862b..5a648bb647 100755 --- a/OpenRA.Mods.RA/Activities/Enter.cs +++ b/OpenRA.Mods.RA/Activities/Enter.cs @@ -24,6 +24,7 @@ namespace OpenRA.Mods.RA.Activities readonly Activity inside; readonly IMove move; readonly int maxTries = 0; + public Target Target { get { return target; } } Target target; State nextState = State.ApproachingOrEntering; // Hint/starting point for next state bool isEnteringOrInside = false; // Used to know if exiting should be used @@ -97,7 +98,6 @@ namespace OpenRA.Mods.RA.Activities inner.Cancel(self); if (isEnteringOrInside) Unreserve(self, true); - isEnteringOrInside = false; } // Cancel inner activity and mark as done unless already leaving or done @@ -178,6 +178,7 @@ namespace OpenRA.Mods.RA.Activities // Entering isEnteringOrInside = true; savedPos = self.CenterPosition; // Save position of self, before entering, for returning on exit + inner = move.MoveIntoTarget(self, target); // Enter if (inner != null) diff --git a/OpenRA.Mods.RA/Capturable.cs b/OpenRA.Mods.RA/Capturable.cs index b8dcf3600e..ef186484a5 100644 --- a/OpenRA.Mods.RA/Capturable.cs +++ b/OpenRA.Mods.RA/Capturable.cs @@ -14,9 +14,9 @@ using OpenRA.Traits; namespace OpenRA.Mods.RA { [Desc("This actor can be captured by a unit with Captures: trait.")] - class CapturableInfo : TraitInfo + class CapturableInfo : ITraitInfo { - [Desc("Type of actor (the Captures: trait defines what Types it can capture).")] + [Desc("Type listed under Types in Captures: trait of actors that can capture this).")] public readonly string Type = "building"; public readonly bool AllowAllies = false; public readonly bool AllowNeutral = true; @@ -25,6 +25,8 @@ namespace OpenRA.Mods.RA public readonly float CaptureThreshold = 0.5f; public readonly bool CancelActivity = false; + public object Create(ActorInitializer init) { return new Capturable(this); } + public bool CanBeTargetedBy(Actor captor, Player owner) { var c = captor.TraitOrDefault(); @@ -50,10 +52,16 @@ namespace OpenRA.Mods.RA class Capturable : INotifyCapture { + public readonly CapturableInfo Info; + public bool BeingCaptured { get; private set; } + public Capturable(CapturableInfo info) { Info = info; } + public void OnCapture(Actor self, Actor captor, Player oldOwner, Player newOwner) { - var info = self.Info.Traits.Get(); - if (info.CancelActivity) + BeingCaptured = true; + self.World.AddFrameEndTask(w => BeingCaptured = false); + + if (Info.CancelActivity) { var stop = new Order("Stop", self, false); foreach (var t in self.TraitsImplementing()) diff --git a/OpenRA.Mods.RA/Captures.cs b/OpenRA.Mods.RA/Captures.cs index 5b5b9d6e05..c4ff5de9da 100644 --- a/OpenRA.Mods.RA/Captures.cs +++ b/OpenRA.Mods.RA/Captures.cs @@ -75,7 +75,7 @@ namespace OpenRA.Mods.RA self.CancelActivity(); self.SetTargetLine(target, Color.Red); - self.QueueActivity(new Enter(self, target.Actor, new CaptureActor(target))); + self.QueueActivity(new CaptureActor(self, target.Actor)); } class CaptureOrderTargeter : UnitOrderTargeter From 6d0feb9fbfe7d34e5d182a18ea9bdeb65814a30c Mon Sep 17 00:00:00 2001 From: atlimit8 Date: Sat, 4 Oct 2014 11:53:30 -0500 Subject: [PATCH 2/8] Demolish as Enter subclass --- OpenRA.Mods.RA/Activities/Demolish.cs | 40 +++++++++++++-------------- OpenRA.Mods.RA/C4Demolition.cs | 4 +-- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/OpenRA.Mods.RA/Activities/Demolish.cs b/OpenRA.Mods.RA/Activities/Demolish.cs index cb9df8f8c7..a2d4189a0d 100644 --- a/OpenRA.Mods.RA/Activities/Demolish.cs +++ b/OpenRA.Mods.RA/Activities/Demolish.cs @@ -8,24 +8,28 @@ */ #endregion +using System.Collections.Generic; using System.Linq; using OpenRA.Effects; using OpenRA.Traits; namespace OpenRA.Mods.RA.Activities { - class Demolish : Activity + class Demolish : Enter { - readonly Target target; + readonly Actor target; + readonly IEnumerable demolishables; readonly int delay; readonly int flashes; readonly int flashesDelay; readonly int flashInterval; readonly int flashDuration; - public Demolish(Actor target, int delay, int flashes, int flashesDelay, int flashInterval, int flashDuration) + public Demolish(Actor self, Actor target, int delay, int flashes, int flashesDelay, int flashInterval, int flashDuration) + : base(self, target) { - this.target = Target.FromActor(target); + this.target = target; + demolishables = target.TraitsImplementing(); this.delay = delay; this.flashes = flashes; this.flashesDelay = flashesDelay; @@ -33,39 +37,35 @@ namespace OpenRA.Mods.RA.Activities this.flashDuration = flashDuration; } - public override Activity Tick(Actor self) + protected override bool CanReserve(Actor self) { - if (IsCanceled || !target.IsValidFor(self)) - return NextActivity; + return demolishables.Any(i => i.IsValidTarget(target, self)); + } + protected override void OnInside(Actor self) + { self.World.AddFrameEndTask(w => { + if (target.IsDead()) + return; + for (var f = 0; f < flashes; f++) w.Add(new DelayedAction(flashesDelay + f * flashInterval, () => - w.Add(new FlashTarget(target.Actor, ticks: flashDuration)))); + w.Add(new FlashTarget(target, ticks: flashDuration)))); w.Add(new DelayedAction(delay, () => { - // Can't demolish an already dead actor - if (target.Type != TargetType.Actor) + if (target.IsDead()) return; - - - var demolishable = target.Actor.TraitOrDefault(); - if (demolishable == null || !demolishable.IsValidTarget(target.Actor, self)) - return; - - var modifiers = target.Actor.TraitsImplementing() + var modifiers = target.TraitsImplementing() .Concat(self.Owner.PlayerActor.TraitsImplementing()) .Select(t => t.GetDamageModifier(self, null)); if (Util.ApplyPercentageModifiers(100, modifiers) > 0) - demolishable.Demolish(target.Actor, self); + demolishables.Do(d => d.Demolish(target, self)); })); }); - - return NextActivity; } } } diff --git a/OpenRA.Mods.RA/C4Demolition.cs b/OpenRA.Mods.RA/C4Demolition.cs index 2e220bd515..4c291439e4 100644 --- a/OpenRA.Mods.RA/C4Demolition.cs +++ b/OpenRA.Mods.RA/C4Demolition.cs @@ -76,8 +76,8 @@ namespace OpenRA.Mods.RA self.CancelActivity(); self.SetTargetLine(target, Color.Red); - self.QueueActivity(new Enter(self, target.Actor, new Demolish( - target.Actor, info.C4Delay, info.Flashes, info.FlashesDelay, info.FlashInterval, info.FlashDuration))); + self.QueueActivity(new Demolish(self, + target.Actor, info.C4Delay, info.Flashes, info.FlashesDelay, info.FlashInterval, info.FlashDuration)); } public string VoicePhraseForOrder(Actor self, Order order) From 41452dcfebebf23bbe3149c0003893d7125c29a1 Mon Sep 17 00:00:00 2001 From: atlimit8 Date: Sat, 4 Oct 2014 15:53:09 -0500 Subject: [PATCH 3/8] RepairBuilding & RepairBridge as Enter subclasses --- OpenRA.Mods.RA/Activities/RepairBridge.cs | 21 +++++++-------- OpenRA.Mods.RA/Activities/RepairBuilding.cs | 30 ++++++++++++--------- OpenRA.Mods.RA/EngineerRepair.cs | 2 +- OpenRA.Mods.RA/RepairsBridges.cs | 2 +- 4 files changed, 29 insertions(+), 26 deletions(-) diff --git a/OpenRA.Mods.RA/Activities/RepairBridge.cs b/OpenRA.Mods.RA/Activities/RepairBridge.cs index 7d770111c5..7da09d5046 100644 --- a/OpenRA.Mods.RA/Activities/RepairBridge.cs +++ b/OpenRA.Mods.RA/Activities/RepairBridge.cs @@ -12,25 +12,24 @@ using OpenRA.Traits; namespace OpenRA.Mods.RA.Activities { - class RepairBridge : Activity + class RepairBridge : Enter { - Target target; + readonly BridgeHut hut; - public RepairBridge(Actor target) { this.target = Target.FromActor(target); } + public RepairBridge(Actor self, Actor target) + : base(self, target) { hut = target.Trait(); } - public override Activity Tick(Actor self) + protected override bool CanReserve(Actor self) { - if (IsCanceled || target.Type != TargetType.Actor) - return NextActivity; + return hut.BridgeDamageState != DamageState.Undamaged; + } - var hut = target.Actor.Trait(); + protected override void OnInside(Actor self) + { if (hut.BridgeDamageState == DamageState.Undamaged) - return NextActivity; - + return; hut.Repair(self); self.Destroy(); - - return this; } } } diff --git a/OpenRA.Mods.RA/Activities/RepairBuilding.cs b/OpenRA.Mods.RA/Activities/RepairBuilding.cs index b5a813e138..92a3dec918 100644 --- a/OpenRA.Mods.RA/Activities/RepairBuilding.cs +++ b/OpenRA.Mods.RA/Activities/RepairBuilding.cs @@ -12,25 +12,29 @@ using OpenRA.Traits; namespace OpenRA.Mods.RA.Activities { - class RepairBuilding : Activity + class RepairBuilding : Enter { - Target target; + readonly Actor target; + readonly Health health; - public RepairBuilding(Actor target) { this.target = Target.FromActor(target); } - - public override Activity Tick(Actor self) + public RepairBuilding(Actor self, Actor target) + : base(self, target) { - if (IsCanceled || target.Type != TargetType.Actor) - return NextActivity; + this.target = target; + health = target.Trait(); + } - var health = target.Actor.Trait(); + protected override bool CanReserve(Actor self) + { + return health.DamageState != DamageState.Undamaged; + } + + protected override void OnInside(Actor self) + { if (health.DamageState == DamageState.Undamaged) - return NextActivity; - - target.Actor.InflictDamage(self, -health.MaxHP, null); + return; + target.InflictDamage(self, -health.MaxHP, null); self.Destroy(); - - return this; } } } diff --git a/OpenRA.Mods.RA/EngineerRepair.cs b/OpenRA.Mods.RA/EngineerRepair.cs index 60c5cdde8b..eca7376f94 100644 --- a/OpenRA.Mods.RA/EngineerRepair.cs +++ b/OpenRA.Mods.RA/EngineerRepair.cs @@ -78,7 +78,7 @@ namespace OpenRA.Mods.RA self.CancelActivity(); self.SetTargetLine(target, Color.Yellow); - self.QueueActivity(new Enter(self, target.Actor, new RepairBuilding(target.Actor))); + self.QueueActivity(new RepairBuilding(self, target.Actor)); } class EngineerRepairOrderTargeter : UnitOrderTargeter diff --git a/OpenRA.Mods.RA/RepairsBridges.cs b/OpenRA.Mods.RA/RepairsBridges.cs index b3d8087042..ac1bdbaf36 100644 --- a/OpenRA.Mods.RA/RepairsBridges.cs +++ b/OpenRA.Mods.RA/RepairsBridges.cs @@ -59,7 +59,7 @@ namespace OpenRA.Mods.RA self.SetTargetLine(Target.FromOrder(self.World, order), Color.Yellow); self.CancelActivity(); - self.QueueActivity(new Enter(self, order.TargetActor, new RepairBridge(order.TargetActor))); + self.QueueActivity(new RepairBridge(self, order.TargetActor)); } } From c994ee4668ddd7682fe6b1b5a0b599601cfe1b31 Mon Sep 17 00:00:00 2001 From: atlimit8 Date: Sat, 4 Oct 2014 19:07:41 -0500 Subject: [PATCH 4/8] DonateSupplies as Enter subclass --- OpenRA.Mods.RA/Activities/DonateSupplies.cs | 27 +++++++++------------ OpenRA.Mods.RA/SupplyTruck.cs | 2 +- 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/OpenRA.Mods.RA/Activities/DonateSupplies.cs b/OpenRA.Mods.RA/Activities/DonateSupplies.cs index b6407e5823..2bd123ba3c 100644 --- a/OpenRA.Mods.RA/Activities/DonateSupplies.cs +++ b/OpenRA.Mods.RA/Activities/DonateSupplies.cs @@ -13,33 +13,28 @@ using OpenRA.Traits; namespace OpenRA.Mods.RA.Activities { - class DonateSupplies : Activity + class DonateSupplies : Enter { - Target target; - int payload; + readonly Actor target; + readonly int payload; - public DonateSupplies(Actor target, int payload) + public DonateSupplies(Actor self, Actor target, int payload) + : base(self, target) { - this.target = Target.FromActor(target); + this.target = target; this.payload = payload; } - public override Activity Tick(Actor self) + protected override void OnInside(Actor self) { - if (IsCanceled || !target.IsValidFor(self)) - return NextActivity; + if (target.IsDead()) + return; - if (target.Type != TargetType.Actor) - return NextActivity; - - var targetActor = target.Actor; - targetActor.Owner.PlayerActor.Trait().GiveCash(payload); + target.Owner.PlayerActor.Trait().GiveCash(payload); self.Destroy(); if (self.Owner.IsAlliedWith(self.World.RenderPlayer)) - self.World.AddFrameEndTask(w => w.Add(new FloatingText(targetActor.CenterPosition, targetActor.Owner.Color.RGB, FloatingText.FormatCashTick(payload), 30))); - - return this; + self.World.AddFrameEndTask(w => w.Add(new FloatingText(target.CenterPosition, target.Owner.Color.RGB, FloatingText.FormatCashTick(payload), 30))); } } } diff --git a/OpenRA.Mods.RA/SupplyTruck.cs b/OpenRA.Mods.RA/SupplyTruck.cs index 61b392caf2..1b50f07615 100644 --- a/OpenRA.Mods.RA/SupplyTruck.cs +++ b/OpenRA.Mods.RA/SupplyTruck.cs @@ -67,7 +67,7 @@ namespace OpenRA.Mods.RA self.CancelActivity(); self.SetTargetLine(target, Color.Yellow); - self.QueueActivity(new Enter(self, target.Actor, new DonateSupplies(target.Actor, info.Payload))); + self.QueueActivity(new DonateSupplies(self, target.Actor, info.Payload)); } class SupplyTruckOrderTargeter : UnitOrderTargeter From ad24a7023536f18f8b95d88f97547328cb441a26 Mon Sep 17 00:00:00 2001 From: atlimit8 Date: Sat, 4 Oct 2014 19:31:35 -0500 Subject: [PATCH 5/8] Infiltrate as Enter subclass --- OpenRA.Mods.RA/Activities/Infiltrate.cs | 26 ++++++++++++---------- OpenRA.Mods.RA/Infiltration/Infiltrates.cs | 2 +- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/OpenRA.Mods.RA/Activities/Infiltrate.cs b/OpenRA.Mods.RA/Activities/Infiltrate.cs index 9a6b88f921..f2636f67d4 100644 --- a/OpenRA.Mods.RA/Activities/Infiltrate.cs +++ b/OpenRA.Mods.RA/Activities/Infiltrate.cs @@ -13,25 +13,27 @@ using OpenRA.Traits; namespace OpenRA.Mods.RA.Activities { - class Infiltrate : Activity + class Infiltrate : Enter { - Target target; - public Infiltrate(Actor target) { this.target = Target.FromActor(target); } - - public override Activity Tick(Actor self) + readonly Actor target; + public Infiltrate(Actor self, Actor target) + : base(self, target) { - if (IsCanceled || target.Type != TargetType.Actor || target.Actor.Owner == self.Owner) - return NextActivity; + this.target = target; + } - foreach (var t in target.Actor.TraitsImplementing()) - t.Infiltrated(target.Actor, self); + protected override void OnInside(Actor self) + { + if (target.IsDead() || target.Owner == self.Owner) + return; + + foreach (var t in target.TraitsImplementing()) + t.Infiltrated(target, self); self.Destroy(); - if (target.Actor.HasTrait()) + if (target.HasTrait()) Sound.PlayToPlayer(self.Owner, "bldginf1.aud"); - - return this; } } } diff --git a/OpenRA.Mods.RA/Infiltration/Infiltrates.cs b/OpenRA.Mods.RA/Infiltration/Infiltrates.cs index 78d4b97ee1..4c8d5e8504 100644 --- a/OpenRA.Mods.RA/Infiltration/Infiltrates.cs +++ b/OpenRA.Mods.RA/Infiltration/Infiltrates.cs @@ -96,7 +96,7 @@ namespace OpenRA.Mods.RA.Infiltration self.CancelActivity(); self.SetTargetLine(target, Color.Red); - self.QueueActivity(new Enter(self, target.Actor, new Infiltrate(target.Actor))); + self.QueueActivity(new Infiltrate(self, target.Actor)); } } } From b736e059e92aacb11411a0144b7666e4c15fc459 Mon Sep 17 00:00:00 2001 From: atlimit8 Date: Sat, 4 Oct 2014 19:38:44 -0500 Subject: [PATCH 6/8] Removed Enter(Actor self, Actor target, Activity inside) & made Enter abstract --- OpenRA.Mods.RA/Activities/Enter.cs | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/OpenRA.Mods.RA/Activities/Enter.cs b/OpenRA.Mods.RA/Activities/Enter.cs index 5a648bb647..c1ccd61cf5 100755 --- a/OpenRA.Mods.RA/Activities/Enter.cs +++ b/OpenRA.Mods.RA/Activities/Enter.cs @@ -16,12 +16,11 @@ using OpenRA.Traits; namespace OpenRA.Mods.RA.Activities { - public class Enter : Activity + public abstract class Enter : Activity { public enum ReserveStatus { None, TooFar, Pending, Ready } enum State { ApproachingOrEntering, Inside, Exiting, Done } - readonly Activity inside; readonly IMove move; readonly int maxTries = 0; public Target Target { get { return target; } } @@ -33,16 +32,10 @@ namespace OpenRA.Mods.RA.Activities bool firstApproach = true; protected Enter(Actor self, Actor target, int maxTries = 1) - : this(self, target, null) - { - this.maxTries = maxTries; - } - - public Enter(Actor self, Actor target, Activity inside) { this.move = self.Trait(); this.target = Target.FromActor(target); - this.inside = inside; + this.maxTries = maxTries; } // CanEnter(target) should to be true; othwise, Enter may abort. @@ -84,7 +77,7 @@ namespace OpenRA.Mods.RA.Activities } // Called when inner activity is this and returns inner activity for next tick. - protected virtual Activity InsideTick(Actor self) { return Util.RunActivity(self, inside); } + protected virtual Activity InsideTick(Actor self) { return null; } // Abort entering and/or leave if necessary protected virtual void AbortOrExit(Actor self) From acc0b618c8b1e414f1b8ae7233206961464d6541 Mon Sep 17 00:00:00 2001 From: atlimit8 Date: Sun, 5 Oct 2014 11:38:06 -0500 Subject: [PATCH 7/8] Restricted terrain targeting to force-move enter transports --- OpenRA.Mods.RA/Activities/Enter.cs | 6 ++++-- OpenRA.Mods.RA/Activities/EnterTransport.cs | 4 ++-- OpenRA.Mods.RA/Passenger.cs | 3 ++- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/OpenRA.Mods.RA/Activities/Enter.cs b/OpenRA.Mods.RA/Activities/Enter.cs index c1ccd61cf5..86dde98b61 100755 --- a/OpenRA.Mods.RA/Activities/Enter.cs +++ b/OpenRA.Mods.RA/Activities/Enter.cs @@ -23,6 +23,7 @@ namespace OpenRA.Mods.RA.Activities readonly IMove move; readonly int maxTries = 0; + readonly bool targetCenter; public Target Target { get { return target; } } Target target; State nextState = State.ApproachingOrEntering; // Hint/starting point for next state @@ -31,11 +32,12 @@ namespace OpenRA.Mods.RA.Activities Activity inner; bool firstApproach = true; - protected Enter(Actor self, Actor target, int maxTries = 1) + protected Enter(Actor self, Actor target, int maxTries = 1, bool targetCenter = false) { this.move = self.Trait(); this.target = Target.FromActor(target); this.maxTries = maxTries; + this.targetCenter = targetCenter; } // CanEnter(target) should to be true; othwise, Enter may abort. @@ -160,7 +162,7 @@ namespace OpenRA.Mods.RA.Activities case ReserveStatus.None: return State.Done; // No available target -> abort to next activity case ReserveStatus.TooFar: - inner = move.MoveToTarget(self, Target.FromPos(target.CenterPosition)); // Approach + inner = move.MoveToTarget(self, targetCenter ? Target.FromPos(target.CenterPosition) : target); // Approach return State.ApproachingOrEntering; case ReserveStatus.Pending: return State.ApproachingOrEntering; // Retry next tick diff --git a/OpenRA.Mods.RA/Activities/EnterTransport.cs b/OpenRA.Mods.RA/Activities/EnterTransport.cs index df8230cbce..932ba3ee6e 100644 --- a/OpenRA.Mods.RA/Activities/EnterTransport.cs +++ b/OpenRA.Mods.RA/Activities/EnterTransport.cs @@ -21,8 +21,8 @@ namespace OpenRA.Mods.RA.Activities readonly int maxTries; Cargo cargo; - public EnterTransport(Actor self, Actor transport, int maxTries = 0) - : base(self, transport, maxTries) + public EnterTransport(Actor self, Actor transport, int maxTries = 0, bool targetCenter = false) + : base(self, transport, maxTries, targetCenter) { this.transport = transport; this.maxTries = maxTries; diff --git a/OpenRA.Mods.RA/Passenger.cs b/OpenRA.Mods.RA/Passenger.cs index 2e65cb3d96..3e4de0ff48 100644 --- a/OpenRA.Mods.RA/Passenger.cs +++ b/OpenRA.Mods.RA/Passenger.cs @@ -165,7 +165,8 @@ namespace OpenRA.Mods.RA self.SetTargetLine(target, Color.Green); self.CancelActivity(); - self.QueueActivity(new EnterTransport(self, order.TargetActor, order.OrderString == "EnterTransport" ? 0 : Info.MaxAlternateTransportAttempts)); + var transports = order.OrderString == "EnterTransports"; + self.QueueActivity(new EnterTransport(self, order.TargetActor, transports ? Info.MaxAlternateTransportAttempts : 0, transports)); } } From 3b21c9713f1798b718b826e3466d52ae773005cd Mon Sep 17 00:00:00 2001 From: atlimit8 Date: Mon, 6 Oct 2014 16:05:07 -0500 Subject: [PATCH 8/8] Added bridge hut repair tracking --- OpenRA.Mods.RA/Activities/RepairBridge.cs | 9 +- OpenRA.Mods.RA/Bridge.cs | 151 ++++++++++++---------- OpenRA.Mods.RA/BridgeHut.cs | 20 ++- 3 files changed, 103 insertions(+), 77 deletions(-) diff --git a/OpenRA.Mods.RA/Activities/RepairBridge.cs b/OpenRA.Mods.RA/Activities/RepairBridge.cs index 7da09d5046..3b0aab74ba 100644 --- a/OpenRA.Mods.RA/Activities/RepairBridge.cs +++ b/OpenRA.Mods.RA/Activities/RepairBridge.cs @@ -17,16 +17,19 @@ namespace OpenRA.Mods.RA.Activities readonly BridgeHut hut; public RepairBridge(Actor self, Actor target) - : base(self, target) { hut = target.Trait(); } + : base(self, target) + { + hut = target.Trait(); + } protected override bool CanReserve(Actor self) { - return hut.BridgeDamageState != DamageState.Undamaged; + return hut.BridgeDamageState != DamageState.Undamaged && !hut.Repairing && hut.Bridge.GetHut(0) != null && hut.Bridge.GetHut(1) != null; } protected override void OnInside(Actor self) { - if (hut.BridgeDamageState == DamageState.Undamaged) + if (hut.BridgeDamageState == DamageState.Undamaged || hut.Repairing || hut.Bridge.GetHut(0) == null || hut.Bridge.GetHut(1) == null) return; hut.Repair(self); self.Destroy(); diff --git a/OpenRA.Mods.RA/Bridge.cs b/OpenRA.Mods.RA/Bridge.cs index 99ce0780ac..c68f79332c 100644 --- a/OpenRA.Mods.RA/Bridge.cs +++ b/OpenRA.Mods.RA/Bridge.cs @@ -8,6 +8,7 @@ */ #endregion +using System; using System.Collections.Generic; using System.Linq; using OpenRA.Effects; @@ -34,7 +35,7 @@ namespace OpenRA.Mods.RA public readonly ushort DestroyedPlusSouthTemplate = 0; public readonly ushort DestroyedPlusBothTemplate = 0; - public readonly string[] ShorePieces = {"br1", "br2"}; + public readonly string[] ShorePieces = { "br1", "br2" }; public readonly int[] NorthOffset = null; public readonly int[] SouthOffset = null; @@ -68,16 +69,19 @@ namespace OpenRA.Mods.RA } } - class Bridge: IRender, INotifyDamageStateChanged + class Bridge : IRender, INotifyDamageStateChanged { + readonly Bridge[] neighbours = new Bridge[2]; + readonly BridgeHut[] huts = new BridgeHut[2]; // Huts before this / first & after this / last + public readonly Health Health; + ushort template; Dictionary footprint; - Actor self; - BridgeInfo Info; + + public BridgeInfo Info; public string Type; - Bridge northNeighbour, southNeighbour; - Health Health; + public BridgeHut Hut { get; internal set; } public Bridge(Actor self, BridgeInfo info) { @@ -88,6 +92,21 @@ namespace OpenRA.Mods.RA this.Type = self.Info.Name; } + public Bridge Neighbour(int direction) { return neighbours[direction]; } + public IEnumerable Enumerate(int direction, bool includeSelf = false) + { + for (var b = includeSelf ? this : neighbours[direction]; b != null; b = b.neighbours[direction]) + yield return b; + } + + public void Do(Action action) + { + action(this, -1); + for (var d = 0; d <= 1; d++) + if (neighbours[d] != null) + action(neighbours[d], d); + } + public void Create(ushort template, Dictionary footprint) { this.template = template; @@ -107,11 +126,31 @@ namespace OpenRA.Mods.RA public void LinkNeighbouringBridges(World world, BridgeLayer bridges) { - // go looking for our neighbors if this is a long bridge. - if (Info.NorthOffset != null) - northNeighbour = GetNeighbor(Info.NorthOffset, bridges); - if (Info.SouthOffset != null) - southNeighbour = GetNeighbor(Info.SouthOffset, bridges); + for (var d = 0; d <= 1; d++) + { + if (neighbours[d] != null) + continue; // Already linked by reverse lookup + + var offset = d == 0 ? Info.NorthOffset : Info.SouthOffset; + if (offset == null) + continue; // End piece type + + neighbours[d] = GetNeighbor(offset, bridges); + if (neighbours[d] != null) + neighbours[d].neighbours[1 - d] = this; // Save reverse lookup + } + } + + public BridgeHut GetHut(int index) + { + if (huts[index] != null) + return huts[index]; // Already found + + var n = neighbours[index]; + if (n == null) + return huts[index] = Hut; // End piece + + return huts[index] = n.Hut ?? n.GetHut(index); } public Bridge GetNeighbor(int[] offset, BridgeLayer bridges) @@ -166,10 +205,7 @@ namespace OpenRA.Mods.RA if (!Info.Long) return Health.IsDead; - if (NeighbourIsDeadShore(northNeighbour)) - return true; - - if (NeighbourIsDeadShore(southNeighbour)) + if (NeighbourIsDeadShore(neighbours[0]) || NeighbourIsDeadShore(neighbours[1])) return true; return Health.IsDead; @@ -180,13 +216,13 @@ namespace OpenRA.Mods.RA if (Info.Long && LongBridgeSegmentIsDead()) { // Long bridges have custom art for multiple segments being destroyed - var northIsDead = northNeighbour != null && northNeighbour.LongBridgeSegmentIsDead(); - var southIsDead = southNeighbour != null && southNeighbour.LongBridgeSegmentIsDead(); - if (northIsDead && southIsDead) + var previousIsDead = neighbours[0] != null && neighbours[0].LongBridgeSegmentIsDead(); + var nextIsDead = neighbours[1] != null && neighbours[1].LongBridgeSegmentIsDead(); + if (previousIsDead && nextIsDead) return Info.DestroyedPlusBothTemplate; - if (northIsDead) + if (previousIsDead) return Info.DestroyedPlusNorthTemplate; - if (southIsDead) + if (nextIsDead) return Info.DestroyedPlusSouthTemplate; return Info.DestroyedTemplate; @@ -223,7 +259,7 @@ namespace OpenRA.Mods.RA } } - public void Repair(Actor repairer, bool continueNorth, bool continueSouth) + public void Repair(Actor repairer, int direction, Action onComplete) { // Repair self var initialDamage = Health.DamageState; @@ -237,68 +273,56 @@ namespace OpenRA.Mods.RA } else Health.InflictDamage(self, repairer, -Health.MaxHP, null, true); + if (direction < 0 ? neighbours[0] == null && neighbours[1] == null : Hut != null || neighbours[direction] == null) + onComplete(); // Done if single or reached other hut }); - // Repair adjacent spans (long bridges) - if (continueNorth && northNeighbour != null) + // Repair adjacent spans onto next hut or end + if (direction >= 0 && Hut == null && neighbours[direction] != null) { - var delay = initialDamage == DamageState.Undamaged || NeighbourIsDeadShore(northNeighbour) ? + var delay = initialDamage == DamageState.Undamaged || NeighbourIsDeadShore(neighbours[direction]) ? 0 : Info.RepairPropagationDelay; self.World.AddFrameEndTask(w => w.Add(new DelayedAction(delay, () => - northNeighbour.Repair(repairer, true, false)))); - } - - if (continueSouth && southNeighbour != null) - { - var delay = initialDamage == DamageState.Undamaged || NeighbourIsDeadShore(southNeighbour) ? - 0 : Info.RepairPropagationDelay; - - self.World.AddFrameEndTask(w => w.Add(new DelayedAction(delay, () => - southNeighbour.Repair(repairer, false, true)))); + neighbours[direction].Repair(repairer, direction, onComplete)))); } } public void DamageStateChanged(Actor self, AttackInfo e) { - UpdateState(); - if (northNeighbour != null) - northNeighbour.UpdateState(); - if (southNeighbour != null) - southNeighbour.UpdateState(); + Do((b, d) => b.UpdateState()); // Need to update the neighbours neighbour to correctly // display the broken shore hack if (Info.ShorePieces.Contains(Type)) - { - if (northNeighbour != null && northNeighbour.northNeighbour != null) - northNeighbour.northNeighbour.UpdateState(); - if (southNeighbour != null && southNeighbour.southNeighbour != null) - southNeighbour.southNeighbour.UpdateState(); - } + for (var d = 0; d <= 1; d++) + if (neighbours[d] != null && neighbours[d].neighbours[d] != null) + neighbours[d].neighbours[d].UpdateState(); } + void AggregateDamageState(Bridge b, int d, ref DamageState damage) + { + if (b.Health.DamageState > damage) + damage = b.Health.DamageState; + if (b.Hut == null && b.neighbours[d] != null) + AggregateDamageState(b.neighbours[d], d, ref damage); + } + + // Find the worst span damage before other hut public DamageState AggregateDamageState() { - // Find the worst span damage in the entire bridge - var br = this; - while (br.northNeighbour != null) - br = br.northNeighbour; - var damage = Health.DamageState; - for (var b = br; b != null; b = b.southNeighbour) - if (b.Health.DamageState > damage) - damage = b.Health.DamageState; - + Do((b, d) => AggregateDamageState(b, d, ref damage)); return damage; } - public void Demolish(Actor saboteur, bool continueNorth, bool continueSouth) + public void Demolish(Actor saboteur, int direction) { var initialDamage = Health.DamageState; self.World.AddFrameEndTask(w => { var weapon = saboteur.World.Map.Rules.Weapons[Info.DemolishWeapon.ToLowerInvariant()]; + // Use .FromPos since this actor is killed. Cannot use Target.FromActor weapon.Impact(Target.FromPos(self.CenterPosition), saboteur, Enumerable.Empty()); @@ -306,23 +330,14 @@ namespace OpenRA.Mods.RA self.Kill(saboteur); }); - // Destroy adjacent spans (long bridges) - if (continueNorth && northNeighbour != null) + // Destroy adjacent spans between (including) huts + if (direction >= 0 && Hut == null && neighbours[direction] != null) { - var delay = initialDamage == DamageState.Dead || NeighbourIsDeadShore(northNeighbour) ? + var delay = initialDamage == DamageState.Dead || NeighbourIsDeadShore(neighbours[direction]) ? 0 : Info.RepairPropagationDelay; self.World.AddFrameEndTask(w => w.Add(new DelayedAction(delay, () => - northNeighbour.Demolish(saboteur, true, false)))); - } - - if (continueSouth && southNeighbour != null) - { - var delay = initialDamage == DamageState.Dead || NeighbourIsDeadShore(southNeighbour) ? - 0 : Info.RepairPropagationDelay; - - self.World.AddFrameEndTask(w => w.Add(new DelayedAction(delay, () => - southNeighbour.Demolish(saboteur, false, true)))); + neighbours[direction].Demolish(saboteur, direction)))); } } } diff --git a/OpenRA.Mods.RA/BridgeHut.cs b/OpenRA.Mods.RA/BridgeHut.cs index b26434f0ad..00bdd898ab 100644 --- a/OpenRA.Mods.RA/BridgeHut.cs +++ b/OpenRA.Mods.RA/BridgeHut.cs @@ -8,6 +8,8 @@ */ #endregion +using System; +using System.Linq; using OpenRA.Traits; namespace OpenRA.Mods.RA @@ -21,28 +23,34 @@ namespace OpenRA.Mods.RA class BridgeHut : IDemolishable { - public Bridge bridge; + Lazy firstBridge; + int repairDirections = 0; + public readonly Bridge Bridge; + public Bridge FirstBridge { get { return firstBridge.Value; } } + public DamageState BridgeDamageState { get { return Bridge.AggregateDamageState(); } } + public bool Repairing { get { return repairDirections > 0; } } public BridgeHut(ActorInitializer init) { - bridge = init.Get().value.Trait(); + Bridge = init.Get().value.Trait(); + Bridge.Hut = this; + firstBridge = new Lazy(() => Bridge.Enumerate(0, true).Last()); } public void Repair(Actor repairer) { - bridge.Repair(repairer, true, true); + repairDirections = Bridge.GetHut(0) != this && Bridge.GetHut(1) != this ? 2 : 1; + Bridge.Do((b, d) => b.Repair(repairer, d, () => repairDirections--)); } public void Demolish(Actor self, Actor saboteur) { - bridge.Demolish(saboteur, true, true); + Bridge.Do((b, d) => b.Demolish(saboteur, d)); } public bool IsValidTarget(Actor self, Actor saboteur) { return BridgeDamageState != DamageState.Dead; } - - public DamageState BridgeDamageState { get { return bridge.AggregateDamageState(); } } } }