Fixed #4640 - Units teleport into transports.

This commit is contained in:
atlimit8
2014-09-25 11:59:00 -05:00
parent af5b18a080
commit cead66668f
5 changed files with 187 additions and 38 deletions

View File

@@ -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))

View File

@@ -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
} }
} }
} }

View File

@@ -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;
} }
} }

View File

@@ -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);

View File

@@ -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;
}
} }
} }