diff --git a/1.6/1.6/Assemblies/ArachnaeSwarm.dll b/1.6/1.6/Assemblies/ArachnaeSwarm.dll index d4b3de2..5425d15 100644 Binary files a/1.6/1.6/Assemblies/ArachnaeSwarm.dll and b/1.6/1.6/Assemblies/ArachnaeSwarm.dll differ diff --git a/1.6/1.6/Assemblies/ArachnaeSwarm.pdb b/1.6/1.6/Assemblies/ArachnaeSwarm.pdb index e8efa02..a4c9347 100644 Binary files a/1.6/1.6/Assemblies/ArachnaeSwarm.pdb and b/1.6/1.6/Assemblies/ArachnaeSwarm.pdb differ diff --git a/1.6/1.6/Defs/ThingDef_Races/ARA_RaceBaseSwarm.xml b/1.6/1.6/Defs/ThingDef_Races/ARA_RaceBaseSwarm.xml index 91e2bc1..fd10bd2 100644 --- a/1.6/1.6/Defs/ThingDef_Races/ARA_RaceBaseSwarm.xml +++ b/1.6/1.6/Defs/ThingDef_Races/ARA_RaceBaseSwarm.xml @@ -109,6 +109,36 @@ +
  • + +
  • + Obedience + true + true +
  • +
  • + Release + true + true +
  • +
  • + Rescue + true + true +
  • +
  • + Tameness + true + true +
  • +
  • + Haul + true + true +
  • + + true +
  • ARA_HiveMindWorker
  • diff --git a/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/Building_ResearchBlueprintReader.xml b/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/Building_ResearchBlueprintReader.xml index 2475c63..e78ab59 100644 --- a/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/Building_ResearchBlueprintReader.xml +++ b/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/Building_ResearchBlueprintReader.xml @@ -41,4 +41,19 @@ 所有建筑:{0} 进行中研究:{0} {0}:{1}个活跃建筑 / {2}个总建筑 + + + 未选择项目 + ✓ 研究完成 + ⚡ 研究中... + ⏸ 已暂停 + 点击选择项目 + 【研究蓝图解读器】 + 当前项目:{0} + 进度:{0} / {1} + 完成度:{0} + 研究已完成! + 预计剩余时间:{0} + 研究已暂停(无电力或其他原因) + 尚未选择研究项目。\n点击"选择研究项目"按钮开始。 diff --git a/Source/ArachnaeSwarm/Buildings/Building_RefuelingVat/Building_RefuelingVat.cs b/Source/ArachnaeSwarm/Buildings/Building_RefuelingVat/Building_RefuelingVat.cs index be1f2cd..d183cb7 100644 --- a/Source/ArachnaeSwarm/Buildings/Building_RefuelingVat/Building_RefuelingVat.cs +++ b/Source/ArachnaeSwarm/Buildings/Building_RefuelingVat/Building_RefuelingVat.cs @@ -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 list = new List(); 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 + } + + /// + /// 处理 pawn 选择:如果是殖民者则直接走进去,如果是囚犯/奴隶则显示搬运者选择菜单 + /// + private void HandlePawnSelection(Pawn pawn) + { + if (pawn == null || pawn.Destroyed) + return; + + // 如果是囚犯或奴隶,需要选择搬运者 + if (pawn.IsPrisonerOfColony || pawn.IsSlaveOfColony) { - defaultLabel = "AssignCarryPrisoner".Translate() + "...", - defaultDesc = "AssignCarryPrisonerDesc".Translate(), - icon = ContentFinder.Get("UI/Commands/Attack"), - action = () => - { - List list = new List(); - - // 获取所有可接受的囚犯和奴隶 - 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() diff --git a/Source/ArachnaeSwarm/Buildings/Building_ResearchBlueprintReader/Building_ResearchBlueprintReader.cs b/Source/ArachnaeSwarm/Buildings/Building_ResearchBlueprintReader/Building_ResearchBlueprintReader.cs index 005d7c3..6f39215 100644 --- a/Source/ArachnaeSwarm/Buildings/Building_ResearchBlueprintReader/Building_ResearchBlueprintReader.cs +++ b/Source/ArachnaeSwarm/Buildings/Building_ResearchBlueprintReader/Building_ResearchBlueprintReader.cs @@ -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(); diff --git a/Source/ArachnaeSwarm/Buildings/Building_ResearchBlueprintReader/Gizmo_ResearchProgress.cs b/Source/ArachnaeSwarm/Buildings/Building_ResearchBlueprintReader/Gizmo_ResearchProgress.cs new file mode 100644 index 0000000..a22f130 --- /dev/null +++ b/Source/ArachnaeSwarm/Buildings/Building_ResearchBlueprintReader/Gizmo_ResearchProgress.cs @@ -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("" + "ARA_ResearchProgress_TooltipCompleted".Translate() + ""); + } + else if (reader.IsResearching) + { + // 计算剩余时间 + float remaining = storedResearch.baseCost - reader.Progress; + var ext = reader.def.GetModExtension(); + float speed = ext?.researchSpeed ?? 10f; + int ticksRemaining = Mathf.CeilToInt(remaining / speed * 60f); + string timeStr = ticksRemaining.ToStringTicksToPeriod(allowSeconds: true, shortForm: true); + + sb.AppendLine("" + "ARA_ResearchProgress_TooltipTimeRemaining".Translate(timeStr) + ""); + } + else + { + sb.AppendLine("" + "ARA_ResearchProgress_TooltipPaused".Translate() + ""); + } + } + else + { + sb.AppendLine("ARA_ResearchProgress_TooltipNoProject".Translate()); + } + + return sb.ToString().TrimEndNewlines(); + } + } +}