Merge pull request #6528 from atlimit8/DragIntoTransports
Modifies IMove & Enter and Fixes #4640 - Units teleport into transports
This commit is contained in:
@@ -101,6 +101,7 @@ namespace OpenRA.Traits
|
||||
public interface INotifyCapture { void OnCapture(Actor self, Actor captor, Player oldOwner, Player newOwner); }
|
||||
public interface INotifyHarvest { void Harvested(Actor self, ResourceType resource); }
|
||||
public interface INotifyInfiltrated { void Infiltrated(Actor self, Actor infiltrator); }
|
||||
public interface IDisableMove { bool MoveDisabled(Actor self); }
|
||||
|
||||
public interface IUpgradable
|
||||
{
|
||||
@@ -206,9 +207,12 @@ namespace OpenRA.Traits
|
||||
Activity MoveWithinRange(Target target, WRange minRange, WRange maxRange);
|
||||
Activity MoveFollow(Actor self, Target target, WRange minRange, WRange maxRange);
|
||||
Activity MoveIntoWorld(Actor self, CPos cell, SubCell subCell = SubCell.Any);
|
||||
Activity MoveToTarget(Actor self, Target target);
|
||||
Activity MoveIntoTarget(Actor self, Target target);
|
||||
Activity VisualMove(Actor self, WPos fromPos, WPos toPos);
|
||||
CPos NearestMoveableCell(CPos target);
|
||||
bool IsMoving { get; set; }
|
||||
bool CanEnterTargetNow(Actor self, Target target);
|
||||
}
|
||||
|
||||
public interface INotifyBlockingMove { void OnNotifyBlockingMove(Actor self, Actor blocking); }
|
||||
|
||||
@@ -47,10 +47,10 @@ namespace OpenRA.Mods.Cnc
|
||||
return this;
|
||||
case State.Turn:
|
||||
state = State.DragIn;
|
||||
return Util.SequenceActivities(new Turn(112), this);
|
||||
return Util.SequenceActivities(new Turn(self, 112), this);
|
||||
case State.DragIn:
|
||||
state = State.Dock;
|
||||
return Util.SequenceActivities(new Drag(startDock, endDock, 12), this);
|
||||
return Util.SequenceActivities(new Drag(self, startDock, endDock, 12), this);
|
||||
case State.Dock:
|
||||
ru.PlayCustomAnimation(self, "dock", () => {
|
||||
ru.PlayCustomAnimRepeating(self, "dock-loop");
|
||||
@@ -73,7 +73,7 @@ namespace OpenRA.Mods.Cnc
|
||||
state = State.Wait;
|
||||
return this;
|
||||
case State.DragOut:
|
||||
return Util.SequenceActivities(new Drag(endDock, startDock, 12), NextActivity);
|
||||
return Util.SequenceActivities(new Drag(self, endDock, startDock, 12), NextActivity);
|
||||
}
|
||||
|
||||
throw new InvalidOperationException("Invalid harvester dock state");
|
||||
|
||||
@@ -62,7 +62,7 @@ namespace OpenRA.Mods.Cnc
|
||||
cargoFacing.Facing = facing.Facing;
|
||||
|
||||
var cargoPassenger = c.Trait<Passenger>();
|
||||
if (cargoInfo.DisplayTypes.Contains(cargoPassenger.info.CargoType))
|
||||
if (cargoInfo.DisplayTypes.Contains(cargoPassenger.Info.CargoType))
|
||||
{
|
||||
var offset = pos - c.CenterPosition + body.LocalToWorld(cargoInfo.LocalOffset[i++ % cargoInfo.LocalOffset.Length].Rotate(bodyOrientation));
|
||||
foreach (var cr in c.Render(wr))
|
||||
|
||||
@@ -64,7 +64,7 @@ namespace OpenRA.Mods.RA.Activities
|
||||
|
||||
var desiredFacing = Util.GetFacing(Target.CenterPosition - self.CenterPosition, 0);
|
||||
if (facing.Facing != desiredFacing)
|
||||
return Util.SequenceActivities(new Turn(desiredFacing), this);
|
||||
return Util.SequenceActivities(new Turn(self, desiredFacing), this);
|
||||
|
||||
attack.DoAttack(self, Target);
|
||||
|
||||
|
||||
@@ -8,41 +8,267 @@
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA.Mods.RA.Move;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.RA.Activities
|
||||
{
|
||||
public class Enter : Activity
|
||||
{
|
||||
readonly Target target;
|
||||
readonly Activity inner;
|
||||
public enum ReserveStatus { None, TooFar, Pending, Ready }
|
||||
enum State { ApproachingOrEntering, Inside, Exiting, Done }
|
||||
|
||||
public Enter(Actor target, Activity inner)
|
||||
readonly Activity inside;
|
||||
readonly IMove move;
|
||||
readonly int maxTries = 0;
|
||||
Target target;
|
||||
State nextState = State.ApproachingOrEntering; // Hint/starting point for next state
|
||||
bool isEnteringOrInside = false; // Used to know if exiting should be used
|
||||
WPos savedPos; // Position just before entering
|
||||
Activity inner;
|
||||
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<IMove>();
|
||||
this.target = Target.FromActor(target);
|
||||
this.inner = inner;
|
||||
this.inside = inside;
|
||||
}
|
||||
|
||||
// CanEnter(target) should to be true; othwise, Enter may abort.
|
||||
// Tries counter starts at 1 (reset every tick)
|
||||
protected virtual bool TryGetAlternateTarget(Actor self, int tries, ref Target target) { return false; }
|
||||
protected virtual bool CanReserve(Actor self) { return true; }
|
||||
protected virtual ReserveStatus Reserve(Actor self)
|
||||
{
|
||||
return !CanReserve(self) ? ReserveStatus.None : move.CanEnterTargetNow(self, target) ? ReserveStatus.Ready : ReserveStatus.TooFar;
|
||||
}
|
||||
|
||||
protected virtual void Unreserve(Actor self, bool abort) { }
|
||||
protected virtual void OnInside(Actor self) { }
|
||||
|
||||
protected bool TryGetAlternateTargetInCircle(Actor self, WRange radius, Action<Target> update, Func<Actor, bool> primaryFilter, Func<Actor, bool>[] preferenceFilters = null)
|
||||
{
|
||||
var radiusSquared = radius.Range * radius.Range;
|
||||
var diff = new WVec(radius, radius, WRange.Zero);
|
||||
var candidates = self.World.ActorMap.ActorsInBox(self.CenterPosition - diff, self.CenterPosition + diff)
|
||||
.Where(primaryFilter).Select(a => new { Actor = a, Ls = (self.CenterPosition - a.CenterPosition).HorizontalLengthSquared })
|
||||
.Where(p => p.Ls <= radiusSquared).OrderBy(p => p.Ls).Select(p => p.Actor);
|
||||
if (preferenceFilters != null)
|
||||
foreach (var filter in preferenceFilters)
|
||||
{
|
||||
var preferredCandidate = candidates.FirstOrDefault(filter);
|
||||
if (preferredCandidate == null)
|
||||
continue;
|
||||
target = Target.FromActor(preferredCandidate);
|
||||
update(target);
|
||||
return true;
|
||||
}
|
||||
|
||||
var candidate = candidates.FirstOrDefault();
|
||||
if (candidate == null)
|
||||
return false;
|
||||
target = Target.FromActor(candidate);
|
||||
update(target);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Called when inner activity is this and returns inner activity for next tick.
|
||||
protected virtual Activity InsideTick(Actor self) { return Util.RunActivity(self, inside); }
|
||||
|
||||
// Abort entering and/or leave if necessary
|
||||
protected virtual void AbortOrExit(Actor self)
|
||||
{
|
||||
if (nextState == State.Done)
|
||||
return;
|
||||
nextState = isEnteringOrInside ? State.Exiting : State.Done;
|
||||
if (inner == this)
|
||||
inner = null;
|
||||
else if (inner != null)
|
||||
inner.Cancel(self);
|
||||
if (isEnteringOrInside)
|
||||
Unreserve(self, true);
|
||||
isEnteringOrInside = false;
|
||||
}
|
||||
|
||||
// Cancel inner activity and mark as done unless already leaving or done
|
||||
protected void Done(Actor self)
|
||||
{
|
||||
if (nextState == State.Done)
|
||||
return;
|
||||
nextState = State.Done;
|
||||
if (inner == this)
|
||||
inner = null;
|
||||
else if (inner != null)
|
||||
inner.Cancel(self);
|
||||
}
|
||||
|
||||
public override void Cancel(Actor self)
|
||||
{
|
||||
AbortOrExit(self);
|
||||
if (nextState < State.Exiting)
|
||||
base.Cancel(self);
|
||||
else
|
||||
NextActivity = null;
|
||||
}
|
||||
|
||||
ReserveStatus TryReserveElseTryAlternateReserve(Actor self)
|
||||
{
|
||||
for (var tries = 0;;)
|
||||
switch (Reserve(self))
|
||||
{
|
||||
case ReserveStatus.None:
|
||||
if (++tries > maxTries || !TryGetAlternateTarget(self, tries, ref target))
|
||||
return ReserveStatus.None;
|
||||
continue;
|
||||
case ReserveStatus.TooFar:
|
||||
// Always goto to transport on first approach
|
||||
if (firstApproach)
|
||||
{
|
||||
firstApproach = false;
|
||||
return ReserveStatus.TooFar;
|
||||
}
|
||||
|
||||
if (++tries > maxTries)
|
||||
return ReserveStatus.TooFar;
|
||||
Target t = target;
|
||||
if (!TryGetAlternateTarget(self, tries, ref t))
|
||||
return ReserveStatus.TooFar;
|
||||
if ((target.CenterPosition - self.CenterPosition).HorizontalLengthSquared <= (t.CenterPosition - self.CenterPosition).HorizontalLengthSquared)
|
||||
return ReserveStatus.TooFar;
|
||||
target = t;
|
||||
continue;
|
||||
case ReserveStatus.Pending:
|
||||
return ReserveStatus.Pending;
|
||||
case ReserveStatus.Ready:
|
||||
return ReserveStatus.Ready;
|
||||
}
|
||||
}
|
||||
|
||||
State FindAndTransitionToNextState(Actor self)
|
||||
{
|
||||
switch (nextState)
|
||||
{
|
||||
case State.ApproachingOrEntering:
|
||||
|
||||
// Reserve to enter or approach
|
||||
isEnteringOrInside = false;
|
||||
switch (TryReserveElseTryAlternateReserve(self))
|
||||
{
|
||||
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
|
||||
return State.ApproachingOrEntering;
|
||||
case ReserveStatus.Pending:
|
||||
return State.ApproachingOrEntering; // Retry next tick
|
||||
case ReserveStatus.Ready:
|
||||
break; // Reserved target -> start entering target
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
nextState = State.Inside; // Should be inside once inner activity is null
|
||||
return State.ApproachingOrEntering;
|
||||
}
|
||||
|
||||
// Can enter but there is no activity for it, so go inside without one
|
||||
goto case State.Inside;
|
||||
|
||||
case State.Inside:
|
||||
// Might as well teleport into target if there is no MoveIntoTarget activity
|
||||
if (nextState == State.ApproachingOrEntering)
|
||||
nextState = State.Inside;
|
||||
|
||||
// Otherwise, try to recover from moving target
|
||||
else if (target.CenterPosition != self.CenterPosition)
|
||||
{
|
||||
nextState = State.ApproachingOrEntering;
|
||||
Unreserve(self, false);
|
||||
if (Reserve(self) == ReserveStatus.Ready)
|
||||
{
|
||||
inner = move.MoveIntoTarget(self, target); // Enter
|
||||
if (inner != null)
|
||||
return State.ApproachingOrEntering;
|
||||
|
||||
nextState = State.ApproachingOrEntering;
|
||||
goto case State.ApproachingOrEntering;
|
||||
}
|
||||
|
||||
nextState = State.ApproachingOrEntering;
|
||||
isEnteringOrInside = false;
|
||||
inner = move.MoveIntoWorld(self, self.World.Map.CellContaining(savedPos));
|
||||
|
||||
return State.ApproachingOrEntering;
|
||||
}
|
||||
|
||||
OnInside(self);
|
||||
|
||||
// Return if Abort(Actor) or Done(self) was called from OnInside.
|
||||
if (nextState >= State.Exiting)
|
||||
return State.Inside;
|
||||
|
||||
inner = this; // Start inside activity
|
||||
nextState = State.Exiting; // Exit once inner activity is null (unless Done(self) is called)
|
||||
return State.Inside;
|
||||
|
||||
// TODO: Handle target moved while inside or always call done for movable targets and use a separate exit activity
|
||||
case State.Exiting:
|
||||
inner = move.MoveIntoWorld(self, self.World.Map.CellContaining(savedPos));
|
||||
|
||||
// If not successfully exiting, retry on next tick
|
||||
if (inner == null)
|
||||
return State.Exiting;
|
||||
isEnteringOrInside = false;
|
||||
nextState = State.Done;
|
||||
return State.Exiting;
|
||||
|
||||
case State.Done:
|
||||
return State.Done;
|
||||
}
|
||||
|
||||
return State.Done; // dummy to quiet dumb compiler
|
||||
}
|
||||
|
||||
Activity CanceledTick(Actor self)
|
||||
{
|
||||
if (inner == null)
|
||||
return Util.RunActivity(self, NextActivity);
|
||||
inner.Cancel(self);
|
||||
inner.Queue(NextActivity);
|
||||
return Util.RunActivity(self, inner);
|
||||
}
|
||||
|
||||
public override Activity Tick(Actor self)
|
||||
{
|
||||
if (IsCanceled || !target.IsValidFor(self))
|
||||
return NextActivity;
|
||||
if (IsCanceled)
|
||||
return CanceledTick(self);
|
||||
|
||||
if (target.Type != TargetType.Actor)
|
||||
return NextActivity;
|
||||
// Check target validity if not exiting or done
|
||||
if (nextState != State.Done && (target.Type != TargetType.Actor || !target.IsValidFor(self)))
|
||||
AbortOrExit(self);
|
||||
|
||||
if (!Util.AdjacentCells(self.World, target).Any(c => c == self.Location))
|
||||
return Util.SequenceActivities(new MoveAdjacentTo(self, target), this);
|
||||
// If no current activity, tick next activity
|
||||
if (inner == null && FindAndTransitionToNextState(self) == State.Done)
|
||||
return CanceledTick(self);
|
||||
|
||||
// Move to the middle of the target, ignoring impassable tiles
|
||||
var move = self.Trait<IMove>();
|
||||
return Util.SequenceActivities(
|
||||
move.VisualMove(self, self.CenterPosition, target.CenterPosition),
|
||||
inner,
|
||||
move.VisualMove(self, target.CenterPosition, self.CenterPosition),
|
||||
NextActivity
|
||||
);
|
||||
// Run inner activity/InsideTick
|
||||
inner = inner == this ? InsideTick(self) : Util.RunActivity(self, inner);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,39 +8,42 @@
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.RA.Activities
|
||||
{
|
||||
class EnterTransport : Activity
|
||||
class EnterTransport : Enter
|
||||
{
|
||||
readonly Actor transport;
|
||||
readonly Cargo cargo;
|
||||
readonly Passenger passenger;
|
||||
readonly int maxTries;
|
||||
Cargo cargo;
|
||||
|
||||
public EnterTransport(Actor self, Actor transport)
|
||||
public EnterTransport(Actor self, Actor transport, int maxTries = 0)
|
||||
: base(self, transport, maxTries)
|
||||
{
|
||||
this.transport = transport;
|
||||
this.maxTries = maxTries;
|
||||
cargo = transport.Trait<Cargo>();
|
||||
passenger = self.Trait<Passenger>();
|
||||
}
|
||||
|
||||
public override Activity Tick(Actor self)
|
||||
protected override void Unreserve(Actor self, bool abort) { passenger.Unreserve(self); }
|
||||
protected override bool CanReserve(Actor self) { return cargo.Unloading || cargo.CanLoad(transport, self); }
|
||||
protected override ReserveStatus Reserve(Actor self)
|
||||
{
|
||||
if (IsCanceled)
|
||||
return NextActivity;
|
||||
|
||||
if (transport == null || !transport.IsInWorld)
|
||||
return NextActivity;
|
||||
|
||||
if (!cargo.CanLoad(transport, self))
|
||||
return NextActivity;
|
||||
|
||||
// TODO: Queue a move order to the transport? need to be
|
||||
// careful about units that can't path to the transport
|
||||
var cells = Util.AdjacentCells(self.World, Target.FromActor(transport));
|
||||
if (!cells.Contains(self.Location))
|
||||
return NextActivity;
|
||||
var status = base.Reserve(self);
|
||||
if (status != ReserveStatus.Ready)
|
||||
return status;
|
||||
if (passenger.Reserve(self, cargo))
|
||||
return ReserveStatus.Ready;
|
||||
return ReserveStatus.Pending;
|
||||
}
|
||||
|
||||
protected override void OnInside(Actor self)
|
||||
{
|
||||
self.World.AddFrameEndTask(w =>
|
||||
{
|
||||
if (self.IsDead() || transport.IsDead() || !cargo.CanLoad(transport, self))
|
||||
@@ -50,7 +53,19 @@ namespace OpenRA.Mods.RA.Activities
|
||||
w.Remove(self);
|
||||
});
|
||||
|
||||
return this;
|
||||
Done(self);
|
||||
}
|
||||
|
||||
protected override bool TryGetAlternateTarget(Actor self, int tries, ref Target target)
|
||||
{
|
||||
if (tries > maxTries)
|
||||
return false;
|
||||
var type = target.Actor.Info.Name;
|
||||
return TryGetAlternateTargetInCircle(
|
||||
self, passenger.Info.AlternateTransportScanRange,
|
||||
t => cargo = t.Actor.Trait<Cargo>(), // update cargo
|
||||
a => { var c = a.TraitOrDefault<Cargo>(); return c != null && (c.Unloading || c.CanLoad(a, self)); },
|
||||
new Func<Actor, bool>[] { a => a.Info.Name == type }); // Prefer transports of the same type
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,7 +153,7 @@ namespace OpenRA.Mods.RA.Activities
|
||||
var facing = self.Trait<IFacing>().Facing;
|
||||
var desired = Util.QuantizeFacing(facing, harvInfo.HarvestFacings) * (256 / harvInfo.HarvestFacings);
|
||||
if (desired != facing)
|
||||
return Util.SequenceActivities(new Turn(desired), this);
|
||||
return Util.SequenceActivities(new Turn(self, desired), this);
|
||||
}
|
||||
|
||||
var resLayer = self.World.WorldActor.Trait<ResourceLayer>();
|
||||
|
||||
@@ -43,7 +43,7 @@ namespace OpenRA.Mods.RA
|
||||
return this;
|
||||
case State.Turn:
|
||||
state = State.Dock;
|
||||
return Util.SequenceActivities(new Turn(angle), this);
|
||||
return Util.SequenceActivities(new Turn(self, angle), this);
|
||||
case State.Dock:
|
||||
ru.PlayCustomAnimation(self, "dock", () => {
|
||||
ru.PlayCustomAnimRepeating(self, "dock-loop");
|
||||
|
||||
@@ -8,22 +8,30 @@
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.RA.Activities
|
||||
{
|
||||
public class Turn : Activity
|
||||
{
|
||||
int desiredFacing;
|
||||
readonly IEnumerable<IDisableMove> moveDisablers;
|
||||
readonly int desiredFacing;
|
||||
|
||||
public Turn( int desiredFacing )
|
||||
public Turn(Actor self, int desiredFacing)
|
||||
{
|
||||
moveDisablers = self.TraitsImplementing<IDisableMove>();
|
||||
this.desiredFacing = desiredFacing;
|
||||
}
|
||||
|
||||
public override Activity Tick( Actor self )
|
||||
{
|
||||
if (IsCanceled) return NextActivity;
|
||||
if (IsCanceled)
|
||||
return NextActivity;
|
||||
if (moveDisablers.Any(d => d.MoveDisabled(self)))
|
||||
return this;
|
||||
|
||||
var facing = self.Trait<IFacing>();
|
||||
|
||||
if( desiredFacing == facing.Facing )
|
||||
|
||||
@@ -54,6 +54,7 @@ namespace OpenRA.Mods.RA.Activities
|
||||
|
||||
public override Activity Tick(Actor self)
|
||||
{
|
||||
cargo.Unloading = false;
|
||||
if (IsCanceled || cargo.IsEmpty(self))
|
||||
return NextActivity;
|
||||
|
||||
@@ -93,6 +94,7 @@ namespace OpenRA.Mods.RA.Activities
|
||||
if (!unloadAll || cargo.IsEmpty(self))
|
||||
return NextActivity;
|
||||
|
||||
cargo.Unloading = true;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,7 +135,7 @@ namespace OpenRA.Mods.RA.Air
|
||||
if (afld == null)
|
||||
return;
|
||||
|
||||
var res = afld.Trait<Reservable>();
|
||||
var res = afld.TraitOrDefault<Reservable>();
|
||||
|
||||
if (res != null)
|
||||
{
|
||||
@@ -204,6 +204,18 @@ namespace OpenRA.Mods.RA.Air
|
||||
public SubCell GetAvailableSubCell(CPos a, SubCell preferredSubCell = SubCell.Any, Actor ignoreActor = null, bool checkTransientActors = true) { return SubCell.Invalid; } // Does not use any subcell
|
||||
public bool CanEnterCell(CPos cell, Actor ignoreActor = null, bool checkTransientActors = true) { return true; }
|
||||
|
||||
public bool CanEnterTargetNow(Actor self, Target target)
|
||||
{
|
||||
if (target.Positions.Any(p => self.World.ActorMap.GetUnitsAt(self.World.Map.CellContaining(p)).Any(a => a != self && a != target.Actor)))
|
||||
return false;
|
||||
var res = target.Actor.TraitOrDefault<Reservable>();
|
||||
if (res == null)
|
||||
return true;
|
||||
UnReserve();
|
||||
Reservation = res.Reserve(target.Actor, self, this);
|
||||
return true;
|
||||
}
|
||||
|
||||
public int MovementSpeed
|
||||
{
|
||||
get
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace OpenRA.Mods.RA.Air
|
||||
.ClosestTo(self);
|
||||
|
||||
if (nearestHpad == null)
|
||||
return Util.SequenceActivities(new Turn(initialFacing), new HeliLand(true), NextActivity);
|
||||
return Util.SequenceActivities(new Turn(self, initialFacing), new HeliLand(true), NextActivity);
|
||||
else
|
||||
return Util.SequenceActivities(new HeliFly(self, Target.FromActor(nearestHpad)));
|
||||
}
|
||||
@@ -58,7 +58,7 @@ namespace OpenRA.Mods.RA.Air
|
||||
|
||||
return Util.SequenceActivities(
|
||||
new HeliFly(self, Target.FromPos(dest.CenterPosition + offset)),
|
||||
new Turn(initialFacing),
|
||||
new Turn(self, initialFacing),
|
||||
new HeliLand(false),
|
||||
new ResupplyAircraft());
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
@@ -70,7 +71,7 @@ namespace OpenRA.Mods.RA.Air
|
||||
if (Info.LandWhenIdle)
|
||||
{
|
||||
if (Info.TurnToLand)
|
||||
self.QueueActivity(new Turn(Info.InitialFacing));
|
||||
self.QueueActivity(new Turn(self, Info.InitialFacing));
|
||||
|
||||
self.QueueActivity(new HeliLand(true));
|
||||
}
|
||||
@@ -96,7 +97,7 @@ namespace OpenRA.Mods.RA.Air
|
||||
|
||||
self.CancelActivity();
|
||||
self.QueueActivity(new HeliFly(self, Target.FromPos(order.TargetActor.CenterPosition + offset)));
|
||||
self.QueueActivity(new Turn(Info.InitialFacing));
|
||||
self.QueueActivity(new Turn(self, Info.InitialFacing));
|
||||
self.QueueActivity(new HeliLand(false));
|
||||
self.QueueActivity(new ResupplyAircraft());
|
||||
self.QueueActivity(new TakeOff());
|
||||
@@ -116,7 +117,7 @@ namespace OpenRA.Mods.RA.Air
|
||||
if (Info.LandWhenIdle)
|
||||
{
|
||||
if (Info.TurnToLand)
|
||||
self.QueueActivity(new Turn(Info.InitialFacing));
|
||||
self.QueueActivity(new Turn(self, Info.InitialFacing));
|
||||
|
||||
self.QueueActivity(new HeliLand(true));
|
||||
}
|
||||
@@ -153,6 +154,12 @@ namespace OpenRA.Mods.RA.Air
|
||||
return new HeliFly(self, Target.FromCell(self.World, cell, subCell));
|
||||
}
|
||||
|
||||
public Activity MoveIntoTarget(Actor self, Target target) { return new HeliLand(false); }
|
||||
public Activity MoveToTarget(Actor self, Target target)
|
||||
{
|
||||
return Util.SequenceActivities(new HeliFly(self, target), new Turn(self, Info.InitialFacing));
|
||||
}
|
||||
|
||||
public Activity VisualMove(Actor self, WPos fromPos, WPos toPos)
|
||||
{
|
||||
// TODO: Ignore repulsion when moving
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using OpenRA.Mods.RA.Activities;
|
||||
using OpenRA.Traits;
|
||||
@@ -129,5 +130,7 @@ namespace OpenRA.Mods.RA.Air
|
||||
|
||||
public Activity MoveIntoWorld(Actor self, CPos cell, SubCell subCell = SubCell.Any) { return new Fly(self, Target.FromCell(self.World, cell)); }
|
||||
public Activity VisualMove(Actor self, WPos fromPos, WPos toPos) { return Util.SequenceActivities(new CallFunc(() => SetVisualPosition(self, fromPos)), new Fly(self, Target.FromPos(toPos))); }
|
||||
public Activity MoveToTarget(Actor self, Target target) { return new Fly(self, target, WRange.FromCells(3), WRange.FromCells(5)); }
|
||||
public Activity MoveIntoTarget(Actor self, Target target) { return new Land(target); }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ namespace OpenRA.Mods.RA
|
||||
self.CancelActivity();
|
||||
|
||||
self.SetTargetLine(target, Color.Red);
|
||||
self.QueueActivity(new Enter(target.Actor, new Demolish(
|
||||
self.QueueActivity(new Enter(self, target.Actor, new Demolish(
|
||||
target.Actor, info.C4Delay, info.Flashes, info.FlashesDelay, info.FlashInterval, info.FlashDuration)));
|
||||
}
|
||||
|
||||
|
||||
@@ -75,7 +75,7 @@ namespace OpenRA.Mods.RA
|
||||
self.CancelActivity();
|
||||
|
||||
self.SetTargetLine(target, Color.Red);
|
||||
self.QueueActivity(new Enter(target.Actor, new CaptureActor(target)));
|
||||
self.QueueActivity(new Enter(self, target.Actor, new CaptureActor(target)));
|
||||
}
|
||||
|
||||
class CaptureOrderTargeter : UnitOrderTargeter
|
||||
|
||||
@@ -29,13 +29,16 @@ namespace OpenRA.Mods.RA
|
||||
public object Create(ActorInitializer init) { return new Cargo(init, this); }
|
||||
}
|
||||
|
||||
public class Cargo : IPips, IIssueOrder, IResolveOrder, IOrderVoice, INotifyKilled, INotifyCapture, ITick, INotifySold
|
||||
public class Cargo : IPips, IIssueOrder, IResolveOrder, IOrderVoice, INotifyKilled, INotifyCapture, ITick, INotifySold, IDisableMove
|
||||
{
|
||||
readonly Actor self;
|
||||
public readonly CargoInfo Info;
|
||||
readonly Actor self;
|
||||
|
||||
public bool Unloading { get; internal set; }
|
||||
int totalWeight = 0;
|
||||
int reservedWeight = 0;
|
||||
List<Actor> cargo = new List<Actor>();
|
||||
HashSet<Actor> reserves = new HashSet<Actor>();
|
||||
public IEnumerable<Actor> Passengers { get { return cargo; } }
|
||||
|
||||
CPos currentCell;
|
||||
@@ -45,6 +48,7 @@ namespace OpenRA.Mods.RA
|
||||
{
|
||||
self = init.self;
|
||||
Info = info;
|
||||
Unloading = false;
|
||||
|
||||
if (init.Contains<RuntimeCargoInit>())
|
||||
{
|
||||
@@ -97,6 +101,7 @@ namespace OpenRA.Mods.RA
|
||||
if (!CanUnload())
|
||||
return;
|
||||
|
||||
Unloading = true;
|
||||
self.CancelActivity();
|
||||
self.QueueActivity(new UnloadCargo(self, true));
|
||||
}
|
||||
@@ -115,7 +120,27 @@ namespace OpenRA.Mods.RA
|
||||
|
||||
public bool CanLoad(Actor self, Actor a)
|
||||
{
|
||||
return HasSpace(GetWeight(a)) && self.CenterPosition.Z == 0;
|
||||
return (reserves.Contains(a) || HasSpace(GetWeight(a))) && self.CenterPosition.Z == 0;
|
||||
}
|
||||
|
||||
internal bool ReserveSpace(Actor a)
|
||||
{
|
||||
if (reserves.Contains(a))
|
||||
return true;
|
||||
var w = GetWeight(a);
|
||||
if (!HasSpace(w))
|
||||
return false;
|
||||
reserves.Add(a);
|
||||
reservedWeight += w;
|
||||
return true;
|
||||
}
|
||||
|
||||
internal void UnreserveSpace(Actor a)
|
||||
{
|
||||
if (!reserves.Contains(a))
|
||||
return;
|
||||
reservedWeight -= GetWeight(a);
|
||||
reserves.Remove(a);
|
||||
}
|
||||
|
||||
public string CursorForOrder(Actor self, Order order)
|
||||
@@ -130,7 +155,8 @@ namespace OpenRA.Mods.RA
|
||||
return self.HasVoice("Unload") ? "Unload" : "Move";
|
||||
}
|
||||
|
||||
public bool HasSpace(int weight) { return totalWeight + weight <= Info.MaxWeight; }
|
||||
public bool MoveDisabled(Actor self) { return reserves.Any(); }
|
||||
public bool HasSpace(int weight) { return totalWeight + reservedWeight + weight <= Info.MaxWeight; }
|
||||
public bool IsEmpty(Actor self) { return cargo.Count == 0; }
|
||||
|
||||
public Actor Peek(Actor self) { return cargo[0]; }
|
||||
@@ -177,7 +203,13 @@ namespace OpenRA.Mods.RA
|
||||
public void Load(Actor self, Actor a)
|
||||
{
|
||||
cargo.Add(a);
|
||||
totalWeight += GetWeight(a);
|
||||
var w = GetWeight(a);
|
||||
totalWeight += w;
|
||||
if (reserves.Contains(a))
|
||||
{
|
||||
reservedWeight -= w;
|
||||
reserves.Remove(a);
|
||||
}
|
||||
|
||||
foreach (var npe in self.TraitsImplementing<INotifyPassengerEntered>())
|
||||
npe.PassengerEntered(self, a);
|
||||
|
||||
@@ -78,7 +78,7 @@ namespace OpenRA.Mods.RA
|
||||
self.CancelActivity();
|
||||
|
||||
self.SetTargetLine(target, Color.Yellow);
|
||||
self.QueueActivity(new Enter(target.Actor, new RepairBuilding(target.Actor)));
|
||||
self.QueueActivity(new Enter(self, target.Actor, new RepairBuilding(target.Actor)));
|
||||
}
|
||||
|
||||
class EngineerRepairOrderTargeter : UnitOrderTargeter
|
||||
|
||||
@@ -49,7 +49,7 @@ namespace OpenRA.Mods.RA
|
||||
var finalPos = init.world.Map.CenterOfCell(TopLeft);
|
||||
var distance = (finalPos - CenterPosition).Length;
|
||||
if (speed > 0 && distance > 0)
|
||||
self.QueueActivity(new Drag(CenterPosition, finalPos, distance / speed));
|
||||
self.QueueActivity(new Drag(init.self, CenterPosition, finalPos, distance / speed));
|
||||
}
|
||||
|
||||
public IEnumerable<Pair<CPos, SubCell>> OccupiedCells() { yield return Pair.New(TopLeft, SubCell.FullCell); }
|
||||
|
||||
@@ -96,7 +96,7 @@ namespace OpenRA.Mods.RA.Infiltration
|
||||
self.CancelActivity();
|
||||
|
||||
self.SetTargetLine(target, Color.Red);
|
||||
self.QueueActivity(new Enter(target.Actor, new Infiltrate(target.Actor)));
|
||||
self.QueueActivity(new Enter(self, target.Actor, new Infiltrate(target.Actor)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,18 +9,25 @@
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.RA.Move
|
||||
{
|
||||
public class Drag : Activity
|
||||
{
|
||||
readonly IPositionable positionable;
|
||||
readonly IMove movement;
|
||||
readonly IEnumerable<IDisableMove> moveDisablers;
|
||||
WPos start, end;
|
||||
int length;
|
||||
int ticks = 0;
|
||||
|
||||
public Drag(WPos start, WPos end, int length)
|
||||
public Drag(Actor self, WPos start, WPos end, int length)
|
||||
{
|
||||
positionable = self.Trait<IPositionable>();
|
||||
movement = self.TraitOrDefault<IMove>();
|
||||
moveDisablers = self.TraitsImplementing<IDisableMove>();
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
this.length = length;
|
||||
@@ -28,8 +35,8 @@ namespace OpenRA.Mods.RA.Move
|
||||
|
||||
public override Activity Tick(Actor self)
|
||||
{
|
||||
var positionable = self.Trait<IPositionable>();
|
||||
var movement = self.TraitOrDefault<IMove>();
|
||||
if (moveDisablers.Any(d => d.MoveDisabled(self)))
|
||||
return this;
|
||||
|
||||
var pos = length > 1
|
||||
? WPos.Lerp(start, end, ticks, length - 1)
|
||||
|
||||
@@ -660,22 +660,42 @@ namespace OpenRA.Mods.RA.Move
|
||||
SetPosition(self, cell, subCell);
|
||||
SetVisualPosition(self, pos);
|
||||
|
||||
// Animate transition
|
||||
var to = self.World.Map.CenterOfSubCell(cell, subCell);
|
||||
var speed = MovementSpeedForCell(self, cell);
|
||||
var length = speed > 0 ? (to - pos).Length / speed : 0;
|
||||
return VisualMove(self, pos, self.World.Map.CenterOfSubCell(cell, subCell), cell);
|
||||
}
|
||||
|
||||
var facing = Util.GetFacing(to - pos, Facing);
|
||||
return Util.SequenceActivities(new Turn(facing), new Drag(pos, to, length));
|
||||
public Activity MoveToTarget(Actor self, Target target)
|
||||
{
|
||||
if (target.Type == TargetType.Invalid)
|
||||
return null;
|
||||
|
||||
return new MoveAdjacentTo(self, target);
|
||||
}
|
||||
|
||||
public Activity MoveIntoTarget(Actor self, Target target)
|
||||
{
|
||||
if (target.Type == TargetType.Invalid)
|
||||
return null;
|
||||
|
||||
return VisualMove(self, self.CenterPosition, target.CenterPosition);
|
||||
}
|
||||
|
||||
public bool CanEnterTargetNow(Actor self, Target target)
|
||||
{
|
||||
return self.Location == self.World.Map.CellContaining(target.CenterPosition) || Util.AdjacentCells(self.World, target).Any(c => c == self.Location);
|
||||
}
|
||||
|
||||
public Activity VisualMove(Actor self, WPos fromPos, WPos toPos)
|
||||
{
|
||||
var speed = MovementSpeedForCell(self, self.Location);
|
||||
return VisualMove(self, fromPos, toPos, self.Location);
|
||||
}
|
||||
|
||||
public Activity VisualMove(Actor self, WPos fromPos, WPos toPos, CPos cell)
|
||||
{
|
||||
var speed = MovementSpeedForCell(self, cell);
|
||||
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));
|
||||
return Util.SequenceActivities(new Turn(self, facing), new Drag(self, fromPos, toPos, length));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,7 +151,7 @@ namespace OpenRA.Mods.RA.Move
|
||||
if (firstFacing != mobile.Facing)
|
||||
{
|
||||
path.Add(nextCell.Value.First);
|
||||
return Util.SequenceActivities(new Turn(firstFacing), this);
|
||||
return Util.SequenceActivities(new Turn(self, firstFacing), this);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
@@ -17,34 +18,113 @@ using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.RA
|
||||
{
|
||||
public enum AlternateTransportsMode { None, Force, Default, Always }
|
||||
|
||||
public class EnterTransportTargeter : EnterAlliedActorTargeter<Cargo>
|
||||
{
|
||||
readonly AlternateTransportsMode mode;
|
||||
|
||||
public EnterTransportTargeter(string order, int priority,
|
||||
Func<Actor, bool> canTarget, Func<Actor, bool> useEnterCursor,
|
||||
AlternateTransportsMode mode)
|
||||
: base (order, priority, canTarget, useEnterCursor) { this.mode = mode; }
|
||||
|
||||
public override bool CanTargetActor(Actor self, Actor target, TargetModifiers modifiers, ref string cursor)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case AlternateTransportsMode.None:
|
||||
break;
|
||||
case AlternateTransportsMode.Force:
|
||||
if (modifiers.HasModifier(TargetModifiers.ForceMove))
|
||||
return false;
|
||||
break;
|
||||
case AlternateTransportsMode.Default:
|
||||
if (!modifiers.HasModifier(TargetModifiers.ForceMove))
|
||||
return false;
|
||||
break;
|
||||
case AlternateTransportsMode.Always:
|
||||
return false;
|
||||
}
|
||||
|
||||
return base.CanTargetActor(self, target, modifiers, ref cursor);
|
||||
}
|
||||
}
|
||||
|
||||
public class EnterTransportsTargeter : EnterAlliedActorTargeter<Cargo>
|
||||
{
|
||||
readonly AlternateTransportsMode mode;
|
||||
|
||||
public EnterTransportsTargeter(string order, int priority,
|
||||
Func<Actor, bool> canTarget, Func<Actor, bool> useEnterCursor,
|
||||
AlternateTransportsMode mode)
|
||||
: base (order, priority, canTarget, useEnterCursor) { this.mode = mode; }
|
||||
|
||||
public override bool CanTargetActor(Actor self, Actor target, TargetModifiers modifiers, ref string cursor)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case AlternateTransportsMode.None:
|
||||
return false;
|
||||
case AlternateTransportsMode.Force:
|
||||
if (!modifiers.HasModifier(TargetModifiers.ForceMove))
|
||||
return false;
|
||||
break;
|
||||
case AlternateTransportsMode.Default:
|
||||
if (modifiers.HasModifier(TargetModifiers.ForceMove))
|
||||
return false;
|
||||
break;
|
||||
case AlternateTransportsMode.Always:
|
||||
break;
|
||||
}
|
||||
return base.CanTargetActor(self, target, modifiers, ref cursor);
|
||||
}
|
||||
}
|
||||
|
||||
[Desc("This actor can enter Cargo actors.")]
|
||||
public class PassengerInfo : ITraitInfo
|
||||
{
|
||||
public readonly string CargoType = null;
|
||||
public readonly PipType PipType = PipType.Green;
|
||||
public int Weight = 1;
|
||||
public readonly int Weight = 1;
|
||||
|
||||
[Desc("Use to set when to use alternate transports (Never, Force, Default, Always).",
|
||||
"Force - use force move modifier (Alt) to enable.",
|
||||
"Default - use force move modifier (Alt) to disable.")]
|
||||
public readonly AlternateTransportsMode AlternateTransportsMode = AlternateTransportsMode.Force;
|
||||
|
||||
[Desc("Number of retries using alternate transports.")]
|
||||
public readonly int MaxAlternateTransportAttempts = 1;
|
||||
|
||||
[Desc("Range from self for looking for an alternate transport (default: 5.5 cells).")]
|
||||
public readonly WRange AlternateTransportScanRange = WRange.FromCells(11) / 2;
|
||||
|
||||
public object Create(ActorInitializer init) { return new Passenger(this); }
|
||||
}
|
||||
|
||||
public class Passenger : IIssueOrder, IResolveOrder, IOrderVoice
|
||||
public class Passenger : IIssueOrder, IResolveOrder, IOrderVoice, INotifyRemovedFromWorld
|
||||
{
|
||||
public readonly PassengerInfo info;
|
||||
public Passenger(PassengerInfo info) { this.info = info; }
|
||||
public readonly PassengerInfo Info;
|
||||
public Passenger(PassengerInfo info) { Info = info; }
|
||||
public Actor Transport;
|
||||
public Cargo ReservedCargo { get; private set; }
|
||||
|
||||
public IEnumerable<IOrderTargeter> Orders
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return new EnterAlliedActorTargeter<Cargo>("EnterTransport", 6,
|
||||
target => IsCorrectCargoType(target), target => CanEnter(target));
|
||||
yield return new EnterTransportTargeter("EnterTransport", 6,
|
||||
target => IsCorrectCargoType(target), target => CanEnter(target),
|
||||
Info.AlternateTransportsMode);
|
||||
yield return new EnterTransportsTargeter("EnterTransports", 6,
|
||||
target => IsCorrectCargoType(target), target => CanEnter(target),
|
||||
Info.AlternateTransportsMode);
|
||||
}
|
||||
}
|
||||
|
||||
public Order IssueOrder(Actor self, IOrderTargeter order, Target target, bool queued)
|
||||
{
|
||||
if (order.OrderID == "EnterTransport")
|
||||
if (order.OrderID == "EnterTransport" || order.OrderID == "EnterTransports")
|
||||
return new Order(order.OrderID, self, queued) { TargetActor = target.Actor };
|
||||
|
||||
return null;
|
||||
@@ -53,25 +133,29 @@ namespace OpenRA.Mods.RA
|
||||
bool IsCorrectCargoType(Actor target)
|
||||
{
|
||||
var ci = target.Info.Traits.Get<CargoInfo>();
|
||||
return ci.Types.Contains(info.CargoType);
|
||||
return ci.Types.Contains(Info.CargoType);
|
||||
}
|
||||
|
||||
bool CanEnter(Cargo cargo)
|
||||
{
|
||||
return cargo != null && cargo.HasSpace(Info.Weight);
|
||||
}
|
||||
|
||||
bool CanEnter(Actor target)
|
||||
{
|
||||
var cargo = target.TraitOrDefault<Cargo>();
|
||||
return cargo != null && cargo.HasSpace(info.Weight);
|
||||
return CanEnter(target.TraitOrDefault<Cargo>());
|
||||
}
|
||||
|
||||
public string VoicePhraseForOrder(Actor self, Order order)
|
||||
{
|
||||
if (order.OrderString != "EnterTransport" ||
|
||||
if ((order.OrderString != "EnterTransport" && order.OrderString != "EnterTransports") ||
|
||||
!CanEnter(order.TargetActor)) return null;
|
||||
return "Move";
|
||||
}
|
||||
|
||||
public void ResolveOrder(Actor self, Order order)
|
||||
{
|
||||
if (order.OrderString == "EnterTransport")
|
||||
if (order.OrderString == "EnterTransport" || order.OrderString == "EnterTransports")
|
||||
{
|
||||
if (order.TargetActor == null) return;
|
||||
if (!CanEnter(order.TargetActor)) return;
|
||||
@@ -81,9 +165,26 @@ namespace OpenRA.Mods.RA
|
||||
self.SetTargetLine(target, Color.Green);
|
||||
|
||||
self.CancelActivity();
|
||||
self.QueueActivity(new MoveAdjacentTo(self, target));
|
||||
self.QueueActivity(new EnterTransport(self, order.TargetActor));
|
||||
self.QueueActivity(new EnterTransport(self, order.TargetActor, order.OrderString == "EnterTransport" ? 0 : Info.MaxAlternateTransportAttempts));
|
||||
}
|
||||
}
|
||||
|
||||
public bool Reserve(Actor self, Cargo cargo)
|
||||
{
|
||||
Unreserve(self);
|
||||
if (!cargo.ReserveSpace(self))
|
||||
return false;
|
||||
ReservedCargo = cargo;
|
||||
return true;
|
||||
}
|
||||
|
||||
public void RemovedFromWorld(Actor self) { Unreserve(self); }
|
||||
public void Unreserve(Actor self)
|
||||
{
|
||||
if (ReservedCargo == null)
|
||||
return;
|
||||
ReservedCargo.UnreserveSpace(self);
|
||||
ReservedCargo = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ namespace OpenRA.Mods.RA
|
||||
self.SetTargetLine(Target.FromOrder(self.World, order), Color.Yellow);
|
||||
|
||||
self.CancelActivity();
|
||||
self.QueueActivity(new Enter(order.TargetActor, new RepairBridge(order.TargetActor)));
|
||||
self.QueueActivity(new Enter(self, order.TargetActor, new RepairBridge(order.TargetActor)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -177,7 +177,7 @@ namespace OpenRA.Mods.RA.Scripting
|
||||
var heli = transport.TraitOrDefault<Helicopter>();
|
||||
if (heli != null)
|
||||
{
|
||||
transport.QueueActivity(new Turn(heli.Info.InitialFacing));
|
||||
transport.QueueActivity(new Turn(transport, heli.Info.InitialFacing));
|
||||
transport.QueueActivity(new HeliLand(true));
|
||||
transport.QueueActivity(new Wait(15));
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ namespace OpenRA.Mods.RA
|
||||
self.CancelActivity();
|
||||
|
||||
self.SetTargetLine(target, Color.Yellow);
|
||||
self.QueueActivity(new Enter(target.Actor, new DonateSupplies(target.Actor, info.Payload)));
|
||||
self.QueueActivity(new Enter(self, target.Actor, new DonateSupplies(target.Actor, info.Payload)));
|
||||
}
|
||||
|
||||
class SupplyTruckOrderTargeter : UnitOrderTargeter
|
||||
|
||||
@@ -87,7 +87,7 @@ namespace OpenRA.Mods.RA
|
||||
self.CancelActivity();
|
||||
|
||||
if (self.HasTrait<IFacing>())
|
||||
self.QueueActivity(new Turn(info.Facing));
|
||||
self.QueueActivity(new Turn(self, info.Facing));
|
||||
|
||||
foreach (var nt in self.TraitsImplementing<INotifyTransform>())
|
||||
nt.BeforeTransform(self);
|
||||
|
||||
@@ -41,7 +41,7 @@ namespace OpenRA.Mods.TS
|
||||
{
|
||||
case State.Turn:
|
||||
state = State.Dock;
|
||||
return Util.SequenceActivities(new Turn(160), this);
|
||||
return Util.SequenceActivities(new Turn(self, 160), this);
|
||||
case State.Dock:
|
||||
if (proc.IsInWorld && !proc.IsDead())
|
||||
foreach (var nd in proc.TraitsImplementing<INotifyDocking>())
|
||||
|
||||
Reference in New Issue
Block a user