暂存能量改动

This commit is contained in:
2025-07-21 02:05:37 +08:00
parent eed1c1b46a
commit ef074ec366
31 changed files with 4487 additions and 38 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,62 @@
# 修复乌拉能量喂食系统需求文档
## 介绍
乌拉堕落帝国模组中的能量喂食系统存在严重问题。当乌拉族进入关机状态需要能量补充时,自定义的 `WULA_IngestEnergy` JobDriver 出现了任务循环、物品转移错误和错误执行者等问题。本文档定义了修复这些问题的需求。
## 需求
### 需求 1修复任务重复创建问题
**用户故事:** 作为玩家,我希望当乌拉族需要能量补充时,只有一个殖民者执行喂食任务,而不是多个殖民者同时尝试执行相同任务。
#### 验收标准
1. 当乌拉族进入关机状态时,系统应该只创建一个 `WULA_IngestEnergy` 任务
2. 当一个殖民者已经预留了能量核心时,其他殖民者不应该创建相同的任务
3. 当任务失败时,系统应该正确清理预留状态,允许其他殖民者重新尝试
4. 系统不应该在单个tick内创建多个相同的任务
### 需求 2修复物品转移逻辑
**用户故事:** 作为玩家,我希望殖民者能够正确地拾取和转移能量核心,而不会出现"物品不存在"的错误。
#### 验收标准
1. 当殖民者执行 `WULA_IngestEnergy` 任务时,应该能够成功拾取目标能量核心
2. 当能量核心被其他殖民者拾取或消耗时,当前任务应该正确失败并清理状态
3. 当能量核心不存在或无法访问时,任务应该立即失败而不是进入循环
4. 物品转移应该使用正确的 Toil 方法,确保物品状态一致性
### 需求 3确保正确的任务执行者和目标
**用户故事:** 作为玩家,我希望殖民者将能量核心喂给需要能量的乌拉族,而不是自己消耗能量核心。
#### 验收标准
1. 当执行 `WULA_IngestEnergy` 任务时,殖民者应该将能量核心给予目标乌拉族
2. 能量应该补充到目标乌拉族的 `Need_WulaEnergy` 中,而不是执行者的需求
3. 只有目标乌拉族应该从关机状态中恢复,执行者不应该受到影响
4. 任务完成后,能量核心应该被正确消耗,目标乌拉族应该获得能量
### 需求 4改进任务验证和错误处理
**用户故事:** 作为玩家,我希望当能量喂食任务遇到问题时,系统能够优雅地处理错误,而不是进入无限循环。
#### 验收标准
1. 当目标乌拉族不再需要能量时,任务应该自动取消
2. 当能量核心不可用时,任务应该失败并提供适当的错误信息
3. 当执行者无法到达目标时,任务应该超时失败
4. 系统应该记录详细的调试信息以便问题诊断
### 需求 5优化 WorkGiver 逻辑
**用户故事:** 作为玩家,我希望系统能够智能地分配能量喂食任务,避免资源冲突和重复工作。
#### 验收标准
1. WorkGiver 应该检查目标能量核心是否已被其他任务预留
2. WorkGiver 应该验证执行者能够到达目标乌拉族和能量核心
3. WorkGiver 应该优先选择距离最近的可用能量核心
4. WorkGiver 应该正确处理囚犯和殖民者的不同喂食逻辑

Binary file not shown.

Binary file not shown.

View File

@@ -106,4 +106,32 @@
<li Class="HediffCompProperties_RemoveIfApparelDropped" />
</comps>
</HediffDef>
<HediffDef>
<defName>WULA_Shutdown</defName>
<label>停机</label>
<description>机体能量已完全耗尽,所有非核心功能已下线,需要立刻补充能量。</description>
<hediffClass>HediffWithComps</hediffClass>
<isBad>true</isBad>
<stages>
<li>
<label>停机</label>
<minSeverity>0</minSeverity>
<capMods>
<li>
<capacity>Consciousness</capacity>
<setMax>0.1</setMax>
</li>
<li>
<capacity>Moving</capacity>
<setMax>0.1</setMax>
</li>
<li>
<capacity>Manipulation</capacity>
<setMax>0.1</setMax>
</li>
</capMods>
</li>
</stages>
</HediffDef>
</Defs>

View File

@@ -10,6 +10,19 @@
<MarketValue>1500</MarketValue>
<Mass>0.1</Mass>
</statBases>
<recipeMaker>
<researchPrerequisite>Prosthetics</researchPrerequisite>
<skillRequirements>
<Crafting>8</Crafting>
</skillRequirements>
<recipeUsers>
<li>FabricationBench</li>
</recipeUsers>
</recipeMaker>
<costList>
<Plasteel>50</Plasteel>
<ComponentIndustrial>5</ComponentIndustrial>
</costList>
<comps>
<li Class="CompProperties_Usable">
<compClass>CompUsableImplant</compClass>

View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8" ?>
<Defs>
<JobDef>
<defName>WULA_IngestEnergy</defName>
<driverClass>WulaFallenEmpire.JobDriver_IngestWulaEnergy</driverClass>
<reportString>正在摄取能量。</reportString>
<allowOpportunisticPrefix>true</allowOpportunisticPrefix>
</JobDef>
<JobDef>
<defName>WULA_FeedWulaPatient</defName>
<driverClass>WulaFallenEmpire.JobDriver_FeedWulaPatient</driverClass>
<reportString>正在喂食能量核心。</reportString>
<allowOpportunisticPrefix>true</allowOpportunisticPrefix>
</JobDef>
</Defs>

View File

@@ -2,7 +2,7 @@
<Defs>
<NeedDef>
<defName>WULA_Energy</defName>
<needClass>Need_Food</needClass>
<needClass>WulaFallenEmpire.Need_WulaEnergy</needClass>
<label>能量</label>
<description>乌拉帝国的合成人正常活动需要能量维持,否则身体机能将持续恶化,最终导致有机部分不可逆的死亡。\n\n机械乌拉和常规机械体不同她们只有一种指定的能量接口只能通过能源核心补充能量在乌拉帝国编织体工作台制造这种核心。</description>
<listPriority>800</listPriority>
@@ -14,5 +14,12 @@
<showForCaravanMembers>true</showForCaravanMembers>
<developmentalStageFilter>Baby, Child, Adult</developmentalStageFilter>
<showUnitTicks>true</showUnitTicks>
<modExtensions>
<li Class="WulaFallenEmpire.NeedDefExtension_Energy">
<fallPerDay>1.6</fallPerDay>
<maxLevel>1.0</maxLevel>
<deliverEnergyThreshold>0.5</deliverEnergyThreshold>
</li>
</modExtensions>
</NeedDef>
</Defs>
</Defs>

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8" ?>
<Defs>
<StatDef>
<defName>WulaEnergyMaxLevelOffset</defName>
<label>乌拉能量上限偏移</label>
<description>影响乌拉族能量上限的偏移量。</description>
<category>PawnMisc</category>
<defaultBaseValue>0</defaultBaseValue>
<minValue>-1</minValue>
<maxValue>1</maxValue>
<toStringStyle>PercentZero</toStringStyle>
<displayPriorityInWithStatsUI>4000</displayPriorityInWithStatsUI>
</StatDef>
<StatDef>
<defName>WulaEnergyFallRateFactor</defName>
<label>乌拉能量消耗速度因子</label>
<description>影响乌拉族能量消耗速度的乘数因子。</description>
<category>PawnMisc</category>
<defaultBaseValue>1</defaultBaseValue>
<minValue>0</minValue>
<toStringStyle>PercentZero</toStringStyle>
<displayPriorityInWithStatsUI>3990</displayPriorityInWithStatsUI>
</StatDef>
</Defs>

View File

@@ -0,0 +1,62 @@
<?xml version="1.0" encoding="utf-8" ?>
<Defs>
<ThingDef ParentName="BodyPartBionicBase">
<defName>WULA_Energy_Regulator</defName>
<label>乌拉能量调节器</label>
<description>一个先进的乌拉植入物,能够微调宿主的能量系统,提高能量上限并降低能量消耗速度。</description>
<graphicData>
<texPath>Things/Item/Health/HealthItem</texPath>
<graphicClass>Graphic_Single</graphicClass>
</graphicData>
<statBases>
<MarketValue>1500</MarketValue>
<Mass>0.5</Mass>
</statBases>
<techLevel>Archotech</techLevel>
<recipeMaker>
<researchPrerequisite>WULA_New_Synth_Skill_Technology</researchPrerequisite>
<recipeUsers>
<li>WULA_Synth_Server</li>
</recipeUsers>
<skillRequirements>
<Crafting>10</Crafting>
</skillRequirements>
<workSpeedStat>GeneralLaborSpeed</workSpeedStat>
<workSkill>Crafting</workSkill>
<effectWorking>Smith</effectWorking>
<soundWorking>Recipe_Machining</soundWorking>
<displayPriority>650</displayPriority>
</recipeMaker>
<costList>
<Plasteel>50</Plasteel>
<ComponentSpacer>2</ComponentSpacer>
<WULA_Charge_Cube>5</WULA_Charge_Cube>
</costList>
<thingSetMakerTags>
<li>RewardStandardMidFreq</li>
</thingSetMakerTags>
<tradeTags>
<li>TechHediff</li>
</tradeTags>
</ThingDef>
<HediffDef ParentName="ImplantHediffBase">
<defName>WULA_Energy_Regulator_Implant</defName>
<label>乌拉能量调节器</label>
<description>已安装乌拉能量调节器。这提高了能量上限并降低了能量消耗速度。</description>
<spawnThingOnRemoved>WULA_Energy_Regulator</spawnThingOnRemoved>
<addedPartProps>
<partEfficiency>1.0</partEfficiency>
</addedPartProps>
<stages>
<li>
<statOffsets> <!-- StatOffset 是加法偏移量,正数增加,负数减少 -->
<WulaEnergyMaxLevelOffset>0.2</WulaEnergyMaxLevelOffset> <!-- 能量上限增加 0.2 -->
</statOffsets>
<statFactors> <!-- StatFactor 是乘法因子,小于 1.0 减少,大于 1.0 增加 -->
<WulaEnergyFallRateFactor>0.8</WulaEnergyFallRateFactor> <!-- 能量消耗速度变为原来的 80% -->
</statFactors>
</li>
</stages>
</HediffDef>
</Defs>

View File

@@ -14,10 +14,10 @@
<MarketValue>24</MarketValue>
<Mass>0.3</Mass>
<WorkToMake>450</WorkToMake>
<Nutrition>1</Nutrition>
<Nutrition>1</Nutrition> <!-- Reverted to 1 as per user request -->
</statBases>
<ingestible>
<preferability>MealSimple</preferability>
<preferability>MealSimple</preferability> <!-- Reverted to MealSimple as per user request -->
<optimalityOffsetHumanlikes>-1000</optimalityOffsetHumanlikes>
<optimalityOffsetFeedingAnimals>-1000</optimalityOffsetFeedingAnimals>
<ingestEffect>EatVegetarian</ingestEffect>
@@ -25,6 +25,11 @@
</ingestible>
<allowedArchonexusCount>200</allowedArchonexusCount>
<tradeability>None</tradeability>
<modExtensions>
<li Class="WulaFallenEmpire.ThingDefExtension_EnergySource">
<energyAmount>1.0</energyAmount> <!-- Amount of energy this item provides -->
</li>
</modExtensions>
</ThingDef>
<ThingDef ParentName="ResourceBase">
@@ -237,8 +242,12 @@
<showUseGizmo>true</showUseGizmo>
<userMustHaveHediff>Wula_Synth</userMustHaveHediff>
</li>
<li Class="CompProperties_UseEffect_LearnSkill">
<li Class="WulaFallenEmpire.CompProperties_UseEffect_WulaSkillTrainer">
<skill>Shooting</skill>
<learnAmount>100000</learnAmount>
<baseLossAmount>5000</baseLossAmount>
<noPassionLossFactor>2.0</noPassionLossFactor>
<minorPassionLossFactor>1.5</minorPassionLossFactor>
</li>
</comps>
</ThingDef>
@@ -252,8 +261,12 @@
<showUseGizmo>true</showUseGizmo>
<userMustHaveHediff>Wula_Synth</userMustHaveHediff>
</li>
<li Class="CompProperties_UseEffect_LearnSkill">
<li Class="WulaFallenEmpire.CompProperties_UseEffect_WulaSkillTrainer">
<skill>Melee</skill>
<learnAmount>100000</learnAmount>
<baseLossAmount>5000</baseLossAmount>
<noPassionLossFactor>2.0</noPassionLossFactor>
<minorPassionLossFactor>1.5</minorPassionLossFactor>
</li>
</comps>
</ThingDef>
@@ -267,8 +280,12 @@
<showUseGizmo>true</showUseGizmo>
<userMustHaveHediff>Wula_Synth</userMustHaveHediff>
</li>
<li Class="CompProperties_UseEffect_LearnSkill">
<li Class="WulaFallenEmpire.CompProperties_UseEffect_WulaSkillTrainer">
<skill>Animals</skill>
<learnAmount>100000</learnAmount>
<baseLossAmount>5000</baseLossAmount>
<noPassionLossFactor>2.0</noPassionLossFactor>
<minorPassionLossFactor>1.5</minorPassionLossFactor>
</li>
</comps>
</ThingDef>
@@ -282,8 +299,12 @@
<showUseGizmo>true</showUseGizmo>
<userMustHaveHediff>Wula_Synth</userMustHaveHediff>
</li>
<li Class="CompProperties_UseEffect_LearnSkill">
<li Class="WulaFallenEmpire.CompProperties_UseEffect_WulaSkillTrainer">
<skill>Artistic</skill>
<learnAmount>100000</learnAmount>
<baseLossAmount>5000</baseLossAmount>
<noPassionLossFactor>2.0</noPassionLossFactor>
<minorPassionLossFactor>1.5</minorPassionLossFactor>
</li>
</comps>
</ThingDef>
@@ -297,8 +318,12 @@
<showUseGizmo>true</showUseGizmo>
<userMustHaveHediff>Wula_Synth</userMustHaveHediff>
</li>
<li Class="CompProperties_UseEffect_LearnSkill">
<li Class="WulaFallenEmpire.CompProperties_UseEffect_WulaSkillTrainer">
<skill>Construction</skill>
<learnAmount>100000</learnAmount>
<baseLossAmount>5000</baseLossAmount>
<noPassionLossFactor>2.0</noPassionLossFactor>
<minorPassionLossFactor>1.5</minorPassionLossFactor>
</li>
</comps>
</ThingDef>
@@ -312,8 +337,12 @@
<showUseGizmo>true</showUseGizmo>
<userMustHaveHediff>Wula_Synth</userMustHaveHediff>
</li>
<li Class="CompProperties_UseEffect_LearnSkill">
<li Class="WulaFallenEmpire.CompProperties_UseEffect_WulaSkillTrainer">
<skill>Cooking</skill>
<learnAmount>100000</learnAmount>
<baseLossAmount>5000</baseLossAmount>
<noPassionLossFactor>2.0</noPassionLossFactor>
<minorPassionLossFactor>1.5</minorPassionLossFactor>
</li>
</comps>
</ThingDef>
@@ -327,8 +356,12 @@
<showUseGizmo>true</showUseGizmo>
<userMustHaveHediff>Wula_Synth</userMustHaveHediff>
</li>
<li Class="CompProperties_UseEffect_LearnSkill">
<li Class="WulaFallenEmpire.CompProperties_UseEffect_WulaSkillTrainer">
<skill>Crafting</skill>
<learnAmount>100000</learnAmount>
<baseLossAmount>5000</baseLossAmount>
<noPassionLossFactor>2.0</noPassionLossFactor>
<minorPassionLossFactor>1.5</minorPassionLossFactor>
</li>
</comps>
</ThingDef>
@@ -342,8 +375,12 @@
<showUseGizmo>true</showUseGizmo>
<userMustHaveHediff>Wula_Synth</userMustHaveHediff>
</li>
<li Class="CompProperties_UseEffect_LearnSkill">
<li Class="WulaFallenEmpire.CompProperties_UseEffect_WulaSkillTrainer">
<skill>Intellectual</skill>
<learnAmount>100000</learnAmount>
<baseLossAmount>5000</baseLossAmount>
<noPassionLossFactor>2.0</noPassionLossFactor>
<minorPassionLossFactor>1.5</minorPassionLossFactor>
</li>
</comps>
</ThingDef>
@@ -357,8 +394,12 @@
<showUseGizmo>true</showUseGizmo>
<userMustHaveHediff>Wula_Synth</userMustHaveHediff>
</li>
<li Class="CompProperties_UseEffect_LearnSkill">
<li Class="WulaFallenEmpire.CompProperties_UseEffect_WulaSkillTrainer">
<skill>Medicine</skill>
<learnAmount>100000</learnAmount>
<baseLossAmount>5000</baseLossAmount>
<noPassionLossFactor>2.0</noPassionLossFactor>
<minorPassionLossFactor>1.5</minorPassionLossFactor>
</li>
</comps>
</ThingDef>
@@ -372,8 +413,12 @@
<showUseGizmo>true</showUseGizmo>
<userMustHaveHediff>Wula_Synth</userMustHaveHediff>
</li>
<li Class="CompProperties_UseEffect_LearnSkill">
<li Class="WulaFallenEmpire.CompProperties_UseEffect_WulaSkillTrainer">
<skill>Mining</skill>
<learnAmount>100000</learnAmount>
<baseLossAmount>5000</baseLossAmount>
<noPassionLossFactor>2.0</noPassionLossFactor>
<minorPassionLossFactor>1.5</minorPassionLossFactor>
</li>
</comps>
</ThingDef>
@@ -387,8 +432,12 @@
<showUseGizmo>true</showUseGizmo>
<userMustHaveHediff>Wula_Synth</userMustHaveHediff>
</li>
<li Class="CompProperties_UseEffect_LearnSkill">
<li Class="WulaFallenEmpire.CompProperties_UseEffect_WulaSkillTrainer">
<skill>Plants</skill>
<learnAmount>100000</learnAmount>
<baseLossAmount>5000</baseLossAmount>
<noPassionLossFactor>2.0</noPassionLossFactor>
<minorPassionLossFactor>1.5</minorPassionLossFactor>
</li>
</comps>
</ThingDef>
@@ -402,9 +451,13 @@
<showUseGizmo>true</showUseGizmo>
<userMustHaveHediff>Wula_Synth</userMustHaveHediff>
</li>
<li Class="CompProperties_UseEffect_LearnSkill">
<li Class="WulaFallenEmpire.CompProperties_UseEffect_WulaSkillTrainer">
<skill>Social</skill>
<learnAmount>100000</learnAmount>
<baseLossAmount>5000</baseLossAmount>
<noPassionLossFactor>2.0</noPassionLossFactor>
<minorPassionLossFactor>1.5</minorPassionLossFactor>
</li>
</comps>
</ThingDef>
</Defs>
</Defs>

View File

@@ -52,4 +52,58 @@
</requiredCapacities>
<prioritizeSustains>true</prioritizeSustains>
</WorkGiverDef>
</Defs>
<WorkGiverDef>
<defName>FeedWulaPatient</defName>
<label>为机械乌拉补充能量</label>
<giverClass>WulaFallenEmpire.WorkGiver_FeedWulaPatient</giverClass>
<workType>Doctor</workType>
<priorityInType>100</priorityInType>
<verb>补充能量</verb>
<gerund>补充能量于</gerund>
<requiredCapacities>
<li>Manipulation</li>
</requiredCapacities>
<modExtensions>
<li Class="WulaFallenEmpire.WorkGiverDefExtension_FeedWula">
<energySourceDef>WULA_Charge_Cube</energySourceDef>
</li>
</modExtensions>
</WorkGiverDef>
<WorkGiverDef>
<defName>FeedWulaPrisoner</defName>
<label>为乌拉囚犯补充能量</label>
<giverClass>WulaFallenEmpire.WorkGiver_Warden_FeedWula</giverClass>
<workType>Warden</workType>
<priorityInType>100</priorityInType>
<verb>补充能量</verb>
<gerund>补充能量于</gerund>
<requiredCapacities>
<li>Manipulation</li>
</requiredCapacities>
<modExtensions>
<li Class="WulaFallenEmpire.WorkGiverDefExtension_FeedWula">
<energySourceDef>WULA_Charge_Cube</energySourceDef>
</li>
</modExtensions>
</WorkGiverDef>
<WorkGiverDef>
<defName>DeliverEnergyToWulaPrisoner</defName>
<label>为乌拉囚犯运送能量</label>
<giverClass>WulaFallenEmpire.WorkGiver_Warden_DeliverEnergy</giverClass>
<workType>Warden</workType>
<priorityInType>50</priorityInType>
<verb>运送能量</verb>
<gerund>运送能量于</gerund>
<requiredCapacities>
<li>Manipulation</li>
</requiredCapacities>
<modExtensions>
<li Class="WulaFallenEmpire.WorkGiverDefExtension_FeedWula">
<energySourceDef>WULA_Charge_Cube</energySourceDef>
</li>
</modExtensions>
</WorkGiverDef>
</Defs>

View File

@@ -2,21 +2,25 @@
"Version": 1,
"WorkspaceRootPath": "C:\\Steam\\steamapps\\common\\RimWorld\\Mods\\3516260226\\Source\\WulaFallenEmpire\\",
"Documents": [
{
"AbsoluteMoniker": "D:0:0:{F5AE8C3B-0221-4C16-A128-9A62D521A8FF}|WulaFallenEmpire.csproj|c:\\steam\\steamapps\\common\\rimworld\\mods\\3516260226\\source\\wulafallenempire\\ingestpatch.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{F5AE8C3B-0221-4C16-A128-9A62D521A8FF}|WulaFallenEmpire.csproj|solutionrelative:ingestpatch.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{F5AE8C3B-0221-4C16-A128-9A62D521A8FF}|WulaFallenEmpire.csproj|c:\\steam\\steamapps\\common\\rimworld\\mods\\3516260226\\source\\wulafallenempire\\hediffcomp_regeneratebackstory.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{F5AE8C3B-0221-4C16-A128-9A62D521A8FF}|WulaFallenEmpire.csproj|solutionrelative:hediffcomp_regeneratebackstory.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{F5AE8C3B-0221-4C16-A128-9A62D521A8FF}|WulaFallenEmpire.csproj|C:\\Steam\\steamapps\\common\\RimWorld\\Mods\\3516260226\\Source\\WulaFallenEmpire\\mechanitorpatch.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{F5AE8C3B-0221-4C16-A128-9A62D521A8FF}|WulaFallenEmpire.csproj|solutionrelative:mechanitorpatch.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{F5AE8C3B-0221-4C16-A128-9A62D521A8FF}|WulaFallenEmpire.csproj|C:\\Steam\\steamapps\\common\\RimWorld\\Mods\\3516260226\\Source\\WulaFallenEmpire\\wulafallenempiremod.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{F5AE8C3B-0221-4C16-A128-9A62D521A8FF}|WulaFallenEmpire.csproj|solutionrelative:wulafallenempiremod.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{F5AE8C3B-0221-4C16-A128-9A62D521A8FF}|WulaFallenEmpire.csproj|C:\\Steam\\steamapps\\common\\RimWorld\\Mods\\3516260226\\Source\\WulaFallenEmpire\\hediffcomp_regeneratebackstory.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{F5AE8C3B-0221-4C16-A128-9A62D521A8FF}|WulaFallenEmpire.csproj|solutionrelative:hediffcomp_regeneratebackstory.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{F5AE8C3B-0221-4C16-A128-9A62D521A8FF}|WulaFallenEmpire.csproj|C:\\Steam\\steamapps\\common\\RimWorld\\Mods\\3516260226\\Source\\WulaFallenEmpire\\building_wula_darkenergy_engine.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{F5AE8C3B-0221-4C16-A128-9A62D521A8FF}|WulaFallenEmpire.csproj|solutionrelative:building_wula_darkenergy_engine.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{F5AE8C3B-0221-4C16-A128-9A62D521A8FF}|WulaFallenEmpire.csproj|c:\\steam\\steamapps\\common\\rimworld\\mods\\3516260226\\source\\wulafallenempire\\mechanitorpatch.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{F5AE8C3B-0221-4C16-A128-9A62D521A8FF}|WulaFallenEmpire.csproj|solutionrelative:mechanitorpatch.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
}
],
"DocumentGroupContainers": [
@@ -26,8 +30,21 @@
"DocumentGroups": [
{
"DockedWidth": 200,
"SelectedChildIndex": 2,
"SelectedChildIndex": 0,
"Children": [
{
"$type": "Document",
"DocumentIndex": 0,
"Title": "IngestPatch.cs",
"DocumentMoniker": "C:\\Steam\\steamapps\\common\\RimWorld\\Mods\\3516260226\\Source\\WulaFallenEmpire\\IngestPatch.cs",
"RelativeDocumentMoniker": "IngestPatch.cs",
"ToolTip": "C:\\Steam\\steamapps\\common\\RimWorld\\Mods\\3516260226\\Source\\WulaFallenEmpire\\IngestPatch.cs",
"RelativeToolTip": "IngestPatch.cs",
"ViewState": "AQIAAAAAAAAAAAAAAADwvwoAAAAFAAAA",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-07-20T17:09:27.916Z",
"EditorCaption": ""
},
{
"$type": "Bookmark",
"Name": "ST:0:0:{1c4feeaa-4718-4aa9-859d-94ce25d182ba}"
@@ -47,7 +64,7 @@
},
{
"$type": "Document",
"DocumentIndex": 0,
"DocumentIndex": 3,
"Title": "WulaFallenEmpireMod.cs",
"DocumentMoniker": "C:\\Steam\\steamapps\\common\\RimWorld\\Mods\\3516260226\\Source\\WulaFallenEmpire\\WulaFallenEmpireMod.cs",
"RelativeDocumentMoniker": "WulaFallenEmpireMod.cs",
@@ -55,12 +72,15 @@
"RelativeToolTip": "WulaFallenEmpireMod.cs",
"ViewState": "AQIAAAAAAAAAAAAAAAAAABQAAAAAAAAA",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-07-18T10:23:17.898Z",
"EditorCaption": ""
"WhenOpened": "2025-07-18T10:23:17.898Z"
},
{
"$type": "Bookmark",
"Name": "ST:0:0:{269a02dc-6af8-11d3-bdc4-00c04f688e50}"
},
{
"$type": "Document",
"DocumentIndex": 3,
"DocumentIndex": 2,
"Title": "MechanitorPatch.cs",
"DocumentMoniker": "C:\\Steam\\steamapps\\common\\RimWorld\\Mods\\3516260226\\Source\\WulaFallenEmpire\\MechanitorPatch.cs",
"RelativeDocumentMoniker": "MechanitorPatch.cs",
@@ -68,12 +88,11 @@
"RelativeToolTip": "MechanitorPatch.cs",
"ViewState": "AQIAAAAAAAAAAAAAAAAAACEAAAAJAAAA",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-07-18T10:20:31.368Z",
"EditorCaption": ""
"WhenOpened": "2025-07-18T10:20:31.368Z"
},
{
"$type": "Document",
"DocumentIndex": 2,
"DocumentIndex": 4,
"Title": "Building_Wula_DarkEnergy_Engine.cs",
"DocumentMoniker": "C:\\Steam\\steamapps\\common\\RimWorld\\Mods\\3516260226\\Source\\WulaFallenEmpire\\Building_Wula_DarkEnergy_Engine.cs",
"RelativeDocumentMoniker": "Building_Wula_DarkEnergy_Engine.cs",
@@ -81,8 +100,7 @@
"RelativeToolTip": "Building_Wula_DarkEnergy_Engine.cs",
"ViewState": "AQIAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-07-14T12:24:18.86Z",
"EditorCaption": ""
"WhenOpened": "2025-07-14T12:24:18.86Z"
}
]
}

View File

@@ -0,0 +1,13 @@
{
"folders": [
{
"name": "3516260226",
"path": "../.."
},
{
"name": "Data",
"path": "../../../../Data"
}
],
"settings": {}
}

View File

@@ -0,0 +1,82 @@
using RimWorld;
using Verse;
using System.Collections.Generic;
namespace WulaFallenEmpire
{
public class CompProperties_UseEffect_WulaSkillTrainer : CompProperties_UseEffect
{
public SkillDef skill; // 目标技能
public float xpGainAmount = 50000f; // 目标技能学习量,默认值与原版一致
public float baseLossAmount; // 非目标技能基础减少量
public float noPassionLossFactor; // 无火技能减少乘数
public float minorPassionLossFactor; // 小火技能减少乘数
public CompProperties_UseEffect_WulaSkillTrainer()
{
compClass = typeof(CompUseEffect_WulaSkillTrainer);
}
}
public class CompUseEffect_WulaSkillTrainer : CompUseEffect
{
public CompProperties_UseEffect_WulaSkillTrainer Props => (CompProperties_UseEffect_WulaSkillTrainer)props;
public override void DoEffect(Pawn usedBy)
{
base.DoEffect(usedBy);
if (usedBy.skills == null)
{
return;
}
// 获取目标技能
SkillDef targetSkill = Props.skill;
// 遍历所有技能
foreach (SkillRecord skillRecord in usedBy.skills.skills)
{
if (skillRecord.def == targetSkill)
{
// 目标技能:增加经验
skillRecord.Learn(Props.xpGainAmount, true);
Messages.Message("WULA_SkillTrainer_TargetSkillGained".Translate(usedBy.LabelShort, skillRecord.def.label), usedBy, MessageTypeDefOf.PositiveEvent);
}
else
{
// 非目标技能:减少经验
float experienceLoss = Props.baseLossAmount;
if (skillRecord.passion == Passion.None)
{
experienceLoss *= Props.noPassionLossFactor;
}
else if (skillRecord.passion == Passion.Minor)
{
experienceLoss *= Props.minorPassionLossFactor;
}
// 大火的技能掉得最少,保持默认值
skillRecord.Learn(-experienceLoss, true); // 减少经验
Messages.Message("WULA_SkillTrainer_OtherSkillLost".Translate(usedBy.LabelShort, skillRecord.def.label), usedBy, MessageTypeDefOf.NegativeEvent);
}
}
}
public override bool CanBeUsedBy(Pawn p, out string failReason)
{
if (p.skills == null)
{
failReason = "PawnHasNoSkills".Translate(p.LabelShort);
return false;
}
if (Props.skill == null)
{
failReason = "SkillTrainerHasNoSkill".Translate(parent.LabelShort);
return false;
}
failReason = null;
return true;
}
}
}

View File

@@ -0,0 +1,76 @@
using HarmonyLib;
using RimWorld;
using Verse;
using System; // For Type
namespace WulaFallenEmpire
{
// Patch for WillEat(Pawn p, ThingDef food, ...)
[HarmonyPatch(typeof(FoodUtility), "WillEat", new Type[] { typeof(Pawn), typeof(ThingDef), typeof(Pawn), typeof(bool), typeof(bool) })]
public static class IngestPatch_ThingDef
{
[HarmonyPrefix]
public static bool Prefix(Pawn p, ThingDef food, ref bool __result)
{
// 检查是否是乌拉族
if (p.def.defName == "WulaSpecies")
{
// 检查食物是否是能量核心
ThingDefExtension_EnergySource ext = food.GetModExtension<ThingDefExtension_EnergySource>();
if (ext != null)
{
// 如果是乌拉族且是能量核心,则认为愿意吃
__result = true;
return false; // 跳过原版方法
}
}
return true; // 继续执行原版方法
}
}
// New Patch for WillEat(Pawn p, Thing food, ...)
[HarmonyPatch(typeof(FoodUtility), "WillEat", new Type[] { typeof(Pawn), typeof(Thing), typeof(Pawn), typeof(bool), typeof(bool) })]
public static class IngestPatch_Thing
{
[HarmonyPrefix]
public static bool Prefix(Pawn p, Thing food, ref bool __result)
{
// 检查是否是乌拉族
if (p.def.defName == "WulaSpecies")
{
// 检查食物是否是能量核心
ThingDefExtension_EnergySource ext = food.def.GetModExtension<ThingDefExtension_EnergySource>();
if (ext != null)
{
// 如果是乌拉族且是能量核心,则认为愿意吃
__result = true;
return false; // 跳过原版方法
}
}
return true; // 继续执行原版方法
}
}
// Patch for FoodUtility.FoodIsSuitable(Pawn p, ThingDef food)
[HarmonyPatch(typeof(FoodUtility), "FoodIsSuitable", new Type[] { typeof(Pawn), typeof(ThingDef) })]
public static class IngestPatch_FoodIsSuitable
{
[HarmonyPrefix]
public static bool Prefix(Pawn p, ThingDef food, ref bool __result)
{
// 检查是否是乌拉族
if (p.def.defName == "WulaSpecies")
{
// 检查食物是否是能量核心
ThingDefExtension_EnergySource ext = food.GetModExtension<ThingDefExtension_EnergySource>();
if (ext != null)
{
// 如果是乌拉族且是能量核心,则认为食物是合适的
__result = true;
return false; // 跳过原版方法
}
}
return true; // 继续执行原版方法
}
}
}

View File

@@ -0,0 +1,94 @@
using System.Collections.Generic;
using UnityEngine;
using Verse;
using Verse.AI;
using RimWorld;
namespace WulaFallenEmpire
{
public class JobDriver_FeedWulaPatient : JobDriver
{
private const TargetIndex FoodSourceInd = TargetIndex.A;
private const TargetIndex PatientInd = TargetIndex.B;
private Thing FoodSource => job.GetTarget(FoodSourceInd).Thing;
private Pawn Patient => (Pawn)job.GetTarget(PatientInd).Thing;
public override bool TryMakePreToilReservations(bool errorOnFailed)
{
// 预留食物来源和病患
if (!pawn.Reserve(FoodSource, job, 1, -1, null, errorOnFailed))
{
return false;
}
if (!pawn.Reserve(Patient, job, 1, -1, null, errorOnFailed))
{
return false;
}
return true;
}
protected override IEnumerable<Toil> MakeNewToils()
{
// 失败条件:如果食物来源或病患被摧毁、为空或被禁止
this.FailOn(() => FoodSource.DestroyedOrNull() || !FoodSource.IngestibleNow);
this.FailOn(() => Patient.DestroyedOrNull());
this.FailOn(() => !Patient.InBed()); // 确保病患在床上
// Toil 1: 前往食物来源
yield return Toils_Goto.GotoThing(FoodSourceInd, PathEndMode.ClosestTouch)
.FailOnDespawnedNullOrForbidden(FoodSourceInd);
// Toil 2: 拾取食物来源
yield return Toils_Haul.StartCarryThing(FoodSourceInd); // 使用 StartCarryThing 拾取物品
// Toil 3: 前往病患
yield return Toils_Goto.GotoThing(PatientInd, PathEndMode.Touch)
.FailOnDespawnedOrNull(PatientInd);
// Toil 4: 喂食病患
Toil feedToil = ToilMaker.MakeToil("FeedWulaPatient");
feedToil.initAction = delegate
{
Pawn actor = feedToil.actor;
Thing food = actor.carryTracker.CarriedThing; // 医生携带的食物
if (food == null)
{
actor.jobs.EndCurrentJob(JobCondition.Incompletable);
return;
}
// 获取乌拉能量需求
Need_WulaEnergy energyNeed = Patient.needs.TryGetNeed<Need_WulaEnergy>();
if (energyNeed == null)
{
actor.jobs.EndCurrentJob(JobCondition.Errored);
return;
}
// 检查食物来源是否有自定义能量扩展
ThingDefExtension_EnergySource ext = food.def.GetModExtension<ThingDefExtension_EnergySource>();
if (ext == null)
{
actor.jobs.EndCurrentJob(JobCondition.Errored);
return;
}
// 补充乌拉的能量
energyNeed.CurLevel += ext.energyAmount;
// 消耗物品
food.Destroy(DestroyMode.Vanish); // 销毁医生携带的物品
// 移除医生携带的物品
actor.carryTracker.innerContainer.ClearAndDestroyContents();
// 记录能量摄入 (可选)
// Patient.records.AddTo(RecordDefOf.NutritionEaten, ext.energyAmount);
};
feedToil.defaultCompleteMode = ToilCompleteMode.Instant;
yield return feedToil;
}
}
}

View File

@@ -0,0 +1,97 @@
using System.Collections.Generic;
using System.Linq; // Added for FirstOrDefault
using UnityEngine;
using Verse;
using Verse.AI;
using RimWorld; // For ThingDefOf, StatDefOf, etc.
namespace WulaFallenEmpire
{
public class JobDriver_IngestWulaEnergy : JobDriver
{
private const TargetIndex IngestibleSourceInd = TargetIndex.A;
private Thing IngestibleSource => job.GetTarget(IngestibleSourceInd).Thing;
public override bool TryMakePreToilReservations(bool errorOnFailed)
{
// 尝试预留能量核心
if (pawn.Faction != null)
{
Thing ingestibleSource = IngestibleSource;
int maxAmountToPickup = FoodUtility.GetMaxAmountToPickup(ingestibleSource, pawn, job.count);
if (!pawn.Reserve(ingestibleSource, job, 10, maxAmountToPickup, null, errorOnFailed))
{
return false;
}
job.count = maxAmountToPickup; // 更新job.count以匹配实际预留数量
}
return true;
}
protected override IEnumerable<Toil> MakeNewToils()
{
// 失败条件:如果能量核心被摧毁、为空或被禁止
this.FailOn(() => IngestibleSource.DestroyedOrNull() || !IngestibleSource.IngestibleNow);
// Toil 1: 前往能量核心
yield return Toils_Goto.GotoThing(IngestibleSourceInd, PathEndMode.ClosestTouch)
.FailOnDespawnedNullOrForbidden(IngestibleSourceInd);
// Toil 2: 拾取能量核心并放入carryTracker
yield return Toils_Haul.StartCarryThing(IngestibleSourceInd);
// Toil 3: “摄取”能量核心 (模拟咀嚼过程,可以是一个简单的延迟)
Toil chewToil = ToilMaker.MakeToil("ChewWulaEnergy");
chewToil.initAction = delegate
{
// 设定一个短暂的“咀嚼”时间
pawn.jobs.curDriver.ticksLeftThisToil = 60; // 1秒
};
chewToil.defaultCompleteMode = ToilCompleteMode.Delay;
yield return chewToil;
// Toil 4: 最终处理能量摄取
Toil finalizeToil = ToilMaker.MakeToil("FinalizeWulaEnergyIngest");
finalizeToil.initAction = delegate
{
Pawn actor = finalizeToil.actor;
// 从Pawn的carryTracker中获取能量核心
Thing thing = actor.carryTracker.CarriedThing;
if (thing == null)
{
actor.jobs.EndCurrentJob(JobCondition.Incompletable);
return;
}
// 获取乌拉能量需求
Need_WulaEnergy energyNeed = actor.needs.TryGetNeed<Need_WulaEnergy>();
if (energyNeed == null)
{
actor.jobs.EndCurrentJob(JobCondition.Errored);
return;
}
// 检查食物来源是否有自定义能量扩展
ThingDefExtension_EnergySource ext = thing.def.GetModExtension<ThingDefExtension_EnergySource>();
if (ext == null)
{
actor.jobs.EndCurrentJob(JobCondition.Errored);
return;
}
// 补充乌拉的能量
energyNeed.CurLevel += ext.energyAmount;
// 消耗物品
thing.Destroy(DestroyMode.Vanish);
// 记录能量摄入 (可选,如果需要类似 NutritionEaten 的记录)
// actor.records.AddTo(RecordDefOf.NutritionEaten, ext.energyAmount);
};
finalizeToil.defaultCompleteMode = ToilCompleteMode.Instant;
yield return finalizeToil;
}
}
}

View File

@@ -0,0 +1,14 @@
using Verse;
namespace WulaFallenEmpire
{
public class NeedDefExtension_Energy : DefModExtension
{
// 能量每天的消耗值
public float fallPerDay = 1.6f;
// 能量上限
public float maxLevel = 1.0f;
// 运送能量的阈值
public float deliverEnergyThreshold = 0.5f;
}
}

View File

@@ -0,0 +1,112 @@
using RimWorld;
using UnityEngine;
using Verse;
using WulaFallenEmpire;
namespace WulaFallenEmpire
{
public class Need_WulaEnergy : Need
{
private NeedDefExtension_Energy ext;
private NeedDefExtension_Energy Ext
{
get
{
if (ext == null)
{
if (def == null)
{
return null;
}
ext = def.GetModExtension<NeedDefExtension_Energy>();
}
return ext;
}
}
private float EnergyFallPerTick
{
get
{
if (Ext != null)
{
// 从XML读取每天消耗值并转换为每tick消耗值并应用StatDef因子
return (Ext.fallPerDay / 60000f) * pawn.GetStatValue(WulaStatDefOf.WulaEnergyFallRateFactor);
}
// 如果XML中没有定义则使用一个默认值
return 2.6666667E-05f;
}
}
public bool IsShutdown => CurLevel <= 0.01f;
public override int GUIChangeArrow
{
get
{
if (IsFrozen) return 0;
return -1;
}
}
public override float MaxLevel
{
get
{
if (Ext != null)
{
// 应用StatDef偏移量
return Ext.maxLevel + pawn.GetStatValue(WulaStatDefOf.WulaEnergyMaxLevelOffset);
}
return 1f;
}
}
public Need_WulaEnergy(Pawn pawn) : base(pawn)
{
}
public override void NeedInterval()
{
if (!IsFrozen)
{
CurLevel -= EnergyFallPerTick * 150f;
}
if (IsShutdown)
{
HealthUtility.AdjustSeverity(pawn, HediffDef.Named("WULA_Shutdown"), 0.05f);
}
else
{
Hediff hediff = pawn.health.hediffSet.GetFirstHediffOfDef(HediffDef.Named("WULA_Shutdown"));
if (hediff != null)
{
pawn.health.RemoveHediff(hediff);
}
}
}
public override void SetInitialLevel()
{
CurLevelPercentage = 1.0f;
}
public override string GetTipString()
{
return (LabelCap + ": " + CurLevelPercentage.ToStringPercent()).Colorize(ColoredText.TipSectionTitleColor) + "\n" +
def.description;
}
public override void DrawOnGUI(Rect rect, int maxThresholdMarkers = int.MaxValue, float customMargin = -1f, bool drawArrows = true, bool doTooltip = true, Rect? rectForTooltip = null, bool drawLabel = true)
{
if (threshPercents == null)
{
threshPercents = new System.Collections.Generic.List<float>();
}
threshPercents.Clear();
base.DrawOnGUI(rect, maxThresholdMarkers, customMargin, drawArrows, doTooltip, rectForTooltip, drawLabel);
}
}
}

View File

@@ -0,0 +1,9 @@
using Verse;
namespace WulaFallenEmpire
{
public class ThingDefExtension_EnergySource : DefModExtension
{
public float energyAmount = 1.0f; // Amount of energy this item provides
}
}

View File

@@ -0,0 +1,10 @@
using Verse;
namespace WulaFallenEmpire
{
public class WorkGiverDefExtension_FeedWula : DefModExtension
{
// The ThingDef of the item to be used as energy source.
public ThingDef energySourceDef;
}
}

View File

@@ -0,0 +1,127 @@
using RimWorld;
using System.Collections.Generic;
using System.Linq;
using Verse;
using Verse.AI;
namespace WulaFallenEmpire
{
public class WorkGiver_FeedWulaPatient : WorkGiver_Scanner
{
private WorkGiverDefExtension_FeedWula ext;
private WorkGiverDefExtension_FeedWula Ext
{
get
{
if (ext == null)
{
ext = def.GetModExtension<WorkGiverDefExtension_FeedWula>();
}
return ext;
}
}
public override ThingRequest PotentialWorkThingRequest => ThingRequest.ForDef(ThingDef.Named("WulaSpecies"));
public override PathEndMode PathEndMode => PathEndMode.ClosestTouch;
public override Danger MaxPathDanger(Pawn pawn) => Danger.Deadly;
public override IEnumerable<Thing> PotentialWorkThingsGlobal(Pawn pawn)
{
// Mimic vanilla: Scan all pawns in bed.
return pawn.Map.mapPawns.AllPawns.Where(p => p.InBed());
}
public override bool HasJobOnThing(Pawn pawn, Thing t, bool forced = false)
{
Pawn patient = t as Pawn;
// Basic validation, similar to vanilla
if (patient == null || patient == pawn || !patient.InBed() || patient.def.defName != "WulaSpecies")
{
return false;
}
// Our custom check: Is the Wula in shutdown?
Need_WulaEnergy energyNeed = patient.needs.TryGetNeed<Need_WulaEnergy>();
if (energyNeed == null || !energyNeed.IsShutdown)
{
return false;
}
// CRITICAL vanilla check: If the patient is a prisoner, this is a warden's job, not a doctor's.
// This prevents conflicts between two different work types trying to do the same thing.
if (WardenFeedUtility.ShouldBeFed(patient))
{
return false;
}
// CRITICAL vanilla check: Can the doctor reserve the patient?
// This prevents multiple doctors from trying to feed the same patient at the same time.
if (!pawn.CanReserve(patient, 1, -1, null, forced))
{
return false;
}
// Check for our energy source
if (Ext == null || Ext.energySourceDef == null)
{
Log.ErrorOnce("WorkGiver_FeedWulaPatient is missing the DefModExtension with a valid energySourceDef.", def.GetHashCode());
return false;
}
if (!FindBestEnergySourceFor(pawn, patient, out _, out _))
{
// Mimic vanilla: Provide a reason for failure.
JobFailReason.Is("NoFood".Translate()); // Using vanilla translation key for simplicity
return false;
}
return true;
}
public override Job JobOnThing(Pawn pawn, Thing t, bool forced = false)
{
Pawn patient = (Pawn)t;
if (FindBestEnergySourceFor(pawn, patient, out Thing energySource, out _))
{
Job job = JobMaker.MakeJob(DefDatabase<JobDef>.GetNamed("WULA_FeedWulaPatient"), energySource, patient);
job.count = 1; // Energy cores are single-use.
return job;
}
return null;
}
private bool FindBestEnergySourceFor(Pawn getter, Pawn eater, out Thing foodSource, out ThingDef foodDef)
{
foodSource = null;
foodDef = null;
if (Ext == null || Ext.energySourceDef == null)
{
return false;
}
// CRITICAL vanilla check is embedded here: CanReserve(x) on the food source itself.
foodSource = GenClosest.ClosestThingReachable(
getter.Position,
getter.Map,
ThingRequest.ForDef(Ext.energySourceDef),
PathEndMode.OnCell,
TraverseParms.For(getter),
9999f,
(Thing x) => !x.IsForbidden(getter) && getter.CanReserve(x)
);
if (foodSource != null)
{
foodDef = foodSource.def;
return true;
}
return false;
}
}
}

View File

@@ -0,0 +1,119 @@
using RimWorld;
using Verse;
using Verse.AI;
namespace WulaFallenEmpire
{
public class WorkGiver_Warden_DeliverEnergy : WorkGiver_Scanner
{
private WorkGiverDefExtension_FeedWula ext;
private WorkGiverDefExtension_FeedWula Ext
{
get
{
if (ext == null)
{
ext = def.GetModExtension<WorkGiverDefExtension_FeedWula>();
}
return ext;
}
}
public override ThingRequest PotentialWorkThingRequest => ThingRequest.ForDef(ThingDef.Named("WulaSpecies"));
public override PathEndMode PathEndMode => PathEndMode.ClosestTouch;
public override Danger MaxPathDanger(Pawn pawn) => Danger.Deadly;
public override bool HasJobOnThing(Pawn pawn, Thing t, bool forced = false)
{
Pawn prisoner = t as Pawn;
if (prisoner == null || prisoner == pawn || !prisoner.IsPrisonerOfColony || !prisoner.guest.CanBeBroughtFood)
{
return false;
}
Need_WulaEnergy energyNeed = prisoner.needs.TryGetNeed<Need_WulaEnergy>();
if (energyNeed == null)
{
return false;
}
NeedDefExtension_Energy ext = energyNeed.def.GetModExtension<NeedDefExtension_Energy>();
float threshold = (ext != null) ? ext.deliverEnergyThreshold : 0.5f;
if (energyNeed.CurLevelPercentage > threshold)
{
return false;
}
if (WardenFeedUtility.ShouldBeFed(prisoner))
{
return false;
}
if (!pawn.CanReserve(prisoner, 1, -1, null, forced))
{
return false;
}
if (Ext == null || Ext.energySourceDef == null)
{
Log.ErrorOnce("WorkGiver_Warden_DeliverEnergy is missing the DefModExtension with a valid energySourceDef.", def.GetHashCode());
return false;
}
if (!FindBestEnergySourceFor(pawn, prisoner, out _, out _))
{
JobFailReason.Is("NoFood".Translate());
return false;
}
return true;
}
public override Job JobOnThing(Pawn pawn, Thing t, bool forced = false)
{
Pawn prisoner = (Pawn)t;
if (FindBestEnergySourceFor(pawn, prisoner, out Thing energySource, out _))
{
Job job = JobMaker.MakeJob(JobDefOf.DeliverFood, energySource, prisoner);
job.count = 1;
job.targetC = RCellFinder.SpotToChewStandingNear(prisoner, energySource);
return job;
}
return null;
}
private bool FindBestEnergySourceFor(Pawn getter, Pawn eater, out Thing foodSource, out ThingDef foodDef)
{
foodSource = null;
foodDef = null;
if (Ext == null || Ext.energySourceDef == null)
{
return false;
}
foodSource = GenClosest.ClosestThingReachable(
getter.Position,
getter.Map,
ThingRequest.ForDef(Ext.energySourceDef),
PathEndMode.OnCell,
TraverseParms.For(getter),
9999f,
(Thing x) => !x.IsForbidden(getter) && getter.CanReserve(x) && x.GetRoom() != eater.GetRoom()
);
if (foodSource != null)
{
foodDef = foodSource.def;
return true;
}
return false;
}
}
}

View File

@@ -0,0 +1,115 @@
using RimWorld;
using Verse;
using Verse.AI;
namespace WulaFallenEmpire
{
public class WorkGiver_Warden_FeedWula : WorkGiver_Scanner
{
private WorkGiverDefExtension_FeedWula ext;
private WorkGiverDefExtension_FeedWula Ext
{
get
{
if (ext == null)
{
ext = def.GetModExtension<WorkGiverDefExtension_FeedWula>();
}
return ext;
}
}
public override ThingRequest PotentialWorkThingRequest => ThingRequest.ForDef(ThingDef.Named("WulaSpecies"));
public override PathEndMode PathEndMode => PathEndMode.ClosestTouch;
public override Danger MaxPathDanger(Pawn pawn) => Danger.Deadly;
public override bool HasJobOnThing(Pawn pawn, Thing t, bool forced = false)
{
Pawn prisoner = t as Pawn;
// Basic validation, similar to vanilla's WorkGiver_Warden_Feed
if (prisoner == null || prisoner == pawn || !prisoner.IsPrisonerOfColony || !prisoner.guest.CanBeBroughtFood)
{
return false;
}
// Our custom check: Is the Wula in shutdown?
Need_WulaEnergy energyNeed = prisoner.needs.TryGetNeed<Need_WulaEnergy>();
if (energyNeed == null || !energyNeed.IsShutdown)
{
return false;
}
// Vanilla check: Is the prisoner unable to feed themselves?
if (!WardenFeedUtility.ShouldBeFed(prisoner))
{
return false;
}
// CRITICAL vanilla check: Can the warden reserve the prisoner?
if (!pawn.CanReserve(prisoner, 1, -1, null, forced))
{
return false;
}
// Check for our energy source
if (Ext == null || Ext.energySourceDef == null)
{
Log.ErrorOnce("WorkGiver_Warden_FeedWula is missing the DefModExtension with a valid energySourceDef.", def.GetHashCode());
return false;
}
if (!FindBestEnergySourceFor(pawn, prisoner, out _, out _))
{
JobFailReason.Is("NoFood".Translate());
return false;
}
return true;
}
public override Job JobOnThing(Pawn pawn, Thing t, bool forced = false)
{
Pawn prisoner = (Pawn)t;
if (FindBestEnergySourceFor(pawn, prisoner, out Thing energySource, out _))
{
Job job = JobMaker.MakeJob(DefDatabase<JobDef>.GetNamed("WULA_FeedWulaPatient"), energySource, prisoner);
job.count = 1;
return job;
}
return null;
}
private bool FindBestEnergySourceFor(Pawn getter, Pawn eater, out Thing foodSource, out ThingDef foodDef)
{
foodSource = null;
foodDef = null;
if (Ext == null || Ext.energySourceDef == null)
{
return false;
}
foodSource = GenClosest.ClosestThingReachable(
getter.Position,
getter.Map,
ThingRequest.ForDef(Ext.energySourceDef),
PathEndMode.OnCell,
TraverseParms.For(getter),
9999f,
(Thing x) => !x.IsForbidden(getter) && getter.CanReserve(x)
);
if (foodSource != null)
{
foodDef = foodSource.def;
return true;
}
return false;
}
}
}

View File

@@ -63,6 +63,18 @@
<Compile Include="SectionLayer_WulaHull.cs" />
<Compile Include="HediffComp_RegenerateBackstory.cs" />
<Compile Include="WulaFallenEmpireMod.cs" />
<Compile Include="Need_WulaEnergy.cs" />
<Compile Include="NeedDefExtension_Energy.cs" />
<Compile Include="WorkGiver_FeedWulaPatient.cs" />
<Compile Include="WorkGiverDefExtension_FeedWula.cs" />
<Compile Include="WorkGiver_Warden_FeedWula.cs" />
<Compile Include="WorkGiver_Warden_DeliverEnergy.cs" />
<Compile Include="ThingDefExtension_EnergySource.cs" />
<Compile Include="IngestPatch.cs" />
<Compile Include="JobDriver_IngestWulaEnergy.cs" />
<Compile Include="JobDriver_FeedWulaPatient.cs" />
<Compile Include="WulaStatDefOf.cs" />
<Compile Include="CompUseEffect_WulaSkillTrainer.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
</Project>

View File

@@ -0,0 +1,17 @@
using RimWorld;
using Verse;
namespace WulaFallenEmpire
{
[DefOf]
public static class WulaStatDefOf
{
public static StatDef WulaEnergyMaxLevelOffset;
public static StatDef WulaEnergyFallRateFactor;
static WulaStatDefOf()
{
DefOfHelper.EnsureInitializedInCtor(typeof(WulaStatDefOf));
}
}
}

View File

@@ -1 +1 @@
99a3c2951cfdb2c80824a2ef162fb4d1d7e171804b475e1531b6d8327f9829ec
981fae8ea86dc7ccc506adb49b6855ce4c202ff9e230c7a6c385d9789ef4b0aa