This commit is contained in:
2026-02-25 17:30:59 +08:00
parent 0509f26c3c
commit fff40b0edb
70 changed files with 3951 additions and 1219 deletions

View File

@@ -0,0 +1,195 @@
using RimWorld;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEngine;
using Verse;
using Verse.AI.Group;
namespace WulaFallenEmpire
{
public class CompAutoMechCarrier : CompMechCarrier
{
#region Reflected Fields
private static FieldInfo spawnedPawnsField;
private static FieldInfo cooldownTicksRemainingField;
private static FieldInfo innerContainerField;
private List<Pawn> SpawnedPawns
{
get
{
if (spawnedPawnsField == null)
spawnedPawnsField = typeof(CompMechCarrier).GetField("spawnedPawns", BindingFlags.NonPublic | BindingFlags.Instance);
return (List<Pawn>)spawnedPawnsField.GetValue(this);
}
}
private int CooldownTicksRemaining
{
get
{
if (cooldownTicksRemainingField == null)
cooldownTicksRemainingField = typeof(CompMechCarrier).GetField("cooldownTicksRemaining", BindingFlags.NonPublic | BindingFlags.Instance);
return (int)cooldownTicksRemainingField.GetValue(this);
}
set
{
if (cooldownTicksRemainingField == null)
cooldownTicksRemainingField = typeof(CompMechCarrier).GetField("cooldownTicksRemaining", BindingFlags.NonPublic | BindingFlags.Instance);
cooldownTicksRemainingField.SetValue(this, value);
}
}
private ThingOwner InnerContainer
{
get
{
if (innerContainerField == null)
innerContainerField = typeof(CompMechCarrier).GetField("innerContainer", BindingFlags.NonPublic | BindingFlags.Instance);
return (ThingOwner)innerContainerField.GetValue(this);
}
}
#endregion
public CompProperties_AutoMechCarrier AutoProps => (CompProperties_AutoMechCarrier)props;
private int TotalPawnCapacity => AutoProps.productionQueue.Sum(e => e.count);
private int LiveSpawnedPawnsCount(PawnKindDef kind)
{
SpawnedPawns.RemoveAll(p => p == null || p.Destroyed);
return SpawnedPawns.Count(p => p.kindDef == kind);
}
private AcceptanceReport CanSpawnNow(PawnKindDef kind)
{
if (parent is Pawn pawn && (pawn.IsSelfShutdown() || !pawn.Awake() || pawn.Downed || pawn.Dead || !pawn.Spawned))
return false;
if (CooldownTicksRemaining > 0)
return "CooldownTime".Translate() + " " + CooldownTicksRemaining.ToStringSecondsFromTicks();
PawnProductionEntry entry = AutoProps.productionQueue.First(e => e.pawnKind == kind);
int cost = entry.cost ?? Props.costPerPawn;
if (!AutoProps.freeProduction && InnerContainer.TotalStackCountOfDef(Props.fixedIngredient) < cost)
return "MechCarrierNotEnoughResources".Translate();
return true;
}
private void TrySpawnPawn(PawnKindDef kind)
{
PawnGenerationRequest request = new PawnGenerationRequest(kind, parent.Faction, PawnGenerationContext.NonPlayer, -1, forceGenerateNewPawn: true);
Pawn pawn = PawnGenerator.GeneratePawn(request);
GenSpawn.Spawn(pawn, parent.Position, parent.Map);
SpawnedPawns.Add(pawn);
if (parent is Pawn p && p.GetLord() != null)
p.GetLord().AddPawn(pawn);
if (!AutoProps.freeProduction)
{
PawnProductionEntry entry = AutoProps.productionQueue.First(e => e.pawnKind == kind);
int costLeft = entry.cost ?? Props.costPerPawn;
List<Thing> things = new List<Thing>(InnerContainer);
for (int j = 0; j < things.Count; j++)
{
Thing thing = InnerContainer.Take(things[j], Mathf.Min(things[j].stackCount, costLeft));
costLeft -= thing.stackCount;
thing.Destroy();
if (costLeft <= 0) break;
}
}
PawnProductionEntry spawnEntry = AutoProps.productionQueue.First(e => e.pawnKind == kind);
CooldownTicksRemaining = spawnEntry.cooldownTicks ?? Props.cooldownTicks;
if (Props.spawnedMechEffecter != null)
EffecterTrigger(Props.spawnedMechEffecter, Props.attachSpawnedMechEffecter, pawn);
if (Props.spawnEffecter != null)
EffecterTrigger(Props.spawnEffecter, Props.attachSpawnedEffecter, parent);
}
private void EffecterTrigger(EffecterDef effecterDef, bool attach, Thing target)
{
Effecter effecter = new Effecter(effecterDef);
effecter.Trigger(attach ? ((TargetInfo)target) : new TargetInfo(target.Position, target.Map), TargetInfo.Invalid);
effecter.Cleanup();
}
public override void CompTick()
{
base.CompTick();
if (parent.IsHashIntervalTick(60)) // 每秒检查一次
{
// 检查是否有抑制生产的Hediff
if (AutoProps.disableHediff != null && (parent as Pawn)?.health.hediffSet.HasHediff(AutoProps.disableHediff) == true)
{
return; // 有Hediff停止生产
}
// 1. 先检查是否满员
bool isFull = true;
foreach (var entry in AutoProps.productionQueue)
{
if (LiveSpawnedPawnsCount(entry.pawnKind) < entry.count)
{
isFull = false;
break;
}
}
if (isFull)
{
return; // 如果已满员,则不进行任何操作,包括冷却计时
}
// 2. 如果未满员,才检查冷却时间
if (CooldownTicksRemaining > 0) return;
// 3. 寻找空位并生产
foreach (var entry in AutoProps.productionQueue)
{
if (LiveSpawnedPawnsCount(entry.pawnKind) < entry.count)
{
if (CanSpawnNow(entry.pawnKind).Accepted)
{
TrySpawnPawn(entry.pawnKind);
break; // 每次只生产一个
}
}
}
}
}
public override IEnumerable<Gizmo> CompGetGizmosExtra()
{
// 移除所有Gizmo逻辑
return Enumerable.Empty<Gizmo>();
}
public override string CompInspectStringExtra()
{
SpawnedPawns.RemoveAll(p => p == null || p.Destroyed);
string text = "Pawns: " + SpawnedPawns.Count + " / " + TotalPawnCapacity;
foreach (var entry in AutoProps.productionQueue)
{
text += $"\n- {entry.pawnKind.LabelCap}: {LiveSpawnedPawnsCount(entry.pawnKind)} / {entry.count}";
}
if (CooldownTicksRemaining > 0)
{
text += "\n" + "CooldownTime".Translate() + ": " + CooldownTicksRemaining.ToStringSecondsFromTicks();
}
if (!AutoProps.freeProduction)
{
text += "\n" + base.CompInspectStringExtra();
}
return text;
}
}
}