184 lines
6.7 KiB
C#
184 lines
6.7 KiB
C#
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using Verse;
|
|
using RimWorld;
|
|
using Verse.AI;
|
|
using Verse.AI.Group;
|
|
using UnityEngine; // Add this for ContentFinder
|
|
|
|
namespace ArachnaeSwarm
|
|
{
|
|
public class CompSpawnPawnFromList : ThingComp
|
|
{
|
|
public CompProperties_SpawnPawnFromList Props => (CompProperties_SpawnPawnFromList)props;
|
|
|
|
private int spawnUntilTick = -1;
|
|
private PawnKindDef spawningPawnKind;
|
|
// This component uses its own PawnSpawnEntry, separate from the Queued spawner
|
|
private PawnSpawnEntry selectedEntry;
|
|
public bool IsHatching => spawnUntilTick > 0;
|
|
|
|
public override IEnumerable<FloatMenuOption> CompFloatMenuOptions(Pawn selPawn)
|
|
{
|
|
if (spawnUntilTick > 0)
|
|
{
|
|
yield break;
|
|
}
|
|
// 修改这里:只有当 whitelist 不为空时才检查白名单
|
|
if (Props.whitelist != null && Props.whitelist.Count > 0 && !Props.whitelist.Contains(selPawn.kindDef))
|
|
{
|
|
yield break;
|
|
}
|
|
if (Props.spawnablePawns != null)
|
|
{
|
|
foreach (PawnSpawnEntry entry in Props.spawnablePawns)
|
|
{
|
|
if (entry.pawnKind == null) continue;
|
|
if (entry.requiredResearch != null && !entry.requiredResearch.IsFinished)
|
|
{
|
|
string disabledText = "ARA_Incubate".Translate(entry.pawnKind.label) + " (" + "Requires".Translate() + ": " + entry.requiredResearch.label + ")";
|
|
yield return new FloatMenuOption(disabledText, null);
|
|
}
|
|
else
|
|
{
|
|
yield return new FloatMenuOption("ARA_Incubate".Translate(entry.pawnKind.label), () =>
|
|
{
|
|
Job job = JobMaker.MakeJob(DefDatabase<JobDef>.GetNamed("ARA_IncubateJob"), parent);
|
|
this.selectedEntry = entry;
|
|
selPawn.jobs.TryTakeOrderedJob(job);
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void StartIncubation()
|
|
{
|
|
if (this.selectedEntry == null) return;
|
|
|
|
spawningPawnKind = this.selectedEntry.pawnKind;
|
|
spawnUntilTick = Find.TickManager.TicksGame + this.selectedEntry.delayTicks;
|
|
}
|
|
|
|
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");
|
|
// selectedEntry is not saved because the interaction is a one-off action.
|
|
}
|
|
|
|
// Moved to the correct position, at the class level.
|
|
public override IEnumerable<Gizmo> CompGetGizmosExtra()
|
|
{
|
|
foreach (var g in base.CompGetGizmosExtra())
|
|
{
|
|
yield return g;
|
|
}
|
|
|
|
if (IsHatching)
|
|
{
|
|
yield return new Command_Action
|
|
{
|
|
defaultLabel = "CommandCancelProduction".Translate(),
|
|
defaultDesc = "CommandCancelProductionDesc".Translate(),
|
|
icon = ContentFinder<Texture2D>.Get("UI/Designators/Cancel"),
|
|
action = () =>
|
|
{
|
|
spawnUntilTick = -1;
|
|
spawningPawnKind = null;
|
|
}
|
|
};
|
|
}
|
|
}
|
|
}
|
|
} |