diff --git a/1.6/1.6/Assemblies/ArachnaeSwarm.dll b/1.6/1.6/Assemblies/ArachnaeSwarm.dll
index 02b820c..eeffb18 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 49bfb77..0627f59 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/Thing_building/ARA_NutrientNetworkBuilding.xml b/1.6/1.6/Defs/Thing_building/ARA_NutrientNetworkBuilding.xml
index a097ed0..ae73e4b 100644
--- a/1.6/1.6/Defs/Thing_building/ARA_NutrientNetworkBuilding.xml
+++ b/1.6/1.6/Defs/Thing_building/ARA_NutrientNetworkBuilding.xml
@@ -61,6 +61,7 @@
CatastropheMissileSilo
ARA_AutoSniperCannon
ARA_Pawn_Ootheca
+ ARA_Equipment_Ootheca
80
10
diff --git a/1.6/1.6/Defs/Thing_building/ARA_Ootheca.xml b/1.6/1.6/Defs/Thing_building/ARA_Ootheca.xml
index e051f02..49d69a4 100644
--- a/1.6/1.6/Defs/Thing_building/ARA_Ootheca.xml
+++ b/1.6/1.6/Defs/Thing_building/ARA_Ootheca.xml
@@ -111,42 +111,6 @@
ARA_Incubator_Room
-
-
-
-
- 5
-
- 5
-
- false
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- true
- 2
- Burn
- true
-
-
-
-
-
-
25
@@ -454,44 +418,10 @@
ARA_Incubator_Room
-
-
-
-
- 3
-
- 3
-
- false
-
- 0.03
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
25
-
-
- ArachnaeSwarm.ITab_EquipmentOotheca_Incubation
-
-
-
- ArachnaeSwarm.PlaceWorker_CustomRadius
-
100
@@ -500,14 +430,18 @@
0.2
0.5
-
- 3
- (0.5, 1, 1)
- 0
- true
-
- 这个卵在孵化过程中的吸收半径,确保这些地格中铺满阿拉克涅营养液,并且没有其他的卵,以获得最佳的孵化速度和孵化质量。
- false
+
+
+ 0
+ 10
+ 0
+ 5
+ true
+
+
+ ARA_InsectJelly
+
+
@@ -585,4 +519,266 @@
+
+
+
+ ARA_BioforgeIncubator_Thing
+
+ 一个大型的、需要消耗大量营养物质的孵化设施,可以同时孵化多个物品,并能通过链接外部设备来提高效率。
+
+ ArachnaeSwarm/Building/ARA_BioforgeIncubator_Thing
+ Graphic_Single
+ CutoutComplex
+ false
+ (5.5,6.5)
+ (0, 2, 0.5)
+
+ (2.75, 1.2, 2)
+ (0.2,0,-1.15)
+
+
+ (5,5)
+ false
+ Normal
+
+ 0
+
+ 200
+ 40
+ 10
+
+ false
+ 0
+ Building
+ PassThroughOnly
+ ARA_Creep
+ 50
+
+ 20000
+ 250
+ 2800
+ 1.0
+
+
+ PlaceWorker_PreventInteractionSpotOverlap
+
+ 0.8
+ (0,0,-1)
+ true
+ ARA_Buildings
+ 2600
+ Item
+
+ Laboratory
+ 0.8
+
+ ARA_InsectCreep
+
+
+
+ ARA_Technology_4NPT
+
+
+
+
+
+ 3
+ 1.0
+
+ ArachnaeNode_Race_WeaponSmith
+
+
+
+ 10
+ 30
+ 0.00001
+
+
+ Legendary
+ 0.99
+
+
+ Masterwork
+ 0.90
+
+
+ Excellent
+ 0.70
+
+
+ Good
+ 0.50
+
+
+ Normal
+ 0.20
+
+
+ Poor
+ 0.10
+
+
+
+
+
+
+ 300.0
+
+
+ ARA_InsectJelly
+
+
+ 虫蜜
+ true
+ true
+
+
+
+
+
+ ARA_NutrientNetworkTower
+ ARA_GrowthVat
+
+
+
+ ARA_InsectCreep
+ 8
+
+
+
+
+ ARA_BioforgeIncubator
+
+ 一个大型的、需要消耗大量营养物质的孵化设施,可以同时孵化多个单位,并能通过链接外部设备来提高效率。
+
+ ArachnaeSwarm/Building/ARA_BioforgeIncubator
+ Graphic_Single
+ CutoutComplex
+ (5.5,6.5)
+ false
+ (0, 2, 0.5)
+
+ (2.75, 1.4, 2)
+ (0,0,-1.25)
+
+
+ (5,5)
+ Normal
+ false
+
+ 0
+
+ 200
+ 40
+ 10
+
+ false
+ 0
+ Building
+ PassThroughOnly
+ ARA_Creep
+ ARA_Buildings
+ 50
+
+ ARA_Technology_4NPT
+
+
+ 20000
+ 250
+ 2800
+ 1.0
+
+
+ PlaceWorker_PreventInteractionSpotOverlap
+
+ 0.8
+ (0,0,-1)
+ true
+
+ 2600
+ Item
+
+ Laboratory
+ 0.8
+
+ ARA_InsectCreep
+
+
+
+
+
+ 5
+ 0.5
+
+ ARA_ArachnaeQueen
+
+
+
+ ArachnaeNode_Race_Myrmecocystus
+ 240000
+ 100.0
+
+
+ ArachnaeNode_Race_ShieldHead
+ 180000
+ 40.0
+
+
+ ArachnaeNode_Race_WeaponSmith
+ 180000
+ 40.0
+
+
+ ArachnaeNode_Race_Fighter
+ 90000
+ 20.0
+ ARA_Technology_1KYC
+
+
+ ArachnaeNode_Race_Smokepop
+ 180000
+ 60.0
+ ARA_Technology_5KYC
+
+
+ ArachnaeNode_Race_Skyraider
+ 120000
+ 80.0
+ ARA_Technology_2KYC
+
+
+ ARA_MimicNematodeShamblerSwarmer
+ 600
+ 10.0
+ ARA_Technology_6MEN
+
+
+
+
+
+
+ 20.0
+
+
+ ARA_InsectJelly
+
+
+ 虫蜜
+ true
+ true
+
+
+
+
+
+ ARA_NutrientNetworkTower
+ ARA_GrowthVat
+
+
+
+ ARA_InsectCreep
+ 8
+
+
+
\ No newline at end of file
diff --git a/Source/ArachnaeSwarm/ArachnaeSwarm.csproj b/Source/ArachnaeSwarm/ArachnaeSwarm.csproj
index a762a77..56b0905 100644
--- a/Source/ArachnaeSwarm/ArachnaeSwarm.csproj
+++ b/Source/ArachnaeSwarm/ArachnaeSwarm.csproj
@@ -118,9 +118,11 @@
+
+
diff --git a/Source/ArachnaeSwarm/Buildings/Building_EquipmentOotheca/Building_EquipmentOotheca.cs b/Source/ArachnaeSwarm/Buildings/Building_EquipmentOotheca/Building_EquipmentOotheca.cs
index 072f906..9f37ef8 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
+ public class Building_EquipmentOotheca : Building, IFluxController
{
// 引用组件
public CompEquipmentIncubatorData EquipmentIncubatorData => this.TryGetComp();
@@ -33,27 +33,75 @@ namespace ArachnaeSwarm
private float qualityProgress = 0f;
private float qualityTotal = 0f;
- // === 简化后的营养液系统:只用于速度加成,不消耗 ===
- private int totalNutrientCost = 0; // 总共需要的营养液地块数量(仅用于信息显示)
- private int currentNutrientCount = 0; // 当前周围存在的营养液数量
+ // ======= 孵化活性系统 =======
+ private float neutronFlux = 0.5f; // 0-1, 默认50%
+ private FluxMode fluxMode = FluxMode.Balance; // 默认平衡模式
+ private CompRefuelableNutrition fuelComp; // 燃料组件缓存
+ private Comp_SwarmMaintenance maintenanceComp; // 维护组件缓存
- // 缓存的ModExtension
- private OothecaIncubatorExtension cachedExtension;
+ // 孵化活性公开属性
+ public float NeutronFlux => isIncubating ? neutronFlux : 0f;
+ public float RawFlux => neutronFlux;
+ public FluxMode CurrentFluxMode => fluxMode;
+ public bool IsAutoMode => fluxMode != FluxMode.Manual;
+ public bool IsIncubating => isIncubating;
- // 获取ModExtension的辅助属性
- public OothecaIncubatorExtension Ext
+ // 获取燃料组件
+ public CompRefuelableNutrition FuelComp => fuelComp ?? (fuelComp = this.TryGetComp());
+ public Comp_SwarmMaintenance MaintenanceComp => maintenanceComp ?? (maintenanceComp = this.TryGetComp());
+
+ // 孵化活性效率曲线(非线性:flux²)
+ public float FluxEfficiency => NeutronFlux * NeutronFlux;
+
+ // 是否处于休眠状态
+ public bool IsDormant => NeutronFlux < 0.01f || (FuelComp != null && !FuelComp.HasFuel);
+
+ // 设置活性值
+ public void SetNeutronFlux(float value)
{
- get
+ neutronFlux = Mathf.Clamp01(value);
+ }
+
+ // 切换模式
+ public void CycleFluxMode()
+ {
+ fluxMode = (FluxMode)(((int)fluxMode + 1) % 4);
+ }
+
+ public void SetFluxMode(FluxMode mode)
+ {
+ fluxMode = mode;
+ }
+
+ public string GetModeName()
+ {
+ switch (fluxMode)
{
- if (cachedExtension == null)
- {
- cachedExtension = def.GetModExtension() ?? OothecaIncubatorExtension.Default;
- }
- return cachedExtension;
+ case FluxMode.Manual: return "手动";
+ case FluxMode.Quality: return "品质";
+ case FluxMode.Balance: return "平衡";
+ case FluxMode.Speed: return "速度";
+ default: return "?";
}
}
- // 属性访问器
+ public string GetModeShort()
+ {
+ switch (fluxMode)
+ {
+ case FluxMode.Manual: return "M";
+ case FluxMode.Quality: return "Q";
+ case FluxMode.Balance: return "B";
+ case FluxMode.Speed: return "S";
+ default: return "?";
+ }
+ }
+
+ // 孵化进度百分比(给 Gizmo 用)
+ public float IncubationProgress => incubationDuration > 0 ? incubationProgress / incubationDuration : 0f;
+ public float QualityPercent => qualityTotal > 0 ? qualityProgress / qualityTotal : 0f;
+
+ // 速度乘数
public float SpeedMultiplier
{
get
@@ -69,21 +117,27 @@ namespace ArachnaeSwarm
// 质量属性
public float QualityMultiplier => qualityMultiplier;
public float QualityProgress => qualityProgress;
- public float QualityPercent => qualityTotal > 0 ? qualityProgress / qualityTotal : 0f;
- // 营养液加成属性
- public int CurrentNutrientCount => currentNutrientCount;
- public float NutrientSpeedBonus => currentNutrientCount * Ext.nutrientSolutionBonusPerTile;
+ // 临时保留:营养液相关字段(后续清理)
+ private int totalNutrientCost = 0;
+ private int currentNutrientCount = 0;
+ private OothecaIncubatorExtension cachedExtension;
- // 进度百分比
- public float AdjustedProgressPercent
+ public OothecaIncubatorExtension Ext
{
get
{
- if (incubationDuration <= 0) return 0f;
- return incubationProgress / incubationDuration;
+ if (cachedExtension == null)
+ cachedExtension = def.GetModExtension() ?? OothecaIncubatorExtension.Default;
+ return cachedExtension;
}
}
+
+ // 营养液速度加成(临时保留)
+ public float NutrientSpeedBonus => currentNutrientCount * Ext.nutrientSolutionBonusPerTile;
+
+ // 进度百分比
+ public float AdjustedProgressPercent => incubationDuration > 0 ? incubationProgress / incubationDuration : 0f;
// === 简化的初始化营养液方法 ===
private void InitializeNutrientInfo()
@@ -108,7 +162,7 @@ namespace ArachnaeSwarm
UpdateNutrientCount();
}
- // === 简化的Tick方法 ===
+ // === Tick方法(带活性系统)===
protected override void Tick()
{
base.Tick();
@@ -126,12 +180,45 @@ namespace ArachnaeSwarm
UpdateSpeedMultiplier();
UpdateQualityMultiplier();
}
-
- float currentSpeed = SpeedMultiplier;
-
- // 始终增加进度(不再有营养液不足的暂停)
- incubationProgress += currentSpeed;
- qualityProgress += currentSpeed * QualityMultiplier;
+
+ // 自动模式计算
+ if (IsAutoMode && Find.TickManager.TicksGame % 250 == 0)
+ {
+ CalculateAutoFlux();
+ }
+
+ // 消耗虫蜜(基于孵化活性)
+ if (FuelComp != null && neutronFlux > 0.01f)
+ {
+ float fuelPerTick = (50f * FluxEfficiency) / 60000f;
+ FuelComp.ConsumeFuel(fuelPerTick);
+ }
+
+ // 休眠状态处理
+ if (IsDormant)
+ {
+ // 休眠时品质下降(10%/天)
+ float qualityDecay = (qualityTotal * 0.1f) / 60000f;
+ qualityProgress = Mathf.Max(0f, qualityProgress - qualityDecay);
+
+ if (qualityProgress <= 0 && qualityTotal > 0)
+ {
+ Messages.Message("制造舱因品质归零而损坏!", this, MessageTypeDefOf.NegativeEvent);
+ Destroy(DestroyMode.KillFinalize);
+ return;
+ }
+ }
+ else
+ {
+ // 正常状态:应用活性效率
+ float fluxSpeed = SpeedMultiplier * FluxEfficiency * 5f;
+ incubationProgress += fluxSpeed;
+
+ // 品质独立增长
+ float qualityBonus = 1f + (1f - neutronFlux) * 0.5f;
+ float qualityGain = SpeedMultiplier * QualityMultiplier * qualityBonus;
+ qualityProgress = Mathf.Min(qualityProgress + qualityGain, qualityTotal);
+ }
if (incubationProgress >= incubationDuration)
{
@@ -139,6 +226,57 @@ namespace ArachnaeSwarm
}
}
}
+
+ // 自动模式算法
+ private void CalculateAutoFlux()
+ {
+ if (fluxMode == FluxMode.Manual) return;
+
+ float targetFlux = 0.5f;
+ float incubationPercent = incubationDuration > 0 ? incubationProgress / incubationDuration : 0f;
+ float qualityPercent = qualityTotal > 0 ? qualityProgress / qualityTotal : 0f;
+ float gap = qualityPercent - incubationPercent;
+
+ switch (fluxMode)
+ {
+ case FluxMode.Quality:
+ if (qualityPercent >= 0.98f) targetFlux = 1.0f;
+ else if (gap > 0.2f) targetFlux = 0.6f;
+ else if (gap > 0.1f) targetFlux = 0.45f;
+ else if (gap > 0f) targetFlux = 0.35f;
+ else targetFlux = 0.2f;
+ break;
+
+ case FluxMode.Speed:
+ if (qualityPercent >= 0.95f) targetFlux = 1.0f;
+ else if (qualityPercent < 0.3f && incubationPercent > 0.5f) targetFlux = 0.7f;
+ else if (qualityPercent < 0.2f && incubationPercent > 0.7f) targetFlux = 0.5f;
+ else targetFlux = 1.0f;
+ break;
+
+ case FluxMode.Balance:
+ default:
+ if (qualityPercent >= 0.95f) targetFlux = 1.0f;
+ else if (gap > 0.15f) targetFlux = 0.8f;
+ else if (gap > 0.05f) targetFlux = 0.6f;
+ else if (gap > -0.05f) targetFlux = 0.5f;
+ else if (gap > -0.15f) targetFlux = 0.35f;
+ else targetFlux = 0.2f;
+ break;
+ }
+
+ // 资源保护
+ if (FuelComp != null && FuelComp.Fuel < 2f)
+ targetFlux = Mathf.Min(targetFlux, 0.2f);
+ if (MaintenanceComp != null && MaintenanceComp.CurrentMaintenance / MaintenanceComp.Props.maxMaintenance < 0.15f)
+ targetFlux = Mathf.Min(targetFlux, 0.15f);
+
+ // 平滑调节
+ float adjustSpeed = 0.03f;
+ if (neutronFlux < targetFlux) neutronFlux = Mathf.Min(neutronFlux + adjustSpeed, targetFlux);
+ else if (neutronFlux > targetFlux) neutronFlux = Mathf.Max(neutronFlux - adjustSpeed, targetFlux);
+ neutronFlux = Mathf.Clamp(neutronFlux, 0.1f, 1.0f);
+ }
// === 获取速度因子描述 ===
public string GetSpeedFactorsDescription()
@@ -565,18 +703,30 @@ namespace ArachnaeSwarm
// === Gizmos ===
public override IEnumerable GetGizmos()
{
+ // 过滤掉拆除按钮和半径显示
foreach (var gizmo in base.GetGizmos())
{
+ // 跳过拆除和半径相关的 Gizmo
+ if (gizmo is Command_Action cmd && cmd.defaultLabel != null)
+ {
+ string label = cmd.defaultLabel.ToString();
+ if (label.Contains("拆除") || label.Contains("Deconstruct") ||
+ label.Contains("半径") || label.Contains("Radius"))
+ continue;
+ }
yield return gizmo;
}
+ // 只有玩家派系才显示Gizmo
if (Faction == Faction.OfPlayer)
{
- if (!isIncubating && EquipmentIncubatorData?.IncubationConfigs?.Count > 0)
- {
- yield return CreateTargetSwitchGizmo();
- }
+ // 始终显示双进度条Gizmo
+ yield return new Gizmo_EquipmentIncubationProgress(this);
+ // 始终显示活性 Gizmo
+ yield return new Gizmo_NeutronFlux(this);
+
+ // 不在孵化中且研究完成时才显示呼叫按钮
var config = EquipmentIncubatorData?.SelectedConfig;
if (!isIncubating && config != null && config.IsResearchComplete)
{
@@ -590,6 +740,7 @@ namespace ArachnaeSwarm
};
}
+ // 如果正在孵化,显示取消按钮
if (isIncubating)
{
yield return new Command_Action
@@ -978,6 +1129,10 @@ namespace ArachnaeSwarm
Scribe_Values.Look(ref qualityTotal, "qualityTotal", 0f);
Scribe_Values.Look(ref totalNutrientCost, "totalNutrientCost", 0);
Scribe_Values.Look(ref currentNutrientCount, "currentNutrientCount", 0);
+
+ // 孵化活性系统
+ Scribe_Values.Look(ref neutronFlux, "neutronFlux", 0.5f);
+ Scribe_Values.Look(ref fluxMode, "fluxMode", FluxMode.Balance);
}
}
}
diff --git a/Source/ArachnaeSwarm/Buildings/Building_EquipmentOotheca/Gizmo_EquipmentIncubationProgress.cs b/Source/ArachnaeSwarm/Buildings/Building_EquipmentOotheca/Gizmo_EquipmentIncubationProgress.cs
new file mode 100644
index 0000000..a0c7bc8
--- /dev/null
+++ b/Source/ArachnaeSwarm/Buildings/Building_EquipmentOotheca/Gizmo_EquipmentIncubationProgress.cs
@@ -0,0 +1,239 @@
+// File: Gizmo_EquipmentIncubationProgress.cs
+// 装备孵化进度 Gizmo - 与 Gizmo_IncubationProgress 样式完全一致
+using System.Collections.Generic;
+using RimWorld;
+using UnityEngine;
+using Verse;
+
+namespace ArachnaeSwarm
+{
+ [StaticConstructorOnStartup]
+ public class Gizmo_EquipmentIncubationProgress : Gizmo
+ {
+ private readonly Building_EquipmentOotheca building;
+
+ // 尺寸常量(与 Gizmo_IncubationProgress 相同)
+ private const float Width = 180f;
+ private const float BarHeight = 14f;
+ private const float LabelHeight = 14f;
+ private const float Spacing = 4f;
+ private const float Padding = 8f;
+
+ // 进度条材质(与 Gizmo_IncubationProgress 相同)
+ 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 = -99f; // 在通量 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 - 25f, GetWidth(maxWidth), 100f);
+ 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 = "选择孵化目标...";
+
+ // 标题按钮(只有非孵化状态可点击)
+ 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 - 10f) + " ▼");
+ GUI.color = Color.white;
+ }
+ else
+ {
+ Widgets.Label(titleRect, title.Truncate(titleRect.width));
+ }
+ curY += Text.LineHeight + Spacing;
+
+ // === 内容绘制 ===
+ if (isIncubating)
+ {
+ // 孵化进度标签
+ DrawLabeledProgressBar(ref curY, innerRect.x, innerRect.width,
+ "孵化进度:", building.IncubationProgress, IncubationBarTex);
+
+ curY += Spacing;
+
+ // 品质进度标签
+ DrawLabeledProgressBar(ref curY, innerRect.x, innerRect.width,
+ "品质进度:", building.QualityPercent, QualityBarTex);
+ }
+ else if (hasLarva)
+ {
+ Text.Font = GameFont.Tiny;
+ GUI.color = new Color(0.9f, 0.9f, 0.5f);
+ string statusText = building.larvaOperateTicksRemaining > 0 ? "幼虫激活中..." : "幼虫赶路中...";
+ 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 = (config != null && config.IsResearchComplete) ? "就绪 - 点击上方切换目标" : "需要研究";
+ Widgets.Label(new Rect(innerRect.x, curY, innerRect.width, 20f), statusText);
+ curY += 20f;
+
+ string stats = $"速度:{building.SpeedMultiplier.ToStringPercent()} 质量:{building.QualityMultiplier.ToStringPercent()}";
+ Widgets.Label(new Rect(innerRect.x, curY, innerRect.width, 16f), stats);
+ GUI.color = Color.white;
+ }
+
+ // === 工具提示 ===
+ if (Mouse.IsOver(rect) && !Mouse.IsOver(titleRect))
+ {
+ Widgets.DrawHighlight(rect);
+ TooltipHandler.TipRegion(rect, GetTooltip());
+ }
+
+ 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}天)";
+ options.Add(new FloatMenuOption(label, () =>
+ {
+ building.EquipmentIncubatorData.SwitchToConfig(index);
+ }, icon, Color.white));
+ }
+ }
+
+ Find.WindowStack.Add(new FloatMenu(options));
+ }
+
+ // 带标签的进度条
+ private void DrawLabeledProgressBar(ref float curY, float x, float width, string label, float percent, Texture2D barTex)
+ {
+ // 标签
+ Text.Font = GameFont.Tiny;
+ GUI.color = new Color(0.8f, 0.8f, 0.8f);
+ Widgets.Label(new Rect(x, curY, width, LabelHeight), label);
+ GUI.color = Color.white;
+ curY += LabelHeight;
+
+ // 进度条
+ Rect barRect = new Rect(x, curY, width, BarHeight);
+ Widgets.FillableBar(barRect, percent, barTex, EmptyBarTex, true);
+
+ // 百分比文字
+ Text.Font = GameFont.Tiny;
+ Text.Anchor = TextAnchor.MiddleCenter;
+ Widgets.Label(barRect, percent.ToStringPercent("0"));
+ Text.Anchor = TextAnchor.UpperLeft;
+ curY += BarHeight;
+ }
+
+ private string GetTooltip()
+ {
+ var sb = new System.Text.StringBuilder();
+ bool isIncubating = building.isIncubating;
+
+ if (isIncubating && building.incubatingThingDef != null)
+ {
+ // 孵化中状态
+ sb.AppendLine("【孵化中】");
+ sb.AppendLine("目标: " + building.incubatingThingDef.LabelCap);
+ sb.AppendLine("孵化进度: " + building.IncubationProgress.ToStringPercent());
+ sb.AppendLine("品质进度: " + building.QualityPercent.ToStringPercent());
+
+ float remaining = building.incubationDuration - building.incubationProgress;
+ if (remaining > 0)
+ {
+ sb.AppendLine("剩余时间: " + ((int)remaining).ToStringTicksToPeriod());
+ }
+
+ sb.AppendLine();
+ sb.AppendLine("速度: " + building.SpeedMultiplier.ToStringPercent());
+ sb.AppendLine("质量: " + building.QualityMultiplier.ToStringPercent());
+ }
+ else
+ {
+ // 空闲状态
+ var config = building.EquipmentIncubatorData?.SelectedConfig;
+ if (config != null)
+ {
+ sb.AppendLine("【就绪】");
+ sb.AppendLine("目标: " + config.thingDef.LabelCap);
+ sb.AppendLine("孵化时间: " + config.daysRequired + " 天");
+ }
+ else
+ {
+ sb.AppendLine("【未选择目标】");
+ sb.AppendLine("点击上方标题选择孵化目标");
+ }
+
+ sb.AppendLine();
+ sb.AppendLine("当前速度加成: " + building.SpeedMultiplier.ToStringPercent());
+ sb.AppendLine("当前质量加成: " + building.QualityMultiplier.ToStringPercent());
+ }
+
+ 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 2368112..eccba9a 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
+ public class Building_Ootheca : Building, IFluxController
{
// 引用组件
public CompIncubatorData IncubatorData => this.TryGetComp();
@@ -19,7 +19,7 @@ namespace ArachnaeSwarm
public float incubationDuration = 0f;
public PawnKindDef incubatingPawnKind = null;
- // 幼虫交互相关 - 设为public以便ITab访问
+ // 幼虫交互相关
public Pawn assignedLarva = null;
public int larvaOperateTicksRemaining = 0;
@@ -39,15 +39,6 @@ namespace ArachnaeSwarm
private CompRefuelableNutrition fuelComp; // 燃料组件缓存
private Comp_SwarmMaintenance maintenanceComp; // 维护组件缓存
- // 活性模式枚举
- public enum FluxMode
- {
- Manual, // 手动:完全手动控制
- Quality, // 品质优先:低活性,追求高品质
- Balance, // 平衡:自动平衡速度和品质
- Speed // 速度优先:高活性,快速孵化
- }
-
// 孵化活性公开属性(非孵化时锁定为0)
public float NeutronFlux => isIncubating ? neutronFlux : 0f;
public float RawFlux => neutronFlux; // 原始值用于 Gizmo 显示
diff --git a/Source/ArachnaeSwarm/Buildings/Building_Ootheca/Gizmo_NeutronFlux.cs b/Source/ArachnaeSwarm/Buildings/Building_Ootheca/Gizmo_NeutronFlux.cs
index e1ec7db..c086b1e 100644
--- a/Source/ArachnaeSwarm/Buildings/Building_Ootheca/Gizmo_NeutronFlux.cs
+++ b/Source/ArachnaeSwarm/Buildings/Building_Ootheca/Gizmo_NeutronFlux.cs
@@ -1,5 +1,6 @@
// File: Gizmo_NeutronFlux.cs
-// 竖向滑动条样式的孵化活性调节 Gizmo(带刻度和可拖动光标)
+// 竖向滑动条样式的孵化活性调节 Gizmo(带刻度)
+// 支持实现 IFluxController 接口的所有建筑
using UnityEngine;
using Verse;
@@ -8,11 +9,12 @@ namespace ArachnaeSwarm
[StaticConstructorOnStartup]
public class Gizmo_NeutronFlux : Gizmo
{
- private readonly Building_Ootheca ootheca;
+ private readonly IFluxController controller;
+ private readonly Thing parentThing; // 用于获取 Thing 属性
// 尺寸常量
private const float Width = 100f;
- private const float GizmoHeight = 140f; // 增加高度与信息面板齐平
+ private const float GizmoHeight = 140f;
private const float Padding = 6f;
// 材质
@@ -23,10 +25,12 @@ namespace ArachnaeSwarm
private static readonly Texture2D TickMarkTex = SolidColorMaterials.NewSolidColorTexture(new Color(0.4f, 0.4f, 0.4f, 0.8f));
private static readonly Texture2D CursorTex = SolidColorMaterials.NewSolidColorTexture(new Color(0.9f, 0.9f, 0.9f, 1f));
- public Gizmo_NeutronFlux(Building_Ootheca ootheca)
+ // 构造函数接受接口
+ public Gizmo_NeutronFlux(IFluxController controller)
{
- this.ootheca = ootheca;
- Order = -100f; // 最先显示
+ this.controller = controller;
+ this.parentThing = controller as Thing;
+ Order = -100f;
}
public override float GetWidth(float maxWidth)
@@ -54,12 +58,12 @@ namespace ArachnaeSwarm
// 根据模式显示不同颜色
Color modeColor;
- switch (ootheca.CurrentFluxMode)
+ switch (controller.CurrentFluxMode)
{
- case Building_Ootheca.FluxMode.Manual: modeColor = new Color(0.5f, 0.5f, 0.5f, 0.9f); break;
- case Building_Ootheca.FluxMode.Quality: modeColor = new Color(0.3f, 0.6f, 0.9f, 0.9f); break;
- case Building_Ootheca.FluxMode.Balance: modeColor = new Color(0.2f, 0.7f, 0.2f, 0.9f); break;
- case Building_Ootheca.FluxMode.Speed: modeColor = new Color(0.9f, 0.5f, 0.2f, 0.9f); break;
+ case FluxMode.Manual: modeColor = new Color(0.5f, 0.5f, 0.5f, 0.9f); break;
+ case FluxMode.Quality: modeColor = new Color(0.3f, 0.6f, 0.9f, 0.9f); break;
+ case FluxMode.Balance: modeColor = new Color(0.2f, 0.7f, 0.2f, 0.9f); break;
+ case FluxMode.Speed: modeColor = new Color(0.9f, 0.5f, 0.2f, 0.9f); break;
default: modeColor = Color.gray; break;
}
@@ -69,11 +73,11 @@ namespace ArachnaeSwarm
Text.Font = GameFont.Tiny;
Text.Anchor = TextAnchor.MiddleCenter;
GUI.color = Color.white;
- Widgets.Label(modeRect, ootheca.GetModeShort());
+ Widgets.Label(modeRect, controller.GetModeShort());
if (Widgets.ButtonInvisible(modeRect))
{
- ootheca.CycleFluxMode();
+ controller.CycleFluxMode();
}
// === 竖向计量条 ===
@@ -84,14 +88,14 @@ namespace ArachnaeSwarm
Rect barRect = new Rect(barX, barY, barWidth, barHeight);
// 非孵化时显示灰色锁定状态
- bool isLocked = !ootheca.IsIncubating;
+ bool isLocked = !controller.IsIncubating;
// 绘制背景
GUI.color = isLocked ? new Color(0.3f, 0.3f, 0.3f, 0.5f) : Color.white;
GUI.DrawTexture(barRect, EmptyBarTex);
// 绘制填充(从底部向上)- 使用 RawFlux 显示预设值
- float displayFlux = ootheca.RawFlux;
+ float displayFlux = controller.RawFlux;
float fillHeight = barRect.height * displayFlux;
Rect fillRect = new Rect(barRect.x, barRect.yMax - fillHeight, barRect.width, fillHeight);
GUI.color = isLocked ? new Color(0.5f, 0.35f, 0.1f, 0.5f) : Color.white;
@@ -150,9 +154,9 @@ namespace ArachnaeSwarm
Text.Anchor = TextAnchor.MiddleLeft;
// 百分比(大字)
- GUI.color = ootheca.IsDormant ? Color.red : Color.white;
+ GUI.color = controller.IsDormant ? Color.red : Color.white;
Rect percentRect = new Rect(infoX, barRect.y, infoWidth, 20f);
- Widgets.Label(percentRect, (ootheca.NeutronFlux * 100f).ToString("0") + "%");
+ Widgets.Label(percentRect, (controller.NeutronFlux * 100f).ToString("0") + "%");
Text.Font = GameFont.Tiny;
@@ -162,11 +166,11 @@ namespace ArachnaeSwarm
Widgets.Label(effRect, "效率");
Rect effValRect = new Rect(infoX, barRect.y + 36f, infoWidth, 14f);
GUI.color = Color.white;
- Widgets.Label(effValRect, (ootheca.FluxEfficiency * 100f).ToString("0") + "%");
+ Widgets.Label(effValRect, (controller.FluxEfficiency * 100f).ToString("0") + "%");
// 速度倍率
GUI.color = new Color(0.7f, 0.7f, 0.7f);
- float speedMultiplier = ootheca.FluxEfficiency * 5f;
+ float speedMultiplier = controller.FluxEfficiency * 5f;
Rect speedRect = new Rect(infoX, barRect.y + 54f, infoWidth, 14f);
Widgets.Label(speedRect, "速度");
Rect speedValRect = new Rect(infoX, barRect.y + 68f, infoWidth, 14f);
@@ -190,7 +194,7 @@ namespace ArachnaeSwarm
private void UpdateFluxFromMouse(Rect barRect, float mouseY)
{
float percent = 1f - (mouseY - barRect.y) / barRect.height;
- ootheca.SetNeutronFlux(Mathf.Clamp01(percent));
+ controller.SetNeutronFlux(Mathf.Clamp01(percent));
}
private string GetTooltip()
@@ -206,24 +210,24 @@ namespace ArachnaeSwarm
sb.AppendLine();
// 当前状态
- sb.AppendLine($"当前活性: {(ootheca.RawFlux * 100f):0}%");
- sb.AppendLine($"孵化速度: {(ootheca.FluxEfficiency * 5f):0.0}x");
+ sb.AppendLine($"当前活性: {(controller.RawFlux * 100f):0}%");
+ sb.AppendLine($"孵化速度: {(controller.FluxEfficiency * 5f):0.0}x");
sb.AppendLine();
// 模式说明
- sb.AppendLine($"模式: {ootheca.GetModeName()}");
- switch (ootheca.CurrentFluxMode)
+ sb.AppendLine($"模式: {controller.GetModeName()}");
+ switch (controller.CurrentFluxMode)
{
- case Building_Ootheca.FluxMode.Manual:
+ case FluxMode.Manual:
sb.AppendLine(" 手动调节活性");
break;
- case Building_Ootheca.FluxMode.Quality:
+ case FluxMode.Quality:
sb.AppendLine(" 低活性,追求品质");
break;
- case Building_Ootheca.FluxMode.Balance:
+ case FluxMode.Balance:
sb.AppendLine(" 自动平衡速度和品质");
break;
- case Building_Ootheca.FluxMode.Speed:
+ case FluxMode.Speed:
sb.AppendLine(" 高活性,快速孵化");
break;
}
@@ -232,7 +236,7 @@ namespace ArachnaeSwarm
// 操作
sb.AppendLine("点击拖动调节 | 右上角切换模式");
- if (ootheca.IsDormant)
+ if (controller.IsDormant)
{
sb.AppendLine();
sb.AppendLine("⚠ 休眠中,品质下降!");
diff --git a/Source/ArachnaeSwarm/Buildings/IFluxController.cs b/Source/ArachnaeSwarm/Buildings/IFluxController.cs
new file mode 100644
index 0000000..50f8d91
--- /dev/null
+++ b/Source/ArachnaeSwarm/Buildings/IFluxController.cs
@@ -0,0 +1,37 @@
+namespace ArachnaeSwarm
+{
+ ///
+ /// 共享接口:孵化活性控制器
+ /// Building_Ootheca 和 Building_EquipmentOotheca 都实现此接口
+ ///
+ public interface IFluxController
+ {
+ // 活性值
+ float NeutronFlux { get; }
+ float RawFlux { get; }
+ float FluxEfficiency { get; }
+
+ // 模式
+ FluxMode CurrentFluxMode { get; }
+ bool IsAutoMode { get; }
+ bool IsIncubating { get; }
+ bool IsDormant { get; }
+
+ // 方法
+ void SetNeutronFlux(float value);
+ void CycleFluxMode();
+ string GetModeName();
+ string GetModeShort();
+ }
+
+ ///
+ /// 活性模式枚举(共享)
+ ///
+ public enum FluxMode
+ {
+ Manual, // 手动:完全手动控制
+ Quality, // 品质优先:低活性,追求高品质
+ Balance, // 平衡:自动平衡速度和品质
+ Speed // 速度优先:高活性,快速孵化
+ }
+}