Files
ArachnaeSwarm/Source/ArachnaeSwarm/Buildings/Building_EquipmentOotheca/Building_EquipmentOotheca.cs
2025-12-23 15:51:14 +08:00

447 lines
17 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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);
}
}
}