From ac5a4589ea8418dbcfa60012c25960676ee5cb49 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Wed, 19 Mar 2014 13:10:19 +1300 Subject: [PATCH 1/6] Add IMove.MoveIntoWorld and IMove.VisualMove. --- OpenRA.Game/Traits/TraitsInterfaces.cs | 2 ++ OpenRA.Mods.RA/Air/Helicopter.cs | 11 +++++++++++ OpenRA.Mods.RA/Air/Plane.cs | 3 +++ OpenRA.Mods.RA/Move/Mobile.cs | 26 ++++++++++++++++++++++++++ 4 files changed, 42 insertions(+) diff --git a/OpenRA.Game/Traits/TraitsInterfaces.cs b/OpenRA.Game/Traits/TraitsInterfaces.cs index 035a52e565..9f2faa50ec 100755 --- a/OpenRA.Game/Traits/TraitsInterfaces.cs +++ b/OpenRA.Game/Traits/TraitsInterfaces.cs @@ -161,6 +161,8 @@ namespace OpenRA.Traits Activity MoveTo(CPos cell, Actor ignoredActor); Activity MoveWithinRange(Target target, WRange range); Activity MoveFollow(Actor self, Target target, WRange range); + Activity MoveIntoWorld(Actor self, CPos cell); + Activity VisualMove(Actor self, WPos fromPos, WPos toPos); CPos NearestMoveableCell(CPos target); bool IsMoving { get; set; } } diff --git a/OpenRA.Mods.RA/Air/Helicopter.cs b/OpenRA.Mods.RA/Air/Helicopter.cs index d1687f109a..8996daec2b 100755 --- a/OpenRA.Mods.RA/Air/Helicopter.cs +++ b/OpenRA.Mods.RA/Air/Helicopter.cs @@ -159,5 +159,16 @@ namespace OpenRA.Mods.RA.Air public Activity MoveWithinRange(Target target, WRange minRange, WRange maxRange) { return new HeliFly(self, target, minRange, maxRange); } public Activity MoveFollow(Actor self, Target target, WRange range) { return new Follow(self, target, range); } public CPos NearestMoveableCell(CPos cell) { return cell; } + + public Activity MoveIntoWorld(Actor self, CPos cell) + { + return new HeliFly(self, Target.FromCell(cell)); + } + + public Activity VisualMove(Actor self, WPos fromPos, WPos toPos) + { + // TODO: Ignore repulsion when moving + return Util.SequenceActivities(new CallFunc(() => SetVisualPosition(self, fromPos)), new HeliFly(self, Target.FromPos(toPos))); + } } } diff --git a/OpenRA.Mods.RA/Air/Plane.cs b/OpenRA.Mods.RA/Air/Plane.cs index 07e15802b0..a154ecc6be 100755 --- a/OpenRA.Mods.RA/Air/Plane.cs +++ b/OpenRA.Mods.RA/Air/Plane.cs @@ -100,5 +100,8 @@ namespace OpenRA.Mods.RA.Air public Activity MoveWithinRange(Target target, WRange minRange, WRange maxRange) { return Util.SequenceActivities(new Fly(self, target, minRange, maxRange), new FlyCircle()); } public Activity MoveFollow(Actor self, Target target, WRange range) { return new FlyFollow(self, target, range); } public CPos NearestMoveableCell(CPos cell) { return cell; } + + public Activity MoveIntoWorld(Actor self, CPos cell) { return new Fly(self, Target.FromCell(cell)); } + public Activity VisualMove(Actor self, WPos fromPos, WPos toPos) { return Util.SequenceActivities(new CallFunc(() => SetVisualPosition(self, fromPos)), new Fly(self, Target.FromPos(toPos))); } } } diff --git a/OpenRA.Mods.RA/Move/Mobile.cs b/OpenRA.Mods.RA/Move/Mobile.cs index b281669538..01696b4b17 100755 --- a/OpenRA.Mods.RA/Move/Mobile.cs +++ b/OpenRA.Mods.RA/Move/Mobile.cs @@ -548,5 +548,31 @@ namespace OpenRA.Mods.RA.Move if (self.IsIdle && self.AppearsFriendlyTo(blocking)) Nudge(self, blocking, true); } + + public Activity MoveIntoWorld(Actor self, CPos cell) + { + var pos = self.CenterPosition; + + // Reserve the exit cell + SetPosition(self, cell); + SetVisualPosition(self, pos); + + // Animate transition + var to = cell.CenterPosition; + var speed = MovementSpeedForCell(self, cell); + var length = speed > 0 ? (to - pos).Length / speed : 0; + + var facing = Util.GetFacing(to - pos, Facing); + return Util.SequenceActivities(new Turn(facing), new Drag(pos, to, length)); + } + + public Activity VisualMove(Actor self, WPos fromPos, WPos toPos) + { + var speed = MovementSpeedForCell(self, self.Location); + var length = speed > 0 ? (toPos - fromPos).Length / speed : 0; + + var facing = Util.GetFacing(toPos - fromPos, Facing); + return Util.SequenceActivities(new Turn(facing), new Drag(fromPos, toPos, length)); + } } } From 8b3b894fc5bde650983df4f2575a489b84e33891 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Wed, 19 Mar 2014 13:11:30 +1300 Subject: [PATCH 2/6] Use MoveIntoWorld for production. --- OpenRA.Mods.RA/Production.cs | 22 +++++----------------- mods/ra/rules/structures.yaml | 2 ++ 2 files changed, 7 insertions(+), 17 deletions(-) diff --git a/OpenRA.Mods.RA/Production.cs b/OpenRA.Mods.RA/Production.cs index 715a37c38f..291bd89683 100755 --- a/OpenRA.Mods.RA/Production.cs +++ b/OpenRA.Mods.RA/Production.cs @@ -34,6 +34,7 @@ namespace OpenRA.Mods.RA [Desc("Cell offset where the exiting actor enters the ActorMap")] public readonly CVec ExitCell = CVec.Zero; public readonly int Facing = -1; + public readonly bool MoveIntoWorld = true; } public class Exit { } @@ -58,28 +59,15 @@ namespace OpenRA.Mods.RA var newUnit = self.World.CreateActor(producee.Name, new TypeDictionary { new OwnerInit(self.Owner), - new LocationInit(exit), + new CenterPositionInit(spawn), new FacingInit(initialFacing) }); - // TODO: Move this into an *Init - // TODO: We should be adjusting the actual position for aircraft, not just visuals. - var teleportable = newUnit.Trait(); - teleportable.SetVisualPosition(newUnit, spawn); - - // TODO: Generalize this for non-mobile (e.g. aircraft) too - // Remember to update the Enter activity too - var mobile = newUnit.TraitOrDefault(); - if (mobile != null) - { - // Animate the spawn -> exit transition - var speed = mobile.MovementSpeedForCell(newUnit, exit); - var length = speed > 0 ? (to - spawn).Length / speed : 0; - newUnit.QueueActivity(new Drag(spawn, to, length)); - } + var move = newUnit.Trait(); + if (exitinfo.MoveIntoWorld) + newUnit.QueueActivity(move.MoveIntoWorld(newUnit, exit)); var target = MoveToRallyPoint(self, newUnit, exit); - newUnit.SetTargetLine(Target.FromCell(target), Color.Green, false); foreach (var t in self.TraitsImplementing()) t.UnitProduced(self, newUnit, exit); diff --git a/mods/ra/rules/structures.yaml b/mods/ra/rules/structures.yaml index 384f3e7f31..21ed09bb2f 100644 --- a/mods/ra/rules/structures.yaml +++ b/mods/ra/rules/structures.yaml @@ -1025,6 +1025,7 @@ HPAD: Exit@1: SpawnOffset: 0,-256,0 ExitCell: 0,0 + MoveIntoWorld: false Production: Produces: Helicopter Reservable: @@ -1059,6 +1060,7 @@ AFLD: SpawnOffset: 0,170,0 ExitCell: 1,1 Facing: 192 + MoveIntoWorld: false Production: Produces: Plane Reservable: From 262e0fc48469a9368613ee278856ed132c48b1a4 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Wed, 19 Mar 2014 13:40:17 +1300 Subject: [PATCH 3/6] Use MoveIntoWorld for Enter activities. --- 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 cb12e5b8f5..f9a1b1a64d 100755 --- a/OpenRA.Mods.RA/Activities/Enter.cs +++ b/OpenRA.Mods.RA/Activities/Enter.cs @@ -37,18 +37,11 @@ namespace OpenRA.Mods.RA.Activities return Util.SequenceActivities(new MoveAdjacentTo(self, target), this); // Move to the middle of the target, ignoring impassable tiles - var mobile = self.Trait(); - var to = target.CenterPosition; - var from = self.CenterPosition; - var speed = mobile.MovementSpeedForCell(self, self.Location); - var length = speed > 0 ? (to - from).Length / speed : 0; - + var move = self.Trait(); return Util.SequenceActivities( - new Turn(Util.GetFacing(to - from, mobile.Facing)), - new Drag(from, to, length), + move.VisualMove(self, self.CenterPosition, target.CenterPosition), inner, - new Turn(Util.GetFacing(from - to, mobile.Facing)), - new Drag(to, from, length), + move.VisualMove(self, target.CenterPosition, self.CenterPosition), NextActivity ); } From de735fbd2716df1cfc23cd4194279476b11a5371 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Wed, 19 Mar 2014 14:21:07 +1300 Subject: [PATCH 4/6] Use MoveIntoWorld for transports. Fixes #4758. --- OpenRA.Mods.RA/Activities/UnloadCargo.cs | 33 +++++++----------------- 1 file changed, 10 insertions(+), 23 deletions(-) diff --git a/OpenRA.Mods.RA/Activities/UnloadCargo.cs b/OpenRA.Mods.RA/Activities/UnloadCargo.cs index 81a5be6796..b248603c89 100644 --- a/OpenRA.Mods.RA/Activities/UnloadCargo.cs +++ b/OpenRA.Mods.RA/Activities/UnloadCargo.cs @@ -33,20 +33,21 @@ namespace OpenRA.Mods.RA.Activities public CPos? ChooseExitCell(Actor passenger) { - var mobile = passenger.Trait(); + var pos = passenger.Trait(); return cargo.CurrentAdjacentCells .Shuffle(self.World.SharedRandom) .Cast() - .FirstOrDefault(c => mobile.CanEnterCell(c.Value)); + .FirstOrDefault(c => pos.CanEnterCell(c.Value)); } IEnumerable BlockedExitCells(Actor passenger) { - var mobile = passenger.Trait(); + var pos = passenger.Trait(); + // Find the cells that are blocked by transient actors return cargo.CurrentAdjacentCells - .Where(c => mobile.MovementSpeedForCell(passenger, c) != int.MaxValue && !mobile.CanEnterCell(c)); + .Where(c => pos.CanEnterCell(c, null, true) != pos.CanEnterCell(c, null, false)); } public override Activity Tick(Actor self) @@ -58,6 +59,7 @@ namespace OpenRA.Mods.RA.Activities cloak.Uncloak(); var actor = cargo.Peek(self); + var spawn = self.CenterPosition; var exitCell = ChooseExitCell(actor); if (exitCell == null) @@ -71,33 +73,18 @@ namespace OpenRA.Mods.RA.Activities } cargo.Unload(self); - self.World.AddFrameEndTask(w => { if (actor.Destroyed) return; - var mobile = actor.Trait(); - - var exitSubcell = mobile.GetDesiredSubcell(exitCell.Value, null); - - mobile.fromSubCell = exitSubcell; // these settings make sure that the below Set* calls - mobile.toSubCell = exitSubcell; // and the above GetDesiredSubcell call pick a good free subcell for later units being unloaded - - var exit = exitCell.Value.CenterPosition + MobileInfo.SubCellOffsets[exitSubcell]; - var current = self.Location.CenterPosition + MobileInfo.SubCellOffsets[exitSubcell]; - - mobile.Facing = Util.GetFacing(exit - current, mobile.Facing); - mobile.SetPosition(actor, exitCell.Value); - mobile.SetVisualPosition(actor, current); - var speed = mobile.MovementSpeedForCell(actor, exitCell.Value); - var length = speed > 0 ? (exit - current).Length / speed : 0; + var move = actor.Trait(); + var pos = actor.Trait(); w.Add(actor); actor.CancelActivity(); - actor.QueueActivity(new Drag(current, exit, length)); - actor.QueueActivity(mobile.MoveTo(exitCell.Value, 0)); - + pos.SetVisualPosition(actor, spawn); + actor.QueueActivity(move.MoveIntoWorld(actor, exitCell.Value)); actor.SetTargetLine(Target.FromCell(exitCell.Value), Color.Green, false); }); From 2b3e116f74f50def3b59cf4759b71ded52c7a75a Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Wed, 19 Mar 2014 13:43:56 +1300 Subject: [PATCH 5/6] Remove RenderLandingCraft dependency on Mobile. --- OpenRA.Mods.RA/Render/RenderLandingCraft.cs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/OpenRA.Mods.RA/Render/RenderLandingCraft.cs b/OpenRA.Mods.RA/Render/RenderLandingCraft.cs index 782c5c624d..64d9b2a7fb 100644 --- a/OpenRA.Mods.RA/Render/RenderLandingCraft.cs +++ b/OpenRA.Mods.RA/Render/RenderLandingCraft.cs @@ -14,7 +14,7 @@ using OpenRA.Mods.RA.Move; namespace OpenRA.Mods.RA.Render { - public class RenderLandingCraftInfo : RenderUnitInfo + public class RenderLandingCraftInfo : RenderUnitInfo, Requires { public readonly string[] OpenTerrainTypes = { "Clear" }; public readonly string OpenAnim = "open"; @@ -25,26 +25,24 @@ namespace OpenRA.Mods.RA.Render public class RenderLandingCraft : RenderUnit { + readonly RenderLandingCraftInfo info; readonly Actor self; readonly Cargo cargo; - readonly RenderLandingCraftInfo info; + readonly IMove move; bool open; public RenderLandingCraft(Actor self, RenderLandingCraftInfo info) : base(self) { + this.info = info; this.self = self; cargo = self.Trait(); - this.info = info; + move = self.Trait(); } public bool ShouldBeOpen() { - var mobile = self.TraitOrDefault(); - if (mobile == null) - return false; - - if (self.CenterPosition.Z > 0 || mobile.IsMoving) + if (self.CenterPosition.Z > 0 || move.IsMoving) return false; return cargo.CurrentAdjacentCells From c223e23572451b9429fc270e8c0edd3690f16a0d Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Wed, 19 Mar 2014 13:44:51 +1300 Subject: [PATCH 6/6] Remove RenderInfantry dependency on Mobile. --- OpenRA.Mods.RA/Render/RenderInfantry.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/OpenRA.Mods.RA/Render/RenderInfantry.cs b/OpenRA.Mods.RA/Render/RenderInfantry.cs index d79adb7f9a..bfbc1e76e0 100644 --- a/OpenRA.Mods.RA/Render/RenderInfantry.cs +++ b/OpenRA.Mods.RA/Render/RenderInfantry.cs @@ -14,7 +14,7 @@ using OpenRA.Traits; namespace OpenRA.Mods.RA.Render { - public class RenderInfantryInfo : RenderSimpleInfo, Requires + public class RenderInfantryInfo : RenderSimpleInfo, Requires { public readonly int MinIdleWaitTicks = 30; public readonly int MaxIdleWaitTicks = 110; @@ -35,7 +35,7 @@ namespace OpenRA.Mods.RA.Render IdleAnimating } - Mobile mobile; + IMove move; RenderInfantryInfo info; public bool IsMoving { get; set; } protected bool dirty = false; @@ -60,7 +60,7 @@ namespace OpenRA.Mods.RA.Render this.info = info; anim.PlayFetchIndex(NormalizeInfantrySequence(self, info.StandAnimations.Random(Game.CosmeticRandom)), () => 0); State = AnimationState.Waiting; - mobile = self.Trait(); + move = self.Trait(); self.Trait().SetAutodetectedFacings(anim.CurrentSequence.Facings); } @@ -83,12 +83,12 @@ namespace OpenRA.Mods.RA.Render { base.Tick(self); - if ((State == AnimationState.Moving || dirty) && !mobile.IsMoving) + if ((State == AnimationState.Moving || dirty) && !move.IsMoving) { State = AnimationState.Waiting; anim.PlayFetchIndex(NormalizeInfantrySequence(self, info.StandAnimations.Random(Game.CosmeticRandom)), () => 0); } - else if ((State != AnimationState.Moving || dirty) && mobile.IsMoving) + else if ((State != AnimationState.Moving || dirty) && move.IsMoving) { State = AnimationState.Moving; anim.PlayRepeating(NormalizeInfantrySequence(self, "run"));