Deprecate the release-20181215 path

This commit is contained in:
abcdefg30
2020-02-17 11:24:33 +01:00
committed by Paul Chote
parent f73d23661f
commit 40bb45a02b
26 changed files with 0 additions and 2239 deletions

View File

@@ -1,60 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007-2020 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 AddCarryableHarvester : UpdateRule
{
public override string Name { get { return "Inform about the 'CarryableHarvester' trait."; } }
public override string Description
{
get
{
return "A 'CarryableHarvester' trait was added for harvesters that use 'AutoCarryable'.";
}
}
bool hasAutoCarryable;
readonly List<string> harvesters = new List<string>();
public override IEnumerable<string> BeforeUpdate(ModData modData)
{
harvesters.Clear();
yield break;
}
public override IEnumerable<string> UpdateActorNode(ModData modData, MiniYamlNode actorNode)
{
if (!hasAutoCarryable)
hasAutoCarryable = actorNode.ChildrenMatching("AutoCarryable").Any();
var harvester = actorNode.LastChildMatching("Harvester");
if (harvester != null)
harvesters.Add("{0} ({1})".F(actorNode.Key, harvester.Location.Filename));
yield break;
}
public override IEnumerable<string> AfterUpdate(ModData modData)
{
if (!hasAutoCarryable || !harvesters.Any())
yield break;
yield return "Detected an 'AutoCarryable' trait.\n" +
"Review the following definitions and, if required,\n" +
"add the new 'CarryableHarvester' trait.\n" +
UpdateUtils.FormatMessageList(harvesters, 1);
}
}
}

View File

@@ -1,102 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007-2020 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 AddRearmable : UpdateRule
{
public override string Name { get { return "Added Rearmable trait and move RearmBuildings properties there"; } }
public override string Description
{
get
{
return "Added Rearmable trait and replaced Aircraft.RearmBuildings and\n" +
"Minelayer.RearmBuildings with Rearmable.RearmActors.";
}
}
public override IEnumerable<string> UpdateActorNode(ModData modData, MiniYamlNode actorNode)
{
var aircraftNodes = actorNode.ChildrenMatching("Aircraft");
var minelayerNodes = actorNode.ChildrenMatching("Minelayer");
var ammoPoolNodes = actorNode.ChildrenMatching("AmmoPool");
var addNodes = new List<MiniYamlNode>();
var ammoPoolNames = new List<string>() { "primary" };
foreach (var ap in ammoPoolNodes)
{
var poolName = ap.LastChildMatching("Name");
if (poolName != null && poolName.NodeValue<string>() != "primary")
ammoPoolNames.Add(poolName.NodeValue<string>());
}
var rearmableAdded = false;
foreach (var aircraftNode in aircraftNodes)
{
var rearmBuildings = aircraftNode.LastChildMatching("RearmBuildings");
if (rearmBuildings != null)
{
if (!rearmableAdded)
{
var rearmableNode = new MiniYamlNode("Rearmable", "");
rearmBuildings.MoveAndRenameNode(aircraftNode, rearmableNode, "RearmActors");
// If the list has more than one entry, at least one of them won't be "primary"
if (ammoPoolNames.Count > 1)
{
var ammoPools = new MiniYamlNode("AmmoPools", string.Join(", ", ammoPoolNames));
rearmableNode.AddNode(ammoPools);
}
addNodes.Add(rearmableNode);
rearmableAdded = true;
}
else
aircraftNode.RemoveNodes("RearmBuildings");
}
}
// If it's a minelayer, it won't be an aircraft and rearmableAdded should still be false, so we can use it here
foreach (var minelayerNode in minelayerNodes)
{
var rearmableNode = new MiniYamlNode("Rearmable", "");
var rearmBuildings = minelayerNode.LastChildMatching("RearmBuildings");
if (!rearmableAdded)
{
if (rearmBuildings != null)
rearmBuildings.MoveAndRenameNode(minelayerNode, rearmableNode, "RearmActors");
else
rearmableNode.AddNode(new MiniYamlNode("RearmActors", "fix"));
// If the list has more than one entry, at least one of them won't be "primary"
if (ammoPoolNames.Count > 1)
{
var ammoPools = new MiniYamlNode("AmmoPools", string.Join(", ", ammoPoolNames));
rearmableNode.AddNode(ammoPools);
}
addNodes.Add(rearmableNode);
rearmableAdded = true;
}
else if (rearmableAdded && rearmBuildings != null)
minelayerNode.RemoveNodes("RearmBuildings");
}
foreach (var node in addNodes)
actorNode.AddNode(node);
yield break;
}
}
}

View File

@@ -1,41 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007-2020 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 ChangeTakeOffSoundAndLandingSound : UpdateRule
{
public override string Name { get { return "Change 'TakeOffSound' and 'LandingSound' parameters within 'Aircraft' Trait."; } }
public override string Description
{
get
{
return "The 'TakeOffSound' and 'LandingSound' parameters within 'Aircraft' have been changed\n" +
"to accept an array of playable sounds.\n" +
"They were renamed to 'TakeOffSounds' and 'LandingSounds' respectively, to reflect this change.\n" +
"Definitions of 'TakeOffSound' and 'LandingSound' will be automatically renamed.";
}
}
public override IEnumerable<string> UpdateActorNode(ModData modData, MiniYamlNode actorNode)
{
foreach (var aircraft in actorNode.ChildrenMatching("Aircraft"))
{
aircraft.RenameChildrenMatching("TakeOffSound", "TakeOffSounds");
aircraft.RenameChildrenMatching("LandingSound", "LandingSounds");
}
yield break;
}
}
}

View File

@@ -1,54 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007-2020 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 CloakRequiresConditionToPause : UpdateRule
{
public override string Name { get { return "Change Cloak>RequiresCondition to PauseOnCondition"; } }
public override string Description
{
get
{
return "Disabling cloak trait now resets the delay to recloak to InitialCloakDelay.\n" +
"To keep the old behaviour, you should pause the trait instead.";
}
}
bool displayedMessage;
public override IEnumerable<string> AfterUpdate(ModData modData)
{
var message = "You may want to update the result of PauseOnCondition, as this update\n" +
"just adds ! prefix to RequiresCondition's value to reverse it.";
if (!displayedMessage)
yield return message;
displayedMessage = true;
}
public override IEnumerable<string> UpdateActorNode(ModData modData, MiniYamlNode actorNode)
{
foreach (var node in actorNode.ChildrenMatching("Cloak").Where(t => t.ChildrenMatching("RequiresCondition").Any()))
{
var rc = node.LastChildMatching("RequiresCondition");
rc.ReplaceValue("!(" + rc.Value.Value + ")");
rc.RenameKey("PauseOnCondition");
}
yield break;
}
}
}

View File

@@ -1,61 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007-2020 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 DefineLevelUpImageDefault : UpdateRule
{
public override string Name { get { return "Unhardcoded LevelUpImage and LevelUpSequence on GainsExperience"; } }
public override string Description
{
get
{
return "GainsExperience was hardcoded to play a 'levelup' crate effect from 'crate-effects' image.";
}
}
static readonly string[] CrateActionTraits =
{
"DuplicateUnitCrateAction",
"ExplodeCrateAction",
"GiveCashCrateAction",
"GiveMcvCrateAction",
"GiveUnitCrateAction",
"GrantExternalConditionCrateAction",
"HealUnitsCrateAction",
"HideMapCrateAction",
"LevelUpCrateAction",
"RevealMapCrateAction",
"SupportPowerCrateAction"
};
public override IEnumerable<string> UpdateActorNode(ModData modData, MiniYamlNode actorNode)
{
var levelUpImageNode = new MiniYamlNode("LevelUpImage", "crate-effects");
foreach (var ge in actorNode.ChildrenMatching("GainsExperience"))
ge.AddNode(levelUpImageNode);
foreach (var t in CrateActionTraits)
{
foreach (var ca in actorNode.ChildrenMatching(t))
{
var effect = ca.LastChildMatching("Effect");
if (effect != null)
effect.RenameKey("Sequence");
}
}
yield break;
}
}
}

View File

@@ -1,151 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007-2020 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 DefineNotificationDefaults : UpdateRule
{
public override string Name { get { return "Move mod-specific notifications to yaml"; } }
public override string Description
{
get
{
return "Mod-specific default notifications values have been removed from several traits and the Radar widget\n" +
"(" + traits.Select(f => f.Trait).JoinWith(", ") + ")\n" +
"The mod chrome is updated automatically and uses of these traits are listed for inspection so the values can be overriden in yaml.";
}
}
class TraitWrapper
{
public readonly string Trait;
public readonly Dictionary<string, string> Fields;
public List<string> Uses = new List<string>();
public TraitWrapper(string trait, Dictionary<string, string> fields)
{
Trait = trait;
Fields = fields;
}
}
TraitWrapper[] traits =
{
new TraitWrapper("PrimaryBuilding", new Dictionary<string, string>
{
{ "SelectionNotification", "PrimaryBuildingSelected" }
}),
new TraitWrapper("RepairableBuilding", new Dictionary<string, string>
{
{ "RepairingNotification", "Repairing" }
}),
new TraitWrapper("RepairsUnits", new Dictionary<string, string>
{
{ "StartRepairingNotification", "Repairing" }
}),
new TraitWrapper("GainsExperience", new Dictionary<string, string>
{
{ "LevelUpNotification", "LevelUp" }
}),
new TraitWrapper("MissionObjectives", new Dictionary<string, string>
{
{ "WinNotification", "Win" },
{ "LoseNotification", "Lose" },
{ "LeaveNotification", "Leave" }
}),
new TraitWrapper("PlaceBuilding", new Dictionary<string, string>
{
{ "NewOptionsNotification", "NewOptions" },
{ "CannotPlaceNotification", "BuildingCannotPlaceAudio" }
}),
new TraitWrapper("PlayerResources", new Dictionary<string, string>
{
{ "CashTickUpNotification", "CashTickUp" },
{ "CashTickDownNotification", "CashTickDown" }
}),
new TraitWrapper("ProductionQueue", new Dictionary<string, string>
{
{ "ReadyAudio", "UnitReady" },
{ "BlockedAudio", "NoBuild" },
{ "QueuedAudio", "Training" },
{ "OnHoldAudio", "OnHold" },
{ "CancelledAudio", "Cancelled" }
}),
new TraitWrapper("PowerManager", new Dictionary<string, string>
{
{ "SpeechNotification", "LowPower" }
}),
new TraitWrapper("Infiltrates", new Dictionary<string, string>
{
{ "Notification", "BuildingInfiltrated" }
})
};
string BuildMessage(TraitWrapper t)
{
return "Default notification values have been removed from {0}.\n".F(t.Trait) +
"You may wish to explicitly define the following overrides:\n " + t.Trait + ":\n" +
UpdateUtils.FormatMessageList(t.Fields.Select(kv => " " + kv.Key + ": " + kv.Value), separator: " ") +
"\non the following actors (if they have not already been inherited from a parent).\n" +
UpdateUtils.FormatMessageList(t.Uses);
}
public override IEnumerable<string> AfterUpdate(ModData modData)
{
foreach (var t in traits)
{
if (t.Uses.Any())
yield return BuildMessage(t);
t.Uses.Clear();
}
}
public override IEnumerable<string> UpdateActorNode(ModData modData, MiniYamlNode actorNode)
{
foreach (var t in traits)
{
foreach (var traitNode in actorNode.ChildrenMatching(t.Trait))
{
foreach (var f in t.Fields)
{
var node = traitNode.LastChildMatching(f.Key);
if (node == null)
{
var location = "{0} ({1})".F(actorNode.Key, traitNode.Location.Filename);
if (!t.Uses.Contains(location))
t.Uses.Add(location);
}
}
}
}
yield break;
}
public override IEnumerable<string> UpdateChromeNode(ModData modData, MiniYamlNode chromeNode)
{
foreach (var node in chromeNode.ChildrenMatching("Radar"))
{
if (!node.ChildrenMatching("SoundUp").Any())
node.AddNode("SoundUp", "RadarUp");
if (!node.ChildrenMatching("SoundDown").Any())
node.AddNode("SoundDown", "RadarDown");
}
yield break;
}
}
}

View File

@@ -1,481 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007-2020 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 ExtractHackyAIModules : UpdateRule
{
public override string Name { get { return "Split HackyAI logic handling to BotModules"; } }
public override string Description
{
get
{
return "Most properties and logic are being moved from HackyAI\n" +
"to *BotModules.";
}
}
readonly List<string> locations = new List<string>();
bool messageShown;
readonly string[] harvesterFields =
{
"HarvesterEnemyAvoidanceRadius", "AssignRolesInterval"
};
readonly string[] supportPowerFields =
{
"SupportPowerDecisions"
};
readonly string[] baseBuilderFields =
{
"BuildingQueues",
"DefenseQueues",
"MinimumExcessPower",
"MaximumExcessPower",
"ExcessPowerIncrement",
"ExcessPowerIncreaseThreshold",
"StructureProductionInactiveDelay",
"StructureProductionActiveDelay",
"StructureProductionRandomBonusDelay",
"StructureProductionResumeDelay",
"MaximumFailedPlacementAttempts",
"MaxResourceCellsToCheck",
"CheckForNewBasesDelay",
"MinBaseRadius",
"MaxBaseRadius",
"MinimumDefenseRadius",
"MaximumDefenseRadius",
"RallyPointScanRadius",
"CheckForWaterRadius",
"WaterTerrainTypes",
"NewProductionCashThreshold",
"BuildingCommonNames",
"BuildingLimits",
"BuildingFractions",
};
readonly string[] copyBaseBuilderFields =
{
"MinBaseRadius",
"MaxBaseRadius",
};
readonly string[] captureManagerFields =
{
"CapturingActorTypes",
"CapturableActorTypes",
"MinimumCaptureDelay",
"MaximumCaptureTargetOptions",
"CheckCaptureTargetsForVisibility",
"CapturableStances",
};
readonly string[] squadManagerFields =
{
"SquadSize",
"SquadSizeRandomBonus",
"AssignRolesInterval",
"RushInterval",
"AttackForceInterval",
"MinimumAttackForceDelay",
"RushAttackScanRadius",
"ProtectUnitScanRadius",
"MaxBaseRadius",
"MaximumDefenseRadius",
"IdleScanRadius",
"DangerScanRadius",
"AttackScanRadius",
"ProtectionScanRadius",
"UnitsCommonNames",
"BuildingCommonNames",
};
readonly string[] squadManagerCommonNames =
{
"ConstructionYard",
"NavalProduction",
};
readonly string[] unitBuilderFields =
{
"IdleBaseUnitsMaximum",
"UnitQueues",
"UnitsToBuild",
"UnitLimits",
};
readonly string[] mcvManagerFields =
{
"AssignRolesInterval",
"MinBaseRadius",
"MaxBaseRadius",
"RestrictMCVDeploymentFallbackToBase",
"UnitsCommonNames",
"BuildingCommonNames",
};
public override IEnumerable<string> AfterUpdate(ModData modData)
{
if (!messageShown)
yield return "You may want to check your AI yamls for possible redundant module entries.\n" +
"Additionally, make sure the Player actor has the ConditionManager trait and add it manually if it doesn't.";
messageShown = true;
if (locations.Any())
yield return "This update rule can only autoamtically update the base HackyAI definitions,\n" +
"not any overrides in other files (unless they redefine Type).\n" +
"You will have to manually check and possibly update the following locations:\n" +
UpdateUtils.FormatMessageList(locations);
locations.Clear();
}
public override IEnumerable<string> UpdateActorNode(ModData modData, MiniYamlNode actorNode)
{
if (actorNode.Key != "Player")
yield break;
var dummyAIs = actorNode.ChildrenMatching("DummyAI");
foreach (var dummyAINode in dummyAIs)
dummyAINode.RenameKey("DummyBot");
var hackyAIRemovals = actorNode.ChildrenMatching("-HackyAI");
foreach (var hackyAIRemovalNode in hackyAIRemovals)
hackyAIRemovalNode.RenameKey("-ModularBot");
var hackyAIs = actorNode.ChildrenMatching("HackyAI", includeRemovals: false);
if (!hackyAIs.Any())
yield break;
var addNodes = new List<MiniYamlNode>();
// We add a 'default' HarvesterBotModule in any case (unless the file doesn't contain any HackyAI base definition),
// and only add more for AIs that define custom values for one of its fields.
var defaultHarvNode = new MiniYamlNode("HarvesterBotModule", "");
// We add a 'default' BuildingRepairBotModule in any case,
// and just don't enable it for AIs that had 'ShouldRepairBuildings: false'.
var defaultRepairNode = new MiniYamlNode("BuildingRepairBotModule", "");
foreach (var hackyAINode in hackyAIs)
{
// HackyAIInfo.Name might contain spaces, so Type is better suited to be used as condition name.
// Type can be 'null' if the place we're updating is overriding the default rules (like a map's rules.yaml).
// If that's the case, it's better to not perform most of the updates on this particular yaml file,
// as most - or more likely all - necessary updates will already have been performed on the base ai yaml.
var aiTypeNode = hackyAINode.LastChildMatching("Type");
var aiType = aiTypeNode != null ? aiTypeNode.NodeValue<string>() : null;
if (aiType == null)
{
locations.Add("{0} ({1})".F(hackyAINode.Key, hackyAINode.Location.Filename));
continue;
}
var conditionString = "enable-" + aiType + "-ai";
var addGrantConditionOnBotOwner = true;
// Don't add GrantConditionOnBotOwner if it's already been added with matching condition
var grantBotConditions = actorNode.ChildrenMatching("GrantConditionOnBotOwner");
foreach (var grant in grantBotConditions)
if (grant.LastChildMatching("Condition").NodeValue<string>() == conditionString)
addGrantConditionOnBotOwner = false;
if (addGrantConditionOnBotOwner)
{
var grantNode = new MiniYamlNode("GrantConditionOnBotOwner@" + aiType, "");
var grantCondition = new MiniYamlNode("Condition", conditionString);
var bot = new MiniYamlNode("Bots", aiType);
grantNode.AddNode(grantCondition);
grantNode.AddNode(bot);
addNodes.Add(grantNode);
}
if (harvesterFields.Any(f => hackyAINode.ChildrenMatching(f).Any()))
{
var harvNode = new MiniYamlNode("HarvesterBotModule@" + aiType, "");
harvNode.AddNode(new MiniYamlNode("RequiresCondition", conditionString));
foreach (var hf in harvesterFields)
{
var fieldNode = hackyAINode.LastChildMatching(hf);
if (fieldNode != null)
{
if (hf == "AssignRolesInterval")
fieldNode.MoveAndRenameNode(hackyAINode, harvNode, "ScanForIdleHarvestersInterval");
else
fieldNode.MoveNode(hackyAINode, harvNode);
}
}
addNodes.Add(harvNode);
}
else
{
// We want the default harvester module to be enabled for every AI that didn't customise one of its fields,
// so we need to update RequiresCondition to be enabled on any of the conditions granted by these AIs,
// but only if the condition hasn't been added yet.
var requiresConditionNode = defaultHarvNode.LastChildMatching("RequiresCondition");
if (requiresConditionNode == null)
defaultHarvNode.AddNode(new MiniYamlNode("RequiresCondition", conditionString));
else
{
var oldValue = requiresConditionNode.NodeValue<string>();
if (oldValue.Contains(conditionString))
continue;
requiresConditionNode.ReplaceValue(oldValue + " || " + conditionString);
}
}
if (supportPowerFields.Any(f => hackyAINode.ChildrenMatching(f).Any()))
{
var spNode = new MiniYamlNode("SupportPowerBotModule@" + aiType, "");
spNode.AddNode(new MiniYamlNode("RequiresCondition", conditionString));
foreach (var spf in supportPowerFields)
{
var fieldNode = hackyAINode.LastChildMatching(spf);
if (fieldNode != null)
fieldNode.MoveAndRenameNode(hackyAINode, spNode, "Decisions");
}
addNodes.Add(spNode);
}
if (baseBuilderFields.Any(f => hackyAINode.ChildrenMatching(f).Any()))
{
var bmNode = new MiniYamlNode("BaseBuilderBotModule@" + aiType, "");
bmNode.AddNode(new MiniYamlNode("RequiresCondition", conditionString));
foreach (var bmf in baseBuilderFields)
{
var fieldNode = hackyAINode.LastChildMatching(bmf);
if (fieldNode != null)
{
if (fieldNode.KeyMatches("BuildingFractions", includeRemovals: false))
{
var buildingNodes = fieldNode.Value.Nodes;
foreach (var n in buildingNodes)
ConvertFractionToInteger(n);
}
if (copyBaseBuilderFields.Any(f => f == bmf))
bmNode.AddNode(fieldNode);
else if (fieldNode.KeyMatches("BuildingCommonNames", includeRemovals: false))
foreach (var n in fieldNode.Value.Nodes)
bmNode.AddNode(n.Key + "Types", n.Value.Value);
else
fieldNode.MoveNode(hackyAINode, bmNode);
}
}
addNodes.Add(bmNode);
}
// We want the default repair module to be enabled for every AI that didn't disable 'ShouldRepairBuildings',
// so we need to update RequiresCondition to be enabled on any of the conditions granted by these AIs,
// but only if the condition hasn't been added yet.
var shouldRepairNode = hackyAINode.LastChildMatching("ShouldRepairBuildings");
var enableBuildingRepair = shouldRepairNode == null || shouldRepairNode.NodeValue<bool>();
if (enableBuildingRepair)
{
var requiresConditionNode = defaultRepairNode.LastChildMatching("RequiresCondition");
if (requiresConditionNode == null)
defaultRepairNode.AddNode(new MiniYamlNode("RequiresCondition", conditionString));
else
{
var oldValue = requiresConditionNode.NodeValue<string>();
if (oldValue.Contains(conditionString))
continue;
requiresConditionNode.ReplaceValue(oldValue + " || " + conditionString);
}
}
if (captureManagerFields.Any(f => hackyAINode.ChildrenMatching(f).Any()))
{
var node = new MiniYamlNode("CaptureManagerBotModule@" + aiType, "");
node.AddNode(new MiniYamlNode("RequiresCondition", conditionString));
foreach (var field in captureManagerFields)
{
var fieldNode = hackyAINode.LastChildMatching(field);
if (fieldNode != null)
fieldNode.MoveNode(hackyAINode, node);
}
addNodes.Add(node);
}
if (squadManagerFields.Any(f => hackyAINode.ChildrenMatching(f).Any()))
{
var node = new MiniYamlNode("SquadManagerBotModule@" + aiType, "");
node.AddNode(new MiniYamlNode("RequiresCondition", conditionString));
foreach (var field in squadManagerFields)
{
var fieldNode = hackyAINode.LastChildMatching(field);
if (fieldNode != null)
{
if (fieldNode.KeyMatches("UnitsCommonNames", includeRemovals: false))
{
var mcvNode = fieldNode.LastChildMatching("Mcv");
var excludeNode = fieldNode.LastChildMatching("ExcludeFromSquads");
var navalUnitsNode = fieldNode.LastChildMatching("NavalUnits");
// In the old code, actors listed under Mcv were also excluded from squads.
// However, Mcv[Types] is moved to McvManagerBotModule now, so we need to add them under ExcludeFromSquads as well.
if (excludeNode == null && mcvNode != null)
node.AddNode("ExcludeFromSquadsTypes", mcvNode.Value.Value);
else if (excludeNode != null && mcvNode != null)
{
var mcvValue = mcvNode.NodeValue<string>();
var excludeValue = excludeNode.NodeValue<string>();
node.AddNode("ExcludeFromSquadsTypes", excludeValue + ", " + mcvValue);
}
if (navalUnitsNode != null)
node.AddNode("NavalUnitsTypes", navalUnitsNode.Value.Value);
}
else if (fieldNode.KeyMatches("BuildingCommonNames", includeRemovals: false))
{
foreach (var b in fieldNode.Value.Nodes)
if (squadManagerCommonNames.Any(f => f == b.Key))
node.AddNode(b.Key + "Types", b.Value.Value);
}
else if (fieldNode.KeyMatches("AssignRolesInterval") || fieldNode.KeyMatches("MaxBaseRadius"))
node.AddNode(fieldNode.Key, fieldNode.Value.Value);
else
fieldNode.MoveNode(hackyAINode, node);
}
}
addNodes.Add(node);
}
if (unitBuilderFields.Any(f => hackyAINode.ChildrenMatching(f).Any()))
{
var node = new MiniYamlNode("UnitBuilderBotModule@" + aiType, "");
node.AddNode(new MiniYamlNode("RequiresCondition", conditionString));
foreach (var field in unitBuilderFields)
{
var fieldNode = hackyAINode.LastChildMatching(field);
if (fieldNode != null)
{
if (fieldNode.KeyMatches("UnitsToBuild", includeRemovals: false))
{
var unitNodes = fieldNode.Value.Nodes;
foreach (var n in unitNodes)
ConvertFractionToInteger(n);
}
fieldNode.MoveNode(hackyAINode, node);
}
}
addNodes.Add(node);
}
if (mcvManagerFields.Any(f => hackyAINode.ChildrenMatching(f).Any()))
{
var node = new MiniYamlNode("McvManagerBotModule@" + aiType, "");
node.AddNode(new MiniYamlNode("RequiresCondition", conditionString));
foreach (var field in mcvManagerFields)
{
var fieldNode = hackyAINode.LastChildMatching(field);
if (fieldNode != null)
{
if (fieldNode.KeyMatches("UnitsCommonNames", includeRemovals: false))
{
var mcvNode = fieldNode.LastChildMatching("Mcv");
if (mcvNode != null)
mcvNode.MoveAndRenameNode(hackyAINode, node, "McvTypes");
// Nothing left that needs UnitCommonNames, so we can finally remove it
hackyAINode.RemoveNode(fieldNode);
}
else if (fieldNode.KeyMatches("BuildingCommonNames", includeRemovals: false))
{
foreach (var n in fieldNode.Value.Nodes)
{
if (n.KeyMatches("VehiclesFactory"))
node.AddNode("McvFactoryTypes", n.Value.Value);
else if (n.KeyMatches("ConstructionYard"))
node.AddNode("ConstructionYardTypes", n.Value.Value);
}
// Nothing left that needs BuildingCommonNames, so we can finally remove it
hackyAINode.RemoveNode(fieldNode);
}
else
fieldNode.MoveNode(hackyAINode, node);
}
}
addNodes.Add(node);
}
hackyAINode.RenameKey("ModularBot");
}
// Only add module if any bot is using/enabling it.
var harvRequiresConditionNode = defaultHarvNode.LastChildMatching("RequiresCondition");
if (harvRequiresConditionNode != null)
addNodes.Add(defaultHarvNode);
// Only add module if any bot is using/enabling it.
var repRequiresConditionNode = defaultRepairNode.LastChildMatching("RequiresCondition");
if (repRequiresConditionNode != null)
addNodes.Add(defaultRepairNode);
foreach (var node in addNodes)
actorNode.AddNode(node);
yield break;
}
void ConvertFractionToInteger(MiniYamlNode node)
{
// Is the value a percentage or a 'real' float?
var isPercentage = node.NodeValue<string>().Contains("%");
if (isPercentage)
{
// Remove '%' first, then remove potential '.' and finally clamp to minimum of 1, unless the old value was really zero
var oldValueAsString = node.NodeValue<string>().Split('%')[0];
var oldValueWasZero = oldValueAsString == "0";
var newValue = oldValueAsString.Split('.')[0];
newValue = !oldValueWasZero && newValue == "0" ? "1" : newValue;
node.ReplaceValue(newValue);
}
else
{
var oldValueAsFloat = node.NodeValue<float>();
var oldValueWasZero = node.NodeValue<string>() == "0" || node.NodeValue<string>() == "0.0";
var newValue = (int)(oldValueAsFloat * 100);
// Clamp to minimum of 1, unless the old value was really zero
newValue = !oldValueWasZero && newValue == 0 ? 1 : newValue;
node.ReplaceValue(newValue.ToString());
}
}
}
}

View File

@@ -1,54 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007-2020 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 LowPowerSlowdownToModifier : UpdateRule
{
public override string Name { get { return "LowPowerSlowdown is renamed to LowPowerModifier"; } }
public override string Description
{
get
{
return "ProductionQueue.LowPowerSlowdown is renamed to LowPowerModifier, and\n" +
"multiplied by 100 to allow multiplying the build time with non-integer values.\n" +
"Also default value is changed to 100.";
}
}
readonly string[] queueTraits = { "ProductionQueue", "ClassicProductionQueue" };
public override IEnumerable<string> UpdateActorNode(ModData modData, MiniYamlNode actorNode)
{
foreach (var queue in queueTraits.SelectMany(t => actorNode.ChildrenMatching(t)))
{
var lowPower = queue.LastChildMatching("LowPowerSlowdown");
if (lowPower != null)
{
if (lowPower.NodeValue<int>() == 1)
queue.RemoveNodes("LowPowerSlowdown");
else
{
lowPower.RenameKey("LowPowerModifier");
lowPower.ReplaceValue((lowPower.NodeValue<int>() * 100).ToString());
}
}
else
queue.AddNode("LowPowerModifier", "300");
}
yield break;
}
}
}

View File

@@ -1,79 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007-2020 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 MergeAttackPlaneAndHeli : UpdateRule
{
public override string Name { get { return "AttackPlane and AttackHeli were merged to AttackAircraft"; } }
public override string Description
{
get
{
return "The AttackPlane and AttackHeli traits were merged intto a single\n" +
"AttackAircraft trait.";
}
}
bool displayedMessage;
public override IEnumerable<string> AfterUpdate(ModData modData)
{
var message = "If an actor had a total of more than one AttackPlane and/or AttackHeli,\n"
+ "you may want to check the update results for possible redundant entries.\n";
if (!displayedMessage)
yield return message;
displayedMessage = true;
}
public override IEnumerable<string> UpdateActorNode(ModData modData, MiniYamlNode actorNode)
{
var attackPlanes = actorNode.ChildrenMatching("AttackPlane");
var attackHelis = actorNode.ChildrenMatching("AttackHeli");
var attackPlanesTotal = attackPlanes.Count();
var attackHelisTotal = attackHelis.Count();
if (attackPlanesTotal == 0 && attackHelisTotal == 0)
yield break;
else if (attackPlanesTotal == 1 && attackHelisTotal == 0)
foreach (var attackPlane in attackPlanes)
attackPlane.RenameKey("AttackAircraft");
else if (attackPlanesTotal == 0 && attackHelisTotal == 1)
foreach (var attackHeli in attackHelis)
attackHeli.RenameKey("AttackAircraft");
else
{
// If we got here, we have at least two AttackPlane/-Heli traits in total
var attackPlanesCount = 0;
foreach (var attackPlane in attackPlanes)
{
var suffixCount = attackPlanesCount > 0 ? attackPlanesCount.ToString() : "";
attackPlane.RenameKey("AttackAircraft@Plane" + suffixCount, false, true);
++attackPlanesCount;
}
var attackHelisCount = 0;
foreach (var attackHeli in attackHelis)
{
var suffixCount = attackHelisCount > 0 ? attackHelisCount.ToString() : "";
attackHeli.RenameKey("AttackAircraft@Heli" + suffixCount, false, true);
++attackHelisCount;
}
}
yield break;
}
}
}

View File

@@ -1,153 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007-2020 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 MergeCaptureTraits : UpdateRule
{
public override string Name { get { return "Merge and overhaul Captures traits"; } }
public override string Description
{
get
{
return "The internal and external capturing traits have been merged, and a new\n" +
"CaptureManager trait has been added to help manage interactions between\n" +
"actors and multiple trait instances. The Sabotage logic has also\n" +
"moved from the Capturable trait to the Captures trait.\n" +
"The External* traits are renamed, and the CaptureManager added wherever\n" +
"the Capturable or Captures trait is used. The locations modified are\n" +
"listed for inspection and manual cleanup";
}
}
readonly List<string> captureManagerLocations = new List<string>();
readonly List<string> externalDelayLocations = new List<string>();
readonly List<string> sabotageLocations = new List<string>();
public override IEnumerable<string> AfterUpdate(ModData modData)
{
if (captureManagerLocations.Any())
yield return "The Captures and Capturable traits now depend on the\n" +
"new CaptureManager trait. This trait has automatically been added\n" +
"in the following definitions:\n" + UpdateUtils.FormatMessageList(captureManagerLocations) +
"\nYou may wish to review these definitions and delete any redundant\n" +
"instances that have already been inherited from a parent template.";
if (sabotageLocations.Any())
yield return "The sabotage logic has been disabled by default, which affects\n" +
"the following definitions:\n" + UpdateUtils.FormatMessageList(sabotageLocations) +
"\nThe sabotage logic is now defined on the Captures trait, via the \n" +
"SabotageThreshold field. You may need to define additional capture types\n" +
"and Capturable traits if you wish to use multiple capture thresholds.";
if (externalDelayLocations.Any())
yield return "The following actors have had their capture delays reset to 15 seconds:\n" +
UpdateUtils.FormatMessageList(sabotageLocations) +
"\nThe capture delay is now defined on the Captures trait, via the\n" +
"CaptureDelay field. You may need to define additional capture types\n" +
"and Capturable traits if you wish to use multiple capture delays.";
captureManagerLocations.Clear();
sabotageLocations.Clear();
externalDelayLocations.Clear();
}
public override IEnumerable<string> UpdateActorNode(ModData modData, MiniYamlNode actorNode)
{
var reportLocation = "{0} ({1})".F(actorNode.Key, actorNode.Location.Filename);
var captureManager = actorNode.LastChildMatching("CaptureManager") ?? new MiniYamlNode("CaptureManager", "");
var usesCaptureManager = false;
// Migrate External*
foreach (var c in actorNode.ChildrenMatching("ExternalCapturable"))
{
c.RenameKey("Capturable");
if (c.RemoveNodes("CaptureCompleteTime") > 0)
externalDelayLocations.Add(reportLocation);
}
foreach (var c in actorNode.ChildrenMatching("ExternalCaptures"))
{
c.RenameKey("Captures");
if (c.Key.StartsWith("-"))
continue;
c.AddNode("CaptureDelay", 375);
var consumeNode = c.LastChildMatching("ConsumeActor");
if (consumeNode != null)
consumeNode.RenameKey("ConsumedByCapture");
else
c.AddNode("ConsumedByCapture", false);
var conditionNode = c.LastChildMatching("CapturingCondition");
if (conditionNode != null)
conditionNode.MoveNode(c, captureManager);
var cursorNode = c.LastChildMatching("CaptureCursor");
if (cursorNode != null)
cursorNode.RenameKey("EnterCursor");
else
c.AddNode("EnterCursor", "ability");
var cursorBlockedNode = c.LastChildMatching("CaptureBlockedCursor");
if (cursorBlockedNode != null)
cursorBlockedNode.RenameKey("EnterBlockedCursor");
else
c.AddNode("EnterBlockedCursor", "move-blocked");
}
var addBlinker = false;
foreach (var c in actorNode.ChildrenMatching("ExternalCapturableBar"))
{
c.RenameKey("CapturableProgressBar");
addBlinker = true;
}
if (addBlinker)
actorNode.AddNode("CapturableProgressBlink", "");
// Remove any CaptureThreshold nodes and restore the "building" default
// These run on converted External* traits too
foreach (var traitNode in actorNode.ChildrenMatching("Capturable"))
{
if (!traitNode.Key.StartsWith("-"))
usesCaptureManager = true;
if (traitNode.RemoveNodes("CaptureThreshold") + traitNode.RemoveNodes("Sabotage") > 0)
sabotageLocations.Add(reportLocation);
if (!traitNode.Key.StartsWith("-") && traitNode.LastChildMatching("Types") == null)
traitNode.AddNode("Types", "building");
}
foreach (var traitNode in actorNode.ChildrenMatching("Captures"))
{
if (!traitNode.Key.StartsWith("-"))
usesCaptureManager = true;
if (traitNode.LastChildMatching("CaptureTypes") == null)
traitNode.AddNode("CaptureTypes", "building");
}
if (usesCaptureManager && actorNode.LastChildMatching("CaptureManager") == null)
{
actorNode.AddNode(captureManager);
captureManagerLocations.Add(reportLocation);
}
yield break;
}
}
}

View File

@@ -1,107 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007-2020 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 MergeRearmAndRepairAnimation : UpdateRule
{
public override string Name { get { return "WithRearmAnimation and WithRepairAnimation were merged to WithResupplyAnimation"; } }
public override string Description
{
get
{
return "The WithRearmAnimation and WithRepairAnimation traits were merged intto a single\n" +
"WithResupplyAnimation trait.";
}
}
bool displayedMessage;
public override IEnumerable<string> AfterUpdate(ModData modData)
{
var message = "If an actor had both a WithRearmAnimation and a WithRepairAnimation\n"
+ "or multiple traits of either type, you may want to check the update results for possible\n"
+ "redundant entries.\n";
if (!displayedMessage)
yield return message;
displayedMessage = true;
}
public override IEnumerable<string> UpdateActorNode(ModData modData, MiniYamlNode actorNode)
{
var rearmAnims = actorNode.ChildrenMatching("WithRearmAnimation");
var repairAnims = actorNode.ChildrenMatching("WithRepairAnimation");
var rearmAnimsTotal = rearmAnims.Count();
var repairAnimsTotal = repairAnims.Count();
if (rearmAnimsTotal == 0 && repairAnimsTotal == 0)
yield break;
else if (rearmAnimsTotal == 1 && repairAnimsTotal == 0)
foreach (var rearmAnim in rearmAnims)
rearmAnim.RenameKey("WithResupplyAnimation");
else if (rearmAnimsTotal == 0 && repairAnimsTotal == 1)
foreach (var repairAnim in repairAnims)
repairAnim.RenameKey("WithResupplyAnimation");
else if (rearmAnimsTotal == 1 && repairAnimsTotal == 1)
{
var rearmAnim = rearmAnims.First();
var repairAnim = repairAnims.First();
var rearmSequence = rearmAnim.LastChildMatching("Sequence");
var rearmBody = rearmAnim.LastChildMatching("Body");
var repairSequence = repairAnim.LastChildMatching("Sequence");
var repairBody = repairAnim.LastChildMatching("Body");
var matchingSequences = (rearmSequence == null && repairSequence == null)
|| (rearmSequence != null && repairSequence != null && rearmSequence.Value.Value == repairSequence.Value.Value);
var matchingBodies = (rearmBody == null && repairBody == null)
|| (rearmBody != null && repairBody != null && rearmBody.Value.Value == repairBody.Value.Value);
// If neither animation strays from the default values, we can safely merge them
if (matchingSequences && matchingBodies)
{
rearmAnim.RenameKey("WithResupplyAnimation");
actorNode.RemoveNode(repairAnim);
}
else
{
rearmAnim.RenameKey("WithResupplyAnimation@Rearm", false, true);
repairAnim.RenameKey("WithResupplyAnimation@Repair", false, true);
}
}
else
{
// If we got here, we have more than one of at least one of the two animation traits.
var rearmAnimCount = 0;
foreach (var rearmAnim in rearmAnims)
{
++rearmAnimCount;
rearmAnim.RenameKey("WithResupplyAnimation@Rearm" + rearmAnimCount.ToString(), false, true);
var playOnRearmNode = new MiniYamlNode("PlayAnimationOn", "Rearm");
rearmAnim.AddNode(playOnRearmNode);
}
var repairAnimCount = 0;
foreach (var repairAnim in repairAnims)
{
++repairAnimCount;
repairAnim.RenameKey("WithResupplyAnimation@Repair" + repairAnimCount.ToString(), false, true);
var playOnRepairNode = new MiniYamlNode("PlayAnimationOn", "Repair");
repairAnim.AddNode(playOnRepairNode);
}
}
yield break;
}
}
}

View File

@@ -1,76 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007-2020 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 RefactorResourceLevelAnimating : UpdateRule
{
public override string Name { get { return "Streamlined traits animating player resource level"; } }
public override string Description
{
get
{
return "Replaced WithSiloAnimation with WithResourceLevelSpriteBody and\n" +
"renamed WithResources to WithResourceLevelOverlay.";
}
}
readonly List<string> locations = new List<string>();
public override IEnumerable<string> AfterUpdate(ModData modData)
{
if (locations.Any())
yield return "WithSiloAnimation has been replaced by WithResourceLevelSpriteBody.\n" +
"You may need to disable/remove any previous (including inherited) *SpriteBody traits\n" +
"on the following actors:\n" +
UpdateUtils.FormatMessageList(locations);
locations.Clear();
}
public override IEnumerable<string> UpdateActorNode(ModData modData, MiniYamlNode actorNode)
{
foreach (var wr in actorNode.ChildrenMatching("WithResources"))
wr.RenameKey("WithResourceLevelOverlay");
var siloAnims = actorNode.ChildrenMatching("WithSiloAnimation");
foreach (var sa in siloAnims)
{
// If it's a trait removal, we only rename it.
if (sa.IsRemoval())
{
sa.RenameKey("WithResourceLevelSpriteBody");
continue;
}
var sequence = sa.LastChildMatching("Sequence");
var body = sa.LastChildMatching("Body");
if (sequence == null)
{
var newSequenceNode = new MiniYamlNode("Sequence", "stages");
sa.AddNode(newSequenceNode);
}
if (body != null)
sa.RemoveNode(body);
sa.RenameKey("WithResourceLevelSpriteBody");
locations.Add("{0} ({1})".F(actorNode.Key, sa.Location.Filename));
}
yield break;
}
}
}

View File

@@ -1,66 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007-2020 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 RemoveAttackIgnoresVisibility : UpdateRule
{
public override string Name { get { return "IgnoresVisibility has been removed from Attack* traits."; } }
public override string Description
{
get
{
return "The IgnoresVisibility flag has been removed from the Attack* traits as part of a\n" +
"wider rework of the fog-targeting behaviour. Mods that rely on this logic must\n" +
"implement their own Attack* trait, similar to the AttackSwallow trait.";
}
}
static readonly string[] Traits =
{
"AttackFrontal",
"AttackFollow",
"AttackTurreted",
"AttackOmni",
"AttackBomber",
"AttackPopupTurreted",
"AttackTesla",
"AttackSwallow"
};
readonly List<string> locations = new List<string>();
public override IEnumerable<string> AfterUpdate(ModData modData)
{
if (locations.Any())
yield return "The IgnoresVisibility flag has been removed from the targeting logic on the following actors:\n" +
UpdateUtils.FormatMessageList(locations) + "\n\n" +
"You may wish to enable TargetFrozenActors, or implement a custom Attack* trait like AttackSwallow\n" +
"if you require visibility to be completely ignored.";
locations.Clear();
}
public override IEnumerable<string> UpdateActorNode(ModData modData, MiniYamlNode actorNode)
{
foreach (var trait in Traits)
foreach (var t in actorNode.ChildrenMatching(trait))
if (t.RemoveNodes("IgnoresVisibility") > 0)
locations.Add("{0} ({1})".F(actorNode.Key, actorNode.Location.Filename));
yield break;
}
}
}

View File

@@ -1,51 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007-2020 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 RemoveAttackSuicides : UpdateRule
{
public override string Name { get { return "AttackSuicides trait has been removed."; } }
public override string Description
{
get
{
return "The AttackSuicides trait has been removed, and should be replaced by\n" +
"AttackFrontal + GrantConditionOnAttack + GrantConditionOnDeploy + a dummy\n" +
"weapon for targeting. Affected actors are listed so that these traits can be defined.";
}
}
readonly List<string> locations = new List<string>();
public override IEnumerable<string> AfterUpdate(ModData modData)
{
if (locations.Any())
yield return "The AttackSuicides trait has been removed from the following actors.\n" +
"You must manually define AttackFrontal, GrantConditionOnAttack, GrantConditionOnDeploy\n" +
"traits and create a dummy weapon to use for targeting:\n" +
UpdateUtils.FormatMessageList(locations);
locations.Clear();
}
public override IEnumerable<string> UpdateActorNode(ModData modData, MiniYamlNode actorNode)
{
if (actorNode.RemoveNodes("AttackSuicides") > 0)
locations.Add("{0} ({1})".F(actorNode.Key, actorNode.Location.Filename));
yield break;
}
}
}

View File

@@ -1,45 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007-2020 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 RemoveHealthPercentageRing : UpdateRule
{
public override string Name { get { return "Remove ring support from HealthPercentageDamage warheads' Spread"; } }
public override string Description
{
get
{
return "Setting a second value in this warheads' Spread to define a 'ring' is no longer supported.";
}
}
public override IEnumerable<string> UpdateWeaponNode(ModData modData, MiniYamlNode weaponNode)
{
foreach (var node in weaponNode.ChildrenMatching("Warhead"))
{
if (node.NodeValue<string>() == "HealthPercentageDamage")
{
foreach (var spreadNode in node.ChildrenMatching("Spread"))
{
var oldValue = spreadNode.NodeValue<string[]>();
if (oldValue.Length > 1)
spreadNode.ReplaceValue(oldValue[0]);
}
}
}
yield break;
}
}
}

View File

@@ -1,70 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007-2020 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 RemoveNegativeDamageFullHealthCheck : UpdateRule
{
public override string Name { get { return "Negative damage weapons are now valid against full-health targets."; } }
public override string Description
{
get
{
return "Negative-damage weapons are no longer automatically invalid against targets that have full health.\n" +
"Previous behaviour can be restored by enabling a Targetable trait using GrantConditionOnDamageState.\n" +
"Affected weapons are listed so that conditions may be manually defined.";
}
}
static readonly string[] DamageWarheads =
{
"TargetDamage",
"SpreadDamage",
"HealthPercentageDamage"
};
readonly Dictionary<string, List<string>> locations = new Dictionary<string, List<string>>();
public override IEnumerable<string> AfterUpdate(ModData modData)
{
if (locations.Any())
yield return "The following weapons may now target actors that have full health. Review their\n" +
"target types and, if necessary, use GrantConditionOnDamageState to enable\n" +
"a conditional Targetable trait with the appropriate target type when damaged:\n" +
UpdateUtils.FormatMessageList(locations.Select(
kv => kv.Key + ":\n" + UpdateUtils.FormatMessageList(kv.Value)));
locations.Clear();
}
public override IEnumerable<string> UpdateWeaponNode(ModData modData, MiniYamlNode weaponNode)
{
var used = new List<string>();
foreach (var node in weaponNode.ChildrenMatching("Warhead"))
{
foreach (var warhead in DamageWarheads)
if (node.NodeValue<string>() == warhead && node.ChildrenMatching("Damage").Any(d => d.NodeValue<int>() < 0))
used.Add(node.Key);
if (used.Any())
{
var location = "{0} ({1})".F(weaponNode.Key, node.Location.Filename);
locations[location] = used;
}
}
yield break;
}
}
}

View File

@@ -1,50 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007-2020 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 RemoveRepairBuildingsFromAircraft : UpdateRule
{
public override string Name { get { return "Removed RepairBuildings from Aircraft"; } }
public override string Description
{
get
{
return "Removed RepairBuildings from Aircraft in favor of using Repairable instead.";
}
}
public override IEnumerable<string> UpdateActorNode(ModData modData, MiniYamlNode actorNode)
{
// Aircraft isn't conditional or otherwise supports multiple traits, so LastChildMatching is fine.
var aircraftNode = actorNode.LastChildMatching("Aircraft");
if (aircraftNode != null)
{
var repairBuildings = aircraftNode.LastChildMatching("RepairBuildings");
if (repairBuildings != null)
{
var repariableNode = new MiniYamlNode("Repairable", "");
repairBuildings.MoveAndRenameNode(aircraftNode, repariableNode, "RepairBuildings");
var voice = aircraftNode.LastChildMatching("Voice");
if (voice != null)
repariableNode.AddNode(voice);
actorNode.AddNode(repariableNode);
}
}
yield break;
}
}
}

View File

@@ -1,49 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007-2020 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 RemoveResourceExplodeModifier : UpdateRule
{
public override string Name { get { return "Harvester and StoresResources traits no longer force Explodes.EmptyWeapon"; } }
public override string Description
{
get
{
return "The hardcoded behaviour forcing Explodes to use EmptyWeapon when the harvester/player has no\n" +
"resources has been removed. Affected actors are listed so that conditions may be manually defined.";
}
}
readonly List<string> locations = new List<string>();
public override IEnumerable<string> AfterUpdate(ModData modData)
{
if (locations.Any())
yield return "Review the following definitions and, if the actor uses Harvester or StoresResources,\n" +
"define a new Explodes trait with the previous EmptyWeapon, enabled by Harvester.EmptyCondition or\n" +
"GrantConditionOnPlayerResources.Condition (negated):\n" + UpdateUtils.FormatMessageList(locations);
locations.Clear();
}
public override IEnumerable<string> UpdateActorNode(ModData modData, MiniYamlNode actorNode)
{
if (actorNode.LastChildMatching("Explodes") != null)
locations.Add("{0} ({1})".F(actorNode.Key, actorNode.Location.Filename));
yield break;
}
}
}

View File

@@ -1,55 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007-2020 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 RemovedAutoCarryallCircleTurnSpeed : UpdateRule
{
public override string Name { get { return "Removed AutoCarryall idle circling turnspeed hardcoding"; } }
public override string Description
{
get
{
return "Aircraft that circle while idle despite having CanHover (AutoCarryall) have their\n" +
"turn speed during idle circling no longer hardcoded to 1/3 of regular TurnSpeed." +
"Note that the new IdleTurnSpeed override works on all aircraft that circle when idle.";
}
}
bool showMessage;
bool messageShown;
public override IEnumerable<string> AfterUpdate(ModData modData)
{
var message = "While circling idle, your AutoCarryall(s) will now turn at full TurnSpeed,\n" +
"unless you manually define a custom IdleTurnSpeed.";
if (showMessage && !messageShown)
yield return message;
showMessage = false;
messageShown = true;
}
public override IEnumerable<string> UpdateActorNode(ModData modData, MiniYamlNode actorNode)
{
var autoCarryall = actorNode.LastChildMatching("AutoCarryall");
if (autoCarryall == null)
yield break;
showMessage = true;
yield break;
}
}
}

View File

@@ -1,71 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007-2020 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 RemovedDemolishLocking : UpdateRule
{
public override string Name { get { return "Traits are no longer automatically disabled during the Demolition countdown"; } }
public override string Description
{
get
{
return "Traits are no longer force-disabled during the Demolishing trait destruction countdown.\n" +
"This affects the Production*, Transforms, Sellable, EjectOnDeath and ToggleConditionOnOrder traits.\n" +
"Affected actors are listed so that conditions may be manually defined.";
}
}
static readonly string[] Traits =
{
"Production",
"ProductionAirdrop",
"ProductionFromMapEdge",
"ProductionParadrop",
"Transforms",
"Sellable",
"ToggleConditionOnOrder",
"EjectOnDeath"
};
readonly Dictionary<string, List<string>> locations = new Dictionary<string, List<string>>();
public override IEnumerable<string> AfterUpdate(ModData modData)
{
if (locations.Any())
yield return "Review the following definitions and, if the actor is Demolishable,\n" +
"define Demolishable.Condition and use this condition to disable them:\n" +
UpdateUtils.FormatMessageList(locations.Select(
kv => kv.Key + ":\n" + UpdateUtils.FormatMessageList(kv.Value)));
locations.Clear();
}
public override IEnumerable<string> UpdateActorNode(ModData modData, MiniYamlNode actorNode)
{
var used = new List<string>();
foreach (var t in Traits)
if (actorNode.LastChildMatching(t, includeRemovals: false) != null)
used.Add(t);
if (used.Any())
{
var location = "{0} ({1})".F(actorNode.Key, actorNode.Location.Filename);
locations[location] = used;
}
yield break;
}
}
}

View File

@@ -1,111 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007-2020 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 RemovedNotifyBuildComplete : UpdateRule
{
public override string Name { get { return "Traits are no longer automatically disabled during Building make-animations"; } }
public override string Description
{
get
{
return "Traits are no longer force-disabled while the WithMakeAnimation trait is active.\n" +
"This affects the With*Animation, With*Overlay, *Production, Attack*,\n" +
"Transforms, Sellable, Gate, ToggleConditionOnOrder, and ConyardChronoReturn traits.\n" +
"The AnnounceOnBuild trait has been replaced with a new VoiceAnnouncement trait.\n" +
"Affected actors are listed so that conditions may be manually defined.";
}
}
static readonly string[] Traits =
{
"WithAcceptDeliveredCashAnimation",
"WithBuildingPlacedAnimation",
"WithBuildingPlacedOverlay",
"WithChargeAnimation",
"WithChargeOverlay",
"WithDockedOverlay",
"WithIdleAnimation",
"WithIdleOverlay",
"WithNukeLaunchAnimation",
"WithNukeLaunchOverlay",
"WithProductionDoorOverlay",
"WithProductionOverlay",
"WithRepairOverlay",
"WithResources",
"WithResupplyAnimation",
"WithSiloAnimation",
"WithSpriteTurret",
"WithVoxelBarrel",
"WithVoxelTurret",
"WithDeliveryAnimation",
"WithCrumbleOverlay",
"WithDeliveryOverlay",
"Production",
"ProductionAirdrop",
"ProductionFromMapEdge",
"ProductionParadrop",
"AttackFrontal",
"AttackFollow",
"AttackTurreted",
"AttackOmni",
"AttackBomber",
"AttackPopupTurreted",
"AttackTesla",
"Transforms",
"Sellable",
"Gate",
"ConyardChronoReturn",
"ToggleConditionOnOrder",
"VoiceAnnouncement"
};
readonly Dictionary<string, List<string>> locations = new Dictionary<string, List<string>>();
public override IEnumerable<string> AfterUpdate(ModData modData)
{
if (locations.Any())
yield return "Review the following definitions and, for those that are buildings,\n" +
"define conditions to disable them while WithMakeAnimation is active:\n" +
UpdateUtils.FormatMessageList(locations.Select(
kv => kv.Key + ":\n" + UpdateUtils.FormatMessageList(kv.Value)));
locations.Clear();
}
public override IEnumerable<string> UpdateActorNode(ModData modData, MiniYamlNode actorNode)
{
foreach (var announce in actorNode.ChildrenMatching("AnnounceOnBuild"))
{
announce.RenameKey("VoiceAnnouncement");
if (announce.LastChildMatching("Voice") == null)
announce.AddNode("Voice", "Build");
}
var used = new List<string>();
foreach (var t in Traits)
if (actorNode.LastChildMatching(t) != null)
used.Add(t);
if (used.Any())
{
var location = "{0} ({1})".F(actorNode.Key, actorNode.Location.Filename);
locations[location] = used;
}
yield break;
}
}
}

View File

@@ -1,52 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007-2020 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 RenameCrateActionNotification : UpdateRule
{
public override string Name { get { return "*CrateAction>Notification renamed to Sound"; } }
public override string Description
{
get
{
return "'*CrateAction' traits now have an actual `Notification` field.\n" +
"The new `Sound` field does what the old `Notification` did.";
}
}
string[] traits =
{
"DuplicateUnitCrateAction",
"ExplodeCrateAction",
"GiveCashCrateAction",
"GiveMcvCrateAction",
"GiveUnitCrateAction",
"GrantExternalConditionCrateAction",
"HealUnitsCrateAction",
"HideMapCrateAction",
"LevelUpCrateAction",
"RevelMapCrateAction",
"SupportPowerCrateAction"
};
public override IEnumerable<string> UpdateActorNode(ModData modData, MiniYamlNode actorNode)
{
foreach (var trait in traits)
foreach (var action in actorNode.ChildrenMatching(trait))
action.RenameChildrenMatching("Notification", "Sound");
yield break;
}
}
}

View File

@@ -1,35 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007-2020 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 RenameEditorTilesetFilter : UpdateRule
{
public override string Name { get { return "EditorTilesetFilter renamed to MapEditorData"; } }
public override string Description
{
get
{
return "The name EditorTilesetFilter was misleading and was renamed to MapEditorData.";
}
}
public override IEnumerable<string> UpdateActorNode(ModData modData, MiniYamlNode actorNode)
{
foreach (var data in actorNode.ChildrenMatching("EditorTilesetFilter"))
data.RenameKey("MapEditorData");
yield break;
}
}
}

View File

@@ -1,73 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007-2020 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 ReplacedWithChargeAnimation : UpdateRule
{
public override string Name { get { return "Replaced WithChargeAnimation with WithChargeSpriteBody"; } }
public override string Description
{
get
{
return "Replaced WithChargeAnimation with WithChargeSpriteBody.";
}
}
readonly List<string> locations = new List<string>();
public override IEnumerable<string> AfterUpdate(ModData modData)
{
if (locations.Any())
yield return "WithChargeAnimation has been replaced by WithChargeSpriteBody.\n" +
"You may need to disable/remove any previous (including inherited) *SpriteBody traits\n" +
"on the following actors:\n" +
UpdateUtils.FormatMessageList(locations);
locations.Clear();
}
public override IEnumerable<string> UpdateActorNode(ModData modData, MiniYamlNode actorNode)
{
var chargeAnims = actorNode.ChildrenMatching("WithChargeAnimation");
foreach (var ca in chargeAnims)
{
// If it's a trait removal, we only rename it.
if (ca.IsRemoval())
{
ca.RenameKey("WithChargeSpriteBody");
continue;
}
var sequence = ca.LastChildMatching("Sequence");
var body = ca.LastChildMatching("Body");
if (sequence == null)
{
var newSequenceNode = new MiniYamlNode("Sequence", "active");
ca.AddNode(newSequenceNode);
}
if (body != null)
ca.RemoveNode(body);
ca.RenameKey("WithChargeSpriteBody");
locations.Add("{0} ({1})".F(actorNode.Key, ca.Location.Filename));
}
yield break;
}
}
}

View File

@@ -1,63 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007-2020 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 RequireProductionType : UpdateRule
{
public override string Name { get { return "Require 'ProductionType' on 'ProductionBar'"; } }
public override string Description
{
get
{
return "The 'ProductionBar' trait now requires the 'ProductionType' to be set.\n" +
"The value will be automatically set to the first value in 'Produces' of the first 'Production' trait.";
}
}
readonly string[] productionTraits = { "Production", "ProductionAirdrop", "ProductionParadrop", "ProductionFromMapEdge" };
public override IEnumerable<string> UpdateActorNode(ModData modData, MiniYamlNode actorNode)
{
foreach (var pb in actorNode.ChildrenMatching("ProductionBar"))
{
var type = pb.LastChildMatching("ProductionType");
if (type != null)
continue;
MiniYamlNode production = null;
foreach (var trait in productionTraits)
{
if (production != null)
break;
production = actorNode.ChildrenMatching(trait).FirstOrDefault();
}
if (production == null)
continue;
var produces = production.LastChildMatching("Produces");
if (produces == null)
continue;
var toAdd = produces.NodeValue<string[]>().FirstOrDefault();
if (toAdd != null)
pb.AddNode("ProductionType", toAdd);
}
yield break;
}
}
}

View File

@@ -34,35 +34,6 @@ namespace OpenRA.Mods.Common.UpdateRules
Justification = "Extracting update lists to temporary variables obfuscates the definitions.")]
static readonly UpdatePath[] Paths =
{
new UpdatePath("release-20181215", "release-20190314", new UpdateRule[]
{
new AddCarryableHarvester(),
new RenameEditorTilesetFilter(),
new DefineNotificationDefaults(),
new MergeRearmAndRepairAnimation(),
new MergeCaptureTraits(),
new RemovedNotifyBuildComplete(),
new LowPowerSlowdownToModifier(),
new ChangeTakeOffSoundAndLandingSound(),
new RemoveHealthPercentageRing(),
new RenameCrateActionNotification(),
new RemoveRepairBuildingsFromAircraft(),
new AddRearmable(),
new MergeAttackPlaneAndHeli(),
new RemovedDemolishLocking(),
new RequireProductionType(),
new CloakRequiresConditionToPause(),
new ExtractHackyAIModules(),
new RemoveNegativeDamageFullHealthCheck(),
new RemoveResourceExplodeModifier(),
new DefineLevelUpImageDefault(),
new RemovedAutoCarryallCircleTurnSpeed(),
new RemoveAttackIgnoresVisibility(),
new ReplacedWithChargeAnimation(),
new RefactorResourceLevelAnimating(),
new RemoveAttackSuicides(),
}),
new UpdatePath("release-20190314", "release-20191117", new UpdateRule[]
{
new MultipleDeploySounds(),