diff --git a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj
index 03d2ed1e13..ceaa777a7a 100644
--- a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj
+++ b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj
@@ -592,13 +592,20 @@
+
+
+
+
+
+
+
diff --git a/OpenRA.Mods.Common/UpdateRules/Rules/MoveVisualBounds.cs b/OpenRA.Mods.Common/UpdateRules/Rules/MoveVisualBounds.cs
new file mode 100644
index 0000000000..432876dd19
--- /dev/null
+++ b/OpenRA.Mods.Common/UpdateRules/Rules/MoveVisualBounds.cs
@@ -0,0 +1,72 @@
+#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 MoveVisualBounds : UpdateRule
+ {
+ public override string Name { get { return "Move 'SelectionDecorations.VisualBounds' to 'Selectable.Bounds'"; } }
+ public override string Description
+ {
+ get
+ {
+ return "'SelectionDecorations.VisualBounds' was moved to 'Selectable.Bounds'.\n" +
+ "'AutoRenderSize' and 'CustomRenderSize' were renamed to 'Interactable'.";
+ }
+ }
+
+ public override IEnumerable UpdateActorNode(ModData modData, MiniYamlNode actorNode)
+ {
+ var autoSelectionSize = actorNode.LastChildMatching("AutoSelectionSize");
+ if (autoSelectionSize != null)
+ actorNode.AddNode("Interactable", "");
+
+ var customSelectionSize = actorNode.LastChildMatching("CustomSelectionSize");
+ if (customSelectionSize != null)
+ {
+ var bounds = customSelectionSize.LastChildMatching("CustomBounds");
+ var customRenderSize = new MiniYamlNode("Interactable", "");
+ if (bounds != null)
+ customRenderSize.AddNode("Bounds", bounds.NodeValue());
+
+ actorNode.AddNode(customRenderSize);
+ }
+
+ var sd = actorNode.LastChildMatching("SelectionDecorations");
+ if (sd != null)
+ {
+ var boundsNode = sd.LastChildMatching("VisualBounds");
+ if (boundsNode != null)
+ {
+ boundsNode.RenameKey("DecorationBounds");
+ sd.RemoveNode(boundsNode);
+ var selectable = actorNode.LastChildMatching("Selectable");
+ if (selectable == null)
+ {
+ selectable = new MiniYamlNode("Selectable", new MiniYaml(""));
+ actorNode.AddNode(selectable);
+ }
+
+ selectable.AddNode(boundsNode);
+ }
+ }
+
+ if (actorNode.LastChildMatching("-Selectable") != null && actorNode.LastChildMatching("Interactable") == null)
+ actorNode.AddNode("Interactable", "");
+
+ actorNode.RemoveNodes("CustomSelectionSize");
+ actorNode.RemoveNodes("AutoSelectionSize");
+ yield break;
+ }
+ }
+}
diff --git a/OpenRA.Mods.Common/UpdateRules/Rules/RemoveIDisable.cs b/OpenRA.Mods.Common/UpdateRules/Rules/RemoveIDisable.cs
new file mode 100644
index 0000000000..9d116d6a1b
--- /dev/null
+++ b/OpenRA.Mods.Common/UpdateRules/Rules/RemoveIDisable.cs
@@ -0,0 +1,47 @@
+#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 RemoveIDisable : UpdateRule
+ {
+ public override string Name { get { return "Remove 'IDisabled'"; } }
+ public override string Description
+ {
+ get
+ {
+ return "'Actor.IsDisabled' has been removed in favor of pausing/disabling traits via conditions.";
+ }
+ }
+
+ bool displayed;
+
+ public override IEnumerable UpdateActorNode(ModData modData, MiniYamlNode actorNode)
+ {
+ var doc = actorNode.LastChildMatching("DisableOnCondition");
+ var grant = actorNode.LastChildMatching("GrantConditionOnDisabled");
+
+ if (!displayed && (doc != null || grant != null))
+ {
+ displayed = true;
+ yield return "Actor.IsDisabled has been removed in favor of pausing/disabling traits via conditions.\n" +
+ "DisableOnCondition and GrantConditionOnDisabled were stop-gap solutions that have been removed along with it.\n" +
+ "You'll have to use RequiresCondition or PauseOnCondition on individual traits to 'disable' actors.";
+ }
+
+ actorNode.RemoveNodes("DisableOnCondition");
+ actorNode.RemoveNodes("GrantConditionOnDisabled");
+ yield break;
+ }
+ }
+}
diff --git a/OpenRA.Mods.Common/UpdateRules/Rules/RenameBurstDelay.cs b/OpenRA.Mods.Common/UpdateRules/Rules/RenameBurstDelay.cs
new file mode 100644
index 0000000000..949127a435
--- /dev/null
+++ b/OpenRA.Mods.Common/UpdateRules/Rules/RenameBurstDelay.cs
@@ -0,0 +1,37 @@
+#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 RenameBurstDelay : UpdateRule
+ {
+ public override string Name { get { return "BurstDelay was renamed to BurstDelays due to support of multiple values."; } }
+ public override string Description
+ {
+ get
+ {
+ return "It's now possible to set multiple delay values (one for each consecutive burst),\n" +
+ "so the property was renamed to BurstDelays to account for this.";
+ }
+ }
+
+ public override IEnumerable UpdateWeaponNode(ModData modData, MiniYamlNode weaponNode)
+ {
+ var bd = weaponNode.LastChildMatching("BurstDelay");
+ if (bd != null)
+ bd.RenameKey("BurstDelays");
+
+ yield break;
+ }
+ }
+}
diff --git a/OpenRA.Mods.Common/UpdateRules/Rules/ReplaceCanPowerDown.cs b/OpenRA.Mods.Common/UpdateRules/Rules/ReplaceCanPowerDown.cs
new file mode 100644
index 0000000000..11b0cdf83e
--- /dev/null
+++ b/OpenRA.Mods.Common/UpdateRules/Rules/ReplaceCanPowerDown.cs
@@ -0,0 +1,74 @@
+#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 ReplaceCanPowerDown : UpdateRule
+ {
+ public override string Name { get { return "Replace 'CanPowerDown' by 'ToggleConditionOnOrder'"; } }
+ public override string Description
+ {
+ get
+ {
+ return "'CanPowerDown' was replaced with a more general 'ToggleConditionOnOrder' trait.";
+ }
+ }
+
+ public override IEnumerable UpdateActorNode(ModData modData, MiniYamlNode actorNode)
+ {
+ var cpd = actorNode.LastChildMatching("CanPowerDown");
+ if (cpd == null)
+ yield break;
+
+ cpd.RenameKey("ToggleConditionOnOrder");
+ var upSound = cpd.LastChildMatching("PowerupSound");
+ if (upSound != null)
+ upSound.RenameKey("DisabledSound");
+
+ var upSpeech = cpd.LastChildMatching("PowerupSpeech");
+ if (upSpeech != null)
+ upSpeech.RenameKey("DisabledSpeech");
+
+ var downSound = cpd.LastChildMatching("PowerdownSound");
+ if (downSound != null)
+ downSound.RenameKey("EnabledSound");
+
+ var downSpeech = cpd.LastChildMatching("PowerdownSpeech");
+ if (downSpeech != null)
+ downSpeech.RenameKey("EnabledSpeech");
+
+ cpd.AddNode("OrderName", "PowerDown");
+
+ var condition = cpd.LastChildMatching("PowerdownCondition");
+ if (condition != null)
+ condition.RenameKey("Condition");
+ else
+ cpd.AddNode("Condition", "powerdown");
+
+ if (cpd.ChildrenMatching("CancelWhenDisabled").Any())
+ {
+ cpd.RemoveNodes("CancelWhenDisabled");
+ yield return "CancelWhenDisabled was removed when CanPowerDown was replaced by ToggleConditionOnOrder.\n" +
+ "Use PauseOnCondition instead of RequiresCondition to replicate the behavior of 'false'.";
+ }
+
+ actorNode.AddNode(new MiniYamlNode("PowerMultiplier@POWERDOWN", new MiniYaml("", new List()
+ {
+ new MiniYamlNode("RequiresCondition", condition.Value.Value),
+ new MiniYamlNode("Modifier", "0")
+ })));
+ yield break;
+ }
+ }
+}
diff --git a/OpenRA.Mods.Common/UpdateRules/Rules/ReworkCheckboxes.cs b/OpenRA.Mods.Common/UpdateRules/Rules/ReworkCheckboxes.cs
new file mode 100644
index 0000000000..4ee1a679d1
--- /dev/null
+++ b/OpenRA.Mods.Common/UpdateRules/Rules/ReworkCheckboxes.cs
@@ -0,0 +1,145 @@
+#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 ReworkCheckboxes : UpdateRule
+ {
+ public override string Name { get { return "Rename 'Locked' and 'Enabled' on checkboxes and dropdowns"; } }
+ public override string Description
+ {
+ get
+ {
+ return "'Locked' and 'Enabled' were renamed to contain the respective checkboxes' name,\n" +
+ "like 'FogCheckboxLocked'. For dropdowns 'Locked' was renamed to 'DropdownLocked'.";
+ }
+ }
+
+ public override IEnumerable UpdateActorNode(ModData modData, MiniYamlNode actorNode)
+ {
+ var mpUnits = actorNode.LastChildMatching("SpawnMPUnits");
+ if (mpUnits != null)
+ {
+ var locked = mpUnits.LastChildMatching("Locked");
+ if (locked != null)
+ locked.RenameKey("DropdownLocked");
+ }
+
+ var shroud = actorNode.LastChildMatching("Shroud");
+ if (shroud != null)
+ {
+ var fogLocked = shroud.LastChildMatching("FogLocked");
+ if (fogLocked != null)
+ fogLocked.RenameKey("FogCheckboxLocked");
+
+ var fogEnabled = shroud.LastChildMatching("FogEnabled");
+ if (fogEnabled != null)
+ fogEnabled.RenameKey("FogCheckboxEnabled");
+
+ var exploredMapLocked = shroud.LastChildMatching("ExploredMapLocked");
+ if (exploredMapLocked != null)
+ exploredMapLocked.RenameKey("ExploredMapCheckboxLocked");
+
+ var exploredMapEnabled = shroud.LastChildMatching("ExploredMapEnabled");
+ if (exploredMapEnabled != null)
+ exploredMapEnabled.RenameKey("ExploredMapCheckboxEnabled");
+ }
+
+ var options = actorNode.LastChildMatching("MapOptions");
+ if (options != null)
+ {
+ var shortGameLocked = options.LastChildMatching("ShortGameLocked");
+ if (shortGameLocked != null)
+ shortGameLocked.RenameKey("ShortGameCheckboxLocked");
+
+ var shortGameEnabled = options.LastChildMatching("ShortGameEnabled");
+ if (shortGameEnabled != null)
+ shortGameEnabled.RenameKey("ShortGameCheckboxEnabled");
+
+ var techLevelLocked = options.LastChildMatching("TechLevelLocked");
+ if (techLevelLocked != null)
+ techLevelLocked.RenameKey("TechLevelDropdownLocked");
+
+ var gameSpeedLocked = options.LastChildMatching("GameSpeedLocked");
+ if (gameSpeedLocked != null)
+ gameSpeedLocked.RenameKey("GameSpeedDropdownLocked");
+ }
+
+ var creeps = actorNode.LastChildMatching("MapCreeps");
+ if (creeps != null)
+ {
+ var locked = creeps.LastChildMatching("Locked");
+ if (locked != null)
+ locked.RenameKey("CheckboxLocked");
+
+ var enabled = creeps.LastChildMatching("Enabled");
+ if (enabled != null)
+ enabled.RenameKey("CheckboxEnabled");
+ }
+
+ var buildRadius = actorNode.LastChildMatching("MapBuildRadius");
+ if (buildRadius != null)
+ {
+ var alllyLocked = buildRadius.LastChildMatching("AllyBuildRadiusLocked");
+ if (alllyLocked != null)
+ alllyLocked.RenameKey("AllyBuildRadiusCheckboxLocked");
+
+ var allyEnabled = buildRadius.LastChildMatching("AllyBuildRadiusEnabled");
+ if (allyEnabled != null)
+ allyEnabled.RenameKey("AllyBuildRadiusCheckboxEnabled");
+
+ var buildRadiusLocked = buildRadius.LastChildMatching("BuildRadiusLocked");
+ if (buildRadiusLocked != null)
+ buildRadiusLocked.RenameKey("BuildRadiusCheckboxLocked");
+
+ var buildRadiusEnabled = buildRadius.LastChildMatching("BuildRadiusEnabled");
+ if (buildRadiusEnabled != null)
+ buildRadiusEnabled.RenameKey("BuildRadiusCheckboxEnabled");
+ }
+
+ var devMode = actorNode.LastChildMatching("DeveloperMode");
+ if (devMode != null)
+ {
+ var locked = devMode.LastChildMatching("Locked");
+ if (locked != null)
+ locked.RenameKey("CheckboxLocked");
+
+ var enabled = devMode.LastChildMatching("Enabled");
+ if (enabled != null)
+ enabled.RenameKey("CheckboxEnabled");
+ }
+
+ var spawner = actorNode.LastChildMatching("CrateSpawner");
+ if (spawner != null)
+ {
+ var locked = spawner.LastChildMatching("Locked");
+ if (locked != null)
+ locked.RenameKey("CheckboxLocked");
+
+ var enabled = spawner.LastChildMatching("Enabled");
+ if (enabled != null)
+ enabled.RenameKey("CheckboxEnabled");
+ }
+
+ var resources = actorNode.LastChildMatching("PlayerResources");
+ if (resources != null)
+ {
+ var locked = resources.LastChildMatching("Locked");
+ if (locked != null)
+ locked.RenameKey("DefaultCashDropdownLocked");
+ }
+
+ yield break;
+ }
+ }
+}
diff --git a/OpenRA.Mods.Common/UpdateRules/Rules/SplitGateFromBuilding.cs b/OpenRA.Mods.Common/UpdateRules/Rules/SplitGateFromBuilding.cs
new file mode 100644
index 0000000000..6b02bce035
--- /dev/null
+++ b/OpenRA.Mods.Common/UpdateRules/Rules/SplitGateFromBuilding.cs
@@ -0,0 +1,77 @@
+#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 SplitGateFromBuilding : UpdateRule
+ {
+ public override string Name { get { return "Make gates use the 'Building' trait"; } }
+ public override string Description
+ {
+ get
+ {
+ return "The 'Gate' trait does no longer inherit 'Building'.\n" +
+ "Thus gates must define their own 'Building' trait.";
+ }
+ }
+
+ public override IEnumerable UpdateActorNode(ModData modData, MiniYamlNode actorNode)
+ {
+ var gate = actorNode.LastChildMatching("Gate");
+ if (gate == null)
+ yield break;
+
+ var openSound = gate.LastChildMatching("OpeningSound");
+ var closeSound = gate.LastChildMatching("ClosingSound");
+ var closeDelay = gate.LastChildMatching("CloseDelay");
+ var transitDelay = gate.LastChildMatching("TransitionDelay");
+ var blockHeight = gate.LastChildMatching("BlocksProjectilesHeight");
+
+ var newGate = new MiniYamlNode("Gate", "");
+ gate.RenameKey("Building");
+
+ if (openSound != null)
+ {
+ newGate.AddNode(openSound);
+ gate.RemoveNode(openSound);
+ }
+
+ if (closeSound != null)
+ {
+ newGate.AddNode(closeSound);
+ gate.RemoveNode(closeSound);
+ }
+
+ if (closeDelay != null)
+ {
+ newGate.AddNode(closeDelay);
+ gate.RemoveNode(closeDelay);
+ }
+
+ if (transitDelay != null)
+ {
+ newGate.AddNode(transitDelay);
+ gate.RemoveNode(transitDelay);
+ }
+
+ if (blockHeight != null)
+ {
+ newGate.AddNode(blockHeight);
+ gate.RemoveNode(blockHeight);
+ }
+
+ actorNode.AddNode(newGate);
+ yield break;
+ }
+ }
+}
diff --git a/OpenRA.Mods.Common/UpdateRules/Rules/WarnAboutInfiltrateForTypes.cs b/OpenRA.Mods.Common/UpdateRules/Rules/WarnAboutInfiltrateForTypes.cs
new file mode 100644
index 0000000000..a200f462de
--- /dev/null
+++ b/OpenRA.Mods.Common/UpdateRules/Rules/WarnAboutInfiltrateForTypes.cs
@@ -0,0 +1,64 @@
+#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;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace OpenRA.Mods.Common.UpdateRules.Rules
+{
+ public class WarnAboutInfiltrateForTypes : UpdateRule
+ {
+ public override string Name { get { return "Introduced Types field to InfiltrateFor* traits"; } }
+ public override string Description
+ {
+ get
+ {
+ return "InfiltrateFor* traits now have a Types field and infiltration will only have the desired\n" +
+ "effect if the Types include the type of the infiltrator.";
+ }
+ }
+
+ readonly string[] infiltrateForTraits =
+ {
+ "InfiltrateForCash", "InfiltrateForDecoration",
+ "InfiltrateForExploration", "InfiltrateForPowerOutage",
+ "InfiltrateForSupportPower",
+ };
+
+ readonly List> infiltrateForLocations = new List>();
+
+ public override IEnumerable AfterUpdate(ModData modData)
+ {
+ var message1 = "You need to define Types on the InfiltrateFor* trait(s) on the following actors:\n"
+ + UpdateUtils.FormatMessageList(infiltrateForLocations.Select(n => n.Item1 + " (" + n.Item2 + ")"));
+
+ if (infiltrateForLocations.Any())
+ yield return message1;
+
+ infiltrateForLocations.Clear();
+ }
+
+ public override IEnumerable UpdateActorNode(ModData modData, MiniYamlNode actorNode)
+ {
+ foreach (var t in infiltrateForTraits)
+ {
+ if (actorNode.LastChildMatching(t) != null)
+ {
+ infiltrateForLocations.Add(Tuple.Create(actorNode.Key, actorNode.Location.Filename));
+ yield break;
+ }
+ }
+
+ yield break;
+ }
+ }
+}
diff --git a/OpenRA.Mods.Common/UpdateRules/UpdatePath.cs b/OpenRA.Mods.Common/UpdateRules/UpdatePath.cs
index 08f4df9e1c..938d1ef40b 100644
--- a/OpenRA.Mods.Common/UpdateRules/UpdatePath.cs
+++ b/OpenRA.Mods.Common/UpdateRules/UpdatePath.cs
@@ -34,22 +34,29 @@ namespace OpenRA.Mods.Common.UpdateRules
Justification = "Extracting update lists to temporary variables obfuscates the definitions.")]
static readonly UpdatePath[] Paths =
{
- new UpdatePath("incomplete-release-20171014", "release-20180218", new UpdateRule[]
+ new UpdatePath("release-20171014", "release-20180218", new UpdateRule[]
{
new RemoveMobileOnRails(),
new AircraftCanHoverGeneralization(),
new AddNukeLaunchAnimation(),
+ new RenameWithTurreted(),
+ new RemovePlayerPaletteTileset(),
new CapturableChanges(),
new DecoupleSelfReloading(),
- new RemovePlayerPaletteTileset(),
- new RenameWithTurreted(),
- new ScaleDefaultModHealth(),
- new ScaleSupportPowerSecondsToTicks(),
- new ChangeBuildableArea(),
- new ChangeCanPowerDown(),
- new DropPauseAnimationWhenDisabled(),
new RemoveOutOfAmmo(),
- new ReplaceRequiresPower()
+ new ChangeCanPowerDown(),
+ new ReplaceRequiresPower(),
+ new DropPauseAnimationWhenDisabled(),
+ new ChangeBuildableArea(),
+ new MoveVisualBounds(),
+ new ScaleDefaultModHealth(),
+ new ReworkCheckboxes(),
+ new SplitGateFromBuilding(),
+ new RemoveIDisable(),
+ new ReplaceCanPowerDown(),
+ new ScaleSupportPowerSecondsToTicks(),
+ new WarnAboutInfiltrateForTypes(),
+ new RenameBurstDelay(),
}),
new UpdatePath("release-20180218", "release-20180307", new UpdateRule[0]),