Rework Carryall drop-off queueing and ordering.

This commit is contained in:
tovl
2019-04-14 10:31:44 +02:00
committed by reaperrr
parent a403d9937d
commit 0b747ba927
5 changed files with 170 additions and 179 deletions

View File

@@ -18,44 +18,34 @@ namespace OpenRA.Mods.Common.Activities
public class DeliverUnit : Activity
{
readonly Actor self;
readonly Carryable carryable;
readonly Carryall carryall;
readonly IPositionable positionable;
readonly BodyOrientation body;
readonly IFacing carryableFacing;
readonly IFacing carryallFacing;
readonly CPos destination;
readonly IFacing facing;
CPos? destination;
enum DeliveryState { Transport, Land, Wait, Release, TakeOff, Done, Aborted }
DeliveryState state;
public DeliverUnit(Actor self, CPos destination)
public DeliverUnit(Actor self, CPos? destination = null)
{
this.self = self;
this.destination = destination;
carryallFacing = self.Trait<IFacing>();
facing = self.Trait<IFacing>();
carryall = self.Trait<Carryall>();
body = self.Trait<BodyOrientation>();
carryable = carryall.Carryable.Trait<Carryable>();
positionable = carryall.Carryable.Trait<IPositionable>();
carryableFacing = carryall.Carryable.Trait<IFacing>();
state = DeliveryState.Transport;
}
CPos? FindDropLocation(CPos targetCell, WDist maxSearchDistance)
{
var positionable = carryall.Carryable.Trait<IPositionable>();
// The easy case
if (positionable.CanEnterCell(targetCell))
if (positionable.CanEnterCell(targetCell, self))
return targetCell;
var cellRange = (maxSearchDistance.Length + 1023) / 1024;
var centerPosition = self.World.Map.CenterOfCell(targetCell);
foreach (var c in self.World.Map.FindTilesInCircle(targetCell, cellRange))
{
if (!positionable.CanEnterCell(c))
if (!positionable.CanEnterCell(c, self))
continue;
var delta = self.World.Map.CenterOfCell(c) - centerPosition;
@@ -66,14 +56,6 @@ namespace OpenRA.Mods.Common.Activities
return null;
}
// Check if we can drop the unit at our current location.
bool CanDropHere()
{
var localOffset = carryall.CarryableOffset.Rotate(body.QuantizeOrientation(self, self.Orientation));
var targetCell = self.World.Map.CellContaining(self.CenterPosition + body.LocalToWorld(localOffset));
return positionable.CanEnterCell(targetCell);
}
public override Activity Tick(Actor self)
{
if (ChildActivity != null)
@@ -83,120 +65,80 @@ namespace OpenRA.Mods.Common.Activities
return this;
}
if (IsCanceling)
if (IsCanceling || carryall.State != Carryall.CarryallState.Carrying || carryall.Carryable.IsDead)
return NextActivity;
if ((carryall.State == Carryall.CarryallState.Idle || carryall.Carryable.IsDead) && state != DeliveryState.TakeOff)
state = DeliveryState.Aborted;
if (destination == null)
destination = self.Location;
switch (state)
var targetLocation = FindDropLocation(destination.Value, carryall.Info.DropRange);
// Can't land, so wait at the target until something changes
if (!targetLocation.HasValue)
{
case DeliveryState.Transport:
{
var targetLocation = FindDropLocation(destination, carryall.Info.DropRange);
// Can't land, so wait at the target until something changes
if (!targetLocation.HasValue)
{
QueueChild(self, new HeliFly(self, Target.FromCell(self.World, destination)), true);
QueueChild(self, new Wait(25));
return this;
}
var targetPosition = self.World.Map.CenterOfCell(targetLocation.Value);
var localOffset = carryall.CarryableOffset.Rotate(body.QuantizeOrientation(self, self.Orientation));
var carryablePosition = self.CenterPosition + body.LocalToWorld(localOffset);
if ((carryablePosition - targetPosition).HorizontalLengthSquared != 0)
{
// For non-zero offsets the drop position depends on the carryall facing
// We therefore need to predict/correct for the facing *at the drop point*
if (carryall.CarryableOffset.HorizontalLengthSquared != 0)
{
var facing = (targetPosition - self.CenterPosition).Yaw.Facing;
localOffset = carryall.CarryableOffset.Rotate(body.QuantizeOrientation(self, WRot.FromFacing(facing)));
QueueChild(self, new HeliFly(self, Target.FromPos(targetPosition - body.LocalToWorld(localOffset))), true);
QueueChild(self, new Turn(self, facing));
return this;
}
QueueChild(self, new HeliFly(self, Target.FromPos(targetPosition)), true);
return this;
}
state = DeliveryState.Land;
return this;
}
case DeliveryState.Land:
{
if (!CanDropHere())
{
state = DeliveryState.Transport;
return this;
}
// Make sure that the carried actor is on the ground before releasing it
var localOffset = carryall.CarryableOffset.Rotate(body.QuantizeOrientation(self, self.Orientation));
var carryablePosition = self.CenterPosition + body.LocalToWorld(localOffset);
if (self.World.Map.DistanceAboveTerrain(carryablePosition) != WDist.Zero)
{
QueueChild(self, new HeliLand(self, false, -new WDist(carryall.CarryableOffset.Z)), true);
return this;
}
state = carryall.Info.UnloadingDelay > 0 ? DeliveryState.Wait : DeliveryState.Release;
return this;
}
case DeliveryState.Wait:
state = DeliveryState.Release;
QueueChild(self, new Wait(carryall.Info.UnloadingDelay, false), true);
return this;
case DeliveryState.Release:
if (!CanDropHere())
{
state = DeliveryState.Transport;
return this;
}
Release();
state = DeliveryState.TakeOff;
return this;
case DeliveryState.TakeOff:
QueueChild(self, new HeliFly(self, Target.FromPos(self.CenterPosition)), true);
state = DeliveryState.Done;
return this;
case DeliveryState.Aborted:
carryall.UnreserveCarryable(self);
break;
QueueChild(self, new HeliFly(self, Target.FromCell(self.World, destination.Value)), true);
QueueChild(self, new Wait(25));
return this;
}
return NextActivity;
// Move to drop-off location
var targetPosition = self.World.Map.CenterOfCell(targetLocation.Value);
var localOffset = carryall.CarryableOffset.Rotate(body.QuantizeOrientation(self, self.Orientation));
var carryablePosition = self.CenterPosition + body.LocalToWorld(localOffset);
if ((carryablePosition - targetPosition).HorizontalLengthSquared != 0)
{
// For non-zero offsets the drop position depends on the carryall facing
// We therefore need to predict/correct for the facing *at the drop point*
if (carryall.CarryableOffset.HorizontalLengthSquared != 0)
{
var facing = (targetPosition - self.CenterPosition).Yaw.Facing;
localOffset = carryall.CarryableOffset.Rotate(body.QuantizeOrientation(self, WRot.FromFacing(facing)));
QueueChild(self, new HeliFly(self, Target.FromPos(targetPosition - body.LocalToWorld(localOffset))), true);
QueueChild(self, new Turn(self, facing));
return this;
}
QueueChild(self, new HeliFly(self, Target.FromPos(targetPosition)), true);
return this;
}
// Make sure that the carried actor is on the ground before releasing it
if (self.World.Map.DistanceAboveTerrain(carryablePosition) != WDist.Zero)
QueueChild(self, new HeliLand(self, true), true);
// Pause briefly before releasing for visual effect
if (carryall.Info.UnloadingDelay > 0)
QueueChild(self, new Wait(carryall.Info.UnloadingDelay, false), true);
// Release carried actor
QueueChild(self, new CallFunc(Release));
QueueChild(self, new HeliFly(self, Target.FromPos(self.CenterPosition)));
return this;
}
void Release()
{
self.Trait<Aircraft>().RemoveInfluence();
var localOffset = carryall.CarryableOffset.Rotate(body.QuantizeOrientation(self, self.Orientation));
var targetPosition = self.CenterPosition + body.LocalToWorld(localOffset);
var targetLocation = self.World.Map.CellContaining(targetPosition);
positionable.SetPosition(carryall.Carryable, targetLocation, SubCell.FullCell);
carryall.Carryable.Trait<IPositionable>().SetPosition(carryall.Carryable, targetLocation, SubCell.FullCell);
// HACK: directly manipulate the turret facings to match the new orientation
// This can eventually go away, when we make turret facings relative to the body
var facingDelta = carryallFacing.Facing - carryableFacing.Facing;
var carryableFacing = carryall.Carryable.Trait<IFacing>();
var facingDelta = facing.Facing - carryableFacing.Facing;
foreach (var t in carryall.Carryable.TraitsImplementing<Turreted>())
t.TurretFacing += facingDelta;
carryableFacing.Facing = carryallFacing.Facing;
carryableFacing.Facing = facing.Facing;
// Put back into world
self.World.AddFrameEndTask(w =>
{
var cargo = carryall.Carryable;
var carryable = carryall.Carryable.Trait<Carryable>();
w.Add(cargo);
carryall.DetachCarryable(self);
carryable.UnReserve(cargo);