599 lines
22 KiB
C#
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);
|
|
}
|
|
}
|
|
}
|