Files
WulaFallenEmpireRW/Source/WulaFallenEmpire/GlobalWorkTable/Building_GlobalWorkTable.cs
2025-11-22 16:58:29 +08:00

601 lines
23 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.
// 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, IThingHolder
{
public GlobalProductionOrderStack globalOrderStack;
public ThingOwner innerContainer; // 用于存储待上传的原材料
private CompPowerTrader powerComp;
private CompBreakdownable breakdownableComp;
private int lastProcessTick = -1;
private const int ProcessInterval = 1;
// 材质映射定义
private static readonly Dictionary<StuffCategoryDef, ThingDef> StuffCategoryMapping = new Dictionary<StuffCategoryDef, ThingDef>
{
{ StuffCategoryDefOf.Metallic, ThingDefOf.Plasteel }, // 金属类 -> 玻璃钢
{ StuffCategoryDefOf.Fabric, ThingDefOf_WULA.Hyperweave } // 布革类 -> 超织物
};
public Building_GlobalWorkTable()
{
globalOrderStack = new GlobalProductionOrderStack(this);
innerContainer = new ThingOwner<Thing>(this, false);
}
public override void ExposeData()
{
base.ExposeData();
Scribe_Deep.Look(ref globalOrderStack, "globalOrderStack", this);
Scribe_Deep.Look(ref innerContainer, "innerContainer", this);
}
public override void SpawnSetup(Map map, bool respawningAfterLoad)
{
base.SpawnSetup(map, respawningAfterLoad);
powerComp = GetComp<CompPowerTrader>();
breakdownableComp = GetComp<CompBreakdownable>();
}
protected override void Tick()
{
base.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<GlobalWorkTableAirdropExtension>();
// 修改:添加空投命令到技能栏,添加工厂设施检查
public override IEnumerable<Gizmo> GetGizmos()
{
foreach (Gizmo g in base.GetGizmos())
{
yield return g;
}
// 只有在有输出物品且有工厂设施的飞行器时才显示空投按钮
var globalStorage = Find.World.GetComponent<GlobalStorageWorldComponent>();
bool hasOutputItems = globalStorage != null && globalStorage.outputStorage.Any(kvp => kvp.Value > 0);
bool hasFactoryFlyOver = HasFactoryFacilityFlyOver();
if (hasOutputItems && hasFactoryFlyOver)
{
yield return new Command_Action
{
action = StartAirdropTargeting,
defaultLabel = "WULA_AirdropProducts".Translate(),
defaultDesc = "WULA_AirdropProductsDesc".Translate(),
icon = ContentFinder<Texture2D>.Get("Wula/UI/Commands/WULA_AirdropProducts"),
};
}
else if (hasOutputItems && !hasFactoryFlyOver)
{
yield return new Command_Action
{
action = () => Messages.Message("WULA_NoFactoryFlyOver".Translate(), MessageTypeDefOf.RejectInput),
defaultLabel = "WULA_AirdropProducts".Translate(),
defaultDesc = "WULA_NoFactoryFlyOverDesc".Translate(),
icon = ContentFinder<Texture2D>.Get("Wula/UI/Commands/WULA_AirdropProducts"),
};
}
}
// 新增检查是否有拥有FactoryFacility设施的飞行器
private bool HasFactoryFacilityFlyOver()
{
Map map = Map;
if (map == null) return false;
try
{
// 检查所有FlyOver类型的物体
var allFlyOvers = new List<Thing>();
var dynamicObjects = map.dynamicDrawManager.DrawThings;
foreach (var thing in dynamicObjects)
{
if (thing is FlyOver)
{
allFlyOvers.Add(thing);
}
}
foreach (var thing in allFlyOvers)
{
if (thing is FlyOver flyOver && !flyOver.Destroyed)
{
// 检查设施
var facilitiesComp = flyOver.GetComp<CompFlyOverFacilities>();
if (facilitiesComp == null)
{
continue;
}
if (facilitiesComp.HasFacility("FactoryFacility"))
{
return true;
}
}
}
return false;
}
catch (System.Exception ex)
{
Log.Error($"[FactoryFacility Check] Error in HasFactoryFacilityFlyOver: {ex}");
return false;
}
}
// 新增:开始空投目标选择
private void StartAirdropTargeting()
{
// 检查是否有输出物品
var globalStorage = Find.World.GetComponent<GlobalStorageWorldComponent>();
if (globalStorage == null || !globalStorage.outputStorage.Any(kvp => kvp.Value > 0))
{
Messages.Message("WULA_NoProductsToAirdrop".Translate(), MessageTypeDefOf.RejectInput);
return;
}
// 检查是否有工厂设施的飞行器
if (!HasFactoryFacilityFlyOver())
{
Messages.Message("WULA_NoFactoryFlyOver".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<GlobalStorageWorldComponent>();
if (globalStorage == null)
return;
// 再次检查是否有工厂设施的飞行器
if (!HasFactoryFacilityFlyOver())
{
Messages.Message("WULA_NoFactoryFlyOver".Translate(), MessageTypeDefOf.RejectInput);
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<IntVec3> 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<List<Thing>> 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<IntVec3> FindValidDropSpots(IntVec3 center, float radius, int maxSpots)
{
List<IntVec3> validSpots = new List<IntVec3>();
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;
}
// 在 Building_GlobalWorkTable.cs 中修改 DistributeItemsToPods 方法
private List<List<Thing>> DistributeItemsToPods(GlobalStorageWorldComponent storage, int podCount)
{
List<List<Thing>> podContents = new List<List<Thing>>();
// 初始化空投舱内容列表
for (int i = 0; i < podCount; i++)
{
podContents.Add(new List<Thing>());
}
// 获取所有输出物品并转换为Thing列表
List<Thing> allItems = new List<Thing>();
// 首先处理机械体,因为需要特殊处理
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)
{
try
{
Pawn pawn = PawnGenerator.GeneratePawn(randomPawnKind, Faction.OfPlayer);
// 确保Pawn处于活跃状态
if (pawn != null)
{
// 设置Pawn为可用的状态
pawn.health.Reset();
pawn.drafter = new Pawn_DraftController(pawn);
allItems.Add(pawn);
}
else
{
Log.Error("[Airdrop] Generated pawn is null");
}
}
catch (System.Exception ex)
{
Log.Error($"[Airdrop] Error generating pawn: {ex}");
}
}
else
{
Log.Error($"[Airdrop] Could not find suitable PawnKindDef for {thingDef.defName}");
}
}
// 立即从存储中移除已处理的机械体
storage.RemoveFromOutputStorage(thingDef, remainingCount);
}
}
// 然后处理普通物品
foreach (var kvp in storage.outputStorage.ToList())
{
if (kvp.Value <= 0) continue;
ThingDef thingDef = kvp.Key;
int remainingCount = kvp.Value;
// 跳过已经处理的机械体
if (thingDef.race != null) continue;
Log.Message($"[Airdrop] Processing {remainingCount} items of type {thingDef.defName}");
// 对于普通物品,按照堆叠限制分割
while (remainingCount > 0)
{
int stackSize = Mathf.Min(remainingCount, thingDef.stackLimit);
Thing thing = CreateThingWithMaterial(thingDef, stackSize);
if (thing != null)
{
allItems.Add(thing);
remainingCount -= stackSize;
}
else
{
Log.Error($"[Airdrop] Failed to create thing: {thingDef.defName}");
break;
}
}
// 从存储中移除已处理的物品
storage.RemoveFromOutputStorage(thingDef, kvp.Value);
}
if (allItems.Count == 0)
{
return podContents;
}
// 平均分配物品到空投舱
int currentPod = 0;
foreach (Thing item in allItems)
{
if (item != null)
{
podContents[currentPod].Add(item);
currentPod = (currentPod + 1) % podCount;
}
}
// 记录分配结果
for (int i = 0; i < podContents.Count; i++)
{
Log.Message($"[Airdrop] Pod {i} contains {podContents[i].Count} items");
}
return podContents;
}
// 新增:创建物品并应用材质规则
private Thing CreateThingWithMaterial(ThingDef thingDef, int stackCount)
{
// 检查物品是否需要材质
if (thingDef.MadeFromStuff)
{
// 获取物品可用的材质类别
var stuffCategories = thingDef.stuffCategories;
if (stuffCategories != null && stuffCategories.Count > 0)
{
// 检查是否有金属类材质需求
var metallicCategory = stuffCategories.FirstOrDefault(sc =>
sc.defName == "Metallic" || sc.defName.Contains("Metallic"));
// 检查是否有布革类材质需求
var fabricCategory = stuffCategories.FirstOrDefault(sc =>
sc.defName == "Fabric" || sc.defName.Contains("Fabric") ||
sc.defName == "Leathery" || sc.defName.Contains("Leather"));
// 应用材质规则
ThingDef selectedStuff = null;
if (metallicCategory != null)
{
// 金属类 -> 玻璃钢
selectedStuff = ThingDefOf.Plasteel;
}
else if (fabricCategory != null)
{
// 布革类 -> 超织物
selectedStuff = ThingDefOf_WULA.Hyperweave;
}
// 创建带有指定材质的物品
if (selectedStuff != null)
{
Thing thing = ThingMaker.MakeThing(thingDef, selectedStuff);
thing.stackCount = stackCount;
return thing;
}
}
}
// 默认情况:创建无材质的物品
Thing defaultThing = ThingMaker.MakeThing(thingDef);
defaultThing.stackCount = stackCount;
return defaultThing;
}
// 改进 GetRandomPawnKindForType 方法
private PawnKindDef GetRandomPawnKindForType(ThingDef pawnType)
{
if (pawnType.race == null)
{
Log.Error($"[Airdrop] GetRandomPawnKindForType: {pawnType.defName} is not a pawn type");
return null;
}
// 获取工作台的派系
Faction workTableFaction = this.Faction;
if (workTableFaction == null)
{
Log.Error($"[Airdrop] Work table has no faction");
return null;
}
// 获取该种族的所有PawnKindDef
var availableKinds = DefDatabase<PawnKindDef>.AllDefs
.Where(kind => kind.race == pawnType)
.ToList();
if (availableKinds.Count == 0)
{
Log.Error($"[Airdrop] No PawnKindDef found for race: {pawnType.defName}");
return null;
}
// 最高优先级与工作台派系完全相同的PawnKind
var matchingFactionKinds = availableKinds
.Where(kind => kind.defaultFactionDef != null &&
kind.defaultFactionDef == workTableFaction.def)
.ToList();
if (matchingFactionKinds.Count > 0)
{
var selected = matchingFactionKinds.RandomElement();
return selected;
}
// 次高优先级玩家派系的PawnKind如果工作台是玩家派系
if (workTableFaction.IsPlayer)
{
var playerFactionKinds = availableKinds
.Where(kind => kind.defaultFactionDef != null &&
(kind.defaultFactionDef == FactionDefOf.PlayerColony ||
kind.defaultFactionDef == FactionDefOf.PlayerTribe))
.ToList();
if (playerFactionKinds.Count > 0)
{
var selected = playerFactionKinds.RandomElement();
return selected;
}
}
// 备选没有特定派系的PawnKind
var noFactionKinds = availableKinds
.Where(kind => kind.defaultFactionDef == null)
.ToList();
if (noFactionKinds.Count > 0)
{
var selected = noFactionKinds.RandomElement();
Log.Message($"[Airdrop] Selected no-faction PawnKind: {selected.defName}");
return selected;
}
// 最后选择任何可用的PawnKind
var selectedKind = availableKinds.RandomElement();
Log.Message($"[Airdrop] Selected fallback PawnKind: {selectedKind.defName}");
return selectedKind;
}
// IThingHolder 实现
public void GetChildHolders(List<IThingHolder> outChildren)
{
ThingOwnerUtility.AppendThingHoldersFromThings(outChildren, GetDirectlyHeldThings());
}
public ThingOwner GetDirectlyHeldThings()
{
return innerContainer;
}
// 修改 CreateDropPod 方法
private bool CreateDropPod(IntVec3 dropCell, List<Thing> contents)
{
try
{
if (contents == null || contents.Count == 0)
{
Log.Warning("[Airdrop] CreateDropPod: contents is null or empty");
return false;
}
Log.Message($"[Airdrop] Creating drop pod at {dropCell} with {contents.Count} items");
// 检查目标单元格是否有效
if (!dropCell.IsValid || !dropCell.InBounds(Map))
{
Log.Error($"[Airdrop] Invalid drop cell: {dropCell}");
return false;
}
// 创建空投舱信息 - 使用 DropPodInfo 而不是 ActiveTransporterInfo
ActiveTransporterInfo dropPodInfo = new ActiveTransporterInfo();
dropPodInfo.openDelay = 180; // 3秒后打开
dropPodInfo.leaveSlag = true;
// 创建容器并添加物品
ThingOwner container = new ThingOwner<Thing>();
foreach (Thing thing in contents)
{
if (thing != null)
{
if (!container.TryAdd(thing, true))
{
Log.Error($"[Airdrop] Failed to add {thing.Label} to drop pod");
}
else
{
Log.Message($"[Airdrop] Added {thing.Label} to drop pod");
}
}
}
if (container.Count == 0)
{
Log.Warning("[Airdrop] No items were successfully added to drop pod");
return false;
}
dropPodInfo.innerContainer = container;
// 生成空投舱
DropPodUtility.MakeDropPodAt(dropCell, Map, dropPodInfo);
Log.Message($"[Airdrop] Successfully created drop pod at {dropCell}");
return true;
}
catch (System.Exception ex)
{
Log.Error($"[Airdrop] Failed to create drop pod at {dropCell}: {ex}");
return false;
}
}
}
}