diff --git a/1.6/1.6/Assemblies/ArachnaeSwarm.dll b/1.6/1.6/Assemblies/ArachnaeSwarm.dll index ef6ef20..58bb077 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 f966b8d..19a9f7f 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 c65c706..a097ed0 100644 --- a/1.6/1.6/Defs/Thing_building/ARA_NutrientNetworkBuilding.xml +++ b/1.6/1.6/Defs/Thing_building/ARA_NutrientNetworkBuilding.xml @@ -60,6 +60,7 @@
  • ARA_Acidling_AutoMortar
  • CatastropheMissileSilo
  • ARA_AutoSniperCannon
  • +
  • ARA_Pawn_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 8e599b4..e051f02 100644 --- a/1.6/1.6/Defs/Thing_building/ARA_Ootheca.xml +++ b/1.6/1.6/Defs/Thing_building/ARA_Ootheca.xml @@ -151,9 +151,7 @@ 25 - -
  • ArachnaeSwarm.PlaceWorker_CustomRadius
  • -
    +
  • 100 @@ -162,15 +160,27 @@ 0.2 0.5
  • -
  • - 5 - (0.5, 1, 1) - 0 - true - - 这个卵在孵化过程中的吸收半径,确保这些地格中铺满阿拉克涅营养液,并且没有其他的卵,以获得最佳的孵化速度和孵化质量。 - false + + +
  • + 25.0 + + +
  • ARA_InsectJelly
  • + + + 虫蜜 + true + true + 5 + true +
  • + +
  • ARA_NutrientNetworkTower
  • + + +
  • 0 diff --git a/Source/ArachnaeSwarm/ArachnaeSwarm.csproj b/Source/ArachnaeSwarm/ArachnaeSwarm.csproj index f073ec6..a762a77 100644 --- a/Source/ArachnaeSwarm/ArachnaeSwarm.csproj +++ b/Source/ArachnaeSwarm/ArachnaeSwarm.csproj @@ -124,6 +124,7 @@ + diff --git a/Source/ArachnaeSwarm/Building_Comps/ARA_SwarmMaintenance/Comp_SwarmMaintenance.cs b/Source/ArachnaeSwarm/Building_Comps/ARA_SwarmMaintenance/Comp_SwarmMaintenance.cs index 4572354..dea2e06 100644 --- a/Source/ArachnaeSwarm/Building_Comps/ARA_SwarmMaintenance/Comp_SwarmMaintenance.cs +++ b/Source/ArachnaeSwarm/Building_Comps/ARA_SwarmMaintenance/Comp_SwarmMaintenance.cs @@ -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 diff --git a/Source/ArachnaeSwarm/Buildings/Building_Ootheca/Building_Ootheca.cs b/Source/ArachnaeSwarm/Buildings/Building_Ootheca/Building_Ootheca.cs index 821d7fb..3e7d70e 100644 --- a/Source/ArachnaeSwarm/Buildings/Building_Ootheca/Building_Ootheca.cs +++ b/Source/ArachnaeSwarm/Buildings/Building_Ootheca/Building_Ootheca.cs @@ -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()); + public Comp_SwarmMaintenance MaintenanceComp => maintenanceComp ?? (maintenanceComp = this.TryGetComp()); + + // 孵化活性效率曲线(非线性: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 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); } } } diff --git a/Source/ArachnaeSwarm/Buildings/Building_Ootheca/Gizmo_IncubationProgress.cs b/Source/ArachnaeSwarm/Buildings/Building_Ootheca/Gizmo_IncubationProgress.cs index ba13d53..f3a0a2d 100644 --- a/Source/ArachnaeSwarm/Buildings/Building_Ootheca/Gizmo_IncubationProgress.cs +++ b/Source/ArachnaeSwarm/Buildings/Building_Ootheca/Gizmo_IncubationProgress.cs @@ -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); // 内部区域 diff --git a/Source/ArachnaeSwarm/Buildings/Building_Ootheca/Gizmo_NeutronFlux.cs b/Source/ArachnaeSwarm/Buildings/Building_Ootheca/Gizmo_NeutronFlux.cs new file mode 100644 index 0000000..b7eb1a7 --- /dev/null +++ b/Source/ArachnaeSwarm/Buildings/Building_Ootheca/Gizmo_NeutronFlux.cs @@ -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("════════════════"); + sb.AppendLine("⚠ 当前处于休眠状态!"); + sb.AppendLine("品质正在下降!"); + sb.AppendLine("════════════════"); + } + + return sb.ToString().TrimEndNewlines(); + } + } +}