using System; using System.Collections.Generic; using System.Linq; using System.Text; using RimWorld; using UnityEngine; using Verse; using WulaFallenEmpire; namespace WulaFallenEmpire.EventSystem.AI.Tools { public class Tool_CallBombardment : AITool { public override string Name => "call_bombardment"; public override string Description => "Calls orbital bombardment/support using an AbilityDef configuration (e.g., WULA_Firepower_Cannon_Salvo, WULA_Firepower_EnergyLance_Strafe). Supports Circular Bombardment, Strafe, Energy Lance, and Surveillance."; public override string UsageSchema => "{\"abilityDef\":\"WULA_Firepower_Cannon_Salvo\",\"x\":12,\"z\":34,\"direction\":\"20,30\",\"angle\":90,\"filterFriendlyFire\":true}"; public override Dictionary GetParametersSchema() { var properties = new Dictionary { ["abilityDef"] = SchemaString("AbilityDef defName.", nullable: true), ["x"] = SchemaInteger("Target cell X.", nullable: true), ["z"] = SchemaInteger("Target cell Z.", nullable: true), ["cell"] = SchemaString("Target cell formatted as 'x,z'.", nullable: true), ["direction"] = SchemaString("Direction cell 'x,z' for strafes.", nullable: true), ["angle"] = SchemaNumber("Angle for strafe/lance direction.", nullable: true), ["filterFriendlyFire"] = SchemaBoolean("Avoid friendly fire if possible.", nullable: true), ["dirX"] = SchemaInteger("Direction cell X.", nullable: true), ["dirZ"] = SchemaInteger("Direction cell Z.", nullable: true) }; return SchemaObject(properties, RequiredList( "abilityDef", "x", "z", "cell", "direction", "angle", "filterFriendlyFire", "dirX", "dirZ")); } public override string Execute(string args) { try { var parsed = ParseJsonArgs(args); string abilityDefName = TryGetString(parsed, "abilityDef", out var abilityStr) && !string.IsNullOrWhiteSpace(abilityStr) ? abilityStr.Trim() : "WULA_Firepower_Cannon_Salvo"; if (!TryParseTargetCell(parsed, out var targetCell)) { return "Error: Missing target coordinates. Provide 'x' and 'z' (or 'cell' formatted as 'x,z')."; } Map map = Find.CurrentMap; if (map == null) return "Error: No active map."; if (!targetCell.InBounds(map)) return $"Error: Target {targetCell} is out of bounds."; AbilityDef abilityDef = DefDatabase.GetNamed(abilityDefName, false); if (abilityDef == null) return $"Error: AbilityDef '{abilityDefName}' not found."; // Switch logic based on AbilityDef components var circular = abilityDef.comps?.OfType().FirstOrDefault(); if (circular != null) return BombardmentUtility.ExecuteCircularBombardment(map, targetCell, abilityDef, circular, parsed); var bombard = abilityDef.comps?.OfType().FirstOrDefault(); if (bombard != null) return BombardmentUtility.ExecuteStrafeBombardment(map, targetCell, abilityDef, bombard, parsed); var lance = abilityDef.comps?.OfType().FirstOrDefault(); if (lance != null) return BombardmentUtility.ExecuteEnergyLance(map, targetCell, abilityDef, lance, parsed); var skyfaller = abilityDef.comps?.OfType().FirstOrDefault(); if (skyfaller != null) return BombardmentUtility.ExecuteCallSkyfaller(map, targetCell, abilityDef, skyfaller); return $"Error: AbilityDef '{abilityDefName}' is not a supported bombardment/support type."; } catch (Exception ex) { return $"Error: {ex.Message}"; } } private static bool TryParseTargetCell(Dictionary parsed, out IntVec3 cell) { cell = IntVec3.Invalid; if (TryGetInt(parsed, "x", out int x) && TryGetInt(parsed, "z", out int z)) { cell = new IntVec3(x, 0, z); return true; } if (TryGetString(parsed, "cell", out var cellStr) && !string.IsNullOrWhiteSpace(cellStr)) { var parts = cellStr.Split(new[] { ',', '\uFF0C', ' ' }, StringSplitOptions.RemoveEmptyEntries); if (parts.Length >= 2 && int.TryParse(parts[0], out int cx) && int.TryParse(parts[1], out int cz)) { cell = new IntVec3(cx, 0, cz); return true; } } return false; } } }