diff --git a/1.6/1.6/Assemblies/WulaFallenEmpire.dll b/1.6/1.6/Assemblies/WulaFallenEmpire.dll
index 9f0feedc..86145388 100644
Binary files a/1.6/1.6/Assemblies/WulaFallenEmpire.dll and b/1.6/1.6/Assemblies/WulaFallenEmpire.dll differ
diff --git a/1.6/1.6/Defs/JobDefs/WULA_JobDefs.xml b/1.6/1.6/Defs/JobDefs/WULA_JobDefs.xml
index 79489a62..ea7a7900 100644
--- a/1.6/1.6/Defs/JobDefs/WULA_JobDefs.xml
+++ b/1.6/1.6/Defs/JobDefs/WULA_JobDefs.xml
@@ -69,6 +69,18 @@
false
+
+ WULA_TransformPawn
+ WulaFallenEmpire.JobDriver_TransformPawn
+ 变更装备中。
+ true
+ true
+ true
+ false
+ Always
+ false
+
+
WULA_EnterMech
diff --git a/1.6/1.6/Defs/ThingDefs_Buildings/WULA_Turret_Buildings.xml b/1.6/1.6/Defs/ThingDefs_Buildings/WULA_Turret_Buildings.xml
index cb08025e..5776549f 100644
--- a/1.6/1.6/Defs/ThingDefs_Buildings/WULA_Turret_Buildings.xml
+++ b/1.6/1.6/Defs/ThingDefs_Buildings/WULA_Turret_Buildings.xml
@@ -265,7 +265,7 @@
WULA_Cat_Bunker_Cleanzone
- 清理出一块场地并准备好资源,使得乌拉帝国可以向此处投放建筑。\n\n乌拉猫猫地堡是集生产和防御为一体的坚实建筑,3只乌拉猫猫自律机械体会和地堡一起空降。地堡可供乌拉猫猫更换工作类型,并允许乌拉猫猫进驻使用内部武器击败来犯敌军。
+ 清理出一块场地并准备好资源,使得乌拉帝国可以向此处投放建筑。\n\n乌拉猫猫地堡是集生产和防御为一体的坚实建筑,3只乌拉猫猫自律机械体会和地堡一起空降。地堡可供乌拉猫猫更换工作类型,并拥有内部武器用于击败来犯敌军。
Wula/Building/WULA_Cat_Bunker_south
MinifiedThing
Normal
@@ -385,9 +385,9 @@
WULA_Cat_Bunker
- 这是一个从乌拉帝国母舰上空投下来的地堡,它拥有一些预制件,可以供乌拉猫猫更换其工作类型。此外,当敌人袭击时,可将乌拉猫猫召回至地堡内,它们将在地堡里对外射击以击退来犯者。
- WulaFallenEmpire.Building_MechanoidRecycler
+ 这是一个从乌拉帝国母舰上空投下来的地堡,它拥有一些预制件,可以供乌拉猫猫更换其工作类型。此外,当敌人袭击时,地堡的自动机枪会对外射击以击退来犯者。
Normal
+ Building_TurretGun
WULA_Cat_Bunker_TurretGun
Mech_WULA_Cat
@@ -407,10 +407,8 @@
Building
- Impassable
- true
- 1
- false
+ PassThroughOnly
+ 0.9
false
false
false
@@ -444,101 +442,28 @@
true
false
-
- 6
-
-
-
- Mech_WULA_Cat
- Mech_WULA_Cat_Constructor
- Mech_WULA_Cat_Assault
-
- WULA_RecycleMechanoid
- 5
-
-
-
- Mech_WULA_Cat
- Mech_WULA_Cat_Constructor
- Mech_WULA_Cat_Assault
-
-
-
-
-
- Mech_WULA_Cat
- 1
-
-
- Mech_WULA_Cat_Constructor
- 1
-
-
- Mech_WULA_Cat_Assault
- 1
-
-
-
-
+
+ Mech_WULA_Cat_Assault
+ 3
+ true
+ false
+ true
+
+ 500
+
+ 60
+
+
true
-
-
- 1
- WULA_Cat_Bunker_TurretGun
- 0
- true
- 1
- true
-
-
- 2
- WULA_Cat_Bunker_TurretGun
- 0
- true
- 2
- true
-
-
- 3
- WULA_Cat_Bunker_TurretGun
- 0
- true
- 3
- true
-
-
- 4
- WULA_Cat_Bunker_TurretGun
- 0
- true
- 4
- true
-
-
- 5
- WULA_Cat_Bunker_TurretGun
- 0
- true
- 5
- true
-
-
- 6
- WULA_Cat_Bunker_TurretGun
- 0
- true
- 6
- true
-
WULA_Cat_Bunker_TurretGun
- 由进入地堡的乌拉猫猫操纵的炮塔——说那么多干什么,扣扳机就完了,殖民地会报销弹药的。
+ 由驻守地堡的乌拉猫猫操纵的炮塔——说那么多干什么,扣扳机就完了,殖民地会报销弹药的。
Wula/Weapon/WULA_Weapon_Empty
Graphic_Single
@@ -558,7 +483,7 @@
Bullet_WULA_RW_Base_AR
28
5
- 12
+ 24
Shot_AssaultRifle
GunTail_Medium
9
diff --git a/1.6/1.6/Defs/ThingDefs_Races/Races_Wulaspecies.xml b/1.6/1.6/Defs/ThingDefs_Races/Races_Wulaspecies.xml
index 610a2796..7ac3aef8 100644
--- a/1.6/1.6/Defs/ThingDefs_Races/Races_Wulaspecies.xml
+++ b/1.6/1.6/Defs/ThingDefs_Races/Races_Wulaspecies.xml
@@ -951,6 +951,16 @@
Firefighter
+
+
+ true
+
+ Mech_WULA_Cat
+ Mech_WULA_Cat_Constructor
+ Mech_WULA_Cat_Assault
+
+
+
Mech_WULA_Cat_Constructor
@@ -975,6 +985,16 @@
2
+
+
+ true
+
+ Mech_WULA_Cat
+ Mech_WULA_Cat_Constructor
+ Mech_WULA_Cat_Assault
+
+
+
Mech_WULA_Cat_Assault
@@ -1003,6 +1023,16 @@
4
+
+
+ true
+
+ Mech_WULA_Cat
+ Mech_WULA_Cat_Constructor
+ Mech_WULA_Cat_Assault
+
+
+
Mech_WULA_Cat_Cloak_Sniper
diff --git a/Source/WulaFallenEmpire/BuildingComp/WULA_BuildToPawn/CompBuildToPawn.cs b/Source/WulaFallenEmpire/BuildingComp/WULA_BuildToPawn/CompBuildToPawn.cs
new file mode 100644
index 00000000..008e8fa1
--- /dev/null
+++ b/Source/WulaFallenEmpire/BuildingComp/WULA_BuildToPawn/CompBuildToPawn.cs
@@ -0,0 +1,62 @@
+// CompBuildToPawn_SimpleDelay.cs
+using RimWorld;
+using System.Collections.Generic;
+using Verse;
+
+namespace WulaFallenEmpire
+{
+ public class CompBuildToPawn : ThingComp
+ {
+ public CompProperties_BuildToPawn Props => (CompProperties_BuildToPawn)props;
+
+ private bool shouldSpawn = false;
+ private int delayCounter = 0;
+
+ public override void PostSpawnSetup(bool respawningAfterLoad)
+ {
+ base.PostSpawnSetup(respawningAfterLoad);
+
+ // 跳过存档加载和蓝图/框架
+ if (respawningAfterLoad || parent.def.IsBlueprint || parent.def.IsFrame)
+ return;
+
+ // 延迟一帧
+ shouldSpawn = true;
+ delayCounter = 0;
+ }
+
+ public override void CompTick()
+ {
+ base.CompTick();
+
+ if (shouldSpawn && delayCounter >= 1) // 延迟一帧后执行
+ {
+ if (Props.pawnKindDef != null && parent != null && !parent.Destroyed && parent.Map != null)
+ {
+ // 生成Pawn
+ for (int i = 0; i < Props.spawnCount; i++)
+ {
+ Pawn pawn = PawnGenerator.GeneratePawn(Props.pawnKindDef);
+ if (Props.inheritFaction)
+ pawn.SetFaction(parent.Faction, null);
+
+ GenSpawn.Spawn(pawn, parent.Position, parent.Map, WipeMode.Vanish);
+
+ if (Props.initDrafted && pawn.drafter!=null)
+ pawn.drafter.Drafted = true;
+ }
+
+ if (Props.destroyBuilding)
+ // 摧毁建筑
+ parent.Destroy();
+ }
+
+ shouldSpawn = false;
+ }
+ else if (shouldSpawn)
+ {
+ delayCounter++;
+ }
+ }
+ }
+}
diff --git a/Source/WulaFallenEmpire/BuildingComp/WULA_BuildToPawn/CompProperties_BuildToPawn.cs b/Source/WulaFallenEmpire/BuildingComp/WULA_BuildToPawn/CompProperties_BuildToPawn.cs
new file mode 100644
index 00000000..5378cc98
--- /dev/null
+++ b/Source/WulaFallenEmpire/BuildingComp/WULA_BuildToPawn/CompProperties_BuildToPawn.cs
@@ -0,0 +1,20 @@
+// CompProperties_BuildToPawn.cs
+using RimWorld;
+using Verse;
+
+namespace WulaFallenEmpire
+{
+ public class CompProperties_BuildToPawn : CompProperties
+ {
+ public PawnKindDef pawnKindDef; // 要生成的Pawn种类
+ public int spawnCount = 1; // 生成数量,默认为1
+ public bool inheritFaction = true; // 是否继承建筑的派系
+ public bool destroyBuilding = false; // 是否销毁建筑
+ public bool initDrafted = false; // 是否生成时直接设为征召
+
+ public CompProperties_BuildToPawn()
+ {
+ this.compClass = typeof(CompBuildToPawn);
+ }
+ }
+}
diff --git a/Source/WulaFallenEmpire/BuildingComp/WULA_Gather/CompGather.cs b/Source/WulaFallenEmpire/BuildingComp/WULA_Gather/CompGather.cs
new file mode 100644
index 00000000..1355c57d
--- /dev/null
+++ b/Source/WulaFallenEmpire/BuildingComp/WULA_Gather/CompGather.cs
@@ -0,0 +1,400 @@
+using System;
+using System.Collections.Generic;
+using Verse;
+using Verse.AI;
+using RimWorld;
+using UnityEngine;
+
+namespace WulaFallenEmpire
+{
+ // 召集组件属性
+ public class CompProperties_Gather : CompProperties
+ {
+ public float gatherRange = 100f; // 召集范围(单元格)
+ public SoundDef gatherSound; // 召集音效
+ public int cooldownTicks = 1200; // 召集冷却时间(tick,默认20秒)
+
+ // 转化相关
+ public bool canTransformPawns = true; // 是否允许转化Pawn
+ public IntVec3 spawnOffset = IntVec3.Zero; // 新Pawn生成位置偏移
+
+ public CompProperties_Gather()
+ {
+ compClass = typeof(Comp_Gather);
+ }
+ }
+
+ // 召集组件实现
+ public class Comp_Gather : ThingComp
+ {
+ private int lastGatherTick = -1000; // 上一次召集的tick
+ private bool gatheringActive = false; // 召集是否正在进行
+ private int gatherDurationLeft = 0; // 召集持续时间剩余
+
+ // Gizmo缓存
+ private Command_Action cachedGizmo;
+
+ // 属性
+ public CompProperties_Gather Props => (CompProperties_Gather)props;
+
+ public bool CanGatherNow
+ {
+ get
+ {
+ if (!parent.Spawned || parent.Destroyed)
+ return false;
+
+ // 检查冷却时间
+ int currentTick = Find.TickManager.TicksGame;
+ if (currentTick - lastGatherTick < Props.cooldownTicks)
+ return false;
+
+ // 检查建筑是否可用
+ if (parent is Building building)
+ {
+ if (building.IsBrokenDown() || building.IsForbidden(Faction.OfPlayer))
+ return false;
+ }
+
+ return true;
+ }
+ }
+
+ public bool IsGatheringActive => gatheringActive;
+
+ // 公开方法:检查是否可以进行转化
+ public bool CanTransformPawn(Pawn pawn)
+ {
+ if (!Props.canTransformPawns)
+ return false;
+
+ if (!parent.Spawned || parent.Destroyed)
+ return false;
+
+ // 检查Pawn是否拥有AutonomousCat组件
+ if (pawn.TryGetComp() == null)
+ return false;
+
+ // 检查建筑是否可用
+ if (parent is Building building)
+ {
+ if (building.IsBrokenDown() || building.IsForbidden(Faction.OfPlayer))
+ return false;
+ }
+
+ return true;
+ }
+
+ // 获取生成位置
+ public IntVec3 GetSpawnPosition()
+ {
+ if (parent.Spawned)
+ {
+ return parent.Position + Props.spawnOffset;
+ }
+ return parent.Position;
+ }
+
+ // 公开方法:执行转化
+ public void TransformPawn(Pawn originalPawn, PawnKindDef targetPawnKind)
+ {
+ if (!CanTransformPawn(originalPawn))
+ return;
+
+ try
+ {
+ // 记录原始信息
+ Map map = originalPawn.Map;
+ IntVec3 position = GetSpawnPosition();
+ Faction faction = originalPawn.Faction;
+
+ // 检查位置是否可用
+ if (!position.Walkable(map) || position.Fogged(map))
+ {
+ // 尝试在周围寻找可用位置
+ if (!CellFinder.TryFindRandomCellNear(position, map, 3,
+ (c) => c.Walkable(map) && !c.Fogged(map), out position))
+ {
+ Messages.Message("Wula_NoSpawnSpace".Translate(), MessageTypeDefOf.RejectInput);
+ return;
+ }
+ }
+
+ // 创建新的Pawn
+ Pawn newPawn = PawnGenerator.GeneratePawn(targetPawnKind, faction);
+
+ // 复制一些重要信息
+ if (originalPawn.Name != null)
+ {
+ newPawn.Name = originalPawn.Name;
+ }
+ newPawn.gender = originalPawn.gender;
+
+ // 销毁原始Pawn
+ originalPawn.Destroy(DestroyMode.Vanish);
+
+ // 生成新的Pawn
+ GenSpawn.Spawn(newPawn, position, map);
+
+ // 为新Pawn添加AutonomousCat组件(如果还没有)
+ EnsureAutonomousCatComponent(newPawn);
+
+ // 显示消息
+ Messages.Message(
+ "Wula_TransformComplete".Translate(originalPawn.LabelShort, newPawn.LabelShort),
+ MessageTypeDefOf.PositiveEvent
+ );
+
+ // 记录日志
+ if (Prefs.DevMode)
+ {
+ Log.Message($"[CompGather] Transformation complete: {originalPawn.LabelShort} -> {newPawn.LabelShort}");
+ }
+ }
+ catch (Exception ex)
+ {
+ Log.Error($"Error completing transformation: {ex.Message}");
+ }
+ }
+
+ // 确保新Pawn有AutonomousCat组件
+ private void EnsureAutonomousCatComponent(Pawn newPawn)
+ {
+ // 检查是否已经有AutonomousCat组件
+ if (newPawn.TryGetComp() != null)
+ return;
+
+ // 检查Pawn的定义中是否有AutonomousCat组件
+ var compProps = newPawn.def.comps?.Find(c => c.compClass == typeof(Comp_AutonomousCat)) as CompProperties_AutonomousCat;
+ if (compProps == null)
+ {
+ // 如果没有,添加一个默认的AutonomousCat组件
+ newPawn.AllComps.Add(new Comp_AutonomousCat()
+ {
+ parent = newPawn,
+ props = new CompProperties_AutonomousCat()
+ {
+ autoDraftOnGather = true
+ }
+ });
+
+ if (Prefs.DevMode)
+ {
+ Log.Message($"[CompGather] Added AutonomousCat component to {newPawn.LabelShort}");
+ }
+ }
+ }
+
+ // Gizmo显示
+ public override IEnumerable CompGetGizmosExtra()
+ {
+ foreach (Gizmo gizmo in base.CompGetGizmosExtra())
+ {
+ yield return gizmo;
+ }
+
+ // 只对玩家派系显示
+ if (parent.Faction == Faction.OfPlayer)
+ {
+ if (cachedGizmo == null)
+ {
+ InitializeGizmo();
+ }
+
+ yield return cachedGizmo;
+ }
+ }
+
+ private void InitializeGizmo()
+ {
+ cachedGizmo = new Command_Action();
+ cachedGizmo.defaultLabel = "Wula_GatherCats".Translate();
+ cachedGizmo.defaultDesc = "Wula_GatherCatsDesc".Translate();
+ cachedGizmo.icon = ContentFinder.Get("UI/Gizmos/GatherCats", false) ?? BaseContent.BadTex;
+ cachedGizmo.action = StartGathering;
+
+ // 添加冷却时间显示
+ cachedGizmo.disabledReason = GetDisabledReason();
+
+ // 热键
+ cachedGizmo.hotKey = KeyBindingDefOf.Misc2;
+ }
+
+ private string GetDisabledReason()
+ {
+ if (!parent.Spawned || parent.Destroyed)
+ return "Building destroyed or not spawned";
+
+ int currentTick = Find.TickManager.TicksGame;
+ int ticksSinceLastGather = currentTick - lastGatherTick;
+
+ if (ticksSinceLastGather < Props.cooldownTicks)
+ {
+ int remainingTicks = Props.cooldownTicks - ticksSinceLastGather;
+ return "Wula_GatherCooldown".Translate(remainingTicks.ToStringTicksToPeriod());
+ }
+
+ if (parent is Building building && building.IsBrokenDown())
+ return "Wula_BuildingBroken".Translate();
+
+ return null;
+ }
+
+ // 开始召集
+ private void StartGathering()
+ {
+ if (!CanGatherNow)
+ return;
+
+ // 记录召集时间
+ lastGatherTick = Find.TickManager.TicksGame;
+
+ // 设置召集状态
+ gatheringActive = true;
+ gatherDurationLeft = 60; // 持续1秒
+
+ // 查找并命令范围内的 Autonomous Cats
+ GatherAutonomousCats();
+
+ // 显示消息
+ Messages.Message("Wula_GatheringStarted".Translate(), MessageTypeDefOf.PositiveEvent);
+
+ // 刷新Gizmo状态
+ cachedGizmo.disabledReason = GetDisabledReason();
+ }
+
+ // 查找并命令 Autonomous Cats
+ private void GatherAutonomousCats()
+ {
+ if (parent.Map == null)
+ return;
+
+ // 查找范围内的所有 Autonomous Cats
+ List autonomousCats = new List();
+ foreach (Pawn pawn in parent.Map.mapPawns.AllPawnsSpawned)
+ {
+ // 检查是否拥有 AutonomousCat 组件
+ var comp = pawn.TryGetComp();
+ if (comp != null)
+ {
+ // 检查是否有待处理的转化,如果有则不响应召集
+ if (comp.PendingTransformTarget != null)
+ continue;
+
+ // 检查距离
+ float distance = pawn.Position.DistanceTo(parent.Position);
+ if (distance <= Props.gatherRange)
+ {
+ autonomousCats.Add(pawn);
+ }
+ }
+ }
+
+ // 命令每个 Autonomous Cat
+ foreach (Pawn cat in autonomousCats)
+ {
+ CommandCatToGather(cat);
+ }
+
+ // 报告召集数量
+ if (autonomousCats.Count > 0)
+ {
+ Messages.Message(
+ "Wula_CatsGathered".Translate(autonomousCats.Count),
+ MessageTypeDefOf.NeutralEvent
+ );
+ }
+ }
+
+ // 命令单个 Autonomous Cat
+ private void CommandCatToGather(Pawn cat)
+ {
+ if (cat == null || !cat.Spawned || cat.Dead)
+ return;
+
+ try
+ {
+ // 获取 AutonomousCat 组件
+ var comp = cat.TryGetComp();
+ if (comp != null)
+ {
+ // 使用组件的响应方法
+ comp.RespondToGather(parent);
+ }
+ else
+ {
+ // 如果没有组件,使用默认行为
+ if (cat.drafter != null)
+ {
+ cat.drafter.Drafted = true;
+ }
+
+ Job job = new Job(JobDefOf.Goto, parent.Position);
+ job.expiryInterval = 30000;
+ job.checkOverrideOnExpire = true;
+
+ if (cat.CurJob != null)
+ {
+ cat.jobs.EndCurrentJob(JobCondition.InterruptForced);
+ }
+
+ cat.jobs.StartJob(job, JobCondition.InterruptForced);
+ }
+
+ // 记录日志
+ if (Prefs.DevMode)
+ {
+ Log.Message($"[CompGather] Cat {cat.LabelShort} commanded to gather at {parent.Position}");
+ }
+ }
+ catch (Exception ex)
+ {
+ Log.Error($"Error commanding cat to gather: {ex.Message}");
+ }
+ }
+
+ // 每帧更新
+ public override void CompTick()
+ {
+ base.CompTick();
+
+ if (gatheringActive)
+ {
+ gatherDurationLeft--;
+ if (gatherDurationLeft <= 0)
+ {
+ gatheringActive = false;
+ }
+ }
+
+ // 每30tick更新一次Gizmo状态
+ if (parent.IsHashIntervalTick(30) && cachedGizmo != null)
+ {
+ cachedGizmo.disabledReason = GetDisabledReason();
+ }
+ }
+
+ // 保存/加载数据
+ public override void PostExposeData()
+ {
+ base.PostExposeData();
+ Scribe_Values.Look(ref lastGatherTick, "lastGatherTick", -1000);
+ Scribe_Values.Look(ref gatheringActive, "gatheringActive", false);
+ Scribe_Values.Look(ref gatherDurationLeft, "gatherDurationLeft", 0);
+ }
+
+ // 绘制效果(可选)
+ public override void PostDraw()
+ {
+ base.PostDraw();
+
+ // 如果正在召集,绘制一个光环效果
+ if (gatheringActive)
+ {
+ float pulse = Mathf.Sin(Find.TickManager.TicksGame * 0.1f) * 0.5f + 0.5f;
+ GenDraw.DrawRadiusRing(parent.Position, Props.gatherRange, Color.Lerp(Color.cyan, Color.white, pulse),
+ (c) => (c.x + c.y + Find.TickManager.TicksGame) % 10 < 5);
+ }
+ }
+ }
+}
diff --git a/Source/WulaFallenEmpire/Pawn_Comps/AutonomousCat/CompAutonomousCat.cs b/Source/WulaFallenEmpire/Pawn_Comps/AutonomousCat/CompAutonomousCat.cs
new file mode 100644
index 00000000..cf35d3ef
--- /dev/null
+++ b/Source/WulaFallenEmpire/Pawn_Comps/AutonomousCat/CompAutonomousCat.cs
@@ -0,0 +1,398 @@
+using System;
+using System.Collections.Generic;
+using Verse;
+using Verse.AI;
+using RimWorld;
+using UnityEngine;
+
+namespace WulaFallenEmpire
+{
+ // AutonomousCat组件属性
+ public class CompProperties_AutonomousCat : CompProperties
+ {
+ public bool autoDraftOnGather = true; // 被召集时自动征召
+
+ // 转化功能
+ public List transformablePawnKinds; // 可转化的Pawn种类列表
+ public float transformTime = 3f; // 转化所需时间(秒)
+ public SoundDef transformSound; // 转化音效
+ public EffecterDef transformEffect; // 转化特效
+
+ // 外观设置
+ public Color gatherLineColor = new Color(0.2f, 0.8f, 0.2f, 0.8f); // 召集线颜色
+ public float gatherLineWidth = 0.2f; // 召集线宽度
+
+ public CompProperties_AutonomousCat()
+ {
+ compClass = typeof(Comp_AutonomousCat);
+ }
+ }
+
+ // AutonomousCat组件实现
+ public class Comp_AutonomousCat : ThingComp
+ {
+ // 状态跟踪
+ private bool isRespondingToGather = false;
+ private Thing gatherTarget = null;
+ private int gatherResponseEndTick = 0;
+
+ // 转化目标
+ private PawnKindDef pendingTransformTarget = null;
+
+ // Gizmo缓存
+ private Command_Action cachedTransformGizmo;
+ private bool gizmoInitialized = false;
+
+ // 属性
+ public CompProperties_AutonomousCat Props => (CompProperties_AutonomousCat)props;
+
+ // 公开属性
+ public bool IsRespondingToGather => isRespondingToGather;
+ public Thing GatherTarget => gatherTarget;
+ public PawnKindDef PendingTransformTarget => pendingTransformTarget;
+
+ public override void Initialize(CompProperties props)
+ {
+ base.Initialize(props);
+ }
+
+ // 响应召集命令
+ public void RespondToGather(Thing target)
+ {
+ if (parent is Pawn pawn && !pawn.Dead && pawn.Spawned)
+ {
+ try
+ {
+ // 如果有待处理的转化,不响应召集
+ if (pendingTransformTarget != null)
+ return;
+
+ // 设置目标
+ gatherTarget = target;
+ isRespondingToGather = true;
+ gatherResponseEndTick = Find.TickManager.TicksGame + 6000; // 100秒后超时
+
+ // 自动征召
+ if (Props.autoDraftOnGather && pawn.drafter != null)
+ {
+ pawn.drafter.Drafted = true;
+ }
+
+ // 创建移动到目标的Job
+ if (target != null && target.Spawned)
+ {
+ CreateGatherJob(pawn, target);
+ }
+
+ // 记录日志
+ if (Prefs.DevMode)
+ {
+ Log.Message($"[CompAutonomousCat] {pawn.LabelShort} responding to gather call from {target?.LabelShort ?? "unknown"}");
+ }
+ }
+ catch (Exception ex)
+ {
+ Log.Error($"Error in RespondToGather for {parent.LabelShort}: {ex.Message}");
+ }
+ }
+ }
+
+ // 创建召集任务
+ private void CreateGatherJob(Pawn pawn, Thing target)
+ {
+ try
+ {
+ // 清除当前任务
+ if (pawn.CurJob != null)
+ {
+ pawn.jobs.EndCurrentJob(JobCondition.InterruptForced);
+ }
+
+ // 创建移动到目标的Job
+ Job job = new Job(JobDefOf.Goto, target.Position);
+
+ // 设置任务优先级和参数
+ job.expiryInterval = 30000; // 长时间有效
+ job.checkOverrideOnExpire = true;
+
+ // 开始任务
+ pawn.jobs.StartJob(job, JobCondition.InterruptForced);
+ }
+ catch (Exception ex)
+ {
+ Log.Error($"Error creating gather job for {pawn.LabelShort}: {ex.Message}");
+ }
+ }
+
+ // 开始转化流程
+ public void StartTransformation(PawnKindDef targetPawnKind)
+ {
+ if (parent is Pawn pawn && !pawn.Dead && pawn.Spawned)
+ {
+ try
+ {
+ // 查找最近的Comp_Gather建筑
+ Thing closestGatherBuilding = FindClosestGatherBuilding();
+
+ if (closestGatherBuilding == null)
+ {
+ Messages.Message(
+ "Wula_NoGatherBuilding".Translate(),
+ MessageTypeDefOf.RejectInput
+ );
+ return;
+ }
+
+ // 存储转化目标
+ pendingTransformTarget = targetPawnKind;
+
+ // 创建转化Job
+ Job job = JobMaker.MakeJob(Wula_JobDefOf.WULA_TransformPawn, closestGatherBuilding);
+
+ // 清除当前任务并开始新任务
+ pawn.jobs.StopAll();
+ pawn.jobs.StartJob(job, JobCondition.InterruptForced);
+
+ // 显示消息
+ Messages.Message(
+ "Wula_TransformStarted".Translate(pawn.LabelShort, targetPawnKind.label),
+ MessageTypeDefOf.NeutralEvent
+ );
+
+ // 记录日志
+ if (Prefs.DevMode)
+ {
+ Log.Message($"[CompAutonomousCat] {pawn.LabelShort} starting transformation to {targetPawnKind.label}");
+ }
+ }
+ catch (Exception ex)
+ {
+ Log.Error($"Error starting transformation for {parent.LabelShort}: {ex.Message}");
+ }
+ }
+ }
+
+ // 清除转化目标(由JobDriver调用)
+ public void ClearTransformTarget()
+ {
+ pendingTransformTarget = null;
+ }
+
+ // 查找最近的Comp_Gather建筑
+ private Thing FindClosestGatherBuilding()
+ {
+ if (parent.Map == null)
+ return null;
+
+ Thing closestBuilding = null;
+ float closestDistance = float.MaxValue;
+
+ // 查找所有Comp_Gather建筑
+ foreach (Thing thing in parent.Map.listerThings.AllThings)
+ {
+ if (thing.TryGetComp() != null &&
+ thing.Spawned &&
+ !thing.Destroyed &&
+ thing.Faction == parent.Faction)
+ {
+ float distance = thing.Position.DistanceTo(parent.Position);
+ if (distance < closestDistance)
+ {
+ closestDistance = distance;
+ closestBuilding = thing;
+ }
+ }
+ }
+
+ return closestBuilding;
+ }
+
+ // 每帧更新
+ public override void CompTick()
+ {
+ base.CompTick();
+
+ // 处理召集响应
+ if (isRespondingToGather)
+ {
+ UpdateGatherResponse();
+ }
+ }
+
+ // 更新召集响应
+ private void UpdateGatherResponse()
+ {
+ // 检查是否超时
+ if (Find.TickManager.TicksGame > gatherResponseEndTick)
+ {
+ EndGatherResponse();
+ return;
+ }
+
+ // 检查目标是否仍然有效
+ if (gatherTarget == null || !gatherTarget.Spawned || gatherTarget.Destroyed)
+ {
+ EndGatherResponse();
+ return;
+ }
+
+ // 检查Pawn是否已经死亡或无法行动
+ if (parent is Pawn pawn && (pawn.Dead || pawn.Downed || !pawn.Spawned))
+ {
+ EndGatherResponse();
+ return;
+ }
+
+ // 检查是否已经到达目标附近
+ if (parent is Pawn movingPawn && movingPawn.Position.DistanceTo(gatherTarget.Position) < 5f)
+ {
+ // 到达目标,结束召集响应
+ EndGatherResponse();
+
+ // 可选:到达后执行其他动作
+ if (movingPawn.CurJobDef == JobDefOf.Goto)
+ {
+ // 切换到等待或警戒状态
+ movingPawn.jobs.EndCurrentJob(JobCondition.Succeeded);
+ }
+ }
+ }
+
+ // 结束召集响应
+ private void EndGatherResponse()
+ {
+ isRespondingToGather = false;
+ gatherTarget = null;
+ }
+
+ // 绘制效果
+ public override void PostDraw()
+ {
+ base.PostDraw();
+
+ // 如果正在响应召集,绘制连接线
+ if (isRespondingToGather && gatherTarget != null && parent.Spawned)
+ {
+ DrawGatherLine();
+ }
+ }
+
+ // 绘制召集线
+ private void DrawGatherLine()
+ {
+ Vector3 startPos = parent.DrawPos;
+ Vector3 endPos = gatherTarget.DrawPos;
+
+ // 提升到覆盖层高度
+ startPos.y = AltitudeLayer.MetaOverlays.AltitudeFor();
+ endPos.y = AltitudeLayer.MetaOverlays.AltitudeFor();
+
+ // 绘制连接线
+ GenDraw.DrawLineBetween(
+ startPos,
+ endPos
+ );
+ }
+
+ // Gizmo显示
+ public override IEnumerable CompGetGizmosExtra()
+ {
+ foreach (Gizmo gizmo in base.CompGetGizmosExtra())
+ {
+ yield return gizmo;
+ }
+
+ // 只对玩家派系显示
+ if (parent.Faction == Faction.OfPlayer && parent is Pawn pawn && !pawn.Dead)
+ {
+ // 延迟初始化Gizmo
+ if (!gizmoInitialized)
+ {
+ InitializeGizmo();
+ gizmoInitialized = true;
+ }
+
+ if (cachedTransformGizmo != null)
+ {
+ // 如果已有待处理的转化,显示不同图标或状态
+ if (pendingTransformTarget != null)
+ {
+ cachedTransformGizmo.disabledReason = "Wula_TransformPending".Translate(pendingTransformTarget.label);
+ }
+
+ yield return cachedTransformGizmo;
+ }
+ }
+ }
+
+ // 初始化Gizmo
+ private void InitializeGizmo()
+ {
+ if (Props.transformablePawnKinds != null && Props.transformablePawnKinds.Count > 0)
+ {
+ cachedTransformGizmo = new Command_Action();
+ cachedTransformGizmo.defaultLabel = "Wula_Transform".Translate();
+ cachedTransformGizmo.defaultDesc = "Wula_TransformDesc".Translate();
+ cachedTransformGizmo.icon = ContentFinder.Get("UI/Gizmos/Transform", false) ?? BaseContent.BadTex;
+ cachedTransformGizmo.action = () => ShowTransformMenu();
+
+ // 设置热键
+ cachedTransformGizmo.hotKey = KeyBindingDefOf.Misc3;
+ }
+ }
+
+ // 显示转化菜单
+ private void ShowTransformMenu()
+ {
+ if (Props.transformablePawnKinds == null || Props.transformablePawnKinds.Count == 0)
+ return;
+
+ List options = new List();
+
+ foreach (PawnKindDef pawnKind in Props.transformablePawnKinds)
+ {
+ options.Add(new FloatMenuOption(
+ pawnKind.LabelCap,
+ () => StartTransformation(pawnKind),
+ pawnKind.race.uiIcon,
+ Color.white
+ ));
+ }
+
+ // 添加取消选项
+ options.Add(new FloatMenuOption(
+ "Cancel".Translate(),
+ null,
+ MenuOptionPriority.Default
+ ));
+
+ Find.WindowStack.Add(new FloatMenu(options));
+ }
+
+ // 保存/加载数据
+ public override void PostExposeData()
+ {
+ base.PostExposeData();
+
+ Scribe_Values.Look(ref isRespondingToGather, "isRespondingToGather", false);
+ Scribe_References.Look(ref gatherTarget, "gatherTarget");
+ Scribe_Values.Look(ref gatherResponseEndTick, "gatherResponseEndTick", 0);
+
+ // 保存/加载转化目标
+ Scribe_Defs.Look(ref pendingTransformTarget, "pendingTransformTarget");
+
+ if (Scribe.mode == LoadSaveMode.PostLoadInit)
+ {
+ // 重置不正确的状态
+ if (isRespondingToGather && (gatherTarget == null || !gatherTarget.Spawned))
+ {
+ isRespondingToGather = false;
+ }
+
+ // 重置Gizmo缓存
+ gizmoInitialized = false;
+ cachedTransformGizmo = null;
+ }
+ }
+ }
+}
diff --git a/Source/WulaFallenEmpire/Pawn_Comps/AutonomousCat/JobDriver_TransformPawn.cs b/Source/WulaFallenEmpire/Pawn_Comps/AutonomousCat/JobDriver_TransformPawn.cs
new file mode 100644
index 00000000..6da93fe0
--- /dev/null
+++ b/Source/WulaFallenEmpire/Pawn_Comps/AutonomousCat/JobDriver_TransformPawn.cs
@@ -0,0 +1,143 @@
+using System.Collections.Generic;
+using Verse;
+using Verse.AI;
+using RimWorld;
+using UnityEngine;
+
+namespace WulaFallenEmpire
+{
+ public class JobDriver_TransformPawn : JobDriver
+ {
+ private const TargetIndex GatherBuildingIndex = TargetIndex.A;
+
+ private Comp_Gather GatherComp => job.targetA.Thing?.TryGetComp();
+ private Comp_AutonomousCat PawnComp => pawn.TryGetComp();
+
+ public override bool TryMakePreToilReservations(bool errorOnFailed)
+ {
+ // 预留目标建筑
+ if (!pawn.Reserve(job.targetA, job, 1, -1, null, errorOnFailed))
+ {
+ return false;
+ }
+ return true;
+ }
+
+ protected override IEnumerable MakeNewToils()
+ {
+ // 第1步:移动到目标建筑
+ yield return Toils_Goto.GotoCell(GatherBuildingIndex, PathEndMode.InteractionCell);
+
+ // 第2步:进行转化工作
+ Toil transformToil = new Toil();
+ transformToil.initAction = () =>
+ {
+ // 获取目标建筑
+ Thing gatherBuilding = job.targetA.Thing;
+ if (gatherBuilding == null || gatherBuilding.Destroyed)
+ {
+ ReadyForNextToil();
+ return;
+ }
+
+ // 获取Comp_Gather
+ var gatherComp = gatherBuilding.TryGetComp();
+ if (gatherComp == null)
+ {
+ ReadyForNextToil();
+ return;
+ }
+
+ // 确保可以转化
+ if (!gatherComp.CanTransformPawn(pawn))
+ {
+ Messages.Message("Wula_CannotTransformHere".Translate(), MessageTypeDefOf.RejectInput);
+ ReadyForNextToil();
+ return;
+ }
+ };
+
+ transformToil.tickAction = () =>
+ {
+ // 确保目标建筑仍然有效
+ Thing gatherBuilding = job.targetA.Thing;
+ if (gatherBuilding == null || gatherBuilding.Destroyed ||
+ gatherBuilding.Map != pawn.Map ||
+ pawn.Position.DistanceTo(gatherBuilding.Position) > 3f)
+ {
+ // 中断转化,清除转化目标
+ PawnComp?.ClearTransformTarget();
+ EndJobWith(JobCondition.Incompletable);
+ return;
+ }
+
+ // 面向建筑
+ pawn.rotationTracker.FaceCell(gatherBuilding.Position);
+
+ // 播放转化效果
+ if (Find.TickManager.TicksGame % 20 == 0)
+ {
+ PlayTransformEffects();
+ }
+ };
+
+ // 从Comp_AutonomousCat获取转化时间
+ var compProps = PawnComp?.Props as CompProperties_AutonomousCat;
+ int transformDuration = compProps != null ?
+ Mathf.RoundToInt(compProps.transformTime * 60f) : 180; // 默认3秒
+
+ transformToil.defaultCompleteMode = ToilCompleteMode.Delay;
+ transformToil.defaultDuration = transformDuration;
+ yield return transformToil;
+
+ // 第3步:完成转化
+ yield return new Toil
+ {
+ initAction = () =>
+ {
+ // 获取目标建筑
+ Thing gatherBuilding = job.targetA.Thing;
+ if (gatherBuilding == null || gatherBuilding.Destroyed)
+ {
+ return;
+ }
+
+ // 获取Comp_Gather
+ var gatherComp = gatherBuilding.TryGetComp();
+ if (gatherComp == null)
+ {
+ return;
+ }
+
+ // 获取要转化的PawnKindDef(从Comp_AutonomousCat中)
+ var targetPawnKind = PawnComp?.PendingTransformTarget;
+ if (targetPawnKind == null)
+ {
+ Messages.Message("Wula_NoTransformTarget".Translate(), MessageTypeDefOf.RejectInput);
+ return;
+ }
+
+ // 调用Comp_Gather的转化方法
+ gatherComp.TransformPawn(pawn, targetPawnKind);
+
+ // 清除转化目标
+ PawnComp?.ClearTransformTarget();
+ },
+ defaultCompleteMode = ToilCompleteMode.Instant
+ };
+ }
+
+ // 播放转化效果
+ private void PlayTransformEffects()
+ {
+ // 播放音效
+ var compProps = PawnComp?.Props as CompProperties_AutonomousCat;
+
+ // 播放特效
+ if (compProps?.transformEffect != null)
+ {
+ compProps.transformEffect.Spawn(pawn.Position, pawn.Map).Cleanup();
+ }
+ }
+ }
+}
diff --git a/Source/WulaFallenEmpire/WulaDefOf.cs b/Source/WulaFallenEmpire/WulaDefOf.cs
index 627e86af..d98eeede 100644
--- a/Source/WulaFallenEmpire/WulaDefOf.cs
+++ b/Source/WulaFallenEmpire/WulaDefOf.cs
@@ -30,6 +30,7 @@ namespace WulaFallenEmpire
public static JobDef WULA_RepairMech;
public static JobDef WULA_ForceEjectPilot;
public static JobDef WULA_CarryToMech;
+ public static JobDef WULA_TransformPawn;
static Wula_JobDefOf()
{
diff --git a/Source/WulaFallenEmpire/WulaFallenEmpire.csproj b/Source/WulaFallenEmpire/WulaFallenEmpire.csproj
index d8cd77ae..681553e3 100644
--- a/Source/WulaFallenEmpire/WulaFallenEmpire.csproj
+++ b/Source/WulaFallenEmpire/WulaFallenEmpire.csproj
@@ -85,6 +85,9 @@
+
+
+
@@ -97,6 +100,8 @@
+
+