diff --git a/1.6/1.6/Assemblies/ArachnaeSwarm.dll b/1.6/1.6/Assemblies/ArachnaeSwarm.dll
index 903bfd1..ff0850c 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 e19bbea..527b991 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/Languages/ChineseSimplified (简体中文)/Keyed/ARA_Building_Ootheca.xml b/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/ARA_Building_Ootheca.xml
index 9547b6b..2811907 100644
--- a/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/ARA_Building_Ootheca.xml
+++ b/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/ARA_Building_Ootheca.xml
@@ -227,4 +227,22 @@
等待营养液...
已消耗
+
+
+ 选择孵化目标...
+ 品质:
+ 进度:
+ 点击上方选择目标
+ 需要完成研究
+ 幼虫激活中...
+ 幼虫赶路中...
+ 天
+ 【孵化中】
+ 目标: {0}
+ 进度: {0}
+ 品质: {0}{1}
+ 剩余: {0}
+ 【就绪】
+ 孵化时间: {0}
+ 【未选择目标】\n点击标题选择孵化目标
diff --git a/Source/ArachnaeSwarm/Building_Comps/ARA_CompInteractiveProducer/CompQueuedInteractiveProducerWithFlux.cs b/Source/ArachnaeSwarm/Building_Comps/ARA_CompInteractiveProducer/CompQueuedInteractiveProducerWithFlux.cs
index e176a06..8df50e8 100644
--- a/Source/ArachnaeSwarm/Building_Comps/ARA_CompInteractiveProducer/CompQueuedInteractiveProducerWithFlux.cs
+++ b/Source/ArachnaeSwarm/Building_Comps/ARA_CompInteractiveProducer/CompQueuedInteractiveProducerWithFlux.cs
@@ -67,7 +67,7 @@ namespace ArachnaeSwarm
}
}
- public class CompQueuedInteractiveProducerWithFlux : ThingComp, IFluxController, ILarvaActivatable
+ public class CompQueuedInteractiveProducerWithFlux : ThingComp, IFluxController, ILarvaActivatable, IOrderGizmoProvider
{
// === 通量系统字段 ===
private float neutronFlux = 0.5f;
@@ -79,8 +79,10 @@ namespace ArachnaeSwarm
// === 幼虫管理 ===
private List assignedLarvae = new List();
- // === UI 状态(供 Gizmo 使用,不保存) ===
- public float GizmoScrollPosition = 0f;
+ // === IOrderGizmoProvider 实现 ===
+ public float GizmoScrollPosition { get; set; } = 0f;
+ public int QueueLimit => Props.productionQueueLimit;
+ void IOrderGizmoProvider.ShowOrderMenu() => ShowOrderMenuPublic();
// === 组件引用 ===
private CompRefuelableNutrition _fuelComp;
@@ -160,18 +162,19 @@ namespace ArachnaeSwarm
public void RemoveOrderByIndex(int index) { if (index >= 0 && index < orders.Count) orders.RemoveAt(index); }
// === Gizmo 用的订单信息 ===
- public List GetOrdersForGizmo()
+ public List GetOrdersForGizmo()
{
- var result = new List();
+ var result = new List();
foreach (var order in orders)
{
- result.Add(new OrderDisplayInfo
+ result.Add(new PawnOrderDisplayInfo
{
label = order.process?.thingDef?.LabelCap ?? "?",
status = order.status,
- productionProgress = GetProgress(order),
+ progress = GetProgress(order),
qualityProgress = order.QualityPercent,
- estimatedQuality = GetQualityCategory(order).GetLabel()
+ estimatedQuality = GetQualityCategory(order).GetLabel(),
+ remainingTime = ""
});
}
return result;
@@ -394,7 +397,7 @@ namespace ArachnaeSwarm
public override IEnumerable CompGetGizmosExtra()
{
yield return new Gizmo_NeutronFlux(this) { Order = -150f };
- yield return new Gizmo_DualProgressBar(this) { Order = -140f };
+ yield return new Gizmo_PawnProgressBar(this) { Order = -140f };
if (orders.Count < Props.productionQueueLimit)
{
diff --git a/Source/ArachnaeSwarm/Building_Comps/ARA_SpawnPawnFromList/CompQueuedPawnSpawnerWithFlux.cs b/Source/ArachnaeSwarm/Building_Comps/ARA_SpawnPawnFromList/CompQueuedPawnSpawnerWithFlux.cs
index d7c0b78..88eca79 100644
--- a/Source/ArachnaeSwarm/Building_Comps/ARA_SpawnPawnFromList/CompQueuedPawnSpawnerWithFlux.cs
+++ b/Source/ArachnaeSwarm/Building_Comps/ARA_SpawnPawnFromList/CompQueuedPawnSpawnerWithFlux.cs
@@ -80,7 +80,7 @@ namespace ArachnaeSwarm
}
}
- public class CompQueuedPawnSpawnerWithFlux : ThingComp, IFluxController, ILarvaActivatable
+ public class CompQueuedPawnSpawnerWithFlux : ThingComp, IFluxController, ILarvaActivatable, IOrderGizmoProvider
{
// === 通量系统字段 ===
private float neutronFlux = 0.5f;
@@ -93,7 +93,7 @@ namespace ArachnaeSwarm
private List assignedLarvae = new List();
// === UI 状态(供 Gizmo 使用,不保存) ===
- public float GizmoScrollPosition = 0f;
+ public float GizmoScrollPosition { get; set; } = 0f;
public string LarvaStatusText = null; // 幼虫状态文本
// === 组件引用 ===
@@ -161,6 +161,10 @@ namespace ArachnaeSwarm
public int WaitingForLarvaCount => orders.Count(o => o.status == OrderStatus.WaitingForLarva);
public int IncubatingCount => orders.Count(o => o.status == OrderStatus.Incubating);
+
+ // === IOrderGizmoProvider 实现 ===
+ public int QueueLimit => Props.productionQueueLimit;
+ void IOrderGizmoProvider.ShowOrderMenu() => ShowOrderMenuPublic();
// === Gizmo 用的订单信息 ===
public List GetOrdersForGizmo()
diff --git a/Source/ArachnaeSwarm/Buildings/Building_EquipmentOotheca/Building_EquipmentOotheca.cs b/Source/ArachnaeSwarm/Buildings/Building_EquipmentOotheca/Building_EquipmentOotheca.cs
index b48af4d..e64913d 100644
--- a/Source/ArachnaeSwarm/Buildings/Building_EquipmentOotheca/Building_EquipmentOotheca.cs
+++ b/Source/ArachnaeSwarm/Buildings/Building_EquipmentOotheca/Building_EquipmentOotheca.cs
@@ -8,7 +8,7 @@ using System;
namespace ArachnaeSwarm
{
- public class Building_EquipmentOotheca : Building, IFluxController, ILarvaActivatable
+ public class Building_EquipmentOotheca : Building, IFluxController, ILarvaActivatable, IOrderGizmoProvider
{
// === 通量系统字段 ===
private float neutronFlux = 0.5f;
@@ -85,6 +85,84 @@ namespace ArachnaeSwarm
public float QualityMultiplier => qualityMultiplier;
+ // === IOrderGizmoProvider 实现 ===
+ private float gizmoScrollPosition = 0f;
+ public float GizmoScrollPosition { get => gizmoScrollPosition; set => gizmoScrollPosition = value; }
+ public int QueueLimit => 1; // 单孵化只能有1个
+
+ public List GetOrdersForGizmo()
+ {
+ var list = new List();
+ var config = EquipmentIncubatorData?.SelectedConfig;
+
+ if (isIncubating && incubatingThingDef != null)
+ {
+ list.Add(new PawnOrderDisplayInfo
+ {
+ label = incubatingThingDef.LabelCap,
+ progress = IncubationProgress,
+ qualityProgress = QualityPercent,
+ estimatedQuality = QualityPercent > 0.8f ? "优秀" : QualityPercent > 0.5f ? "良好" : "普通",
+ remainingTime = incubationDuration > incubationProgress ?
+ ((int)(incubationDuration - incubationProgress)).ToStringTicksToPeriod() : "",
+ status = OrderStatus.Incubating
+ });
+ }
+ else if (assignedLarva != null)
+ {
+ // 幼虫正在前来
+ string targetLabel = config?.thingDef?.LabelCap ?? "ARA_Menu_SelectProductionTarget".Translate();
+ list.Add(new PawnOrderDisplayInfo
+ {
+ label = targetLabel,
+ progress = 0f,
+ qualityProgress = 0f,
+ estimatedQuality = "",
+ remainingTime = "",
+ status = OrderStatus.WaitingForLarva
+ });
+ }
+ else if (config != null)
+ {
+ // 已选目标,等待就绪
+ list.Add(new PawnOrderDisplayInfo
+ {
+ label = config.thingDef.LabelCap,
+ progress = 0f,
+ qualityProgress = 0f,
+ estimatedQuality = "",
+ remainingTime = config.IsResearchComplete ? "ARA_Status_Ready".Translate() : "ARA_Status_NeedResearch".Translate(),
+ status = OrderStatus.WaitingForLarva
+ });
+ }
+
+ return list;
+ }
+
+ public void ShowOrderMenu() => EquipmentIncubatorData?.ShowFloatMenu();
+
+ public void RemoveOrderByIndex(int index)
+ {
+ if (index != 0) return;
+
+ // 取消孵化中的订单
+ if (isIncubating)
+ {
+ CancelIncubation();
+ }
+ // 释放幼虫
+ else if (assignedLarva != null)
+ {
+ assignedLarva = null;
+ larvaOperateTicksRemaining = 0;
+ }
+ // 清除已选目标
+ else if (EquipmentIncubatorData?.SelectedConfig != null)
+ {
+ EquipmentIncubatorData.SwitchToConfig(-1); // 清除选择
+ }
+ }
+
private void InitializeNutrientInfo() { } // 清理完毕
// === Tick方法(带活性系统)===
@@ -413,7 +491,7 @@ namespace ArachnaeSwarm
if (Faction == Faction.OfPlayer)
{
- yield return new Gizmo_EquipmentIncubationProgress(this);
+ yield return new Gizmo_PawnProgressBar(this);
yield return new Gizmo_NeutronFlux(this);
var config = EquipmentIncubatorData?.SelectedConfig;
diff --git a/Source/ArachnaeSwarm/Buildings/Building_EquipmentOotheca/Gizmo_EquipmentIncubationProgress.cs b/Source/ArachnaeSwarm/Buildings/Building_EquipmentOotheca/Gizmo_EquipmentIncubationProgress.cs
deleted file mode 100644
index c9a571b..0000000
--- a/Source/ArachnaeSwarm/Buildings/Building_EquipmentOotheca/Gizmo_EquipmentIncubationProgress.cs
+++ /dev/null
@@ -1,241 +0,0 @@
-// File: Gizmo_EquipmentIncubationProgress.cs
-// 双向进度条 Gizmo - 品质向左,进度向右(装备孵化版)
-using System.Collections.Generic;
-using RimWorld;
-using UnityEngine;
-using Verse;
-
-namespace ArachnaeSwarm
-{
- [StaticConstructorOnStartup]
- public class Gizmo_EquipmentIncubationProgress : Gizmo
- {
- private readonly Building_EquipmentOotheca building;
-
- // 尺寸常量
- private const float Width = 180f;
- private const float BarHeight = 18f;
- private const float Spacing = 4f;
- private const float Padding = 8f;
-
- // 进度条材质
- private static readonly Texture2D IncubationBarTex = SolidColorMaterials.NewSolidColorTexture(new Color(0.2f, 0.7f, 0.2f, 0.8f));
- private static readonly Texture2D QualityBarTex = SolidColorMaterials.NewSolidColorTexture(new Color(0.2f, 0.5f, 0.9f, 0.8f));
- private static readonly Texture2D EmptyBarTex = SolidColorMaterials.NewSolidColorTexture(new Color(0.1f, 0.1f, 0.1f, 0.5f));
-
- public Gizmo_EquipmentIncubationProgress(Building_EquipmentOotheca building)
- {
- this.building = building;
- Order = -140f;
- }
-
- public override float GetWidth(float maxWidth)
- {
- return Mathf.Min(Width, maxWidth);
- }
-
- public override GizmoResult GizmoOnGUI(Vector2 topLeft, float maxWidth, GizmoRenderParms parms)
- {
- // 主矩形区域 (75px高度)
- Rect rect = new Rect(topLeft.x, topLeft.y, GetWidth(maxWidth), 75f);
- Widgets.DrawWindowBackground(rect);
-
- Rect innerRect = rect.ContractedBy(Padding);
- float curY = innerRect.y;
-
- // 状态判断
- bool isIncubating = building.isIncubating;
- bool hasLarva = building.assignedLarva != null;
- var config = building.EquipmentIncubatorData?.SelectedConfig;
-
- // === 标题行(可点击切换目标) ===
- Text.Font = GameFont.Small;
- Rect titleRect = new Rect(innerRect.x, curY, innerRect.width, Text.LineHeight);
-
- string title;
- if (isIncubating && building.incubatingThingDef != null)
- title = building.incubatingThingDef.LabelCap;
- else if (config != null)
- title = config.thingDef.LabelCap;
- else
- title = "ARA_Menu_SelectProductionTarget".Translate();
-
- // 标题按钮(只有非孵化状态可点击)
- bool canSwitch = !isIncubating && !hasLarva && building.EquipmentIncubatorData?.IncubationConfigs?.Count > 0;
- if (canSwitch)
- {
- if (Mouse.IsOver(titleRect))
- {
- Widgets.DrawHighlight(titleRect);
- }
-
- if (Widgets.ButtonInvisible(titleRect))
- {
- ShowTargetSwitchMenu();
- }
-
- GUI.color = new Color(0.7f, 0.9f, 1f);
- Widgets.Label(titleRect, title.Truncate(titleRect.width - 20f) + " ▼");
- GUI.color = Color.white;
- }
- else
- {
- Widgets.Label(titleRect, title.Truncate(titleRect.width));
- }
- curY += Text.LineHeight + Spacing;
-
- // === 双向进度条区域 ===
- if (isIncubating)
- {
- // 标签行:品质进度: :孵化进度
- Text.Font = GameFont.Tiny;
- Rect labelRect = new Rect(innerRect.x, curY, innerRect.width, 14f);
-
- GUI.color = new Color(0.6f, 0.7f, 0.9f);
- Text.Anchor = TextAnchor.MiddleLeft;
- Widgets.Label(new Rect(labelRect.x, labelRect.y, labelRect.width / 2f, labelRect.height),
- "ARA_Label_Quality".Translate());
-
- GUI.color = new Color(0.6f, 0.9f, 0.6f);
- Text.Anchor = TextAnchor.MiddleRight;
- Widgets.Label(new Rect(labelRect.x + labelRect.width / 2f, labelRect.y, labelRect.width / 2f, labelRect.height),
- "ARA_Label_Progress".Translate());
-
- Text.Anchor = TextAnchor.UpperLeft;
- GUI.color = Color.white;
- curY += 14f;
-
- // 双向进度条
- Rect barRect = new Rect(innerRect.x, curY, innerRect.width, BarHeight);
- float midX = barRect.x + barRect.width / 2f;
- float halfWidth = barRect.width / 2f;
-
- // 背景
- GUI.DrawTexture(barRect, EmptyBarTex);
-
- // 品质进度(向左)
- float qualityWidth = halfWidth * building.QualityPercent;
- Rect qualityRect = new Rect(midX - qualityWidth, barRect.y, qualityWidth, barRect.height);
- GUI.DrawTexture(qualityRect, QualityBarTex);
-
- // 孵化进度(向右)
- float progressWidth = halfWidth * building.IncubationProgress;
- Rect progressRect = new Rect(midX, barRect.y, progressWidth, barRect.height);
- GUI.DrawTexture(progressRect, IncubationBarTex);
-
- // 中线
- Widgets.DrawLineVertical(midX, barRect.y, barRect.height);
-
- // 进度条边框
- Widgets.DrawBox(barRect, 1);
-
- // Tooltip
- string tooltip = GetTooltip();
- TooltipHandler.TipRegion(barRect, tooltip);
- }
- else if (hasLarva)
- {
- Text.Font = GameFont.Tiny;
- GUI.color = new Color(0.9f, 0.9f, 0.5f);
- string statusText = building.larvaOperateTicksRemaining > 0
- ? "ARA_Status_LarvaActivating".Translate()
- : "ARA_Status_LarvaOnTheWay".Translate();
- Widgets.Label(new Rect(innerRect.x, curY, innerRect.width, 30f), statusText);
- GUI.color = Color.white;
- }
- else
- {
- // 无目标或等待状态
- Text.Font = GameFont.Tiny;
- GUI.color = new Color(0.7f, 0.7f, 0.7f);
- string statusText;
- if (config == null)
- statusText = "ARA_Status_SelectTarget".Translate();
- else if (!config.IsResearchComplete)
- statusText = "ARA_Status_NeedResearch".Translate();
- else
- statusText = "ARA_Status_Ready".Translate();
- Widgets.Label(new Rect(innerRect.x, curY, innerRect.width, 20f), statusText);
- GUI.color = Color.white;
- }
-
- // 工具提示(整体)
- if (Mouse.IsOver(rect) && !isIncubating)
- {
- Widgets.DrawHighlight(rect);
- }
-
- Text.Font = GameFont.Small;
- return new GizmoResult(GizmoState.Clear);
- }
-
- private void ShowTargetSwitchMenu()
- {
- var configs = building.EquipmentIncubatorData?.IncubationConfigs;
- if (configs == null || configs.Count == 0) return;
-
- List options = new List();
-
- for (int i = 0; i < configs.Count; i++)
- {
- var cfg = configs[i];
- int index = i;
-
- Texture2D icon = cfg.thingDef?.uiIcon;
- string label = cfg.thingDef.LabelCap;
-
- if (cfg.requiredResearch != null && !cfg.requiredResearch.IsFinished)
- {
- label += $" ({cfg.requiredResearch.LabelCap})";
- options.Add(new FloatMenuOption(label, null, icon, Color.white));
- }
- else
- {
- label += $" ({cfg.DaysRequired}" + "ARA_Days".Translate() + ")";
- options.Add(new FloatMenuOption(label, () =>
- {
- building.EquipmentIncubatorData.SwitchToConfig(index);
- }, icon, Color.white));
- }
- }
-
- Find.WindowStack.Add(new FloatMenu(options));
- }
-
- private string GetTooltip()
- {
- var sb = new System.Text.StringBuilder();
- bool isIncubating = building.isIncubating;
-
- if (isIncubating && building.incubatingThingDef != null)
- {
- sb.AppendLine("ARA_Tooltip_Incubating".Translate());
- sb.AppendLine("ARA_Tooltip_Target".Translate(building.incubatingThingDef.LabelCap));
- sb.AppendLine("ARA_Tooltip_Progress".Translate(building.IncubationProgress.ToStringPercent()));
- sb.AppendLine("ARA_Tooltip_Quality".Translate(building.QualityPercent.ToStringPercent(), ""));
-
- float remaining = building.incubationDuration - building.incubationProgress;
- if (remaining > 0)
- {
- sb.AppendLine("ARA_Tooltip_Remaining".Translate(((int)remaining).ToStringTicksToPeriod()));
- }
- }
- else
- {
- var config = building.EquipmentIncubatorData?.SelectedConfig;
- if (config != null)
- {
- sb.AppendLine("ARA_Tooltip_Ready".Translate());
- sb.AppendLine("ARA_Tooltip_Target".Translate(config.thingDef.LabelCap));
- sb.AppendLine("ARA_Tooltip_Duration".Translate(config.DaysRequired + " " + "ARA_Days".Translate()));
- }
- else
- {
- sb.AppendLine("ARA_Tooltip_NoTarget".Translate());
- }
- }
-
- return sb.ToString().TrimEndNewlines();
- }
- }
-}
diff --git a/Source/ArachnaeSwarm/Buildings/Building_Ootheca/Building_Ootheca.cs b/Source/ArachnaeSwarm/Buildings/Building_Ootheca/Building_Ootheca.cs
index d98e7ea..fa99108 100644
--- a/Source/ArachnaeSwarm/Buildings/Building_Ootheca/Building_Ootheca.cs
+++ b/Source/ArachnaeSwarm/Buildings/Building_Ootheca/Building_Ootheca.cs
@@ -8,7 +8,7 @@ using Verse.AI;
namespace ArachnaeSwarm
{
- public class Building_Ootheca : Building, IFluxController, ILarvaActivatable
+ public class Building_Ootheca : Building, IFluxController, ILarvaActivatable, IOrderGizmoProvider
{
// === 通量系统字段 ===
private float neutronFlux = 0.5f;
@@ -86,6 +86,84 @@ namespace ArachnaeSwarm
public float QualityPercent => qualityTotal > 0 ? qualityProgress / qualityTotal : 0f;
public float AdjustedProgressPercent => incubationDuration > 0 ? incubationProgress / incubationDuration : 0f;
+ // === IOrderGizmoProvider 实现 ===
+ private float gizmoScrollPosition = 0f;
+ public float GizmoScrollPosition { get => gizmoScrollPosition; set => gizmoScrollPosition = value; }
+ public int QueueLimit => 1; // 单孵化只能有1个
+
+ public List GetOrdersForGizmo()
+ {
+ var list = new List();
+ var config = IncubatorData?.SelectedConfig;
+
+ if (isIncubating && incubatingPawnKind != null)
+ {
+ list.Add(new PawnOrderDisplayInfo
+ {
+ label = incubatingPawnKind.LabelCap,
+ progress = AdjustedProgressPercent,
+ qualityProgress = QualityPercent,
+ estimatedQuality = QualityPercent > 0.8f ? "优秀" : QualityPercent > 0.5f ? "良好" : "普通",
+ remainingTime = GetRemainingDays() > 0 ? GetRemainingDays().ToString("F1") + " " + "ARA_Days".Translate() : "",
+ status = OrderStatus.Incubating
+ });
+ }
+ else if (assignedLarva != null)
+ {
+ // 幼虫正在前来
+ string targetLabel = config?.pawnKind?.LabelCap ?? "ARA_Gizmo_SelectIncubationTarget".Translate();
+ list.Add(new PawnOrderDisplayInfo
+ {
+ label = targetLabel,
+ progress = 0f,
+ qualityProgress = 0f,
+ estimatedQuality = "",
+ remainingTime = "",
+ status = OrderStatus.WaitingForLarva
+ });
+ }
+ else if (config != null)
+ {
+ // 已选目标,等待就绪(研究完成则显示就绪状态)
+ list.Add(new PawnOrderDisplayInfo
+ {
+ label = config.pawnKind.LabelCap,
+ progress = 0f,
+ qualityProgress = 0f,
+ estimatedQuality = "",
+ remainingTime = config.IsResearchComplete ? "ARA_Status_Ready".Translate() : "ARA_Status_NeedResearch".Translate(),
+ status = OrderStatus.WaitingForLarva
+ });
+ }
+ // 如果没有选择目标,返回空列表(Gizmo 会显示"选择目标"状态)
+
+ return list;
+ }
+
+ public void ShowOrderMenu() => IncubatorData?.ShowFloatMenu();
+
+ public void RemoveOrderByIndex(int index)
+ {
+ if (index != 0) return;
+
+ // 取消孵化中的订单
+ if (isIncubating)
+ {
+ CancelIncubation();
+ }
+ // 释放幼虫
+ else if (assignedLarva != null)
+ {
+ assignedLarva = null;
+ larvaOperateTicksRemaining = 0;
+ }
+ // 清除已选目标
+ else if (IncubatorData?.SelectedConfig != null)
+ {
+ IncubatorData.SwitchToConfig(-1); // 清除选择
+ }
+ }
+
// === 描述方法 ===
public string GetSpeedFactorsDescription()
{
@@ -428,7 +506,7 @@ namespace ArachnaeSwarm
if (Faction == Faction.OfPlayer)
{
- yield return new Gizmo_IncubationProgress(this);
+ yield return new Gizmo_PawnProgressBar(this);
yield return new Gizmo_NeutronFlux(this);
var config = IncubatorData?.SelectedConfig;
diff --git a/Source/ArachnaeSwarm/Buildings/Building_Ootheca/Gizmo_DualProgressBar.cs b/Source/ArachnaeSwarm/Buildings/Building_Ootheca/Gizmo_DualProgressBar.cs
deleted file mode 100644
index 1cccc06..0000000
--- a/Source/ArachnaeSwarm/Buildings/Building_Ootheca/Gizmo_DualProgressBar.cs
+++ /dev/null
@@ -1,210 +0,0 @@
-using RimWorld;
-using System.Collections.Generic;
-using UnityEngine;
-using Verse;
-
-namespace ArachnaeSwarm
-{
- ///
- /// 双向进度条 Gizmo - 用于物品孵化池
- /// 样式与旧版 Gizmo_IncubationProgress 统一
- ///
- [StaticConstructorOnStartup]
- public class Gizmo_DualProgressBar : Gizmo
- {
- private const float Width = 200f;
- private const float BarHeight = 18f;
- private const float Spacing = 4f;
- private const float Padding = 8f;
- private const float MaxVisibleOrders = 3;
-
- private static readonly Texture2D ProgressBarTex = SolidColorMaterials.NewSolidColorTexture(new Color(0.2f, 0.7f, 0.2f, 0.8f));
- private static readonly Texture2D QualityBarTex = SolidColorMaterials.NewSolidColorTexture(new Color(0.2f, 0.5f, 0.9f, 0.8f));
- private static readonly Texture2D EmptyBarTex = SolidColorMaterials.NewSolidColorTexture(new Color(0.1f, 0.1f, 0.1f, 0.5f));
-
- private readonly CompQueuedInteractiveProducerWithFlux comp;
- // scrollPosition 现在存储在 comp 中以在刷新间保持
-
- public Gizmo_DualProgressBar(CompQueuedInteractiveProducerWithFlux comp)
- {
- this.comp = comp;
- this.Order = -140f;
- }
-
- public override float GetWidth(float maxWidth) => Mathf.Min(Width, maxWidth);
-
- public override GizmoResult GizmoOnGUI(Vector2 topLeft, float maxWidth, GizmoRenderParms parms)
- {
- var orders = comp.GetOrdersForGizmo();
- int orderCount = orders.Count;
-
- // 计算高度
- int visibleCount = Mathf.Min(orderCount, (int)MaxVisibleOrders);
- float contentHeight = Padding * 2 + Text.LineHeight + Spacing;
- contentHeight += Mathf.Max(1, visibleCount) * (BarHeight + Spacing + 14f);
- float totalHeight = Mathf.Max(75f, contentHeight);
-
- Rect rect = new Rect(topLeft.x, topLeft.y - (totalHeight - 75f), GetWidth(maxWidth), totalHeight);
- Widgets.DrawWindowBackground(rect);
-
- Rect innerRect = rect.ContractedBy(Padding);
- float curY = innerRect.y;
-
- // === 标题区域(可点击打开菜单) ===
- Text.Font = GameFont.Small;
- Rect titleRect = new Rect(innerRect.x, curY, innerRect.width, Text.LineHeight);
-
- string title;
- bool canAdd = orderCount < comp.Props.productionQueueLimit;
-
- if (orderCount > 0)
- {
- title = orders[0].label;
- if (orderCount > 1) title += $" (+{orderCount - 1})";
- }
- else
- {
- title = "ARA_Menu_SelectProductionTarget".Translate();
- }
-
- if (canAdd)
- {
- if (Mouse.IsOver(titleRect))
- {
- Widgets.DrawHighlight(titleRect);
- }
-
- if (Widgets.ButtonInvisible(titleRect))
- {
- comp.ShowOrderMenuPublic();
- }
-
- GUI.color = new Color(0.7f, 0.9f, 1f);
- Widgets.Label(titleRect, title.Truncate(titleRect.width - 20f) + " ▼");
- GUI.color = Color.white;
- }
- else
- {
- GUI.color = new Color(0.5f, 0.5f, 0.5f);
- Widgets.Label(titleRect, title.Truncate(titleRect.width) + " " + "ARA_Gizmo_QueueFull".Translate());
- GUI.color = Color.white;
- }
- curY += Text.LineHeight + Spacing;
-
- // === 订单列表 ===
- if (orderCount > 0)
- {
- float itemHeight = BarHeight + Spacing + 14f;
- float listHeight = Mathf.Min(visibleCount, orderCount) * itemHeight;
- float totalContentHeight = orderCount * itemHeight;
- bool needsScrollbar = orderCount > MaxVisibleOrders;
-
- float scrollbarWidth = needsScrollbar ? 12f : 0f;
- Rect listRect = new Rect(innerRect.x, curY, innerRect.width - scrollbarWidth, listHeight);
-
- // 滚动条
- if (needsScrollbar)
- {
- Rect scrollbarRect = new Rect(innerRect.xMax - scrollbarWidth, curY, scrollbarWidth, listHeight);
- float scrollMax = totalContentHeight - listHeight;
- comp.GizmoScrollPosition = GUI.VerticalScrollbar(scrollbarRect, comp.GizmoScrollPosition, listHeight, 0f, totalContentHeight);
-
- if (Mouse.IsOver(listRect))
- {
- comp.GizmoScrollPosition -= Event.current.delta.y * 1.5f;
- comp.GizmoScrollPosition = Mathf.Clamp(comp.GizmoScrollPosition, 0f, scrollMax);
- }
- }
-
- GUI.BeginClip(listRect);
- float drawY = -comp.GizmoScrollPosition;
-
- for (int i = 0; i < orderCount; i++)
- {
- var order = orders[i];
- Rect itemRect = new Rect(0, drawY, listRect.width, itemHeight - Spacing);
-
- if (itemRect.yMax > 0 && itemRect.y < listRect.height)
- {
- DrawOrderItem(itemRect, order, i);
- }
- drawY += itemHeight;
- }
-
- GUI.EndClip();
- }
- else
- {
- Text.Font = GameFont.Tiny;
- GUI.color = new Color(0.7f, 0.7f, 0.7f);
- Widgets.Label(new Rect(innerRect.x, curY, innerRect.width, 20f), "ARA_Status_Ready".Translate());
- GUI.color = Color.white;
- }
-
- Text.Font = GameFont.Small;
- return new GizmoResult(GizmoState.Clear);
- }
-
- private void DrawOrderItem(Rect rect, OrderDisplayInfo order, int index)
- {
- float labelHeight = 14f;
-
- Text.Font = GameFont.Tiny;
- Rect labelRect = new Rect(rect.x, rect.y, rect.width - 20f, labelHeight);
-
- if (order.status == OrderStatus.WaitingForLarva)
- {
- GUI.color = new Color(1f, 0.8f, 0.4f);
- Widgets.Label(labelRect, $"{order.label} [" + "ARA_Status_WaitingForLarva".Translate() + "]");
- }
- else
- {
- GUI.color = Color.white;
- Widgets.Label(labelRect, $"{order.label} {order.productionProgress.ToStringPercent("F0")}");
- }
- GUI.color = Color.white;
-
- Rect cancelRect = new Rect(rect.xMax - 16f, rect.y, 16f, labelHeight);
- if (Widgets.ButtonText(cancelRect, "×", false))
- {
- comp.RemoveOrderByIndex(index);
- }
-
- Rect barRect = new Rect(rect.x, rect.y + labelHeight, rect.width, BarHeight);
-
- if (order.status == OrderStatus.Incubating)
- {
- float midX = barRect.x + barRect.width / 2f;
- float halfWidth = barRect.width / 2f;
-
- GUI.DrawTexture(barRect, EmptyBarTex);
-
- float qualityWidth = halfWidth * order.qualityProgress;
- Rect qualityRect = new Rect(midX - qualityWidth, barRect.y, qualityWidth, barRect.height);
- GUI.DrawTexture(qualityRect, QualityBarTex);
-
- float progressWidth = halfWidth * order.productionProgress;
- Rect progressRect = new Rect(midX, barRect.y, progressWidth, barRect.height);
- GUI.DrawTexture(progressRect, ProgressBarTex);
-
- Widgets.DrawLineVertical(midX, barRect.y, barRect.height);
-
- // Tooltip
- string tooltip = $"{order.label}\n" +
- "ARA_Tooltip_Quality".Translate(order.qualityProgress.ToStringPercent(), order.estimatedQuality) + "\n" +
- "ARA_Tooltip_Progress".Translate(order.productionProgress.ToStringPercent());
- TooltipHandler.TipRegion(barRect, tooltip);
- }
- else
- {
- GUI.DrawTexture(barRect, EmptyBarTex);
- Text.Font = GameFont.Tiny;
- Text.Anchor = TextAnchor.MiddleCenter;
- GUI.color = new Color(0.8f, 0.6f, 0.2f);
- Widgets.Label(barRect, "ARA_Status_WaitingForLarva".Translate());
- GUI.color = Color.white;
- Text.Anchor = TextAnchor.UpperLeft;
- }
- }
- }
-}
diff --git a/Source/ArachnaeSwarm/Buildings/Building_Ootheca/Gizmo_IncubationProgress.cs b/Source/ArachnaeSwarm/Buildings/Building_Ootheca/Gizmo_IncubationProgress.cs
deleted file mode 100644
index f6b9459..0000000
--- a/Source/ArachnaeSwarm/Buildings/Building_Ootheca/Gizmo_IncubationProgress.cs
+++ /dev/null
@@ -1,239 +0,0 @@
-// File: Gizmo_IncubationProgress.cs
-// 双向进度条 Gizmo - 品质向左,进度向右
-using System.Collections.Generic;
-using RimWorld;
-using UnityEngine;
-using Verse;
-
-namespace ArachnaeSwarm
-{
- [StaticConstructorOnStartup]
- public class Gizmo_IncubationProgress : Gizmo
- {
- private readonly Building_Ootheca ootheca;
-
- // 尺寸常量
- private const float Width = 180f;
- private const float BarHeight = 18f;
- private const float Spacing = 4f;
- private const float Padding = 8f;
-
- // 进度条材质
- private static readonly Texture2D IncubationBarTex = SolidColorMaterials.NewSolidColorTexture(new Color(0.2f, 0.7f, 0.2f, 0.8f));
- private static readonly Texture2D QualityBarTex = SolidColorMaterials.NewSolidColorTexture(new Color(0.2f, 0.5f, 0.9f, 0.8f));
- private static readonly Texture2D EmptyBarTex = SolidColorMaterials.NewSolidColorTexture(new Color(0.1f, 0.1f, 0.1f, 0.5f));
-
- public Gizmo_IncubationProgress(Building_Ootheca ootheca)
- {
- this.ootheca = ootheca;
- Order = -140f;
- }
-
- public override float GetWidth(float maxWidth)
- {
- return Mathf.Min(Width, maxWidth);
- }
-
- public override GizmoResult GizmoOnGUI(Vector2 topLeft, float maxWidth, GizmoRenderParms parms)
- {
- // 主矩形区域 (75px高度)
- Rect rect = new Rect(topLeft.x, topLeft.y, GetWidth(maxWidth), 75f);
- Widgets.DrawWindowBackground(rect);
-
- Rect innerRect = rect.ContractedBy(Padding);
- float curY = innerRect.y;
-
- // 状态判断
- bool isIncubating = ootheca.isIncubating;
- bool hasLarva = ootheca.assignedLarva != null;
- var config = ootheca.IncubatorData?.SelectedConfig;
-
- // === 标题行(可点击切换目标) ===
- Text.Font = GameFont.Small;
- Rect titleRect = new Rect(innerRect.x, curY, innerRect.width, Text.LineHeight);
-
- string title;
- if (isIncubating && ootheca.incubatingPawnKind != null)
- title = ootheca.incubatingPawnKind.LabelCap;
- else if (config != null)
- title = config.pawnKind.LabelCap;
- else
- title = "ARA_Gizmo_SelectIncubationTarget".Translate();
-
- // 标题按钮(只有非孵化状态可点击)
- bool canSwitch = !isIncubating && !hasLarva && ootheca.IncubatorData?.IncubationConfigs?.Count > 0;
- if (canSwitch)
- {
- if (Mouse.IsOver(titleRect))
- {
- Widgets.DrawHighlight(titleRect);
- }
-
- if (Widgets.ButtonInvisible(titleRect))
- {
- ShowTargetSwitchMenu();
- }
-
- GUI.color = new Color(0.7f, 0.9f, 1f);
- Widgets.Label(titleRect, title.Truncate(titleRect.width - 20f) + " ▼");
- GUI.color = Color.white;
- }
- else
- {
- Widgets.Label(titleRect, title.Truncate(titleRect.width));
- }
- curY += Text.LineHeight + Spacing;
-
- // === 双向进度条区域 ===
- if (isIncubating)
- {
- // 标签行:品质进度: :孵化进度
- Text.Font = GameFont.Tiny;
- Rect labelRect = new Rect(innerRect.x, curY, innerRect.width, 14f);
-
- GUI.color = new Color(0.6f, 0.7f, 0.9f);
- Text.Anchor = TextAnchor.MiddleLeft;
- Widgets.Label(new Rect(labelRect.x, labelRect.y, labelRect.width / 2f, labelRect.height),
- "ARA_Label_Quality".Translate());
-
- GUI.color = new Color(0.6f, 0.9f, 0.6f);
- Text.Anchor = TextAnchor.MiddleRight;
- Widgets.Label(new Rect(labelRect.x + labelRect.width / 2f, labelRect.y, labelRect.width / 2f, labelRect.height),
- "ARA_Label_Progress".Translate());
-
- Text.Anchor = TextAnchor.UpperLeft;
- GUI.color = Color.white;
- curY += 14f;
-
- // 双向进度条
- Rect barRect = new Rect(innerRect.x, curY, innerRect.width, BarHeight);
- float midX = barRect.x + barRect.width / 2f;
- float halfWidth = barRect.width / 2f;
-
- // 背景
- GUI.DrawTexture(barRect, EmptyBarTex);
-
- // 品质进度(向左)
- float qualityWidth = halfWidth * ootheca.QualityPercent;
- Rect qualityRect = new Rect(midX - qualityWidth, barRect.y, qualityWidth, barRect.height);
- GUI.DrawTexture(qualityRect, QualityBarTex);
-
- // 孵化进度(向右)
- float progressWidth = halfWidth * ootheca.AdjustedProgressPercent;
- Rect progressRect = new Rect(midX, barRect.y, progressWidth, barRect.height);
- GUI.DrawTexture(progressRect, IncubationBarTex);
-
- // 中线
- Widgets.DrawLineVertical(midX, barRect.y, barRect.height);
-
- // 进度条边框
- Widgets.DrawBox(barRect, 1);
-
- // Tooltip
- string tooltip = GetTooltip();
- TooltipHandler.TipRegion(barRect, tooltip);
- }
- else if (hasLarva)
- {
- Text.Font = GameFont.Tiny;
- GUI.color = new Color(0.9f, 0.9f, 0.5f);
- string statusText = ootheca.larvaOperateTicksRemaining > 0
- ? "ARA_Status_LarvaActivating".Translate()
- : "ARA_Status_LarvaOnTheWay".Translate();
- Widgets.Label(new Rect(innerRect.x, curY, innerRect.width, 30f), statusText);
- GUI.color = Color.white;
- }
- else
- {
- // 无目标或等待状态
- Text.Font = GameFont.Tiny;
- GUI.color = new Color(0.7f, 0.7f, 0.7f);
- string statusText;
- if (config == null)
- statusText = "ARA_Status_SelectTarget".Translate();
- else if (!config.IsResearchComplete)
- statusText = "ARA_Status_NeedResearch".Translate();
- else
- statusText = "ARA_Status_Ready".Translate();
- Widgets.Label(new Rect(innerRect.x, curY, innerRect.width, 20f), statusText);
- GUI.color = Color.white;
- }
-
- // 工具提示(整体)
- if (Mouse.IsOver(rect) && !isIncubating)
- {
- Widgets.DrawHighlight(rect);
- }
-
- Text.Font = GameFont.Small;
- return new GizmoResult(GizmoState.Clear);
- }
-
- private void ShowTargetSwitchMenu()
- {
- var configs = ootheca.IncubatorData?.IncubationConfigs;
- if (configs == null || configs.Count == 0) return;
-
- List options = new List();
-
- for (int i = 0; i < configs.Count; i++)
- {
- var cfg = configs[i];
- int index = i;
-
- string label = cfg.pawnKind.LabelCap;
- if (cfg.requiredResearch != null && !cfg.requiredResearch.IsFinished)
- {
- label += $" ({cfg.requiredResearch.LabelCap})";
- options.Add(new FloatMenuOption(label, null));
- }
- else
- {
- label += $" ({cfg.daysRequired}" + "ARA_Days".Translate() + ")";
- options.Add(new FloatMenuOption(label, () =>
- {
- ootheca.IncubatorData.SwitchToConfig(index);
- }));
- }
- }
-
- Find.WindowStack.Add(new FloatMenu(options));
- }
-
- private string GetTooltip()
- {
- var sb = new System.Text.StringBuilder();
- bool isIncubating = ootheca.isIncubating;
-
- if (isIncubating && ootheca.incubatingPawnKind != null)
- {
- sb.AppendLine("ARA_Tooltip_Incubating".Translate());
- sb.AppendLine("ARA_Tooltip_Target".Translate(ootheca.incubatingPawnKind.LabelCap));
- sb.AppendLine("ARA_Tooltip_Progress".Translate(ootheca.AdjustedProgressPercent.ToStringPercent()));
- sb.AppendLine("ARA_Tooltip_Quality".Translate(ootheca.QualityPercent.ToStringPercent(), ""));
-
- float daysRemaining = ootheca.GetRemainingDays();
- if (daysRemaining > 0 && daysRemaining < float.MaxValue)
- {
- sb.AppendLine("ARA_Tooltip_Remaining".Translate(daysRemaining.ToString("F1") + " " + "ARA_Days".Translate()));
- }
- }
- else
- {
- var config = ootheca.IncubatorData?.SelectedConfig;
- if (config != null)
- {
- sb.AppendLine("ARA_Tooltip_Ready".Translate());
- sb.AppendLine("ARA_Tooltip_Target".Translate(config.pawnKind.LabelCap));
- sb.AppendLine("ARA_Tooltip_Duration".Translate(config.daysRequired + " " + "ARA_Days".Translate()));
- }
- else
- {
- sb.AppendLine("ARA_Tooltip_NoTarget".Translate());
- }
- }
-
- return sb.ToString().TrimEndNewlines();
- }
- }
-}
diff --git a/Source/ArachnaeSwarm/Buildings/Building_Ootheca/Gizmo_PawnProgressBar.cs b/Source/ArachnaeSwarm/Buildings/Building_Ootheca/Gizmo_PawnProgressBar.cs
index 7284bde..75899c3 100644
--- a/Source/ArachnaeSwarm/Buildings/Building_Ootheca/Gizmo_PawnProgressBar.cs
+++ b/Source/ArachnaeSwarm/Buildings/Building_Ootheca/Gizmo_PawnProgressBar.cs
@@ -6,8 +6,7 @@ using Verse;
namespace ArachnaeSwarm
{
///
- /// 双向进度条 Gizmo - 用于督虫孵化池
- /// 样式与旧版 Gizmo_IncubationProgress 统一
+ /// 统一的双向进度条 Gizmo - 用于所有孵化建筑/组件
///
[StaticConstructorOnStartup]
public class Gizmo_PawnProgressBar : Gizmo
@@ -22,12 +21,11 @@ namespace ArachnaeSwarm
private static readonly Texture2D QualityBarTex = SolidColorMaterials.NewSolidColorTexture(new Color(0.2f, 0.5f, 0.9f, 0.8f));
private static readonly Texture2D EmptyBarTex = SolidColorMaterials.NewSolidColorTexture(new Color(0.1f, 0.1f, 0.1f, 0.5f));
- private readonly CompQueuedPawnSpawnerWithFlux comp;
- // scrollPosition 现在存储在 comp 中以在刷新间保持
+ private readonly IOrderGizmoProvider provider;
- public Gizmo_PawnProgressBar(CompQueuedPawnSpawnerWithFlux comp)
+ public Gizmo_PawnProgressBar(IOrderGizmoProvider provider)
{
- this.comp = comp;
+ this.provider = provider;
this.Order = -140f;
}
@@ -35,7 +33,7 @@ namespace ArachnaeSwarm
public override GizmoResult GizmoOnGUI(Vector2 topLeft, float maxWidth, GizmoRenderParms parms)
{
- var orders = comp.GetOrdersForGizmo();
+ var orders = provider.GetOrdersForGizmo();
int orderCount = orders.Count;
// 计算高度
@@ -55,7 +53,7 @@ namespace ArachnaeSwarm
Rect titleRect = new Rect(innerRect.x, curY, innerRect.width, Text.LineHeight);
string title;
- bool canAdd = orderCount < comp.Props.productionQueueLimit;
+ bool canAdd = orderCount < provider.QueueLimit;
if (orderCount > 0)
{
@@ -78,7 +76,7 @@ namespace ArachnaeSwarm
if (Widgets.ButtonInvisible(titleRect))
{
- comp.ShowOrderMenuPublic();
+ provider.ShowOrderMenu();
}
// 带下拉箭头的标题
@@ -111,18 +109,18 @@ namespace ArachnaeSwarm
{
Rect scrollbarRect = new Rect(innerRect.xMax - scrollbarWidth, curY, scrollbarWidth, listHeight);
float scrollMax = totalContentHeight - listHeight;
- comp.GizmoScrollPosition = GUI.VerticalScrollbar(scrollbarRect, comp.GizmoScrollPosition, listHeight, 0f, totalContentHeight);
+ provider.GizmoScrollPosition = GUI.VerticalScrollbar(scrollbarRect, provider.GizmoScrollPosition, listHeight, 0f, totalContentHeight);
// 也支持滚轮
if (Mouse.IsOver(listRect))
{
- comp.GizmoScrollPosition -= Event.current.delta.y * 1.5f;
- comp.GizmoScrollPosition = Mathf.Clamp(comp.GizmoScrollPosition, 0f, scrollMax);
+ provider.GizmoScrollPosition -= Event.current.delta.y * 1.5f;
+ provider.GizmoScrollPosition = Mathf.Clamp(provider.GizmoScrollPosition, 0f, scrollMax);
}
}
GUI.BeginClip(listRect);
- float drawY = -comp.GizmoScrollPosition;
+ float drawY = -provider.GizmoScrollPosition;
for (int i = 0; i < orderCount; i++)
{
@@ -175,7 +173,7 @@ namespace ArachnaeSwarm
Rect cancelRect = new Rect(rect.xMax - 16f, rect.y, 16f, labelHeight);
if (Widgets.ButtonText(cancelRect, "×", false))
{
- comp.RemoveOrderByIndex(index);
+ provider.RemoveOrderByIndex(index);
}
// 进度条
@@ -202,6 +200,21 @@ namespace ArachnaeSwarm
// 中线
Widgets.DrawLineVertical(midX, barRect.y, barRect.height);
+
+ // 百分比文字(在进度条内部)
+ Text.Font = GameFont.Tiny;
+ Text.Anchor = TextAnchor.MiddleLeft;
+ GUI.color = new Color(0.8f, 0.9f, 1f);
+ Widgets.Label(new Rect(barRect.x + 2f, barRect.y, halfWidth - 4f, barRect.height),
+ order.qualityProgress.ToStringPercent("F0"));
+
+ Text.Anchor = TextAnchor.MiddleRight;
+ GUI.color = new Color(0.8f, 1f, 0.8f);
+ Widgets.Label(new Rect(midX + 2f, barRect.y, halfWidth - 4f, barRect.height),
+ order.progress.ToStringPercent("F0"));
+
+ Text.Anchor = TextAnchor.UpperLeft;
+ GUI.color = Color.white;
// Tooltip
string tooltip = $"{order.label}\n" +
diff --git a/Source/ArachnaeSwarm/Buildings/IOrderGizmoProvider.cs b/Source/ArachnaeSwarm/Buildings/IOrderGizmoProvider.cs
new file mode 100644
index 0000000..1d0b322
--- /dev/null
+++ b/Source/ArachnaeSwarm/Buildings/IOrderGizmoProvider.cs
@@ -0,0 +1,27 @@
+// File: IOrderGizmoProvider.cs
+// 订单 Gizmo 数据提供者接口 - 让所有孵化建筑使用同一个 Gizmo
+using System.Collections.Generic;
+
+namespace ArachnaeSwarm
+{
+ ///
+ /// 订单 Gizmo 数据提供者接口
+ ///
+ public interface IOrderGizmoProvider
+ {
+ /// 获取订单列表用于 Gizmo 显示
+ List GetOrdersForGizmo();
+
+ /// 最大队列数量(单孵化为1)
+ int QueueLimit { get; }
+
+ /// 显示添加订单菜单
+ void ShowOrderMenu();
+
+ /// 移除指定索引的订单
+ void RemoveOrderByIndex(int index);
+
+ /// Gizmo 滚动位置(用于多订单时)
+ float GizmoScrollPosition { get; set; }
+ }
+}