This commit is contained in:
2026-02-24 12:02:38 +08:00
parent 1af5f0c1d8
commit 96bc1d4c5a
57 changed files with 6595 additions and 1170 deletions

View File

@@ -0,0 +1,446 @@
// CompMechFuel.cs
using RimWorld;
using System.Collections.Generic;
using UnityEngine;
using Verse;
using Verse.AI;
using System.Linq;
namespace WulaFallenEmpire
{
public class CompMechFuel : ThingComp
{
public CompProperties_MechFuel Props => (CompProperties_MechFuel)props;
private float fuel;
private bool isShutdown = false;
private int lastFuelTick = -1;
public float Fuel => fuel;
public float FuelPercent => fuel / Props.fuelCapacity;
public bool HasFuel => fuel > 0f;
public bool IsFull => FuelPercent >= 0.999f;
public bool NeedsRefueling => FuelPercent < Props.autoRefuelThreshold && Props.allowAutoRefuel;
public bool IsShutdown => isShutdown;
public ThingDef FuelType => Props.fuelType;
// 停机状态 Hediff
private HediffDef ShutdownHediffDef => HediffDef.Named("DD_MechShutdown");
public override void PostSpawnSetup(bool respawningAfterLoad)
{
base.PostSpawnSetup(respawningAfterLoad);
lastFuelTick = Find.TickManager.TicksGame;
// 如果是新生成的机甲,自动加满燃料
if (!respawningAfterLoad && fuel <= 0f)
{
Refuel(Props.fuelCapacity);
}
// 确保停机状态和 Hediff 同步
SyncShutdownHediff();
}
public override void CompTick()
{
base.CompTick();
// 每60ticks1秒消耗一次燃料
if (Find.TickManager.TicksGame % 60 == 0)
{
ConsumeFuelOverTime();
}
// 检查是否需要关机
CheckShutdown();
// 确保停机状态和 Hediff 同步
SyncShutdownHediff();
}
private void SyncShutdownHediff()
{
var mech = parent as Pawn;
if (mech == null || mech.health == null || ShutdownHediffDef == null)
return;
bool hasShutdownHediff = mech.health.hediffSet.HasHediff(ShutdownHediffDef);
// 如果处于停机状态但没有 Hediff添加 Hediff
if (isShutdown && !hasShutdownHediff)
{
mech.health.AddHediff(ShutdownHediffDef);
}
// 如果不处于停机状态但有 Hediff移除 Hediff
else if (!isShutdown && hasShutdownHediff)
{
var hediff = mech.health.hediffSet.GetFirstHediffOfDef(ShutdownHediffDef);
if (hediff != null)
{
mech.health.RemoveHediff(hediff);
}
}
}
private void ConsumeFuelOverTime()
{
if (fuel <= 0f || !parent.Spawned)
return;
// 检查是否有驾驶员 - 没有驾驶员时不消耗燃料
var pilotComp = parent.TryGetComp<CompMechPilotHolder>();
bool hasPilot = pilotComp != null && pilotComp.HasPilots;
if (!hasPilot)
return; // 没有驾驶员,不消耗燃料
// 获取当前时间
int currentTick = Find.TickManager.TicksGame;
// 计算经过的游戏时间(以天为单位)
float daysPassed = (currentTick - lastFuelTick) / 60000f; // 60000 ticks = 1天
// 计算基础燃料消耗
float consumption = Props.dailyFuelConsumption * daysPassed;
// 如果机甲正在活动(移动、战斗等),消耗更多燃料
var mech = parent as Pawn;
if (mech != null)
{
// 增加活动消耗
if (mech.pather.Moving)
{
consumption *= 2f; // 移动时消耗加倍
}
// 战斗状态消耗更多
if (mech.CurJob != null && mech.CurJob.def == JobDefOf.AttackStatic)
{
consumption *= 1.5f;
}
}
// 消耗燃料
fuel = Mathf.Max(0f, fuel - consumption);
// 更新最后消耗时间
lastFuelTick = currentTick;
}
private void CheckShutdown()
{
if (!Props.shutdownWhenEmpty || isShutdown)
return;
// 燃料耗尽时关机
if (fuel <= 0f && parent.Spawned)
{
Shutdown();
}
}
private void Shutdown()
{
if (isShutdown)
return;
isShutdown = true;
var mech = parent as Pawn;
if (mech != null)
{
// 取消所有工作
mech.jobs.StopAll();
mech.drafter.Drafted = false;
// 添加停机 Hediff
if (ShutdownHediffDef != null)
{
mech.health.AddHediff(ShutdownHediffDef);
}
// 播放关机效果
MoteMaker.ThrowText(mech.DrawPos, mech.Map, "DD_Shutdown".Translate(), Color.gray, 3.5f);
}
}
public void Startup()
{
if (!isShutdown || fuel <= 0f)
return;
isShutdown = false;
var mech = parent as Pawn;
if (mech != null)
{
// 移除停机 Hediff
if (ShutdownHediffDef != null)
{
var hediff = mech.health.hediffSet.GetFirstHediffOfDef(ShutdownHediffDef);
if (hediff != null)
{
mech.health.RemoveHediff(hediff);
}
}
MoteMaker.ThrowText(mech.DrawPos, mech.Map, "DD_Startup".Translate(), Color.green, 3.5f);
}
}
public bool TryConsumeFuel(float amount)
{
if (fuel >= amount)
{
fuel -= amount;
return true;
}
return false;
}
public bool Refuel(float amount)
{
float oldFuel = fuel;
fuel = Mathf.Min(Props.fuelCapacity, fuel + amount);
// 如果之前关机了且现在有燃料了,启动
if (isShutdown && fuel > 0f)
{
Startup();
}
return fuel > oldFuel;
}
// 设置燃料到特定值(测试用)
public void SetFuel(float amount)
{
float oldFuel = fuel;
fuel = Mathf.Clamp(amount, 0f, Props.fuelCapacity);
// 检查是否需要关机或启动
if (fuel <= 0f)
{
if (!isShutdown && Props.shutdownWhenEmpty)
{
Shutdown();
}
}
else if (isShutdown && fuel > 0f)
{
Startup();
}
// 发送调试消息
if (DebugSettings.godMode)
{
Messages.Message($"DD_Debug_FuelSet".Translate(
parent.LabelShort,
fuel.ToString("F1"),
Props.fuelCapacity.ToString("F1"),
(fuel / Props.fuelCapacity * 100f).ToString("F0") + "%"
), parent, MessageTypeDefOf.PositiveEvent);
}
}
public float FuelSpaceRemaining => Mathf.Max(0f, Props.fuelCapacity - fuel);
public int GetFuelCountToFullyRefuel()
{
if (FuelType == null)
return 0;
float fuelNeeded = FuelSpaceRemaining;
return Mathf.CeilToInt(fuelNeeded);
}
// 立刻加注 - 现在触发最近殖民者来加注
public void RefuelNow()
{
if (IsFull || parent.Map == null || FuelType == null)
return;
// 寻找最近的可用殖民者
Pawn bestColonist = FindBestColonistForRefuel();
if (bestColonist == null)
{
Messages.Message("DD_NoColonistAvailable".Translate(), parent, MessageTypeDefOf.RejectInput);
return;
}
// 寻找燃料
Thing fuel = FindFuelForRefuel(bestColonist);
if (fuel == null)
{
Messages.Message("DD_NoFuelAvailable".Translate(FuelType), parent, MessageTypeDefOf.RejectInput);
return;
}
// 为殖民者创建强制加注工作
Job job = JobMaker.MakeJob(Wula_JobDefOf.DD_RefuelMech, parent, fuel);
job.count = GetFuelCountToFullyRefuel();
job.playerForced = true;
bestColonist.jobs.StartJob(job, JobCondition.InterruptForced, null, resumeCurJobAfterwards: true);
// 显示消息
Messages.Message("DD_OrderedRefuel".Translate(bestColonist.LabelShort, parent.LabelShort),
parent, MessageTypeDefOf.PositiveEvent);
}
private Pawn FindBestColonistForRefuel()
{
Map map = parent.Map;
if (map == null)
return null;
// 寻找所有可用的殖民者
List<Pawn> colonists = map.mapPawns.FreeColonists.ToList();
// 过滤掉无法工作或无法到达机甲的殖民者
colonists = colonists.Where(colonist =>
colonist.health.capacities.CapableOf(PawnCapacityDefOf.Manipulation) &&
colonist.health.capacities.CapableOf(PawnCapacityDefOf.Moving) &&
!colonist.Downed &&
!colonist.Dead &&
colonist.CanReserveAndReach(parent, PathEndMode.Touch, Danger.Some)
).ToList();
if (!colonists.Any())
return null;
// 按照距离排序,选择最近的殖民者
return colonists.OrderBy(colonist => colonist.Position.DistanceTo(parent.Position)).FirstOrDefault();
}
private Thing FindFuelForRefuel(Pawn colonist)
{
if (FuelType == null)
return null;
// 先在殖民者库存中寻找
if (colonist.inventory != null)
{
Thing fuelInInventory = colonist.inventory.innerContainer.FirstOrDefault(t => t.def == FuelType);
if (fuelInInventory != null)
return fuelInInventory;
}
// 在地图上寻找可用的燃料
return GenClosest.ClosestThingReachable(
colonist.Position,
colonist.Map,
ThingRequest.ForDef(FuelType),
PathEndMode.ClosestTouch,
TraverseParms.For(colonist),
9999f,
validator: thing => !thing.IsForbidden(colonist) && colonist.CanReserve(thing)
);
}
public bool CanRefuelNow()
{
if (IsFull || parent.Map == null || FuelType == null)
return false;
// 检查是否有可用殖民者
if (FindBestColonistForRefuel() == null)
return false;
return true;
}
// 检查机甲是否有驾驶员
public bool HasPilot()
{
var pilotComp = parent.TryGetComp<CompMechPilotHolder>();
return pilotComp != null && pilotComp.HasPilots;
}
public override IEnumerable<Gizmo> CompGetGizmosExtra()
{
// 添加燃料状态Gizmo
yield return new Gizmo_MechFuelStatus(this);
// 添加立刻加注按钮
if (!IsFull && parent.Faction == Faction.OfPlayer)
{
Command_Action refuelNow = new Command_Action
{
defaultLabel = "DD_RefuelNow".Translate(),
defaultDesc = "DD_RefuelNowDesc".Translate(),
icon = ContentFinder<Texture2D>.Get("WulaFallenEmpire/UI/Commands/DD_Refuel_Mech"),
action = () => RefuelNow()
};
// 检查是否可以立刻加注
if (!CanRefuelNow())
{
refuelNow.Disable("DD_CannotRefuelNow".Translate());
}
yield return refuelNow;
}
// 在 God Mode 下显示测试按钮
if (DebugSettings.godMode && parent.Faction == Faction.OfPlayer)
{
// 设置燃料为空
Command_Action setEmpty = new Command_Action
{
defaultLabel = "DD_Debug_SetEmpty".Translate(),
defaultDesc = "DD_Debug_SetEmptyDesc".Translate(),
icon = ContentFinder<Texture2D>.Get("UI/Commands/SetEmpty", false) ?? BaseContent.BadTex,
action = () => SetFuel(0f)
};
yield return setEmpty;
// 设置燃料为50%
Command_Action setHalf = new Command_Action
{
defaultLabel = "DD_Debug_SetHalf".Translate(),
defaultDesc = "DD_Debug_SetHalfDesc".Translate(),
icon = ContentFinder<Texture2D>.Get("UI/Commands/SetHalf", false) ?? BaseContent.BadTex,
action = () => SetFuel(Props.fuelCapacity * 0.5f)
};
yield return setHalf;
// 设置燃料为满
Command_Action setFull = new Command_Action
{
defaultLabel = "DD_Debug_SetFull".Translate(),
defaultDesc = "DD_Debug_SetFullDesc".Translate(),
icon = ContentFinder<Texture2D>.Get("UI/Commands/SetFull", false) ?? BaseContent.BadTex,
action = () => SetFuel(Props.fuelCapacity)
};
yield return setFull;
}
}
public override void PostExposeData()
{
base.PostExposeData();
Scribe_Values.Look(ref fuel, "fuel", Props.fuelCapacity);
Scribe_Values.Look(ref isShutdown, "isShutdown", false);
Scribe_Values.Look(ref lastFuelTick, "lastFuelTick", -1);
}
public override string CompInspectStringExtra()
{
string baseString = base.CompInspectStringExtra();
string fuelString = "DD_Fuel".Translate(FuelType) + ": " +
fuel.ToString("F1") + " / " + Props.fuelCapacity.ToString("F1") +
" (" + (FuelPercent * 100f).ToString("F0") + "%)";
if (!baseString.NullOrEmpty())
return baseString + "\n" + fuelString;
else
return fuelString;
}
}
}