Files
ArachnaeSwarm/Source/ArachnaeSwarm/Buildings/Building_ResearchBlueprintReader/Building_ResearchBlueprintReader.cs
2025-12-17 12:00:45 +08:00

599 lines
22 KiB
C#

// File: Buildings/Building_ResearchBlueprintReader.cs
using RimWorld;
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using Verse;
namespace ArachnaeSwarm
{
public class Building_ResearchBlueprintReader : Building
{
// 当前正在研究的科技
private ResearchProjectDef currentResearch;
// 当前研究进度
private float progress;
// 自动研究标志
private bool autoResearch;
// 储存的科技
private ResearchProjectDef storedResearch;
// 锁定信息
private ResearchBlueprintLockInfo lockInfo;
// 管理器引用
private ResearchBlueprintReaderManager manager;
// 电力组件
private CompPowerTrader powerComp;
public ResearchProjectDef CurrentResearch => currentResearch;
public float Progress => progress;
public float ProgressPercent => currentResearch != null ? progress / currentResearch.baseCost : 0f;
public ResearchProjectDef StoredResearch => storedResearch;
public bool IsLocked => storedResearch != null;
public ResearchBlueprintReaderManager Manager
{
get => manager;
set => manager = value;
}
// 获取研究速度
private float ResearchSpeed
{
get
{
var ext = this.def.GetModExtension<ResearchBlueprintReaderExtension>();
return ext?.researchSpeed ?? 10f;
}
}
// 是否允许储存科技
private bool CanStoreResearch
{
get
{
var ext = this.def.GetModExtension<ResearchBlueprintReaderExtension>();
return ext?.canStoreResearch ?? true;
}
}
public override void ExposeData()
{
base.ExposeData();
Scribe_Defs.Look(ref currentResearch, "currentResearch");
Scribe_Values.Look(ref progress, "progress", 0f);
Scribe_Values.Look(ref autoResearch, "autoResearch", false);
Scribe_Defs.Look(ref storedResearch, "storedResearch");
Scribe_Deep.Look(ref lockInfo, "lockInfo");
if (Scribe.mode == LoadSaveMode.LoadingVars)
{
// 加载时重建与管理器的连接
manager = ResearchBlueprintReaderManager.Instance;
if (manager != null)
{
manager.RegisterReader(this);
}
}
}
public override void SpawnSetup(Map map, bool respawningAfterLoad)
{
base.SpawnSetup(map, respawningAfterLoad);
// 获取管理器
manager = ResearchBlueprintReaderManager.Instance;
if (manager != null)
{
manager.RegisterReader(this);
}
// 获取电力组件
powerComp = GetComp<CompPowerTrader>();
Log.Message($"[ResearchBlueprintReader] Spawned at {Position}, Manager: {manager != null}");
}
public override void Destroy(DestroyMode mode = DestroyMode.Vanish)
{
// 如果建筑储存了科技,先释放
if (storedResearch != null)
{
if (manager != null)
{
manager.ReleaseStoredResearch(storedResearch);
}
else
{
// 如果没有管理器,直接移除科技
Utilities.ResearchRemover.RemoveResearchProject(storedResearch, false);
}
}
// 注销建筑
if (manager != null)
{
manager.UnregisterReader(this);
}
base.Destroy(mode);
}
protected override void Tick()
{
base.Tick();
// 检查电力
bool hasPower = powerComp == null || powerComp.PowerOn;
// 如果启用了自动研究且有研究项目,则增加进度
if (hasPower && autoResearch && currentResearch != null && !currentResearch.IsFinished && !IsLocked)
{
float speed = ResearchSpeed;
// 应用电力效率
if (powerComp != null)
{
var ext = this.def.GetModExtension<ResearchBlueprintReaderExtension>();
if (ext != null)
{
float efficiency = powerComp.PowerNet.CurrentStoredEnergy() / powerComp.PowerNet.batteryComps.Sum(b => b.Props.storedEnergyMax);
speed *= Mathf.Lerp(0.5f, 1f, efficiency);
}
}
AddResearchProgress(speed / 60f); // 转换为每Tick
// 检查是否完成
if (progress >= currentResearch.baseCost)
{
CompleteCurrentResearch();
}
}
}
private void AddResearchProgress(float amount)
{
progress += amount;
// 将进度添加到研究管理器
Find.ResearchManager.AddProgress(currentResearch, amount);
// 更新进度显示
if (Find.TickManager.TicksGame % 60 == 0) // 每秒更新一次视觉效果
{
// 可以添加一些视觉效果,比如闪烁灯光
}
}
private void CompleteCurrentResearch()
{
if (currentResearch != null && !currentResearch.IsFinished)
{
Log.Message($"[ResearchBlueprintReader] Completing research: {currentResearch.defName} at {Position}");
if (CanStoreResearch && manager != null)
{
// 请求管理器处理完成和储存
manager.RequestResearchCompletion(this, currentResearch);
}
else
{
// 如果不能储存,直接完成
Find.ResearchManager.FinishProject(currentResearch, doCompletionDialog: false);
Messages.Message($"研究完成: {currentResearch.LabelCap}",
MessageTypeDefOf.PositiveEvent);
// 重置状态
currentResearch = null;
progress = 0f;
autoResearch = false;
}
}
}
/// <summary>
/// 锁定建筑以储存科技(由管理器调用)
/// </summary>
public void LockForStorage(ResearchProjectDef project, ResearchBlueprintLockInfo info)
{
if (project == null || info == null) return;
storedResearch = project;
lockInfo = info;
// 停止当前研究
currentResearch = null;
progress = 0f;
autoResearch = false;
Log.Message($"[ResearchBlueprintReader] Locked for storing {project.defName}");
}
/// <summary>
/// 解锁建筑(释放储存的科技)
/// </summary>
public void UnlockBuilding()
{
if (storedResearch != null)
{
var project = storedResearch;
storedResearch = null;
lockInfo = null;
// 移除科技完成状态
Utilities.ResearchRemover.RemoveResearchProject(project, false);
Messages.Message($"建筑已解锁,科技已移除: {project.LabelCap}",
MessageTypeDefOf.NeutralEvent);
Log.Message($"[ResearchBlueprintReader] Unlocked and removed {project.defName}");
}
}
public void StartResearch(ResearchProjectDef project)
{
if (IsLocked)
{
Messages.Message("建筑已锁定储存科技,无法开始新研究",
MessageTypeDefOf.RejectInput);
return;
}
if (project == null || project.IsFinished || project.techprintCount <= 0)
return;
// 检查科技是否已被其他建筑储存
if (manager != null && manager.IsResearchStored(project))
{
Messages.Message($"科技已被其他建筑储存: {project.LabelCap}",
MessageTypeDefOf.RejectInput);
return;
}
currentResearch = project;
progress = Find.ResearchManager.GetProgress(project);
Messages.Message($"开始研究: {project.LabelCap}",
MessageTypeDefOf.NeutralEvent);
}
public void StopResearch()
{
if (currentResearch != null)
{
Messages.Message($"停止研究: {currentResearch.LabelCap}",
MessageTypeDefOf.NeutralEvent);
currentResearch = null;
progress = 0f;
autoResearch = false;
}
}
public override IEnumerable<Gizmo> GetGizmos()
{
foreach (Gizmo gizmo in base.GetGizmos())
{
yield return gizmo;
}
// 如果已锁定,显示解锁按钮
if (IsLocked)
{
var unlockCmd = new Command_Action();
unlockCmd.defaultLabel = "解锁建筑";
unlockCmd.defaultDesc = "释放储存的科技,允许重新研究";
unlockCmd.icon = ContentFinder<Texture2D>.Get("UI/Designators/Unlock", false);
unlockCmd.action = delegate
{
if (manager != null)
{
manager.ReleaseStoredResearch(storedResearch);
storedResearch = null;
lockInfo = null;
}
};
yield return unlockCmd;
// 显示储存信息
var infoCmd = new Command_Action();
infoCmd.defaultLabel = $"储存: {storedResearch.LabelCap}";
infoCmd.defaultDesc = "点击查看详细信息";
infoCmd.icon = ContentFinder<Texture2D>.Get("UI/Designators/Info", false);
infoCmd.action = delegate
{
Messages.Message($"此建筑储存着: {storedResearch.LabelCap}\n" +
$"描述: {storedResearch.description.StripTags()}",
MessageTypeDefOf.NeutralEvent);
};
yield return infoCmd;
yield break; // 锁定状态下不显示其他按钮
}
// 选择研究按钮
var selectCmd = new Command_Action();
selectCmd.defaultLabel = "选择研究项目";
selectCmd.defaultDesc = "选择要自动研究的科技项目";
selectCmd.icon = ContentFinder<Texture2D>.Get("UI/Designators/Research", false);
selectCmd.action = delegate
{
ShowResearchMenu();
};
yield return selectCmd;
// 如果已有研究项目,显示停止按钮
if (currentResearch != null)
{
var stopCmd = new Command_Action();
stopCmd.defaultLabel = "停止研究";
stopCmd.defaultDesc = "停止当前的研究项目";
stopCmd.icon = ContentFinder<Texture2D>.Get("UI/Designators/Cancel", false);
stopCmd.action = StopResearch;
yield return stopCmd;
}
// 自动研究切换按钮
var autoCmd = new Command_Toggle();
autoCmd.defaultLabel = "自动研究";
autoCmd.defaultDesc = "开启/关闭自动研究功能";
autoCmd.icon = ContentFinder<Texture2D>.Get("UI/Widgets/CheckOn", false);
autoCmd.isActive = () => autoResearch;
autoCmd.toggleAction = delegate
{
autoResearch = !autoResearch;
Messages.Message($"自动研究: {(autoResearch ? "" : "")}",
MessageTypeDefOf.NeutralEvent);
};
yield return autoCmd;
// 调试按钮:快速完成研究
if (DebugSettings.godMode && currentResearch != null)
{
var debugCmd = new Command_Action();
debugCmd.defaultLabel = "调试: 快速完成";
debugCmd.defaultDesc = "立即完成当前研究";
debugCmd.icon = ContentFinder<Texture2D>.Get("UI/Designators/Dev", false);
debugCmd.action = delegate
{
progress = currentResearch.baseCost;
CompleteCurrentResearch();
};
yield return debugCmd;
}
}
private void ShowResearchMenu()
{
try
{
var araTab = DefDatabase<ResearchTabDef>.GetNamedSilentFail("ARA_ResearchTab");
if (araTab == null)
{
Messages.Message("ARA_ResearchTab未找到", MessageTypeDefOf.RejectInput);
return;
}
var availableProjects = DefDatabase<ResearchProjectDef>.AllDefsListForReading
.Where(p => p.tab == araTab && p.techprintCount > 0 && !p.IsFinished)
.ToList();
if (availableProjects.Count == 0)
{
Messages.Message("没有可用的科技项目", MessageTypeDefOf.NeutralEvent);
return;
}
List<FloatMenuOption> options = new List<FloatMenuOption>();
var sortedProjects = availableProjects.OrderBy(p => p.defName).ToList();
foreach (var project in sortedProjects)
{
bool allPrerequisitesMet = AreAllPrerequisitesCompleted(project);
// 检查是否已被储存
bool isStored = manager != null && manager.IsResearchStored(project);
string label = project.LabelCap.RawText ?? project.defName;
float currentProgress = Find.ResearchManager.GetProgress(project);
if (currentProgress > 0)
label += $" ({currentProgress:F0}/{project.baseCost:F0})";
if (isStored)
{
label = $"<color=#ff9900>{label} [已储存]</color>";
}
else if (!allPrerequisitesMet)
{
bool missingHidden = HasMissingHiddenPrerequisites(project);
if (missingHidden)
label = $"<color=#ff9900>{label} [需要隐藏前置]</color>";
else
label = $"<color=#999999>{label} [需要前置条件]</color>";
}
var option = new FloatMenuOption(label, () => StartResearch(project))
{
Disabled = !allPrerequisitesMet || isStored,
tooltip = GetProjectTooltip(project, allPrerequisitesMet, isStored)
};
options.Add(option);
}
if (options.Count > 0)
{
Find.WindowStack.Add(new FloatMenu(options));
}
}
catch (Exception ex)
{
Log.Error($"[ResearchBlueprintReader] Error in ShowResearchMenu: {ex}");
Messages.Message($"显示研究菜单时出错: {ex.Message}",
MessageTypeDefOf.NegativeEvent);
}
}
private bool AreAllPrerequisitesCompleted(ResearchProjectDef project)
{
// 检查普通前置
if (project.prerequisites != null)
{
foreach (var prereq in project.prerequisites)
{
if (!prereq.IsFinished)
return false;
}
}
// 检查隐藏前置
if (project.hiddenPrerequisites != null)
{
foreach (var hiddenPrereq in project.hiddenPrerequisites)
{
if (hiddenPrereq != null && !hiddenPrereq.IsFinished)
return false;
}
}
return true;
}
private bool HasMissingHiddenPrerequisites(ResearchProjectDef project)
{
if (project.hiddenPrerequisites != null)
{
foreach (var hiddenPrereq in project.hiddenPrerequisites)
{
if (hiddenPrereq != null && !hiddenPrereq.IsFinished)
return true;
}
}
return false;
}
private string GetProjectTooltip(ResearchProjectDef project, bool prerequisitesMet, bool isStored)
{
var builder = new System.Text.StringBuilder();
builder.AppendLine(project.description.StripTags());
builder.AppendLine();
builder.AppendLine($"成本: {project.baseCost}");
builder.AppendLine($"所需蓝图数量: {project.techprintCount}");
if (isStored)
{
builder.AppendLine();
builder.AppendLine("<color=#ff9900>⚠ 此科技已被其他建筑储存</color>");
var storageBuilding = manager?.GetStorageBuildingFor(project);
if (storageBuilding != null)
{
builder.AppendLine($"储存建筑: {storageBuilding.Position}");
}
}
// 检查所有未完成的前置(包括隐藏的)
List<ResearchProjectDef> missingPrereqs = new List<ResearchProjectDef>();
// 普通前置
if (project.prerequisites != null)
{
foreach (var prereq in project.prerequisites)
{
if (!prereq.IsFinished)
missingPrereqs.Add(prereq);
}
}
// 隐藏前置
if (project.hiddenPrerequisites != null)
{
foreach (var hiddenPrereq in project.hiddenPrerequisites)
{
if (hiddenPrereq != null && !hiddenPrereq.IsFinished)
missingPrereqs.Add(hiddenPrereq);
}
}
if (missingPrereqs.Count > 0)
{
builder.AppendLine();
builder.AppendLine("<color=#ff9999>缺失的前置科技:</color>");
foreach (var prereq in missingPrereqs)
{
string label = prereq.LabelCap.RawText ?? prereq.defName;
bool isHidden = project.hiddenPrerequisites != null &&
project.hiddenPrerequisites.Contains(prereq);
if (isHidden)
builder.AppendLine($" • {label} <color=#ffcc00>[隐藏前置]</color>");
else
builder.AppendLine($" • {label}");
}
}
return builder.ToString();
}
public override string GetInspectString()
{
var builder = new System.Text.StringBuilder(base.GetInspectString());
if (builder.Length > 0)
builder.AppendLine();
if (IsLocked)
{
builder.AppendLine($"<color=#ff9900>🔒 储存科技: {storedResearch.LabelCap}</color>");
if (lockInfo != null)
{
int days = lockInfo.storeTime / 60000;
builder.AppendLine($"储存时间: {days}天");
}
}
else if (currentResearch != null)
{
builder.AppendLine($"正在研究: {currentResearch.LabelCap}");
builder.AppendLine($"进度: {progress:F0}/{currentResearch.baseCost:F0} ({ProgressPercent:P0})");
builder.Append($"自动研究: {(autoResearch ? "" : "")}");
// 显示研究速度
builder.AppendLine();
builder.Append($"研究速度: {ResearchSpeed:F1}/秒");
}
else
{
builder.Append("未选择研究项目");
}
return builder.ToString().TrimEndNewlines();
}
// 供其他系统调用的方法
public bool IsResearchingProject(ResearchProjectDef project)
{
return currentResearch == project;
}
public bool CanResearchProject(ResearchProjectDef project)
{
if (project == null) return false;
if (project.tab == null || project.tab.defName != "ARA_ResearchTab") return false;
if (project.techprintCount <= 0) return false;
if (project.IsFinished) return false;
if (manager != null && manager.IsResearchStored(project)) return false;
return AreAllPrerequisitesCompleted(project);
}
}
}