Merge pull request #9438 from atlimit8/UpgradableMobile

Upgradable Mobile and replace IDisableMove
This commit is contained in:
Matthias Mailänder
2015-12-05 18:24:40 +01:00
24 changed files with 300 additions and 98 deletions

View File

@@ -127,7 +127,6 @@ namespace OpenRA.Traits
public interface INotifyCapture { void OnCapture(Actor self, Actor captor, Player oldOwner, Player newOwner); } public interface INotifyCapture { void OnCapture(Actor self, Actor captor, Player oldOwner, Player newOwner); }
public interface INotifyInfiltrated { void Infiltrated(Actor self, Actor infiltrator); } public interface INotifyInfiltrated { void Infiltrated(Actor self, Actor infiltrator); }
public interface INotifyDiscovered { void OnDiscovered(Actor self, Player discoverer, bool playNotification); } public interface INotifyDiscovered { void OnDiscovered(Actor self, Player discoverer, bool playNotification); }
public interface IDisableMove { bool MoveDisabled(Actor self); }
public interface ISeedableResource { void Seed(Actor self); } public interface ISeedableResource { void Seed(Actor self); }

View File

@@ -19,7 +19,7 @@ namespace OpenRA.Mods.Common.Activities
{ {
readonly IPositionable positionable; readonly IPositionable positionable;
readonly IMove movement; readonly IMove movement;
readonly IDisableMove[] moveDisablers; readonly IDisabledTrait disableable;
WPos start, end; WPos start, end;
int length; int length;
int ticks = 0; int ticks = 0;
@@ -28,7 +28,7 @@ namespace OpenRA.Mods.Common.Activities
{ {
positionable = self.Trait<IPositionable>(); positionable = self.Trait<IPositionable>();
movement = self.TraitOrDefault<IMove>(); movement = self.TraitOrDefault<IMove>();
moveDisablers = self.TraitsImplementing<IDisableMove>().ToArray(); disableable = movement as IDisabledTrait;
this.start = start; this.start = start;
this.end = end; this.end = end;
this.length = length; this.length = length;
@@ -36,7 +36,7 @@ namespace OpenRA.Mods.Common.Activities
public override Activity Tick(Actor self) public override Activity Tick(Actor self)
{ {
if (moveDisablers.Any(d => d.MoveDisabled(self))) if (disableable != null && disableable.IsTraitDisabled)
return this; return this;
var pos = length > 1 var pos = length > 1

View File

@@ -25,7 +25,6 @@ namespace OpenRA.Mods.Common.Activities
static readonly List<CPos> NoPath = new List<CPos>(); static readonly List<CPos> NoPath = new List<CPos>();
readonly Mobile mobile; readonly Mobile mobile;
readonly IDisableMove[] moveDisablers;
readonly WDist nearEnough; readonly WDist nearEnough;
readonly Func<List<CPos>> getPath; readonly Func<List<CPos>> getPath;
readonly Actor ignoredActor; readonly Actor ignoredActor;
@@ -43,7 +42,6 @@ namespace OpenRA.Mods.Common.Activities
public Move(Actor self, CPos destination) public Move(Actor self, CPos destination)
{ {
mobile = self.Trait<Mobile>(); mobile = self.Trait<Mobile>();
moveDisablers = self.TraitsImplementing<IDisableMove>().ToArray();
getPath = () => getPath = () =>
{ {
@@ -65,7 +63,6 @@ namespace OpenRA.Mods.Common.Activities
public Move(Actor self, CPos destination, WDist nearEnough) public Move(Actor self, CPos destination, WDist nearEnough)
{ {
mobile = self.Trait<Mobile>(); mobile = self.Trait<Mobile>();
moveDisablers = self.TraitsImplementing<IDisableMove>().ToArray();
getPath = () => self.World.WorldActor.Trait<IPathFinder>() getPath = () => self.World.WorldActor.Trait<IPathFinder>()
.FindUnitPath(mobile.ToCell, destination, self); .FindUnitPath(mobile.ToCell, destination, self);
@@ -76,7 +73,6 @@ namespace OpenRA.Mods.Common.Activities
public Move(Actor self, CPos destination, SubCell subCell, WDist nearEnough) public Move(Actor self, CPos destination, SubCell subCell, WDist nearEnough)
{ {
mobile = self.Trait<Mobile>(); mobile = self.Trait<Mobile>();
moveDisablers = self.TraitsImplementing<IDisableMove>().ToArray();
getPath = () => self.World.WorldActor.Trait<IPathFinder>() getPath = () => self.World.WorldActor.Trait<IPathFinder>()
.FindUnitPathToRange(mobile.FromCell, subCell, self.World.Map.CenterOfSubCell(destination, subCell), nearEnough, self); .FindUnitPathToRange(mobile.FromCell, subCell, self.World.Map.CenterOfSubCell(destination, subCell), nearEnough, self);
@@ -87,7 +83,6 @@ namespace OpenRA.Mods.Common.Activities
public Move(Actor self, CPos destination, Actor ignoredActor) public Move(Actor self, CPos destination, Actor ignoredActor)
{ {
mobile = self.Trait<Mobile>(); mobile = self.Trait<Mobile>();
moveDisablers = self.TraitsImplementing<IDisableMove>().ToArray();
getPath = () => getPath = () =>
{ {
@@ -107,7 +102,6 @@ namespace OpenRA.Mods.Common.Activities
public Move(Actor self, Target target, WDist range) public Move(Actor self, Target target, WDist range)
{ {
mobile = self.Trait<Mobile>(); mobile = self.Trait<Mobile>();
moveDisablers = self.TraitsImplementing<IDisableMove>().ToArray();
getPath = () => getPath = () =>
{ {
@@ -125,7 +119,6 @@ namespace OpenRA.Mods.Common.Activities
public Move(Actor self, Func<List<CPos>> getPath) public Move(Actor self, Func<List<CPos>> getPath)
{ {
mobile = self.Trait<Mobile>(); mobile = self.Trait<Mobile>();
moveDisablers = self.TraitsImplementing<IDisableMove>().ToArray();
this.getPath = getPath; this.getPath = getPath;
@@ -155,7 +148,7 @@ namespace OpenRA.Mods.Common.Activities
if (IsCanceled) if (IsCanceled)
return NextActivity; return NextActivity;
if (moveDisablers.Any(d => d.MoveDisabled(self))) if (mobile.IsTraitDisabled)
return this; return this;
if (destination == mobile.ToCell) if (destination == mobile.ToCell)

View File

@@ -11,18 +11,19 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using OpenRA.Activities; using OpenRA.Activities;
using OpenRA.Mods.Common.Traits;
using OpenRA.Traits; using OpenRA.Traits;
namespace OpenRA.Mods.Common.Activities namespace OpenRA.Mods.Common.Activities
{ {
public class Turn : Activity public class Turn : Activity
{ {
readonly IDisableMove[] moveDisablers; readonly IDisabledTrait disablable;
readonly int desiredFacing; readonly int desiredFacing;
public Turn(Actor self, int desiredFacing) public Turn(Actor self, int desiredFacing)
{ {
moveDisablers = self.TraitsImplementing<IDisableMove>().ToArray(); disablable = self.TraitOrDefault<IMove>() as IDisabledTrait;
this.desiredFacing = desiredFacing; this.desiredFacing = desiredFacing;
} }
@@ -30,7 +31,7 @@ namespace OpenRA.Mods.Common.Activities
{ {
if (IsCanceled) if (IsCanceled)
return NextActivity; return NextActivity;
if (moveDisablers.Any(d => d.MoveDisabled(self))) if (disablable != null && disablable.IsTraitDisabled)
return this; return this;
var facing = self.Trait<IFacing>(); var facing = self.Trait<IFacing>();

View File

@@ -484,7 +484,6 @@
<Compile Include="Traits\ProducibleWithLevel.cs" /> <Compile Include="Traits\ProducibleWithLevel.cs" />
<Compile Include="Traits\Upgrades\DeployToUpgrade.cs" /> <Compile Include="Traits\Upgrades\DeployToUpgrade.cs" />
<Compile Include="Traits\Upgrades\DisableOnUpgrade.cs" /> <Compile Include="Traits\Upgrades\DisableOnUpgrade.cs" />
<Compile Include="Traits\Upgrades\DisableMovementOnUpgrade.cs" />
<Compile Include="Traits\Upgrades\UpgradableTrait.cs" /> <Compile Include="Traits\Upgrades\UpgradableTrait.cs" />
<Compile Include="Traits\Upgrades\UpgradeActorsNear.cs" /> <Compile Include="Traits\Upgrades\UpgradeActorsNear.cs" />
<Compile Include="Traits\Upgrades\UpgradeManager.cs" /> <Compile Include="Traits\Upgrades\UpgradeManager.cs" />

View File

@@ -61,5 +61,8 @@ namespace OpenRA.Mods.Common.Scripting
{ {
Self.QueueActivity(new EnterTransport(Self, transport, 1, true)); Self.QueueActivity(new EnterTransport(Self, transport, 1, true));
} }
[Desc("Whether the actor can move (false if immobilized).")]
public bool IsMobile { get { return !mobile.IsTraitDisabled; } }
} }
} }

View File

@@ -19,7 +19,7 @@ using OpenRA.Traits;
namespace OpenRA.Mods.Common.Traits namespace OpenRA.Mods.Common.Traits
{ {
[Desc("This actor can transport Passenger actors.")] [Desc("This actor can transport Passenger actors.")]
public class CargoInfo : ITraitInfo, Requires<IOccupySpaceInfo> public class CargoInfo : ITraitInfo, Requires<IOccupySpaceInfo>, Requires<UpgradeManagerInfo>
{ {
[Desc("The maximum sum of Passenger.Weight that this actor can support.")] [Desc("The maximum sum of Passenger.Weight that this actor can support.")]
public readonly int MaxWeight = 0; public readonly int MaxWeight = 0;
@@ -51,14 +51,19 @@ namespace OpenRA.Mods.Common.Traits
[Desc("Cursor to display when unable to unload the passengers.")] [Desc("Cursor to display when unable to unload the passengers.")]
public readonly string UnloadBlockedCursor = "deploy-blocked"; public readonly string UnloadBlockedCursor = "deploy-blocked";
[UpgradeGrantedReference]
[Desc("The upgrades to grant to self while loading cargo.")]
public readonly string[] LoadingUpgrades = { };
public object Create(ActorInitializer init) { return new Cargo(init, this); } public object Create(ActorInitializer init) { return new Cargo(init, this); }
} }
public class Cargo : IPips, IIssueOrder, IResolveOrder, IOrderVoice, INotifyCreated, INotifyKilled, public class Cargo : IPips, IIssueOrder, IResolveOrder, IOrderVoice, INotifyCreated, INotifyKilled,
INotifyOwnerChanged, INotifyAddedToWorld, ITick, INotifySold, IDisableMove, INotifyActorDisposing INotifyOwnerChanged, INotifyAddedToWorld, ITick, INotifySold, INotifyActorDisposing
{ {
public readonly CargoInfo Info; public readonly CargoInfo Info;
readonly Actor self; readonly Actor self;
readonly UpgradeManager upgradeManager;
readonly Stack<Actor> cargo = new Stack<Actor>(); readonly Stack<Actor> cargo = new Stack<Actor>();
readonly HashSet<Actor> reserves = new HashSet<Actor>(); readonly HashSet<Actor> reserves = new HashSet<Actor>();
readonly Lazy<IFacing> facing; readonly Lazy<IFacing> facing;
@@ -80,6 +85,7 @@ namespace OpenRA.Mods.Common.Traits
Info = info; Info = info;
Unloading = false; Unloading = false;
checkTerrainType = info.UnloadTerrainTypes.Count > 0; checkTerrainType = info.UnloadTerrainTypes.Count > 0;
upgradeManager = self.Trait<UpgradeManager>();
if (init.Contains<RuntimeCargoInit>()) if (init.Contains<RuntimeCargoInit>())
{ {
@@ -183,6 +189,10 @@ namespace OpenRA.Mods.Common.Traits
if (!HasSpace(w)) if (!HasSpace(w))
return false; return false;
if (reserves.Count == 0)
foreach (var u in Info.LoadingUpgrades)
upgradeManager.GrantUpgrade(self, u, this);
reserves.Add(a); reserves.Add(a);
reservedWeight += w; reservedWeight += w;
@@ -196,6 +206,10 @@ namespace OpenRA.Mods.Common.Traits
reservedWeight -= GetWeight(a); reservedWeight -= GetWeight(a);
reserves.Remove(a); reserves.Remove(a);
if (reserves.Count == 0)
foreach (var u in Info.LoadingUpgrades)
upgradeManager.RevokeUpgrade(self, u, this);
} }
public string CursorForOrder(Actor self, Order order) public string CursorForOrder(Actor self, Order order)
@@ -214,7 +228,6 @@ namespace OpenRA.Mods.Common.Traits
return Info.UnloadVoice; return Info.UnloadVoice;
} }
public bool MoveDisabled(Actor self) { return reserves.Any(); }
public bool HasSpace(int weight) { return totalWeight + reservedWeight + 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; }
@@ -235,7 +248,7 @@ namespace OpenRA.Mods.Common.Traits
p.Transport = null; p.Transport = null;
foreach (var u in p.Info.GrantUpgrades) foreach (var u in p.Info.GrantUpgrades)
self.Trait<UpgradeManager>().RevokeUpgrade(self, u, p); upgradeManager.RevokeUpgrade(self, u, p);
return a; return a;
} }
@@ -287,6 +300,10 @@ namespace OpenRA.Mods.Common.Traits
{ {
reservedWeight -= w; reservedWeight -= w;
reserves.Remove(a); reserves.Remove(a);
if (reserves.Count == 0)
foreach (var u in Info.LoadingUpgrades)
upgradeManager.RevokeUpgrade(self, u, this);
} }
foreach (var npe in self.TraitsImplementing<INotifyPassengerEntered>()) foreach (var npe in self.TraitsImplementing<INotifyPassengerEntered>())
@@ -295,7 +312,7 @@ namespace OpenRA.Mods.Common.Traits
var p = a.Trait<Passenger>(); var p = a.Trait<Passenger>();
p.Transport = self; p.Transport = self;
foreach (var u in p.Info.GrantUpgrades) foreach (var u in p.Info.GrantUpgrades)
self.Trait<UpgradeManager>().GrantUpgrade(self, u, p); upgradeManager.GrantUpgrade(self, u, p);
} }
public void Killed(Actor self, AttackInfo e) public void Killed(Actor self, AttackInfo e)

View File

@@ -38,7 +38,7 @@ namespace OpenRA.Mods.Common.Traits
} }
[Desc("Unit is able to move.")] [Desc("Unit is able to move.")]
public class MobileInfo : IMoveInfo, IPositionableInfo, IOccupySpaceInfo, IFacingInfo, public class MobileInfo : UpgradableTraitInfo, IMoveInfo, IPositionableInfo, IOccupySpaceInfo, IFacingInfo,
UsesInit<FacingInit>, UsesInit<LocationInit>, UsesInit<SubCellInit> UsesInit<FacingInit>, UsesInit<LocationInit>, UsesInit<SubCellInit>
{ {
[FieldLoader.LoadUsing("LoadSpeeds", true)] [FieldLoader.LoadUsing("LoadSpeeds", true)]
@@ -72,7 +72,7 @@ namespace OpenRA.Mods.Common.Traits
[VoiceReference] public readonly string Voice = "Action"; [VoiceReference] public readonly string Voice = "Action";
public virtual object Create(ActorInitializer init) { return new Mobile(init, this); } public override object Create(ActorInitializer init) { return new Mobile(init, this); }
static object LoadSpeeds(MiniYaml y) static object LoadSpeeds(MiniYaml y)
{ {
@@ -304,8 +304,8 @@ namespace OpenRA.Mods.Common.Traits
bool IOccupySpaceInfo.SharesCell { get { return SharesCell; } } bool IOccupySpaceInfo.SharesCell { get { return SharesCell; } }
} }
public class Mobile : IIssueOrder, IResolveOrder, IOrderVoice, IPositionable, IMove, IFacing, ISync, IDeathActorInitModifier, public class Mobile : UpgradableTrait<MobileInfo>, IIssueOrder, IResolveOrder, IOrderVoice, IPositionable, IMove, IFacing, ISync,
INotifyAddedToWorld, INotifyRemovedFromWorld, INotifyBlockingMove IDeathActorInitModifier, INotifyAddedToWorld, INotifyRemovedFromWorld, INotifyBlockingMove
{ {
const int AverageTicksBeforePathing = 5; const int AverageTicksBeforePathing = 5;
const int SpreadTicksBeforePathing = 5; const int SpreadTicksBeforePathing = 5;
@@ -313,7 +313,6 @@ namespace OpenRA.Mods.Common.Traits
readonly Actor self; readonly Actor self;
readonly Lazy<IEnumerable<int>> speedModifiers; readonly Lazy<IEnumerable<int>> speedModifiers;
public readonly MobileInfo Info;
public bool IsMoving { get; set; } public bool IsMoving { get; set; }
int facing; int facing;
@@ -349,9 +348,9 @@ namespace OpenRA.Mods.Common.Traits
} }
public Mobile(ActorInitializer init, MobileInfo info) public Mobile(ActorInitializer init, MobileInfo info)
: base(info)
{ {
self = init.Self; self = init.Self;
Info = info;
speedModifiers = Exts.Lazy(() => self.TraitsImplementing<ISpeedModifier>().ToArray().Select(x => x.GetSpeedModifier())); speedModifiers = Exts.Lazy(() => self.TraitsImplementing<ISpeedModifier>().ToArray().Select(x => x.GetSpeedModifier()));
@@ -438,7 +437,7 @@ namespace OpenRA.Mods.Common.Traits
self.World.ScreenMap.Remove(self); self.World.ScreenMap.Remove(self);
} }
public IEnumerable<IOrderTargeter> Orders { get { yield return new MoveOrderTargeter(self, Info); } } public IEnumerable<IOrderTargeter> Orders { get { yield return new MoveOrderTargeter(self, this); } }
// Note: Returns a valid order even if the unit can't move to the target // Note: Returns a valid order even if the unit can't move to the target
public Order IssueOrder(Actor self, IOrderTargeter order, Target target, bool queued) public Order IssueOrder(Actor self, IOrderTargeter order, Target target, bool queued)
@@ -629,6 +628,9 @@ namespace OpenRA.Mods.Common.Traits
public void Nudge(Actor self, Actor nudger, bool force) public void Nudge(Actor self, Actor nudger, bool force)
{ {
if (IsTraitDisabled)
return;
/* initial fairly braindead implementation. */ /* initial fairly braindead implementation. */
if (!force && self.Owner.Stances[nudger.Owner] != Stance.Ally) if (!force && self.Owner.Stances[nudger.Owner] != Stance.Ally)
return; /* don't allow ourselves to be pushed around return; /* don't allow ourselves to be pushed around
@@ -691,16 +693,14 @@ namespace OpenRA.Mods.Common.Traits
class MoveOrderTargeter : IOrderTargeter class MoveOrderTargeter : IOrderTargeter
{ {
readonly MobileInfo unitType; readonly Mobile mobile;
readonly bool rejectMove; readonly bool rejectMove;
readonly IDisableMove[] moveDisablers;
public bool OverrideSelection { get { return false; } } public bool OverrideSelection { get { return false; } }
public MoveOrderTargeter(Actor self, MobileInfo unitType) public MoveOrderTargeter(Actor self, Mobile unit)
{ {
this.unitType = unitType; this.mobile = unit;
rejectMove = !self.AcceptsOrder("Move"); rejectMove = !self.AcceptsOrder("Move");
moveDisablers = self.TraitsImplementing<IDisableMove>().ToArray();
} }
public string OrderID { get { return "Move"; } } public string OrderID { get { return "Move"; } }
@@ -717,12 +717,12 @@ namespace OpenRA.Mods.Common.Traits
var explored = self.Owner.Shroud.IsExplored(location); var explored = self.Owner.Shroud.IsExplored(location);
cursor = self.World.Map.Contains(location) ? cursor = self.World.Map.Contains(location) ?
(self.World.Map.GetTerrainInfo(location).CustomCursor ?? unitType.Cursor) : unitType.BlockedCursor; (self.World.Map.GetTerrainInfo(location).CustomCursor ?? mobile.Info.Cursor) : mobile.Info.BlockedCursor;
if ((!explored && !unitType.MoveIntoShroud) if (mobile.IsTraitDisabled
|| (explored && unitType.MovementCostForCell(self.World, location) == int.MaxValue) || (!explored && !mobile.Info.MoveIntoShroud)
|| moveDisablers.Any(d => d.MoveDisabled(self))) || (explored && mobile.Info.MovementCostForCell(self.World, location) == int.MaxValue))
cursor = unitType.BlockedCursor; cursor = mobile.Info.BlockedCursor;
return true; return true;
} }

View File

@@ -1,28 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007-2015 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. For more information,
* see COPYING.
*/
#endregion
using OpenRA.Traits;
namespace OpenRA.Mods.Common.Traits
{
[Desc("Disable the ability to move and turn of the actor when this trait is enabled by an upgrade.")]
public class DisableMovementInfo : UpgradableTraitInfo
{
public override object Create(ActorInitializer init) { return new DisableMovementOnUpgrade(this); }
}
public class DisableMovementOnUpgrade : UpgradableTrait<DisableMovementInfo>, IDisableMove
{
public DisableMovementOnUpgrade(DisableMovementInfo info)
: base(info) { }
public bool MoveDisabled(Actor self) { return !IsTraitDisabled; }
}
}

View File

@@ -18,12 +18,11 @@ namespace OpenRA.Mods.Common.Traits
public override object Create(ActorInitializer init) { return new DisableOnUpgrade(this); } public override object Create(ActorInitializer init) { return new DisableOnUpgrade(this); }
} }
public class DisableOnUpgrade : UpgradableTrait<DisableOnUpgradeInfo>, IDisable, IDisableMove public class DisableOnUpgrade : UpgradableTrait<DisableOnUpgradeInfo>, IDisable
{ {
public DisableOnUpgrade(DisableOnUpgradeInfo info) public DisableOnUpgrade(DisableOnUpgradeInfo info)
: base(info) { } : base(info) { }
public bool Disabled { get { return !IsTraitDisabled; } } public bool Disabled { get { return !IsTraitDisabled; } }
public bool MoveDisabled(Actor self) { return !IsTraitDisabled; }
} }
} }

View File

@@ -2510,6 +2510,179 @@ namespace OpenRA.Mods.Common.UtilityCommands
} }
} }
// Mobile actors immobilized by Carryable, Cargo, DeployToUpgrade, and/or others using upgrade(s)
if (engineVersion < 20151204 && depth == 0)
{
var notMobile = "notmobile";
var mobileNode = node.Value.Nodes.Find(n => n.Key == "Mobile");
var carryableNode = node.Value.Nodes.Find(n => n.Key == "Carryable");
var cargoNode = node.Value.Nodes.Find(n => n.Key == "Cargo");
var deployToUpgradeNode = node.Value.Nodes.Find(n => n.Key == "DeployToUpgrade");
var disableUpgradeNode = node.Value.Nodes.Find(n => n.Key == "DisableUpgrade");
var disableMovementOnUpgradeNode = node.Value.Nodes.Find(n => n.Key == "DisableMovementOnUpgrade");
Action<MiniYamlNode, string> addNotMobileToTraitUpgrades = (trait, upgradesKey) =>
{
if (trait != null)
{
var upgrades = trait.Value.Nodes.Find(u => u.Key == upgradesKey);
if (upgrades == null)
trait.Value.Nodes.Add(new MiniYamlNode(upgradesKey, notMobile));
else if (string.IsNullOrEmpty(upgrades.Value.Value))
upgrades.Value.Value = notMobile;
else if (!upgrades.Value.Value.Contains(notMobile))
upgrades.Value.Value += ", " + notMobile;
}
};
if (mobileNode != null)
{
var mobileUpgrades = mobileNode.Value.Nodes.Find(n => n.Key == "UpgradeTypes");
var mobileUpgradeMaxEnabledLevel = mobileNode.Value.Nodes.Find(n => n.Key == "UpgradeMaxEnabledLevel");
var comma = new char[] { ',' };
Func<bool> addUpgradeMaxEnabledLevelNode = () =>
{
if (mobileUpgradeMaxEnabledLevel == null)
{
mobileUpgradeMaxEnabledLevel = new MiniYamlNode("UpgradeMaxEnabledLevel", "0");
mobileNode.Value.Nodes.Add(mobileUpgradeMaxEnabledLevel);
return true;
}
else
return mobileUpgradeMaxEnabledLevel.Value.Value == "0";
};
// If exactly one upgrade type is in UpgradeTypes and UpgradeMaxEnabledLevel is/can be 0 , then use it as notmobile
if (mobileUpgrades != null && !string.IsNullOrEmpty(mobileUpgrades.Value.Value)
&& !mobileUpgrades.Value.Value.Contains(",") && addUpgradeMaxEnabledLevelNode())
notMobile = mobileUpgrades.Value.Value;
if (mobileUpgradeMaxEnabledLevel != null && mobileUpgradeMaxEnabledLevel.Value.Value != "0")
Console.WriteLine("\t\t" + node.Key + " actor rules may require manual upgrading for immobilization upgrade logic.");
else
{
Action<string> addImmobilizeUpgradeType = upgradeType =>
{
if (mobileUpgrades == null)
{
mobileUpgrades = new MiniYamlNode("UpgradeTypes", upgradeType);
mobileNode.Value.Nodes.Add(mobileUpgrades);
}
else if (string.IsNullOrEmpty(mobileUpgrades.Value.Value))
mobileUpgrades.Value.Value = upgradeType;
else if (!mobileUpgrades.Value.Value.Split(comma).Contains(upgradeType))
mobileUpgrades.Value.Value += ", " + upgradeType;
};
Predicate<string> addImmobilizeUpgradeTypes = upgradeTypes =>
{
if (string.IsNullOrEmpty(upgradeTypes))
return false;
foreach (var upgradeType in upgradeTypes.Split(comma))
addImmobilizeUpgradeType(upgradeType);
return true;
};
Predicate<MiniYamlNode> addUpgradeTypeFromTrait = trait =>
{
var upgradeTypesNode = trait.Value.Nodes.Find(n => n.Key == "UpgradeTypes");
if (upgradeTypesNode == null)
return false;
addUpgradeMaxEnabledLevelNode();
return addImmobilizeUpgradeTypes(upgradeTypesNode.Value.Value);
};
var noticeWritten = false;
Action writeNotice = () =>
{
if (noticeWritten)
return;
Console.WriteLine("\t\t" + node.Key + " actor rules may require manual upgrading for immobilization upgrade logic.");
noticeWritten = true;
};
if (disableUpgradeNode != null && !addUpgradeTypeFromTrait(disableUpgradeNode))
{
writeNotice();
Console.WriteLine("\t\t\tOne or more upgrades may need to be copied from the DisableUpgrade trait to the Mobile trait.");
}
if (disableMovementOnUpgradeNode != null)
{
if (addUpgradeTypeFromTrait(disableMovementOnUpgradeNode))
parent.Value.Nodes.Remove(disableMovementOnUpgradeNode);
else
{
writeNotice();
Console.WriteLine("\t\t\tOne or more upgrades may need to be moved from the DisableMovementOnUpgrade trait to the Mobile trait.");
Console.WriteLine("\t\t\t\tRemember to remove the DisableMovementOnUpgrade trait.");
}
}
if (carryableNode != null || cargoNode != null || deployToUpgradeNode != null)
{
addUpgradeMaxEnabledLevelNode();
addImmobilizeUpgradeTypes(notMobile);
addNotMobileToTraitUpgrades(carryableNode, "CarryableUpgrades");
addNotMobileToTraitUpgrades(cargoNode, "LoadingUpgrades");
addNotMobileToTraitUpgrades(deployToUpgradeNode, "DeployedUpgrades");
}
}
}
else if (!node.Value.Nodes.Exists(n => n.Key == "Husk" || n.Key == "Building" || n.Key == "Aircraft" || n.Key == "Immobile"))
{
if (carryableNode != null || cargoNode != null || deployToUpgradeNode != null)
{
Console.WriteLine("\t\tIf " + node.Key
+ " has a Mobile trait then adding the following with <upgrade> substituted by an immobilization upgrade for "
+ node.Key + " may be neeeded:");
if (carryableNode != null)
{
Console.WriteLine("\t\t\tCarryable:");
Console.WriteLine("\t\t\t\tCarryableUpgrades: <upgrade>");
}
if (cargoNode != null)
{
Console.WriteLine("\t\t\tCargo:");
Console.WriteLine("\t\t\t\tLoadingUpgrades: <upgrade>");
}
if (deployToUpgradeNode != null)
{
Console.WriteLine("\t\t\tDeployToUpgrade:");
Console.WriteLine("\t\t\t\tDeployedUpgrades: <upgrade>");
}
}
var disableUpgradeUpgradeTypesNode = disableUpgradeNode != null
? disableUpgradeNode.Value.Nodes.Find(n => n.Key == "UpgradeTypes")
: null;
var disableMovementOnUpgradeUpgradeTypesNode = disableMovementOnUpgradeNode != null
? disableMovementOnUpgradeNode.Value.Nodes.Find(n => n.Key == "UpgradeTypes")
: null;
if (disableUpgradeUpgradeTypesNode != null || disableMovementOnUpgradeUpgradeTypesNode != null)
Console.WriteLine("\t\t" + node.Key + " actor rules may require manual upgrading for immobilization upgrade logic.");
if (disableUpgradeUpgradeTypesNode != null)
Console.WriteLine("\t\t\tDisableUpgrade UpgradeTypes: " + disableUpgradeUpgradeTypesNode.Value.Value);
if (disableMovementOnUpgradeUpgradeTypesNode != null)
Console.WriteLine("\t\t\tDisableMovementOnUpgrade UpgradeTypes: " + disableMovementOnUpgradeUpgradeTypesNode.Value.Value);
if (disableMovementOnUpgradeNode != null)
node.Value.Nodes.Remove(disableMovementOnUpgradeNode);
}
}
UpgradeActorRules(engineVersion, ref node.Value.Nodes, node, depth + 1); UpgradeActorRules(engineVersion, ref node.Value.Nodes, node, depth + 1);
} }
} }

View File

@@ -17,24 +17,49 @@ using OpenRA.Traits;
namespace OpenRA.Mods.D2k.Traits namespace OpenRA.Mods.D2k.Traits
{ {
[Desc("Can be carried by units with the trait `Carryall`.")] [Desc("Can be carried by units with the trait `Carryall`.")]
public class CarryableInfo : ITraitInfo public class CarryableInfo : ITraitInfo, Requires<UpgradeManagerInfo>
{ {
[Desc("Required distance away from destination before requesting a pickup. Default is 6 cells.")] [Desc("Required distance away from destination before requesting a pickup. Default is 6 cells.")]
public WDist MinDistance = WDist.FromCells(6); public readonly WDist MinDistance = WDist.FromCells(6);
[UpgradeGrantedReference]
[Desc("The upgrades to grant to self while waiting or being carried.")]
public readonly string[] CarryableUpgrades = { };
public object Create(ActorInitializer init) { return new Carryable(init.Self, this); } public object Create(ActorInitializer init) { return new Carryable(init.Self, this); }
} }
public class Carryable : IDisableMove, INotifyHarvesterAction, ICallForTransport public class Carryable : INotifyHarvesterAction, ICallForTransport
{ {
readonly CarryableInfo info; readonly CarryableInfo info;
readonly Actor self; readonly Actor self;
readonly UpgradeManager upgradeManager;
public bool Reserved { get; private set; } public bool Reserved { get; private set; }
// If we're locked there isn't much we can do. We'll have to wait for the carrier to finish with us. We should not move or get new orders! // If we're locked there isn't much we can do. We'll have to wait for the carrier to finish with us. We should not move or get new orders!
bool locked; bool locked;
void Unlock()
{
if (!locked)
return;
locked = false;
foreach (var u in info.CarryableUpgrades)
upgradeManager.RevokeUpgrade(self, u, this);
}
void Lock()
{
if (locked)
return;
locked = true;
foreach (var u in info.CarryableUpgrades)
upgradeManager.GrantUpgrade(self, u, this);
}
public bool WantsTransport { get; set; } public bool WantsTransport { get; set; }
public CPos Destination; public CPos Destination;
Activity afterLandActivity; Activity afterLandActivity;
@@ -43,6 +68,7 @@ namespace OpenRA.Mods.D2k.Traits
{ {
this.info = info; this.info = info;
this.self = self; this.self = self;
upgradeManager = self.Trait<UpgradeManager>();
locked = false; locked = false;
Reserved = false; Reserved = false;
@@ -110,7 +136,7 @@ namespace OpenRA.Mods.D2k.Traits
public void Dropped() public void Dropped()
{ {
WantsTransport = false; WantsTransport = false;
locked = false; Unlock();
if (afterLandActivity != null) if (afterLandActivity != null)
{ {
@@ -144,7 +170,7 @@ namespace OpenRA.Mods.D2k.Traits
public void UnReserve(Actor carrier) public void UnReserve(Actor carrier)
{ {
Reserved = false; Reserved = false;
locked = false; Unlock();
} }
// Prepare for transport pickup // Prepare for transport pickup
@@ -166,16 +192,9 @@ namespace OpenRA.Mods.D2k.Traits
// Cancel our activities // Cancel our activities
self.CancelActivity(); self.CancelActivity();
locked = true; Lock();
return true; return true;
} }
// IMoveDisabled
public bool MoveDisabled(Actor self)
{
// We do not want to move while being locked. The carrier will try to pick us up.
return locked;
}
} }
} }

View File

@@ -47,6 +47,8 @@ LST:
BuildPaletteOrder: 1000 BuildPaletteOrder: 1000
Prerequisites: ~disabled Prerequisites: ~disabled
Mobile: Mobile:
UpgradeTypes: notmobile
UpgradeMaxEnabledLevel: 0
Crushes: crate Crushes: crate
TerrainSpeeds: TerrainSpeeds:
Clear: 100 Clear: 100
@@ -76,4 +78,5 @@ LST:
MaxWeight: 5 MaxWeight: 5
PipCount: 5 PipCount: 5
PassengerFacing: 0 PassengerFacing: 0
LoadingUpgrades: notmobile

View File

@@ -89,6 +89,8 @@ APC:
Prerequisites: pyle Prerequisites: pyle
Queue: Vehicle.GDI Queue: Vehicle.GDI
Mobile: Mobile:
UpgradeTypes: notmobile
UpgradeMaxEnabledLevel: 0
ROT: 8 ROT: 8
Speed: 128 Speed: 128
Health: Health:
@@ -120,6 +122,7 @@ APC:
Types: Infantry Types: Infantry
MaxWeight: 5 MaxWeight: 5
PipCount: 5 PipCount: 5
LoadingUpgrades: notmobile
SpawnActorOnDeath: SpawnActorOnDeath:
Actor: APC.Husk Actor: APC.Husk

View File

@@ -58,6 +58,8 @@
Inherits@2: ^GainsExperience Inherits@2: ^GainsExperience
Inherits@3: ^SpriteActor Inherits@3: ^SpriteActor
Mobile: Mobile:
UpgradeTypes: notmobile
UpgradeMaxEnabledLevel: 0
Crushes: crate, spicebloom Crushes: crate, spicebloom
TerrainSpeeds: TerrainSpeeds:
Sand: 100 Sand: 100
@@ -92,6 +94,7 @@
Voiced: Voiced:
VoiceSet: VehicleVoice VoiceSet: VehicleVoice
Carryable: Carryable:
CarryableUpgrades: notmobile
WithDecorationCarryable: WithDecorationCarryable:
Image: pips Image: pips
Sequence: pickup-indicator Sequence: pickup-indicator

View File

@@ -93,6 +93,8 @@ thumper:
RevealsShroud: RevealsShroud:
Range: 2c768 Range: 2c768
Mobile: Mobile:
UpgradeTypes: deployed
UpgradeMaxEnabledLevel: 0
Speed: 43 Speed: 43
DeployToUpgrade: DeployToUpgrade:
DeployedUpgrades: deployed DeployedUpgrades: deployed
@@ -119,9 +121,6 @@ thumper:
Falloff: 0, 0, 0, 100, 100, 100, 25, 11, 6, 4, 3, 2, 1, 0 Falloff: 0, 0, 0, 100, 100, 100, 25, 11, 6, 4, 3, 2, 1, 0
UpgradeTypes: deployed UpgradeTypes: deployed
UpgradeMinEnabledLevel: 1 UpgradeMinEnabledLevel: 1
DisableOnUpgrade:
UpgradeTypes: deployed
UpgradeMinEnabledLevel: 1
Passenger: Passenger:
PipType: Blue PipType: Blue
Voiced: Voiced:

View File

@@ -226,6 +226,8 @@ LST:
Armor: Armor:
Type: Heavy Type: Heavy
Mobile: Mobile:
UpgradeTypes: notmobile
UpgradeMaxEnabledLevel: 0
ROT: 10 ROT: 10
Speed: 113 Speed: 113
RevealsShroud: RevealsShroud:
@@ -239,6 +241,7 @@ LST:
MaxWeight: 5 MaxWeight: 5
PipCount: 5 PipCount: 5
PassengerFacing: 0 PassengerFacing: 0
LoadingUpgrades: notmobile
-Chronoshiftable: -Chronoshiftable:
PT: PT:

View File

@@ -334,6 +334,8 @@ JEEP:
Mobile: Mobile:
ROT: 10 ROT: 10
Speed: 170 Speed: 170
UpgradeTypes: notmobile
UpgradeMaxEnabledLevel: 0
RevealsShroud: RevealsShroud:
Range: 8c0 Range: 8c0
Turreted: Turreted:
@@ -350,6 +352,7 @@ JEEP:
Types: Infantry Types: Infantry
MaxWeight: 1 MaxWeight: 1
PipCount: 1 PipCount: 1
LoadingUpgrades: notmobile
ProducibleWithLevel: ProducibleWithLevel:
Prerequisites: vehicles.upgraded Prerequisites: vehicles.upgraded
@@ -371,6 +374,8 @@ APC:
Mobile: Mobile:
Speed: 142 Speed: 142
Crushes: wall, mine, crate, infantry Crushes: wall, mine, crate, infantry
UpgradeTypes: notmobile
UpgradeMaxEnabledLevel: 0
RevealsShroud: RevealsShroud:
Range: 5c0 Range: 5c0
Armament: Armament:
@@ -384,6 +389,7 @@ APC:
Types: Infantry Types: Infantry
MaxWeight: 5 MaxWeight: 5
PipCount: 5 PipCount: 5
LoadingUpgrades: notmobile
ProducibleWithLevel: ProducibleWithLevel:
Prerequisites: vehicles.upgraded Prerequisites: vehicles.upgraded
@@ -727,6 +733,8 @@ STNK:
Mobile: Mobile:
Speed: 142 Speed: 142
Crushes: wall, mine, crate, infantry Crushes: wall, mine, crate, infantry
UpgradeTypes: notmobile
UpgradeMaxEnabledLevel: 0
RevealsShroud: RevealsShroud:
Range: 7c0 Range: 7c0
AutoTarget: AutoTarget:
@@ -743,6 +751,7 @@ STNK:
Types: Infantry Types: Infantry
MaxWeight: 4 MaxWeight: 4
PipCount: 4 PipCount: 4
LoadingUpgrades: notmobile
Cloak: Cloak:
InitialDelay: 125 InitialDelay: 125
CloakDelay: 250 CloakDelay: 250

View File

@@ -98,6 +98,7 @@ BUS:
MaxWeight: 20 MaxWeight: 20
PipCount: 5 PipCount: 5
UnloadVoice: Unload UnloadVoice: Unload
LoadingUpgrades: notmobile
PICK: PICK:
Inherits: ^CivilianVoxelVehicle Inherits: ^CivilianVoxelVehicle
@@ -119,6 +120,7 @@ PICK:
MaxWeight: 2 MaxWeight: 2
PipCount: 5 PipCount: 5
UnloadVoice: Unload UnloadVoice: Unload
LoadingUpgrades: notmobile
CAR: CAR:
Inherits: ^CivilianVoxelVehicle Inherits: ^CivilianVoxelVehicle
@@ -140,6 +142,7 @@ CAR:
MaxWeight: 4 MaxWeight: 4
PipCount: 5 PipCount: 5
UnloadVoice: Unload UnloadVoice: Unload
LoadingUpgrades: notmobile
WINI: WINI:
Inherits: ^CivilianVoxelVehicle Inherits: ^CivilianVoxelVehicle
@@ -161,6 +164,7 @@ WINI:
MaxWeight: 5 MaxWeight: 5
PipCount: 5 PipCount: 5
UnloadVoice: Unload UnloadVoice: Unload
LoadingUpgrades: notmobile
LOCOMOTIVE: LOCOMOTIVE:
Inherits: ^Train Inherits: ^Train
@@ -169,10 +173,8 @@ LOCOMOTIVE:
Tooltip: Tooltip:
Name: Train Locomotive Name: Train Locomotive
Cargo: Cargo:
Types: Infantry
MaxWeight: 2 MaxWeight: 2
PipCount: 2 PipCount: 2
UnloadVoice: Unload
TRAINCAR: TRAINCAR:
Inherits: ^Train Inherits: ^Train
@@ -181,10 +183,8 @@ TRAINCAR:
Tooltip: Tooltip:
Name: Passenger Car Name: Passenger Car
Cargo: Cargo:
Types: Infantry
MaxWeight: 10 MaxWeight: 10
PipCount: 5 PipCount: 5
UnloadVoice: Unload
CARGOCAR: CARGOCAR:
Inherits: ^Train Inherits: ^Train
@@ -193,8 +193,6 @@ CARGOCAR:
Tooltip: Tooltip:
Name: Cargo Car Name: Cargo Car
Cargo: Cargo:
Types: Infantry
MaxWeight: 10 MaxWeight: 10
PipCount: 5 PipCount: 5
UnloadVoice: Unload

View File

@@ -73,6 +73,12 @@
UpgradeTypes: empdisable UpgradeTypes: empdisable
Modifier: 0 Modifier: 0
^EmpDisableMobile:
Inherits: ^EmpDisable
Mobile:
UpgradeTypes: notmobile
UpgradeMaxEnabledLevel: 0
^BasicBuilding: ^BasicBuilding:
Inherits@1: ^ExistsInWorld Inherits@1: ^ExistsInWorld
Inherits@2: ^SpriteActor Inherits@2: ^SpriteActor
@@ -334,7 +340,7 @@
^Cyborg: ^Cyborg:
Inherits@1: ^Infantry Inherits@1: ^Infantry
Inherits@2: ^EmpDisable Inherits@2: ^EmpDisableMobile
RevealsShroud: RevealsShroud:
Range: 4c0 Range: 4c0
MustBeDestroyed: MustBeDestroyed:
@@ -361,7 +367,7 @@
^Vehicle: ^Vehicle:
Inherits@1: ^GainsExperience Inherits@1: ^GainsExperience
Inherits@2: ^ExistsInWorld Inherits@2: ^ExistsInWorld
Inherits@3: ^EmpDisable Inherits@3: ^EmpDisableMobile
DrawLineToTarget: DrawLineToTarget:
Mobile: Mobile:
Crushes: crate Crushes: crate
@@ -656,7 +662,7 @@
ActorLostNotification: ActorLostNotification:
^Train: ^Train:
Inherits@1: ^EmpDisable Inherits@1: ^EmpDisableMobile
Inherits@2: ^ExistsInWorld Inherits@2: ^ExistsInWorld
RenderVoxels: RenderVoxels:
WithVoxelBody: WithVoxelBody:
@@ -667,6 +673,10 @@
ROT: 5 ROT: 5
Voice: Move Voice: Move
Speed: 113 Speed: 113
Cargo:
Types: Infantry
UnloadVoice: Unload
LoadingUpgrades: notmobile
Health: Health:
HP: 100 HP: 100
Armor: Armor:

View File

@@ -27,6 +27,7 @@ APC:
MaxWeight: 5 MaxWeight: 5
PipCount: 5 PipCount: 5
UnloadVoice: Unload UnloadVoice: Unload
LoadingUpgrades: notmobile
-WithVoxelBody: -WithVoxelBody:
WithVoxelWaterBody: WithVoxelWaterBody:
LeavesTrails: LeavesTrails:

View File

@@ -226,6 +226,7 @@ SAPC:
MaxWeight: 5 MaxWeight: 5
PipCount: 5 PipCount: 5
UnloadVoice: Unload UnloadVoice: Unload
LoadingUpgrades: notmobile
SUBTANK: SUBTANK:
Inherits: ^VoxelTank Inherits: ^VoxelTank

View File

@@ -127,7 +127,7 @@ LPST:
gdi: lpst.gdi gdi: lpst.gdi
nod: lpst.nod nod: lpst.nod
DeployToUpgrade: DeployToUpgrade:
DeployedUpgrades: deployed DeployedUpgrades: deployed, notmobile
UndeployedUpgrades: undeployed UndeployedUpgrades: undeployed
DeployAnimation: make DeployAnimation: make
Facing: 160 Facing: 160
@@ -141,9 +141,6 @@ LPST:
WithSpriteBody@deployed: WithSpriteBody@deployed:
UpgradeTypes: undeployed UpgradeTypes: undeployed
UpgradeMaxEnabledLevel: 0 UpgradeMaxEnabledLevel: 0
DisableOnUpgrade:
UpgradeTypes: undeployed
UpgradeMaxEnabledLevel: 0
DetectCloaked: DetectCloaked:
UpgradeTypes: deployed UpgradeTypes: deployed
UpgradeMinEnabledLevel: 1 UpgradeMinEnabledLevel: 1

View File

@@ -90,7 +90,7 @@ EMPulseCannon:
Warhead@emp: GrantUpgrade Warhead@emp: GrantUpgrade
Range: 3c0 Range: 3c0
Duration: 250 Duration: 250
Upgrades: empdisable Upgrades: empdisable, notmobile
ClusterMissile: ClusterMissile:
ValidTargets: Ground, Water, Air ValidTargets: Ground, Water, Air