Files
WulaFallenEmpireRW/Source/WulaFallenEmpire/EventSystem/AI/Tools/Tool_CallBombardment.cs
ProjectKoi-Kalo\Kalo 1e64302d21 新增原生工具调用数据结构与解析:SimpleAIClient.cs
AITool 增加 Schema 构造器与函数定义生成,所有工具补齐 GetParametersSchema():AITool.cs 与 *.cs
2025-12-31 15:44:57 +08:00

110 lines
5.1 KiB
C#

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<string, object> GetParametersSchema()
{
var properties = new Dictionary<string, object>
{
["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<AbilityDef>.GetNamed(abilityDefName, false);
if (abilityDef == null) return $"Error: AbilityDef '{abilityDefName}' not found.";
// Switch logic based on AbilityDef components
var circular = abilityDef.comps?.OfType<CompProperties_AbilityCircularBombardment>().FirstOrDefault();
if (circular != null) return BombardmentUtility.ExecuteCircularBombardment(map, targetCell, abilityDef, circular, parsed);
var bombard = abilityDef.comps?.OfType<CompProperties_AbilityBombardment>().FirstOrDefault();
if (bombard != null) return BombardmentUtility.ExecuteStrafeBombardment(map, targetCell, abilityDef, bombard, parsed);
var lance = abilityDef.comps?.OfType<CompProperties_AbilityEnergyLance>().FirstOrDefault();
if (lance != null) return BombardmentUtility.ExecuteEnergyLance(map, targetCell, abilityDef, lance, parsed);
var skyfaller = abilityDef.comps?.OfType<CompProperties_AbilityCallSkyfaller>().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<string, object> 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;
}
}
}