diff --git a/1.6/1.6/Assemblies/WulaFallenEmpire.dll b/1.6/1.6/Assemblies/WulaFallenEmpire.dll
index 4f393ed2..9177c77e 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/HediffDefs/Hediffs_WULA.xml b/1.6/1.6/Defs/HediffDefs/Hediffs_WULA.xml
index 440e47f0..a3b472ab 100644
--- a/1.6/1.6/Defs/HediffDefs/Hediffs_WULA.xml
+++ b/1.6/1.6/Defs/HediffDefs/Hediffs_WULA.xml
@@ -24,6 +24,12 @@
0.05
+
+
+ Consciousness
+ 0.25
+
+
Flu
@@ -38,6 +44,7 @@
WULA_Energy
+ WULA_MaintenanceNeed
Food
@@ -45,6 +52,11 @@
+
+
+ 0.0025
+
+
WULA_ChargingHediff
@@ -68,73 +80,67 @@
+
- WULA_Maintenance_Neglect
+ WULA_Maintenance_MinorBreakdown
- 乌拉帝国的合成人因为设计的过于繁琐,导致需要频繁维护。当她们处于良好维护状态时,各方面的能力都会有所上升,反之如果常年得不到维护或是短时间受到大量伤害,则其将变得难以自主运行甚至直接停机!
+ 这台乌拉帝国合成人已经在环境恶劣的边缘世界活跃了一段时间,尽管总体状态良好但是已经有了一些小瑕疵。
Hediff_High
(0.8, 0.35, 0.35)
false
- 0
- 0
- 2.0
-
-
-
- 60
-
- 0.0166
-
- 0.03333
-
-
- 0.005
-
-
+ 0.1
+ 0.5
+ 1.0
-
+
0
Consciousness
- 0.1
-
-
-
-
-
- 0.5
-
-
- Consciousness
- 0
-
-
-
-
-
- 0.75
-
-
- Consciousness
- -0.20
+ -0.25
+
+
+
+ WULA_Maintenance_MajorBreakdown
+
+ 这台乌拉帝国合成人有一段时间没有进行维护了,运行起来相当吃力。
+ Hediff_High
+ (0.8, 0.35, 0.35)
+ false
+ 0.1
+ 0.5
+ 1.0
+
- 1.0
+ 0
Consciousness
- 0.5
+ -0.25
+
+
+
+ WULA_Maintenance_CriticalFailuren
+
+ 这台乌拉帝国合成人几乎无法运作了,需要立刻进行维护,否则就只是一堆废铁。
+ Hediff_High
+ (0.8, 0.35, 0.35)
+ false
+ 0.1
+ 0.5
+ 1.0
+
- 2.0
+ 0
Consciousness
@@ -321,9 +327,9 @@
0.5
1.5
0.1
- 0.01
- 1200
+ 0.02
+ 600
-
+
\ No newline at end of file
diff --git a/1.6/1.6/Defs/JobDefs/WULA_JobDefs.xml b/1.6/1.6/Defs/JobDefs/WULA_JobDefs.xml
index 57d31346..4c13fce4 100644
--- a/1.6/1.6/Defs/JobDefs/WULA_JobDefs.xml
+++ b/1.6/1.6/Defs/JobDefs/WULA_JobDefs.xml
@@ -29,5 +29,4 @@
true
false
-
\ No newline at end of file
diff --git a/1.6/1.6/Defs/NeedDefs/WULA_Needs.xml b/1.6/1.6/Defs/NeedDefs/WULA_Needs.xml
index 01a3f2ae..8f0e420e 100644
--- a/1.6/1.6/Defs/NeedDefs/WULA_Needs.xml
+++ b/1.6/1.6/Defs/NeedDefs/WULA_Needs.xml
@@ -23,4 +23,28 @@
+
+
+ WULA_MaintenanceNeed
+
+ WulaFallenEmpire.Need_Maintenance
+ 乌拉帝国的合成人因为设计的过于繁琐,导致需要频繁维护。当她们处于良好维护状态时,各方面的能力都会有所上升,反之如果常年得不到维护或是短时间受到大量伤害,则其将变得难以自主运行甚至直接停机!
+ true
+ true
+ 799
+ true
+ false
+ false
+
+
+ 0.05
+ 0.1
+ 5
+ PatientBedRest
+ WULA_Maintenance_MinorBreakdown
+ WULA_Maintenance_MajorBreakdown
+ WULA_Maintenance_CriticalFailuren
+
+
+
diff --git a/1.6/1.6/Defs/ThingDefs_Buildings/Buildings_Drop.xml b/1.6/1.6/Defs/ThingDefs_Buildings/Buildings_Drop.xml
index 2d60658b..07595880 100644
--- a/1.6/1.6/Defs/ThingDefs_Buildings/Buildings_Drop.xml
+++ b/1.6/1.6/Defs/ThingDefs_Buildings/Buildings_Drop.xml
@@ -147,9 +147,6 @@
BuildingDestroyed_Metal_Small
3.5
-
- BuildingsMisc
-
6
@@ -230,4 +227,84 @@
+
+
+
+ WULA_Cube_Productor_BIO
+
+ 一台仿制乌拉帝国科技而建造的塑性构造体,不仅要消耗大量木头用以提供生物能,还只能生产基础的衣物和能源核心用以维持生存——不过它很轻,可以随探险队一起移动。
+ WulaFallenEmpire.Building_GlobalWorkTable
+ MapMeshAndRealTime
+
+ Wula/Building/WULA_Cube_Productor_BIO
+ Graphic_Multi
+ (1,1)
+
+ false
+
+
+ (0.75, 0.75, 0.5)
+
+
+ ConstructMetal
+
+ 50
+
+ Building
+ false
+ 0.5
+ True
+
+ 5
+ 2000
+ 180
+ 1.0
+ 0.5
+
+ (1,1)
+ WULA_Buildings
+ 2120
+ PassThroughOnly
+ 50
+ True
+ (0,0,-1)
+ Item
+
+ WULA_Base_Technology
+
+
+
+ Make_WULA_Charge_Cube
+ Recharge_WULA_Charge_Cube
+ Wula_Make_Zro
+
+
+ WulaFallenEmpire.ITab_GlobalBills
+
+
+
+ 300.0
+ 150.0
+
+
+ WoodLog
+
+
+ true
+ true
+
+
+ CompHeatPusherPowered
+ 4
+
+
+
+ PlaceWorker_PreventInteractionSpotOverlap
+
+
+
+ BillsTab
+ 0.10
+
+
\ No newline at end of file
diff --git a/1.6/1.6/Defs/ThingDefs_Buildings/Buildings_WULA.xml b/1.6/1.6/Defs/ThingDefs_Buildings/Buildings_WULA.xml
index eb897d06..6f367791 100644
--- a/1.6/1.6/Defs/ThingDefs_Buildings/Buildings_WULA.xml
+++ b/1.6/1.6/Defs/ThingDefs_Buildings/Buildings_WULA.xml
@@ -807,18 +807,20 @@
true
- 30000
- 150000
- 500
- 25
- WULA_Maintenance_Neglect
- 2
- 1
-
- 0.01
BiosculpterPod_Enter
BiosculpterPod_Exit
BiosculpterPod_Operating
+ 30000
+ 150000
+ 500
+ 25
+ 2
+ 1
+ 0.3
+ 1.0
+ true
+ true
+ 5
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 ed0e4852..edc78c6f 100644
--- a/1.6/1.6/Defs/ThingDefs_Races/Races_Wulaspecies.xml
+++ b/1.6/1.6/Defs/ThingDefs_Races/Races_Wulaspecies.xml
@@ -664,7 +664,7 @@
Filth_MachineBits
- 1
+ 1.2
Steel
Steel
diff --git a/1.6/1.6/Defs/WorkGivers/Wula_WorkGivers.xml b/1.6/1.6/Defs/WorkGivers/Wula_WorkGivers.xml
index ccbd74d2..311a64b9 100644
--- a/1.6/1.6/Defs/WorkGivers/Wula_WorkGivers.xml
+++ b/1.6/1.6/Defs/WorkGivers/Wula_WorkGivers.xml
@@ -110,4 +110,16 @@
+
+
+ WULA_DoMaintenanceWork
+ PatientBedRest
+ WulaFallenEmpire.WorkGiver_DoMaintenance
+ 100
+ 接受维护于
+ 接受维护于
+ false
+ true
+ true
+
\ No newline at end of file
diff --git a/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/Misc_Gameplay.xml b/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/Misc_Gameplay.xml
index d3531b35..4061e0cb 100644
--- a/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/Misc_Gameplay.xml
+++ b/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/Misc_Gameplay.xml
@@ -92,4 +92,68 @@
该空投地点顶部有屋顶,无法进行空投
被厚岩顶阻挡
被屋顶阻挡
+
+
+ 维护舱状态
+ 空闲
+ 运行中
+
+
+ 进入维护舱
+ 选择需要维护的合成人
+ 取消当前维护周期
+ 没有合成人需要维护
+ 需要 {0} 个零部件
+
+
+ 维护水平
+ {0} 开始维护周期
+ {0} 维护完成
+ 修复了 {0} 的 {1} 处损伤
+ 修复了 {0} 的缺失部位
+ 维护已取消
+ 没有可用的搬运者
+ 无维护需求
+
+
+ 维护需求
+ 状态: {0} (上次维护: {1}天前)
+ 退化速率: {0}/天
+ {0} 的维护已完成
+
+
+ 运行正常
+ 轻微故障
+ 严重故障
+ 完全故障
+
+ 合成人运行在最佳状态
+ 合成人出现轻微故障,工作效率降低
+ 合成人出现严重故障,需要立即维护
+ 合成人完全故障,无法工作
+
+
+ 合成人维护
+ 执行维护
+
+
+ 伤害会影响维护度({0}/点伤害)
+ 损伤惩罚
+ 近期损伤事件
+ {0} 维护完成(修复了 {1} 损伤)
+ 修复了 {0} 的结构损伤
+ 距上次维护
+
+
+ 全球生产
+ 生产订单
+ 添加生产订单
+ Resume
+ Pause
+ Delete
+ 等待资源
+ Completed
+ Unknown
+ 全球存储中的资源不足
+ 无可用配方
\ No newline at end of file
diff --git a/Source/WulaFallenEmpire/GlobalWorkTable/Building_GlobalWorkTable.cs b/Source/WulaFallenEmpire/GlobalWorkTable/Building_GlobalWorkTable.cs
new file mode 100644
index 00000000..1d13f56e
--- /dev/null
+++ b/Source/WulaFallenEmpire/GlobalWorkTable/Building_GlobalWorkTable.cs
@@ -0,0 +1,61 @@
+// Building_GlobalWorkTable.cs (修复版)
+using RimWorld;
+using System.Collections.Generic;
+using Verse;
+
+namespace WulaFallenEmpire
+{
+ public class Building_GlobalWorkTable : Building_WorkTable
+ {
+ public GlobalProductionOrderStack globalOrderStack;
+
+ private CompPowerTrader powerComp;
+ private int lastProcessTick = -1;
+ private const int ProcessInterval = 60; // 每60tick处理一次
+
+ public Building_GlobalWorkTable()
+ {
+ globalOrderStack = new GlobalProductionOrderStack(this);
+ }
+
+ public override void ExposeData()
+ {
+ base.ExposeData();
+ Scribe_Deep.Look(ref globalOrderStack, "globalOrderStack", this);
+ }
+
+ public override void SpawnSetup(Map map, bool respawningAfterLoad)
+ {
+ base.SpawnSetup(map, respawningAfterLoad);
+ powerComp = GetComp();
+ }
+
+ public override void Tick()
+ {
+ base.Tick();
+
+ // 每60tick处理一次生产订单
+ if (Find.TickManager.TicksGame % ProcessInterval == 0 &&
+ Find.TickManager.TicksGame != lastProcessTick)
+ {
+ lastProcessTick = Find.TickManager.TicksGame;
+
+ if (powerComp == null || powerComp.PowerOn)
+ {
+ Log.Message($"[DEBUG] Processing orders at tick {Find.TickManager.TicksGame}");
+ globalOrderStack.ProcessOrders();
+ }
+ else
+ {
+ Log.Message("[DEBUG] No power, skipping order processing");
+ }
+ }
+ }
+
+ public bool CurrentlyUsableForGlobalBills()
+ {
+ return (powerComp == null || powerComp.PowerOn) &&
+ (GetComp() == null || !GetComp().BrokenDown);
+ }
+ }
+}
diff --git a/Source/WulaFallenEmpire/GlobalWorkTable/GlobalProductionOrder.cs b/Source/WulaFallenEmpire/GlobalWorkTable/GlobalProductionOrder.cs
new file mode 100644
index 00000000..f66fe8f1
--- /dev/null
+++ b/Source/WulaFallenEmpire/GlobalWorkTable/GlobalProductionOrder.cs
@@ -0,0 +1,120 @@
+// GlobalProductionOrder.cs (修复版)
+using RimWorld;
+using System.Collections.Generic;
+using Verse;
+
+namespace WulaFallenEmpire
+{
+ public class GlobalProductionOrder : IExposable
+ {
+ public RecipeDef recipe;
+ public int targetCount = 1;
+ public int currentCount = 0;
+ public bool paused = true; // 初始状态为暂停
+ public float progress = 0f;
+
+ // 生产状态
+ public ProductionState state = ProductionState.Waiting;
+
+ public enum ProductionState
+ {
+ Waiting, // 等待资源
+ Producing, // 生产中
+ Completed // 完成
+ }
+
+ public void ExposeData()
+ {
+ Scribe_Defs.Look(ref recipe, "recipe");
+ Scribe_Values.Look(ref targetCount, "targetCount", 1);
+ Scribe_Values.Look(ref currentCount, "currentCount", 0);
+ Scribe_Values.Look(ref paused, "paused", true);
+ Scribe_Values.Look(ref progress, "progress", 0f);
+ Scribe_Values.Look(ref state, "state", ProductionState.Waiting);
+ }
+
+ public string Label => recipe.LabelCap;
+ public string Description => $"{currentCount}/{targetCount} {recipe.products[0].thingDef.label}";
+
+ // 检查是否有足够资源 - 修复逻辑,只检查costList
+ public bool HasEnoughResources()
+ {
+ var globalStorage = Find.World.GetComponent();
+ if (globalStorage == null)
+ {
+ Log.Warning("GlobalStorageWorldComponent not found");
+ return false;
+ }
+
+ // 只检查costList,不检查ingredients
+ if (recipe.costList != null && recipe.costList.Count > 0)
+ {
+ foreach (var cost in recipe.costList)
+ {
+ int required = cost.count;
+ int available = globalStorage.GetInputStorageCount(cost.thingDef);
+
+ Log.Message($"[DEBUG] Checking {cost.thingDef.defName}: required={required}, available={available}");
+
+ if (available < required)
+ {
+ Log.Message($"[DEBUG] Insufficient {cost.thingDef.defName}");
+ return false;
+ }
+ }
+ Log.Message("[DEBUG] All resources available");
+ return true;
+ }
+ else
+ {
+ Log.Warning($"Recipe {recipe.defName} has no costList");
+ return false;
+ }
+ }
+
+ // 消耗资源 - 修复逻辑,只消耗costList
+ public bool ConsumeResources()
+ {
+ var globalStorage = Find.World.GetComponent();
+ if (globalStorage == null) return false;
+
+ // 只消耗costList中的资源
+ if (recipe.costList != null)
+ {
+ foreach (var cost in recipe.costList)
+ {
+ if (!globalStorage.RemoveFromInputStorage(cost.thingDef, cost.count))
+ {
+ Log.Warning($"Failed to consume {cost.count} {cost.thingDef.defName}");
+ return false;
+ }
+ Log.Message($"[DEBUG] Consumed {cost.count} {cost.thingDef.defName}");
+ }
+ return true;
+ }
+ return false;
+ }
+
+ // 生产一个产品
+ public void Produce()
+ {
+ var globalStorage = Find.World.GetComponent();
+ if (globalStorage == null) return;
+
+ foreach (var product in recipe.products)
+ {
+ globalStorage.AddToOutputStorage(product.thingDef, product.count);
+ Log.Message($"[DEBUG] Produced {product.count} {product.thingDef.defName}");
+ }
+
+ currentCount++;
+ progress = 0f;
+
+ if (currentCount >= targetCount)
+ {
+ state = ProductionState.Completed;
+ Log.Message("[DEBUG] Order completed");
+ }
+ }
+ }
+}
diff --git a/Source/WulaFallenEmpire/GlobalWorkTable/GlobalProductionOrderStack.cs b/Source/WulaFallenEmpire/GlobalWorkTable/GlobalProductionOrderStack.cs
new file mode 100644
index 00000000..c3b8ac49
--- /dev/null
+++ b/Source/WulaFallenEmpire/GlobalWorkTable/GlobalProductionOrderStack.cs
@@ -0,0 +1,98 @@
+// GlobalProductionOrderStack.cs (修复版)
+using RimWorld;
+using System.Collections.Generic;
+using Verse;
+
+namespace WulaFallenEmpire
+{
+ public class GlobalProductionOrderStack : IExposable
+ {
+ public Building_GlobalWorkTable table;
+ public List orders = new List();
+
+ public GlobalProductionOrderStack(Building_GlobalWorkTable table)
+ {
+ this.table = table;
+ }
+
+ public void ExposeData()
+ {
+ Scribe_References.Look(ref table, "table");
+ Scribe_Collections.Look(ref orders, "orders", LookMode.Deep);
+ }
+
+ public void AddOrder(GlobalProductionOrder order)
+ {
+ orders.Add(order);
+
+ // 添加到全局存储中统一管理
+ var globalStorage = Find.World.GetComponent();
+ if (globalStorage != null)
+ {
+ globalStorage.AddProductionOrder(order);
+ }
+ }
+
+ public void Delete(GlobalProductionOrder order)
+ {
+ orders.Remove(order);
+
+ var globalStorage = Find.World.GetComponent();
+ if (globalStorage != null)
+ {
+ globalStorage.RemoveProductionOrder(order);
+ }
+ }
+
+ public void ProcessOrders()
+ {
+ foreach (var order in orders)
+ {
+ if (order.paused || order.state == GlobalProductionOrder.ProductionState.Completed)
+ continue;
+
+ // 检查资源并更新状态
+ if (order.state == GlobalProductionOrder.ProductionState.Waiting)
+ {
+ if (order.HasEnoughResources())
+ {
+ order.state = GlobalProductionOrder.ProductionState.Producing;
+ Log.Message($"[DEBUG] Order {order.recipe.defName} started producing");
+ }
+ else
+ {
+ continue;
+ }
+ }
+
+ // 生产中
+ if (order.state == GlobalProductionOrder.ProductionState.Producing)
+ {
+ // 更清晰的进度计算
+ float progressPerTick = 1f / (order.recipe.workAmount * 5f); // 调整系数以控制生产速度
+ order.progress += progressPerTick;
+
+ if (order.progress >= 1f)
+ {
+ // 消耗资源并生产 - 在结束时扣除资源
+ if (order.ConsumeResources())
+ {
+ order.Produce();
+ }
+ else
+ {
+ // 资源被其他订单消耗,回到等待状态
+ order.state = GlobalProductionOrder.ProductionState.Waiting;
+ order.progress = 0f;
+ Log.Message("[DEBUG] Resources consumed by another order, returning to waiting state");
+ }
+ }
+ else
+ {
+ Log.Message($"[DEBUG] Order {order.recipe.defName} progress: {order.progress:P0}");
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/Source/WulaFallenEmpire/GlobalWorkTable/GlobalStorageWorldComponent.cs b/Source/WulaFallenEmpire/GlobalWorkTable/GlobalStorageWorldComponent.cs
new file mode 100644
index 00000000..64668bce
--- /dev/null
+++ b/Source/WulaFallenEmpire/GlobalWorkTable/GlobalStorageWorldComponent.cs
@@ -0,0 +1,148 @@
+using LudeonTK;
+using RimWorld;
+using RimWorld.Planet;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using UnityEngine;
+using Verse;
+
+namespace WulaFallenEmpire
+{
+ public class GlobalStorageWorldComponent : WorldComponent
+ {
+ public Dictionary inputStorage = new Dictionary();
+ public Dictionary outputStorage = new Dictionary();
+
+ // 存储生产订单
+ public List productionOrders = new List();
+
+ public GlobalStorageWorldComponent(World world) : base(world) { }
+
+ public override void ExposeData()
+ {
+ base.ExposeData();
+
+ // 序列化输入存储
+ Scribe_Collections.Look(ref inputStorage, "inputStorage", LookMode.Def, LookMode.Value);
+ if (inputStorage == null) inputStorage = new Dictionary();
+
+ // 序列化输出存储
+ Scribe_Collections.Look(ref outputStorage, "outputStorage", LookMode.Def, LookMode.Value);
+ if (outputStorage == null) outputStorage = new Dictionary();
+
+ // 序列化生产订单
+ Scribe_Collections.Look(ref productionOrders, "productionOrders", LookMode.Deep);
+ if (productionOrders == null) productionOrders = new List();
+ }
+
+ // 输入存储方法
+ public void AddToInputStorage(ThingDef thingDef, int count)
+ {
+ if (inputStorage.ContainsKey(thingDef))
+ inputStorage[thingDef] += count;
+ else
+ inputStorage[thingDef] = count;
+ }
+
+ public bool RemoveFromInputStorage(ThingDef thingDef, int count)
+ {
+ if (inputStorage.ContainsKey(thingDef) && inputStorage[thingDef] >= count)
+ {
+ inputStorage[thingDef] -= count;
+ if (inputStorage[thingDef] <= 0)
+ inputStorage.Remove(thingDef);
+ return true;
+ }
+ return false;
+ }
+
+ public int GetInputStorageCount(ThingDef thingDef)
+ {
+ return inputStorage.ContainsKey(thingDef) ? inputStorage[thingDef] : 0;
+ }
+
+ // 输出存储方法
+ public void AddToOutputStorage(ThingDef thingDef, int count)
+ {
+ if (outputStorage.ContainsKey(thingDef))
+ outputStorage[thingDef] += count;
+ else
+ outputStorage[thingDef] = count;
+ }
+
+ public bool RemoveFromOutputStorage(ThingDef thingDef, int count)
+ {
+ if (outputStorage.ContainsKey(thingDef) && outputStorage[thingDef] >= count)
+ {
+ outputStorage[thingDef] -= count;
+ if (outputStorage[thingDef] <= 0)
+ outputStorage.Remove(thingDef);
+ return true;
+ }
+ return false;
+ }
+
+ public int GetOutputStorageCount(ThingDef thingDef)
+ {
+ return outputStorage.ContainsKey(thingDef) ? outputStorage[thingDef] : 0;
+ }
+
+ // 生产订单管理
+ public void AddProductionOrder(GlobalProductionOrder order)
+ {
+ productionOrders.Add(order);
+ }
+
+ public void RemoveProductionOrder(GlobalProductionOrder order)
+ {
+ productionOrders.Remove(order);
+ }
+
+ // 添加调试方法
+ [DebugAction("WULA", "Add Test Resources", actionType = DebugActionType.Action)]
+ public static void DebugAddTestResources()
+ {
+ var globalStorage = Find.World.GetComponent();
+ if (globalStorage != null)
+ {
+ globalStorage.AddToInputStorage(ThingDefOf.Steel, 200);
+ globalStorage.AddToInputStorage(ThingDefOf.ComponentIndustrial, 100);
+ Log.Message("Added test resources to global storage");
+ }
+ }
+ [DebugAction("WULA", "Spawn All Products", actionType = DebugActionType.Action)]
+ public static void DebugSpawnAllProducts()
+ {
+ var globalStorage = Find.World.GetComponent();
+ if (globalStorage != null)
+ {
+ // 查找任意工作台来生成物品
+ var workTable = Find.CurrentMap?.listerBuildings?.allBuildingsColonist?
+ .FirstOrDefault(b => b is Building_GlobalWorkTable) as Building_GlobalWorkTable;
+
+ if (workTable != null && workTable.Spawned)
+ {
+ foreach (var kvp in globalStorage.outputStorage.ToList()) // 使用ToList避免修改时枚举
+ {
+ ThingDef thingDef = kvp.Key;
+ int count = kvp.Value;
+
+ while (count > 0)
+ {
+ int stackSize = Mathf.Min(count, thingDef.stackLimit);
+ Thing thing = ThingMaker.MakeThing(thingDef);
+ thing.stackCount = stackSize;
+
+ GenPlace.TryPlaceThing(thing, workTable.Position, workTable.Map, ThingPlaceMode.Near);
+
+ globalStorage.RemoveFromOutputStorage(thingDef, stackSize);
+ count -= stackSize;
+ }
+ }
+ Log.Message("Spawned all output products");
+ }
+ }
+ }
+ }
+}
diff --git a/Source/WulaFallenEmpire/GlobalWorkTable/ITab_GlobalBills.cs b/Source/WulaFallenEmpire/GlobalWorkTable/ITab_GlobalBills.cs
new file mode 100644
index 00000000..fc269678
--- /dev/null
+++ b/Source/WulaFallenEmpire/GlobalWorkTable/ITab_GlobalBills.cs
@@ -0,0 +1,285 @@
+// ITab_GlobalBills.cs (修复版)
+using System.Collections.Generic;
+using RimWorld;
+using UnityEngine;
+using Verse;
+using Verse.Sound;
+
+namespace WulaFallenEmpire
+{
+ public class ITab_GlobalBills : ITab
+ {
+ private float viewHeight = 1000f;
+ private Vector2 scrollPosition;
+ private GlobalProductionOrder mouseoverOrder;
+
+ private static readonly Vector2 WinSize = new Vector2(420f, 480f);
+
+ protected Building_GlobalWorkTable SelTable => (Building_GlobalWorkTable)base.SelThing;
+
+ public ITab_GlobalBills()
+ {
+ size = WinSize;
+ labelKey = "WULA_GlobalBillsTab";
+ tutorTag = "GlobalBills";
+ }
+
+ protected override void FillTab()
+ {
+ Rect mainRect = new Rect(0f, 0f, WinSize.x, WinSize.y).ContractedBy(10f);
+
+ // 标题
+ Text.Font = GameFont.Medium;
+ Widgets.Label(new Rect(mainRect.x, mainRect.y, mainRect.width, 30f), "WULA_GlobalProduction".Translate());
+ Text.Font = GameFont.Small;
+
+ // 开发模式按钮区域
+ if (Prefs.DevMode)
+ {
+ Rect devButtonRect = new Rect(mainRect.x, mainRect.y + 35f, mainRect.width, 25f);
+ DoDevButtons(devButtonRect);
+ }
+
+ // 订单列表区域 - 调整位置
+ float ordersRectY = Prefs.DevMode ? mainRect.y + 65f : mainRect.y + 35f;
+ Rect ordersRect = new Rect(mainRect.x, ordersRectY, mainRect.width, mainRect.height - (Prefs.DevMode ? 110f : 80f));
+ mouseoverOrder = DoOrdersListing(ordersRect);
+
+ // 添加订单按钮
+ Rect addButtonRect = new Rect(mainRect.x, mainRect.yMax - 35f, mainRect.width, 30f);
+ if (Widgets.ButtonText(addButtonRect, "WULA_AddProductionOrder".Translate()))
+ {
+ Find.WindowStack.Add(new FloatMenu(GenerateRecipeOptions()));
+ }
+ }
+
+ private void DoDevButtons(Rect rect)
+ {
+ Rect button1Rect = new Rect(rect.x, rect.y, rect.width / 2 - 5f, rect.height);
+ Rect button2Rect = new Rect(rect.x + rect.width / 2 + 5f, rect.y, rect.width / 2 - 5f, rect.height);
+
+ if (Widgets.ButtonText(button1Rect, "DEV: Add Resources"))
+ {
+ AddTestResources();
+ }
+
+ if (Widgets.ButtonText(button2Rect, "DEV: Spawn Products"))
+ {
+ SpawnOutputProducts();
+ }
+ }
+
+ private void AddTestResources()
+ {
+ var globalStorage = Find.World.GetComponent();
+ if (globalStorage != null)
+ {
+ // 添加200钢铁
+ ThingDef steelDef = ThingDefOf.Steel;
+ globalStorage.AddToInputStorage(steelDef, 200);
+
+ // 添加100零部件
+ ThingDef componentDef = ThingDefOf.ComponentIndustrial;
+ globalStorage.AddToInputStorage(componentDef, 100);
+
+ Messages.Message("Added 200 Steel and 100 Components to global storage", MessageTypeDefOf.PositiveEvent);
+ Log.Message("[DEBUG] Added test resources");
+ }
+ }
+
+ private void SpawnOutputProducts()
+ {
+ var globalStorage = Find.World.GetComponent();
+ if (globalStorage != null && SelTable != null && SelTable.Spawned)
+ {
+ Map map = SelTable.Map;
+ IntVec3 spawnCell = SelTable.Position;
+ int totalSpawned = 0;
+
+ // 复制列表以避免修改时枚举
+ var outputCopy = new Dictionary(globalStorage.outputStorage);
+
+ foreach (var kvp in outputCopy)
+ {
+ ThingDef thingDef = kvp.Key;
+ int count = kvp.Value;
+
+ if (count > 0)
+ {
+ // 创建物品并放置到地图上
+ while (count > 0)
+ {
+ int stackSize = Mathf.Min(count, thingDef.stackLimit);
+ Thing thing = ThingMaker.MakeThing(thingDef);
+ thing.stackCount = stackSize;
+
+ if (GenPlace.TryPlaceThing(thing, spawnCell, map, ThingPlaceMode.Near))
+ {
+ globalStorage.RemoveFromOutputStorage(thingDef, stackSize);
+ count -= stackSize;
+ totalSpawned += stackSize;
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+ }
+
+ Messages.Message($"Spawned {totalSpawned} items at worktable location", MessageTypeDefOf.PositiveEvent);
+ Log.Message($"[DEBUG] Spawned {totalSpawned} output products");
+ }
+ }
+
+ private GlobalProductionOrder DoOrdersListing(Rect rect)
+ {
+ GlobalProductionOrder result = null;
+
+ Widgets.DrawMenuSection(rect);
+ Rect outRect = rect.ContractedBy(5f);
+ Rect viewRect = new Rect(0f, 0f, outRect.width - 16f, viewHeight);
+
+ Widgets.BeginScrollView(outRect, ref scrollPosition, viewRect);
+
+ float curY = 0f;
+ for (int i = 0; i < SelTable.globalOrderStack.orders.Count; i++)
+ {
+ var order = SelTable.globalOrderStack.orders[i];
+
+ // 增加订单行高度
+ Rect orderRect = new Rect(0f, curY, viewRect.width, 90f);
+
+ if (DoOrderRow(orderRect, order))
+ {
+ result = order;
+ }
+
+ curY += 95f; // 增加行间距
+
+ // 分隔线
+ if (i < SelTable.globalOrderStack.orders.Count - 1)
+ {
+ Widgets.DrawLineHorizontal(0f, curY - 2f, viewRect.width);
+ curY += 5f;
+ }
+ }
+
+ if (Event.current.type == EventType.Layout)
+ {
+ viewHeight = curY;
+ }
+
+ Widgets.EndScrollView();
+ return result;
+ }
+
+ private bool DoOrderRow(Rect rect, GlobalProductionOrder order)
+ {
+ Widgets.DrawHighlightIfMouseover(rect);
+
+ // 增加内边距和行高
+ float padding = 8f;
+ float lineHeight = 20f;
+
+ // 订单信息
+ Rect infoRect = new Rect(rect.x + padding, rect.y + padding, rect.width - 100f, lineHeight);
+ Widgets.Label(infoRect, order.Label);
+
+ Rect descRect = new Rect(rect.x + padding, rect.y + padding + lineHeight + 2f, rect.width - 100f, lineHeight);
+ Widgets.Label(descRect, order.Description);
+
+ // 状态显示区域
+ Rect statusRect = new Rect(rect.x + padding, rect.y + padding + (lineHeight + 2f) * 2, rect.width - 100f, lineHeight);
+
+ if (order.state == GlobalProductionOrder.ProductionState.Producing)
+ {
+ // 进度条
+ Rect progressRect = new Rect(rect.x + padding, rect.y + padding + (lineHeight + 2f) * 2, rect.width - 100f, 18f);
+ Widgets.FillableBar(progressRect, order.progress);
+
+ // 进度文本
+ Text.Anchor = TextAnchor.MiddleCenter;
+ Widgets.Label(progressRect, $"{order.progress:P0}");
+ Text.Anchor = TextAnchor.UpperLeft;
+ }
+ else
+ {
+ string statusText = order.state switch
+ {
+ GlobalProductionOrder.ProductionState.Waiting => "WULA_WaitingForResources".Translate(),
+ GlobalProductionOrder.ProductionState.Completed => "WULA_Completed".Translate(),
+ _ => "WULA_Unknown".Translate()
+ };
+ Widgets.Label(statusRect, statusText);
+ }
+
+ // 控制按钮
+ float buttonY = rect.y + padding;
+ Rect pauseButtonRect = new Rect(rect.xMax - 90f, buttonY, 40f, 25f);
+ if (Widgets.ButtonText(pauseButtonRect, order.paused ? "WULA_Resume".Translate() : "WULA_Pause".Translate()))
+ {
+ order.paused = !order.paused;
+ SoundDefOf.Click.PlayOneShotOnCamera();
+ }
+
+ Rect deleteButtonRect = new Rect(rect.xMax - 45f, buttonY, 40f, 25f);
+ if (Widgets.ButtonText(deleteButtonRect, "WULA_Delete".Translate()))
+ {
+ SelTable.globalOrderStack.Delete(order);
+ SoundDefOf.Click.PlayOneShotOnCamera();
+ }
+
+ // 资源检查提示 - 修复逻辑
+ bool shouldShowRedBorder = (order.state == GlobalProductionOrder.ProductionState.Waiting && !order.HasEnoughResources());
+ if (shouldShowRedBorder)
+ {
+ TooltipHandler.TipRegion(rect, "WULA_InsufficientResources".Translate());
+ GUI.color = Color.red;
+ Widgets.DrawBox(rect, 2);
+ GUI.color = Color.white;
+ }
+
+ return Mouse.IsOver(rect);
+ }
+
+ private List GenerateRecipeOptions()
+ {
+ var options = new List();
+
+ foreach (var recipe in SelTable.def.AllRecipes)
+ {
+ if (recipe.AvailableNow && recipe.AvailableOnNow(SelTable))
+ {
+ string label = recipe.LabelCap;
+
+ options.Add(new FloatMenuOption(label, () =>
+ {
+ var newOrder = new GlobalProductionOrder
+ {
+ recipe = recipe,
+ targetCount = 1,
+ paused = true // 初始暂停
+ };
+
+ SelTable.globalOrderStack.AddOrder(newOrder);
+ SoundDefOf.Click.PlayOneShotOnCamera();
+ Log.Message($"[DEBUG] Added order for {recipe.defName}");
+ }));
+ }
+ }
+
+ if (options.Count == 0)
+ {
+ options.Add(new FloatMenuOption("WULA_NoAvailableRecipes".Translate(), null));
+ }
+
+ return options;
+ }
+
+ public override void TabUpdate()
+ {
+ base.TabUpdate();
+ }
+ }
+}
diff --git a/Source/WulaFallenEmpire/HediffComp/HediffCompProperties_NanoRepair.cs b/Source/WulaFallenEmpire/HediffComp/HediffCompProperties_NanoRepair.cs
index b16fc4b6..eb4374d2 100644
--- a/Source/WulaFallenEmpire/HediffComp/HediffCompProperties_NanoRepair.cs
+++ b/Source/WulaFallenEmpire/HediffComp/HediffCompProperties_NanoRepair.cs
@@ -1,3 +1,4 @@
+// HediffCompProperties_NanoRepair.cs
using RimWorld;
using Verse;
using System.Collections.Generic;
@@ -12,7 +13,6 @@ namespace WulaFallenEmpire
public float minEnergyThreshold = 0.1f; // 最低能量阈值
public float repairCostPerHP = 0.1f; // 每点生命值修复的能量消耗
public int repairCooldownAfterDamage = 300; // 受到伤害后的修复冷却时间
- public float repairTolerance = 0f; // 修复容忍度,低于此值认为已完全修复
public HediffCompProperties_NanoRepair()
{
@@ -200,7 +200,7 @@ namespace WulaFallenEmpire
return true;
}
- // 使用 GetPartHealth 检查是否有损伤
+ // 检查是否有损伤
if (HasDamagedParts())
{
if (debugCounter % 10 == 0)
@@ -208,14 +208,7 @@ namespace WulaFallenEmpire
return true;
}
- // 检查是否有需要治疗的疾病
- if (Pawn.health.hediffSet.HasTendableNonInjuryNonMissingPartHediff())
- {
- if (debugCounter % 10 == 0)
- Log.Message($"[NanoRepair] 检测到可治疗疾病");
- return true;
- }
-
+ // 不再检查疾病
if (debugCounter % 10 == 0)
Log.Message($"[NanoRepair] 没有检测到任何需要修复的损伤");
return false;
@@ -235,12 +228,12 @@ namespace WulaFallenEmpire
float maxHealth = part.def.GetMaxHealth(Pawn);
float currentHealth = Pawn.health.hediffSet.GetPartHealth(part);
- // 使用修复容忍度,只有当损伤大于容忍度时才认为需要修复
- if (currentHealth < maxHealth - Props.repairTolerance)
+ // 不再使用修复容忍度,任何损伤都需要修复
+ if (currentHealth < maxHealth)
{
damagedCount++;
if (debugCounter % 10 == 0 && damagedCount == 1)
- Log.Message($"[NanoRepair] 部位 {part.def.defName} 有损伤: {currentHealth}/{maxHealth} (容忍度: {Props.repairTolerance})");
+ Log.Message($"[NanoRepair] 部位 {part.def.defName} 有损伤: {currentHealth}/{maxHealth}");
}
}
}
@@ -264,8 +257,8 @@ namespace WulaFallenEmpire
float maxHealth = part.def.GetMaxHealth(Pawn);
float currentHealth = Pawn.health.hediffSet.GetPartHealth(part);
- // 使用修复容忍度
- if (currentHealth < maxHealth - Props.repairTolerance)
+ // 不再使用修复容忍度,任何损伤都需要修复
+ if (currentHealth < maxHealth)
{
damagedParts.Add(part);
if (debugCounter % 10 == 0 && damagedParts.Count <= 3)
@@ -309,13 +302,7 @@ namespace WulaFallenEmpire
return;
}
- // 最后修复疾病
- if (TryRepairDiseases(energyNeed))
- {
- if (debugCounter % 10 == 0)
- Log.Message($"[NanoRepair] 已修复疾病");
- return;
- }
+ // 不再修复疾病
if (debugCounter % 10 == 0)
Log.Message($"[NanoRepair] 没有执行任何修复");
@@ -450,110 +437,18 @@ namespace WulaFallenEmpire
return false;
}
- private bool TryRepairDiseases(Need energyNeed)
- {
- var diseases = Pawn.health.hediffSet.GetTendableNonInjuryNonMissingPartHediffs();
- if (diseases == null)
- {
- if (debugCounter % 10 == 0)
- Log.Message($"[NanoRepair] 没有可治疗疾病");
- return false;
- }
-
- int diseaseCount = 0;
- foreach (var disease in diseases)
- {
- if (disease.TendableNow())
- diseaseCount++;
- }
-
- if (diseaseCount == 0)
- {
- if (debugCounter % 10 == 0)
- Log.Message($"[NanoRepair] 没有可治疗的疾病");
- return false;
- }
-
- if (debugCounter % 10 == 0)
- Log.Message($"[NanoRepair] 检查修复疾病,共有 {diseaseCount} 个");
-
- foreach (var disease in diseases)
- {
- if (disease.TendableNow())
- {
- float repairCost = CalculateRepairCost(disease);
-
- if (debugCounter % 10 == 0)
- Log.Message($"[NanoRepair] 尝试修复疾病 {disease.def.defName}, 严重性: {disease.Severity:F2}, 成本: {repairCost:F2}, 当前能量: {energyNeed.CurLevel:F2}");
-
- if (energyNeed.CurLevel >= repairCost)
- {
- if (RepairDisease(disease, repairCost))
- {
- energyNeed.CurLevel -= repairCost;
- if (debugCounter % 10 == 0)
- Log.Message($"[NanoRepair] 成功修复疾病 {disease.def.defName}, 消耗能量: {repairCost:F2}");
- return true;
- }
- }
- else
- {
- if (debugCounter % 10 == 0)
- Log.Message($"[NanoRepair] 能量不足修复疾病: {energyNeed.CurLevel:F2} < {repairCost:F2}");
- }
- }
- }
- return false;
- }
-
- private float CalculateRepairCost(Hediff hediff)
- {
- float baseCost = Props.repairCostPerHP;
-
- // 根据机械族的能量消耗属性调整成本
- var mechEnergyLoss = Pawn.GetStatValue(StatDefOf.MechEnergyLossPerHP);
- if (mechEnergyLoss > 0)
- {
- baseCost *= mechEnergyLoss;
- }
-
- float severityMultiplier = 1.0f;
-
- if (hediff is Hediff_Injury injury)
- {
- severityMultiplier = injury.Severity;
- }
- else if (hediff is Hediff_MissingPart)
- {
- // 缺失部件修复成本使用正常计算
- severityMultiplier = 1.0f;
- }
- else
- {
- severityMultiplier = hediff.Severity * 1.5f;
- }
-
- float finalCost = baseCost * severityMultiplier;
-
- if (debugCounter % 10 == 0)
- Log.Message($"[NanoRepair] 计算修复成本: 基础={Props.repairCostPerHP}, 机械族能耗系数={mechEnergyLoss}, 严重性系数={severityMultiplier}, 最终成本={finalCost:F2}");
-
- return finalCost;
- }
-
+ // 新的修复逻辑:完美修复所有伤口
private bool RepairDamagedPart(BodyPartRecord part, float repairCost)
{
try
{
float maxHealth = part.def.GetMaxHealth(Pawn);
float currentHealth = Pawn.health.hediffSet.GetPartHealth(part);
- float healthToRepair = Mathf.Min(maxHealth - currentHealth, repairCost / Props.repairCostPerHP);
if (debugCounter % 10 == 0)
- Log.Message($"[NanoRepair] 开始修复部位 {part.def.defName}, 计划修复量: {healthToRepair:F1}");
+ Log.Message($"[NanoRepair] 开始修复部位 {part.def.defName}, 当前健康: {currentHealth:F1}/{maxHealth:F1}");
- // 直接修复部位的健康值,而不是查找特定的hediff
- // 找到该部位的所有hediff并尝试修复
+ // 获取该部位的所有hediff
var hediffsOnPart = new List();
foreach (var hediff in Pawn.health.hediffSet.hediffs)
{
@@ -575,17 +470,10 @@ namespace WulaFallenEmpire
if (debugCounter % 10 == 0)
Log.Message($"[NanoRepair] 在部位 {part.def.defName} 上找到 {hediffsOnPart.Count} 个hediff");
- // 按严重性排序,先修复最严重的hediff
- hediffsOnPart.Sort((a, b) => b.Severity.CompareTo(a.Severity));
-
- float remainingRepair = healthToRepair;
bool anyRepairDone = false;
foreach (var hediff in hediffsOnPart)
{
- if (remainingRepair <= 0)
- break;
-
// 检查hediff是否可修复
if (!CanRepairHediff(hediff))
{
@@ -593,26 +481,29 @@ namespace WulaFallenEmpire
Log.Message($"[NanoRepair] 跳过不可修复的hediff: {hediff.def.defName}");
continue;
}
-
- float healAmount = Mathf.Min(hediff.Severity, remainingRepair);
- hediff.Severity -= healAmount;
- remainingRepair -= healAmount;
- anyRepairDone = true;
- if (debugCounter % 10 == 0)
- Log.Message($"[NanoRepair] 修复hediff {hediff.def.defName}, 修复量: {healAmount:F1}, 剩余严重性: {hediff.Severity:F1}");
-
- // 使用修复容忍度,只有当严重性大于容忍度时才移除hediff
- if (hediff.Severity <= Props.repairTolerance)
+ // 新的修复逻辑:对于小于1的伤口,直接删除
+ if (hediff.Severity < 1.0f)
{
Pawn.health.RemoveHediff(hediff);
+ anyRepairDone = true;
if (debugCounter % 10 == 0)
- Log.Message($"[NanoRepair] hediff {hediff.def.defName} 已完全修复并移除");
+ Log.Message($"[NanoRepair] 删除严重性小于1的hediff: {hediff.def.defName} (严重性: {hediff.Severity:F2})");
+ }
+ else
+ {
+ // 对于大于等于1的伤口,完全修复
+ float originalSeverity = hediff.Severity;
+ hediff.Severity = 0f;
+ Pawn.health.RemoveHediff(hediff);
+ anyRepairDone = true;
+ if (debugCounter % 10 == 0)
+ Log.Message($"[NanoRepair] 完全修复hediff: {hediff.def.defName} (严重性: {originalSeverity:F2} -> 0)");
}
}
if (debugCounter % 10 == 0)
- Log.Message($"[NanoRepair] 部位 {part.def.defName} 修复完成,总修复量: {healthToRepair - remainingRepair:F1}");
+ Log.Message($"[NanoRepair] 部位 {part.def.defName} 修复完成,执行了 {anyRepairDone} 次修复");
return anyRepairDone;
}
@@ -626,12 +517,16 @@ namespace WulaFallenEmpire
// 检查hediff是否可修复
private bool CanRepairHediff(Hediff hediff)
{
- // 如果是机械族特有的hediff,总是可以修复
- if (IsMechSpecificHediff(hediff))
- return true;
+ // 跳过疾病
+ if (IsDisease(hediff))
+ {
+ if (debugCounter % 10 == 0)
+ Log.Message($"[NanoRepair] 跳过疾病: {hediff.def.defName}");
+ return false;
+ }
- // 如果是可治疗的hediff,可以修复
- if (hediff.TendableNow())
+ // 如果是机械族特有的hediff,可以修复
+ if (IsMechSpecificHediff(hediff))
return true;
// 如果是损伤类型的hediff,可以修复
@@ -642,6 +537,26 @@ namespace WulaFallenEmpire
return false;
}
+ // 检查是否是疾病
+ private bool IsDisease(Hediff hediff)
+ {
+ // 这里可以定义哪些hediff被认为是疾病
+ // 常见的疾病类型
+ string[] diseaseKeywords = {
+ "Disease", "Flu", "Plague", "Infection", "Malaria",
+ "SleepingSickness", "FibrousMechanites", "SensoryMechanites",
+ "WoundInfection", "FoodPoisoning", "GutWorms", "MuscleParasites"
+ };
+
+ foreach (string keyword in diseaseKeywords)
+ {
+ if (hediff.def.defName.Contains(keyword))
+ return true;
+ }
+
+ return false;
+ }
+
// 将缺失部件转换为指定的hediff
private bool ConvertMissingPartToInjury(Hediff_MissingPart missingPart, float repairCost)
{
@@ -701,33 +616,6 @@ namespace WulaFallenEmpire
hediff.def.defName.Contains("Gunshot"); // 包括枪伤
}
- private bool RepairDisease(Hediff disease, float repairCost)
- {
- try
- {
- // 修复疾病
- float healAmount = Mathf.Min(disease.Severity, repairCost / (Props.repairCostPerHP * 1.5f));
- disease.Severity -= healAmount;
-
- if (debugCounter % 10 == 0)
- Log.Message($"[NanoRepair] 修复疾病 {disease.def.defName}, 修复量: {healAmount:F2}, 剩余严重性: {disease.Severity:F2}");
-
- // 使用修复容忍度
- if (disease.Severity <= Props.repairTolerance)
- {
- Pawn.health.RemoveHediff(disease);
- if (debugCounter % 10 == 0)
- Log.Message($"[NanoRepair] 疾病 {disease.def.defName} 已完全修复并移除");
- }
- return true;
- }
- catch (System.Exception ex)
- {
- Log.Error($"[NanoRepair] 修复疾病 {disease.def.defName} 时出错: {ex}");
- return false;
- }
- }
-
public override void Notify_PawnPostApplyDamage(DamageInfo dinfo, float totalDamageDealt)
{
base.Notify_PawnPostApplyDamage(dinfo, totalDamageDealt);
diff --git a/Source/WulaFallenEmpire/Pawn/WULA_Maintenance/Building_MaintenancePod.cs b/Source/WulaFallenEmpire/Pawn/WULA_Maintenance/Building_MaintenancePod.cs
index ec8209eb..1437c790 100644
--- a/Source/WulaFallenEmpire/Pawn/WULA_Maintenance/Building_MaintenancePod.cs
+++ b/Source/WulaFallenEmpire/Pawn/WULA_Maintenance/Building_MaintenancePod.cs
@@ -1,35 +1,32 @@
+// Building_MaintenancePod.cs
using RimWorld;
using Verse;
namespace WulaFallenEmpire
{
- public class CompProperties_MaintenanceCycle : CompProperties_BiosculpterPod_BaseCycle
+ public class Building_MaintenancePod : Building
{
- public HediffDef hediffToRemove;
+ public CompMaintenancePod MaintenanceComp => GetComp();
- public CompProperties_MaintenanceCycle()
+ protected override void Tick()
{
- compClass = typeof(CompMaintenanceCycle);
+ base.Tick();
+ // 建筑级别的特殊逻辑可以在这里添加
}
- }
- public class CompMaintenanceCycle : CompBiosculpterPod_Cycle
- {
- public new CompProperties_MaintenanceCycle Props => (CompProperties_MaintenanceCycle)props;
-
- public override void CycleCompleted(Pawn pawn)
+ public override string GetInspectString()
{
- if (pawn == null)
+ string baseString = base.GetInspectString();
+ string maintenanceString = MaintenanceComp?.CompInspectStringExtra();
+
+ if (!string.IsNullOrEmpty(maintenanceString))
{
- return;
+ if (!string.IsNullOrEmpty(baseString))
+ return baseString + "\n" + maintenanceString;
+ return maintenanceString;
}
- Hediff hediff = pawn.health.hediffSet.GetFirstHediffOfDef(Props.hediffToRemove);
- if (hediff != null)
- {
- hediff.Severity = 0f;
- Messages.Message("WULA_MaintenanceCycleComplete".Translate(pawn.Named("PAWN")), pawn, MessageTypeDefOf.PositiveEvent);
- }
+ return baseString;
}
}
-}
\ No newline at end of file
+}
diff --git a/Source/WulaFallenEmpire/Pawn/WULA_Maintenance/CompMaintenancePod.cs b/Source/WulaFallenEmpire/Pawn/WULA_Maintenance/CompMaintenancePod.cs
index dee1f776..ccb1671c 100644
--- a/Source/WulaFallenEmpire/Pawn/WULA_Maintenance/CompMaintenancePod.cs
+++ b/Source/WulaFallenEmpire/Pawn/WULA_Maintenance/CompMaintenancePod.cs
@@ -15,16 +15,25 @@ namespace WulaFallenEmpire
public SoundDef enterSound;
public SoundDef exitSound;
public EffecterDef operatingEffecter;
- public int baseDurationTicks = 60000;
- public float ticksPerSeverity = 0f;
+
+ // ʱ
+ public int baseDurationTicks = 60000; // άʱ䣨1죩
+ public float ticksPerNeedLevel = 120000f; // ÿҪʱ
+
+ //
public float powerConsumptionRunning = 250f;
public float powerConsumptionIdle = 50f;
- public HediffDef hediffToRemove;
- public float componentCostPerSeverity = 1f;
- public int baseComponentCost = 0;
- public float minSeverityToMaintain = 0.75f;
- public float hediffSeverityAfterCycle = 0.01f;
+ //
+ public float componentCostPerNeedLevel = 2f;
+ public int baseComponentCost = 1;
+
+ // άЧ
+ public float minNeedLevelToMaintain = 0.3f; // ڴֵҪά
+ public float needLevelAfterCycle = 1.0f; // άˮƽ
+ public bool healInjuries = true; // Ƿ
+ public bool healMissingParts = true; // Ƿȱʧλ
+ public int maxInjuriesHealedPerCycle = 5; // ÿάƵ
public CompProperties_MaintenancePod()
{
compClass = typeof(CompMaintenancePod);
@@ -40,45 +49,55 @@ namespace WulaFallenEmpire
private CompRefuelable refuelableComp;
private int ticksRemaining;
private MaintenancePodState state = MaintenancePodState.Idle;
-
+ private Effecter operatingEffecter;
private static readonly Texture2D CancelIcon = ContentFinder.Get("UI/Designators/Cancel");
private static readonly Texture2D EnterIcon = ContentFinder.Get("UI/Commands/PodEject");
-
// ===================== Properties =====================
public CompProperties_MaintenancePod Props => (CompProperties_MaintenancePod)props;
public MaintenancePodState State => state;
public Pawn Occupant => innerContainer.FirstOrDefault() as Pawn;
public bool PowerOn => powerComp != null && powerComp.PowerOn;
-
- public float RequiredComponents(Pawn pawn)
+ public float RequiredComponents
{
- if (pawn == null || Props.hediffToRemove == null) return Props.baseComponentCost;
- Hediff hediff = pawn.health.hediffSet.GetFirstHediffOfDef(Props.hediffToRemove);
- if (hediff == null) return Props.baseComponentCost;
- return Props.baseComponentCost + (int)(hediff.Severity * Props.componentCostPerSeverity);
- }
+ get
+ {
+ var occupant = Occupant;
+ if (occupant == null) return Props.baseComponentCost;
- public int RequiredDuration(Pawn pawn)
+ var maintenanceNeed = occupant.needs?.TryGetNeed();
+ if (maintenanceNeed == null) return Props.baseComponentCost;
+
+ // ڵǰˮƽ
+ float needDeficit = 1.0f - maintenanceNeed.CurLevel;
+ return Props.baseComponentCost + (needDeficit * Props.componentCostPerNeedLevel);
+ }
+ }
+ public int RequiredDuration
{
- if (pawn == null || Props.hediffToRemove == null) return Props.baseDurationTicks;
- Hediff hediff = pawn.health.hediffSet.GetFirstHediffOfDef(Props.hediffToRemove);
- if (hediff == null) return Props.baseDurationTicks;
- return Props.baseDurationTicks + (int)(hediff.Severity * Props.ticksPerSeverity);
- }
+ get
+ {
+ var occupant = Occupant;
+ if (occupant == null) return Props.baseDurationTicks;
+ var maintenanceNeed = occupant.needs?.TryGetNeed();
+ if (maintenanceNeed == null) return Props.baseDurationTicks;
+
+ // ڵǰˮƽάʱ
+ float needDeficit = 1.0f - maintenanceNeed.CurLevel;
+ return Props.baseDurationTicks + (int)(needDeficit * Props.ticksPerNeedLevel);
+ }
+ }
// ===================== Setup =====================
public CompMaintenancePod()
{
innerContainer = new ThingOwner(this, false, LookMode.Deep);
}
-
public override void PostSpawnSetup(bool respawningAfterLoad)
{
base.PostSpawnSetup(respawningAfterLoad);
powerComp = parent.TryGetComp();
refuelableComp = parent.TryGetComp();
}
-
public override void PostExposeData()
{
base.PostExposeData();
@@ -86,361 +105,335 @@ namespace WulaFallenEmpire
Scribe_Values.Look(ref ticksRemaining, "ticksRemaining", 0);
Scribe_Deep.Look(ref innerContainer, "innerContainer", this);
}
-
public override void PostDestroy(DestroyMode mode, Map previousMap)
{
base.PostDestroy(mode, previousMap);
- // If the pod is deconstructed or destroyed, eject the occupant to prevent deletion.
if (mode == DestroyMode.Deconstruct || mode == DestroyMode.KillFinalize)
{
- Log.Warning($"[WulaPodDebug] Pod destroyed (mode: {mode}). Ejecting pawn.");
EjectPawn();
}
}
-
// ===================== IThingHolder Implementation =====================
public void GetChildHolders(List outChildren)
{
ThingOwnerUtility.AppendThingHoldersFromThings(outChildren, GetDirectlyHeldThings());
}
-
public ThingOwner GetDirectlyHeldThings()
{
return innerContainer;
}
-
// ===================== Core Logic =====================
public override void CompTick()
{
base.CompTick();
if (!parent.Spawned) return;
-
- if (state == MaintenancePodState.Running)
- {
- if (PowerOn)
- {
- ticksRemaining--;
- if (ticksRemaining <= 0)
- {
- CycleFinished();
- }
- }
- }
-
+ // µ
if (powerComp != null)
{
powerComp.PowerOutput = -(state == MaintenancePodState.Running ? Props.powerConsumptionRunning : Props.powerConsumptionIdle);
}
- }
+ // ά
+ if (state == MaintenancePodState.Running && PowerOn)
+ {
+ ticksRemaining--;
+ // Ч
+ if (Props.operatingEffecter != null)
+ {
+ if (operatingEffecter == null)
+ {
+ operatingEffecter = Props.operatingEffecter.Spawn();
+ }
+ operatingEffecter.EffectTick(parent, Occupant);
+ }
+ if (ticksRemaining <= 0)
+ {
+ CycleFinished();
+ }
+ }
+ else if (operatingEffecter != null)
+ {
+ operatingEffecter.Cleanup();
+ operatingEffecter = null;
+ }
+ }
public void StartCycle(Pawn pawn)
{
- Log.Warning($"[WulaPodDebug] StartCycle called for pawn: {pawn.LabelShortCap}");
- float required = RequiredComponents(pawn);
- if (refuelableComp.Fuel < required)
+ if (pawn == null) return;
+ // Ƿ㹻
+ float requiredComponents = RequiredComponents;
+ if (refuelableComp.Fuel < requiredComponents)
{
- Log.Error($"[WulaPodDebug] ERROR: Tried to start cycle for {pawn.LabelShort} without enough components.");
+ Messages.Message("WULA_MaintenancePod_NotEnoughComponents".Translate(requiredComponents.ToString("F0")), MessageTypeDefOf.RejectInput);
return;
}
-
- if (required > 0)
+ //
+ if (requiredComponents > 0)
{
- refuelableComp.ConsumeFuel(required);
+ refuelableComp.ConsumeFuel(requiredComponents);
}
-
- Log.Warning($"[WulaPodDebug] Pawn state before action: holdingOwner is {(pawn.holdingOwner == null ? "NULL" : "NOT NULL")}, Spawned is {pawn.Spawned}");
-
- // THE ACTUAL FIX: A pawn, whether held or not, must be despawned before being put in a container.
+ // pawn
if (pawn.Spawned)
{
- Log.Warning($"[WulaPodDebug] Pawn is spawned. Despawning...");
pawn.DeSpawn(DestroyMode.Vanish);
}
- Log.Warning($"[WulaPodDebug] Attempting to add/transfer pawn to container.");
innerContainer.TryAddOrTransfer(pawn);
-
-
+ // ʼά
state = MaintenancePodState.Running;
- ticksRemaining = RequiredDuration(pawn);
- Log.Warning($"[WulaPodDebug] Cycle started. Ticks remaining: {ticksRemaining}");
- }
+ ticksRemaining = RequiredDuration;
+ // ŽЧ
+ if (Props.enterSound != null)
+ {
+ Props.enterSound.PlayOneShot(new TargetInfo(parent.Position, parent.Map));
+ }
+ Messages.Message("WULA_MaintenanceCycleStarted".Translate(pawn.LabelShortCap), MessageTypeDefOf.PositiveEvent);
+ }
private void CycleFinished()
{
- Pawn occupant = Occupant;
- Log.Warning($"[WulaPodDebug] CycleFinished. Occupant: {(occupant == null ? "NULL" : occupant.LabelShortCap)}");
+ var occupant = Occupant;
if (occupant == null)
{
- Log.Error("[WulaPodDebug] ERROR: Maintenance cycle finished, but no one was inside.");
state = MaintenancePodState.Idle;
return;
}
+ // ִάЧ
+ PerformMaintenanceEffects(occupant);
- // 1. Fix the maintenance hediff
- bool maintenanceDone = false;
- if (Props.hediffToRemove != null)
+ // pawn
+ EjectPawn();
+
+ Messages.Message("WULA_MaintenanceCycleComplete".Translate(occupant.LabelShortCap), MessageTypeDefOf.PositiveEvent);
+ }
+ private void PerformMaintenanceEffects(Pawn pawn)
+ {
+ var maintenanceNeed = pawn.needs?.TryGetNeed();
+
+ // 1. ָά
+ if (maintenanceNeed != null)
{
- Hediff hediff = occupant.health.hediffSet.GetFirstHediffOfDef(Props.hediffToRemove);
- if (hediff != null)
- {
- hediff.Severity = Props.hediffSeverityAfterCycle;
- Messages.Message("WULA_MaintenanceComplete".Translate(occupant.Named("PAWN")), occupant, MessageTypeDefOf.PositiveEvent);
- maintenanceDone = true;
- }
+ maintenanceNeed.PerformMaintenance(Props.needLevelAfterCycle);
}
-
- // 2. Heal all other injuries and missing parts
+ // 2. ˣã
+ if (Props.healInjuries)
+ {
+ HealInjuries(pawn);
+ }
+ // 3. ȱʧλã
+ if (Props.healMissingParts)
+ {
+ HealMissingParts(pawn);
+ }
+ }
+ private void HealInjuries(Pawn pawn)
+ {
int injuriesHealed = 0;
- // Loop until no more health conditions can be fixed
- while (HealthUtility.TryGetWorstHealthCondition(occupant, out var hediffToFix, out var _))
+ var injuries = pawn.health.hediffSet.hediffs
+ .Where(h => h.def.isBad && h.Visible && h.def != HediffDefOf.BloodLoss)
+ .ToList();
+ foreach (var injury in injuries)
{
- // Ensure we don't try to "heal" the maintenance hediff itself, as it's handled separately.
- if (hediffToFix != null && hediffToFix.def == Props.hediffToRemove)
- {
+ if (injuriesHealed >= Props.maxInjuriesHealedPerCycle)
break;
- }
-
- // Store the state before attempting to fix
- int initialHediffCount = occupant.health.hediffSet.hediffs.Count;
- var hediffsBefore = new HashSet(occupant.health.hediffSet.hediffs);
-
- // Attempt to fix the worst condition
- HealthUtility.FixWorstHealthCondition(occupant);
-
- // Check if a change actually occurred
- bool conditionFixed = initialHediffCount > occupant.health.hediffSet.hediffs.Count ||
- !hediffsBefore.SetEquals(occupant.health.hediffSet.hediffs);
-
- if (conditionFixed)
- {
- injuriesHealed++;
- }
- else
- {
- // If FixWorstHealthCondition did nothing, it means it can't handle
- // the current worst condition. We must break to avoid an infinite loop.
- Log.Warning($"[WulaPodDebug] Halting healing loop. FixWorstHealthCondition did not resolve: {hediffToFix?.LabelCap ?? "a missing part"}.");
- break;
- }
+ pawn.health.RemoveHediff(injury);
+ injuriesHealed++;
}
-
if (injuriesHealed > 0)
{
- Messages.Message("WULA_MaintenanceHealedAllWounds".Translate(occupant.Named("PAWN")), occupant, MessageTypeDefOf.PositiveEvent);
+ Messages.Message("WULA_MaintenanceHealedInjuries".Translate(pawn.LabelShortCap, injuriesHealed), MessageTypeDefOf.PositiveEvent);
+ }
+ }
+ private void HealMissingParts(Pawn pawn)
+ {
+ var missingParts = pawn.health.hediffSet.GetMissingPartsCommonAncestors();
+ int partsHealed = 0;
+ foreach (var missingPart in missingParts)
+ {
+ if (partsHealed >= 1) // ÿһȱʧλ
+ break;
+ pawn.health.RemoveHediff(missingPart);
+ partsHealed++;
+ }
+ if (partsHealed > 0)
+ {
+ Messages.Message("WULA_MaintenanceHealedParts".Translate(pawn.LabelShortCap), MessageTypeDefOf.PositiveEvent);
}
- else if (!maintenanceDone)
- {
- // If nothing was done at all, give a neutral message
- Messages.Message("WULA_MaintenanceNoEffect".Translate(occupant.Named("PAWN")), occupant, MessageTypeDefOf.NeutralEvent);
- }
-
- EjectPawn();
}
-
public void EjectPawn(bool interrupted = false)
{
- Pawn occupant = Occupant;
- Log.Warning($"[WulaPodDebug] EjectPawn. Occupant: {(occupant == null ? "NULL" : occupant.LabelShortCap)}");
+ var occupant = Occupant;
if (occupant != null)
{
- Map mapToUse = parent.Map ?? Find.CurrentMap;
- if (mapToUse == null)
+ // Ԫ
+ innerContainer.TryDropAll(parent.InteractionCell, parent.Map, ThingPlaceMode.Near);
+
+ // ˳Ч
+ if (Props.exitSound != null)
{
- // Try to find the map from nearby things
- mapToUse = GenClosest.ClosestThing_Global(occupant.Position, Gen.YieldSingle(parent), 99999f, (thing) => thing.Map != null)?.Map;
+ Props.exitSound.PlayOneShot(new TargetInfo(parent.Position, parent.Map));
}
-
- if (mapToUse != null)
- {
- innerContainer.TryDropAll(parent.InteractionCell, mapToUse, ThingPlaceMode.Near);
- if (Props.exitSound != null)
- {
- SoundStarter.PlayOneShot(Props.exitSound, new TargetInfo(parent.Position, mapToUse));
- }
- }
- else
- {
- Log.Error($"[WulaPodDebug] EjectPawn FAILED: No valid map found to eject {occupant.LabelShortCap}. The pawn will be lost.");
- }
-
- // Additional logic to handle occupant if needed
+ // жϣӦøЧ
if (interrupted)
{
- occupant.needs?.mood.thoughts.memories.TryGainMemory(ThoughtDefOf.SoakingWet);
- occupant.health?.AddHediff(HediffDefOf.BiosculptingSickness);
+ occupant.needs?.mood?.thoughts?.memories?.TryGainMemory(ThoughtDefOf.SoakingWet);
}
}
innerContainer.Clear();
state = MaintenancePodState.Idle;
- Log.Warning($"[WulaPodDebug] EjectPawn finished. State set to Idle.");
- }
+ // Ч
+ if (operatingEffecter != null)
+ {
+ operatingEffecter.Cleanup();
+ operatingEffecter = null;
+ }
+ }
// ===================== UI & Gizmos =====================
public override string CompInspectStringExtra()
{
StringBuilder sb = new StringBuilder();
sb.AppendLine("WULA_MaintenancePod_Status".Translate() + ": " + $"WULA_MaintenancePod_State_{state}".Translate());
-
- if (state == MaintenancePodState.Running)
+ if (state == MaintenancePodState.Running && Occupant != null)
{
- if (Occupant != null)
- {
- sb.AppendLine("Contains".Translate() + ": " + Occupant.NameShortColored.Resolve());
- }
+ sb.AppendLine("Contains".Translate() + ": " + Occupant.NameShortColored.Resolve());
sb.AppendLine("TimeLeft".Translate() + ": " + ticksRemaining.ToStringTicksToPeriod());
+ var maintenanceNeed = Occupant.needs?.TryGetNeed();
+ if (maintenanceNeed != null)
+ {
+ // ֱʾ CurLevelȷ Need ʾһ
+ sb.AppendLine("WULA_MaintenanceLevel".Translate() + ": " + maintenanceNeed.CurLevel.ToStringPercent());
+ }
}
-
if (!PowerOn)
{
sb.AppendLine("NoPower".Translate().Colorize(Color.red));
}
-
return sb.ToString().TrimEnd();
}
-
public override IEnumerable CompGetGizmosExtra()
{
foreach (var gizmo in base.CompGetGizmosExtra())
{
yield return gizmo;
}
-
+ // άյİť
if (state == MaintenancePodState.Idle && PowerOn)
{
- var enterCommand = new Command_Action
+ yield return new Command_Action
{
defaultLabel = "WULA_MaintenancePod_Enter".Translate(),
defaultDesc = "WULA_MaintenancePod_EnterDesc".Translate(),
icon = EnterIcon,
- action = () =>
- {
- List options = GetPawnOptions();
- if (options.Any())
- {
- Find.WindowStack.Add(new FloatMenu(options));
- }
- else
- {
- Messages.Message("WULA_MaintenancePod_NoOneNeeds".Translate(), MessageTypeDefOf.RejectInput);
- }
- }
+ action = () => ShowPawnSelectionMenu()
};
- yield return enterCommand;
}
-
+ // ȡάİť
if (state == MaintenancePodState.Running)
{
- var cancelCommand = new Command_Action
+ yield return new Command_Action
{
defaultLabel = "CommandCancelConstructionLabel".Translate(),
defaultDesc = "WULA_MaintenancePod_CancelDesc".Translate(),
icon = CancelIcon,
action = () =>
{
- EjectPawn();
+ EjectPawn(true);
Messages.Message("WULA_MaintenanceCanceled".Translate(), MessageTypeDefOf.NegativeEvent);
}
};
- yield return cancelCommand;
- }
-
- // DEV GIZMO
- if (DebugSettings.godMode && state == MaintenancePodState.Running)
- {
- var finishCommand = new Command_Action
- {
- defaultLabel = "DEV: Finish Cycle",
- action = () =>
- {
- Log.Warning("[WulaPodDebug] DEV: Force finishing cycle.");
- CycleFinished();
- }
- };
- yield return finishCommand;
}
}
-
+ private void ShowPawnSelectionMenu()
+ {
+ var options = GetPawnOptions();
+ if (options.Any())
+ {
+ Find.WindowStack.Add(new FloatMenu(options));
+ }
+ else
+ {
+ Messages.Message("WULA_MaintenancePod_NoOneNeeds".Translate(), MessageTypeDefOf.RejectInput);
+ }
+ }
private List GetPawnOptions()
{
- List options = new List();
- // Now iterates over all pawns on the map, not just colonists.
- foreach (Pawn p in parent.Map.mapPawns.AllPawns.Where(pawn => pawn.def.defName == "WulaSpecies" || pawn.def.defName == "WulaSpeciesReal"))
- {
- if (p.health.hediffSet.HasHediff(Props.hediffToRemove))
- {
- // If the pawn is downed or not a free colonist, they need to be brought to the pod.
- if (p.Downed || !p.IsFreeColonist)
- {
- float required = RequiredComponents(p);
- if (refuelableComp.Fuel < required)
- {
- options.Add(new FloatMenuOption(p.LabelShortCap + " (" + p.KindLabel + ", " + "WULA_MaintenancePod_NotEnoughComponents".Translate(required.ToString("F0")) + ")", null));
- }
- else
- {
- // Find colonists who can haul the pawn.
- var potentialHaulers = parent.Map.mapPawns.FreeColonistsSpawned.Where(colonist =>
- !colonist.Downed && colonist.CanReserveAndReach(p, PathEndMode.OnCell, Danger.Deadly) && colonist.CanReserveAndReach(parent, PathEndMode.InteractionCell, Danger.Deadly));
+ var options = new List();
+ var map = parent.Map;
- if (!potentialHaulers.Any())
- {
- // If no one can haul, then it's unreachable.
- options.Add(new FloatMenuOption(p.LabelShortCap + " (" + p.KindLabel + ", " + "CannotReach".Translate() + ")", null));
- }
- else
- {
- Action action = delegate
- {
- // Create a menu to select which colonist should do the hauling.
- var haulerOptions = new List();
- foreach (var hauler in potentialHaulers)
- {
- haulerOptions.Add(new FloatMenuOption(hauler.LabelCap, delegate
- {
- var haulJob = JobMaker.MakeJob(JobDefOf_WULA.WULA_HaulToMaintenancePod, p, parent);
- haulJob.count = 1;
- hauler.jobs.TryTakeOrderedJob(haulJob, JobTag.Misc);
- }));
- }
- Find.WindowStack.Add(new FloatMenu(haulerOptions));
- };
- options.Add(new FloatMenuOption(p.LabelShortCap + " (" + p.KindLabel + ")", action));
- }
- }
- }
- // If the pawn is a free colonist and can walk, they can go on their own.
- else
- {
- if (!p.CanReach(parent, PathEndMode.InteractionCell, Danger.Deadly))
- {
- options.Add(new FloatMenuOption(p.LabelShortCap + " (" + "CannotReach".Translate() + ")", null));
- }
- else
- {
- float required = RequiredComponents(p);
- if (refuelableComp.Fuel >= required)
- {
- options.Add(new FloatMenuOption(p.LabelShortCap, () =>
- {
- Job job = JobMaker.MakeJob(JobDefOf_WULA.WULA_EnterMaintenancePod, parent);
- p.jobs.TryTakeOrderedJob(job, JobTag.Misc);
- }));
- }
- else
- {
- options.Add(new FloatMenuOption(p.LabelShortCap + " (" + "WULA_MaintenancePod_NotEnoughComponents".Translate(required.ToString("F0")) + ")", null));
- }
- }
- }
+ foreach (var pawn in map.mapPawns.AllPawnsSpawned)
+ {
+ // ȼǷά
+ var maintenanceNeed = pawn.needs?.TryGetNeed();
+ if (maintenanceNeed == null)
+ {
+ // Pawnûά
+ continue;
}
+
+ // ǷҪά
+ if (maintenanceNeed.CurLevel > Props.minNeedLevelToMaintain && !DebugSettings.godMode)
+ continue;
+
+ // ѡ
+ var option = CreatePawnOption(pawn, maintenanceNeed);
+ if (option != null)
+ options.Add(option);
}
+
return options;
}
- }
+ private FloatMenuOption CreatePawnOption(Pawn pawn, Need_Maintenance need)
+ {
+ string label = $"{pawn.LabelShortCap} ({need.CurLevel.ToStringPercent()})";
+ float requiredComponents = RequiredComponents;
+ // Ƿ㹻
+ if (refuelableComp.Fuel < requiredComponents)
+ {
+ return new FloatMenuOption(label + " (" + "WULA_MaintenancePod_NotEnoughComponents".Translate(requiredComponents.ToString("F0")) + ")", null);
+ }
+ // ǷԵ
+ if (!pawn.CanReach(parent, PathEndMode.InteractionCell, Danger.Deadly))
+ {
+ return new FloatMenuOption(label + " (" + "CannotReach".Translate() + ")", null);
+ }
+ return new FloatMenuOption(label, () =>
+ {
+ if (pawn.Downed || !pawn.IsFreeColonist)
+ {
+ // Ҫ
+ var haulJob = JobMaker.MakeJob(JobDefOf_WULA.WULA_HaulToMaintenancePod, pawn, parent);
+ var hauler = FindBestHauler(pawn);
+ if (hauler != null)
+ {
+ hauler.jobs.TryTakeOrderedJob(haulJob);
+ }
+ else
+ {
+ Messages.Message("WULA_NoHaulerAvailable".Translate(), MessageTypeDefOf.RejectInput);
+ }
+ }
+ else
+ {
+ // Լ
+ var enterJob = JobMaker.MakeJob(JobDefOf_WULA.WULA_EnterMaintenancePod, parent);
+ pawn.jobs.TryTakeOrderedJob(enterJob);
+ }
+ });
+ }
+ private Pawn FindBestHauler(Pawn target)
+ {
+ return parent.Map.mapPawns.FreeColonistsSpawned
+ .Where(colonist => !colonist.Downed &&
+ colonist.CanReserveAndReach(target, PathEndMode.OnCell, Danger.Deadly) &&
+ colonist.CanReserveAndReach(parent, PathEndMode.InteractionCell, Danger.Deadly))
+ .OrderBy(colonist => colonist.Position.DistanceTo(target.Position))
+ .FirstOrDefault();
+ }
+ }
public enum MaintenancePodState
{
Idle,
- Running,
+ Running
}
}
\ No newline at end of file
diff --git a/Source/WulaFallenEmpire/Pawn/WULA_Maintenance/HediffCompProperties_MaintenanceDamage.cs b/Source/WulaFallenEmpire/Pawn/WULA_Maintenance/HediffCompProperties_MaintenanceDamage.cs
new file mode 100644
index 00000000..61eb71ce
--- /dev/null
+++ b/Source/WulaFallenEmpire/Pawn/WULA_Maintenance/HediffCompProperties_MaintenanceDamage.cs
@@ -0,0 +1,36 @@
+// HediffComp_MaintenanceDamage.cs
+using RimWorld;
+using Verse;
+
+namespace WulaFallenEmpire
+{
+ public class HediffCompProperties_MaintenanceDamage : HediffCompProperties
+ {
+ public float damageToMaintenanceFactor = 0.01f; // 每点伤害扣除的维护度比例
+
+ public HediffCompProperties_MaintenanceDamage()
+ {
+ compClass = typeof(HediffComp_MaintenanceDamage);
+ }
+ }
+
+ public class HediffComp_MaintenanceDamage : HediffComp
+ {
+ private HediffCompProperties_MaintenanceDamage Props => (HediffCompProperties_MaintenanceDamage)props;
+
+ public override void Notify_PawnPostApplyDamage(DamageInfo dinfo, float totalDamageDealt)
+ {
+ base.Notify_PawnPostApplyDamage(dinfo, totalDamageDealt);
+
+ // 获取维护需求
+ var maintenanceNeed = Pawn.needs?.TryGetNeed();
+ if (maintenanceNeed == null)
+ return;
+
+ // 直接应用伤害惩罚
+ maintenanceNeed.ApplyDamagePenalty(totalDamageDealt);
+ }
+
+ public override string CompTipStringExtra => "WULA_DamageAffectsMaintenance".Translate(Props.damageToMaintenanceFactor.ToStringPercent());
+ }
+}
diff --git a/Source/WulaFallenEmpire/Pawn/WULA_Maintenance/HediffComp_MaintenanceNeed.cs b/Source/WulaFallenEmpire/Pawn/WULA_Maintenance/HediffComp_MaintenanceNeed.cs
deleted file mode 100644
index 72cc6722..00000000
--- a/Source/WulaFallenEmpire/Pawn/WULA_Maintenance/HediffComp_MaintenanceNeed.cs
+++ /dev/null
@@ -1,40 +0,0 @@
-using Verse;
-
-namespace WulaFallenEmpire
-{
- public class HediffCompProperties_MaintenanceNeed : HediffCompProperties
- {
- public float severityPerDayBeforeThreshold = 0.0f;
- public float severityPerDayAfterThreshold = 0.0f;
- public float thresholdDays = 0.0f;
-
- public HediffCompProperties_MaintenanceNeed()
- {
- compClass = typeof(HediffComp_MaintenanceNeed);
- }
- }
-
- public class HediffComp_MaintenanceNeed : HediffComp
- {
- private HediffCompProperties_MaintenanceNeed Props => (HediffCompProperties_MaintenanceNeed)props;
-
- public override void CompPostTick(ref float severityAdjustment)
- {
- base.CompPostTick(ref severityAdjustment);
-
- // We adjust severity once per game day (60000 ticks)
- if (parent.ageTicks % 60000 == 0)
- {
- float ageInDays = (float)parent.ageTicks / 60000f;
- if (ageInDays < Props.thresholdDays)
- {
- severityAdjustment += Props.severityPerDayBeforeThreshold;
- }
- else
- {
- severityAdjustment += Props.severityPerDayAfterThreshold;
- }
- }
- }
- }
-}
\ No newline at end of file
diff --git a/Source/WulaFallenEmpire/Pawn/WULA_Maintenance/JobDefOf_WULA.cs b/Source/WulaFallenEmpire/Pawn/WULA_Maintenance/JobDefOf_WULA.cs
deleted file mode 100644
index 917ffc15..00000000
--- a/Source/WulaFallenEmpire/Pawn/WULA_Maintenance/JobDefOf_WULA.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-using RimWorld;
-using Verse;
-
-namespace WulaFallenEmpire
-{
- [DefOf]
- public static class JobDefOf_WULA
- {
- public static JobDef WULA_EnterMaintenancePod;
-
- public static JobDef WULA_HaulToMaintenancePod;
-
- static JobDefOf_WULA()
- {
- DefOfHelper.EnsureInitializedInCtor(typeof(JobDefOf_WULA));
- }
- }
-}
\ No newline at end of file
diff --git a/Source/WulaFallenEmpire/Pawn/WULA_Maintenance/JobDriver_EnterMaintenancePod.cs b/Source/WulaFallenEmpire/Pawn/WULA_Maintenance/JobDriver_EnterMaintenancePod.cs
index 839f57bd..ee2a2d80 100644
--- a/Source/WulaFallenEmpire/Pawn/WULA_Maintenance/JobDriver_EnterMaintenancePod.cs
+++ b/Source/WulaFallenEmpire/Pawn/WULA_Maintenance/JobDriver_EnterMaintenancePod.cs
@@ -1,5 +1,5 @@
+// JobDriver_EnterMaintenancePod.cs (更新版)
using RimWorld;
-using System;
using System.Collections.Generic;
using Verse;
using Verse.AI;
@@ -11,6 +11,7 @@ namespace WulaFallenEmpire
private const TargetIndex PodIndex = TargetIndex.A;
protected Thing Pod => job.GetTarget(PodIndex).Thing;
+ protected CompMaintenancePod PodComp => Pod?.TryGetComp();
public override bool TryMakePreToilReservations(bool errorOnFailed)
{
@@ -19,29 +20,24 @@ namespace WulaFallenEmpire
protected override IEnumerable MakeNewToils()
{
- Log.Warning($"[WulaPodDebug] JobDriver_EnterMaintenancePod started for pawn: {pawn.LabelShortCap}");
this.FailOnDespawnedNullOrForbidden(PodIndex);
- this.FailOnBurningImmobile(PodIndex);
+ this.FailOn(() => PodComp == null || PodComp.State != MaintenancePodState.Idle || !PodComp.PowerOn);
- var podComp = Pod.TryGetComp();
- this.FailOn(() => podComp == null || podComp.State != MaintenancePodState.Idle || !podComp.PowerOn);
+ // 移动到维护舱
+ yield return Toils_Goto.GotoThing(PodIndex, PathEndMode.InteractionCell);
- // Go to the pod's interaction cell
- Toil goToPod = Toils_Goto.GotoThing(PodIndex, PathEndMode.InteractionCell);
- goToPod.AddPreInitAction(() => Log.Warning($"[WulaPodDebug] EnterJob: Pawn {pawn.LabelShortCap} is going to the pod."));
- yield return goToPod;
-
- // Enter the pod
- Toil enterToil = new Toil
+ // 进入维护舱
+ yield return new Toil
{
initAction = () =>
{
- Log.Warning($"[WulaPodDebug] EnterJob: Pawn {pawn.LabelShortCap} has arrived and is entering the pod.");
- podComp.StartCycle(pawn);
+ if (PodComp != null)
+ {
+ PodComp.StartCycle(pawn);
+ }
},
defaultCompleteMode = ToilCompleteMode.Instant
};
- yield return enterToil;
}
}
-}
\ No newline at end of file
+}
diff --git a/Source/WulaFallenEmpire/Pawn/WULA_Maintenance/JobDriver_HaulToMaintenancePod.cs b/Source/WulaFallenEmpire/Pawn/WULA_Maintenance/JobDriver_HaulToMaintenancePod.cs
index 8504f1c5..f836377b 100644
--- a/Source/WulaFallenEmpire/Pawn/WULA_Maintenance/JobDriver_HaulToMaintenancePod.cs
+++ b/Source/WulaFallenEmpire/Pawn/WULA_Maintenance/JobDriver_HaulToMaintenancePod.cs
@@ -1,3 +1,4 @@
+// JobDriver_HaulToMaintenancePod.cs (修复版)
using System.Collections.Generic;
using RimWorld;
using Verse;
@@ -12,52 +13,70 @@ namespace WulaFallenEmpire
protected Pawn Takee => (Pawn)job.GetTarget(TakeeIndex).Thing;
protected Building Pod => (Building)job.GetTarget(PodIndex).Thing;
- protected CompMaintenancePod PodComp => Pod.TryGetComp();
+ protected CompMaintenancePod PodComp => Pod?.TryGetComp();
public override bool TryMakePreToilReservations(bool errorOnFailed)
{
+ // 修复:明确指定计数为1
return pawn.Reserve(Takee, job, 1, -1, null, errorOnFailed)
&& pawn.Reserve(Pod, job, 1, -1, null, errorOnFailed);
}
protected override IEnumerable MakeNewToils()
{
- Log.Warning($"[WulaPodDebug] JobDriver_HaulToMaintenancePod started. Hauler: {pawn.LabelShortCap}, Takee: {Takee.LabelShortCap}");
- // Standard failure conditions
this.FailOnDestroyedOrNull(TakeeIndex);
this.FailOnDestroyedOrNull(PodIndex);
- this.FailOnAggroMentalStateAndHostile(TakeeIndex);
- this.FailOn(() => PodComp == null);
- this.FailOn(() => !pawn.CanReach(Pod, PathEndMode.InteractionCell, Danger.Deadly));
- this.FailOn(() => !Takee.Downed);
+ this.FailOn(() => PodComp == null || PodComp.State != MaintenancePodState.Idle);
- // Go to the pawn to be rescued
- Toil goToTakee = Toils_Goto.GotoThing(TakeeIndex, PathEndMode.ClosestTouch)
- .FailOnDespawnedNullOrForbidden(TakeeIndex)
- .FailOnDespawnedNullOrForbidden(PodIndex)
- .FailOnSomeonePhysicallyInteracting(TakeeIndex);
- goToTakee.AddPreInitAction(() => Log.Warning($"[WulaPodDebug] HaulJob: {pawn.LabelShortCap} is going to pick up {Takee.LabelShortCap}."));
- yield return goToTakee;
+ // 前往目标 pawn
+ yield return Toils_Goto.GotoThing(TakeeIndex, PathEndMode.ClosestTouch);
- // Start carrying the pawn
- Toil startCarrying = Toils_Haul.StartCarryThing(TakeeIndex, false, true, false);
- startCarrying.AddPreInitAction(() => Log.Warning($"[WulaPodDebug] HaulJob: {pawn.LabelShortCap} is now carrying {Takee.LabelShortCap}."));
- yield return startCarrying;
-
- // Go to the maintenance pod
- Toil goToPod = Toils_Goto.GotoThing(PodIndex, PathEndMode.InteractionCell);
- goToPod.AddPreInitAction(() => Log.Warning($"[WulaPodDebug] HaulJob: {pawn.LabelShortCap} is hauling {Takee.LabelShortCap} to the pod."));
- yield return goToPod;
-
- // Place the pawn inside the pod
- Toil placeInPod = ToilMaker.MakeToil("PlaceInPod");
- placeInPod.initAction = delegate
+ // 开始搬运 - 修复计数问题
+ yield return new Toil
{
- Log.Warning($"[WulaPodDebug] HaulJob: {pawn.LabelShortCap} has arrived and is placing {Takee.LabelShortCap} in the pod.");
- PodComp.StartCycle(Takee);
+ initAction = () =>
+ {
+ // 明确设置搬运数量为1
+ if (pawn.carryTracker.CarriedThing == null)
+ {
+ if (Takee == null || Takee.Destroyed)
+ {
+ Log.Error("试图搬运不存在的Pawn");
+ return;
+ }
+
+ // 使用TryStartCarryThing并明确指定数量
+ if (pawn.carryTracker.TryStartCarry(Takee, 1) <= 0)
+ {
+ Log.Error($"无法搬运Pawn: {Takee.Label}");
+ EndJobWith(JobCondition.Incompletable);
+ }
+ }
+ },
+ defaultCompleteMode = ToilCompleteMode.Instant
+ };
+
+ // 前往维护舱
+ yield return Toils_Goto.GotoThing(PodIndex, PathEndMode.InteractionCell);
+
+ // 放入维护舱
+ yield return new Toil
+ {
+ initAction = () =>
+ {
+ if (PodComp != null && Takee != null)
+ {
+ // 确保Pawn被放下
+ if (pawn.carryTracker.CarriedThing == Takee)
+ {
+ pawn.carryTracker.TryDropCarriedThing(pawn.Position, ThingPlaceMode.Near, out _);
+ }
+
+ PodComp.StartCycle(Takee);
+ }
+ },
+ defaultCompleteMode = ToilCompleteMode.Instant
};
- placeInPod.defaultCompleteMode = ToilCompleteMode.Instant;
- yield return placeInPod;
}
}
-}
\ No newline at end of file
+}
diff --git a/Source/WulaFallenEmpire/Pawn/WULA_Maintenance/Job_Maintenance.cs b/Source/WulaFallenEmpire/Pawn/WULA_Maintenance/Job_Maintenance.cs
deleted file mode 100644
index 46cd988c..00000000
--- a/Source/WulaFallenEmpire/Pawn/WULA_Maintenance/Job_Maintenance.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-using RimWorld;
-using Verse;
-using Verse.AI;
-
-namespace WulaFallenEmpire
-{
- public class WorkGiver_DoMaintenance : WorkGiver_Scanner
- {
- public override ThingRequest PotentialWorkThingRequest => ThingRequest.ForDef(ThingDef.Named("WULA_MaintenancePod"));
-
- public override bool HasJobOnThing(Pawn pawn, Thing t, bool forced = false)
- {
- return pawn.CanReserve(t, 1, -1, null, forced);
- }
-
- public override Job JobOnThing(Pawn pawn, Thing t, bool forced = false)
- {
- return JobMaker.MakeJob(DefDatabase.GetNamed("WULA_EnterMaintenancePod"), t);
- }
- }
-}
\ No newline at end of file
diff --git a/Source/WulaFallenEmpire/Pawn/WULA_Maintenance/MaintenanceNeedExtension.cs b/Source/WulaFallenEmpire/Pawn/WULA_Maintenance/MaintenanceNeedExtension.cs
new file mode 100644
index 00000000..4162105c
--- /dev/null
+++ b/Source/WulaFallenEmpire/Pawn/WULA_Maintenance/MaintenanceNeedExtension.cs
@@ -0,0 +1,26 @@
+// MaintenanceNeedExtension.cs
+using Verse;
+
+namespace WulaFallenEmpire
+{
+ public class MaintenanceNeedExtension : DefModExtension
+ {
+ // 基础退化设置
+ public float severityPerDayBeforeThreshold = 0.05f;
+ public float severityPerDayAfterThreshold = 0.1f;
+ public float thresholdDays = 5f;
+
+ // 状态阈值
+ public float minorBreakdownThreshold = 0.3f;
+ public float majorBreakdownThreshold = 0.1f;
+ public float criticalFailureThreshold = 0.01f;
+
+ // 伤害相关设置 - 简化
+ public float damageToMaintenanceFactor = 0.01f; // 每点伤害扣除的维护度
+
+ // 维护效果相关的 HediffDefs
+ public HediffDef minorBreakdownHediff = null;
+ public HediffDef majorBreakdownHediff = null;
+ public HediffDef criticalFailureHediff = null;
+ }
+}
diff --git a/Source/WulaFallenEmpire/Pawn/WULA_Maintenance/Need_Maintenance.cs b/Source/WulaFallenEmpire/Pawn/WULA_Maintenance/Need_Maintenance.cs
new file mode 100644
index 00000000..6f7cb1a7
--- /dev/null
+++ b/Source/WulaFallenEmpire/Pawn/WULA_Maintenance/Need_Maintenance.cs
@@ -0,0 +1,237 @@
+// Need_Maintenance.cs
+using RimWorld;
+using Verse;
+using System.Linq;
+using System;
+
+namespace WulaFallenEmpire
+{
+ public class Need_Maintenance : Need
+ {
+ private MaintenanceNeedExtension Extension => def.GetModExtension();
+
+ // 上次维护的天数
+ private float daysSinceLastMaintenance = 0f;
+
+ // 当前维护状态
+ public MaintenanceStatus Status
+ {
+ get
+ {
+ if (CurLevel <= Extension?.criticalFailureThreshold) return MaintenanceStatus.CriticalFailure;
+ if (CurLevel <= Extension?.majorBreakdownThreshold) return MaintenanceStatus.MajorBreakdown;
+ if (CurLevel <= Extension?.minorBreakdownThreshold) return MaintenanceStatus.MinorBreakdown;
+ return MaintenanceStatus.Operational;
+ }
+ }
+
+ public float DaysSinceLastMaintenance => daysSinceLastMaintenance;
+
+ public Need_Maintenance(Pawn pawn) : base(pawn)
+ {
+ }
+
+ public override void SetInitialLevel()
+ {
+ CurLevel = 1.0f;
+ daysSinceLastMaintenance = 0f;
+ }
+
+ public override void NeedInterval()
+ {
+ if (pawn.Dead || !pawn.Spawned)
+ return;
+
+ // 每150 ticks 更新一次(Need 的标准间隔)
+ if (IsFrozen)
+ return;
+
+ // 增加天数计数
+ daysSinceLastMaintenance += 150f / 60000f; // 150 ticks 占一天的比例
+
+ // 计算退化速率
+ float degradationRate = CalculateDegradationRate();
+
+ // 应用退化
+ CurLevel -= degradationRate * (150f / 60000f); // 转换为每天的比例
+
+ // 确保数值在有效范围内
+ CurLevel = ClampNeedLevel(CurLevel);
+
+ // 检查状态变化
+ CheckStatusChanges();
+ }
+
+ private float CalculateDegradationRate()
+ {
+ if (Extension == null)
+ return 0f;
+
+ if (daysSinceLastMaintenance < Extension.thresholdDays)
+ {
+ return Extension.severityPerDayBeforeThreshold;
+ }
+ else
+ {
+ return Extension.severityPerDayAfterThreshold;
+ }
+ }
+
+ private void CheckStatusChanges()
+ {
+ if (Extension == null)
+ return;
+
+ // 检查是否需要应用故障效果
+ var currentStatus = Status;
+
+ // 移除旧的维护相关 Hediff
+ RemoveMaintenanceHediffs();
+
+ // 根据状态添加相应的 Hediff
+ switch (currentStatus)
+ {
+ case MaintenanceStatus.MinorBreakdown:
+ if (Extension.minorBreakdownHediff != null)
+ pawn.health.AddHediff(Extension.minorBreakdownHediff);
+ break;
+
+ case MaintenanceStatus.MajorBreakdown:
+ if (Extension.majorBreakdownHediff != null)
+ pawn.health.AddHediff(Extension.majorBreakdownHediff);
+ break;
+
+ case MaintenanceStatus.CriticalFailure:
+ if (Extension.criticalFailureHediff != null)
+ pawn.health.AddHediff(Extension.criticalFailureHediff);
+ break;
+ }
+ }
+
+ private void RemoveMaintenanceHediffs()
+ {
+ if (Extension == null)
+ return;
+
+ // 移除所有维护相关的 Hediff
+ var hediffsToRemove = pawn.health.hediffSet.hediffs.FindAll(h =>
+ h.def == Extension.minorBreakdownHediff ||
+ h.def == Extension.majorBreakdownHediff ||
+ h.def == Extension.criticalFailureHediff);
+
+ foreach (var hediff in hediffsToRemove)
+ {
+ pawn.health.RemoveHediff(hediff);
+ }
+ }
+
+ // 执行维护操作
+ public void PerformMaintenance(float maintenanceAmount = 1.0f)
+ {
+ CurLevel += maintenanceAmount;
+ CurLevel = ClampNeedLevel(CurLevel);
+ daysSinceLastMaintenance = 0f;
+
+ // 移除所有维护相关的负面效果
+ RemoveMaintenanceHediffs();
+
+ // 触发维护完成的效果
+ OnMaintenancePerformed(maintenanceAmount);
+ }
+
+ // 应用伤害惩罚 - 简单的线性减少
+ public void ApplyDamagePenalty(float damageAmount)
+ {
+ if (Extension == null) return;
+
+ // 直接线性减少维护度
+ float reduction = damageAmount * Extension.damageToMaintenanceFactor;
+ CurLevel = Math.Max(0f, CurLevel - reduction);
+
+ // 立即检查状态变化
+ CheckStatusChanges();
+
+ if (pawn.IsColonistPlayerControlled && reduction > 0.01f)
+ {
+ Messages.Message("WULA_MaintenanceReducedDueToDamage".Translate(pawn.LabelShort, reduction.ToStringPercent()),
+ pawn, MessageTypeDefOf.NegativeEvent);
+ }
+ }
+
+ private void OnMaintenancePerformed(float amount)
+ {
+ // 这里可以添加维护完成时的特殊效果
+ if (pawn.IsColonistPlayerControlled)
+ {
+ Messages.Message("WULA_MaintenanceCompleted".Translate(pawn.LabelShort), pawn, MessageTypeDefOf.PositiveEvent);
+ }
+ }
+
+ private float ClampNeedLevel(float level)
+ {
+ return level < 0f ? 0f : (level > 1f ? 1f : level);
+ }
+
+ public override string GetTipString()
+ {
+ string baseTip = base.GetTipString();
+
+ string statusText = "WULA_MaintenanceStatus".Translate(Status.GetLabel(), daysSinceLastMaintenance.ToString("F1"));
+ string degradationText = "WULA_DegradationRate".Translate(CalculateDegradationRate().ToString("F3"));
+
+ return $"{baseTip}\n\n{statusText}\n{degradationText}";
+ }
+
+ public override void ExposeData()
+ {
+ base.ExposeData();
+ Scribe_Values.Look(ref daysSinceLastMaintenance, "daysSinceLastMaintenance", 0f);
+ }
+ }
+
+ // 维护状态枚举
+ public enum MaintenanceStatus
+ {
+ Operational,
+ MinorBreakdown,
+ MajorBreakdown,
+ CriticalFailure
+ }
+
+ public static class MaintenanceStatusExtensions
+ {
+ public static string GetLabel(this MaintenanceStatus status)
+ {
+ switch (status)
+ {
+ case MaintenanceStatus.Operational:
+ return "WULA_Operational".Translate();
+ case MaintenanceStatus.MinorBreakdown:
+ return "WULA_MinorBreakdown".Translate();
+ case MaintenanceStatus.MajorBreakdown:
+ return "WULA_MajorBreakdown".Translate();
+ case MaintenanceStatus.CriticalFailure:
+ return "WULA_CriticalFailure".Translate();
+ default:
+ return "Unknown";
+ }
+ }
+
+ public static string GetDescription(this MaintenanceStatus status)
+ {
+ switch (status)
+ {
+ case MaintenanceStatus.Operational:
+ return "WULA_OperationalDesc".Translate();
+ case MaintenanceStatus.MinorBreakdown:
+ return "WULA_MinorBreakdownDesc".Translate();
+ case MaintenanceStatus.MajorBreakdown:
+ return "WULA_MajorBreakdownDesc".Translate();
+ case MaintenanceStatus.CriticalFailure:
+ return "WULA_CriticalFailureDesc".Translate();
+ default:
+ return "Unknown";
+ }
+ }
+ }
+}
diff --git a/Source/WulaFallenEmpire/Pawn/WULA_Maintenance/WorkGiver_DoMaintenance.cs b/Source/WulaFallenEmpire/Pawn/WULA_Maintenance/WorkGiver_DoMaintenance.cs
new file mode 100644
index 00000000..563cb1d6
--- /dev/null
+++ b/Source/WulaFallenEmpire/Pawn/WULA_Maintenance/WorkGiver_DoMaintenance.cs
@@ -0,0 +1,49 @@
+// WorkGiver_DoMaintenance.cs (修复版)
+using RimWorld;
+using Verse;
+using Verse.AI;
+
+namespace WulaFallenEmpire
+{
+ public class WorkGiver_DoMaintenance : WorkGiver_Scanner
+ {
+ public override ThingRequest PotentialWorkThingRequest =>
+ ThingRequest.ForDef(ThingDef.Named("WULA_MaintenancePod"));
+
+ public override PathEndMode PathEndMode => PathEndMode.Touch;
+
+ public override bool HasJobOnThing(Pawn pawn, Thing t, bool forced = false)
+ {
+ // 检查维护舱是否可用
+ if (!pawn.CanReserve(t, 1, -1, null, forced))
+ return false;
+
+ var podComp = t.TryGetComp();
+ if (podComp == null || podComp.State != MaintenancePodState.Idle || !podComp.PowerOn)
+ return false;
+
+ // 检查当前pawn是否有维护需求且需要维护
+ return PawnNeedsMaintenance(pawn);
+ }
+
+ public override Job JobOnThing(Pawn pawn, Thing t, bool forced = false)
+ {
+ return JobMaker.MakeJob(JobDefOf_WULA.WULA_EnterMaintenancePod, t);
+ }
+
+ // 检查单个Pawn是否需要维护
+ private bool PawnNeedsMaintenance(Pawn pawn)
+ {
+ // 检查是否有维护需求组件
+ var maintenanceNeed = pawn.needs?.TryGetNeed();
+ if (maintenanceNeed == null)
+ {
+ // 这个Pawn没有维护需求,不应该使用维护舱
+ return false;
+ }
+
+ // 检查维护水平是否低于阈值
+ return maintenanceNeed.CurLevel <= 0.3f; // 需要维护的阈值
+ }
+ }
+}
diff --git a/Source/WulaFallenEmpire/WulaDefOf.cs b/Source/WulaFallenEmpire/WulaDefOf.cs
index 87611687..762c95aa 100644
--- a/Source/WulaFallenEmpire/WulaDefOf.cs
+++ b/Source/WulaFallenEmpire/WulaDefOf.cs
@@ -15,4 +15,16 @@ namespace WulaFallenEmpire
DefOfHelper.EnsureInitializedInCtor(typeof(ThingDefOf_WULA));
}
}
+ [DefOf]
+ public static class JobDefOf_WULA
+ {
+ public static JobDef WULA_EnterMaintenancePod;
+
+ public static JobDef WULA_HaulToMaintenancePod;
+
+ static JobDefOf_WULA()
+ {
+ DefOfHelper.EnsureInitializedInCtor(typeof(JobDefOf_WULA));
+ }
+ }
}
\ No newline at end of file
diff --git a/Source/WulaFallenEmpire/WulaFallenEmpire.csproj b/Source/WulaFallenEmpire/WulaFallenEmpire.csproj
index 6808b591..ecabd352 100644
--- a/Source/WulaFallenEmpire/WulaFallenEmpire.csproj
+++ b/Source/WulaFallenEmpire/WulaFallenEmpire.csproj
@@ -106,6 +106,11 @@
+
+
+
+
+
@@ -142,11 +147,12 @@
-
-
+
-
+
+
+