This commit is contained in:
2025-12-23 14:13:12 +08:00
parent 84f5bf036c
commit c70e4daf38
9 changed files with 525 additions and 85 deletions

Binary file not shown.

Binary file not shown.

View File

@@ -60,6 +60,7 @@
<li>ARA_Acidling_AutoMortar</li>
<li>CatastropheMissileSilo</li>
<li>ARA_AutoSniperCannon</li>
<li>ARA_Pawn_Ootheca</li>
</linkableBuildings>
<maxDistance>80</maxDistance> <!-- 供能范围 -->
<maxSimultaneous>10</maxSimultaneous>

View File

@@ -151,9 +151,7 @@
<ARA_InsectJelly>25</ARA_InsectJelly>
</costList>
<placeWorkers>
<li>ArachnaeSwarm.PlaceWorker_CustomRadius</li>
</placeWorkers>
<comps>
<li Class="ArachnaeSwarm.CompProperties_SwarmMaintenance">
<maxMaintenance>100</maxMaintenance>
@@ -162,15 +160,27 @@
<warningThreshold>0.2</warningThreshold>
<maintenanceThresholdForJob>0.5</maintenanceThresholdForJob>
</li>
<li Class="ArachnaeSwarm.CompProperties_CustomRadius">
<radius>5</radius> <!-- 半径大小 -->
<color>(0.5, 1, 1)</color> <!-- 绿色圆圈 -->
<radiusOffset>0</radiusOffset> <!-- 半径偏移 -->
<showInGUI>true</showInGUI>
<label>吸收半径</label>
<description>这个卵在孵化过程中的吸收半径,确保这些地格中铺满阿拉克涅营养液,并且没有其他的卵,以获得最佳的孵化速度和孵化质量。</description>
<defaultVisible>false</defaultVisible>
<!-- 虫蜜燃料系统 -->
<li Class="ArachnaeSwarm.CompProperties_RefuelableNutrition">
<fuelCapacity>25.0</fuelCapacity>
<fuelFilter>
<thingDefs>
<li>ARA_InsectJelly</li>
</thingDefs>
</fuelFilter>
<fuelGizmoLabel>虫蜜</fuelGizmoLabel>
<showAllowAutoRefuelToggle>true</showAllowAutoRefuelToggle>
<targetFuelLevelConfigurable>true</targetFuelLevelConfigurable>
<initialConfigurableTargetFuelLevel>5</initialConfigurableTargetFuelLevel>
<consumeFuelOnlyWhenUsed>true</consumeFuelOnlyWhenUsed>
</li>
<li Class="CompProperties_AffectedByFacilities">
<linkableFacilities>
<li>ARA_NutrientNetworkTower</li>
</linkableFacilities>
</li>
<li Class="ArachnaeSwarm.CompProperties_IncubatorData">
<!-- 按钮和菜单配置 -->
<defaultIndex>0</defaultIndex>

View File

@@ -124,6 +124,7 @@
<Compile Include="Buildings\Building_Ootheca\Building_Ootheca.cs" />
<Compile Include="Buildings\Building_Ootheca\CompProperties_IncubatorData.cs" />
<Compile Include="Buildings\Building_Ootheca\Gizmo_IncubationProgress.cs" />
<Compile Include="Buildings\Building_Ootheca\Gizmo_NeutronFlux.cs" />
<Compile Include="Buildings\Building_Ootheca\JobDriver_OperateIncubator.cs" />
<Compile Include="Buildings\Building_Ootheca\OothecaIncubatorExtension.cs" />
<Compile Include="Buildings\Building_ResearchBlueprintReader\Building_ResearchBlueprintReader.cs" />

View File

@@ -88,9 +88,27 @@ namespace ArachnaeSwarm
{
if (parent == null || parent.Map == null)
return;
// 计算递减量每天递减量转换为每2500tick约0.347天的递减量
float decayAmount = Props.maintenanceDecayPerDay * (2500f / 60000f);
// 计算基础递减量每天递减量转换为每2500tick约0.0417天的递减量
float baseDecayAmount = Props.maintenanceDecayPerDay * (2500f / 60000f);
// 检查是否为卵囊建筑,并根据孵化状态调整消耗
float decayMultiplier = 1f;
if (parent is Building_Ootheca ootheca)
{
if (!ootheca.IsIncubating)
{
// 未孵化时维护消耗减少80%
decayMultiplier = 0.2f;
}
else
{
// 孵化时根据活性调整(活性越高消耗越多)
decayMultiplier = 0.5f + ootheca.FluxEfficiency * 0.5f;
}
}
float decayAmount = baseDecayAmount * decayMultiplier;
currentMaintenance -= decayAmount;
// 确保不低于0

View File

@@ -33,6 +33,42 @@ namespace ArachnaeSwarm
private float qualityProgress = 0f;
private float qualityTotal = 0f;
// ======= 中子通量系统 =======
private float neutronFlux = 0.5f; // 0-1, 默认50%
private bool autoFluxMode = true; // 自动模式
private CompRefuelableNutrition fuelComp; // 燃料组件缓存
private Comp_SwarmMaintenance maintenanceComp; // 维护组件缓存
// 孵化活性公开属性非孵化时锁定为0
public float NeutronFlux => isIncubating ? neutronFlux : 0f;
public float RawFlux => neutronFlux; // 原始值用于 Gizmo 显示
public bool AutoFluxMode => autoFluxMode;
// 获取燃料组件
public CompRefuelableNutrition FuelComp => fuelComp ?? (fuelComp = this.TryGetComp<CompRefuelableNutrition>());
public Comp_SwarmMaintenance MaintenanceComp => maintenanceComp ?? (maintenanceComp = this.TryGetComp<Comp_SwarmMaintenance>());
// 孵化活性效率曲线非线性flux² 使低活性效率极低)
public float FluxEfficiency => NeutronFlux * NeutronFlux;
// 是否处于休眠状态无燃料或活性为0
public bool IsDormant => NeutronFlux < 0.01f || (FuelComp != null && !FuelComp.HasFuel);
// 是否正在孵化(公开属性)
public bool IsIncubating => isIncubating;
// 设置中子通量
public void SetNeutronFlux(float value)
{
neutronFlux = Mathf.Clamp01(value);
}
// 切换自动模式
public void ToggleAutoMode()
{
autoFluxMode = !autoFluxMode;
}
// 缓存的ModExtension
private OothecaIncubatorExtension cachedExtension;
@@ -81,38 +117,18 @@ namespace ArachnaeSwarm
public string GetSpeedFactorsDescription()
{
var builder = new StringBuilder();
builder.AppendLine("ARA_OothecaIncubator.SpeedFactors".Translate());
builder.AppendLine("速度因子");
builder.AppendLine();
// 1. 检查是否在孵化间中
// 检查是否在孵化间中
bool inIncubatorRoom = IsInIncubatorRoom();
if (Ext.requiresIncubatorRoom)
{
builder.AppendLine(inIncubatorRoom ?
"ARA_OothecaIncubator.InIncubatorRoom".Translate() :
"ARA_OothecaIncubator.NotInIncubatorRoom".Translate());
builder.AppendLine(inIncubatorRoom ? "✓ 在孵化间中" : "✗ 不在孵化间中");
}
// 2. 检查营养液数量
int nutrientSolutionCount = CountNearbyNutrientSolutions();
if (nutrientSolutionCount > 0)
{
builder.AppendLine("ARA_OothecaIncubator.NutrientSolutions".Translate(
nutrientSolutionCount,
nutrientSolutionCount * Ext.nutrientSolutionBonusPerTile * 100));
}
else
{
builder.AppendLine("ARA_OothecaIncubator.NoNutrientSolutionsNearby".Translate());
}
// 显示检测半径
builder.AppendLine();
builder.AppendLine("ARA_OothecaIncubator.NutrientDetectionRadius".Translate(Ext.nutrientSolutionRadius));
builder.AppendLine();
builder.AppendLine("ARA_OothecaIncubator.TotalSpeedMultiplier".Translate(SpeedMultiplier.ToStringPercent()));
builder.AppendLine("总速度倍率: " + SpeedMultiplier.ToStringPercent());
return builder.ToString().TrimEndNewlines();
}
@@ -422,22 +438,25 @@ public override string GetInspectString()
// Gizmos
public override IEnumerable<Gizmo> GetGizmos()
{
// 过滤掉拆除按钮
foreach (var gizmo in base.GetGizmos())
{
// 跳过拆除相关的 Gizmo
if (gizmo is Command_Action cmd && cmd.defaultLabel != null &&
(cmd.defaultLabel.ToString().Contains("拆除") || cmd.defaultLabel.ToString().Contains("Deconstruct")))
continue;
yield return gizmo;
}
// 只有玩家派系才显示Gizmo
if (Faction == Faction.OfPlayer)
{
// 始终显示双进度条Gizmo(内部会自动处理非孵化状态的显示)
// 始终显示双进度条Gizmo
yield return new Gizmo_IncubationProgress(this);
// 不在孵化中时才显示切换目标按钮
if (!isIncubating && IncubatorData?.IncubationConfigs?.Count > 0)
{
yield return CreateTargetSwitchGizmo();
}
// 中子通量控制 Gizmo
yield return new Gizmo_NeutronFlux(this);
// 不在孵化中且研究完成时才显示呼叫按钮
var config = IncubatorData?.SelectedConfig;
@@ -661,40 +680,181 @@ public override string GetInspectString()
}
// 孵化进度 - 使用override而不是new
protected override void Tick()
protected override void Tick()
{
base.Tick();
// 减少操作剩余时间(仅用于显示)
if (larvaOperateTicksRemaining > 0)
{
larvaOperateTicksRemaining--;
}
// 只有在孵化过程中才消耗资源和自动调节
if (isIncubating)
{
// 自动模式计算每250ticks更新一次
if (autoFluxMode && Find.TickManager.TicksGame % 250 == 0)
{
base.Tick();
CalculateAutoFlux();
}
// 消耗虫蜜(基于孵化活性)
if (FuelComp != null && neutronFlux > 0.01f)
{
// 基础消耗50虫蜜/天 在100%活性,非线性
float baseConsumptionPerDay = 50f * FluxEfficiency;
float consumptionPerTick = baseConsumptionPerDay / 60000f;
FuelComp.ConsumeFuel(consumptionPerTick);
}
}
// 更新孵化进度和质量进度
if (isIncubating)
{
// 更新乘数
if (lastMultiplierUpdateTick < 0 || Find.TickManager.TicksGame - lastMultiplierUpdateTick >= MultiplierUpdateInterval)
{
UpdateSpeedMultiplier();
UpdateQualityMultiplier();
}
// 检查是否休眠
if (IsDormant)
{
// 休眠状态:品质进度下降
float qualityDecayPerTick = 0.1f / 60000f; // 每天下降10%
qualityProgress = Mathf.Max(0, qualityProgress - qualityDecayPerTick * incubationDuration);
// 减少操作剩余时间(仅用于显示)
if (larvaOperateTicksRemaining > 0)
// 品质归零 → 破坏卵
if (qualityProgress <= 0 && qualityTotal > 0)
{
larvaOperateTicksRemaining--;
// 注意孵化启动现在由JobDriver触发这里只更新显示
}
// 更新孵化进度和质量进度
if (isIncubating)
{
// 更新质量乘数(与速度乘数同步更新)
if (lastMultiplierUpdateTick < 0 || Find.TickManager.TicksGame - lastMultiplierUpdateTick >= MultiplierUpdateInterval)
{
UpdateSpeedMultiplier();
UpdateQualityMultiplier();
}
// 应用速度乘数
float currentSpeed = SpeedMultiplier;
incubationProgress += currentSpeed;
// 质量进度与速度同步增长,但乘以质量乘数
qualityProgress += currentSpeed * QualityMultiplier;
if (incubationProgress >= incubationDuration)
{
CompleteIncubation();
}
Messages.Message("卵囊因品质归零而损坏!", this, MessageTypeDefOf.NegativeEvent);
Destroy(DestroyMode.KillFinalize);
return;
}
}
else
{
// 正常状态应用中子通量效率100%通量时5倍速度
float fluxSpeed = SpeedMultiplier * FluxEfficiency * 5f;
incubationProgress += fluxSpeed;
// 质量进度也受中子通量影响
float fluxQuality = QualityMultiplier * FluxEfficiency * 5f;
qualityProgress += fluxSpeed * fluxQuality;
}
if (incubationProgress >= incubationDuration)
{
CompleteIncubation();
}
}
}
// 自动模式:智能计算最优中子通量
// 目标:在资源允许的情况下,尽可能快速完成孵化
private void CalculateAutoFlux()
{
if (!autoFluxMode) return;
float targetFlux = 1.0f; // 默认100%
// === 策略1根据孵化剩余时间优化 ===
if (isIncubating && incubationDuration > 0)
{
float remainingProgress = incubationDuration - incubationProgress;
float remainingDays = remainingProgress / (60000f * SpeedMultiplier);
// 计算虫蜜能维持多少天(按当前通量)
float fuelDays = float.MaxValue;
if (FuelComp != null && FuelComp.Fuel > 0)
{
// 消耗率 = 50 * flux² 每天
float currentConsumption = 50f * neutronFlux * neutronFlux;
fuelDays = currentConsumption > 0 ? FuelComp.Fuel / currentConsumption : float.MaxValue;
}
// 计算维护能维持多少天
float maintenanceDays = float.MaxValue;
if (MaintenanceComp != null)
{
float maintenance = MaintenanceComp.CurrentMaintenance;
float decayPerDay = MaintenanceComp.Props.maintenanceDecayPerDay;
maintenanceDays = decayPerDay > 0 ? maintenance / decayPerDay : float.MaxValue;
}
// 找到瓶颈资源
float minResourceDays = Mathf.Min(fuelDays, maintenanceDays);
// 安全边际:资源至少要能维持 剩余孵化天数 + 0.5天
float requiredDays = remainingDays + 0.5f;
if (minResourceDays < requiredDays && minResourceDays > 0)
{
// 资源不足,需要降低通量
// 用二分法找到刚好能完成孵化的通量
float lowFlux = 0.1f;
float highFlux = neutronFlux;
for (int i = 0; i < 8; i++) // 8次迭代足够精确
{
float midFlux = (lowFlux + highFlux) / 2f;
float testEfficiency = midFlux * midFlux;
float testSpeed = SpeedMultiplier * testEfficiency * 5f;
float testDays = testSpeed > 0 ? remainingProgress / (testSpeed * 60000f) : float.MaxValue;
// 计算该通量下资源能维持多久
float testFuelDays = FuelComp != null && FuelComp.Fuel > 0
? FuelComp.Fuel / (50f * testEfficiency + 0.01f)
: float.MaxValue;
if (testFuelDays >= testDays + 0.5f)
lowFlux = midFlux; // 可以更高
else
highFlux = midFlux; // 需要更低
}
targetFlux = lowFlux;
}
}
// === 策略2紧急保护 ===
// 虫蜜极低时紧急降速
if (FuelComp != null && FuelComp.Fuel < 5f)
{
targetFlux = Mathf.Min(targetFlux, 0.3f);
}
// 维护极低时紧急降速
if (MaintenanceComp != null)
{
float maintenancePercent = MaintenanceComp.CurrentMaintenance / MaintenanceComp.Props.maxMaintenance;
if (maintenancePercent < 0.15f)
{
targetFlux = Mathf.Min(targetFlux, 0.2f);
}
}
// === 策略3资源充足时全速 ===
bool fuelAbundant = FuelComp == null || FuelComp.Fuel > FuelComp.Props.fuelCapacity * 0.8f;
bool maintenanceAbundant = MaintenanceComp == null ||
MaintenanceComp.CurrentMaintenance > MaintenanceComp.Props.maxMaintenance * 0.7f;
if (fuelAbundant && maintenanceAbundant)
{
targetFlux = 1.0f;
}
// 平滑调节避免突变每次最多调整5%
float adjustSpeed = 0.05f;
if (neutronFlux < targetFlux)
neutronFlux = Mathf.Min(neutronFlux + adjustSpeed, targetFlux);
else if (neutronFlux > targetFlux)
neutronFlux = Mathf.Max(neutronFlux - adjustSpeed, targetFlux);
neutronFlux = Mathf.Clamp(neutronFlux, 0.05f, 1.0f); // 最低5%防止完全停止
}
// 应用质量效果到生成的pawn
private void ApplyQualityEffects(Pawn pawn, float qualityPercent)
@@ -862,23 +1022,17 @@ public override string GetInspectString()
return count;
}
// 更新速度乘数
// 更新速度乘数(已移除营养液逻辑,后续将使用 CompRefuelableNutrition
private void UpdateSpeedMultiplier()
{
float multiplier = 1.0f;
// 1. 检查是否在孵化间中(如果要求)
// 检查是否在孵化间中(如果要求)
if (Ext.requiresIncubatorRoom && !IsInIncubatorRoom())
{
multiplier *= Ext.speedPenaltyOutsideIncubator; // 应用惩罚
multiplier *= Ext.speedPenaltyOutsideIncubator;
}
// 2. 计算周围营养液的加成
int nutrientSolutionCount = CountNearbyNutrientSolutions();
float nutrientBonus = 1.0f + (nutrientSolutionCount * Ext.nutrientSolutionBonusPerTile);
multiplier *= nutrientBonus;
speedMultiplier = multiplier;
lastMultiplierUpdateTick = Find.TickManager.TicksGame;
}
@@ -927,6 +1081,10 @@ public override string GetInspectString()
Scribe_Values.Look(ref qualityMultiplier, "qualityMultiplier", 1.0f);
Scribe_Values.Look(ref qualityProgress, "qualityProgress", 0f);
Scribe_Values.Look(ref qualityTotal, "qualityTotal", 0f);
// 中子通量系统
Scribe_Values.Look(ref neutronFlux, "neutronFlux", 0.5f);
Scribe_Values.Look(ref autoFluxMode, "autoFluxMode", true);
}
}
}

View File

@@ -27,7 +27,7 @@ namespace ArachnaeSwarm
public Gizmo_IncubationProgress(Building_Ootheca ootheca)
{
this.ootheca = ootheca;
Order = -100f; // 显示在左侧
Order = -99f; // 在通量 Gizmo 之后显示
}
public override float GetWidth(float maxWidth)
@@ -37,8 +37,8 @@ namespace ArachnaeSwarm
public override GizmoResult GizmoOnGUI(Vector2 topLeft, float maxWidth, GizmoRenderParms parms)
{
// 主矩形区域(向上偏移以容纳更高的内容)
Rect rect = new Rect(topLeft.x, topLeft.y - 55f, GetWidth(maxWidth), 130f);
// 主矩形区域
Rect rect = new Rect(topLeft.x, topLeft.y - 25f, GetWidth(maxWidth), 100f);
Widgets.DrawWindowBackground(rect);
// 内部区域

View File

@@ -0,0 +1,252 @@
// File: Gizmo_NeutronFlux.cs
// 竖向滑动条样式的孵化活性调节 Gizmo带刻度和可拖动光标
using UnityEngine;
using Verse;
namespace ArachnaeSwarm
{
[StaticConstructorOnStartup]
public class Gizmo_NeutronFlux : Gizmo
{
private readonly Building_Ootheca ootheca;
// 尺寸常量
private const float Width = 100f;
private const float GizmoHeight = 140f; // 增加高度与信息面板齐平
private const float Padding = 6f;
// 材质
private static readonly Texture2D FluxBarTex = SolidColorMaterials.NewSolidColorTexture(new Color(0.9f, 0.5f, 0.1f, 0.9f));
private static readonly Texture2D EmptyBarTex = SolidColorMaterials.NewSolidColorTexture(new Color(0.15f, 0.15f, 0.15f, 0.8f));
private static readonly Texture2D AutoOnTex = SolidColorMaterials.NewSolidColorTexture(new Color(0.2f, 0.7f, 0.2f, 0.9f));
private static readonly Texture2D AutoOffTex = SolidColorMaterials.NewSolidColorTexture(new Color(0.5f, 0.3f, 0.3f, 0.7f));
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));
private bool isDragging = false;
public Gizmo_NeutronFlux(Building_Ootheca ootheca)
{
this.ootheca = ootheca;
Order = -100f; // 最先显示
}
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 - 65f, GetWidth(maxWidth), GizmoHeight);
Widgets.DrawWindowBackground(rect);
Rect innerRect = rect.ContractedBy(Padding);
// === 标题行 ===
Text.Font = GameFont.Small;
Text.Anchor = TextAnchor.MiddleLeft;
Rect titleRect = new Rect(innerRect.x, innerRect.y, innerRect.width - 24f, 18f);
Widgets.Label(titleRect, "活性");
// === 右上角自动模式按钮 ===
float buttonSize = 20f;
Rect autoRect = new Rect(innerRect.xMax - buttonSize, innerRect.y, buttonSize, buttonSize);
GUI.DrawTexture(autoRect, ootheca.AutoFluxMode ? AutoOnTex : AutoOffTex);
Widgets.DrawBox(autoRect, 1);
Text.Font = GameFont.Tiny;
Text.Anchor = TextAnchor.MiddleCenter;
GUI.color = Color.white;
Widgets.Label(autoRect, ootheca.AutoFluxMode ? "A" : "M");
if (Widgets.ButtonInvisible(autoRect))
{
ootheca.ToggleAutoMode();
}
// === 竖向滑动条 ===
float barWidth = 32f;
float barHeight = 90f; // 增加高度
float barX = innerRect.x + 8f;
float barY = innerRect.y + 24f;
Rect barRect = new Rect(barX, barY, barWidth, barHeight);
// 非孵化时显示灰色锁定状态
bool isLocked = !ootheca.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 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;
GUI.DrawTexture(fillRect, FluxBarTex);
GUI.color = Color.white;
// 绘制刻度线10格
for (int i = 1; i < 10; i++)
{
float tickY = barRect.y + barRect.height * (1f - i / 10f);
float tickWidth = (i == 5) ? barRect.width * 0.6f : barRect.width * 0.3f;
Rect tickRect = new Rect(barRect.x, tickY - 0.5f, tickWidth, 1f);
GUI.DrawTexture(tickRect, TickMarkTex);
}
// 绘制边框
Widgets.DrawBox(barRect, 1);
// === 可拖动光标(三角形指示器)===
float cursorY = barRect.yMax - fillHeight;
float cursorWidth = 12f;
float cursorHeight = 14f;
Rect cursorRect = new Rect(barRect.xMax + 2f, cursorY - cursorHeight / 2f, cursorWidth, cursorHeight);
// 绘制三角形光标(指向左边)
GUI.color = isDragging ? new Color(1f, 0.8f, 0.3f, 1f) : new Color(0.9f, 0.9f, 0.9f, 1f);
for (int i = 0; i < 7; i++)
{
float w = cursorWidth * (1f - Mathf.Abs(i - 3) / 4f);
float y = cursorY - 3.5f + i;
Rect lineRect = new Rect(cursorRect.x, y, w, 1f);
GUI.DrawTexture(lineRect, CursorTex);
}
GUI.color = Color.white;
// === 拖动交互(包括光标区域)===
Rect interactRect = new Rect(barRect.x - 5f, barRect.y - 5f, barRect.width + cursorWidth + 15f, barRect.height + 10f);
if (Event.current.type == EventType.MouseDown && interactRect.Contains(Event.current.mousePosition))
{
isDragging = true;
UpdateFluxFromMouse(barRect);
Event.current.Use();
}
if (Event.current.type == EventType.MouseUp)
{
isDragging = false;
}
if (isDragging && (Event.current.type == EventType.MouseDrag || Event.current.type == EventType.Repaint))
{
if (Event.current.type == EventType.MouseDrag)
{
UpdateFluxFromMouse(barRect);
Event.current.Use();
}
}
// === 右侧信息显示 ===
float infoX = barRect.xMax + 18f;
float infoWidth = innerRect.xMax - infoX;
Text.Font = GameFont.Small;
Text.Anchor = TextAnchor.MiddleLeft;
// 百分比(大字)
GUI.color = ootheca.IsDormant ? Color.red : Color.white;
Rect percentRect = new Rect(infoX, barRect.y, infoWidth, 20f);
Widgets.Label(percentRect, (ootheca.NeutronFlux * 100f).ToString("0") + "%");
Text.Font = GameFont.Tiny;
// 效率
GUI.color = new Color(0.7f, 0.7f, 0.7f);
Rect effRect = new Rect(infoX, barRect.y + 22f, infoWidth, 14f);
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") + "%");
// 速度倍率
GUI.color = new Color(0.7f, 0.7f, 0.7f);
float speedMultiplier = ootheca.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);
GUI.color = speedMultiplier >= 1f ? new Color(0.5f, 1f, 0.5f) : new Color(1f, 0.7f, 0.5f);
Widgets.Label(speedValRect, speedMultiplier.ToString("0.0") + "x");
GUI.color = Color.white;
Text.Anchor = TextAnchor.UpperLeft;
Text.Font = GameFont.Small;
// 工具提示
if (Mouse.IsOver(rect))
{
Widgets.DrawHighlight(rect);
TooltipHandler.TipRegion(rect, GetTooltip());
}
return new GizmoResult(GizmoState.Clear);
}
private void UpdateFluxFromMouse(Rect barRect)
{
float mouseY = Event.current.mousePosition.y;
float percent = 1f - (mouseY - barRect.y) / barRect.height;
ootheca.SetNeutronFlux(Mathf.Clamp01(percent));
}
private string GetTooltip()
{
var sb = new System.Text.StringBuilder();
// 标题
sb.AppendLine("【孵化活性控制器】");
sb.AppendLine();
// 当前状态
sb.AppendLine("═══ 当前状态 ═══");
sb.AppendLine($"活性: {(ootheca.NeutronFlux * 100f):0}%");
sb.AppendLine($"效率: {(ootheca.FluxEfficiency * 100f):0}% (活性²)");
sb.AppendLine($"孵化速度: {(ootheca.FluxEfficiency * 5f):0.0}x");
sb.AppendLine($"模式: {(ootheca.AutoFluxMode ? "" : "")}");
sb.AppendLine();
// 效率说明
sb.AppendLine("═══ 效率曲线 ═══");
sb.AppendLine("活性与效率呈非线性关系:");
sb.AppendLine(" 20% 活性 → 4% 效率 (0.2x速度)");
sb.AppendLine(" 50% 活性 → 25% 效率 (1.25x速度)");
sb.AppendLine(" 70% 活性 → 49% 效率 (2.45x速度)");
sb.AppendLine(" 100% 活性 → 100% 效率 (5x速度)");
sb.AppendLine();
// 消耗说明
sb.AppendLine("═══ 资源消耗 ═══");
float dailyFuelConsumption = 50f * ootheca.FluxEfficiency;
sb.AppendLine($"虫蜜消耗: {dailyFuelConsumption:0.0}/天");
sb.AppendLine("(基础50/天 × 效率)");
sb.AppendLine();
// 操作说明
sb.AppendLine("═══ 操作指南 ═══");
sb.AppendLine("• 拖动滑块或光标调节通量");
sb.AppendLine("• 右上角[A/M]切换模式");
sb.AppendLine("• 自动模式智能平衡资源和速度");
sb.AppendLine();
// 警告
sb.AppendLine("═══ 注意事项 ═══");
sb.AppendLine("• 通量为0时进入休眠状态");
sb.AppendLine("• 休眠时品质持续下降");
sb.AppendLine("• 品质归零卵囊将被破坏");
sb.AppendLine("• 虫蜜耗尽也会进入休眠");
if (ootheca.IsDormant)
{
sb.AppendLine();
sb.AppendLine("<color=red>════════════════</color>");
sb.AppendLine("<color=red>⚠ 当前处于休眠状态!</color>");
sb.AppendLine("<color=red>品质正在下降!</color>");
sb.AppendLine("<color=red>════════════════</color>");
}
return sb.ToString().TrimEndNewlines();
}
}
}