diff --git a/OpenRA.Mods.Common/Activities/PickupUnit.cs b/OpenRA.Mods.Common/Activities/PickupUnit.cs
index 56e47f2c26..7b4b2626db 100644
--- a/OpenRA.Mods.Common/Activities/PickupUnit.cs
+++ b/OpenRA.Mods.Common/Activities/PickupUnit.cs
@@ -60,7 +60,7 @@ namespace OpenRA.Mods.Common.Activities
if (cargo != carryall.Carryable)
return NextActivity;
- if (cargo.IsDead || IsCanceled)
+ if (cargo.IsDead || IsCanceled || carryable.IsTraitDisabled)
{
carryall.UnreserveCarryable(self);
return NextActivity;
diff --git a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj
index 982265900a..c0938fdadc 100644
--- a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj
+++ b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj
@@ -774,6 +774,7 @@
+
diff --git a/OpenRA.Mods.Common/Traits/Carryable.cs b/OpenRA.Mods.Common/Traits/Carryable.cs
index 7674266188..8f45f29a2b 100644
--- a/OpenRA.Mods.Common/Traits/Carryable.cs
+++ b/OpenRA.Mods.Common/Traits/Carryable.cs
@@ -15,38 +15,41 @@ using OpenRA.Traits;
namespace OpenRA.Mods.Common.Traits
{
[Desc("Can be carried by actors with the `Carryall` trait.")]
- public class CarryableInfo : ITraitInfo
+ public class CarryableInfo : UpgradableTraitInfo
{
[UpgradeGrantedReference]
- [Desc("The upgrades to grant to self while waiting or being carried.")]
- public readonly string[] CarryableUpgrades = { };
+ [Desc("The condition to grant to self while a carryall has been reserved.")]
+ public readonly string ReservedCondition = null;
+
+ [UpgradeGrantedReference]
+ [Desc("The condition to grant to self while being carried.")]
+ public readonly string CarriedCondition = null;
[Desc("Carryall attachment point relative to body.")]
public readonly WVec LocalOffset = WVec.Zero;
- public virtual object Create(ActorInitializer init) { return new Carryable(init.Self, this); }
+ public override object Create(ActorInitializer init) { return new Carryable(init.Self, this); }
}
- public class Carryable : INotifyCreated
+ public class Carryable : UpgradableTrait
{
- readonly CarryableInfo info;
UpgradeManager upgradeManager;
+ int reservedToken = UpgradeManager.InvalidConditionToken;
+ int carriedToken = UpgradeManager.InvalidConditionToken;
public Actor Carrier { get; private set; }
public bool Reserved { get { return state != State.Free; } }
public CPos? Destination { get; protected set; }
- public bool WantsTransport { get { return Destination != null; } }
+ public bool WantsTransport { get { return Destination != null && !IsTraitDisabled; } }
protected enum State { Free, Reserved, Locked }
protected State state = State.Free;
protected bool attached;
public Carryable(Actor self, CarryableInfo info)
- {
- this.info = info;
- }
+ : base(info) { }
- void INotifyCreated.Created(Actor self)
+ protected override void Created(Actor self)
{
upgradeManager = self.Trait();
}
@@ -57,8 +60,9 @@ namespace OpenRA.Mods.Common.Traits
return;
attached = true;
- foreach (var u in info.CarryableUpgrades)
- upgradeManager.GrantUpgrade(self, u, this);
+
+ if (carriedToken == UpgradeManager.InvalidConditionToken && !string.IsNullOrEmpty(Info.CarriedCondition))
+ carriedToken = upgradeManager.GrantCondition(self, Info.CarriedCondition);
}
// This gets called by carrier after we touched down
@@ -68,17 +72,22 @@ namespace OpenRA.Mods.Common.Traits
return;
attached = false;
- foreach (var u in info.CarryableUpgrades)
- upgradeManager.RevokeUpgrade(self, u, this);
+
+ if (carriedToken != UpgradeManager.InvalidConditionToken)
+ carriedToken = upgradeManager.RevokeCondition(self, carriedToken);
}
public virtual bool Reserve(Actor self, Actor carrier)
{
- if (Reserved)
+ if (Reserved || IsTraitDisabled)
return false;
state = State.Reserved;
Carrier = carrier;
+
+ if (reservedToken == UpgradeManager.InvalidConditionToken && !string.IsNullOrEmpty(Info.ReservedCondition))
+ reservedToken = upgradeManager.GrantCondition(self, Info.ReservedCondition);
+
return true;
}
@@ -86,6 +95,9 @@ namespace OpenRA.Mods.Common.Traits
{
state = State.Free;
Carrier = null;
+
+ if (reservedToken != UpgradeManager.InvalidConditionToken)
+ reservedToken = upgradeManager.RevokeCondition(self, reservedToken);
}
// Prepare for transport pickup
diff --git a/OpenRA.Mods.Common/Traits/Carryall.cs b/OpenRA.Mods.Common/Traits/Carryall.cs
index 04afefeb61..756c0a2bcd 100644
--- a/OpenRA.Mods.Common/Traits/Carryall.cs
+++ b/OpenRA.Mods.Common/Traits/Carryall.cs
@@ -283,11 +283,14 @@ namespace OpenRA.Mods.Common.Traits
{
if (!target.AppearsFriendlyTo(self))
return false;
+
var carryable = target.TraitOrDefault();
- if (carryable == null)
+ if (carryable == null || carryable.IsTraitDisabled)
return false;
+
if (carryable.Reserved && carryable.Carrier != self)
return false;
+
return true;
}
diff --git a/OpenRA.Mods.Common/Traits/Upgrades/GrantCondition.cs b/OpenRA.Mods.Common/Traits/Upgrades/GrantCondition.cs
new file mode 100644
index 0000000000..94e89d06ec
--- /dev/null
+++ b/OpenRA.Mods.Common/Traits/Upgrades/GrantCondition.cs
@@ -0,0 +1,56 @@
+#region Copyright & License Information
+/*
+ * Copyright 2007-2016 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 OpenRA.Traits;
+
+namespace OpenRA.Mods.Common.Traits
+{
+ [Desc("Grants a condition while the trait is active.")]
+ class GrantConditionInfo : UpgradableTraitInfo
+ {
+ [FieldLoader.Require]
+ [UpgradeGrantedReference]
+ [Desc("Condition to grant.")]
+ public readonly string Condition = null;
+
+ public override object Create(ActorInitializer init) { return new GrantCondition(this); }
+ }
+
+ class GrantCondition : UpgradableTrait
+ {
+ UpgradeManager manager;
+ int conditionToken = UpgradeManager.InvalidConditionToken;
+
+ public GrantCondition(GrantConditionInfo info)
+ : base(info) { }
+
+ protected override void Created(Actor self)
+ {
+ manager = self.Trait();
+
+ base.Created(self);
+ }
+
+ protected override void TraitEnabled(Actor self)
+ {
+ if (conditionToken == UpgradeManager.InvalidConditionToken)
+ conditionToken = manager.GrantCondition(self, Info.Condition);
+ }
+
+ protected override void TraitDisabled(Actor self)
+ {
+ if (conditionToken == UpgradeManager.InvalidConditionToken)
+ return;
+
+ conditionToken = manager.RevokeCondition(self, conditionToken);
+ }
+ }
+}
\ No newline at end of file
diff --git a/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs b/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs
index 636f2c55ba..7718eca762 100644
--- a/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs
+++ b/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs
@@ -477,6 +477,27 @@ namespace OpenRA.Mods.Common.UtilityCommands
}
}
+ if (engineVersion < 20161119)
+ {
+ // Migrated carryalls over to new conditions system
+ var carryableUpgradesNode = node.Value.Nodes.FirstOrDefault(n => n.Key == "CarryableUpgrades");
+ if (carryableUpgradesNode != null)
+ {
+ var conditions = FieldLoader.GetValue("", carryableUpgradesNode.Value.Value);
+ if (conditions.Length > 1)
+ Console.WriteLine("Unable to automatically migrate {0}:{1} CarryableUpgrades to CarriedCondition. This must be corrected manually",
+ parent.Key, node.Key);
+ else
+ carryableUpgradesNode.Key = "CarriedCondition";
+ }
+
+ if (node.Key == "WithDecorationCarryable")
+ {
+ node.Key = "WithDecoration@CARRYALL";
+ node.Value.Nodes.Add(new MiniYamlNode("RequiresCondition", "carryall-reserved"));
+ }
+ }
+
UpgradeActorRules(modData, engineVersion, ref node.Value.Nodes, node, depth + 1);
}
diff --git a/OpenRA.Mods.D2k/OpenRA.Mods.D2k.csproj b/OpenRA.Mods.D2k/OpenRA.Mods.D2k.csproj
index 50c76c26fc..f009a0f900 100644
--- a/OpenRA.Mods.D2k/OpenRA.Mods.D2k.csproj
+++ b/OpenRA.Mods.D2k/OpenRA.Mods.D2k.csproj
@@ -85,7 +85,6 @@
-
diff --git a/OpenRA.Mods.D2k/Traits/Render/WithDecorationCarryable.cs b/OpenRA.Mods.D2k/Traits/Render/WithDecorationCarryable.cs
deleted file mode 100644
index 9bf9dfd984..0000000000
--- a/OpenRA.Mods.D2k/Traits/Render/WithDecorationCarryable.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-#region Copyright & License Information
-/*
- * Copyright 2007-2016 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 OpenRA.Mods.Common.Traits;
-using OpenRA.Mods.Common.Traits.Render;
-using OpenRA.Traits;
-
-namespace OpenRA.Mods.D2k.Traits.Render
-{
- [Desc("Displays a sprite when the carryable actor is waiting for pickup.")]
- public class WithDecorationCarryableInfo : WithDecorationInfo, Requires
- {
- public override object Create(ActorInitializer init) { return new WithDecorationCarryable(init.Self, this); }
- }
-
- public class WithDecorationCarryable : WithDecoration
- {
- readonly Carryable carryable;
-
- public WithDecorationCarryable(Actor self, WithDecorationCarryableInfo info)
- : base(self, info)
- {
- carryable = self.Trait();
- }
-
- protected override bool ShouldRender(Actor self)
- {
- return carryable.Reserved && base.ShouldRender(self);
- }
- }
-}
diff --git a/mods/d2k/rules/defaults.yaml b/mods/d2k/rules/defaults.yaml
index 368100b356..1c4a8846dc 100644
--- a/mods/d2k/rules/defaults.yaml
+++ b/mods/d2k/rules/defaults.yaml
@@ -159,11 +159,13 @@
Voiced:
VoiceSet: VehicleVoice
AutoCarryable:
- CarryableUpgrades: notmobile
- WithDecorationCarryable:
+ CarriedCondition: notmobile
+ ReservedCondition: carryall-reserved
+ WithDecoration@CARRYALL:
Image: pips
Sequence: pickup-indicator
Offset: -12, -12
+ RequiresCondition: carryall-reserved
^Tank:
Inherits: ^Vehicle
diff --git a/mods/ts/rules/nod-vehicles.yaml b/mods/ts/rules/nod-vehicles.yaml
index 1be6da809d..8837a3402e 100644
--- a/mods/ts/rules/nod-vehicles.yaml
+++ b/mods/ts/rules/nod-vehicles.yaml
@@ -113,10 +113,12 @@ TTNK:
AllowedTerrainTypes: Clear, Road, DirtRoad, Rough
DeploySound: place2.aud
UndeploySound: clicky1.aud
+ GrantCondition@PREVIEWWORKAROUND:
+ Condition: real-actor
WithVoxelBody:
RequiresCondition: undeployed
WithSpriteBody@deployed:
- RequiresCondition: !undeployed
+ RequiresCondition: !undeployed && real-actor
AttackFrontal:
Voice: Attack
RequiresCondition: undeployed
@@ -154,6 +156,8 @@ TTNK:
Type: Concrete
RequiresCondition: deployed
AutoTarget:
+ Carryable:
+ RequiresCondition: undeployed
ART2:
Inherits: ^VoxelTank
diff --git a/mods/ts/rules/shared-vehicles.yaml b/mods/ts/rules/shared-vehicles.yaml
index e069fbbdb8..b90046afa5 100644
--- a/mods/ts/rules/shared-vehicles.yaml
+++ b/mods/ts/rules/shared-vehicles.yaml
@@ -130,6 +130,8 @@ LPST:
RevealsShroud:
Range: 7c0
MaxHeightDelta: 3
+ GrantCondition@PREVIEWWORKAROUND:
+ Condition: real-actor
RenderSprites:
Image: lpst.gdi
FactionImages:
@@ -147,9 +149,11 @@ LPST:
Image: lpst
RequiresCondition: undeployed
WithSpriteBody@deployed:
- RequiresCondition: !undeployed
+ RequiresCondition: !undeployed && real-actor
DetectCloaked:
RequiresCondition: deployed
Range: 18c0
RenderDetectionCircle:
TrailCount: 3
+ Carryable:
+ RequiresCondition: undeployed
\ No newline at end of file