Remove upgrade rules older than release 20160508

Modders will have to use release 20160508 to apply upgrade rules written
between release 20151224 and 20160508.
This commit is contained in:
reaperrr
2016-05-28 15:35:04 +02:00
parent 629f17b430
commit b7644df40a

View File

@@ -24,7 +24,7 @@ namespace OpenRA.Mods.Common.UtilityCommands
{
static class UpgradeRules
{
public const int MinimumSupportedVersion = 20151224;
public const int MinimumSupportedVersion = 20160508;
internal static void TryUpdateColor(ref string value)
{
@@ -96,687 +96,6 @@ namespace OpenRA.Mods.Common.UtilityCommands
{
foreach (var node in nodes)
{
if (engineVersion < 20151225 && depth == 2)
{
if (node.Key == "Color")
{
if (parent != null && parent.Key.StartsWith("FixedColorPalette"))
TryUpdateHSLColor(ref node.Value.Value);
else
TryUpdateColor(ref node.Value.Value);
}
else if (node.Key == "RadarPingColor" || node.Key == "SelectionBoxColor" || node.Key == "BarColor")
TryUpdateColor(ref node.Value.Value);
else if (node.Key == "Fog" || node.Key == "Shroud" || node.Key == "ParticleColors")
TryUpdateColors(ref node.Value.Value);
}
// DeathType on Explodes was renamed to DeathTypes
if (engineVersion < 20151225)
{
if (node.Key == "Explodes")
{
var dt = node.Value.Nodes.FirstOrDefault(n => n.Key == "DeathType");
if (dt != null)
dt.Key = "DeathTypes";
}
}
// Upgrades on DeployToUpgrade were renamed to DeployedUpgrades
if (engineVersion < 20151122)
{
if (node.Key == "DeployToUpgrade")
{
var u = node.Value.Nodes.FirstOrDefault(n => n.Key == "Upgrades");
if (u != null)
u.Key = "DeployedUpgrades";
}
}
if (engineVersion < 20151225)
{
// Rename WithTurret to WithSpriteTurret
if (depth == 1 && node.Key.StartsWith("WithTurret"))
{
var parts = node.Key.Split('@');
node.Key = "WithSpriteTurret";
if (parts.Length > 1)
node.Key += "@" + parts[1];
}
if (depth == 1 && node.Key.StartsWith("-WithTurret"))
{
var parts = node.Key.Split('@');
node.Key = "-WithSpriteTurret";
if (parts.Length > 1)
node.Key += "@" + parts[1];
}
// Rename WithBarrel to WithSpriteBarrel
if (depth == 1 && node.Key.StartsWith("WithBarrel"))
{
var parts = node.Key.Split('@');
node.Key = "WithSpriteBarrel";
if (parts.Length > 1)
node.Key += "@" + parts[1];
}
if (depth == 1 && node.Key.StartsWith("-WithBarrel"))
{
var parts = node.Key.Split('@');
node.Key = "-WithSpriteBarrel";
if (parts.Length > 1)
node.Key += "@" + parts[1];
}
// Rename WithReloadingTurret to WithReloadingSpriteTurret
if (depth == 1 && node.Key.StartsWith("WithReloadingTurret"))
{
var parts = node.Key.Split('@');
node.Key = "WithReloadingSpriteTurret";
if (parts.Length > 1)
node.Key += "@" + parts[1];
}
if (depth == 1 && node.Key.StartsWith("-WithReloadingTurret"))
{
var parts = node.Key.Split('@');
node.Key = "-WithReloadingSpriteTurret";
if (parts.Length > 1)
node.Key += "@" + parts[1];
}
}
// Mobile actors immobilized by Carryable, Cargo, DeployToUpgrade, and/or others using upgrade(s)
if (engineVersion < 20151225 && depth == 0)
{
var notMobile = "notmobile";
var mobileNode = node.Value.Nodes.Find(n => n.Key == "Mobile");
var carryableNode = node.Value.Nodes.Find(n => n.Key == "Carryable");
var cargoNode = node.Value.Nodes.Find(n => n.Key == "Cargo");
var deployToUpgradeNode = node.Value.Nodes.Find(n => n.Key == "DeployToUpgrade");
var disableUpgradeNode = node.Value.Nodes.Find(n => n.Key == "DisableUpgrade");
var disableMovementOnUpgradeNode = node.Value.Nodes.Find(n => n.Key == "DisableMovementOnUpgrade");
Action<MiniYamlNode, string> addNotMobileToTraitUpgrades = (trait, upgradesKey) =>
{
if (trait != null)
{
var upgrades = trait.Value.Nodes.Find(u => u.Key == upgradesKey);
if (upgrades == null)
trait.Value.Nodes.Add(new MiniYamlNode(upgradesKey, notMobile));
else if (string.IsNullOrEmpty(upgrades.Value.Value))
upgrades.Value.Value = notMobile;
else if (!upgrades.Value.Value.Contains(notMobile))
upgrades.Value.Value += ", " + notMobile;
}
};
if (mobileNode != null)
{
var mobileUpgrades = mobileNode.Value.Nodes.Find(n => n.Key == "UpgradeTypes");
var mobileUpgradeMaxEnabledLevel = mobileNode.Value.Nodes.Find(n => n.Key == "UpgradeMaxEnabledLevel");
var comma = new char[] { ',' };
Func<bool> addUpgradeMaxEnabledLevelNode = () =>
{
if (mobileUpgradeMaxEnabledLevel == null)
{
mobileUpgradeMaxEnabledLevel = new MiniYamlNode("UpgradeMaxEnabledLevel", "0");
mobileNode.Value.Nodes.Add(mobileUpgradeMaxEnabledLevel);
return true;
}
else
return mobileUpgradeMaxEnabledLevel.Value.Value == "0";
};
// If exactly one upgrade type is in UpgradeTypes and UpgradeMaxEnabledLevel is/can be 0 , then use it as notmobile
if (mobileUpgrades != null && !string.IsNullOrEmpty(mobileUpgrades.Value.Value)
&& !mobileUpgrades.Value.Value.Contains(",") && addUpgradeMaxEnabledLevelNode())
notMobile = mobileUpgrades.Value.Value;
if (mobileUpgradeMaxEnabledLevel != null && mobileUpgradeMaxEnabledLevel.Value.Value != "0")
Console.WriteLine("\t\t" + node.Key + " actor rules may require manual upgrading for immobilization upgrade logic.");
else
{
Action<string> addImmobilizeUpgradeType = upgradeType =>
{
if (mobileUpgrades == null)
{
mobileUpgrades = new MiniYamlNode("UpgradeTypes", upgradeType);
mobileNode.Value.Nodes.Add(mobileUpgrades);
}
else if (string.IsNullOrEmpty(mobileUpgrades.Value.Value))
mobileUpgrades.Value.Value = upgradeType;
else if (!mobileUpgrades.Value.Value.Split(comma).Contains(upgradeType))
mobileUpgrades.Value.Value += ", " + upgradeType;
};
Predicate<string> addImmobilizeUpgradeTypes = upgradeTypes =>
{
if (string.IsNullOrEmpty(upgradeTypes))
return false;
foreach (var upgradeType in upgradeTypes.Split(comma))
addImmobilizeUpgradeType(upgradeType);
return true;
};
Predicate<MiniYamlNode> addUpgradeTypeFromTrait = trait =>
{
var upgradeTypesNode = trait.Value.Nodes.Find(n => n.Key == "UpgradeTypes");
if (upgradeTypesNode == null)
return false;
addUpgradeMaxEnabledLevelNode();
return addImmobilizeUpgradeTypes(upgradeTypesNode.Value.Value);
};
var noticeWritten = false;
Action writeNotice = () =>
{
if (noticeWritten)
return;
Console.WriteLine("\t\t" + node.Key + " actor rules may require manual upgrading for immobilization upgrade logic.");
noticeWritten = true;
};
if (disableUpgradeNode != null && !addUpgradeTypeFromTrait(disableUpgradeNode))
{
writeNotice();
Console.WriteLine("\t\t\tOne or more upgrades may need to be copied from the DisableUpgrade trait to the Mobile trait.");
}
if (disableMovementOnUpgradeNode != null)
{
if (addUpgradeTypeFromTrait(disableMovementOnUpgradeNode))
parent.Value.Nodes.Remove(disableMovementOnUpgradeNode);
else
{
writeNotice();
Console.WriteLine("\t\t\tOne or more upgrades may need to be moved from the DisableMovementOnUpgrade trait to the Mobile trait.");
Console.WriteLine("\t\t\t\tRemember to remove the DisableMovementOnUpgrade trait.");
}
}
if (carryableNode != null || cargoNode != null || deployToUpgradeNode != null)
{
addUpgradeMaxEnabledLevelNode();
addImmobilizeUpgradeTypes(notMobile);
addNotMobileToTraitUpgrades(carryableNode, "CarryableUpgrades");
addNotMobileToTraitUpgrades(cargoNode, "LoadingUpgrades");
addNotMobileToTraitUpgrades(deployToUpgradeNode, "DeployedUpgrades");
}
}
}
else if (!node.Value.Nodes.Exists(n => n.Key == "Husk" || n.Key == "Building" || n.Key == "Aircraft" || n.Key == "Immobile"))
{
if (carryableNode != null || cargoNode != null || deployToUpgradeNode != null)
{
Console.WriteLine("\t\tIf " + node.Key
+ " has a Mobile trait then adding the following with <upgrade> substituted by an immobilization upgrade for "
+ node.Key + " may be neeeded:");
if (carryableNode != null)
{
Console.WriteLine("\t\t\tCarryable:");
Console.WriteLine("\t\t\t\tCarryableUpgrades: <upgrade>");
}
if (cargoNode != null)
{
Console.WriteLine("\t\t\tCargo:");
Console.WriteLine("\t\t\t\tLoadingUpgrades: <upgrade>");
}
if (deployToUpgradeNode != null)
{
Console.WriteLine("\t\t\tDeployToUpgrade:");
Console.WriteLine("\t\t\t\tDeployedUpgrades: <upgrade>");
}
}
var disableUpgradeUpgradeTypesNode = disableUpgradeNode != null
? disableUpgradeNode.Value.Nodes.Find(n => n.Key == "UpgradeTypes")
: null;
var disableMovementOnUpgradeUpgradeTypesNode = disableMovementOnUpgradeNode != null
? disableMovementOnUpgradeNode.Value.Nodes.Find(n => n.Key == "UpgradeTypes")
: null;
if (disableUpgradeUpgradeTypesNode != null || disableMovementOnUpgradeUpgradeTypesNode != null)
Console.WriteLine("\t\t" + node.Key + " actor rules may require manual upgrading for immobilization upgrade logic.");
if (disableUpgradeUpgradeTypesNode != null)
Console.WriteLine("\t\t\tDisableUpgrade UpgradeTypes: " + disableUpgradeUpgradeTypesNode.Value.Value);
if (disableMovementOnUpgradeUpgradeTypesNode != null)
Console.WriteLine("\t\t\tDisableMovementOnUpgrade UpgradeTypes: " + disableMovementOnUpgradeUpgradeTypesNode.Value.Value);
if (disableMovementOnUpgradeNode != null)
node.Value.Nodes.Remove(disableMovementOnUpgradeNode);
}
}
// 'CloseEnough' on 'RepairableNear' uses WDist now
if (engineVersion < 20151225)
{
if (node.Key == "RepairableNear")
{
var ce = node.Value.Nodes.FirstOrDefault(n => n.Key == "CloseEnough");
if (ce != null && !ce.Value.Value.Contains("c"))
ce.Value.Value = ce.Value.Value + "c0";
}
}
// Added width support for line particles
if (engineVersion < 20151225 && node.Key == "WeatherOverlay")
{
var useSquares = node.Value.Nodes.FirstOrDefault(n => n.Key == "UseSquares");
if (useSquares != null && !FieldLoader.GetValue<bool>("UseSquares", useSquares.Value.Value))
node.Value.Nodes.Add(new MiniYamlNode("ParticleSize", "1, 1"));
}
// Overhauled the actor decorations traits
if (engineVersion < 20151226)
{
if (depth == 1 && (node.Key.StartsWith("WithDecoration") || node.Key.StartsWith("WithRankDecoration")))
{
node.Value.Nodes.RemoveAll(n => n.Key == "Scale");
node.Value.Nodes.RemoveAll(n => n.Key == "Offset");
var sd = node.Value.Nodes.FirstOrDefault(n => n.Key == "SelectionDecoration");
if (sd != null)
sd.Key = "RequiresSelection";
var reference = node.Value.Nodes.FirstOrDefault(n => n.Key == "ReferencePoint");
if (reference != null)
{
var values = FieldLoader.GetValue<string[]>("ReferencePoint", reference.Value.Value);
values = values.Where(v => v != "HCenter" && v != "VCenter").ToArray();
if (values.Length == 0)
values = new[] { "Center" };
reference.Value.Value = FieldSaver.FormatValue(values);
}
var stance = Stance.Ally;
var showToAllies = node.Value.Nodes.FirstOrDefault(n => n.Key == "ShowToAllies");
if (showToAllies != null && !FieldLoader.GetValue<bool>("ShowToAllies", showToAllies.Value.Value))
stance ^= Stance.Ally;
var showToEnemies = node.Value.Nodes.FirstOrDefault(n => n.Key == "ShowToEnemies");
if (showToEnemies != null && FieldLoader.GetValue<bool>("ShowToEnemies", showToEnemies.Value.Value))
stance |= Stance.Enemy;
if (stance != Stance.Ally)
node.Value.Nodes.Add(new MiniYamlNode("Stance", FieldSaver.FormatValue(stance)));
node.Value.Nodes.RemoveAll(n => n.Key == "ShowToAllies");
node.Value.Nodes.RemoveAll(n => n.Key == "ShowToEnemies");
}
if (depth == 1 && node.Key == "Fake")
{
node.Key = "WithDecoration@fake";
node.Value.Nodes.Add(new MiniYamlNode("RequiresSelection", "true"));
node.Value.Nodes.Add(new MiniYamlNode("Image", "pips"));
node.Value.Nodes.Add(new MiniYamlNode("Sequence", "tag-fake"));
node.Value.Nodes.Add(new MiniYamlNode("ReferencePoint", "Top"));
node.Value.Nodes.Add(new MiniYamlNode("ZOffset", "256"));
}
if (depth == 0 && node.Value.Nodes.Any(n => n.Key.StartsWith("PrimaryBuilding")))
{
var decNodes = new List<MiniYamlNode>();
decNodes.Add(new MiniYamlNode("RequiresSelection", "true"));
decNodes.Add(new MiniYamlNode("Image", "pips"));
decNodes.Add(new MiniYamlNode("Sequence", "tag-primary"));
decNodes.Add(new MiniYamlNode("ReferencePoint", "Top"));
decNodes.Add(new MiniYamlNode("ZOffset", "256"));
decNodes.Add(new MiniYamlNode("UpgradeTypes", "primary"));
decNodes.Add(new MiniYamlNode("UpgradeMinEnabledLevel", "1"));
node.Value.Nodes.Add(new MiniYamlNode("WithDecoration@primary", new MiniYaml("", decNodes)));
}
}
// Refactored the low resources notification to a separate trait
if (engineVersion < 20151227 && node.Key == "Player")
{
var resourcesNode = node.Value.Nodes.FirstOrDefault(x => x.Key == "PlayerResources");
if (resourcesNode != null)
{
var intervalNode = resourcesNode.Value.Nodes.FirstOrDefault(x => x.Key == "AdviceInterval");
var storageNode = new MiniYamlNode("ResourceStorageWarning", "");
if (intervalNode != null)
{
// The time value is now in seconds, not ticks. We
// divide by 25 ticks per second at Normal.
int oldInterval;
if (int.TryParse(intervalNode.Value.Value, out oldInterval))
storageNode.Value.Nodes.Add(new MiniYamlNode("AdviceInterval", (oldInterval / 25).ToString()));
resourcesNode.Value.Nodes.Remove(intervalNode);
}
node.Value.Nodes.Add(storageNode);
}
}
// Refactored Health.Radius to HitShapes
if (engineVersion < 20151227)
{
if (node.Key.StartsWith("Health"))
{
var radius = node.Value.Nodes.FirstOrDefault(x => x.Key == "Radius");
if (radius != null)
{
var radiusValue = FieldLoader.GetValue<string>("Radius", radius.Value.Value);
node.Value.Nodes.Add(new MiniYamlNode("Shape", "Circle"));
var shape = node.Value.Nodes.First(x => x.Key == "Shape");
shape.Value.Nodes.Add(new MiniYamlNode("Radius", radiusValue));
node.Value.Nodes.Remove(radius);
}
}
}
// Remove obsolete TransformOnPassenger trait.
if (engineVersion < 20160102)
{
var removed = node.Value.Nodes.RemoveAll(x => x.Key.Contains("TransformOnPassenger"));
if (removed > 0)
{
Console.WriteLine("TransformOnPassenger has been removed.");
Console.WriteLine("Use the upgrades system to apply modifiers to the transport actor instead.");
}
}
if (engineVersion < 20160103)
{
// Overhauled WithActiveAnimation -> WithIdleAnimation
if (node.Key == "WithActiveAnimation")
{
node.Key = "WithIdleAnimation";
foreach (var n in node.Value.Nodes)
if (n.Key == "Sequence")
n.Key = "Sequences";
}
}
if (engineVersion < 20160107 && depth == 1 && node.Key.StartsWith("Cloak"))
{
var defaultCloakType = Traits.UncloakType.Attack
| Traits.UncloakType.Unload | Traits.UncloakType.Infiltrate | Traits.UncloakType.Demolish;
// Merge Uncloak types
var t = defaultCloakType;
for (var i = node.Value.Nodes.Count - 1; i >= 0; i--)
{
var n = node.Value.Nodes[i];
var v = string.Compare(n.Value.Value, "true", true) == 0;
Traits.UncloakType flag;
if (n.Key == "UncloakOnAttack")
flag = Traits.UncloakType.Attack;
else if (n.Key == "UncloakOnMove")
flag = Traits.UncloakType.Move;
else if (n.Key == "UncloakOnUnload")
flag = Traits.UncloakType.Unload;
else if (n.Key == "UncloakOnInfiltrate")
flag = Traits.UncloakType.Infiltrate;
else if (n.Key == "UncloakOnDemolish")
flag = Traits.UncloakType.Demolish;
else
continue;
t = v ? t | flag : t & ~flag;
node.Value.Nodes.Remove(n);
}
if (t != defaultCloakType)
{
Console.WriteLine("\t\tCloak type: " + t.ToString());
var ts = new List<string>();
if (t.HasFlag(Traits.UncloakType.Attack))
ts.Add("Attack");
if (t.HasFlag(Traits.UncloakType.Unload))
ts.Add("Unload");
if (t.HasFlag(Traits.UncloakType.Infiltrate))
ts.Add("Infiltrate");
if (t.HasFlag(Traits.UncloakType.Demolish))
ts.Add("Demolish");
if (t.HasFlag(Traits.UncloakType.Move))
ts.Add("Move");
node.Value.Nodes.Add(new MiniYamlNode("UncloakOn", ts.JoinWith(", ")));
}
}
// Rename WithDockingOverlay to WithDockedOverlay
if (engineVersion < 20160116)
{
if (node.Key.StartsWith("WithDockingOverlay"))
node.Key = "WithDockedOverlay" + node.Key.Substring(18);
}
if (engineVersion < 20160116)
{
if (node.Key == "DemoTruck")
node.Key = "AttackSuicides";
}
// Replaced GpsRemoveFrozenActor with FrozenUnderFogUpdatedByGps
if (engineVersion < 20160117)
{
if (node.Key == "GpsRemoveFrozenActor")
{
node.Key = "FrozenUnderFogUpdatedByGps";
node.Value.Nodes.Clear();
}
}
// Removed arbitrary defaults from InfiltrateForCash
if (engineVersion < 20160118)
{
if (node.Key == "InfiltrateForCash")
{
if (!node.Value.Nodes.Any(n => n.Key == "Percentage"))
node.Value.Nodes.Add(new MiniYamlNode("Percentage", "50"));
if (!node.Value.Nodes.Any(n => n.Key == "Minimum"))
node.Value.Nodes.Add(new MiniYamlNode("Minimum", "500"));
var sound = node.Value.Nodes.FirstOrDefault(n => n.Key == "SoundToVictim");
if (sound != null)
{
node.Value.Nodes.Remove(sound);
Console.WriteLine("The 'SoundToVictim' property of the 'InfiltrateForCash' trait has been");
Console.WriteLine("replaced with a 'Notification' property. Please add the sound file");
Console.WriteLine("'{0}' to your mod's audio notification yaml and".F(sound.Value.Value));
Console.WriteLine("update your mod's rules accordingly.");
Console.WriteLine();
}
}
}
if (engineVersion < 20160301)
{
// Renamed ROT -> TurnSpeed
if (node.Key == "ROT")
node.Key = "TurnSpeed";
}
if (engineVersion < 20160320)
{
// Renamed Parachutable.CorpseSequenceCollection to Image
if (node.Key == "CorpseSequenceCollection")
node.Key = "Image";
// Renamed WithBuildingExplosion.SequenceCollection to Image
if (node.Key == "SequenceCollection")
node.Key = "Image";
}
if (engineVersion < 20160321)
{
var parentKey = parent != null ? parent.Key.Split('@').First() : null;
if (node.Key == "Ticks" && parentKey == "DrawLineToTarget")
node.Key = "Duration";
if (node.Key == "ReloadTicks")
node.Key = "ReloadDelay";
if (node.Key == "SelfReloadTicks")
node.Key = "SelfReloadDelay";
if (node.Key == "LoadTicksPerBale")
node.Key = "BaleLoadDelay";
if (node.Key == "UnloadTicksPerBale")
node.Key = "BaleUnloadDelay";
if (node.Key == "TicksToHold")
node.Key = "HoldDuration";
if (node.Key == "Ticks" && parentKey == "SelfHealing")
node.Key = "Delay";
if (node.Key == "TicksToWaitBeforeReducingMoveRadius")
node.Key = "ReduceMoveRadiusDelay";
if (node.Key == "MinIdleWaitTicks")
node.Key = "MinIdleDelay";
if (node.Key == "MaxIdleWaitTicks")
node.Key = "MaxIdleWaitDelay";
if (node.Key == "ReloadTime")
node.Key = "ReloadDelay";
}
// Got rid of most remaining usages of float in a bid to further reduce desync risk
if (engineVersion < 20160328)
{
// Migrated ProductionQueue BuildSpeed to use int percentage instead of float
if (node.Key.StartsWith("ProductionQueue") || node.Key.StartsWith("ClassicProductionQueue"))
{
var buildSpeedNode = node.Value.Nodes.FirstOrDefault(x => x.Key == "BuildSpeed");
if (buildSpeedNode != null)
{
// The BuildSpeed value is now an int percentage, so multiply the float with 100.
var oldValue = FieldLoader.GetValue<float>("BuildSpeed", buildSpeedNode.Value.Value);
var newValue = (int)(oldValue * 100);
buildSpeedNode.Value.Value = newValue.ToString();
}
}
// Migrated StrategicVictoryConditions RatioRequired to use int percentage instead of float
if (node.Key.StartsWith("StrategicVictoryConditions"))
{
var ratioNode = node.Value.Nodes.FirstOrDefault(x => x.Key == "RatioRequired");
if (ratioNode != null)
{
// The RatioRequired value is now an int percentage, so multiply the float with 100.
var oldValue = FieldLoader.GetValue<float>("RatioRequired", ratioNode.Value.Value);
var newValue = (int)(oldValue * 100);
ratioNode.Value.Value = newValue.ToString();
}
}
// Migrated Minelayer.MinefieldDepth to use WDist instead of float
if (node.Key.StartsWith("Minelayer"))
{
var depthNode = node.Value.Nodes.FirstOrDefault(x => x.Key == "MinefieldDepth");
if (depthNode != null)
{
// The MinefieldDepth value is now a WDist, so multiply the float value with 1024.
var oldValue = FieldLoader.GetValue<float>("MinefieldDepth", depthNode.Value.Value);
var newValue = (int)(oldValue * 1024);
depthNode.Value.Value = newValue.ToString();
}
}
// Migrated SelfHealing to use int percentage instead of float
if (node.Key == "SelfHealing")
{
var healIfBelowNode = node.Value.Nodes.FirstOrDefault(x => x.Key == "HealIfBelow");
if (healIfBelowNode != null)
{
// The HealIfBelow value is now an int percentage, so multiply the float with 100.
var oldValue = FieldLoader.GetValue<float>("HealIfBelow", healIfBelowNode.Value.Value);
var newValue = (int)(oldValue * 100);
healIfBelowNode.Value.Value = newValue.ToString();
}
}
// Migrated EmitInfantryOnSell to use int percentage instead of float
if (node.Key == "EmitInfantryOnSell")
{
var valueNode = node.Value.Nodes.FirstOrDefault(x => x.Key == "ValuePercent");
var minHPNode = node.Value.Nodes.FirstOrDefault(x => x.Key == "MinHpPercent");
if (valueNode != null)
{
// The ValuePercent value is now an int percentage, but was previously geared towards
// percentage rather than float and divided by 100 internally so division by 100 is NOT needed.
var oldValue = FieldLoader.GetValue<float>("ValuePercent", valueNode.Value.Value);
var newValue = (int)oldValue;
valueNode.Value.Value = newValue.ToString();
}
if (minHPNode != null)
{
// The MinHpPercent value is now an int percentage, but was previously geared towards
// percentage rather than float and divided by 100 internally so division by 100 is NOT needed.
var oldValue = FieldLoader.GetValue<float>("MinHpPercent", minHPNode.Value.Value);
var newValue = (int)oldValue;
minHPNode.Value.Value = newValue.ToString();
}
}
// Migrated Captures and Capturable to use int percentage instead of float
if (node.Key == "Captures")
{
var sabotageHPRemNode = node.Value.Nodes.FirstOrDefault(x => x.Key == "SabotageHPRemoval");
if (sabotageHPRemNode != null)
{
// The SabotageHPRemoval value is now an int percentage, so multiply the float with 100.
var oldValue = FieldLoader.GetValue<float>("SabotageHPRemoval", sabotageHPRemNode.Value.Value);
var newValue = (int)(oldValue * 100);
sabotageHPRemNode.Value.Value = newValue.ToString();
}
}
if (node.Key == "Capturable")
{
var captThreshNode = node.Value.Nodes.FirstOrDefault(x => x.Key == "CaptureThreshold");
if (captThreshNode != null)
{
// The CaptureThreshold value is now an int percentage, so multiply the float with 100.
var oldValue = FieldLoader.GetValue<float>("CaptureThreshold", captThreshNode.Value.Value);
var newValue = (int)(oldValue * 100);
captThreshNode.Value.Value = newValue.ToString();
}
}
}
if (engineVersion < 20160402)
{
// Fix misleading property naming.
if (node.Key == "EffectSequence" && parent != null && parent.Key == "SpawnActorPower")
node.Key = "EffectImage";
}
if (engineVersion < 20160408)
{
var traitNode = node.Value.Nodes.FirstOrDefault(n => n.Key == "InsufficientFundsWarning");
if (traitNode != null)
{
var prNode = node.Value.Nodes.FirstOrDefault(n => n.Key == "PlayerResources");
if (prNode != null)
prNode.Value.Nodes.Add(new MiniYamlNode("InsufficientFundsNotification", new MiniYaml("InsufficientFunds")));
node.Value.Nodes.Remove(traitNode);
}
}
if (engineVersion < 20160418)
{
// Removed FrozenUnderFog.StartsRevealed
if (node.Key == "FrozenUnderFog")
node.Value.Nodes.RemoveAll(x => x.Key == "StartsRevealed");
}
if (engineVersion < 20160515)
{
// Use generic naming for building demolition using explosives.
@@ -796,47 +115,6 @@ namespace OpenRA.Mods.Common.UtilityCommands
{
foreach (var node in nodes)
{
if (engineVersion < 20160124)
{
node.Value.Nodes.RemoveAll(x => x.Key == "Charges");
}
// Enhance CreateEffectWarhead
if (engineVersion < 20160131)
{
if (node.Key.StartsWith("Warhead") && node.Value.Value == "CreateEffect")
{
// Add support for multiple explosions to CreateEffectWarhead
var explosionNode = node.Value.Nodes.FirstOrDefault(x => x.Key == "Explosion");
if (explosionNode != null)
explosionNode.Key = "Explosions";
// Add support for multiple impact sounds to CreateEffectWarhead
var impactSoundNode = node.Value.Nodes.FirstOrDefault(x => x.Key == "ImpactSound");
if (impactSoundNode != null)
impactSoundNode.Key = "ImpactSounds";
}
}
// Rename some speed-related Missile properties
if (engineVersion < 20160205)
{
var mod = Game.ModData.Manifest.Mod.Id;
if (mod == "ts")
{
if (node.Key == "Projectile" && node.Value.Value == "Missile")
{
node.Value.Nodes.Add(new MiniYamlNode("MinimumLaunchSpeed", "75"));
node.Value.Nodes.Add(new MiniYamlNode("Speed", "384"));
}
}
else
{
if (node.Key == "MaximumLaunchSpeed" && parent != null && parent.Value.Value == "Missile")
node.Key = "Speed";
}
}
// Refactor Missile RangeLimit from ticks to WDist
if (engineVersion < 20160501)
{