447 lines
17 KiB
C#
447 lines
17 KiB
C#
using RimWorld;
|
||
using System.Collections.Generic;
|
||
using System.Text;
|
||
using UnityEngine;
|
||
using Verse;
|
||
using Verse.AI;
|
||
using System;
|
||
|
||
namespace ArachnaeSwarm
|
||
{
|
||
public class Building_EquipmentOotheca : Building, IFluxController
|
||
{
|
||
// === 通量系统字段 ===
|
||
private float neutronFlux = 0.5f;
|
||
private FluxMode fluxMode = FluxMode.Balance;
|
||
|
||
// === 孵化核心字段 ===
|
||
public bool isIncubating = false;
|
||
public ThingDef incubatingThingDef = null;
|
||
public float incubationProgress = 0f;
|
||
public float incubationDuration = 0f;
|
||
public float qualityProgress = 0f;
|
||
public float qualityTotal = 0f;
|
||
public float qualityMultiplier = 1.0f;
|
||
public float speedMultiplier = 1.0f;
|
||
|
||
// 幼虫相关
|
||
public Pawn assignedLarva = null;
|
||
public int larvaOperateTicksRemaining = 0;
|
||
|
||
// 时间控制
|
||
protected int lastMultiplierUpdateTick = -1;
|
||
protected const int MultiplierUpdateInterval = 250;
|
||
|
||
// === 属性 ===
|
||
public IFluxController FluxController => this;
|
||
public float NeutronFlux => neutronFlux;
|
||
public float RawFlux => neutronFlux;
|
||
public FluxMode FluxMode => fluxMode;
|
||
public FluxMode CurrentFluxMode => fluxMode;
|
||
public float FluxEfficiency => IFluxControllerExtensions.GetEfficiency(neutronFlux);
|
||
public bool IsAutoMode => fluxMode != FluxMode.Manual;
|
||
public bool IsIncubating => isIncubating;
|
||
public bool IsDormant => neutronFlux < 0.05f;
|
||
|
||
public CompRefuelableNutrition FuelComp => GetComp<CompRefuelableNutrition>();
|
||
public Comp_SwarmMaintenance MaintenanceComp => GetComp<Comp_SwarmMaintenance>();
|
||
public CompEquipmentIncubatorData EquipmentIncubatorData => GetComp<CompEquipmentIncubatorData>();
|
||
|
||
public void SetNeutronFlux(float value) => neutronFlux = Mathf.Clamp01(value);
|
||
public void CycleFluxMode() => fluxMode = (FluxMode)(((int)fluxMode + 1) % 4);
|
||
public void SetFluxMode(FluxMode mode) => fluxMode = mode;
|
||
|
||
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",
|
||
_ => "?"
|
||
};
|
||
|
||
public float IncubationProgress => incubationDuration > 0 ? incubationProgress / incubationDuration : 0f;
|
||
public float QualityPercent => qualityTotal > 0 ? qualityProgress / qualityTotal : 0f;
|
||
public float AdjustedProgressPercent => IncubationProgress;
|
||
|
||
public float SpeedMultiplier
|
||
{
|
||
get
|
||
{
|
||
if (lastMultiplierUpdateTick < 0 || Find.TickManager.TicksGame - lastMultiplierUpdateTick >= MultiplierUpdateInterval)
|
||
{
|
||
UpdateSpeedMultiplier();
|
||
}
|
||
return speedMultiplier;
|
||
}
|
||
}
|
||
|
||
public float QualityMultiplier => qualityMultiplier;
|
||
|
||
private void InitializeNutrientInfo() { } // 清理完毕
|
||
|
||
// === Tick方法(带活性系统)===
|
||
protected override void Tick()
|
||
{
|
||
base.Tick();
|
||
|
||
if (larvaOperateTicksRemaining > 0)
|
||
{
|
||
larvaOperateTicksRemaining--;
|
||
}
|
||
|
||
if (isIncubating)
|
||
{
|
||
// 更新乘数
|
||
if (lastMultiplierUpdateTick < 0 || Find.TickManager.TicksGame - lastMultiplierUpdateTick >= MultiplierUpdateInterval)
|
||
{
|
||
UpdateSpeedMultiplier();
|
||
UpdateQualityMultiplier();
|
||
}
|
||
|
||
// 自动模式计算
|
||
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)
|
||
{
|
||
CompleteIncubation();
|
||
}
|
||
}
|
||
}
|
||
|
||
// 自动模式算法
|
||
private void CalculateAutoFlux()
|
||
{
|
||
if (fluxMode == FluxMode.Manual) return;
|
||
|
||
float targetFlux = 0.5f;
|
||
float incubationPercent = incubationDuration > 0 ? incubationProgress / incubationDuration : 0f;
|
||
float gQualityPercent = qualityTotal > 0 ? qualityProgress / qualityTotal : 0f;
|
||
float gap = gQualityPercent - incubationPercent;
|
||
|
||
switch (fluxMode)
|
||
{
|
||
case FluxMode.Quality:
|
||
if (gQualityPercent >= 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 (gQualityPercent >= 0.95f) targetFlux = 1.0f;
|
||
else if (gQualityPercent < 0.3f && incubationPercent > 0.5f) targetFlux = 0.7f;
|
||
else if (gQualityPercent < 0.2f && incubationPercent > 0.7f) targetFlux = 0.5f;
|
||
else targetFlux = 1.0f;
|
||
break;
|
||
|
||
case FluxMode.Balance:
|
||
default:
|
||
if (gQualityPercent >= 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);
|
||
|
||
// 平滑调节
|
||
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()
|
||
{
|
||
StringBuilder sb = new StringBuilder();
|
||
sb.AppendLine("速度因子");
|
||
sb.AppendLine();
|
||
sb.Append("总速度倍率: " + SpeedMultiplier.ToStringPercent());
|
||
return sb.ToString().TrimEndNewlines();
|
||
}
|
||
|
||
public string GetQualityFactorsDescription()
|
||
{
|
||
StringBuilder sb = new StringBuilder();
|
||
sb.AppendLine("质量因子");
|
||
sb.AppendLine();
|
||
sb.Append("总质量倍率: " + QualityMultiplier.ToStringPercent());
|
||
return sb.ToString().TrimEndNewlines();
|
||
}
|
||
|
||
private string BuildCallLarvaDescription(EquipmentIncubationConfig config)
|
||
{
|
||
StringBuilder sb = new StringBuilder();
|
||
sb.AppendLine("呼叫幼虫激活制造舱");
|
||
sb.AppendLine();
|
||
sb.AppendLine("目标: " + config.thingDef.LabelCap);
|
||
return sb.ToString().TrimEndNewlines();
|
||
}
|
||
|
||
// === 幼虫交互 ===
|
||
public void CallLarva()
|
||
{
|
||
if (isIncubating || assignedLarva != null) return;
|
||
|
||
var larva = FindLarva();
|
||
if (larva == null)
|
||
{
|
||
Messages.Message("未找到可用的幼虫!", MessageTypeDefOf.RejectInput);
|
||
return;
|
||
}
|
||
|
||
var job = JobMaker.MakeJob(ARA_JobDefOf.ARA_OperateIncubator, this);
|
||
larva.jobs.TryTakeOrderedJob(job, JobTag.MiscWork);
|
||
assignedLarva = larva;
|
||
Messages.Message("已呼叫幼虫。", MessageTypeDefOf.PositiveEvent);
|
||
}
|
||
|
||
private Pawn FindLarva()
|
||
{
|
||
float searchRadius = 30f;
|
||
Map map = Map;
|
||
if (map == null) return null;
|
||
|
||
foreach (Pawn pawn in map.mapPawns.AllPawnsSpawned)
|
||
{
|
||
if (pawn.def.defName == "ArachnaeBase_Race_Larva" && !pawn.Downed && !pawn.Dead && pawn.Faction == Faction.OfPlayer)
|
||
{
|
||
if (Position.DistanceTo(pawn.Position) <= searchRadius)
|
||
return pawn;
|
||
}
|
||
}
|
||
return null;
|
||
}
|
||
|
||
public void NotifyLarvaArrived(Pawn larva)
|
||
{
|
||
larvaOperateTicksRemaining = 180;
|
||
assignedLarva = larva;
|
||
}
|
||
|
||
public void NotifyLarvaOperationComplete(Pawn larva)
|
||
{
|
||
var config = EquipmentIncubatorData?.SelectedConfig;
|
||
if (config == null) return;
|
||
|
||
incubatingThingDef = config.thingDef;
|
||
incubationDuration = config.daysRequired * 60000f;
|
||
incubationProgress = 0f;
|
||
qualityTotal = incubationDuration;
|
||
qualityProgress = 0f;
|
||
isIncubating = true;
|
||
assignedLarva = null;
|
||
larvaOperateTicksRemaining = 0;
|
||
|
||
Messages.Message("孵化开始: " + incubatingThingDef.LabelCap, MessageTypeDefOf.PositiveEvent);
|
||
}
|
||
|
||
public void CancelIncubation()
|
||
{
|
||
isIncubating = false;
|
||
incubatingThingDef = null;
|
||
incubationProgress = 0f;
|
||
Messages.Message("孵化已取消。", MessageTypeDefOf.NeutralEvent);
|
||
}
|
||
|
||
private void CompleteIncubation()
|
||
{
|
||
if (incubatingThingDef == null) return;
|
||
|
||
float finalQuality = QualityPercent;
|
||
Thing thing = ThingMaker.MakeThing(incubatingThingDef);
|
||
|
||
// 应用质量
|
||
CompQuality compQuality = thing.TryGetComp<CompQuality>();
|
||
if (compQuality != null)
|
||
{
|
||
QualityCategory qc = finalQuality switch {
|
||
>= 0.95f => QualityCategory.Legendary,
|
||
>= 0.85f => QualityCategory.Masterwork,
|
||
>= 0.70f => QualityCategory.Excellent,
|
||
>= 0.50f => QualityCategory.Good,
|
||
>= 0.30f => QualityCategory.Normal,
|
||
>= 0.15f => QualityCategory.Poor,
|
||
_ => QualityCategory.Awful
|
||
};
|
||
compQuality.SetQuality(qc, ArtGenerationContext.Colony);
|
||
}
|
||
|
||
GenSpawn.Spawn(thing, Position, Map);
|
||
isIncubating = false;
|
||
incubatingThingDef = null;
|
||
Messages.Message("孵化完成: " + thing.LabelCap, MessageTypeDefOf.PositiveEvent);
|
||
Destroy();
|
||
}
|
||
|
||
// === 辅助方法 ===
|
||
private void UpdateSpeedMultiplier()
|
||
{
|
||
float multiplier = 1.0f;
|
||
var facilityComp = GetComp<CompAffectedByFacilities>();
|
||
if (facilityComp != null)
|
||
{
|
||
var speedStat = DefDatabase<StatDef>.GetNamedSilentFail("ARA_IncubationSpeedFactor") ?? StatDefOf.WorkTableWorkSpeedFactor;
|
||
multiplier += facilityComp.GetStatOffset(speedStat);
|
||
}
|
||
speedMultiplier = multiplier;
|
||
lastMultiplierUpdateTick = Find.TickManager.TicksGame;
|
||
}
|
||
|
||
private void UpdateQualityMultiplier()
|
||
{
|
||
qualityMultiplier = 1.0f;
|
||
}
|
||
|
||
public float GetRemainingTicks()
|
||
{
|
||
if (!isIncubating) return 0f;
|
||
return Mathf.Max(0f, (incubationDuration - incubationProgress) / (SpeedMultiplier * FluxEfficiency * 5f));
|
||
}
|
||
|
||
public float GetRemainingDays() => GetRemainingTicks() / 60000f;
|
||
public float GetRemainingHours() => (GetRemainingTicks() % 60000f) / 2500f;
|
||
|
||
public override string GetInspectString()
|
||
{
|
||
StringBuilder sb = new StringBuilder();
|
||
if (isIncubating && incubatingThingDef != null)
|
||
{
|
||
sb.AppendLine("正在孵化: " + incubatingThingDef.LabelCap);
|
||
sb.AppendLine("进度: " + AdjustedProgressPercent.ToStringPercent());
|
||
sb.AppendLine("剩余时间: " + GetRemainingDays().ToString("F1") + " 天");
|
||
sb.Append("速度: " + SpeedMultiplier.ToStringPercent() + " | 质量: " + QualityMultiplier.ToStringPercent());
|
||
}
|
||
else if (assignedLarva != null)
|
||
{
|
||
sb.Append(larvaOperateTicksRemaining > 0 ? "幼虫激活中..." : "幼虫赶路中...");
|
||
}
|
||
else
|
||
{
|
||
var config = EquipmentIncubatorData?.SelectedConfig;
|
||
if (config != null)
|
||
{
|
||
sb.AppendLine("目标: " + config.thingDef.LabelCap);
|
||
sb.Append("速度: " + SpeedMultiplier.ToStringPercent());
|
||
}
|
||
}
|
||
|
||
var baseStr = base.GetInspectString();
|
||
if (!string.IsNullOrEmpty(baseStr))
|
||
{
|
||
if (sb.Length > 0) sb.AppendLine();
|
||
sb.Append(baseStr);
|
||
}
|
||
return sb.ToString().TrimEndNewlines();
|
||
}
|
||
|
||
public override IEnumerable<Gizmo> GetGizmos()
|
||
{
|
||
foreach (var gizmo in base.GetGizmos())
|
||
{
|
||
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;
|
||
}
|
||
|
||
if (Faction == Faction.OfPlayer)
|
||
{
|
||
yield return new Gizmo_EquipmentIncubationProgress(this);
|
||
yield return new Gizmo_NeutronFlux(this);
|
||
|
||
if (!isIncubating && EquipmentIncubatorData?.SelectedConfig?.IsResearchComplete == true)
|
||
{
|
||
yield return new Command_Action
|
||
{
|
||
defaultLabel = "呼叫幼虫",
|
||
icon = ContentFinder<Texture2D>.Get("ArachnaeSwarm/UI/Commands/ARA_CallLarva", false),
|
||
action = CallLarva
|
||
};
|
||
}
|
||
|
||
if (isIncubating)
|
||
{
|
||
yield return new Command_Action
|
||
{
|
||
defaultLabel = "取消孵化",
|
||
icon = ContentFinder<Texture2D>.Get("UI/Commands/Cancel", false),
|
||
action = CancelIncubation
|
||
};
|
||
}
|
||
}
|
||
}
|
||
|
||
public override void ExposeData()
|
||
{
|
||
base.ExposeData();
|
||
Scribe_Values.Look(ref isIncubating, "isIncubating", false);
|
||
Scribe_Values.Look(ref incubationProgress, "incubationProgress", 0f);
|
||
Scribe_Values.Look(ref incubationDuration, "incubationDuration", 0f);
|
||
Scribe_Defs.Look(ref incubatingThingDef, "incubatingThingDef");
|
||
Scribe_References.Look(ref assignedLarva, "assignedLarva");
|
||
Scribe_Values.Look(ref larvaOperateTicksRemaining, "larvaOperateTicksRemaining", 0);
|
||
Scribe_Values.Look(ref speedMultiplier, "speedMultiplier", 1.0f);
|
||
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 fluxMode, "fluxMode", FluxMode.Balance);
|
||
}
|
||
}
|
||
}
|