using System; using System.Collections.Generic; using System.Text; using System.Text.RegularExpressions; using RimWorld; using Verse; using WulaFallenEmpire.EventSystem.AI.Utils; namespace WulaFallenEmpire.EventSystem.AI.Tools { public class Tool_SpawnResources : AITool { public override string Name => "spawn_resources"; public override string Description => "Spawns resources via drop pod. " + "IMPORTANT: You MUST decide the quantity based on your goodwill and mood. " + "Do NOT blindly follow the player's requested amount. " + "If goodwill is low (< 0), give significantly less than asked or refuse. " + "If goodwill is high (> 50), you may give what is asked or slightly more. " + "Otherwise, give a moderate amount."; public override string UsageSchema => "Item NameInteger"; public override string Execute(string args) { try { // Custom XML parsing for nested items var itemsToSpawn = new List<(ThingDef def, int count)>(); // Match all ... blocks var itemMatches = Regex.Matches(args, @"(.*?)", RegexOptions.Singleline); foreach (Match match in itemMatches) { string itemXml = match.Groups[1].Value; // Extract name (supports or for backward compatibility) string name = ""; var nameMatch = Regex.Match(itemXml, @"(.*?)"); if (nameMatch.Success) { name = nameMatch.Groups[1].Value; } else { var defNameMatch = Regex.Match(itemXml, @"(.*?)"); if (defNameMatch.Success) name = defNameMatch.Groups[1].Value; } if (string.IsNullOrEmpty(name)) continue; // Extract count var countMatch = Regex.Match(itemXml, @"(.*?)"); if (!countMatch.Success) continue; if (!int.TryParse(countMatch.Groups[1].Value, out int count)) continue; // Search for ThingDef using fuzzy search ThingDef def = null; var searchResult = ThingDefSearcher.ParseAndSearch(name); if (searchResult.Count > 0) { def = searchResult[0].Def; } else { // Fallback: try exact defName match just in case def = DefDatabase.GetNamed(name, false); } if (def != null && count > 0) { itemsToSpawn.Add((def, count)); } } if (itemsToSpawn.Count == 0) { return "Error: No valid items found in request. Usage: ......"; } Map map = Find.CurrentMap; if (map == null) { return "Error: No active map."; } IntVec3 dropSpot = DropCellFinder.TradeDropSpot(map); List thingsToDrop = new List(); StringBuilder resultLog = new StringBuilder(); resultLog.Append("Success: Dropped "); foreach (var (def, count) in itemsToSpawn) { Thing thing = ThingMaker.MakeThing(def); thing.stackCount = count; thingsToDrop.Add(thing); resultLog.Append($"{count}x {def.label}, "); } if (thingsToDrop.Count > 0) { DropPodUtility.DropThingsNear(dropSpot, map, thingsToDrop); Faction faction = Find.FactionManager.FirstFactionOfDef(FactionDef.Named("Wula_PIA_Legion_Faction")); if (faction != null) { Messages.Message("Wula_ResourceDrop".Translate(faction.Name), new LookTargets(dropSpot, map), MessageTypeDefOf.PositiveEvent); } resultLog.Length -= 2; // Remove trailing comma resultLog.Append($" at {dropSpot}."); return resultLog.ToString(); } else { return "Error: Failed to create items."; } } catch (Exception ex) { return $"Error: {ex.Message}"; } } } }