public override IEnumerable <string> UpdateActorNode(ModData modData, MiniYamlNode actorNode) { foreach (var at in actorNode.ChildrenMatching("AttackMove")) { foreach (var node in at.ChildrenMatching("AttackMoveScanCondition")) { node.RenameKey("AttackMoveCondition"); } foreach (var node in at.ChildrenMatching("AssaultMoveScanCondition")) { node.RenameKey("AssaultMoveCondition"); } } 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; }
public override IEnumerable <string> UpdateActorNode(ModData modData, MiniYamlNode actorNode) { // Repairable isn't conditional or otherwise supports multiple traits, so LastChildMatching should be fine. foreach (var placeBuilding in actorNode.ChildrenMatching("ChronoshiftPower")) { placeBuilding.RenameChildrenMatching("OverlaySpriteGroup", "FootprintImage"); placeBuilding.RenameChildrenMatching("InvalidTileSequencePrefix", "InvalidFootprintSequence"); placeBuilding.RenameChildrenMatching("SourceTileSequencePrefix", "SourceFootprintSequence"); foreach (var valid in placeBuilding.ChildrenMatching("ValidTileSequencePrefix")) { valid.RenameKey("ValidFootprintSequence"); valid.Value.Value = valid.Value.Value.Substring(0, valid.Value.Value.Length - 1); } } yield break; }
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; }
public override IEnumerable <string> UpdateActorNode(ModData modData, MiniYamlNode actorNode) { foreach (var kv in TraitFields) { foreach (var traitNode in actorNode.ChildrenMatching(kv.Key)) { foreach (var fieldName in kv.Value) { foreach (var fieldNode in traitNode.ChildrenMatching(fieldName)) { var value = fieldNode.NodeValue <int>(); fieldNode.Value.Value = value != -1 ? FieldSaver.FormatValue(value != 255 ? 4 * value : 1023) : ""; } } } } yield break; }
public override IEnumerable <string> UpdateActorNode(ModData modData, MiniYamlNode actorNode) { foreach (var fallsToEarth in actorNode.ChildrenMatching("FallsToEarth")) { var spinsNode = fallsToEarth.LastChildMatching("Spins"); if (spinsNode != null) { var spins = spinsNode.NodeValue <bool>(); if (!spins) { fallsToEarth.AddNode("MaximumSpinSpeed", "0"); } fallsToEarth.RemoveNode(spinsNode); locations.Add("{0} ({1})".F(actorNode.Key, actorNode.Location.Filename)); } } yield break; }
public override IEnumerable <string> UpdateActorNode(ModData modData, MiniYamlNode actorNode) { var grants = actorNode.ChildrenMatching("GrantConditionOnDeploy"); foreach (var g in grants) { var deploy = g.LastChildMatching("DeploySound"); if (deploy != null) { deploy.RenameKey("DeploySounds"); } var undeploy = g.LastChildMatching("UndeploySound"); if (undeploy != null) { undeploy.RenameKey("UndeploySounds"); } } yield break; }
public override IEnumerable <string> UpdateActorNode(ModData modData, MiniYamlNode actorNode) { foreach (var aircraft in actorNode.ChildrenMatching("Aircraft")) { var canHover = aircraft.LastChildMatching("CanHover"); if (canHover != null && canHover.NodeValue <bool>()) { if (!aircraft.ChildrenMatching("TakeOffOnResupply").Any()) { aircraft.AddNode("TakeOffOnResupply", true); } if (!aircraft.ChildrenMatching("VTOL").Any()) { aircraft.AddNode("VTOL", true); } } } yield break; }
public override IEnumerable <string> UpdateActorNode(ModData modData, MiniYamlNode actorNode) { foreach (var a in actorNode.ChildrenMatching("Armament")) { var muzzleSplitFacings = a.LastChildMatching("MuzzleSplitFacings"); var sequenceNode = a.LastChildMatching("MuzzleSequence"); if (muzzleSplitFacings != null && sequenceNode != null) { var sequence = sequenceNode.Value.Value; var facings = muzzleSplitFacings.NodeValue <int>() - 1; var actor = actorNode.Key.ToLowerInvariant(); yield return("The Armament muzzle effect has been removed from {0} ({1}).\n".F(actor, actorNode.Location.Filename) + "If you would like to restore the muzzle effect you must redefine `MuzzleSequence: {0}`\n".F(sequence) + "and replace the {0}0-{1} sequence definitions with a single `{0}` sequence that uses\n".F(sequence, facings) + "the Combine syntax to assemble the different facing sprites."); a.RemoveNode(muzzleSplitFacings); a.RemoveNode(sequenceNode); } } }
public override IEnumerable <string> UpdateActorNode(ModData modData, MiniYamlNode actorNode) { if (actorNode.Key != "Player") { yield break; } var hackyAIs = actorNode.ChildrenMatching("HackyAI"); if (!hackyAIs.Any()) { yield break; } foreach (var hackyAINode in hackyAIs) { // We no longer support individual values for each AI, // and in practice the default of 5 has proven to be a solid middle-ground, // so just removing any custom value and notifying the modder about it should suffice. var minQuotient = hackyAINode.LastChildMatching("MinOrderQuotientPerTick"); if (minQuotient != null) { hackyAINode.RemoveNode(minQuotient); if (!showMessage) { showMessage = true; } } } var botOrderManager = actorNode.LastChildMatching("BotOrderManager"); if (botOrderManager == null) { var addBotOrderManager = new MiniYamlNode("BotOrderManager", ""); actorNode.AddNode(addBotOrderManager); } yield break; }
public override IEnumerable <string> UpdateActorNode(ModData modData, MiniYamlNode actorNode) { var aircraftTraits = actorNode.ChildrenMatching("Aircraft"); foreach (var aircraft in aircraftTraits) { var canHover = false; var canHoverNode = aircraft.LastChildMatching("CanHover"); if (canHoverNode != null) { canHover = canHoverNode.NodeValue <bool>(); } else { yield break; } aircraft.AddNode("CanSlide", canHover.ToString()); } yield break; }
public override IEnumerable <string> UpdateActorNode(ModData modData, MiniYamlNode actorNode) { var nukePowerTraits = actorNode.ChildrenMatching("NukePower"); foreach (var nukePowerTrait in nukePowerTraits) { var traitName = nukePowerTrait.Key; var weaponNode = nukePowerTrait.ChildrenMatching("MissileWeapon").FirstOrDefault(); if (weaponNode == null) { continue; } var weaponName = weaponNode.Value.Value; weaponsToUpdate.Add(new Tuple <string, string, string>(weaponName, traitName, "{0} ({1})".F(actorNode.Key, actorNode.Location.Filename))); nukePowerTrait.RemoveNodes("FlashType"); } yield break; }
public override IEnumerable <string> UpdateActorNode(ModData modData, MiniYamlNode actorNode) { var modId = modData.Manifest.Id; foreach (var bo in actorNode.ChildrenMatching("BodyOrientation")) { var usesClassicFacings = false; var facingFudgeNode = bo.LastChildMatching("UseClassicFacingFudge"); if (facingFudgeNode != null) { usesClassicFacings = facingFudgeNode.NodeValue <bool>(); bo.RemoveNode(facingFudgeNode); } if (usesClassicFacings) { bo.RenameKey("ClassicFacingBodyOrientation"); locations.Add("{0} ({1})".F(actorNode.Key, actorNode.Location.Filename)); } } yield break; }
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> UpdateActorNode(ModData modData, MiniYamlNode actorNode) { foreach (var gcod in actorNode.ChildrenMatching("GrantConditionOnDeploy")) { var canUndeploy = gcod.LastChildMatching("CanUndeploy"); if (canUndeploy == null) { continue; } gcod.RemoveNode(canUndeploy); if (canUndeploy.NodeValue <bool>()) { continue; } var deployedCondition = gcod.LastChildMatching("DeployedCondition"); gcod.AddNode("PauseOnCondition", deployedCondition.Value.Value); } yield break; }
public override IEnumerable <string> UpdateActorNode(ModData modData, MiniYamlNode actorNode) { var nukePowers = actorNode.ChildrenMatching("NukePower").ToList(); foreach (var nuke in nukePowers) { var activation = nuke.LastChildMatching("ActivationSequence"); if (activation == null) { continue; } var sequence = activation.NodeValue <string>(); nuke.RemoveNode(activation); actorNode.AddNode("WithNukeLaunchAnimation", ""); if (sequence != "active") { actorNode.LastChildMatching("WithNukeLaunchAnimation").AddNode("Sequence", sequence); } } yield break; }
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; }
public override IEnumerable <string> UpdateActorNode(ModData modData, MiniYamlNode actorNode) { foreach (var layer in actorNode.ChildrenMatching("SmudgeLayer")) { var chance = layer.LastChildMatching("SmokePercentage"); if (chance != null) { chance.RenameKey("SmokeChance"); } else { layer.AddNode("SmokeChance", FieldSaver.FormatValue("25")); } var image = layer.LastChildMatching("SmokeType"); if (image != null) { image.RenameKey("SmokeImage"); } else { layer.AddNode("SmokeImage", FieldSaver.FormatValue("smoke_m")); } var sequences = layer.LastChildMatching("SmokeSequence"); if (sequences != null) { sequences.RenameKey("SmokeSequences"); } else { layer.AddNode("SmokeSequences", FieldSaver.FormatValue("idle")); } } yield break; }
public override IEnumerable <string> UpdateActorNode(ModData modData, MiniYamlNode actorNode) { var addNodes = new List <MiniYamlNode>(); foreach (var burns in actorNode.ChildrenMatching("Burns")) { var anim = burns.LastChildMatching("Anim"); var animValue = anim != null?anim.NodeValue <string>() : "1"; var damage = burns.LastChildMatching("Damage"); var damageValue = damage != null?damage.NodeValue <int>() : 1; var interval = burns.LastChildMatching("Interval"); var intervalValue = interval != null?interval.NodeValue <int>() : 8; var overlay = new MiniYamlNode("WithIdleOverlay@Burns", ""); overlay.AddNode("Image", FieldSaver.FormatValue("fire")); overlay.AddNode("Sequence", FieldSaver.FormatValue(animValue)); overlay.AddNode("IsDecoration", FieldSaver.FormatValue(true)); addNodes.Add(overlay); var changesHealth = new MiniYamlNode("ChangesHealth", ""); changesHealth.AddNode("Step", FieldSaver.FormatValue(-damageValue)); changesHealth.AddNode("StartIfBelow", FieldSaver.FormatValue(101)); changesHealth.AddNode("Delay", FieldSaver.FormatValue(intervalValue)); addNodes.Add(changesHealth); } actorNode.RemoveNodes("Burns"); foreach (var addNode in addNodes) { actorNode.AddNode(addNode); } yield break; }
public override IEnumerable <string> UpdateActorNode(ModData modData, MiniYamlNode actorNode) { var aircraft = actorNode.LastChildMatching("Aircraft"); var attackAircraft = actorNode.ChildrenMatching("AttackAircraft"); if (aircraft != null) { var abortOnResupply = aircraft.LastChildMatching("AbortOnResupply"); if (abortOnResupply == null) { yield break; } // Only add field to AttackAircraft if explicitly set to 'false' if (!abortOnResupply.NodeValue <bool>()) { if (attackAircraft.Any()) { foreach (var a in attackAircraft) { a.AddNode(abortOnResupply); } } else { var newAttackAircraft = new MiniYamlNode("AttackAircraft", ""); newAttackAircraft.AddNode(abortOnResupply); actorNode.AddNode(newAttackAircraft); } } aircraft.RemoveNode(abortOnResupply); } yield break; }
public override IEnumerable <string> UpdateActorNode(ModData modData, MiniYamlNode actorNode) { var addNodes = new List <MiniYamlNode>(); var aircraft = modData.DefaultRules.Actors.Values.Where(a => a.HasTraitInfo <AircraftInfo>() && a.HasTraitInfo <AttackBaseInfo>()).Select(a => a.Name); var airUnits = new MiniYamlNode("AirUnitsTypes", FieldSaver.FormatValue(aircraft.ToList())); addNodes.Add(airUnits); var vips = modData.DefaultRules.Actors.Values.Where(a => a.HasTraitInfo <HarvesterInfo>() || a.HasTraitInfo <BaseBuildingInfo>() || (a.HasTraitInfo <BuildingInfo>() && a.HasTraitInfo <BuildableInfo>() && !a.HasTraitInfo <LineBuildInfo>() && !a.HasTraitInfo <PlugInfo>())).Select(a => a.Name); var protection = new MiniYamlNode("ProtectionTypes", FieldSaver.FormatValue(vips.ToList())); addNodes.Add(protection); foreach (var squadManager in actorNode.ChildrenMatching("SquadManagerBotModule")) { foreach (var addNode in addNodes) { squadManager.AddNode(addNode); } } yield break; }
public override IEnumerable <string> UpdateWeaponNode(ModData modData, MiniYamlNode weaponNode) { foreach (var projectileNode in weaponNode.ChildrenMatching("Projectile")) { if (projectileNode.Value.Value == null) { continue; } if (ProjectileFields.TryGetValue(projectileNode.Value.Value, out var fieldNames)) { foreach (var fieldName in fieldNames) { foreach (var fieldNode in projectileNode.ChildrenMatching(fieldName)) { var value = fieldNode.NodeValue <int>(); fieldNode.Value.Value = FieldSaver.FormatValue(value != 255 ? 4 * value : 1023); } } } } yield break; }
public static MiniYamlNode LastChildMatching(this MiniYamlNode node, string match, bool includeRemovals = true) { return(node.ChildrenMatching(match, includeRemovals: includeRemovals).LastOrDefault()); }
public override IEnumerable <string> UpdateActorNode(ModData modData, MiniYamlNode actorNode) { foreach (var resourceNode in actorNode.ChildrenMatching("ResourceType")) { var typeNode = resourceNode.LastChildMatching("Type"); if (typeNode != null) { var resourceLayerNode = new MiniYamlNode(typeNode.Value.Value, ""); resourceLayer.Nodes.Add(resourceLayerNode); var resourceRendererNode = new MiniYamlNode(typeNode.Value.Value, ""); resourceRenderer.Nodes.Add(resourceRendererNode); var indexNode = resourceNode.LastChildMatching("ResourceType"); if (indexNode != null) { indexNode.RenameKey("ResourceIndex"); resourceLayerNode.AddNode(indexNode); } var terrainTypeNode = resourceNode.LastChildMatching("TerrainType"); if (terrainTypeNode != null) { resourceLayerNode.AddNode(terrainTypeNode); } var allowedTerrainNode = resourceNode.LastChildMatching("AllowedTerrainTypes"); if (allowedTerrainNode != null) { resourceLayerNode.AddNode(allowedTerrainNode); } var maxDensityNode = resourceNode.LastChildMatching("MaxDensity"); if (maxDensityNode != null) { resourceLayerNode.AddNode(maxDensityNode); } var valueNode = resourceNode.LastChildMatching("ValuePerUnit"); if (valueNode != null) { values.Nodes.Add(new MiniYamlNode(typeNode.Value.Value, valueNode.Value.Value)); } var imageNode = resourceNode.LastChildMatching("Image"); if (imageNode != null) { resourceRendererNode.AddNode(imageNode); } var sequencesNode = resourceNode.LastChildMatching("Sequences"); if (sequencesNode != null) { resourceRendererNode.AddNode(sequencesNode); } var paletteNode = resourceNode.LastChildMatching("Palette"); if (paletteNode != null) { resourceRendererNode.AddNode(paletteNode); } var nameNode = resourceNode.LastChildMatching("Name"); if (nameNode != null) { resourceRendererNode.AddNode(nameNode); } } else { yield return("Unable to process definition:\n" + resourceNode.Value.ToLines(resourceNode.Key).JoinWith("\n") + "\n\n" + "This override has been removed and must be manually reimplemented if still needed."); } } actorNode.RemoveNodes("ResourceType"); foreach (var resourceRendererNode in actorNode.ChildrenMatching("ResourceRenderer")) { resourceRendererNode.RemoveNodes("RenderTypes"); } foreach (var resourceRendererNode in actorNode.ChildrenMatching("D2kResourceRenderer")) { resourceRendererNode.RemoveNodes("RenderTypes"); } }
public override IEnumerable <string> UpdateActorNode(ModData modData, MiniYamlNode actorNode) { foreach (var announce in actorNode.ChildrenMatching("AnnounceOnKill")) { var intervalNode = announce.LastChildMatching("Interval"); if (intervalNode != null) { var interval = intervalNode.NodeValue <int>(); intervalNode.Value.Value = FieldSaver.FormatValue(interval * 1000); } } foreach (var notifier in actorNode.ChildrenMatching("BaseAttackNotifier")) { var notifyIntervalNode = notifier.LastChildMatching("NotifyInterval"); if (notifyIntervalNode != null) { var notifyInterval = notifyIntervalNode.NodeValue <int>(); notifyIntervalNode.Value.Value = FieldSaver.FormatValue(notifyInterval * 1000); } } foreach (var notifier in actorNode.ChildrenMatching("HarvesterAttackNotifier")) { var notifyIntervalNode = notifier.LastChildMatching("NotifyInterval"); if (notifyIntervalNode != null) { var notifyInterval = notifyIntervalNode.NodeValue <int>(); notifyIntervalNode.Value.Value = FieldSaver.FormatValue(notifyInterval * 1000); } } foreach (var rsw in actorNode.ChildrenMatching("ResourceStorageWarning")) { var adviceIntervalNode = rsw.LastChildMatching("AdviceInterval"); if (adviceIntervalNode != null) { var adviceInterval = adviceIntervalNode.NodeValue <int>(); adviceIntervalNode.Value.Value = FieldSaver.FormatValue(adviceInterval * 1000); } } foreach (var pm in actorNode.ChildrenMatching("PowerManager")) { var adviceIntervalNode = pm.LastChildMatching("AdviceInterval"); if (adviceIntervalNode != null) { var adviceInterval = adviceIntervalNode.NodeValue <int>(); adviceIntervalNode.Value.Value = FieldSaver.FormatValue(adviceInterval * 40); } } foreach (var pr in actorNode.ChildrenMatching("PlayerResources")) { var noFundsIntervalNode = pr.LastChildMatching("InsufficientFundsNotificationDelay"); if (noFundsIntervalNode != null) { var noFundsInterval = noFundsIntervalNode.NodeValue <int>(); noFundsIntervalNode.Value.Value = FieldSaver.FormatValue(noFundsInterval * 40); noFundsIntervalNode.RenameKey("InsufficientFundsNotificationInterval"); } } yield break; }
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; }
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; }
public override IEnumerable <string> UpdateActorNode(ModData modData, MiniYamlNode actorNode) { var locationKey = $"{actorNode.Key} ({actorNode.Location.Filename})"; var anyConditionalSmokeTrail = false; foreach (var smokeTrail in actorNode.ChildrenMatching("SmokeTrailWhenDamaged")) { var spriteNode = smokeTrail.LastChildMatching("Sprite"); if (spriteNode != null) { smokeTrail.RenameChildrenMatching("Sprite", "Image"); } else { smokeTrail.AddNode("Image", FieldSaver.FormatValue("smokey")); } var intervalNode = smokeTrail.LastChildMatching("Interval"); if (intervalNode != null) { var interval = intervalNode.NodeValue <int>(); smokeTrail.RenameChildrenMatching("Interval", "MovingInterval"); smokeTrail.AddNode("StationaryInterval", FieldSaver.FormatValue(interval)); } else { smokeTrail.AddNode("MovingInterval", FieldSaver.FormatValue(3)); smokeTrail.AddNode("StationaryInterval", FieldSaver.FormatValue(3)); } var minDamageNode = smokeTrail.LastChildMatching("MinDamage"); var isConditional = true; if (minDamageNode != null) { var minDamage = minDamageNode.NodeValue <string>(); if (minDamage == "Undamaged") { isConditional = false; } else if (minDamage != "Heavy") { locations.GetOrAdd(locationKey).Add(smokeTrail.Key); } smokeTrail.RemoveNode(minDamageNode); } smokeTrail.AddNode("SpawnAtLastPosition", FieldSaver.FormatValue(false)); smokeTrail.AddNode("TrailWhileStationary", FieldSaver.FormatValue(true)); smokeTrail.AddNode("Type", FieldSaver.FormatValue("CenterPosition")); if (isConditional) { smokeTrail.AddNode("RequiresCondition", FieldSaver.FormatValue("enable-smoke")); anyConditionalSmokeTrail = true; } smokeTrail.RenameChildrenMatching("Sequence", "Sequences"); smokeTrail.RenameChildrenMatching("Offset", "Offsets"); smokeTrail.RenameKey("LeavesTrails"); } if (anyConditionalSmokeTrail) { var grantCondition = new MiniYamlNode("GrantConditionOnDamageState@SmokeTrail", ""); grantCondition.AddNode("Condition", FieldSaver.FormatValue("enable-smoke")); actorNode.AddNode(grantCondition); } yield break; }
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; }
public override IEnumerable <string> UpdateActorNode(ModData modData, MiniYamlNode actorNode) { var addNodes = new List <MiniYamlNode>(); foreach (var mobileNode in actorNode.ChildrenMatching("Mobile")) { var checkFields = locomotorFields.Append(subterraneanFields).Append(jumpjetFields); if (checkFields.Any(f => mobileNode.ChildrenMatching(f).Any())) { locations.Add(Tuple.Create(actorNode.Key, actorNode.Location.Filename)); } var tunnelConditionNode = mobileNode.LastChildMatching("TunnelCondition"); if (tunnelConditionNode != null) { var grantNode = new MiniYamlNode("GrantConditionOnTunnelLayer", ""); tunnelConditionNode.MoveAndRenameNode(mobileNode, grantNode, "Condition"); addNodes.Add(grantNode); } var subterraneanNode = mobileNode.LastChildMatching("Subterranean"); if (subterraneanNode != null) { subterraneanUsed = true; mobileNode.RemoveNodes("Subterranean"); var conditionNode = mobileNode.LastChildMatching("SubterraneanCondition"); if (conditionNode != null) { conditionNode.RenameKey("Condition"); } var transitionImageNode = mobileNode.LastChildMatching("SubterraneanTransitionImage"); var transitionSequenceNode = mobileNode.LastChildMatching("SubterraneanTransitionSequence"); var transitionPaletteNode = mobileNode.LastChildMatching("SubterraneanTransitionPalette"); var transitionSoundNode = mobileNode.LastChildMatching("SubterraneanTransitionSound"); var nodes = new[] { conditionNode, transitionImageNode, transitionSequenceNode, transitionPaletteNode, transitionSoundNode }; if (nodes.Any(n => n != null)) { var grantNode = new MiniYamlNode("GrantConditionOnSubterraneanLayer", ""); foreach (var node in nodes) { if (node != null) { node.MoveNode(mobileNode, grantNode); } } addNodes.Add(grantNode); } } var jumpjetNode = mobileNode.LastChildMatching("Jumpjet"); if (jumpjetNode != null) { jumpjetUsed = true; mobileNode.RemoveNodes("Jumpjet"); var conditionNode = mobileNode.LastChildMatching("JumpjetCondition"); if (conditionNode != null) { var grantNode = new MiniYamlNode("GrantConditionOnJumpjetLayer", ""); conditionNode.MoveAndRenameNode(mobileNode, grantNode, "Condition"); addNodes.Add(grantNode); } } } foreach (var node in addNodes) { actorNode.AddNode(node); } yield break; }