feat: 为燃料补充槽添加收容失效自毁系统和Pawn追踪功能

This commit is contained in:
2025-12-25 15:25:03 +08:00
parent 52e29f9c11
commit 2cacc468db
7 changed files with 284 additions and 46 deletions

Binary file not shown.

Binary file not shown.

View File

@@ -109,6 +109,36 @@
</deathAction>
</race>
<comps>
<li Class="ArachnaeSwarm.CompProperties_AdvancedTraining">
<trainables>
<li>
<trainable>Obedience</trainable>
<trainInstantly>true</trainInstantly>
<setWanted>true</setWanted>
</li>
<li>
<trainable>Release</trainable>
<trainInstantly>true</trainInstantly>
<setWanted>true</setWanted>
</li>
<li>
<trainable>Rescue</trainable>
<trainInstantly>true</trainInstantly>
<setWanted>true</setWanted>
</li>
<li>
<trainable>Tameness</trainable>
<trainInstantly>true</trainInstantly>
<setWanted>true</setWanted>
</li>
<li>
<trainable>Haul</trainable>
<trainInstantly>true</trainInstantly>
<setWanted>true</setWanted>
</li>
</trainables>
<disableAllSkillDecay>true</disableAllSkillDecay> <!-- 阻止这个动物的所有技能衰减 -->
</li>
<li Class="ArachnaeSwarm.CompProperties_HediffGiver">
<hediffs>
<li>ARA_HiveMindWorker</li>

View File

@@ -41,4 +41,19 @@
<ResearchManager_TotalBuildings>所有建筑:{0}</ResearchManager_TotalBuildings>
<ResearchManager_ActiveResearch>进行中研究:{0}</ResearchManager_ActiveResearch>
<ResearchManager_ProjectStatus>{0}{1}个活跃建筑 / {2}个总建筑</ResearchManager_ProjectStatus>
<!-- Gizmo_ResearchProgress.cs -->
<ARA_ResearchProgress_NoProject>未选择项目</ARA_ResearchProgress_NoProject>
<ARA_ResearchProgress_Completed>✓ 研究完成</ARA_ResearchProgress_Completed>
<ARA_ResearchProgress_Researching>⚡ 研究中...</ARA_ResearchProgress_Researching>
<ARA_ResearchProgress_Paused>⏸ 已暂停</ARA_ResearchProgress_Paused>
<ARA_ResearchProgress_SelectProject>点击选择项目</ARA_ResearchProgress_SelectProject>
<ARA_ResearchProgress_TooltipTitle>【研究蓝图解读器】</ARA_ResearchProgress_TooltipTitle>
<ARA_ResearchProgress_TooltipProject>当前项目:{0}</ARA_ResearchProgress_TooltipProject>
<ARA_ResearchProgress_TooltipProgress>进度:{0} / {1}</ARA_ResearchProgress_TooltipProgress>
<ARA_ResearchProgress_TooltipPercentage>完成度:{0}</ARA_ResearchProgress_TooltipPercentage>
<ARA_ResearchProgress_TooltipCompleted>研究已完成!</ARA_ResearchProgress_TooltipCompleted>
<ARA_ResearchProgress_TooltipTimeRemaining>预计剩余时间:{0}</ARA_ResearchProgress_TooltipTimeRemaining>
<ARA_ResearchProgress_TooltipPaused>研究已暂停(无电力或其他原因)</ARA_ResearchProgress_TooltipPaused>
<ARA_ResearchProgress_TooltipNoProject>尚未选择研究项目。\n点击"选择研究项目"按钮开始。</ARA_ResearchProgress_TooltipNoProject>
</LanguageData>

View File

@@ -572,7 +572,8 @@ namespace ArachnaeSwarm
{
yield return gizmo;
}
// 选择殖民者的操作
// 合并后的统一按钮:选择人员
var command_Action = new Command_Action
{
defaultLabel = "InsertPerson".Translate() + "...",
@@ -583,10 +584,17 @@ namespace ArachnaeSwarm
List<FloatMenuOption> list = new List<FloatMenuOption>();
foreach (Pawn p in base.Map.mapPawns.AllPawnsSpawned)
{
if (p != null && !p.Destroyed && CanAcceptPawn(p).Accepted)
{
list.Add(new FloatMenuOption(p.LabelCap, () => SelectPawn(p), p, Color.white));
}
if (p == null || p.Destroyed || !CanAcceptPawn(p).Accepted)
continue;
// 根据 pawn 类型显示不同的标签
string label = p.LabelCap;
if (p.IsPrisonerOfColony)
label += " (" + "Prisoner".Translate() + ")";
else if (p.IsSlaveOfColony)
label += " (" + "Slave".Translate() + ")";
list.Add(new FloatMenuOption(label, () => HandlePawnSelection(p), p, Color.white));
}
if (!list.Any())
{
@@ -600,49 +608,26 @@ namespace ArachnaeSwarm
command_Action.Disable("NoViablePawns".Translate());
}
yield return command_Action;
// 指派搬运囚犯/奴隶的操作
var command_CarryPrisoner = new Command_Action
}
/// <summary>
/// 处理 pawn 选择:如果是殖民者则直接走进去,如果是囚犯/奴隶则显示搬运者选择菜单
/// </summary>
private void HandlePawnSelection(Pawn pawn)
{
if (pawn == null || pawn.Destroyed)
return;
// 如果是囚犯或奴隶,需要选择搬运者
if (pawn.IsPrisonerOfColony || pawn.IsSlaveOfColony)
{
defaultLabel = "AssignCarryPrisoner".Translate() + "...",
defaultDesc = "AssignCarryPrisonerDesc".Translate(),
icon = ContentFinder<Texture2D>.Get("UI/Commands/Attack"),
action = () =>
{
List<FloatMenuOption> list = new List<FloatMenuOption>();
// 获取所有可接受的囚犯和奴隶
foreach (Pawn p in base.Map.mapPawns.AllPawnsSpawned)
{
if (p != null && !p.Destroyed && CanAcceptPawn(p).Accepted && (p.IsPrisonerOfColony || p.IsSlaveOfColony))
{
list.Add(new FloatMenuOption(
p.LabelCap + " (" + (p.IsPrisonerOfColony ? "Prisoner" : "Slave") + ")",
() => AssignCarrierForPrisoner(p),
p,
Color.white
));
}
}
if (!list.Any())
{
list.Add(new FloatMenuOption("NoPrisonersOrSlaves".Translate(), null));
}
Find.WindowStack.Add(new FloatMenu(list));
}
};
// 检查是否有可用的囚犯/奴隶
bool hasPrisonersOrSlaves = base.Map.mapPawns.AllPawnsSpawned
.Any(p => p != null && !p.Destroyed && CanAcceptPawn(p).Accepted && (p.IsPrisonerOfColony || p.IsSlaveOfColony));
if (!hasPrisonersOrSlaves)
{
command_CarryPrisoner.Disable("NoPrisonersOrSlaves".Translate());
AssignCarrierForPrisoner(pawn);
}
else
{
// 殖民者可以自己走进去
SelectPawn(pawn);
}
yield return command_CarryPrisoner;
}
public override string GetInspectString()

View File

@@ -249,6 +249,9 @@ namespace ArachnaeSwarm
yield return gizmo;
}
// 研究进度 Gizmo
yield return new Gizmo_ResearchProgress(this);
// 选择研究按钮
var selectCmd = new Command_Action();
selectCmd.defaultLabel = "ResearchBlueprintReader_SelectProject".Translate();

View File

@@ -0,0 +1,205 @@
// File: Gizmo_ResearchProgress.cs
// 研究蓝图解读器的研究进度 Gizmo
using RimWorld;
using UnityEngine;
using Verse;
namespace ArachnaeSwarm
{
[StaticConstructorOnStartup]
public class Gizmo_ResearchProgress : Gizmo
{
private readonly Building_ResearchBlueprintReader reader;
// 尺寸常量
private const float Width = 180f;
private const float GizmoHeight = 75f;
private const float Padding = 6f;
private const float BarHeight = 18f;
// 材质颜色
private static readonly Texture2D ProgressBarTex = SolidColorMaterials.NewSolidColorTexture(new Color(0.3f, 0.6f, 0.9f, 0.9f));
private static readonly Texture2D CompletedBarTex = SolidColorMaterials.NewSolidColorTexture(new Color(0.2f, 0.8f, 0.3f, 0.9f));
private static readonly Texture2D PausedBarTex = SolidColorMaterials.NewSolidColorTexture(new Color(0.7f, 0.7f, 0.3f, 0.9f));
private static readonly Texture2D EmptyBarTex = SolidColorMaterials.NewSolidColorTexture(new Color(0.15f, 0.15f, 0.15f, 0.8f));
public Gizmo_ResearchProgress(Building_ResearchBlueprintReader reader)
{
this.reader = reader;
Order = -130f; // 在其他 Gizmo 之后
}
public override float GetWidth(float maxWidth)
{
return Mathf.Min(Width, maxWidth);
}
public override GizmoResult GizmoOnGUI(Vector2 topLeft, float maxWidth, GizmoRenderParms parms)
{
Rect rect = new Rect(topLeft.x, topLeft.y, GetWidth(maxWidth), GizmoHeight);
Widgets.DrawWindowBackground(rect);
Rect innerRect = rect.ContractedBy(Padding);
float curY = innerRect.y;
var storedResearch = reader.StoredResearch;
// === 第一行:标题 ===
Text.Font = GameFont.Small;
Text.Anchor = TextAnchor.MiddleLeft;
GUI.color = Color.white;
Rect titleRect = new Rect(innerRect.x, curY, innerRect.width, 18f);
string title;
if (storedResearch != null)
{
title = storedResearch.LabelCap.RawText ?? storedResearch.defName;
// 截断过长的标题
title = title.Truncate(innerRect.width - 4f);
}
else
{
title = "ARA_ResearchProgress_NoProject".Translate();
}
Widgets.Label(titleRect, title);
curY += 20f;
// === 第二行:状态信息 ===
Text.Font = GameFont.Tiny;
Text.Anchor = TextAnchor.MiddleLeft;
Rect statusRect = new Rect(innerRect.x, curY, innerRect.width, 14f);
if (storedResearch != null)
{
string statusText;
if (storedResearch.IsFinished)
{
GUI.color = new Color(0.3f, 0.9f, 0.3f);
statusText = "ARA_ResearchProgress_Completed".Translate();
}
else if (reader.IsResearching)
{
GUI.color = new Color(0.5f, 0.8f, 1f);
statusText = "ARA_ResearchProgress_Researching".Translate();
}
else
{
GUI.color = new Color(0.9f, 0.7f, 0.2f);
statusText = "ARA_ResearchProgress_Paused".Translate();
}
Widgets.Label(statusRect, statusText);
}
else
{
GUI.color = new Color(0.5f, 0.5f, 0.5f);
Widgets.Label(statusRect, "ARA_ResearchProgress_SelectProject".Translate());
}
curY += 15f;
// === 第三行:进度条 ===
GUI.color = Color.white;
Rect barRect = new Rect(innerRect.x, curY, innerRect.width, BarHeight);
// 背景
GUI.DrawTexture(barRect, EmptyBarTex);
if (storedResearch != null)
{
float percentage = storedResearch.baseCost > 0
? Mathf.Clamp01(reader.Progress / storedResearch.baseCost)
: 0f;
// 根据状态选择颜色
Texture2D barTex;
if (storedResearch.IsFinished)
barTex = CompletedBarTex;
else if (reader.IsResearching)
barTex = ProgressBarTex;
else
barTex = PausedBarTex;
// 填充条
Rect fillRect = new Rect(barRect.x, barRect.y, barRect.width * percentage, barRect.height);
GUI.DrawTexture(fillRect, barTex);
// 百分比文字
Text.Font = GameFont.Tiny;
Text.Anchor = TextAnchor.MiddleCenter;
GUI.color = Color.white;
string progressText = $"{reader.Progress:F0} / {storedResearch.baseCost:F0}";
Widgets.Label(barRect, progressText);
}
else
{
// 无项目时显示空状态
Text.Font = GameFont.Tiny;
Text.Anchor = TextAnchor.MiddleCenter;
GUI.color = new Color(0.5f, 0.5f, 0.5f);
Widgets.Label(barRect, "---");
}
// === 工具提示 ===
if (Mouse.IsOver(rect))
{
Widgets.DrawHighlight(rect);
TooltipHandler.TipRegion(rect, GetTooltip());
}
GUI.color = Color.white;
Text.Anchor = TextAnchor.UpperLeft;
Text.Font = GameFont.Small;
return new GizmoResult(GizmoState.Clear);
}
private string GetTooltip()
{
var sb = new System.Text.StringBuilder();
var storedResearch = reader.StoredResearch;
sb.AppendLine("ARA_ResearchProgress_TooltipTitle".Translate());
sb.AppendLine();
if (storedResearch != null)
{
sb.AppendLine("ARA_ResearchProgress_TooltipProject".Translate(storedResearch.LabelCap));
sb.AppendLine("ARA_ResearchProgress_TooltipProgress".Translate(
reader.Progress.ToString("F0"),
storedResearch.baseCost.ToString("F0")));
float percentage = storedResearch.baseCost > 0
? reader.Progress / storedResearch.baseCost
: 0f;
sb.AppendLine("ARA_ResearchProgress_TooltipPercentage".Translate(percentage.ToStringPercent()));
sb.AppendLine();
if (storedResearch.IsFinished)
{
sb.AppendLine("<color=green>" + "ARA_ResearchProgress_TooltipCompleted".Translate() + "</color>");
}
else if (reader.IsResearching)
{
// 计算剩余时间
float remaining = storedResearch.baseCost - reader.Progress;
var ext = reader.def.GetModExtension<ResearchBlueprintReaderExtension>();
float speed = ext?.researchSpeed ?? 10f;
int ticksRemaining = Mathf.CeilToInt(remaining / speed * 60f);
string timeStr = ticksRemaining.ToStringTicksToPeriod(allowSeconds: true, shortForm: true);
sb.AppendLine("<color=#88ccff>" + "ARA_ResearchProgress_TooltipTimeRemaining".Translate(timeStr) + "</color>");
}
else
{
sb.AppendLine("<color=yellow>" + "ARA_ResearchProgress_TooltipPaused".Translate() + "</color>");
}
}
else
{
sb.AppendLine("ARA_ResearchProgress_TooltipNoProject".Translate());
}
return sb.ToString().TrimEndNewlines();
}
}
}