diff --git a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj
index c47a048674..60e34ed772 100644
--- a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj
+++ b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj
@@ -586,6 +586,11 @@
+
+
+
+
+
diff --git a/OpenRA.Mods.Common/UpdateRules/Rules/AddNukeLaunchAnimation.cs b/OpenRA.Mods.Common/UpdateRules/Rules/AddNukeLaunchAnimation.cs
new file mode 100644
index 0000000000..1f8e546350
--- /dev/null
+++ b/OpenRA.Mods.Common/UpdateRules/Rules/AddNukeLaunchAnimation.cs
@@ -0,0 +1,48 @@
+#region Copyright & License Information
+/*
+ * Copyright 2007-2018 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 System.Linq;
+
+namespace OpenRA.Mods.Common.UpdateRules.Rules
+{
+ public class AddNukeLaunchAnimation : UpdateRule
+ {
+ public override string Name { get { return "Add 'WithNukeLaunchAnimation' and remove 'NukePower.ActivationSequence'"; } }
+ public override string Description
+ {
+ get
+ {
+ return "The 'ActivationSequence' property has been removed.\n" +
+ "Use the new 'WithNukeLaunchAnimation' trait instead.";
+ }
+ }
+
+ public override IEnumerable UpdateActorNode(ModData modData, MiniYamlNode actorNode)
+ {
+ var nukePowers = actorNode.ChildrenMatching("NukePower").ToList();
+ foreach (var nuke in nukePowers)
+ {
+ var activation = nuke.LastChildMatching("ActivationSequence");
+ if (activation == null)
+ continue;
+
+ var sequence = activation.NodeValue();
+ nuke.RemoveNode(activation);
+ actorNode.AddNode("WithNukeLaunchAnimation", "");
+ if (sequence != "active")
+ actorNode.LastChildMatching("WithNukeLaunchAnimation").AddNode("Sequence", sequence);
+ }
+
+ yield break;
+ }
+ }
+}
diff --git a/OpenRA.Mods.Common/UpdateRules/Rules/CapturableChanges.cs b/OpenRA.Mods.Common/UpdateRules/Rules/CapturableChanges.cs
new file mode 100644
index 0000000000..1c4b1ee0ab
--- /dev/null
+++ b/OpenRA.Mods.Common/UpdateRules/Rules/CapturableChanges.cs
@@ -0,0 +1,86 @@
+#region Copyright & License Information
+/*
+ * Copyright 2007-2018 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.Traits;
+
+namespace OpenRA.Mods.Common.UpdateRules.Rules
+{
+ public class CapturableChanges : UpdateRule
+ {
+ public override string Name { get { return "Changes on 'Captures' and 'ExternalCaptures'"; } }
+ public override string Description
+ {
+ get
+ {
+ return "'Type' was renamed to 'Types'. 'AllowAllies',\n" +
+ "'AllowNeutral' and 'AllowEnemies' were replaced by 'ValidStances'.";
+ }
+ }
+
+ void ApplyChanges(MiniYamlNode actorNode, MiniYamlNode node)
+ {
+ // Type renamed to Types
+ var type = node.LastChildMatching("Type");
+ if (type != null)
+ type.RenameKey("Types");
+
+ // Allow(Allies|Neutral|Enemies) replaced with a ValidStances enum
+ var stance = Stance.Neutral | Stance.Enemy;
+ var allowAllies = node.LastChildMatching("AllowAllies");
+ if (allowAllies != null)
+ {
+ if (allowAllies.NodeValue())
+ stance |= Stance.Ally;
+ else
+ stance &= ~Stance.Ally;
+
+ node.RemoveNode(allowAllies);
+ }
+
+ var allowNeutral = node.LastChildMatching("AllowNeutral");
+ if (allowNeutral != null)
+ {
+ if (allowNeutral.NodeValue())
+ stance |= Stance.Neutral;
+ else
+ stance &= ~Stance.Neutral;
+
+ node.RemoveNode(allowNeutral);
+ }
+
+ var allowEnemies = node.LastChildMatching("AllowEnemies");
+ if (allowEnemies != null)
+ {
+ if (allowEnemies.NodeValue())
+ stance |= Stance.Enemy;
+ else
+ stance &= ~Stance.Enemy;
+
+ node.RemoveNode(allowEnemies);
+ }
+
+ if (stance != (Stance.Neutral | Stance.Enemy))
+ node.AddNode("ValidStances", stance);
+ }
+
+ public override IEnumerable UpdateActorNode(ModData modData, MiniYamlNode actorNode)
+ {
+ foreach (var ca in actorNode.ChildrenMatching("Capturable"))
+ ApplyChanges(actorNode, ca);
+
+ foreach (var eca in actorNode.ChildrenMatching("ExternalCapturable"))
+ ApplyChanges(actorNode, eca);
+
+ yield break;
+ }
+ }
+}
diff --git a/OpenRA.Mods.Common/UpdateRules/Rules/DecoupleSelfReloading.cs b/OpenRA.Mods.Common/UpdateRules/Rules/DecoupleSelfReloading.cs
new file mode 100644
index 0000000000..6804b4672e
--- /dev/null
+++ b/OpenRA.Mods.Common/UpdateRules/Rules/DecoupleSelfReloading.cs
@@ -0,0 +1,85 @@
+#region Copyright & License Information
+/*
+ * Copyright 2007-2018 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 System.Linq;
+
+namespace OpenRA.Mods.Common.UpdateRules.Rules
+{
+ public class DecoupleSelfReloading : UpdateRule
+ {
+ public override string Name { get { return "Replace 'SelfReloads' with 'ReloadAmmoPool'"; } }
+ public override string Description
+ {
+ get
+ {
+ return "'SelfReloads', 'SelfReloadDelay', 'ReloadCount', 'ResetOnFire'\n" +
+ "and 'RearmSound' were renamed and moved from 'AmmoPool' to a new 'ReloadAmmoPool' trait.";
+ }
+ }
+
+ public override IEnumerable UpdateActorNode(ModData modData, MiniYamlNode actorNode)
+ {
+ var poolNumber = 0;
+ var ammoPools = actorNode.ChildrenMatching("AmmoPool").ToList();
+ foreach (var pool in ammoPools)
+ {
+ var selfReloads = pool.LastChildMatching("SelfReloads");
+ if (selfReloads == null || !selfReloads.NodeValue())
+ continue;
+
+ poolNumber++;
+ var reloadOnCond = new MiniYamlNode("ReloadAmmoPool@" + poolNumber, "");
+
+ var name = pool.LastChildMatching("Name");
+ if (name != null)
+ reloadOnCond.AddNode("AmmoPool", name.NodeValue());
+
+ var selfReloadDelay = pool.LastChildMatching("SelfReloadDelay");
+ if (selfReloadDelay != null)
+ {
+ selfReloadDelay.RenameKey("Delay");
+ reloadOnCond.AddNode(selfReloadDelay);
+ pool.RemoveNodes("SelfReloadDelay");
+ }
+
+ pool.RemoveNodes("SelfReloads");
+
+ var reloadCount = pool.LastChildMatching("ReloadCount");
+ if (reloadCount != null)
+ {
+ reloadCount.RenameKey("Count");
+ reloadOnCond.AddNode(reloadCount);
+ pool.RemoveNodes("ReloadCount");
+ }
+
+ var reset = pool.LastChildMatching("ResetOnFire");
+ if (reset != null)
+ {
+ reloadOnCond.AddNode(reset);
+ pool.RemoveNodes("ResetOnFire");
+ }
+
+ var rearmSound = pool.LastChildMatching("RearmSound");
+ if (rearmSound != null)
+ {
+ rearmSound.RenameKey("Sound");
+ reloadOnCond.AddNode(rearmSound);
+ pool.RemoveNodes("RearmSound");
+ }
+
+ actorNode.AddNode(reloadOnCond);
+ }
+
+ yield break;
+ }
+ }
+}
diff --git a/OpenRA.Mods.Common/UpdateRules/Rules/RemovePlayerPaletteTileset.cs b/OpenRA.Mods.Common/UpdateRules/Rules/RemovePlayerPaletteTileset.cs
new file mode 100644
index 0000000000..22584e2a80
--- /dev/null
+++ b/OpenRA.Mods.Common/UpdateRules/Rules/RemovePlayerPaletteTileset.cs
@@ -0,0 +1,43 @@
+#region Copyright & License Information
+/*
+ * Copyright 2007-2018 The OpenRA Developers (see AUTHORS)
+ * This file is part of OpenRA, which is free software. It is made
+ * available to you under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version. For more
+ * information, see COPYING.
+ */
+#endregion
+
+using System.Collections.Generic;
+
+namespace OpenRA.Mods.Common.UpdateRules.Rules
+{
+ public class RemovePlayerPaletteTileset : UpdateRule
+ {
+ public override string Name { get { return "Replace 'PlayerPaletteFromCurrentTileset'"; } }
+ public override string Description
+ {
+ get
+ {
+ return "The trait 'PlayerPaletteFromCurrentTileset' has been removed.\n" +
+ "Use 'PaletteFromFile' with a Tileset filter.";
+ }
+ }
+
+ public override IEnumerable UpdateActorNode(ModData modData, MiniYamlNode actorNode)
+ {
+ foreach (var ppfct in actorNode.ChildrenMatching("PlayerPaletteFromCurrentTileset"))
+ {
+ ppfct.AddNode("Filename", "");
+ ppfct.AddNode("Tileset", "");
+ ppfct.RenameKey("PaletteFromFile");
+ yield return ppfct.Location + ": The trait 'PlayerPaletteFromCurrentTileset'\n" +
+ "has been replaced by 'PaletteFromFile'. The trait has been renamed for you,\n" +
+ "but you will need to update the definition to specify the correct filename and tileset filters.";
+ }
+
+ yield break;
+ }
+ }
+}
diff --git a/OpenRA.Mods.Common/UpdateRules/Rules/RenameWithTurreted.cs b/OpenRA.Mods.Common/UpdateRules/Rules/RenameWithTurreted.cs
new file mode 100644
index 0000000000..40182f1676
--- /dev/null
+++ b/OpenRA.Mods.Common/UpdateRules/Rules/RenameWithTurreted.cs
@@ -0,0 +1,39 @@
+#region Copyright & License Information
+/*
+ * Copyright 2007-2018 The OpenRA Developers (see AUTHORS)
+ * This file is part of OpenRA, which is free software. It is made
+ * available to you under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version. For more
+ * information, see COPYING.
+ */
+#endregion
+
+using System.Collections.Generic;
+
+namespace OpenRA.Mods.Common.UpdateRules.Rules
+{
+ public class RenameWithTurreted : UpdateRule
+ {
+ public override string Name { get { return "Rename 'WithTurretedAttackAnimation' and 'WithTurretedSpriteBody'"; } }
+ public override string Description
+ {
+ get
+ {
+ return "'WithTurretedAttackAnimation' was renamed to 'WithTurretAttackAnimation'.\n" +
+ "'WithTurretedSpriteBody' was renamed to 'WithEmbeddedTurretSpriteBody'.";
+ }
+ }
+
+ public override IEnumerable UpdateActorNode(ModData modData, MiniYamlNode actorNode)
+ {
+ foreach (var wtaa in actorNode.ChildrenMatching("WithTurretedAttackAnimation"))
+ wtaa.RenameKey("WithTurretAttackAnimation");
+
+ foreach (var wtsb in actorNode.ChildrenMatching("WithTurretedSpriteBody"))
+ wtsb.RenameKey("WithEmbeddedTurretSpriteBody");
+
+ yield break;
+ }
+ }
+}
diff --git a/OpenRA.Mods.Common/UpdateRules/UpdatePath.cs b/OpenRA.Mods.Common/UpdateRules/UpdatePath.cs
index a3d4a2ac37..1bcfde03b8 100644
--- a/OpenRA.Mods.Common/UpdateRules/UpdatePath.cs
+++ b/OpenRA.Mods.Common/UpdateRules/UpdatePath.cs
@@ -37,7 +37,12 @@ namespace OpenRA.Mods.Common.UpdateRules
new UpdatePath("incomplete-release-20171014", "release-20180218", new UpdateRule[]
{
new RemoveMobileOnRails(),
- new AircraftCanHoverGeneralization()
+ new AircraftCanHoverGeneralization(),
+ new AddNukeLaunchAnimation(),
+ new CapturableChanges(),
+ new DecoupleSelfReloading(),
+ new RemovePlayerPaletteTileset(),
+ new RenameWithTurreted()
}),
new UpdatePath("release-20180218", "release-20180307", new UpdateRule[0]),