暂存能量改动

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

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