Files
ArachnaeSwarm/Source/ArachnaeSwarm/CompSpawnPawnFromList.cs
2025-09-02 12:21:49 +08:00

153 lines
5.2 KiB
C#

using System.Collections.Generic;
using System.Linq;
using Verse;
using RimWorld;
using Verse.AI;
using Verse.AI.Group;
namespace ArachnaeSwarm
{
public class CompSpawnPawnFromList : ThingComp
{
public CompProperties_SpawnPawnFromList Props => (CompProperties_SpawnPawnFromList)props;
private int spawnUntilTick = -1;
private PawnKindDef spawningPawnKind;
private PawnKindDef selectedPawnKind;
public bool IsHatching => spawnUntilTick > 0;
public override IEnumerable<FloatMenuOption> CompFloatMenuOptions(Pawn selPawn)
{
if (spawnUntilTick > 0)
{
yield break; // 正在延迟中,不显示菜单
}
if (Props.whitelist == null || !Props.whitelist.Contains(selPawn.kindDef))
{
yield break;
}
if (Props.pawnKinds != null)
{
foreach (PawnKindDef pawnKind in Props.pawnKinds)
{
yield return new FloatMenuOption("ARA_Incubate".Translate(pawnKind.label), () =>
{
Job job = JobMaker.MakeJob(DefDatabase<JobDef>.GetNamed("ARA_IncubateJob"), parent);
selectedPawnKind = pawnKind;
selPawn.jobs.TryTakeOrderedJob(job);
});
}
}
}
public void StartIncubation()
{
spawningPawnKind = selectedPawnKind;
int delay = Props.pawnKindDelays?.FirstOrDefault(pkd => pkd.pawnKind == selectedPawnKind)?.delay ?? 0;
spawnUntilTick = Find.TickManager.TicksGame + delay;
}
public override void CompTick()
{
base.CompTick();
if (spawnUntilTick > 0 && Find.TickManager.TicksGame >= spawnUntilTick)
{
SpawnPawn(spawningPawnKind);
}
}
private void SpawnPawn(PawnKindDef pawnKind)
{
try
{
if (pawnKind == null)
{
Log.Warning("CompSpawnPawnFromList: Tried to spawn pawn but pawnKind is null.");
return;
}
if (!parent.Spawned || parent.Map == null)
{
Log.Error($"CompSpawnPawnFromList: Cannot spawn pawn. Parent {parent} is not spawned or map is null.");
return;
}
int count = Props.spawnCount.RandomInRange;
for (int i = 0; i < count; i++)
{
Pawn pawn = PawnGenerator.GeneratePawn(new PawnGenerationRequest(pawnKind, parent.Faction));
if (pawn == null)
{
Log.Error($"CompSpawnPawnFromList: Failed to generate pawn of kind {pawnKind.defName} for faction {parent.Faction?.Name ?? "null"}.");
continue;
}
if (GenSpawn.Spawn(pawn, parent.Position, parent.Map) == null)
{
Log.Error($"CompSpawnPawnFromList: Failed to spawn pawn {pawn} at {parent.Position}.");
if (!pawn.Destroyed)
{
pawn.Destroy();
}
continue;
}
if (Props.lordJob != null)
{
try
{
LordJob lordJobInstance = (LordJob)System.Activator.CreateInstance(Props.lordJob);
Lord lord = LordMaker.MakeNewLord(parent.Faction, lordJobInstance, parent.Map);
lord.AddPawn(pawn);
}
catch (System.Exception e)
{
Log.Error($"CompSpawnPawnFromList: Error creating LordJob {Props.lordJob?.Name ?? "null"} or assigning pawn {pawn}. Exception: {e}");
}
}
}
if (Props.destroyOnSpawn)
{
parent.Destroy(DestroyMode.Vanish);
}
}
finally
{
spawnUntilTick = -1;
spawningPawnKind = null;
}
}
public override string CompInspectStringExtra()
{
if (spawnUntilTick > 0)
{
int remainingTicks = spawnUntilTick - Find.TickManager.TicksGame;
if (remainingTicks > 0)
{
return "Spawning {0} in: {1}".Translate(spawningPawnKind.label, remainingTicks.ToStringTicksToPeriod());
}
}
else
{
return "ARA_NeedsInteraction".Translate();
}
return null;
}
public override void PostExposeData()
{
base.PostExposeData();
Scribe_Values.Look(ref spawnUntilTick, "spawnUntilTick", -1);
Scribe_Defs.Look(ref spawningPawnKind, "spawningPawnKind");
Scribe_Defs.Look(ref selectedPawnKind, "selectedPawnKind");
}
}
}