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;
}
}
}