Merge pull request #4912 from pchote/exits
Clean up mobile world insertion.
This commit is contained in:
@@ -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; }
|
||||
}
|
||||
|
||||
@@ -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<Mobile>();
|
||||
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<IMove>();
|
||||
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
|
||||
);
|
||||
}
|
||||
|
||||
@@ -33,20 +33,21 @@ namespace OpenRA.Mods.RA.Activities
|
||||
|
||||
public CPos? ChooseExitCell(Actor passenger)
|
||||
{
|
||||
var mobile = passenger.Trait<Mobile>();
|
||||
var pos = passenger.Trait<IPositionable>();
|
||||
|
||||
return cargo.CurrentAdjacentCells
|
||||
.Shuffle(self.World.SharedRandom)
|
||||
.Cast<CPos?>()
|
||||
.FirstOrDefault(c => mobile.CanEnterCell(c.Value));
|
||||
.FirstOrDefault(c => pos.CanEnterCell(c.Value));
|
||||
}
|
||||
|
||||
IEnumerable<CPos> BlockedExitCells(Actor passenger)
|
||||
{
|
||||
var mobile = passenger.Trait<Mobile>();
|
||||
var pos = passenger.Trait<IPositionable>();
|
||||
|
||||
// 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<Mobile>();
|
||||
|
||||
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<IMove>();
|
||||
var pos = actor.Trait<IPositionable>();
|
||||
|
||||
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);
|
||||
});
|
||||
|
||||
|
||||
@@ -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)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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))); }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<IPositionable>();
|
||||
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<Mobile>();
|
||||
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<IMove>();
|
||||
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<INotifyProduction>())
|
||||
t.UnitProduced(self, newUnit, exit);
|
||||
|
||||
@@ -14,7 +14,7 @@ using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.RA.Render
|
||||
{
|
||||
public class RenderInfantryInfo : RenderSimpleInfo, Requires<MobileInfo>
|
||||
public class RenderInfantryInfo : RenderSimpleInfo, Requires<IMoveInfo>
|
||||
{
|
||||
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<Mobile>();
|
||||
move = self.Trait<IMove>();
|
||||
|
||||
self.Trait<IBodyOrientation>().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"));
|
||||
|
||||
@@ -14,7 +14,7 @@ using OpenRA.Mods.RA.Move;
|
||||
|
||||
namespace OpenRA.Mods.RA.Render
|
||||
{
|
||||
public class RenderLandingCraftInfo : RenderUnitInfo
|
||||
public class RenderLandingCraftInfo : RenderUnitInfo, Requires<IMoveInfo>
|
||||
{
|
||||
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<Cargo>();
|
||||
this.info = info;
|
||||
move = self.Trait<IMove>();
|
||||
}
|
||||
|
||||
public bool ShouldBeOpen()
|
||||
{
|
||||
var mobile = self.TraitOrDefault<Mobile>();
|
||||
if (mobile == null)
|
||||
return false;
|
||||
|
||||
if (self.CenterPosition.Z > 0 || mobile.IsMoving)
|
||||
if (self.CenterPosition.Z > 0 || move.IsMoving)
|
||||
return false;
|
||||
|
||||
return cargo.CurrentAdjacentCells
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user