Files
WulaFallenEmpireRW/Source/WulaFallenEmpire/BuildingComp/WULA_MechanoidRecycler/Building_MechanoidRecycler.cs
2026-02-24 17:33:16 +08:00

389 lines
14 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using RimWorld;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
using Verse;
using Verse.AI;
using LudeonTK;
namespace WulaFallenEmpire
{
public class Building_MechanoidRecycler : Building
{
public CompProperties_MechanoidRecycler Props => def.GetCompProperties<CompProperties_MechanoidRecycler>();
// 改为存储计数而不是Pawn实例
private int storedMechanoidCount = 0;
private int spawnTick; // 建筑生成的时间点
// 生成队列存储Pawn生成请求
private Queue<PawnGenerationRequest> spawnQueue = new Queue<PawnGenerationRequest>();
private bool initialUnitsSpawned = false;
public int StoredCount => storedMechanoidCount;
public int MaxStorage => Props.maxStorageCapacity;
public bool IsCooldownActive => Find.TickManager.TicksGame - spawnTick < 24 * 2500; // 24小时冷却
// 新增:检查是否属于玩家派系
public bool IsPlayerFaction => this.Faction == Faction.OfPlayer;
// 生成初始单位(改为计数)
private void SpawnInitialUnits()
{
if (initialUnitsSpawned || Props.initialUnits == null)
return;
foreach (var initialUnit in Props.initialUnits)
{
storedMechanoidCount += initialUnit.count;
}
initialUnitsSpawned = true;
}
public override void SpawnSetup(Map map, bool respawningAfterLoad)
{
base.SpawnSetup(map, respawningAfterLoad);
spawnTick = Find.TickManager.TicksGame;
if (!respawningAfterLoad)
{
SpawnInitialUnits();
}
}
// 回收机械族(改为增加计数)
public void AcceptMechanoid(Pawn mech)
{
if (storedMechanoidCount >= Props.maxStorageCapacity)
{
Messages.Message("WULA_RecyclerFull".Translate(), MessageTypeDefOf.RejectInput);
return;
}
storedMechanoidCount++;
mech.Destroy(); // 直接销毁,不存储实例
Messages.Message("WULA_MechRecycled".Translate(mech.LabelCap, storedMechanoidCount, Props.maxStorageCapacity),
MessageTypeDefOf.PositiveEvent);
}
// 消耗机械族计数
public bool ConsumeMechanoids(int count)
{
if (storedMechanoidCount < count)
return false;
storedMechanoidCount -= count;
return true;
}
// 设置机械族计数(用于转换恢复)
public void SetMechanoidCount(int count)
{
storedMechanoidCount = Mathf.Clamp(count, 0, Props.maxStorageCapacity);
}
protected override void Tick()
{
base.Tick();
// 处理生成队列
if (spawnQueue.Count > 0 && Find.TickManager.TicksGame % 10 == 0)
{
TrySpawnFromQueue();
}
}
// 打开生成界面
public void OpenSpawnInterface()
{
if (storedMechanoidCount == 0)
{
Messages.Message("WULA_NoMechsToConvert".Translate(), MessageTypeDefOf.RejectInput);
return;
}
List<FloatMenuOption> kindOptions = new List<FloatMenuOption>();
foreach (PawnKindDef kindDef in Props.spawnablePawnKinds)
{
kindOptions.Add(new FloatMenuOption(
$"{kindDef.LabelCap}",
() => TrySpawnMechanoids(kindDef, 1)
));
}
Find.WindowStack.Add(new FloatMenu(kindOptions));
}
private void TrySpawnMechanoids(PawnKindDef kindDef, int count)
{
if (!ConsumeMechanoids(count))
{
Messages.Message("WULA_NotEnoughMechs".Translate(), MessageTypeDefOf.RejectInput);
return;
}
for (int i = 0; i < count; i++)
{
PawnGenerationRequest request = new PawnGenerationRequest(
kindDef,
Faction,
PawnGenerationContext.NonPlayer,
-1,
forceGenerateNewPawn: true,
allowDead: false,
allowDowned: false,
canGeneratePawnRelations: false,
mustBeCapableOfViolence: true
);
spawnQueue.Enqueue(request);
}
TrySpawnFromQueue();
Messages.Message("WULA_ConvertingMechs".Translate(count, kindDef.LabelCap), MessageTypeDefOf.PositiveEvent);
}
private void TrySpawnFromQueue()
{
if (spawnQueue.Count == 0)
return;
int spawnCount = Mathf.Min(spawnQueue.Count, 5);
for (int i = 0; i < spawnCount; i++)
{
if (spawnQueue.Count == 0)
break;
PawnGenerationRequest request = spawnQueue.Dequeue();
Pawn newMech = PawnGenerator.GeneratePawn(request);
IntVec3 spawnPos = GetSpawnPosition();
if (spawnPos.IsValid)
{
GenSpawn.Spawn(newMech, spawnPos, Map);
}
else
{
GenSpawn.Spawn(newMech, Position, Map);
}
}
}
private IntVec3 GetSpawnPosition()
{
for (int i = 1; i <= 3; i++)
{
foreach (IntVec3 cell in GenRadial.RadialCellsAround(Position, i, true))
{
if (cell.InBounds(Map) && cell.Walkable(Map) && cell.GetFirstPawn(Map) == null)
return cell;
}
}
return IntVec3.Invalid;
}
// 右键菜单选项
public override IEnumerable<Gizmo> GetGizmos()
{
foreach (Gizmo g in base.GetGizmos())
yield return g;
// 新增:只有玩家派系才能看到和使用这些按钮
if (!IsPlayerFaction)
yield break;
// 回收附近机械族按钮
Command_Action recycleCommand = new Command_Action
{
defaultLabel = "WULA_RecycleNearbyMechs".Translate(),
defaultDesc = "WULA_RecycleNearbyMechsDesc".Translate(Props.recycleRange),
icon = ContentFinder<Texture2D>.Get("Wula/UI/Commands/WULA_RecycleNearbyMechanoids"),
action = RecycleNearbyMechanoids
};
if (storedMechanoidCount >= Props.maxStorageCapacity)
{
recycleCommand.Disable("WULA_StorageFull".Translate());
}
yield return recycleCommand;
// 生成机械族按钮
Command_Action spawnCommand = new Command_Action
{
defaultLabel = "WULA_ConvertMechs".Translate(),
defaultDesc = "WULA_ConvertMechsDesc".Translate(storedMechanoidCount, Props.maxStorageCapacity),
icon = ContentFinder<Texture2D>.Get("Wula/UI/Commands/WULA_ConvertMechanoids"),
action = OpenSpawnInterface
};
if (storedMechanoidCount == 0)
{
spawnCommand.Disable("WULA_NoAvailableMechs".Translate());
}
yield return spawnCommand;
// 开发模式按钮:立即结束冷却
if (Prefs.DevMode && IsCooldownActive)
{
Command_Action devCommand = new Command_Action
{
defaultLabel = "Dev: 立即结束冷却",
defaultDesc = "立即结束转换冷却时间",
action = () =>
{
// 将生成时间设置为足够早,使冷却立即结束
spawnTick = Find.TickManager.TicksGame - (24 * 2500 + 1);
Messages.Message("转换冷却已立即结束", MessageTypeDefOf.SilentInput);
}
};
yield return devCommand;
}
}
// 回收附近机械族
public void RecycleNearbyMechanoids()
{
if (storedMechanoidCount >= Props.maxStorageCapacity)
{
Messages.Message("WULA_StorageFull".Translate(), MessageTypeDefOf.RejectInput);
return;
}
List<Pawn> nearbyMechs = FindNearbyRecyclableMechanoids();
if (nearbyMechs.Count == 0)
{
Messages.Message("WULA_NoNearbyRecyclableMechs".Translate(), MessageTypeDefOf.RejectInput);
return;
}
int assignedCount = 0;
foreach (Pawn mech in nearbyMechs)
{
if (StartRecycleJob(mech))
{
assignedCount++;
}
}
Messages.Message("WULA_MechsOrderedToRecycle".Translate(assignedCount), MessageTypeDefOf.PositiveEvent);
}
private List<Pawn> FindNearbyRecyclableMechanoids()
{
List<Pawn> result = new List<Pawn>();
CellRect searchRect = CellRect.CenteredOn(Position, Props.recycleRange);
foreach (Pawn pawn in Map.mapPawns.AllPawnsSpawned)
{
if (searchRect.Contains(pawn.Position) &&
IsRecyclableMechanoid(pawn) &&
!IsAlreadyGoingToRecycler(pawn) &&
pawn.CanReach(this, PathEndMode.InteractionCell, Danger.Some))
{
result.Add(pawn);
}
}
return result;
}
private bool IsRecyclableMechanoid(Pawn pawn)
{
return pawn.RaceProps.IsMechanoid &&
Props.recyclableRaces.Contains(pawn.def) &&
!pawn.Downed &&
pawn.Faction == Faction;
}
private bool IsAlreadyGoingToRecycler(Pawn mech)
{
Job curJob = mech.CurJob;
if (curJob != null && curJob.def == Props.recycleJobDef && curJob.targetA.Thing == this)
return true;
return false;
}
private bool StartRecycleJob(Pawn mech)
{
if (IsAlreadyGoingToRecycler(mech))
return false;
Job job = JobMaker.MakeJob(Props.recycleJobDef, this);
if (mech.jobs.TryTakeOrderedJob(job))
{
return true;
}
return false;
}
public override string GetInspectString()
{
StringBuilder stringBuilder = new StringBuilder();
string baseString = base.GetInspectString();
if (!string.IsNullOrEmpty(baseString))
{
stringBuilder.Append(baseString);
}
string storedInfo = "WULA_StoredMechs".Translate(storedMechanoidCount, Props.maxStorageCapacity);
if (stringBuilder.Length > 0)
stringBuilder.AppendLine();
stringBuilder.Append(storedInfo);
// 显示冷却状态
if (IsCooldownActive)
{
stringBuilder.AppendLine();
stringBuilder.Append("WULA_TransformCooldown".Translate(GetRemainingCooldownHours().ToString("F1")));
}
return stringBuilder.ToString();
}
public float GetRemainingCooldownHours()
{
int remainingTicks = (24 * 2500) - (Find.TickManager.TicksGame - spawnTick);
return Mathf.Max(0, remainingTicks / 2500f);
}
public static void DevEndCooldown()
{
Building_MechanoidRecycler selectedRecycler = Find.Selector.SingleSelectedThing as Building_MechanoidRecycler;
if (selectedRecycler != null)
{
selectedRecycler.spawnTick = Find.TickManager.TicksGame - (24 * 2500 + 1);
Messages.Message("转换冷却已立即结束", MessageTypeDefOf.SilentInput);
}
else
{
Messages.Message("请先选择一个机械族回收器", MessageTypeDefOf.RejectInput);
}
}
public override void ExposeData()
{
base.ExposeData();
Scribe_Values.Look(ref storedMechanoidCount, "storedMechanoidCount", 0);
Scribe_Values.Look(ref spawnTick, "spawnTick", 0);
Scribe_Values.Look(ref initialUnitsSpawned, "initialUnitsSpawned", false);
Scribe_Collections.Look(ref spawnQueue, "spawnQueue", LookMode.Deep);
if (Scribe.mode == LoadSaveMode.PostLoadInit)
{
if (spawnQueue == null)
spawnQueue = new Queue<PawnGenerationRequest>();
}
}
}
}