This commit is contained in:
2025-12-23 15:44:33 +08:00
parent c130329439
commit 6012771afa
6 changed files with 882 additions and 1868 deletions

View File

@@ -0,0 +1,196 @@
using RimWorld;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using Verse;
namespace ArachnaeSwarm
{
public class CompProperties_QueuedInteractiveProducerWithFlux : CompProperties_QueuedInteractiveProducer
{
public CompProperties_QueuedInteractiveProducerWithFlux()
{
compClass = typeof(CompQueuedInteractiveProducerWithFlux);
}
}
public class CompQueuedInteractiveProducerWithFlux : CompQueuedInteractiveProducer, IFluxController
{
// === 通量系统字段 ===
private float neutronFlux = 0.5f;
private FluxMode fluxMode = FluxMode.Balance;
// === 接口实现 ===
public float NeutronFlux => neutronFlux;
public float RawFlux => neutronFlux;
public FluxMode CurrentFluxMode => fluxMode;
public float FluxEfficiency => IFluxController.GetEfficiency(neutronFlux);
public bool IsAutoMode => fluxMode != FluxMode.Manual;
public bool IsIncubating => IsAnyOrderActive;
public bool IsDormant => neutronFlux < 0.05f;
public void SetNeutronFlux(float value) => neutronFlux = Mathf.Clamp01(value);
public void CycleFluxMode() => fluxMode = (FluxMode)(((int)fluxMode + 1) % 4);
public string GetModeName() => fluxMode switch {
FluxMode.Manual => "手动",
FluxMode.Quality => "品质",
FluxMode.Balance => "平衡",
FluxMode.Speed => "速度",
_ => "?"
};
public string GetModeShort() => fluxMode switch {
FluxMode.Manual => "M",
FluxMode.Quality => "Q",
FluxMode.Balance => "B",
FluxMode.Speed => "S",
_ => "?"
};
private bool IsAnyOrderActive => productionOrders.Any(o => o.productionUntilTick > 0);
// 覆盖 Tick 逻辑
public override void CompTick()
{
float hasFuelVal = FuelComp?.Fuel ?? 10f;
bool hasFuel = hasFuelVal > 0.01f;
// 自动模式
if (IsAutoMode && parent.IsHashIntervalTick(250) && IsAnyOrderActive)
{
CalculateAutoFlux();
}
if (IsAnyOrderActive)
{
// 消耗燃料
if (FuelComp != null && neutronFlux > 0.01f)
{
float fuelPerTick = (80f * FluxEfficiency) / 60000f; // 物品孵化池消耗略高
FuelComp.ConsumeFuel(fuelPerTick);
}
if (hasFuel)
{
float ambientTemperature = parent.AmbientTemperature;
bool isTempSafe = ambientTemperature >= Props.minSafeTemperature && ambientTemperature <= Props.maxSafeTemperature;
// 计算通量速度倍率100%活性时5倍速度
float speedFactor = 1f + (FacilitiesComp?.GetStatOffset(StatDef.Named("ARA_IncubationSpeedFactor")) ?? 0f);
float fluxSpeed = speedFactor * FluxEfficiency * 5f;
foreach (var order in productionOrders.Where(o => o.productionUntilTick > 0))
{
// 1. 进度推进(受通量倍率影响)
// 由于基类逻辑是每 Tick 递减,我们这里手动控制递减量
float progressStep = fluxSpeed;
int ticksToSubtract = Mathf.FloorToInt(progressStep);
if (Rand.Value < (progressStep - ticksToSubtract)) ticksToSubtract++;
order.productionUntilTick = Mathf.Max(0, order.productionUntilTick - ticksToSubtract);
// 2. 品质累积(基础:每 Tick 增加 1
// 注意:如果 fluxSpeed > 1生产变快但品质累积速度不变
// 这样总的 ticksUnderOptimalConditions 就会减少,从而降低品质分数。
// 这完美地实现了“速度越快,品质越低”的平衡逻辑。
if (!IsDormant)
{
if (isTempSafe)
{
order.ticksUnderOptimalConditions++;
}
else
{
float tempDelta = (ambientTemperature > Props.maxSafeTemperature) ? ambientTemperature - Props.maxSafeTemperature : Props.minSafeTemperature - ambientTemperature;
order.temperaturePenaltyPercent = Mathf.Min(1f, order.temperaturePenaltyPercent + tempDelta * Props.penaltyPerDegreePerTick);
}
}
else
{
// 休眠状态下品质会缓慢衰减
order.ticksUnderOptimalConditions = Mathf.Max(0, order.ticksUnderOptimalConditions - 2);
}
}
}
}
// 处理订单完成和消耗率更新UI用
UpdateLogic();
}
private void UpdateLogic()
{
// 完成订单
productionOrders.RemoveAll(order =>
{
if (order.productionUntilTick == 0)
{
FinishProduction(order);
return true;
}
return false;
});
// 启动新订单
int currentlyProducingCount = productionOrders.Count(o => o.productionUntilTick > 0);
if (currentlyProducingCount < Props.productionQueueLimit)
{
var waitingOrder = productionOrders.FirstOrDefault(o => o.productionUntilTick == -1);
if (waitingOrder != null)
{
// 初始 Tick 数,会被后续 Tick 动态加速
waitingOrder.productionUntilTick = waitingOrder.process.productionTicks;
}
}
// 更新燃料消耗率显示
if (FuelComp != null)
{
float totalConsumption = 0f;
if (IsAnyOrderActive && NeutronFlux > 0.01f)
{
totalConsumption = currentlyProducingCount * 80f * FluxEfficiency;
}
FuelComp.currentConsumptionRate = totalConsumption;
}
}
private void CalculateAutoFlux()
{
if (fluxMode == FluxMode.Manual) return;
float targetFlux = 0.5f;
// 简单逻辑:平衡模式趋向于 0.5;品质模式倾向于 0.1;速度模式倾向于 1.0
switch (fluxMode)
{
case FluxMode.Speed: targetFlux = 1.0f; break;
case FluxMode.Quality: targetFlux = 0.1f; break;
case FluxMode.Balance:
default: targetFlux = 0.5f; break;
}
// 资源保护
if (FuelComp != null && FuelComp.Fuel < 50f) targetFlux = Mathf.Min(targetFlux, 0.2f);
neutronFlux = Mathf.Lerp(neutronFlux, targetFlux, 0.05f);
}
public override IEnumerable<Gizmo> CompGetGizmosExtra()
{
foreach (var g in base.CompGetGizmosExtra()) yield return g;
if (parent.Faction == Faction.OfPlayer)
{
yield return new Gizmo_NeutronFlux(this);
}
}
public override void PostExposeData()
{
base.PostExposeData();
Scribe_Values.Look(ref neutronFlux, "neutronFlux", 0.5f);
Scribe_Values.Look(ref fluxMode, "fluxMode", FluxMode.Balance);
}
}
}

View File

@@ -0,0 +1,211 @@
using RimWorld;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using Verse;
namespace ArachnaeSwarm
{
public class CompProperties_QueuedPawnSpawnerWithFlux : CompProperties_QueuedPawnSpawner
{
public CompProperties_QueuedPawnSpawnerWithFlux()
{
compClass = typeof(CompQueuedPawnSpawnerWithFlux);
}
}
public class CompQueuedPawnSpawnerWithFlux : CompQueuedPawnSpawner, IFluxController
{
// === 通量系统字段 ===
private float neutronFlux = 0.5f;
private FluxMode fluxMode = FluxMode.Balance;
// === 接口实现 ===
public float NeutronFlux => neutronFlux;
public float RawFlux => neutronFlux;
public FluxMode CurrentFluxMode => fluxMode;
public float FluxEfficiency => IFluxController.GetEfficiency(neutronFlux);
public bool IsAutoMode => fluxMode != FluxMode.Manual;
public bool IsIncubating => IsAnyOrderActive;
public bool IsDormant => neutronFlux < 0.05f;
public void SetNeutronFlux(float value) => neutronFlux = Mathf.Clamp01(value);
public void CycleFluxMode() => fluxMode = (FluxMode)(((int)fluxMode + 1) % 4);
public string GetModeName() => fluxMode switch {
FluxMode.Manual => "手动",
FluxMode.Quality => "品质",
FluxMode.Balance => "平衡",
FluxMode.Speed => "速度",
_ => "?"
};
public string GetModeShort() => fluxMode switch {
FluxMode.Manual => "M",
FluxMode.Quality => "Q",
FluxMode.Balance => "B",
FluxMode.Speed => "S",
_ => "?"
};
// 辅助属性
private bool IsAnyOrderActive => productionOrders.Any(o => o.spawnUntilTick > 0);
// 覆盖 Tick 逻辑以处理通量效果
public override void CompTick()
{
// 注意:我们直接重写逻辑,而不是仅仅调用 base.CompTick
// 这样我们可以更精确地控制进度增加速度。
bool hasFuel = FuelComp?.HasFuel ?? true;
// 自动模式调节
if (IsAutoMode && parent.IsHashIntervalTick(250) && IsAnyOrderActive)
{
CalculateAutoFlux();
}
if (IsAnyOrderActive)
{
// 消耗燃料(基于通量效率)
if (FuelComp != null && neutronFlux > 0.01f)
{
float fuelPerTick = (50f * FluxEfficiency) / 60000f;
FuelComp.ConsumeFuel(fuelPerTick);
}
if (!hasFuel)
{
// 没燃料时进度停滞
}
else if (IsDormant)
{
// 休眠逻辑:目前排队组件暂不支持品质损耗,仅停滞
}
else
{
// 正常孵化:受通量加速影响
float speedFactor = 1f + (FacilitiesComp?.GetStatOffset(StatDef.Named("ARA_IncubationSpeedFactor")) ?? 0f);
float fluxSpeed = speedFactor * FluxEfficiency * 5f;
// 更新所有激活订单的进度
// 由于基类逻辑是基于 TickManager.TicksGame 的spawnUntilTick
// 我们需要手动调整这个目标 Tick 来实现加速。
//
// 复杂点:基类认为每 Tick 进度 +1。我们要实现每 Tick 进度 +fluxSpeed。
// 所以我们每 Tick 实际上让目标 Tick 靠近当前 Tick (fluxSpeed - 1) 个单位。
foreach (var order in productionOrders.Where(o => o.spawnUntilTick > 0))
{
// 计算需要减少的剩余时间量
float extraProgress = fluxSpeed - 1f;
// 我们通过增加一个随机概率或累积器来处理小数
// 这里简单处理:直接修改 spawnUntilTick
// (注意:如果 fluxSpeed < 1spawnUntilTick 会延后)
if (extraProgress > 0)
{
// 实际应该减少的值。如果 fluxSpeed=5则每 tick 应该减少 5 tick 的等待时间。
// 基类自然减少了 1我们额外减少 4。
int extraTicks = Mathf.FloorToInt(extraProgress);
if (Rand.Value < (extraProgress - extraTicks)) extraTicks++;
order.spawnUntilTick -= extraTicks;
}
else if (extraProgress < 0)
{
// 减速逻辑
float delayExtra = 1f - fluxSpeed;
int delayTicks = Mathf.FloorToInt(delayExtra);
if (Rand.Value < (delayExtra - delayTicks)) delayTicks++;
order.spawnUntilTick += delayTicks;
}
}
}
}
// 处理订单完成和启动新订单(逻辑基本同基类,但我们需要确保燃料消耗正常更新)
TickProductionLogic();
}
private void TickProductionLogic()
{
// 完成订单
productionOrders.RemoveAll(order =>
{
if (order.spawnUntilTick > 0 && Find.TickManager.TicksGame >= order.spawnUntilTick)
{
Pawn pawn = PawnGenerator.GeneratePawn(new PawnGenerationRequest(order.entry.pawnKind, parent.Faction));
if (pawn != null) GenPlace.TryPlaceThing(pawn, parent.Position, parent.Map, ThingPlaceMode.Near);
return true;
}
return false;
});
// 启动待办订单
int currentlyProducingCount = productionOrders.Count(o => o.spawnUntilTick > 0);
if (currentlyProducingCount < Props.productionQueueLimit)
{
var waitingOrder = productionOrders.FirstOrDefault(o => o.spawnUntilTick == -1);
if (waitingOrder != null)
{
// 初始目标 Tick之后会在 CompTick 中被通量系统动态调整
waitingOrder.spawnUntilTick = Find.TickManager.TicksGame + waitingOrder.entry.delayTicks;
}
}
// 更新燃料消耗显示UI用
if (FuelComp != null)
{
float totalConsumptionPerDay = 0f;
if (IsAnyOrderActive && NeutronFlux > 0.01f)
{
// 基础:每激活一个槽位在 100% 活性下消耗 50/天?
// 或者统一由组件控制
totalConsumptionPerDay = currentlyProducingCount * 50f * FluxEfficiency;
}
FuelComp.currentConsumptionRate = totalConsumptionPerDay;
}
}
private void CalculateAutoFlux()
{
if (fluxMode == FluxMode.Manual) return;
// 排队组件目前主要影响速度。平衡模式下,如果燃料充足,保持中等偏高速度。
float targetFlux = 0.5f;
switch (fluxMode)
{
case FluxMode.Speed: targetFlux = 1.0f; break;
case FluxMode.Quality: targetFlux = 0.2f; break; // 排队组件目前无品质机制,所以此模式意义较小
case FluxMode.Balance:
default: targetFlux = 0.6f; break;
}
// 资源保护
if (FuelComp != null && FuelComp.Fuel < 20f) targetFlux = Mathf.Min(targetFlux, 0.3f);
neutronFlux = Mathf.Lerp(neutronFlux, targetFlux, 0.05f);
}
public override IEnumerable<Gizmo> CompGetGizmosExtra()
{
foreach (var g in base.CompGetGizmosExtra()) yield return g;
if (parent.Faction == Faction.OfPlayer)
{
// 注意:进度 Gizmo 由 Building 负责显示,
// 但如果是通用 Building 挂载此组件,可能需要在此提供。
// 鉴于目前是特定 Building 类,我们暂不在此重复,保持现有的逻辑。
// 不过,我们需要确保通量控制 Gizmo 可用。
yield return new Gizmo_NeutronFlux(this);
}
}
public override void PostExposeData()
{
base.PostExposeData();
Scribe_Values.Look(ref neutronFlux, "neutronFlux", 0.5f);
Scribe_Values.Look(ref fluxMode, "fluxMode", FluxMode.Balance);
}
}
}

View File

@@ -115,5 +115,14 @@ namespace ArachnaeSwarm
ConsumeFuel(Props.fuelConsumptionRate / 60000f);
}
}
public override bool ShouldAutoRefuelNow =>
allowAutoRefuel && TargetFuelLevel > 0.01f && (Fuel < TargetFuelLevel * 0.75f || Fuel == 0f);
public override bool ShouldAutoRefuelNowIgnoringFuelPct =>
allowAutoRefuel && TargetFuelLevel > 0.01f && Fuel < TargetFuelLevel;
// 覆盖基类属性,确保 WorkGiver 扫描时拦截
public new float TargetFuelLevel => allowAutoRefuel ? base.TargetFuelLevel : 0f;
}
}