Airborne transports only land to (un)load.
This commit is contained in:
@@ -45,7 +45,7 @@ namespace OpenRA.Mods.Common.Activities
|
||||
destination = Target.FromCell(self.World, self.Location);
|
||||
|
||||
QueueChild(self, new Land(self, destination, deliverRange), true);
|
||||
QueueChild(self, new Wait(carryall.Info.UnloadingDelay, false), true);
|
||||
QueueChild(self, new Wait(carryall.Info.BeforeUnloadDelay, false), true);
|
||||
QueueChild(self, new ReleaseUnit(self));
|
||||
QueueChild(self, new TakeOff(self));
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ namespace OpenRA.Mods.Common.Activities
|
||||
|
||||
Actor enterActor;
|
||||
Cargo enterCargo;
|
||||
Aircraft enterAircraft;
|
||||
|
||||
public EnterTransport(Actor self, Target target)
|
||||
: base(self, target, Color.Green)
|
||||
@@ -35,6 +36,7 @@ namespace OpenRA.Mods.Common.Activities
|
||||
{
|
||||
enterActor = targetActor;
|
||||
enterCargo = targetActor.TraitOrDefault<Cargo>();
|
||||
enterAircraft = targetActor.TraitOrDefault<Aircraft>();
|
||||
|
||||
// Make sure we can still enter the transport
|
||||
// (but not before, because this may stop the actor in the middle of nowhere)
|
||||
@@ -44,6 +46,9 @@ namespace OpenRA.Mods.Common.Activities
|
||||
return false;
|
||||
}
|
||||
|
||||
if (enterAircraft != null && !enterAircraft.AtLandAltitude)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -24,13 +24,27 @@ namespace OpenRA.Mods.Common.Activities
|
||||
readonly Cargo cargo;
|
||||
readonly INotifyUnload[] notifiers;
|
||||
readonly bool unloadAll;
|
||||
readonly Aircraft aircraft;
|
||||
readonly bool assignTargetOnFirstRun;
|
||||
readonly WDist unloadRange;
|
||||
|
||||
public UnloadCargo(Actor self, bool unloadAll)
|
||||
Target destination;
|
||||
|
||||
public UnloadCargo(Actor self, WDist unloadRange, bool unloadAll = true)
|
||||
: this(self, Target.Invalid, unloadRange, unloadAll)
|
||||
{
|
||||
assignTargetOnFirstRun = true;
|
||||
}
|
||||
|
||||
public UnloadCargo(Actor self, Target destination, WDist unloadRange, bool unloadAll = true)
|
||||
{
|
||||
this.self = self;
|
||||
cargo = self.Trait<Cargo>();
|
||||
notifiers = self.TraitsImplementing<INotifyUnload>().ToArray();
|
||||
this.unloadAll = unloadAll;
|
||||
aircraft = self.TraitOrDefault<Aircraft>();
|
||||
this.destination = destination;
|
||||
this.unloadRange = unloadRange;
|
||||
}
|
||||
|
||||
public Pair<CPos, SubCell>? ChooseExitSubCell(Actor passenger)
|
||||
@@ -53,6 +67,23 @@ namespace OpenRA.Mods.Common.Activities
|
||||
.Where(c => pos.CanEnterCell(c, null, true) != pos.CanEnterCell(c, null, false));
|
||||
}
|
||||
|
||||
protected override void OnFirstRun(Actor self)
|
||||
{
|
||||
if (assignTargetOnFirstRun)
|
||||
destination = Target.FromCell(self.World, self.Location);
|
||||
|
||||
// Move to the target destination
|
||||
if (aircraft != null)
|
||||
QueueChild(self, new Land(self, destination, unloadRange));
|
||||
else
|
||||
{
|
||||
var cell = self.World.Map.Clamp(this.self.World.Map.CellContaining(destination.CenterPosition));
|
||||
QueueChild(self, new Move(self, cell, unloadRange));
|
||||
}
|
||||
|
||||
QueueChild(self, new Wait(cargo.Info.BeforeUnloadDelay));
|
||||
}
|
||||
|
||||
public override Activity Tick(Actor self)
|
||||
{
|
||||
if (ChildActivity != null)
|
||||
@@ -62,16 +93,11 @@ namespace OpenRA.Mods.Common.Activities
|
||||
return this;
|
||||
}
|
||||
|
||||
cargo.Unloading = false;
|
||||
if (IsCanceling || cargo.IsEmpty(self))
|
||||
return NextActivity;
|
||||
|
||||
if (!cargo.CanUnload())
|
||||
if (cargo.CanUnload())
|
||||
{
|
||||
Cancel(self, true);
|
||||
return NextActivity;
|
||||
}
|
||||
|
||||
foreach (var inu in notifiers)
|
||||
inu.Unloading(self);
|
||||
|
||||
@@ -101,11 +127,18 @@ namespace OpenRA.Mods.Common.Activities
|
||||
actor.SetTargetLine(Target.FromCell(w, exitSubCell.Value.First, exitSubCell.Value.Second), Color.Green, false);
|
||||
w.Add(actor);
|
||||
});
|
||||
}
|
||||
|
||||
if (!unloadAll || cargo.IsEmpty(self))
|
||||
return NextActivity;
|
||||
if (!unloadAll || !cargo.CanUnload())
|
||||
{
|
||||
Cancel(self, true);
|
||||
if (cargo.Info.AfterUnloadDelay > 0)
|
||||
QueueChild(self, new Wait(cargo.Info.AfterUnloadDelay, false), true);
|
||||
|
||||
if (aircraft != null && !aircraft.Info.LandWhenIdle)
|
||||
QueueChild(self, new TakeOff(self), true);
|
||||
}
|
||||
|
||||
cargo.Unloading = true;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,44 +150,14 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
else
|
||||
{
|
||||
var aircraft = transport.TraitOrDefault<Aircraft>();
|
||||
|
||||
// Scripted cargo aircraft must turn to default position before unloading.
|
||||
// TODO: pass facing through UnloadCargo instead.
|
||||
if (aircraft != null)
|
||||
{
|
||||
var destination = entryPath.Last();
|
||||
|
||||
// Try to find an alternative landing spot if we can't land at the current destination
|
||||
if (!aircraft.CanLand(destination) && dropRange > 0)
|
||||
{
|
||||
var locomotors = cargo.Passengers
|
||||
.Select(a => a.Info.TraitInfoOrDefault<MobileInfo>())
|
||||
.Where(m => m != null)
|
||||
.Distinct()
|
||||
.Select(m => m.LocomotorInfo)
|
||||
.ToList();
|
||||
|
||||
foreach (var c in transport.World.Map.FindTilesInCircle(destination, dropRange))
|
||||
{
|
||||
if (!aircraft.CanLand(c))
|
||||
continue;
|
||||
|
||||
if (!locomotors.All(m => domainIndex.IsPassable(destination, c, m)))
|
||||
continue;
|
||||
|
||||
destination = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
transport.QueueActivity(new Land(transport, Target.FromCell(transport.World, destination), facing: aircraft.Info.InitialFacing));
|
||||
transport.QueueActivity(new Wait(15));
|
||||
}
|
||||
transport.QueueActivity(new Land(transport, Target.FromCell(transport.World, entryPath.Last()), WDist.FromCells(dropRange), aircraft.Info.InitialFacing));
|
||||
|
||||
if (cargo != null)
|
||||
{
|
||||
transport.QueueActivity(new UnloadCargo(transport, true));
|
||||
transport.QueueActivity(new WaitFor(() => cargo.IsEmpty(transport)));
|
||||
}
|
||||
|
||||
transport.QueueActivity(new Wait(aircraft != null ? 50 : 25));
|
||||
transport.QueueActivity(new UnloadCargo(transport, WDist.FromCells(dropRange)));
|
||||
}
|
||||
|
||||
if (exitFunc != null)
|
||||
|
||||
@@ -42,9 +42,15 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
|
||||
[ScriptActorPropertyActivity]
|
||||
[Desc("Command transport to unload passengers.")]
|
||||
public void UnloadPassengers()
|
||||
public void UnloadPassengers(CPos? cell = null, int unloadRange = 5)
|
||||
{
|
||||
Self.QueueActivity(new UnloadCargo(Self, true));
|
||||
if (cell.HasValue)
|
||||
{
|
||||
var destination = Target.FromCell(Self.World, cell.Value);
|
||||
Self.QueueActivity(new UnloadCargo(Self, destination, WDist.FromCells(unloadRange)));
|
||||
}
|
||||
else
|
||||
Self.QueueActivity(new UnloadCargo(Self, WDist.FromCells(unloadRange)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -664,7 +664,8 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
protected virtual void OnBecomingIdle(Actor self)
|
||||
{
|
||||
var atLandAltitude = self.World.Map.DistanceAboveTerrain(CenterPosition) == LandAltitude;
|
||||
var altitude = self.World.Map.DistanceAboveTerrain(CenterPosition);
|
||||
var atLandAltitude = altitude == LandAltitude;
|
||||
|
||||
// Work-around to prevent players from accidentally canceling resupply by pressing 'Stop',
|
||||
// by re-queueing Resupply as long as resupply hasn't finished and aircraft is still on resupplier.
|
||||
@@ -692,6 +693,8 @@ namespace OpenRA.Mods.Common.Traits
|
||||
// Will go away soon (in a separate PR) with the arrival of ActionsWhenIdle.
|
||||
self.QueueActivity(new FlyCircle(self, -1, Info.IdleTurnSpeed > -1 ? Info.IdleTurnSpeed : TurnSpeed));
|
||||
}
|
||||
else if (!atLandAltitude && altitude != Info.CruiseAltitude && !Info.LandWhenIdle)
|
||||
self.QueueActivity(new TakeOff(self));
|
||||
}
|
||||
|
||||
#region Implement IPositionable
|
||||
|
||||
@@ -47,9 +47,21 @@ namespace OpenRA.Mods.Common.Traits
|
||||
[Desc("Voice to play when ordered to unload the passengers.")]
|
||||
public readonly string UnloadVoice = "Action";
|
||||
|
||||
[Desc("Radius to search for a load/unload location if the ordered cell is blocked.")]
|
||||
public readonly WDist LoadRange = WDist.FromCells(5);
|
||||
|
||||
[Desc("Which direction the passenger will face (relative to the transport) when unloading.")]
|
||||
public readonly int PassengerFacing = 128;
|
||||
|
||||
[Desc("Delay (in ticks) before continuing after loading a passenger.")]
|
||||
public readonly int AfterLoadDelay = 8;
|
||||
|
||||
[Desc("Delay (in ticks) before unloading the first passenger.")]
|
||||
public readonly int BeforeUnloadDelay = 8;
|
||||
|
||||
[Desc("Delay (in ticks) before continuing after unloading a passenger.")]
|
||||
public readonly int AfterUnloadDelay = 25;
|
||||
|
||||
[Desc("Cursor to display when able to unload the passengers.")]
|
||||
public readonly string UnloadCursor = "deploy";
|
||||
|
||||
@@ -96,15 +108,16 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
CPos currentCell;
|
||||
public IEnumerable<CPos> CurrentAdjacentCells { get; private set; }
|
||||
public bool Unloading { get; internal set; }
|
||||
public IEnumerable<Actor> Passengers { get { return cargo; } }
|
||||
public int PassengerCount { get { return cargo.Count; } }
|
||||
|
||||
enum State { Free, Locked }
|
||||
State state = State.Free;
|
||||
|
||||
public Cargo(ActorInitializer init, CargoInfo info)
|
||||
{
|
||||
self = init.Self;
|
||||
Info = info;
|
||||
Unloading = false;
|
||||
checkTerrainType = info.UnloadTerrainTypes.Count > 0;
|
||||
|
||||
if (init.Contains<RuntimeCargoInit>())
|
||||
@@ -195,11 +208,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
if (!order.Queued)
|
||||
self.CancelActivity();
|
||||
|
||||
Unloading = true;
|
||||
if (aircraft != null)
|
||||
self.QueueActivity(new Land(self));
|
||||
|
||||
self.QueueActivity(new UnloadCargo(self, true));
|
||||
self.QueueActivity(new UnloadCargo(self, Info.LoadRange));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,13 +227,13 @@ namespace OpenRA.Mods.Common.Traits
|
||||
return false;
|
||||
}
|
||||
|
||||
return !IsEmpty(self) && (aircraft == null || aircraft.CanLand(self.Location))
|
||||
return !IsEmpty(self) && (aircraft == null || aircraft.CanLand(self.Location, blockedByMobile: false))
|
||||
&& CurrentAdjacentCells != null && CurrentAdjacentCells.Any(c => Passengers.Any(p => p.Trait<IPositionable>().CanEnterCell(c, null, immediate)));
|
||||
}
|
||||
|
||||
public bool CanLoad(Actor self, Actor a)
|
||||
{
|
||||
return (reserves.Contains(a) || HasSpace(GetWeight(a))) && self.IsAtGroundLevel();
|
||||
return reserves.Contains(a) || HasSpace(GetWeight(a));
|
||||
}
|
||||
|
||||
internal bool ReserveSpace(Actor a)
|
||||
@@ -241,6 +250,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
reserves.Add(a);
|
||||
reservedWeight += w;
|
||||
LockForPickup(self);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -252,11 +262,43 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
reservedWeight -= GetWeight(a);
|
||||
reserves.Remove(a);
|
||||
ReleaseLock(self);
|
||||
|
||||
if (loadingToken != ConditionManager.InvalidConditionToken)
|
||||
loadingToken = conditionManager.RevokeCondition(self, loadingToken);
|
||||
}
|
||||
|
||||
// Prepare for transport pickup
|
||||
bool LockForPickup(Actor self)
|
||||
{
|
||||
if (state == State.Locked)
|
||||
return false;
|
||||
|
||||
state = State.Locked;
|
||||
|
||||
self.CancelActivity();
|
||||
|
||||
var air = self.TraitOrDefault<Aircraft>();
|
||||
if (air != null && !air.AtLandAltitude)
|
||||
self.QueueActivity(new Land(self));
|
||||
|
||||
self.QueueActivity(new WaitFor(() => state != State.Locked, false));
|
||||
return true;
|
||||
}
|
||||
|
||||
void ReleaseLock(Actor self)
|
||||
{
|
||||
if (reservedWeight != 0)
|
||||
return;
|
||||
|
||||
state = State.Free;
|
||||
|
||||
self.QueueActivity(new Wait(Info.AfterLoadDelay, false));
|
||||
var air = self.TraitOrDefault<Aircraft>();
|
||||
if (air != null)
|
||||
self.QueueActivity(new TakeOff(self));
|
||||
}
|
||||
|
||||
public string CursorForOrder(Actor self, Order order)
|
||||
{
|
||||
if (order.OrderString != "Unload")
|
||||
@@ -353,6 +395,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
{
|
||||
reservedWeight -= w;
|
||||
reserves.Remove(a);
|
||||
ReleaseLock(self);
|
||||
|
||||
if (loadingToken != ConditionManager.InvalidConditionToken)
|
||||
loadingToken = conditionManager.RevokeCondition(self, loadingToken);
|
||||
|
||||
@@ -23,11 +23,11 @@ namespace OpenRA.Mods.Common.Traits
|
||||
[Desc("Transports actors with the `Carryable` trait.")]
|
||||
public class CarryallInfo : ITraitInfo, Requires<BodyOrientationInfo>, Requires<AircraftInfo>
|
||||
{
|
||||
[Desc("Delay on the ground while attaching an actor to the carryall.")]
|
||||
public readonly int LoadingDelay = 0;
|
||||
[Desc("Delay (in ticks) on the ground while attaching an actor to the carryall.")]
|
||||
public readonly int BeforeLoadDelay = 0;
|
||||
|
||||
[Desc("Delay on the ground while detacting an actor to the carryall.")]
|
||||
public readonly int UnloadingDelay = 0;
|
||||
[Desc("Delay (in ticks) on the ground while detaching an actor from the carryall.")]
|
||||
public readonly int BeforeUnloadDelay = 0;
|
||||
|
||||
[Desc("Carryable attachment point relative to body.")]
|
||||
public readonly WVec LocalOffset = WVec.Zero;
|
||||
@@ -317,7 +317,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
self.CancelActivity();
|
||||
|
||||
self.SetTargetLine(order.Target, Color.Yellow);
|
||||
self.QueueActivity(order.Queued, new PickupUnit(self, order.Target.Actor, Info.LoadingDelay));
|
||||
self.QueueActivity(order.Queued, new PickupUnit(self, order.Target.Actor, Info.BeforeLoadDelay));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -168,9 +168,13 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
public bool Reserve(Actor self, Cargo cargo)
|
||||
{
|
||||
if (cargo == ReservedCargo)
|
||||
return true;
|
||||
|
||||
Unreserve(self);
|
||||
if (!cargo.ReserveSpace(self))
|
||||
return false;
|
||||
|
||||
ReservedCargo = cargo;
|
||||
return true;
|
||||
}
|
||||
@@ -181,6 +185,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
{
|
||||
if (ReservedCargo == null)
|
||||
return;
|
||||
|
||||
ReservedCargo.UnreserveSpace(self);
|
||||
ReservedCargo = null;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace OpenRA.Mods.Common.UpdateRules.Rules
|
||||
{
|
||||
public class RenameCarryallDelays : UpdateRule
|
||||
{
|
||||
public override string Name { get { return "Rename Carryall and Cargo delay parameters"; } }
|
||||
public override string Description
|
||||
{
|
||||
get
|
||||
{
|
||||
return "Carryall's LoadingDelay and UnloadingDelay parameters have been renamed\n"
|
||||
+ "to BeforeLoadDelay and BeforeUnloadDelay to match new parameters on Cargo.";
|
||||
}
|
||||
}
|
||||
|
||||
public override IEnumerable<string> UpdateActorNode(ModData modData, MiniYamlNode actorNode)
|
||||
{
|
||||
foreach (var carryall in actorNode.ChildrenMatching("Carryall"))
|
||||
{
|
||||
foreach (var node in carryall.ChildrenMatching("LoadingDelay"))
|
||||
node.RenameKey("BeforeLoadDelay");
|
||||
|
||||
foreach (var node in carryall.ChildrenMatching("UnloadingDelay"))
|
||||
node.RenameKey("BeforeUnloadDelay");
|
||||
}
|
||||
|
||||
yield break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -129,6 +129,7 @@ namespace OpenRA.Mods.Common.UpdateRules
|
||||
new RemovePlaceBuildingPalettes(),
|
||||
new RenameHoversOffsetModifier(),
|
||||
new AddAirAttackTypes(),
|
||||
new RenameCarryallDelays(),
|
||||
})
|
||||
};
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ TRAN:
|
||||
Queue: Aircraft.GDI, Aircraft.Nod
|
||||
Description: Fast Infantry Transport Helicopter.\n Unarmed
|
||||
Aircraft:
|
||||
LandWhenIdle: true
|
||||
LandWhenIdle: false
|
||||
TurnSpeed: 5
|
||||
Speed: 150
|
||||
AltitudeVelocity: 0c100
|
||||
@@ -43,6 +43,7 @@ TRAN:
|
||||
Types: Infantry
|
||||
MaxWeight: 10
|
||||
PipCount: 10
|
||||
AfterUnloadDelay: 40
|
||||
SpawnActorOnDeath:
|
||||
Actor: TRAN.Husk
|
||||
SelectionDecorations:
|
||||
|
||||
@@ -34,8 +34,8 @@ carryall.reinforce:
|
||||
Actor: carryall.huskVTOL
|
||||
RequiresCondition: !cruising
|
||||
Carryall:
|
||||
LoadingDelay: 10
|
||||
UnloadingDelay: 15
|
||||
BeforeLoadDelay: 10
|
||||
BeforeUnloadDelay: 15
|
||||
LocalOffset: 0, 0, -128
|
||||
RenderSprites:
|
||||
Image: carryall
|
||||
@@ -52,8 +52,8 @@ carryall:
|
||||
Inherits: carryall.reinforce
|
||||
-Carryall:
|
||||
AutoCarryall:
|
||||
LoadingDelay: 10
|
||||
UnloadingDelay: 15
|
||||
BeforeLoadDelay: 10
|
||||
BeforeUnloadDelay: 15
|
||||
LocalOffset: 0, 0, -128
|
||||
Aircraft:
|
||||
MinAirborneAltitude: 400
|
||||
|
||||
@@ -238,6 +238,7 @@ TRAN:
|
||||
Range: 6c0
|
||||
Type: GroundPosition
|
||||
Aircraft:
|
||||
LandWhenIdle: false
|
||||
TurnSpeed: 5
|
||||
Speed: 128
|
||||
AltitudeVelocity: 0c58
|
||||
@@ -261,6 +262,7 @@ TRAN:
|
||||
Types: Infantry
|
||||
MaxWeight: 8
|
||||
PipCount: 8
|
||||
AfterUnloadDelay: 40
|
||||
SpawnActorOnDeath:
|
||||
Actor: TRAN.Husk
|
||||
SelectionDecorations:
|
||||
|
||||
@@ -190,7 +190,7 @@ ORCATRAN:
|
||||
Prerequisites: ~disabled
|
||||
RenderSprites:
|
||||
Aircraft:
|
||||
LandWhenIdle: true
|
||||
LandWhenIdle: false
|
||||
TurnSpeed: 5
|
||||
Speed: 84
|
||||
InitialFacing: 0
|
||||
@@ -210,6 +210,7 @@ ORCATRAN:
|
||||
PipCount: 5
|
||||
UnloadVoice: Move
|
||||
EjectOnDeath: true
|
||||
AfterUnloadDelay: 40
|
||||
SpawnActorOnDeath:
|
||||
Actor: ORCATRAN.Husk
|
||||
|
||||
@@ -236,6 +237,8 @@ TRNSPORT:
|
||||
Carryall:
|
||||
Voice: Move
|
||||
LocalOffset: 0,0,-317
|
||||
BeforeLoadDelay: 10
|
||||
BeforeUnloadDelay: 10
|
||||
Health:
|
||||
HP: 17500
|
||||
Armor:
|
||||
|
||||
Reference in New Issue
Block a user