diff --git a/1.6/1.6/Assemblies/WulaFallenEmpire.dll b/1.6/1.6/Assemblies/WulaFallenEmpire.dll
index 387a0dc0..31601a33 100644
Binary files a/1.6/1.6/Assemblies/WulaFallenEmpire.dll and b/1.6/1.6/Assemblies/WulaFallenEmpire.dll differ
diff --git a/Source/WulaFallenEmpire/EventSystem/AI/Tools/Tool_GetMapPawns.cs b/Source/WulaFallenEmpire/EventSystem/AI/Tools/Tool_GetMapPawns.cs
index 8dd75d30..3efffd79 100644
--- a/Source/WulaFallenEmpire/EventSystem/AI/Tools/Tool_GetMapPawns.cs
+++ b/Source/WulaFallenEmpire/EventSystem/AI/Tools/Tool_GetMapPawns.cs
@@ -10,8 +10,16 @@ namespace WulaFallenEmpire.EventSystem.AI.Tools
public class Tool_GetMapPawns : AITool
{
public override string Name => "get_map_pawns";
- public override string Description => "Scans the current map and lists pawns. Supports filtering by relation (friendly/hostile/neutral), type (colonist/animal/mechanoid/humanlike), and status (prisoner/slave/guest/downed).";
- public override string UsageSchema => "string (optional, comma-separated: friendly, hostile, neutral, colonist, animal, mech, humanlike, prisoner, slave, guest, wild, downed)int (optional, default 50)";
+ public override string Description => "Scans the current map and lists pawns (including corpses). Supports filtering by relation (friendly/hostile/neutral), type (colonist/animal/mech/humanlike), and status (prisoner/slave/guest/wild/downed/dead).";
+ public override string UsageSchema =>
+ "string (optional, comma-separated: friendly, hostile, neutral, colonist, animal, mech, humanlike, prisoner, slave, guest, wild, downed, dead)true/false (optional, default true)int (optional, default 50)";
+
+ private struct MapPawnEntry
+ {
+ public Pawn Pawn;
+ public bool IsDead;
+ public IntVec3 Position;
+ }
public override string Execute(string args)
{
@@ -21,36 +29,85 @@ namespace WulaFallenEmpire.EventSystem.AI.Tools
string filterRaw = null;
if (parsed.TryGetValue("filter", out string f)) filterRaw = f;
+
int maxResults = 50;
if (parsed.TryGetValue("maxResults", out string maxStr) && int.TryParse(maxStr, out int mr))
{
maxResults = Math.Max(1, Math.Min(200, mr));
}
+ bool includeDead = true;
+ if (parsed.TryGetValue("includeDead", out string includeDeadStr) && bool.TryParse(includeDeadStr, out bool parsedIncludeDead))
+ {
+ includeDead = parsedIncludeDead;
+ }
+
Map map = Find.CurrentMap;
if (map == null) return "Error: No active map.";
var filters = ParseFilters(filterRaw);
+ if (filters.Contains("dead")) includeDead = true;
- List pawns = map.mapPawns?.AllPawnsSpawned?.Where(p => p != null).ToList() ?? new List();
- pawns = pawns.Where(p => MatchesFilters(p, filters)).ToList();
+ var entries = new List();
- if (pawns.Count == 0) return "No pawns matched.";
+ var livePawns = map.mapPawns?.AllPawnsSpawned?.Where(p => p != null).ToList() ?? new List();
+ foreach (var pawn in livePawns)
+ {
+ entries.Add(new MapPawnEntry
+ {
+ Pawn = pawn,
+ IsDead = pawn.Dead,
+ Position = pawn.Position
+ });
+ }
- pawns = pawns
- .OrderByDescending(p => IsHostileToPlayer(p))
- .ThenByDescending(p => p.RaceProps?.Humanlike ?? false)
- .ThenBy(p => p.def?.label ?? "")
- .ThenBy(p => p.Name?.ToStringShort ?? "")
+ if (includeDead && map.listerThings != null)
+ {
+ var corpses = map.listerThings.ThingsInGroup(ThingRequestGroup.Corpse);
+ if (corpses != null)
+ {
+ foreach (var thing in corpses)
+ {
+ if (thing is not Corpse corpse) continue;
+ Pawn inner = corpse.InnerPawn;
+ if (inner == null) continue;
+
+ entries.Add(new MapPawnEntry
+ {
+ Pawn = inner,
+ IsDead = true,
+ Position = corpse.Position
+ });
+ }
+ }
+ }
+
+ entries = entries
+ .Where(e => e.Pawn != null)
+ .GroupBy(e => e.Pawn.thingIDNumber)
+ .Select(g => g.First())
+ .Where(e => includeDead || !e.IsDead)
+ .Where(e => MatchesFilters(e, filters))
+ .ToList();
+
+ if (entries.Count == 0) return "No pawns matched.";
+
+ int matched = entries.Count;
+ var selected = entries
+ .OrderByDescending(e => IsHostileToPlayer(e.Pawn))
+ .ThenBy(e => e.IsDead) // living first
+ .ThenByDescending(e => e.Pawn.RaceProps?.Humanlike ?? false)
+ .ThenBy(e => e.Pawn.def?.label ?? "")
+ .ThenBy(e => e.Pawn.Name?.ToStringShort ?? "")
.Take(maxResults)
.ToList();
StringBuilder sb = new StringBuilder();
- sb.AppendLine($"Found {pawns.Count} pawns on map (showing up to {maxResults}):");
+ sb.AppendLine($"Found {matched} matching pawns on map (showing {selected.Count}):");
- foreach (var pawn in pawns)
+ foreach (var entry in selected)
{
- AppendPawnLine(sb, pawn);
+ AppendPawnLine(sb, entry);
}
return sb.ToString().TrimEnd();
@@ -66,7 +123,7 @@ namespace WulaFallenEmpire.EventSystem.AI.Tools
var set = new HashSet(StringComparer.OrdinalIgnoreCase);
if (string.IsNullOrWhiteSpace(filterRaw)) return set;
- var parts = filterRaw.Split(new[] { ',', ',', ';', '、', '|' }, StringSplitOptions.RemoveEmptyEntries);
+ var parts = filterRaw.Split(new[] { ',', '\uFF0C', ';', '\u3001', '|' }, StringSplitOptions.RemoveEmptyEntries);
foreach (var part in parts)
{
string token = part.Trim().ToLowerInvariant();
@@ -85,16 +142,18 @@ namespace WulaFallenEmpire.EventSystem.AI.Tools
else if (token == "访客" || token == "客人") token = "guest";
else if (token == "野生") token = "wild";
else if (token == "倒地" || token == "昏迷") token = "downed";
+ else if (token == "死亡" || token == "尸体") token = "dead";
set.Add(token);
}
return set;
}
- private static bool MatchesFilters(Pawn pawn, HashSet filters)
+ private static bool MatchesFilters(MapPawnEntry entry, HashSet filters)
{
if (filters == null || filters.Count == 0) return true;
+ Pawn pawn = entry.Pawn;
bool anyMatched = false;
foreach (var f in filters)
{
@@ -112,6 +171,7 @@ namespace WulaFallenEmpire.EventSystem.AI.Tools
"guest" => pawn.guest != null && pawn.Faction != null && pawn.Faction != Faction.OfPlayer,
"wild" => pawn.Faction == null && (pawn.RaceProps?.Animal ?? false),
"downed" => pawn.Downed,
+ "dead" => entry.IsDead || pawn.Dead,
_ => false
};
@@ -137,19 +197,20 @@ namespace WulaFallenEmpire.EventSystem.AI.Tools
private static bool IsNeutralToPlayer(Pawn pawn)
{
if (pawn == null || Faction.OfPlayer == null) return false;
- if (pawn.Faction == null) return true; // wild/animals etc.
+ if (pawn.Faction == null) return true;
if (pawn.Faction == Faction.OfPlayer) return false;
return !pawn.HostileTo(Faction.OfPlayer);
}
- private static void AppendPawnLine(StringBuilder sb, Pawn pawn)
+ private static void AppendPawnLine(StringBuilder sb, MapPawnEntry entry)
{
+ Pawn pawn = entry.Pawn;
string name = pawn.Name?.ToStringShort ?? pawn.LabelShortCap;
string kind = pawn.def?.label ?? "unknown";
string faction = pawn.Faction?.Name ?? (pawn.RaceProps?.Animal == true ? "Wild" : "None");
string relation = IsHostileToPlayer(pawn) ? "Hostile" : (pawn.Faction == Faction.OfPlayer ? "Player" : "Non-hostile");
- string tags = BuildTags(pawn);
- string pos = pawn.Position.IsValid ? pawn.Position.ToString() : "?";
+ string tags = BuildTags(pawn, entry.IsDead);
+ string pos = entry.Position.IsValid ? entry.Position.ToString() : (pawn.Position.IsValid ? pawn.Position.ToString() : "?");
sb.Append($"- {name} ({kind})");
sb.Append($" faction={faction} relation={relation} pos={pos}");
@@ -157,7 +218,7 @@ namespace WulaFallenEmpire.EventSystem.AI.Tools
sb.AppendLine();
}
- private static string BuildTags(Pawn pawn)
+ private static string BuildTags(Pawn pawn, bool isDead)
{
var tags = new List();
if (pawn.IsFreeColonist) tags.Add("colonist");
@@ -165,6 +226,7 @@ namespace WulaFallenEmpire.EventSystem.AI.Tools
if (pawn.IsSlaveOfColony) tags.Add("slave");
if (pawn.guest != null && pawn.Faction != null && pawn.Faction != Faction.OfPlayer) tags.Add("guest");
if (pawn.Downed) tags.Add("downed");
+ if (isDead || pawn.Dead) tags.Add("dead");
if (pawn.InMentalState) tags.Add("mental");
if (pawn.Drafted) tags.Add("drafted");
if (pawn.RaceProps?.Humanlike ?? false) tags.Add("humanlike");
@@ -174,3 +236,4 @@ namespace WulaFallenEmpire.EventSystem.AI.Tools
}
}
}
+
diff --git a/Source/WulaFallenEmpire/EventSystem/AI/UI/Dialog_AIConversation.cs b/Source/WulaFallenEmpire/EventSystem/AI/UI/Dialog_AIConversation.cs
index a467df55..5541cf55 100644
--- a/Source/WulaFallenEmpire/EventSystem/AI/UI/Dialog_AIConversation.cs
+++ b/Source/WulaFallenEmpire/EventSystem/AI/UI/Dialog_AIConversation.cs
@@ -183,15 +183,16 @@ Usage:
Description: Scans the current map and lists pawns. Supports filtering by relation/type/status.
Use this tool when:
- You need to know what pawns are present on the map (raiders, visitors, animals, mechs, colonists).
-- The player claims there are threats or asks about who/what is nearby.
-Parameters:
-- filter: (OPTIONAL) Comma-separated filters: friendly, hostile, neutral, colonist, animal, mech, humanlike, prisoner, slave, guest, wild, downed.
-- maxResults: (OPTIONAL) Max lines to return (default 50).
-Usage:
-
+ - The player claims there are threats or asks about who/what is nearby.
+ Parameters:
+ - filter: (OPTIONAL) Comma-separated filters: friendly, hostile, neutral, colonist, animal, mech, humanlike, prisoner, slave, guest, wild, downed, dead.
+ - includeDead: (OPTIONAL) true/false, include corpse pawns (default true).
+ - maxResults: (OPTIONAL) Max lines to return (default 50).
+ Usage:
+
hostile, humanlike
50
-
+
## call_bombardment
Description: Calls orbital bombardment support at a specified map coordinate using an AbilityDef's bombardment configuration (e.g., WULA_Firepower_Cannon_Salvo).