考察任务
This commit is contained in:
221
Source/WulaFallenEmpire/QuestNodes/QuestNode_AddInspectionJob.cs
Normal file
221
Source/WulaFallenEmpire/QuestNodes/QuestNode_AddInspectionJob.cs
Normal file
@@ -0,0 +1,221 @@
|
||||
using RimWorld;
|
||||
using RimWorld.QuestGen;
|
||||
using Verse;
|
||||
using Verse.AI;
|
||||
|
||||
namespace WulaFallenEmpire
|
||||
{
|
||||
public class QuestNode_AddInspectionJob : QuestNode
|
||||
{
|
||||
public SlateRef<Pawn> pawn; // 直接接收 Pawn 对象
|
||||
|
||||
public SlateRef<JobDef> inspectionJobDef; // 考察工作定义
|
||||
public SlateRef<float> inspectionDuration; // 考察停留时间(秒)
|
||||
public SlateRef<bool> requirePlayerOwned; // 是否要求玩家拥有
|
||||
public SlateRef<bool> requireAccessible; // 是否要求可到达
|
||||
|
||||
protected override bool TestRunInt(Slate slate)
|
||||
{
|
||||
if (inspectionJobDef.GetValue(slate) == null)
|
||||
{
|
||||
Log.Error("[QuestNode_AddInspectionJob] inspectionJobDef is null");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override void RunInt()
|
||||
{
|
||||
Slate slate = QuestGen.slate;
|
||||
|
||||
// 直接获取 Pawn 对象
|
||||
Pawn pawnValue = pawn.GetValue(slate);
|
||||
if (pawnValue == null)
|
||||
{
|
||||
Log.Error("[QuestNode_AddInspectionJob] pawn is null");
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查 Pawn 是否有效且已生成
|
||||
if (!IsPawnValidAndSpawned(pawnValue))
|
||||
{
|
||||
// 如果 Pawn 无效或未生成,记录调试信息但不报错
|
||||
if (QuestGen.slate.Get<bool>("debugLogging", false))
|
||||
{
|
||||
Log.Message($"[QuestNode_AddInspectionJob] Pawn {pawnValue.Name} is not ready for job assignment (Destroyed: {pawnValue.Destroyed}, Spawned: {pawnValue.Spawned}, Map: {pawnValue.Map?.Index ?? -1})");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取工作定义
|
||||
JobDef jobDef = inspectionJobDef.GetValue(slate) ?? JobDefOf.Wait;
|
||||
|
||||
// 创建并分配工作
|
||||
Job job = CreateInspectionJob(pawnValue, jobDef, slate);
|
||||
if (job != null)
|
||||
{
|
||||
pawnValue.jobs.TryTakeOrderedJob(job, JobTag.Misc);
|
||||
|
||||
if (QuestGen.slate.Get<bool>("debugLogging", false))
|
||||
{
|
||||
Log.Message($"[QuestNode_AddInspectionJob] Assigned inspection job to {pawnValue.Name} at position {pawnValue.Position}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (QuestGen.slate.Get<bool>("debugLogging", false))
|
||||
{
|
||||
Log.Message($"[QuestNode_AddInspectionJob] Failed to create inspection job for {pawnValue.Name}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检查 Pawn 是否有效且已生成
|
||||
/// </summary>
|
||||
private bool IsPawnValidAndSpawned(Pawn pawn)
|
||||
{
|
||||
if (pawn == null || pawn.Destroyed)
|
||||
return false;
|
||||
|
||||
if (!pawn.Spawned)
|
||||
return false;
|
||||
|
||||
if (pawn.Map == null)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建考察工作
|
||||
/// </summary>
|
||||
private Job CreateInspectionJob(Pawn pawn, JobDef jobDef, Slate slate)
|
||||
{
|
||||
// 寻找合适的考察目标
|
||||
Thing inspectionTarget = FindInspectionTarget(pawn, slate);
|
||||
if (inspectionTarget == null)
|
||||
{
|
||||
if (QuestGen.slate.Get<bool>("debugLogging", false))
|
||||
{
|
||||
Log.Message($"[QuestNode_AddInspectionJob] No valid inspection target found for {pawn.Name} on map {pawn.Map}");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// 创建工作
|
||||
Job job = JobMaker.MakeJob(jobDef, inspectionTarget);
|
||||
|
||||
// 设置停留时间(转换为 ticks)
|
||||
float duration = inspectionDuration.GetValue(slate);
|
||||
if (duration > 0)
|
||||
{
|
||||
job.expiryInterval = (int)(duration * 60f); // 秒转换为 ticks
|
||||
}
|
||||
else
|
||||
{
|
||||
job.expiryInterval = Rand.Range(180, 300); // 3-5 秒的随机时间
|
||||
}
|
||||
|
||||
// 设置工作标签
|
||||
job.def.joyDuration = job.expiryInterval;
|
||||
|
||||
if (QuestGen.slate.Get<bool>("debugLogging", false))
|
||||
{
|
||||
Log.Message($"[QuestNode_AddInspectionJob] Created inspection job for {pawn.Name} at {inspectionTarget.Label} (Position: {inspectionTarget.Position})");
|
||||
}
|
||||
|
||||
return job;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 寻找考察目标
|
||||
/// </summary>
|
||||
private Thing FindInspectionTarget(Pawn pawn, Slate slate)
|
||||
{
|
||||
bool requirePlayerOwnedValue = requirePlayerOwned.GetValue(slate);
|
||||
bool requireAccessibleValue = requireAccessible.GetValue(slate);
|
||||
|
||||
if (QuestGen.slate.Get<bool>("debugLogging", false))
|
||||
{
|
||||
Log.Message($"[QuestNode_AddInspectionJob] Searching for inspection target for {pawn.Name}");
|
||||
Log.Message($"[QuestNode_AddInspectionJob] Require player owned: {requirePlayerOwnedValue}, Require accessible: {requireAccessibleValue}");
|
||||
}
|
||||
|
||||
// 寻找玩家拥有的建筑
|
||||
Thing target = GenClosest.ClosestThingReachable(
|
||||
pawn.Position,
|
||||
pawn.Map,
|
||||
ThingRequest.ForGroup(ThingRequestGroup.BuildingArtificial),
|
||||
PathEndMode.Touch,
|
||||
TraverseParms.For(pawn),
|
||||
maxDistance: 50f,
|
||||
validator: (Thing t) => IsValidInspectionTarget(t, pawn, requirePlayerOwnedValue, requireAccessibleValue)
|
||||
);
|
||||
|
||||
if (QuestGen.slate.Get<bool>("debugLogging", false))
|
||||
{
|
||||
if (target != null)
|
||||
{
|
||||
Log.Message($"[QuestNode_AddInspectionJob] Found target: {target.Label} at {target.Position}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Message($"[QuestNode_AddInspectionJob] No target found within range");
|
||||
}
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检查是否有效的考察目标
|
||||
/// </summary>
|
||||
private bool IsValidInspectionTarget(Thing thing, Pawn pawn, bool requirePlayerOwned, bool requireAccessible)
|
||||
{
|
||||
// 基本检查
|
||||
if (thing == null || thing.Destroyed)
|
||||
return false;
|
||||
|
||||
// 检查是否玩家拥有
|
||||
if (requirePlayerOwned && thing.Faction != Faction.OfPlayer)
|
||||
{
|
||||
if (QuestGen.slate.Get<bool>("debugLogging", false) && thing.Faction != null)
|
||||
{
|
||||
Log.Message($"[QuestNode_AddInspectionJob] Target {thing.Label} faction: {thing.Faction.Name}, required: Player");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查是否可到达
|
||||
if (requireAccessible && !pawn.CanReach(thing, PathEndMode.Touch, Danger.None))
|
||||
{
|
||||
if (QuestGen.slate.Get<bool>("debugLogging", false))
|
||||
{
|
||||
Log.Message($"[QuestNode_AddInspectionJob] Target {thing.Label} at {thing.Position} is not reachable by {pawn.Name}");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 排除一些不适合的建筑类型
|
||||
if (thing.def.IsFrame || thing.def.IsBlueprint)
|
||||
return false;
|
||||
|
||||
// 确保建筑是完整的
|
||||
if (thing is Building building && (building.IsBurning() || building.IsBrokenDown()))
|
||||
return false;
|
||||
|
||||
// 确保不是禁止进入的区域
|
||||
if (thing.IsForbidden(pawn))
|
||||
return false;
|
||||
|
||||
if (QuestGen.slate.Get<bool>("debugLogging", false))
|
||||
{
|
||||
Log.Message($"[QuestNode_AddInspectionJob] Target {thing.Label} at {thing.Position} is valid");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,194 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using RimWorld;
|
||||
using RimWorld.Planet;
|
||||
using RimWorld.QuestGen;
|
||||
using Verse;
|
||||
|
||||
namespace WulaFallenEmpire
|
||||
{
|
||||
public class QuestNode_GeneratePawnWithCustomization : QuestNode
|
||||
{
|
||||
[NoTranslate]
|
||||
public SlateRef<string> storeAs;
|
||||
|
||||
[NoTranslate]
|
||||
public SlateRef<string> addToList;
|
||||
|
||||
[NoTranslate]
|
||||
public SlateRef<IEnumerable<string>> addToLists;
|
||||
|
||||
public SlateRef<PawnKindDef> kindDef;
|
||||
|
||||
public SlateRef<Faction> faction;
|
||||
|
||||
public SlateRef<bool> forbidAnyTitle;
|
||||
|
||||
public SlateRef<bool> ensureNonNumericName;
|
||||
|
||||
public SlateRef<IEnumerable<TraitDef>> forcedTraits;
|
||||
|
||||
public SlateRef<IEnumerable<TraitDef>> prohibitedTraits;
|
||||
|
||||
public SlateRef<Pawn> extraPawnForExtraRelationChance;
|
||||
|
||||
public SlateRef<float> relationWithExtraPawnChanceFactor;
|
||||
|
||||
public SlateRef<bool?> allowAddictions;
|
||||
|
||||
public SlateRef<float> biocodeWeaponChance;
|
||||
|
||||
public SlateRef<float> biocodeApparelChance;
|
||||
|
||||
public SlateRef<bool> mustBeCapableOfViolence;
|
||||
|
||||
public SlateRef<bool> isChild;
|
||||
|
||||
public SlateRef<bool> allowPregnant;
|
||||
|
||||
public SlateRef<Gender?> fixedGender;
|
||||
|
||||
public SlateRef<bool> giveDependentDrugs;
|
||||
|
||||
// 只保留自定义背景故事功能
|
||||
public SlateRef<BackstoryDef> childhoodBackstory;
|
||||
public SlateRef<BackstoryDef> adulthoodBackstory;
|
||||
public SlateRef<bool> useCustomBackstories;
|
||||
|
||||
private const int MinExpertSkill = 11;
|
||||
|
||||
protected override bool TestRunInt(Slate slate)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
protected virtual DevelopmentalStage GetDevelopmentalStage(Slate slate)
|
||||
{
|
||||
if (!Find.Storyteller.difficulty.ChildrenAllowed || !isChild.GetValue(slate))
|
||||
{
|
||||
return DevelopmentalStage.Adult;
|
||||
}
|
||||
return DevelopmentalStage.Child;
|
||||
}
|
||||
|
||||
protected override void RunInt()
|
||||
{
|
||||
Slate slate = QuestGen.slate;
|
||||
PawnKindDef value = kindDef.GetValue(slate);
|
||||
Faction value2 = faction.GetValue(slate);
|
||||
bool flag = allowAddictions.GetValue(slate) ?? true;
|
||||
bool value3 = allowPregnant.GetValue(slate);
|
||||
IEnumerable<TraitDef> value4 = forcedTraits.GetValue(slate);
|
||||
IEnumerable<TraitDef> value5 = prohibitedTraits.GetValue(slate);
|
||||
float value6 = biocodeWeaponChance.GetValue(slate);
|
||||
bool value7 = mustBeCapableOfViolence.GetValue(slate);
|
||||
Pawn value8 = extraPawnForExtraRelationChance.GetValue(slate);
|
||||
float value9 = relationWithExtraPawnChanceFactor.GetValue(slate);
|
||||
Gender? value10 = fixedGender.GetValue(slate);
|
||||
float value11 = biocodeApparelChance.GetValue(slate);
|
||||
DevelopmentalStage developmentalStage = GetDevelopmentalStage(slate);
|
||||
|
||||
// 获取自定义背景故事设置
|
||||
BackstoryDef childhoodBackstoryValue = childhoodBackstory.GetValue(slate);
|
||||
BackstoryDef adulthoodBackstoryValue = adulthoodBackstory.GetValue(slate);
|
||||
bool useCustomBackstoriesValue = useCustomBackstories.GetValue(slate);
|
||||
|
||||
PawnGenerationRequest request = new PawnGenerationRequest(
|
||||
value, value2, PawnGenerationContext.NonPlayer, null,
|
||||
forceGenerateNewPawn: false, allowDead: false, allowDowned: false,
|
||||
canGeneratePawnRelations: true, value7, 1f, forceAddFreeWarmLayerIfNeeded: false,
|
||||
allowGay: true, value3, allowFood: true, flag, inhabitant: false,
|
||||
certainlyBeenInCryptosleep: false, forceRedressWorldPawnIfFormerColonist: false,
|
||||
worldPawnFactionDoesntMatter: false, value6, value11, value8, value9,
|
||||
null, null, value4, value5, null, null, null, value10, null, null, null,
|
||||
null, forceNoIdeo: false, forceNoBackstory: false, forbidAnyTitle: false,
|
||||
forceDead: false, null, null, null, null, null, 0f, developmentalStage);
|
||||
|
||||
request.BiocodeApparelChance = biocodeApparelChance.GetValue(slate);
|
||||
request.ForbidAnyTitle = forbidAnyTitle.GetValue(slate);
|
||||
|
||||
Pawn pawn = PawnGenerator.GeneratePawn(request);
|
||||
|
||||
// 确保名字不是数字(如果设置了)
|
||||
if (ensureNonNumericName.GetValue(slate) && (pawn.Name == null || pawn.Name.Numerical))
|
||||
{
|
||||
pawn.Name = PawnBioAndNameGenerator.GeneratePawnName(pawn);
|
||||
}
|
||||
|
||||
// 应用自定义背景故事
|
||||
if (useCustomBackstoriesValue)
|
||||
{
|
||||
ApplyCustomBackstories(pawn, childhoodBackstoryValue, adulthoodBackstoryValue);
|
||||
}
|
||||
|
||||
if (giveDependentDrugs.GetValue(slate) && ModsConfig.BiotechActive && pawn.genes != null)
|
||||
{
|
||||
foreach (Gene item in pawn.genes.GenesListForReading)
|
||||
{
|
||||
if (item.Active)
|
||||
{
|
||||
Gene_ChemicalDependency dep = item as Gene_ChemicalDependency;
|
||||
if (dep != null && DefDatabase<ThingDef>.AllDefs.Where((ThingDef x) => x.IsDrug && x.GetCompProperties<CompProperties_Drug>().chemical == dep.def.chemical).TryRandomElementByWeight((ThingDef x) => x.generateCommonality, out var result))
|
||||
{
|
||||
Thing thing = ThingMaker.MakeThing(result);
|
||||
thing.stackCount = Rand.Range(1, 3);
|
||||
pawn.inventory.innerContainer.TryAddOrTransfer(thing);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (storeAs.GetValue(slate) != null)
|
||||
{
|
||||
QuestGen.slate.Set(storeAs.GetValue(slate), pawn);
|
||||
}
|
||||
|
||||
if (addToList.GetValue(slate) != null)
|
||||
{
|
||||
QuestGenUtility.AddToOrMakeList(QuestGen.slate, addToList.GetValue(slate), pawn);
|
||||
}
|
||||
|
||||
if (addToLists.GetValue(slate) != null)
|
||||
{
|
||||
foreach (string item2 in addToLists.GetValue(slate))
|
||||
{
|
||||
QuestGenUtility.AddToOrMakeList(QuestGen.slate, item2, pawn);
|
||||
}
|
||||
}
|
||||
|
||||
QuestGen.AddToGeneratedPawns(pawn);
|
||||
if (!pawn.IsWorldPawn())
|
||||
{
|
||||
Find.WorldPawns.PassToWorld(pawn);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 应用自定义背景故事
|
||||
/// </summary>
|
||||
private void ApplyCustomBackstories(Pawn pawn, BackstoryDef childhood, BackstoryDef adulthood)
|
||||
{
|
||||
if (childhood != null)
|
||||
{
|
||||
pawn.story.Childhood = childhood;
|
||||
}
|
||||
|
||||
if (adulthood != null)
|
||||
{
|
||||
pawn.story.Adulthood = adulthood;
|
||||
}
|
||||
|
||||
// 重新计算技能,因为背景故事会影响技能
|
||||
if (pawn.skills != null)
|
||||
{
|
||||
pawn.skills.Notify_SkillDisablesChanged();
|
||||
}
|
||||
|
||||
// 重新计算工作类型
|
||||
if (pawn.workSettings != null)
|
||||
{
|
||||
pawn.workSettings.Notify_DisabledWorkTypesChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user