// Building_GlobalWorkTable.cs (调整为每秒处理) using RimWorld; using System.Collections.Generic; using System.Linq; using Verse; using Verse.AI; using UnityEngine; namespace WulaFallenEmpire { public class Building_GlobalWorkTable : Building_WorkTable { public GlobalProductionOrderStack globalOrderStack; private CompPowerTrader powerComp; private CompBreakdownable breakdownableComp; private int lastProcessTick = -1; private const int ProcessInterval = 1; // 改为每tick处理,以实现每秒1工作量 public Building_GlobalWorkTable() { globalOrderStack = new GlobalProductionOrderStack(this); } public override void ExposeData() { base.ExposeData(); Scribe_Deep.Look(ref globalOrderStack, "globalOrderStack", this); } public override void SpawnSetup(Map map, bool respawningAfterLoad) { base.SpawnSetup(map, respawningAfterLoad); powerComp = GetComp(); breakdownableComp = GetComp(); } // 在 Building_GlobalWorkTable 类中修改 Tick 方法 protected override void Tick() { base.Tick(); // 修复:改为每60 ticks(1秒)处理一次,避免每tick处理导致的精度问题 if (Find.TickManager.TicksGame % 60 == 0 && Find.TickManager.TicksGame != lastProcessTick) { lastProcessTick = Find.TickManager.TicksGame; if (CurrentlyUsableForGlobalBills()) { globalOrderStack.ProcessOrders(); } } } public bool CurrentlyUsableForGlobalBills() { if (powerComp != null && !powerComp.PowerOn) return false; if (breakdownableComp != null && breakdownableComp.BrokenDown) return false; return true; } // 新增:获取空投扩展参数 public GlobalWorkTableAirdropExtension AirdropExtension => def.GetModExtension(); // 新增:添加空投命令到技能栏 public override IEnumerable GetGizmos() { foreach (Gizmo g in base.GetGizmos()) { yield return g; } // 只有在有输出物品时才显示空投按钮 var globalStorage = Find.World.GetComponent(); if (globalStorage != null && globalStorage.outputStorage.Any(kvp => kvp.Value > 0)) { yield return new Command_Action { action = StartAirdropTargeting, defaultLabel = "WULA_AirdropProducts".Translate(), defaultDesc = "WULA_AirdropProductsDesc".Translate(), icon = ContentFinder.Get("Wula/UI/Commands/WULA_AirdropProducts"), disabledReason = "WULA_CannotAirdrop".Translate() }; } } // 新增:开始空投目标选择 private void StartAirdropTargeting() { // 检查是否有输出物品 var globalStorage = Find.World.GetComponent(); if (globalStorage == null || !globalStorage.outputStorage.Any(kvp => kvp.Value > 0)) { Messages.Message("WULA_NoProductsToAirdrop".Translate(), MessageTypeDefOf.RejectInput); return; } // 启动目标选择 Find.Targeter.BeginTargeting(new TargetingParameters { canTargetLocations = true, canTargetPawns = false, canTargetBuildings = false, canTargetItems = false }, OnAirdropTargetSelected, null, OnAirdropTargetingCancelled); } private void OnAirdropTargetSelected(LocalTargetInfo target) { ExecuteAirdrop(target.Cell); } private void OnAirdropTargetingCancelled() { // 目标选择取消,不做任何操作 } // 新增:执行空投逻辑 private void ExecuteAirdrop(IntVec3 targetCell) { var globalStorage = Find.World.GetComponent(); if (globalStorage == null) return; // 获取空投参数 var airdropExt = AirdropExtension; float maxRange = airdropExt?.maxRange ?? 50f; float randomRange = airdropExt?.randomRange ?? 15f; int minPods = airdropExt?.minPods ?? 1; int maxPods = airdropExt?.maxPods ?? 10; // 检查目标距离 if (targetCell.DistanceTo(Position) > maxRange) { Messages.Message("WULA_AirdropTargetTooFar".Translate(maxRange), MessageTypeDefOf.RejectInput); return; } // 查找有效的落点 List validDropSpots = FindValidDropSpots(targetCell, randomRange, maxPods); if (validDropSpots.Count == 0) { Messages.Message("WULA_NoValidDropSpots".Translate(), MessageTypeDefOf.RejectInput); return; } // 计算实际空投舱数量 int actualPodCount = Mathf.Clamp(validDropSpots.Count, minPods, maxPods); // 分配物品到空投舱 List> podContents = DistributeItemsToPods(globalStorage, actualPodCount); if (podContents.Count == 0) { Messages.Message("WULA_FailedToDistributeItems".Translate(), MessageTypeDefOf.RejectInput); return; } // 生成空投舱 int successfulDrops = 0; for (int i = 0; i < Mathf.Min(actualPodCount, podContents.Count); i++) { if (CreateDropPod(validDropSpots[i], podContents[i])) { successfulDrops++; } } Messages.Message("WULA_AirdropSuccessful".Translate(successfulDrops), MessageTypeDefOf.PositiveEvent); } // 新增:查找有效落点 private List FindValidDropSpots(IntVec3 center, float radius, int maxSpots) { List validSpots = new List(); Map map = Map; // 在指定半径内搜索有效格子 foreach (IntVec3 cell in GenRadial.RadialCellsAround(center, radius, true)) { if (!cell.IsValid || !cell.InBounds(map)) continue; // 检查是否为厚岩顶 if (map.roofGrid.RoofAt(cell)?.isThickRoof ?? false) continue; // 检查是否可以放置空投舱 if (DropCellFinder.IsGoodDropSpot(cell, map, false, true)) { validSpots.Add(cell); if (validSpots.Count >= maxSpots) break; } } // 如果有效格子太少,放宽条件(但仍然排除厚岩顶) if (validSpots.Count < 3) { foreach (IntVec3 cell in GenRadial.RadialCellsAround(center, radius, true)) { if (!cell.IsValid || !cell.InBounds(map)) continue; if (map.roofGrid.RoofAt(cell)?.isThickRoof ?? false) continue; if (!validSpots.Contains(cell) && cell.Standable(map)) { validSpots.Add(cell); if (validSpots.Count >= maxSpots) break; } } } return validSpots; } // 新增:分配物品到空投舱 private List> DistributeItemsToPods(GlobalStorageWorldComponent storage, int podCount) { List> podContents = new List>(); // 初始化空投舱内容列表 for (int i = 0; i < podCount; i++) { podContents.Add(new List()); } // 获取所有输出物品并转换为Thing列表 List allItems = new List(); foreach (var kvp in storage.outputStorage.ToList()) { if (kvp.Value <= 0) continue; ThingDef thingDef = kvp.Key; int remainingCount = kvp.Value; // 如果是Pawn,需要特殊处理 if (thingDef.race != null) { // 对于Pawn,每个单独生成 for (int i = 0; i < remainingCount; i++) { PawnKindDef randomPawnKind = GetRandomPawnKindForType(thingDef); if (randomPawnKind != null) { Pawn pawn = PawnGenerator.GeneratePawn(randomPawnKind, Faction.OfPlayer); allItems.Add(pawn); } } } else { // 对于普通物品,按照堆叠限制分割 while (remainingCount > 0) { int stackSize = Mathf.Min(remainingCount, thingDef.stackLimit); Thing thing = ThingMaker.MakeThing(thingDef); thing.stackCount = stackSize; allItems.Add(thing); remainingCount -= stackSize; } } } if (allItems.Count == 0) return podContents; // 平均分配物品到空投舱 int currentPod = 0; foreach (Thing item in allItems) { podContents[currentPod].Add(item); currentPod = (currentPod + 1) % podCount; } // 从存储中移除已分配的物品 foreach (var kvp in storage.outputStorage.ToList()) { storage.outputStorage[kvp.Key] = 0; } return podContents; } // 在 Building_GlobalWorkTable.cs 中修改 GetRandomPawnKindForType 方法 private PawnKindDef GetRandomPawnKindForType(ThingDef pawnType) { if (pawnType.race == null) return null; // 获取建筑拥有者派系 Faction buildingFaction = this.Faction; if (buildingFaction == null) { Log.Warning("Building has no faction, cannot select appropriate pawn kind"); return null; } // 获取该种族的所有PawnKindDef var availableKinds = DefDatabase.AllDefs .Where(kind => kind.race == pawnType) .ToList(); if (availableKinds.Count == 0) return null; // 按优先级分组 var matchingFactionKinds = availableKinds .Where(kind => kind.defaultFactionDef != null && kind.defaultFactionDef == buildingFaction.def) .ToList(); var noFactionKinds = availableKinds .Where(kind => kind.defaultFactionDef == null) .ToList(); // 排除与建筑派系不同的PawnKind var excludedKinds = availableKinds .Where(kind => kind.defaultFactionDef != null && kind.defaultFactionDef != buildingFaction.def) .ToList(); // 记录调试信息 if (DebugSettings.godMode) { Log.Message($"[DEBUG] PawnKind selection for {pawnType.defName}:"); Log.Message($" Building faction: {buildingFaction.def.defName}"); Log.Message($" Matching faction kinds: {matchingFactionKinds.Count}"); Log.Message($" No faction kinds: {noFactionKinds.Count}"); Log.Message($" Excluded kinds: {excludedKinds.Count}"); foreach (var kind in matchingFactionKinds) Log.Message($" Matching: {kind.defName} (faction: {kind.defaultFactionDef?.defName ?? "null"})"); foreach (var kind in noFactionKinds) Log.Message($" No faction: {kind.defName}"); foreach (var kind in excludedKinds) Log.Message($" Excluded: {kind.defName} (faction: {kind.defaultFactionDef?.defName})"); } // 优先级选择 PawnKindDef selectedKind = null; // 1. 最高优先级:与建筑派系相同的PawnKind if (matchingFactionKinds.Count > 0) { selectedKind = matchingFactionKinds.RandomElement(); if (DebugSettings.godMode) Log.Message($"[DEBUG] Selected matching faction kind: {selectedKind.defName}"); } // 2. 备选:没有defaultFactionDef的PawnKind else if (noFactionKinds.Count > 0) { selectedKind = noFactionKinds.RandomElement(); if (DebugSettings.godMode) Log.Message($"[DEBUG] Selected no-faction kind: {selectedKind.defName}"); } // 3. 没有符合条件的PawnKind else { Log.Warning($"No suitable PawnKind found for {pawnType.defName} with building faction {buildingFaction.def.defName}"); return null; } return selectedKind; } // 新增:创建空投舱 private bool CreateDropPod(IntVec3 dropCell, List contents) { try { if (contents == null || contents.Count == 0) return false; // 创建空投舱信息 ActiveTransporterInfo dropPodInfo = new ActiveTransporterInfo(); // 添加所有物品到空投舱 foreach (Thing thing in contents) { dropPodInfo.innerContainer.TryAdd(thing, true); } // 设置空投舱参数 dropPodInfo.openDelay = 180; // 3秒后打开 dropPodInfo.leaveSlag = true; // 生成空投舱 DropPodUtility.MakeDropPodAt(dropCell, Map, dropPodInfo); return true; } catch (System.Exception ex) { Log.Error($"Failed to create drop pod at {dropCell}: {ex}"); return false; } } } }