Move movement to resupplier inside Resupply activity

From Repairable(Near).
This commit is contained in:
reaperrr
2019-06-25 02:36:31 +02:00
committed by Paul Chote
parent a7fa372045
commit f71912f337
3 changed files with 94 additions and 96 deletions

View File

@@ -10,9 +10,11 @@
#endregion #endregion
using System; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using OpenRA.Activities; using OpenRA.Activities;
using OpenRA.Mods.Common.Traits; using OpenRA.Mods.Common.Traits;
using OpenRA.Primitives;
using OpenRA.Traits; using OpenRA.Traits;
namespace OpenRA.Mods.Common.Activities namespace OpenRA.Mods.Common.Activities
@@ -27,9 +29,13 @@ namespace OpenRA.Mods.Common.Activities
readonly RepairableNear repairableNear; readonly RepairableNear repairableNear;
readonly Rearmable rearmable; readonly Rearmable rearmable;
readonly INotifyResupply[] notifyResupplies; readonly INotifyResupply[] notifyResupplies;
readonly ICallForTransport[] transportCallers;
readonly IMove move;
readonly Aircraft aircraft;
int remainingTicks; int remainingTicks;
bool played; bool played;
bool actualResupplyStarted;
ResupplyType activeResupplyTypes = ResupplyType.None; ResupplyType activeResupplyTypes = ResupplyType.None;
public Resupply(Actor self, Actor host, WDist closeEnough) public Resupply(Actor self, Actor host, WDist closeEnough)
@@ -42,6 +48,9 @@ namespace OpenRA.Mods.Common.Activities
repairableNear = self.TraitOrDefault<RepairableNear>(); repairableNear = self.TraitOrDefault<RepairableNear>();
rearmable = self.TraitOrDefault<Rearmable>(); rearmable = self.TraitOrDefault<Rearmable>();
notifyResupplies = host.TraitsImplementing<INotifyResupply>().ToArray(); notifyResupplies = host.TraitsImplementing<INotifyResupply>().ToArray();
transportCallers = self.TraitsImplementing<ICallForTransport>().ToArray();
move = self.Trait<IMove>();
aircraft = move as Aircraft;
var cannotRepairAtHost = health == null || health.DamageState == DamageState.Undamaged var cannotRepairAtHost = health == null || health.DamageState == DamageState.Undamaged
|| !allRepairsUnits.Any() || !allRepairsUnits.Any()
@@ -56,23 +65,6 @@ namespace OpenRA.Mods.Common.Activities
activeResupplyTypes |= ResupplyType.Rearm; activeResupplyTypes |= ResupplyType.Rearm;
} }
protected override void OnFirstRun(Actor self)
{
if (host.Type == TargetType.Invalid)
return;
if (activeResupplyTypes > 0)
foreach (var notifyResupply in notifyResupplies)
notifyResupply.BeforeResupply(host.Actor, self, activeResupplyTypes);
// Reset the ReloadDelay to avoid any issues with early cancellation
// from previous reload attempts (explicit order, host building died, etc).
// HACK: this really shouldn't be managed from here
if (activeResupplyTypes.HasFlag(ResupplyType.Rearm))
foreach (var pool in rearmable.RearmableAmmoPools)
pool.RemainingTicks = pool.Info.ReloadDelay;
}
public override bool Tick(Actor self) public override bool Tick(Actor self)
{ {
// HACK: If the activity is cancelled while we're already resupplying (or about to start resupplying), // HACK: If the activity is cancelled while we're already resupplying (or about to start resupplying),
@@ -83,7 +75,6 @@ namespace OpenRA.Mods.Common.Activities
foreach (var notifyResupply in notifyResupplies) foreach (var notifyResupply in notifyResupplies)
notifyResupply.ResupplyTick(host.Actor, self, ResupplyType.None); notifyResupply.ResupplyTick(host.Actor, self, ResupplyType.None);
var aircraft = self.TraitOrDefault<Aircraft>();
if (aircraft != null) if (aircraft != null)
{ {
aircraft.AllowYieldingReservation(); aircraft.AllowYieldingReservation();
@@ -92,14 +83,15 @@ namespace OpenRA.Mods.Common.Activities
return true; return true;
} }
else if (self.Info.HasTraitInfo<MobileInfo>()) else if (repairableNear != null)
return true;
else
{ {
QueueChild(self.Trait<IMove>().MoveToTarget(self, host)); QueueChild(move.MoveToTarget(self, host));
return false; return false;
} }
} }
else if (IsCanceling || host.Type == TargetType.Invalid else if (IsCanceling || host.Type != TargetType.Actor || !host.Actor.IsInWorld || host.Actor.IsDead)
|| (closeEnough.LengthSquared > 0 && !host.IsInRange(self.CenterPosition, closeEnough)))
{ {
// This is necessary to ensure host resupply actions (like animations) finish properly // This is necessary to ensure host resupply actions (like animations) finish properly
foreach (var notifyResupply in notifyResupplies) foreach (var notifyResupply in notifyResupplies)
@@ -107,6 +99,50 @@ namespace OpenRA.Mods.Common.Activities
return true; return true;
} }
else if (activeResupplyTypes != 0 && aircraft == null &&
(closeEnough.LengthSquared > 0 && !host.IsInRange(self.CenterPosition, closeEnough)))
{
var targetCell = self.World.Map.CellContaining(host.Actor.CenterPosition);
List<Activity> movement = new List<Activity>();
movement.Add(move.MoveWithinRange(host, closeEnough, targetLineColor: Color.Green));
// HACK: Repairable needs the actor to move to host center.
// TODO: Get rid of this or at least replace it with something less hacky.
if (repairableNear == null)
movement.Add(move.MoveTo(targetCell, host.Actor));
var moveActivities = ActivityUtils.SequenceActivities(movement.ToArray());
var delta = (self.CenterPosition - host.CenterPosition).LengthSquared;
var transport = transportCallers.FirstOrDefault(t => t.MinimumDistance.LengthSquared < delta);
if (transport != null)
{
QueueChild(new WaitForTransport(self, moveActivities));
// TODO: Make this compatible with RepairableNear
transport.RequestTransport(self, targetCell, new Resupply(self, host.Actor, closeEnough));
}
else
QueueChild(moveActivities);
return false;
}
// We don't want to trigger this until we've reached the resupplier and can start resupplying
if (!actualResupplyStarted && activeResupplyTypes > 0)
{
actualResupplyStarted = true;
foreach (var notifyResupply in notifyResupplies)
notifyResupply.BeforeResupply(host.Actor, self, activeResupplyTypes);
// Reset the ReloadDelay to avoid any issues with early cancellation
// from previous reload attempts (explicit order, host building died, etc).
// HACK: this really shouldn't be managed from here
if (activeResupplyTypes.HasFlag(ResupplyType.Rearm))
foreach (var pool in rearmable.RearmableAmmoPools)
pool.RemainingTicks = pool.Info.ReloadDelay;
}
if (activeResupplyTypes.HasFlag(ResupplyType.Repair)) if (activeResupplyTypes.HasFlag(ResupplyType.Repair))
RepairTick(self); RepairTick(self);
@@ -119,10 +155,18 @@ namespace OpenRA.Mods.Common.Activities
if (activeResupplyTypes == 0) if (activeResupplyTypes == 0)
{ {
var aircraft = self.TraitOrDefault<Aircraft>();
if (aircraft != null) if (aircraft != null)
aircraft.AllowYieldingReservation(); aircraft.AllowYieldingReservation();
if (self.CurrentActivity.NextActivity == null)
{
var rp = host.Actor.TraitOrDefault<RallyPoint>();
if (rp != null)
Queue(move.MoveTo(rp.Location, repairableNear != null ? null : host.Actor));
else if (repairableNear == null)
Queue(move.MoveToTarget(self, host));
}
return true; return true;
} }

View File

@@ -44,20 +44,20 @@ namespace OpenRA.Mods.Common.Traits
{ {
public readonly RepairableInfo Info; public readonly RepairableInfo Info;
readonly IHealth health; readonly IHealth health;
readonly IMove movement;
Rearmable rearmable; Rearmable rearmable;
bool requireForceMove; bool requireForceMove;
bool isAircraft;
public Repairable(Actor self, RepairableInfo info) public Repairable(Actor self, RepairableInfo info)
{ {
Info = info; Info = info;
health = self.Trait<IHealth>(); health = self.Trait<IHealth>();
movement = self.Trait<IMove>();
} }
void INotifyCreated.Created(Actor self) void INotifyCreated.Created(Actor self)
{ {
rearmable = self.TraitOrDefault<Rearmable>(); rearmable = self.TraitOrDefault<Rearmable>();
isAircraft = self.Info.HasTraitInfo<AircraftInfo>();
} }
public IEnumerable<IOrderTargeter> Orders public IEnumerable<IOrderTargeter> Orders
@@ -106,58 +106,38 @@ namespace OpenRA.Mods.Common.Traits
void IResolveOrder.ResolveOrder(Actor self, Order order) void IResolveOrder.ResolveOrder(Actor self, Order order)
{ {
if (order.OrderString == "Repair") if (order.OrderString != "Repair")
{ return;
// Repair orders are only valid for own/allied actors,
// which are guaranteed to never be frozen.
if (order.Target.Type != TargetType.Actor)
return;
// Aircraft handle Repair orders directly in the Aircraft trait // Repair orders are only valid for own/allied actors,
if (self.Info.HasTraitInfo<AircraftInfo>()) // which are guaranteed to never be frozen.
return;
if (!CanRepairAt(order.Target.Actor) || (!CanRepair() && !CanRearm()))
return;
if (!order.Queued)
self.CancelActivity();
self.SetTargetLine(order.Target, Color.Green);
var activities = ActivityUtils.SequenceActivities(
movement.MoveToTarget(self, order.Target, targetLineColor: Color.Green),
new CallFunc(() => AfterReachActivities(self, order, movement)));
self.QueueActivity(new WaitForTransport(self, activities));
TryCallTransport(self, order.Target, new CallFunc(() => AfterReachActivities(self, order, movement)));
}
}
void AfterReachActivities(Actor self, Order order, IMove movement)
{
if (order.Target.Type != TargetType.Actor) if (order.Target.Type != TargetType.Actor)
return; return;
var targetActor = order.Target.Actor; // Aircraft handle Repair orders directly in the Aircraft trait
if (!targetActor.IsInWorld || targetActor.IsDead || targetActor.TraitsImplementing<RepairsUnits>().All(r => r.IsTraitDisabled)) // TODO: Move the order handling of both this trait and Aircraft to a generalistic DockManager
if (isAircraft)
return; return;
// TODO: This is hacky, but almost every single component affected if (!CanRepairAt(order.Target.Actor) || (!CanRepair() && !CanRearm()))
// will need to be rewritten anyway, so this is OK for now. return;
self.QueueActivity(movement.MoveTo(self.World.Map.CellContaining(targetActor.CenterPosition), targetActor));
// Add a CloseEnough range of 512 to ensure we're at the host actor if (!order.Queued)
self.QueueActivity(new Resupply(self, targetActor, new WDist(512))); self.CancelActivity();
var rp = targetActor.TraitOrDefault<RallyPoint>(); self.SetTargetLine(order.Target, Color.Green);
if (rp != null) self.QueueActivity(new Resupply(self, order.Target.Actor, new WDist(512)));
{ }
self.QueueActivity(new CallFunc(() =>
{ IEnumerable<VariableObserver> IObservesVariables.GetVariableObservers()
self.SetTargetLine(Target.FromCell(self.World, rp.Location), Color.Green); {
self.QueueActivity(movement.MoveTo(rp.Location, targetActor)); if (Info.RequireForceMoveCondition != null)
})); yield return new VariableObserver(RequireForceMoveConditionChanged, Info.RequireForceMoveCondition.Variables);
} }
void RequireForceMoveConditionChanged(Actor self, IReadOnlyDictionary<string, int> conditions)
{
requireForceMove = Info.RequireForceMoveCondition.Evaluate(conditions);
} }
public Actor FindRepairBuilding(Actor self) public Actor FindRepairBuilding(Actor self)
@@ -172,27 +152,5 @@ namespace OpenRA.Mods.Common.Traits
// Worst case FirstOrDefault() will return a TraitPair<null, null>, which is OK. // Worst case FirstOrDefault() will return a TraitPair<null, null>, which is OK.
return repairBuilding.FirstOrDefault().Actor; return repairBuilding.FirstOrDefault().Actor;
} }
static void TryCallTransport(Actor self, Target target, Activity nextActivity)
{
var targetCell = self.World.Map.CellContaining(target.CenterPosition);
var delta = (self.CenterPosition - target.CenterPosition).LengthSquared;
var transports = self.TraitsImplementing<ICallForTransport>()
.Where(t => t.MinimumDistance.LengthSquared < delta);
foreach (var t in transports)
t.RequestTransport(self, targetCell, nextActivity);
}
IEnumerable<VariableObserver> IObservesVariables.GetVariableObservers()
{
if (Info.RequireForceMoveCondition != null)
yield return new VariableObserver(RequireForceMoveConditionChanged, Info.RequireForceMoveCondition.Variables);
}
void RequireForceMoveConditionChanged(Actor self, IReadOnlyDictionary<string, int> conditions)
{
requireForceMove = Info.RequireForceMoveCondition.Evaluate(conditions);
}
} }
} }

View File

@@ -41,14 +41,12 @@ namespace OpenRA.Mods.Common.Traits
{ {
public readonly RepairableNearInfo Info; public readonly RepairableNearInfo Info;
readonly Actor self; readonly Actor self;
readonly IMove movement;
bool requireForceMove; bool requireForceMove;
public RepairableNear(Actor self, RepairableNearInfo info) public RepairableNear(Actor self, RepairableNearInfo info)
{ {
this.self = self; this.self = self;
Info = info; Info = info;
movement = self.Trait<IMove>();
} }
public IEnumerable<IOrderTargeter> Orders public IEnumerable<IOrderTargeter> Orders
@@ -104,10 +102,8 @@ namespace OpenRA.Mods.Common.Traits
if (!order.Queued) if (!order.Queued)
self.CancelActivity(); self.CancelActivity();
self.QueueActivity(movement.MoveWithinRange(order.Target, Info.CloseEnough, targetLineColor: Color.Green)); self.SetTargetLine(order.Target, Color.Green);
self.QueueActivity(new Resupply(self, order.Target.Actor, Info.CloseEnough)); self.QueueActivity(new Resupply(self, order.Target.Actor, Info.CloseEnough));
self.SetTargetLine(order.Target, Color.Green, false);
} }
public Actor FindRepairBuilding(Actor self) public Actor FindRepairBuilding(Actor self)