Fixed #4640 - Units teleport into transports.
This commit is contained in:
@@ -62,7 +62,7 @@ namespace OpenRA.Mods.Cnc
|
|||||||
cargoFacing.Facing = facing.Facing;
|
cargoFacing.Facing = facing.Facing;
|
||||||
|
|
||||||
var cargoPassenger = c.Trait<Passenger>();
|
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));
|
var offset = pos - c.CenterPosition + body.LocalToWorld(cargoInfo.LocalOffset[i++ % cargoInfo.LocalOffset.Length].Rotate(bodyOrientation));
|
||||||
foreach (var cr in c.Render(wr))
|
foreach (var cr in c.Render(wr))
|
||||||
|
|||||||
@@ -8,39 +8,42 @@
|
|||||||
*/
|
*/
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using OpenRA.Traits;
|
using OpenRA.Traits;
|
||||||
|
|
||||||
namespace OpenRA.Mods.RA.Activities
|
namespace OpenRA.Mods.RA.Activities
|
||||||
{
|
{
|
||||||
class EnterTransport : Activity
|
class EnterTransport : Enter
|
||||||
{
|
{
|
||||||
readonly Actor transport;
|
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.transport = transport;
|
||||||
|
this.maxTries = maxTries;
|
||||||
cargo = transport.Trait<Cargo>();
|
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)
|
var status = base.Reserve(self);
|
||||||
return NextActivity;
|
if (status != ReserveStatus.Ready)
|
||||||
|
return status;
|
||||||
if (transport == null || !transport.IsInWorld)
|
if (passenger.Reserve(self, cargo))
|
||||||
return NextActivity;
|
return ReserveStatus.Ready;
|
||||||
|
return ReserveStatus.Pending;
|
||||||
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;
|
|
||||||
|
|
||||||
|
protected override void OnInside(Actor self)
|
||||||
|
{
|
||||||
self.World.AddFrameEndTask(w =>
|
self.World.AddFrameEndTask(w =>
|
||||||
{
|
{
|
||||||
if (self.IsDead() || transport.IsDead() || !cargo.CanLoad(transport, self))
|
if (self.IsDead() || transport.IsDead() || !cargo.CanLoad(transport, self))
|
||||||
@@ -50,7 +53,19 @@ namespace OpenRA.Mods.RA.Activities
|
|||||||
w.Remove(self);
|
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ namespace OpenRA.Mods.RA.Activities
|
|||||||
|
|
||||||
public override Activity Tick(Actor self)
|
public override Activity Tick(Actor self)
|
||||||
{
|
{
|
||||||
|
cargo.Unloading = false;
|
||||||
if (IsCanceled || cargo.IsEmpty(self))
|
if (IsCanceled || cargo.IsEmpty(self))
|
||||||
return NextActivity;
|
return NextActivity;
|
||||||
|
|
||||||
@@ -93,6 +94,7 @@ namespace OpenRA.Mods.RA.Activities
|
|||||||
if (!unloadAll || cargo.IsEmpty(self))
|
if (!unloadAll || cargo.IsEmpty(self))
|
||||||
return NextActivity;
|
return NextActivity;
|
||||||
|
|
||||||
|
cargo.Unloading = true;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,11 +31,14 @@ namespace OpenRA.Mods.RA
|
|||||||
|
|
||||||
public class Cargo : IPips, IIssueOrder, IResolveOrder, IOrderVoice, INotifyKilled, INotifyCapture, ITick, INotifySold
|
public class Cargo : IPips, IIssueOrder, IResolveOrder, IOrderVoice, INotifyKilled, INotifyCapture, ITick, INotifySold
|
||||||
{
|
{
|
||||||
readonly Actor self;
|
|
||||||
public readonly CargoInfo Info;
|
public readonly CargoInfo Info;
|
||||||
|
readonly Actor self;
|
||||||
|
|
||||||
|
public bool Unloading { get; internal set; }
|
||||||
int totalWeight = 0;
|
int totalWeight = 0;
|
||||||
|
int reservedWeight = 0;
|
||||||
List<Actor> cargo = new List<Actor>();
|
List<Actor> cargo = new List<Actor>();
|
||||||
|
HashSet<Actor> reserves = new HashSet<Actor>();
|
||||||
public IEnumerable<Actor> Passengers { get { return cargo; } }
|
public IEnumerable<Actor> Passengers { get { return cargo; } }
|
||||||
|
|
||||||
CPos currentCell;
|
CPos currentCell;
|
||||||
@@ -45,6 +48,7 @@ namespace OpenRA.Mods.RA
|
|||||||
{
|
{
|
||||||
self = init.self;
|
self = init.self;
|
||||||
Info = info;
|
Info = info;
|
||||||
|
Unloading = false;
|
||||||
|
|
||||||
if (init.Contains<RuntimeCargoInit>())
|
if (init.Contains<RuntimeCargoInit>())
|
||||||
{
|
{
|
||||||
@@ -97,6 +101,7 @@ namespace OpenRA.Mods.RA
|
|||||||
if (!CanUnload())
|
if (!CanUnload())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
Unloading = true;
|
||||||
self.CancelActivity();
|
self.CancelActivity();
|
||||||
self.QueueActivity(new UnloadCargo(self, true));
|
self.QueueActivity(new UnloadCargo(self, true));
|
||||||
}
|
}
|
||||||
@@ -115,7 +120,27 @@ namespace OpenRA.Mods.RA
|
|||||||
|
|
||||||
public bool CanLoad(Actor self, Actor a)
|
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)
|
public string CursorForOrder(Actor self, Order order)
|
||||||
@@ -130,7 +155,7 @@ namespace OpenRA.Mods.RA
|
|||||||
return self.HasVoice("Unload") ? "Unload" : "Move";
|
return self.HasVoice("Unload") ? "Unload" : "Move";
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool HasSpace(int weight) { return totalWeight + weight <= Info.MaxWeight; }
|
public bool HasSpace(int weight) { return totalWeight + reservedWeight + weight <= Info.MaxWeight; }
|
||||||
public bool IsEmpty(Actor self) { return cargo.Count == 0; }
|
public bool IsEmpty(Actor self) { return cargo.Count == 0; }
|
||||||
|
|
||||||
public Actor Peek(Actor self) { return cargo[0]; }
|
public Actor Peek(Actor self) { return cargo[0]; }
|
||||||
@@ -177,7 +202,13 @@ namespace OpenRA.Mods.RA
|
|||||||
public void Load(Actor self, Actor a)
|
public void Load(Actor self, Actor a)
|
||||||
{
|
{
|
||||||
cargo.Add(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>())
|
foreach (var npe in self.TraitsImplementing<INotifyPassengerEntered>())
|
||||||
npe.PassengerEntered(self, a);
|
npe.PassengerEntered(self, a);
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
*/
|
*/
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@@ -17,34 +18,113 @@ using OpenRA.Traits;
|
|||||||
|
|
||||||
namespace OpenRA.Mods.RA
|
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.")]
|
[Desc("This actor can enter Cargo actors.")]
|
||||||
public class PassengerInfo : ITraitInfo
|
public class PassengerInfo : ITraitInfo
|
||||||
{
|
{
|
||||||
public readonly string CargoType = null;
|
public readonly string CargoType = null;
|
||||||
public readonly PipType PipType = PipType.Green;
|
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 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 readonly PassengerInfo Info;
|
||||||
public Passenger(PassengerInfo info) { this.info = info; }
|
public Passenger(PassengerInfo info) { Info = info; }
|
||||||
public Actor Transport;
|
public Actor Transport;
|
||||||
|
public Cargo ReservedCargo { get; private set; }
|
||||||
|
|
||||||
public IEnumerable<IOrderTargeter> Orders
|
public IEnumerable<IOrderTargeter> Orders
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
yield return new EnterAlliedActorTargeter<Cargo>("EnterTransport", 6,
|
yield return new EnterTransportTargeter("EnterTransport", 6,
|
||||||
target => IsCorrectCargoType(target), target => CanEnter(target));
|
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)
|
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 new Order(order.OrderID, self, queued) { TargetActor = target.Actor };
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
@@ -53,25 +133,29 @@ namespace OpenRA.Mods.RA
|
|||||||
bool IsCorrectCargoType(Actor target)
|
bool IsCorrectCargoType(Actor target)
|
||||||
{
|
{
|
||||||
var ci = target.Info.Traits.Get<CargoInfo>();
|
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)
|
bool CanEnter(Actor target)
|
||||||
{
|
{
|
||||||
var cargo = target.TraitOrDefault<Cargo>();
|
return CanEnter(target.TraitOrDefault<Cargo>());
|
||||||
return cargo != null && cargo.HasSpace(info.Weight);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public string VoicePhraseForOrder(Actor self, Order order)
|
public string VoicePhraseForOrder(Actor self, Order order)
|
||||||
{
|
{
|
||||||
if (order.OrderString != "EnterTransport" ||
|
if ((order.OrderString != "EnterTransport" && order.OrderString != "EnterTransports") ||
|
||||||
!CanEnter(order.TargetActor)) return null;
|
!CanEnter(order.TargetActor)) return null;
|
||||||
return "Move";
|
return "Move";
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ResolveOrder(Actor self, Order order)
|
public void ResolveOrder(Actor self, Order order)
|
||||||
{
|
{
|
||||||
if (order.OrderString == "EnterTransport")
|
if (order.OrderString == "EnterTransport" || order.OrderString == "EnterTransports")
|
||||||
{
|
{
|
||||||
if (order.TargetActor == null) return;
|
if (order.TargetActor == null) return;
|
||||||
if (!CanEnter(order.TargetActor)) return;
|
if (!CanEnter(order.TargetActor)) return;
|
||||||
@@ -81,9 +165,26 @@ namespace OpenRA.Mods.RA
|
|||||||
self.SetTargetLine(target, Color.Green);
|
self.SetTargetLine(target, Color.Green);
|
||||||
|
|
||||||
self.CancelActivity();
|
self.CancelActivity();
|
||||||
self.QueueActivity(new MoveAdjacentTo(self, target));
|
self.QueueActivity(new EnterTransport(self, order.TargetActor, order.OrderString == "EnterTransport" ? 0 : Info.MaxAlternateTransportAttempts));
|
||||||
self.QueueActivity(new EnterTransport(self, order.TargetActor));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user