Require force move for all undeploy-triggering orders.

This commit is contained in:
Paul Chote
2019-06-07 23:08:11 +00:00
committed by reaperrr
parent 5d886b79f1
commit ebe37a44ad
19 changed files with 249 additions and 90 deletions

View File

@@ -1,57 +0,0 @@
#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;
using OpenRA.Mods.Common.Traits;
using OpenRA.Traits;
namespace OpenRA.Mods.Common.Orders
{
public class AircraftMoveOrderTargeter : IOrderTargeter
{
public string OrderID { get; protected set; }
public int OrderPriority { get; protected set; }
public bool TargetOverridesSelection(TargetModifiers modifiers)
{
return modifiers.HasModifier(TargetModifiers.ForceMove);
}
readonly AircraftInfo info;
public AircraftMoveOrderTargeter(AircraftInfo info)
{
this.info = info;
OrderID = "Move";
OrderPriority = 4;
}
public virtual bool CanTarget(Actor self, Target target, List<Actor> othersAtTarget, ref TargetModifiers modifiers, ref string cursor)
{
if (target.Type != TargetType.Terrain)
return false;
var location = self.World.Map.CellContaining(target.CenterPosition);
var explored = self.Owner.Shroud.IsExplored(location);
cursor = self.World.Map.Contains(location) ?
(self.World.Map.GetTerrainInfo(location).CustomCursor ?? "move") :
"move-blocked";
IsQueued = modifiers.HasModifier(TargetModifiers.ForceQueue);
if (!explored && !info.MoveIntoShroud)
cursor = "move-blocked";
return true;
}
public bool IsQueued { get; protected set; }
}
}

View File

@@ -16,11 +16,11 @@ namespace OpenRA.Mods.Common.Orders
{ {
public class EnterAlliedActorTargeter<T> : UnitOrderTargeter where T : ITraitInfo public class EnterAlliedActorTargeter<T> : UnitOrderTargeter where T : ITraitInfo
{ {
readonly Func<Actor, bool> canTarget; readonly Func<Actor, TargetModifiers, bool> canTarget;
readonly Func<Actor, bool> useEnterCursor; readonly Func<Actor, bool> useEnterCursor;
public EnterAlliedActorTargeter(string order, int priority, public EnterAlliedActorTargeter(string order, int priority,
Func<Actor, bool> canTarget, Func<Actor, bool> useEnterCursor) Func<Actor, TargetModifiers, bool> canTarget, Func<Actor, bool> useEnterCursor)
: base(order, priority, "enter", false, true) : base(order, priority, "enter", false, true)
{ {
this.canTarget = canTarget; this.canTarget = canTarget;
@@ -29,7 +29,7 @@ namespace OpenRA.Mods.Common.Orders
public override bool CanTargetActor(Actor self, Actor target, TargetModifiers modifiers, ref string cursor) public override bool CanTargetActor(Actor self, Actor target, TargetModifiers modifiers, ref string cursor)
{ {
if (!self.Owner.IsAlliedWith(target.Owner) || !target.Info.HasTraitInfo<T>() || !canTarget(target)) if (!self.Owner.IsAlliedWith(target.Owner) || !target.Info.HasTraitInfo<T>() || !canTarget(target, modifiers))
return false; return false;
cursor = useEnterCursor(target) ? "enter" : "enter-blocked"; cursor = useEnterCursor(target) ? "enter" : "enter-blocked";

View File

@@ -22,7 +22,7 @@ using OpenRA.Traits;
namespace OpenRA.Mods.Common.Traits namespace OpenRA.Mods.Common.Traits
{ {
public class AircraftInfo : ITraitInfo, IPositionableInfo, IFacingInfo, IMoveInfo, ICruiseAltitudeInfo, public class AircraftInfo : ITraitInfo, IPositionableInfo, IFacingInfo, IMoveInfo, ICruiseAltitudeInfo,
IActorPreviewInitInfo, IEditorActorOptions IActorPreviewInitInfo, IEditorActorOptions, IObservesVariablesInfo
{ {
public readonly WDist CruiseAltitude = new WDist(1280); public readonly WDist CruiseAltitude = new WDist(1280);
@@ -120,6 +120,10 @@ namespace OpenRA.Mods.Common.Traits
[Desc("Display order for the facing slider in the map editor")] [Desc("Display order for the facing slider in the map editor")]
public readonly int EditorFacingDisplayOrder = 3; public readonly int EditorFacingDisplayOrder = 3;
[ConsumedConditionReference]
[Desc("Boolean expression defining the condition under which the regular (non-force) move cursor is disabled.")]
public readonly BooleanExpression RequireForceMoveCondition = null;
public int GetInitialFacing() { return InitialFacing; } public int GetInitialFacing() { return InitialFacing; }
public WDist GetCruiseAltitude() { return CruiseAltitude; } public WDist GetCruiseAltitude() { return CruiseAltitude; }
@@ -197,6 +201,7 @@ namespace OpenRA.Mods.Common.Traits
public bool MayYieldReservation { get; private set; } public bool MayYieldReservation { get; private set; }
public bool ForceLanding { get; private set; } public bool ForceLanding { get; private set; }
CPos? landingCell; CPos? landingCell;
bool requireForceMove;
public WDist LandAltitude { get; private set; } public WDist LandAltitude { get; private set; }
@@ -245,6 +250,9 @@ namespace OpenRA.Mods.Common.Traits
{ {
if (Info.LandOnCondition != null) if (Info.LandOnCondition != null)
yield return new VariableObserver(ForceLandConditionChanged, Info.LandOnCondition.Variables); yield return new VariableObserver(ForceLandConditionChanged, Info.LandOnCondition.Variables);
if (Info.RequireForceMoveCondition != null)
yield return new VariableObserver(RequireForceMoveConditionChanged, Info.RequireForceMoveCondition.Variables);
} }
void ForceLandConditionChanged(Actor self, IReadOnlyDictionary<string, int> variables) void ForceLandConditionChanged(Actor self, IReadOnlyDictionary<string, int> variables)
@@ -252,6 +260,11 @@ namespace OpenRA.Mods.Common.Traits
landNow = Info.LandOnCondition.Evaluate(variables); landNow = Info.LandOnCondition.Evaluate(variables);
} }
void RequireForceMoveConditionChanged(Actor self, IReadOnlyDictionary<string, int> conditions)
{
requireForceMove = Info.RequireForceMoveCondition.Evaluate(conditions);
}
void INotifyCreated.Created(Actor self) void INotifyCreated.Created(Actor self)
{ {
Created(self); Created(self);
@@ -508,6 +521,14 @@ namespace OpenRA.Mods.Common.Traits
self.QueueActivity(new TakeOff(self)); self.QueueActivity(new TakeOff(self));
} }
bool AircraftCanEnter(Actor a, TargetModifiers modifiers)
{
if (requireForceMove && !modifiers.HasModifier(TargetModifiers.ForceMove))
return false;
return AircraftCanEnter(a);
}
public bool AircraftCanEnter(Actor a) public bool AircraftCanEnter(Actor a)
{ {
if (self.AppearsHostileTo(a)) if (self.AppearsHostileTo(a))
@@ -854,9 +875,9 @@ namespace OpenRA.Mods.Common.Traits
get get
{ {
yield return new EnterAlliedActorTargeter<BuildingInfo>("Enter", 5, yield return new EnterAlliedActorTargeter<BuildingInfo>("Enter", 5,
target => AircraftCanEnter(target), target => Reservable.IsAvailableFor(target, self)); AircraftCanEnter, target => Reservable.IsAvailableFor(target, self));
yield return new AircraftMoveOrderTargeter(Info); yield return new AircraftMoveOrderTargeter(this);
} }
} }
@@ -1038,5 +1059,43 @@ namespace OpenRA.Mods.Common.Traits
if (!inits.Contains<DynamicFacingInit>() && !inits.Contains<FacingInit>()) if (!inits.Contains<DynamicFacingInit>() && !inits.Contains<FacingInit>())
inits.Add(new DynamicFacingInit(() => Facing)); inits.Add(new DynamicFacingInit(() => Facing));
} }
public class AircraftMoveOrderTargeter : IOrderTargeter
{
readonly Aircraft aircraft;
public string OrderID { get { return "Move"; } }
public int OrderPriority { get { return 4; } }
public bool IsQueued { get; protected set; }
public AircraftMoveOrderTargeter(Aircraft aircraft)
{
this.aircraft = aircraft;
}
public bool TargetOverridesSelection(TargetModifiers modifiers)
{
return modifiers.HasModifier(TargetModifiers.ForceMove);
}
public virtual bool CanTarget(Actor self, Target target, List<Actor> othersAtTarget, ref TargetModifiers modifiers, ref string cursor)
{
if (target.Type != TargetType.Terrain || (aircraft.requireForceMove && !modifiers.HasModifier(TargetModifiers.ForceMove)))
return false;
var location = self.World.Map.CellContaining(target.CenterPosition);
var explored = self.Owner.Shroud.IsExplored(location);
cursor = self.World.Map.Contains(location) ?
(self.World.Map.GetTerrainInfo(location).CustomCursor ?? "move") :
"move-blocked";
IsQueued = modifiers.HasModifier(TargetModifiers.ForceQueue);
if (!explored && !aircraft.Info.MoveIntoShroud)
cursor = "move-blocked";
return true;
}
}
} }
} }

View File

@@ -33,6 +33,9 @@ namespace OpenRA.Mods.Common.Traits
[VoiceReference] [VoiceReference]
public readonly string Voice = "Action"; public readonly string Voice = "Action";
[Desc("Require the force-move modifier to display the move cursor.")]
public readonly bool RequiresForceMove = false;
public override object Create(ActorInitializer init) { return new TransformsIntoAircraft(init, this); } public override object Create(ActorInitializer init) { return new TransformsIntoAircraft(init, this); }
} }
@@ -66,6 +69,14 @@ namespace OpenRA.Mods.Common.Traits
} }
} }
public bool AircraftCanEnter(Actor a, TargetModifiers modifiers)
{
if (Info.RequiresForceMove && !modifiers.HasModifier(TargetModifiers.ForceMove))
return false;
return AircraftCanEnter(a);
}
public bool AircraftCanEnter(Actor a) public bool AircraftCanEnter(Actor a)
{ {
return !self.AppearsHostileTo(a) && Info.DockActors.Contains(a.Info.Name); return !self.AppearsHostileTo(a) && Info.DockActors.Contains(a.Info.Name);

View File

@@ -29,6 +29,9 @@ namespace OpenRA.Mods.Common.Traits
[VoiceReference] [VoiceReference]
public readonly string Voice = "Action"; public readonly string Voice = "Action";
[Desc("Require the force-move modifier to display the enter cursor.")]
public readonly bool RequiresForceMove = false;
public override object Create(ActorInitializer init) { return new TransformsIntoEntersTunnels(this); } public override object Create(ActorInitializer init) { return new TransformsIntoEntersTunnels(this); }
} }
@@ -50,7 +53,7 @@ namespace OpenRA.Mods.Common.Traits
get get
{ {
if (!IsTraitDisabled) if (!IsTraitDisabled)
yield return new EntersTunnels.EnterTunnelOrderTargeter(Info.EnterCursor, Info.EnterBlockedCursor); yield return new EntersTunnels.EnterTunnelOrderTargeter(Info.EnterCursor, Info.EnterBlockedCursor, () => Info.RequiresForceMove);
} }
} }

View File

@@ -29,6 +29,9 @@ namespace OpenRA.Mods.Common.Traits
[VoiceReference] [VoiceReference]
public readonly string Voice = "Action"; public readonly string Voice = "Action";
[Desc("Require the force-move modifier to display the enter cursor.")]
public readonly bool RequiresForceMove = false;
public override object Create(ActorInitializer init) { return new TransformsIntoPassenger(this); } public override object Create(ActorInitializer init) { return new TransformsIntoPassenger(this); }
} }
@@ -62,6 +65,14 @@ namespace OpenRA.Mods.Common.Traits
return null; return null;
} }
bool IsCorrectCargoType(Actor target, TargetModifiers modifiers)
{
if (Info.RequiresForceMove && !modifiers.HasModifier(TargetModifiers.ForceMove))
return false;
return IsCorrectCargoType(target);
}
bool IsCorrectCargoType(Actor target) bool IsCorrectCargoType(Actor target)
{ {
var ci = target.Info.TraitInfo<CargoInfo>(); var ci = target.Info.TraitInfo<CargoInfo>();

View File

@@ -30,6 +30,9 @@ namespace OpenRA.Mods.Common.Traits
[VoiceReference] [VoiceReference]
public readonly string Voice = "Action"; public readonly string Voice = "Action";
[Desc("Require the force-move modifier to display the enter cursor.")]
public readonly bool RequiresForceMove = false;
public override object Create(ActorInitializer init) { return new TransformsIntoRepairable(this); } public override object Create(ActorInitializer init) { return new TransformsIntoRepairable(this); }
} }
@@ -62,6 +65,14 @@ namespace OpenRA.Mods.Common.Traits
return health.DamageState > DamageState.Undamaged && transforms.Any(t => !t.IsTraitDisabled && !t.IsTraitPaused); return health.DamageState > DamageState.Undamaged && transforms.Any(t => !t.IsTraitDisabled && !t.IsTraitPaused);
} }
bool CanRepairAt(Actor target, TargetModifiers modifiers)
{
if (Info.RequiresForceMove && !modifiers.HasModifier(TargetModifiers.ForceMove))
return false;
return CanRepairAt(target);
}
bool CanRepairAt(Actor target) bool CanRepairAt(Actor target)
{ {
return Info.RepairActors.Contains(target.Info.Name); return Info.RepairActors.Contains(target.Info.Name);

View File

@@ -257,7 +257,7 @@ namespace OpenRA.Mods.Common.Traits
yield return new CarryallPickupOrderTargeter(); yield return new CarryallPickupOrderTargeter();
yield return new DeployOrderTargeter("Unload", 10, yield return new DeployOrderTargeter("Unload", 10,
() => CanUnload() ? Info.UnloadCursor : Info.UnloadBlockedCursor); () => CanUnload() ? Info.UnloadCursor : Info.UnloadBlockedCursor);
yield return new CarryallDeliverUnitTargeter(aircraftInfo, Info, CarryableOffset); yield return new CarryallDeliverUnitTargeter(aircraftInfo, Info);
} }
} }
@@ -355,23 +355,23 @@ namespace OpenRA.Mods.Common.Traits
} }
} }
class CarryallDeliverUnitTargeter : AircraftMoveOrderTargeter class CarryallDeliverUnitTargeter : IOrderTargeter
{ {
readonly AircraftInfo aircraftInfo; readonly AircraftInfo aircraftInfo;
readonly CarryallInfo info; readonly CarryallInfo info;
readonly WVec carryableOffset;
public CarryallDeliverUnitTargeter(AircraftInfo aircraftInfo, CarryallInfo info, WVec carryableOffset) public string OrderID { get { return "DeliverUnit"; } }
: base(aircraftInfo) public int OrderPriority { get { return 6; } }
public bool IsQueued { get; protected set; }
public bool TargetOverridesSelection(TargetModifiers modifiers) { return true; }
public CarryallDeliverUnitTargeter(AircraftInfo aircraftInfo, CarryallInfo info)
{ {
OrderID = "DeliverUnit";
OrderPriority = 6;
this.carryableOffset = carryableOffset;
this.aircraftInfo = aircraftInfo; this.aircraftInfo = aircraftInfo;
this.info = info; this.info = info;
} }
public override bool CanTarget(Actor self, Target target, List<Actor> othersAtTarget, ref TargetModifiers modifiers, ref string cursor) public bool CanTarget(Actor self, Target target, List<Actor> othersAtTarget, ref TargetModifiers modifiers, ref string cursor)
{ {
if (!info.AllowDropOff || !modifiers.HasModifier(TargetModifiers.ForceMove)) if (!info.AllowDropOff || !modifiers.HasModifier(TargetModifiers.ForceMove))
return false; return false;

View File

@@ -9,16 +9,18 @@
*/ */
#endregion #endregion
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using OpenRA.Mods.Common.Orders; using OpenRA.Mods.Common.Orders;
using OpenRA.Primitives; using OpenRA.Primitives;
using OpenRA.Support;
using OpenRA.Traits; using OpenRA.Traits;
namespace OpenRA.Mods.Common.Traits namespace OpenRA.Mods.Common.Traits
{ {
[Desc("This actor can interact with TunnelEntrances to move through TerrainTunnels.")] [Desc("This actor can interact with TunnelEntrances to move through TerrainTunnels.")]
public class EntersTunnelsInfo : ITraitInfo, Requires<IMoveInfo> public class EntersTunnelsInfo : ITraitInfo, Requires<IMoveInfo>, IObservesVariablesInfo
{ {
public readonly string EnterCursor = "enter"; public readonly string EnterCursor = "enter";
public readonly string EnterBlockedCursor = "enter-blocked"; public readonly string EnterBlockedCursor = "enter-blocked";
@@ -26,13 +28,18 @@ namespace OpenRA.Mods.Common.Traits
[VoiceReference] [VoiceReference]
public readonly string Voice = "Action"; public readonly string Voice = "Action";
[ConsumedConditionReference]
[Desc("Boolean expression defining the condition under which the regular (non-force) enter cursor is disabled.")]
public readonly BooleanExpression RequireForceMoveCondition = null;
public object Create(ActorInitializer init) { return new EntersTunnels(init.Self, this); } public object Create(ActorInitializer init) { return new EntersTunnels(init.Self, this); }
} }
public class EntersTunnels : IIssueOrder, IResolveOrder, IOrderVoice public class EntersTunnels : IIssueOrder, IResolveOrder, IOrderVoice, IObservesVariables
{ {
readonly EntersTunnelsInfo info; readonly EntersTunnelsInfo info;
readonly IMove move; readonly IMove move;
bool requireForceMove;
public EntersTunnels(Actor self, EntersTunnelsInfo info) public EntersTunnels(Actor self, EntersTunnelsInfo info)
{ {
@@ -44,7 +51,7 @@ namespace OpenRA.Mods.Common.Traits
{ {
get get
{ {
yield return new EnterTunnelOrderTargeter(info.EnterCursor, info.EnterBlockedCursor); yield return new EnterTunnelOrderTargeter(info.EnterCursor, info.EnterBlockedCursor, () => requireForceMove);
} }
} }
@@ -78,21 +85,34 @@ namespace OpenRA.Mods.Common.Traits
self.QueueActivity(move.MoveTo(tunnel.Exit.Value, tunnel.NearEnough)); self.QueueActivity(move.MoveTo(tunnel.Exit.Value, tunnel.NearEnough));
} }
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);
}
public class EnterTunnelOrderTargeter : UnitOrderTargeter public class EnterTunnelOrderTargeter : UnitOrderTargeter
{ {
readonly string enterCursor; readonly string enterCursor;
readonly string enterBlockedCursor; readonly string enterBlockedCursor;
readonly Func<bool> requireForceMove;
public EnterTunnelOrderTargeter(string enterCursor, string enterBlockedCursor) public EnterTunnelOrderTargeter(string enterCursor, string enterBlockedCursor, Func<bool> requireForceMove)
: base("EnterTunnel", 6, enterCursor, true, true) : base("EnterTunnel", 6, enterCursor, true, true)
{ {
this.enterCursor = enterCursor; this.enterCursor = enterCursor;
this.enterBlockedCursor = enterBlockedCursor; this.enterBlockedCursor = enterBlockedCursor;
this.requireForceMove = requireForceMove;
} }
public override bool CanTargetActor(Actor self, Actor target, TargetModifiers modifiers, ref string cursor) public override bool CanTargetActor(Actor self, Actor target, TargetModifiers modifiers, ref string cursor)
{ {
if (target == null || target.IsDead) if (target == null || target.IsDead || (requireForceMove() && !modifiers.HasModifier(TargetModifiers.ForceMove)))
return false; return false;
var tunnel = target.TraitOrDefault<TunnelEntrance>(); var tunnel = target.TraitOrDefault<TunnelEntrance>();

View File

@@ -299,7 +299,7 @@ namespace OpenRA.Mods.Common.Traits
get get
{ {
yield return new EnterAlliedActorTargeter<IAcceptResourcesInfo>("Deliver", 5, yield return new EnterAlliedActorTargeter<IAcceptResourcesInfo>("Deliver", 5,
proc => IsAcceptableProcType(proc), (proc, _) => IsAcceptableProcType(proc),
proc => proc.Trait<IAcceptResources>().AllowDocking); proc => proc.Trait<IAcceptResources>().AllowDocking);
yield return new HarvestOrderTargeter(); yield return new HarvestOrderTargeter();
} }

View File

@@ -14,12 +14,13 @@ using System.Collections.Generic;
using OpenRA.Mods.Common.Activities; using OpenRA.Mods.Common.Activities;
using OpenRA.Mods.Common.Orders; using OpenRA.Mods.Common.Orders;
using OpenRA.Primitives; using OpenRA.Primitives;
using OpenRA.Support;
using OpenRA.Traits; using OpenRA.Traits;
namespace OpenRA.Mods.Common.Traits namespace OpenRA.Mods.Common.Traits
{ {
[Desc("This actor can enter Cargo actors.")] [Desc("This actor can enter Cargo actors.")]
public class PassengerInfo : ITraitInfo public class PassengerInfo : ITraitInfo, IObservesVariablesInfo
{ {
public readonly string CargoType = null; public readonly string CargoType = null;
public readonly PipType PipType = PipType.Green; public readonly PipType PipType = PipType.Green;
@@ -39,13 +40,18 @@ namespace OpenRA.Mods.Common.Traits
[VoiceReference] [VoiceReference]
public readonly string Voice = "Action"; public readonly string Voice = "Action";
[ConsumedConditionReference]
[Desc("Boolean expression defining the condition under which the regular (non-force) enter cursor is disabled.")]
public readonly BooleanExpression RequireForceMoveCondition = null;
public object Create(ActorInitializer init) { return new Passenger(this); } public object Create(ActorInitializer init) { return new Passenger(this); }
} }
public class Passenger : INotifyCreated, IIssueOrder, IResolveOrder, IOrderVoice, INotifyRemovedFromWorld, INotifyEnteredCargo, INotifyExitedCargo, INotifyKilled public class Passenger : INotifyCreated, IIssueOrder, IResolveOrder, IOrderVoice, INotifyRemovedFromWorld, INotifyEnteredCargo, INotifyExitedCargo, INotifyKilled, IObservesVariables
{ {
public readonly PassengerInfo Info; public readonly PassengerInfo Info;
public Actor Transport; public Actor Transport;
bool requireForceMove;
ConditionManager conditionManager; ConditionManager conditionManager;
int anyCargoToken = ConditionManager.InvalidConditionToken; int anyCargoToken = ConditionManager.InvalidConditionToken;
@@ -79,6 +85,14 @@ namespace OpenRA.Mods.Common.Traits
return null; return null;
} }
bool IsCorrectCargoType(Actor target, TargetModifiers modifiers)
{
if (requireForceMove && !modifiers.HasModifier(TargetModifiers.ForceMove))
return false;
return IsCorrectCargoType(target);
}
bool IsCorrectCargoType(Actor target) bool IsCorrectCargoType(Actor target)
{ {
var ci = target.Info.TraitInfo<CargoInfo>(); var ci = target.Info.TraitInfo<CargoInfo>();
@@ -128,7 +142,7 @@ namespace OpenRA.Mods.Common.Traits
specificCargoToken = conditionManager.RevokeCondition(self, specificCargoToken); specificCargoToken = conditionManager.RevokeCondition(self, specificCargoToken);
} }
public void ResolveOrder(Actor self, Order order) void IResolveOrder.ResolveOrder(Actor self, Order order)
{ {
if (order.OrderString != "EnterTransport") if (order.OrderString != "EnterTransport")
return; return;
@@ -180,5 +194,16 @@ namespace OpenRA.Mods.Common.Traits
if (!Transport.IsDead) if (!Transport.IsDead)
Transport.Trait<Cargo>().Unload(Transport, self); Transport.Trait<Cargo>().Unload(Transport, self);
} }
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

@@ -15,12 +15,13 @@ using OpenRA.Activities;
using OpenRA.Mods.Common.Activities; using OpenRA.Mods.Common.Activities;
using OpenRA.Mods.Common.Orders; using OpenRA.Mods.Common.Orders;
using OpenRA.Primitives; using OpenRA.Primitives;
using OpenRA.Support;
using OpenRA.Traits; using OpenRA.Traits;
namespace OpenRA.Mods.Common.Traits namespace OpenRA.Mods.Common.Traits
{ {
[Desc("This actor can be sent to a structure for repairs.")] [Desc("This actor can be sent to a structure for repairs.")]
public class RepairableInfo : ITraitInfo, Requires<IHealthInfo>, Requires<IMoveInfo> public class RepairableInfo : ITraitInfo, Requires<IHealthInfo>, Requires<IMoveInfo>, IObservesVariablesInfo
{ {
[ActorReference] [ActorReference]
[FieldLoader.Require] [FieldLoader.Require]
@@ -32,15 +33,20 @@ namespace OpenRA.Mods.Common.Traits
[Desc("The amount the unit will be repaired at each step. Use -1 for fallback behavior where HpPerStep from RepairsUnits trait will be used.")] [Desc("The amount the unit will be repaired at each step. Use -1 for fallback behavior where HpPerStep from RepairsUnits trait will be used.")]
public readonly int HpPerStep = -1; public readonly int HpPerStep = -1;
[ConsumedConditionReference]
[Desc("Boolean expression defining the condition under which the regular (non-force) enter cursor is disabled.")]
public readonly BooleanExpression RequireForceMoveCondition = null;
public virtual object Create(ActorInitializer init) { return new Repairable(init.Self, this); } public virtual object Create(ActorInitializer init) { return new Repairable(init.Self, this); }
} }
public class Repairable : IIssueOrder, IResolveOrder, IOrderVoice, INotifyCreated public class Repairable : IIssueOrder, IResolveOrder, IOrderVoice, INotifyCreated, IObservesVariables
{ {
public readonly RepairableInfo Info; public readonly RepairableInfo Info;
readonly IHealth health; readonly IHealth health;
readonly IMove movement; readonly IMove movement;
Rearmable rearmable; Rearmable rearmable;
bool requireForceMove;
public Repairable(Actor self, RepairableInfo info) public Repairable(Actor self, RepairableInfo info)
{ {
@@ -75,9 +81,12 @@ namespace OpenRA.Mods.Common.Traits
return Info.RepairActors.Contains(target.Info.Name); return Info.RepairActors.Contains(target.Info.Name);
} }
bool CanRearmAt(Actor target) bool CanRepairAt(Actor target, TargetModifiers modifiers)
{ {
return rearmable != null && rearmable.Info.RearmActors.Contains(target.Info.Name); if (requireForceMove && !modifiers.HasModifier(TargetModifiers.ForceMove))
return false;
return Info.RepairActors.Contains(target.Info.Name);
} }
bool CanRepair() bool CanRepair()
@@ -95,7 +104,7 @@ namespace OpenRA.Mods.Common.Traits
return order.OrderString == "Repair" && (CanRepair() || CanRearm()) ? Info.Voice : null; return order.OrderString == "Repair" && (CanRepair() || CanRearm()) ? Info.Voice : null;
} }
public void ResolveOrder(Actor self, Order order) void IResolveOrder.ResolveOrder(Actor self, Order order)
{ {
if (order.OrderString == "Repair") if (order.OrderString == "Repair")
{ {
@@ -174,5 +183,16 @@ namespace OpenRA.Mods.Common.Traits
foreach (var t in transports) foreach (var t in transports)
t.RequestTransport(self, targetCell, nextActivity); 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

@@ -14,11 +14,12 @@ using System.Linq;
using OpenRA.Mods.Common.Activities; using OpenRA.Mods.Common.Activities;
using OpenRA.Mods.Common.Orders; using OpenRA.Mods.Common.Orders;
using OpenRA.Primitives; using OpenRA.Primitives;
using OpenRA.Support;
using OpenRA.Traits; using OpenRA.Traits;
namespace OpenRA.Mods.Common.Traits namespace OpenRA.Mods.Common.Traits
{ {
class RepairableNearInfo : ITraitInfo, Requires<IHealthInfo>, Requires<IMoveInfo> class RepairableNearInfo : ITraitInfo, Requires<IHealthInfo>, Requires<IMoveInfo>, IObservesVariablesInfo
{ {
[ActorReference] [ActorReference]
[FieldLoader.Require] [FieldLoader.Require]
@@ -29,14 +30,19 @@ namespace OpenRA.Mods.Common.Traits
[VoiceReference] [VoiceReference]
public readonly string Voice = "Action"; public readonly string Voice = "Action";
[ConsumedConditionReference]
[Desc("Boolean expression defining the condition under which the regular (non-force) enter cursor is disabled.")]
public readonly BooleanExpression RequireForceMoveCondition = null;
public object Create(ActorInitializer init) { return new RepairableNear(init.Self, this); } public object Create(ActorInitializer init) { return new RepairableNear(init.Self, this); }
} }
class RepairableNear : IIssueOrder, IResolveOrder, IOrderVoice class RepairableNear : IIssueOrder, IResolveOrder, IOrderVoice, IObservesVariables
{ {
public readonly RepairableNearInfo Info; public readonly RepairableNearInfo Info;
readonly Actor self; readonly Actor self;
readonly IMove movement; readonly IMove movement;
bool requireForceMove;
public RepairableNear(Actor self, RepairableNearInfo info) public RepairableNear(Actor self, RepairableNearInfo info)
{ {
@@ -50,7 +56,7 @@ namespace OpenRA.Mods.Common.Traits
get get
{ {
yield return new EnterAlliedActorTargeter<BuildingInfo>("RepairNear", 5, yield return new EnterAlliedActorTargeter<BuildingInfo>("RepairNear", 5,
target => CanRepairAt(target), _ => ShouldRepair()); CanRepairAt, _ => ShouldRepair());
} }
} }
@@ -62,6 +68,14 @@ namespace OpenRA.Mods.Common.Traits
return null; return null;
} }
bool CanRepairAt(Actor target, TargetModifiers modifiers)
{
if (requireForceMove && !modifiers.HasModifier(TargetModifiers.ForceMove))
return false;
return Info.RepairActors.Contains(target.Info.Name);
}
bool CanRepairAt(Actor target) bool CanRepairAt(Actor target)
{ {
return Info.RepairActors.Contains(target.Info.Name); return Info.RepairActors.Contains(target.Info.Name);
@@ -108,5 +122,16 @@ 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;
} }
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

@@ -32,9 +32,11 @@ FACT:
TransformsIntoPassenger: TransformsIntoPassenger:
RequiresCondition: factundeploy RequiresCondition: factundeploy
CargoType: Vehicle CargoType: Vehicle
RequiresForceMove: true
TransformsIntoRepairable: TransformsIntoRepairable:
RequiresCondition: factundeploy RequiresCondition: factundeploy
RepairActors: fix RepairActors: fix
RequiresForceMove: true
GrantConditionOnPrerequisite@GLOBALFACTUNDEPLOY: GrantConditionOnPrerequisite@GLOBALFACTUNDEPLOY:
Condition: factundeploy Condition: factundeploy
Prerequisites: global-factundeploy Prerequisites: global-factundeploy

View File

@@ -1149,9 +1149,11 @@ FACT:
TransformsIntoPassenger: TransformsIntoPassenger:
RequiresCondition: factundeploy RequiresCondition: factundeploy
CargoType: Vehicle CargoType: Vehicle
RequiresForceMove: true
TransformsIntoRepairable: TransformsIntoRepairable:
RequiresCondition: factundeploy RequiresCondition: factundeploy
RepairActors: fix RepairActors: fix
RequiresForceMove: true
Sellable: Sellable:
RequiresCondition: !build-incomplete && !chrono-vortex && !being-captured && !being-demolished RequiresCondition: !build-incomplete && !chrono-vortex && !being-captured && !being-demolished
GrantConditionOnPrerequisite@GLOBALFACTUNDEPLOY: GrantConditionOnPrerequisite@GLOBALFACTUNDEPLOY:

View File

@@ -358,6 +358,12 @@ JUGG:
DeploySounds: place2.aud DeploySounds: place2.aud
UndeploySounds: clicky1.aud UndeploySounds: clicky1.aud
Voice: Move Voice: Move
EntersTunnels:
RequireForceMoveCondition: !undeployed
Repairable:
RequireForceMoveCondition: !undeployed
Passenger:
RequireForceMoveCondition: !undeployed
GrantCondition@PREVIEWWORKAROUND: GrantCondition@PREVIEWWORKAROUND:
Condition: real-actor Condition: real-actor
QuantizeFacingsFromSequence: QuantizeFacingsFromSequence:

View File

@@ -141,6 +141,12 @@ TTNK:
DeploySounds: place2.aud DeploySounds: place2.aud
UndeploySounds: clicky1.aud UndeploySounds: clicky1.aud
Voice: Move Voice: Move
EntersTunnels:
RequireForceMoveCondition: !undeployed
Repairable:
RequireForceMoveCondition: !undeployed
Passenger:
RequireForceMoveCondition: !undeployed
GrantCondition@PREVIEWWORKAROUND: GrantCondition@PREVIEWWORKAROUND:
Condition: real-actor Condition: real-actor
WithVoxelBody: WithVoxelBody:
@@ -249,6 +255,12 @@ ART2:
DeploySounds: place2.aud DeploySounds: place2.aud
UndeploySounds: clicky1.aud UndeploySounds: clicky1.aud
Voice: Move Voice: Move
EntersTunnels:
RequireForceMoveCondition: !undeployed
Repairable:
RequireForceMoveCondition: !undeployed
Passenger:
RequireForceMoveCondition: !undeployed
GrantCondition@PREVIEWWORKAROUND: GrantCondition@PREVIEWWORKAROUND:
Condition: real-actor Condition: real-actor
WithVoxelBody: WithVoxelBody:

View File

@@ -43,13 +43,16 @@ GACNST:
RequiresCondition: factundeploy RequiresCondition: factundeploy
RepairActors: gadept RepairActors: gadept
Voice: Move Voice: Move
RequiresForceMove: true
TransformsIntoEntersTunnels: TransformsIntoEntersTunnels:
RequiresCondition: factundeploy RequiresCondition: factundeploy
Voice: Move Voice: Move
RequiresForceMove: true
TransformsIntoPassenger: TransformsIntoPassenger:
RequiresCondition: factundeploy RequiresCondition: factundeploy
CargoType: Vehicle CargoType: Vehicle
Voice: Move Voice: Move
RequiresForceMove: true
GrantConditionOnPrerequisite@GLOBALFACTUNDEPLOY: GrantConditionOnPrerequisite@GLOBALFACTUNDEPLOY:
Condition: factundeploy Condition: factundeploy
Prerequisites: global-factundeploy Prerequisites: global-factundeploy

View File

@@ -154,6 +154,12 @@ LPST:
DeploySounds: place2.aud DeploySounds: place2.aud
UndeploySounds: clicky1.aud UndeploySounds: clicky1.aud
Voice: Move Voice: Move
EntersTunnels:
RequireForceMoveCondition: !undeployed
Repairable:
RequireForceMoveCondition: !undeployed
Passenger:
RequireForceMoveCondition: !undeployed
WithVoxelBody: WithVoxelBody:
RequiresCondition: undeployed RequiresCondition: undeployed
WithSpriteBody@deployed: WithSpriteBody@deployed: