Files
ArachnaeSwarm/Source/ArachnaeSwarm/Building_Comps/ARA_Building_RefuelingVat/Building_RefuelingVat.cs

545 lines
20 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;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using Verse;
using Verse.AI;
namespace ArachnaeSwarm
{
[StaticConstructorOnStartup]
public class Building_RefuelingVat : Building_Enterable, IThingHolder, IThingHolderWithDrawnPawn
{
private CompRefuelable cachedRefuelableComp;
private CompRefuelingVat cachedRefuelingVatComp;
private CompAutoEjector cachedAutoEjectorComp;
private Graphic cachedTopGraphic;
// IThingHolderWithDrawnPawn implementation
public float HeldPawnDrawPos_Y => DrawPos.y + 0.03658537f;
public float HeldPawnBodyAngle => base.Rotation.AsAngle;
public PawnPosture HeldPawnPosture => PawnPosture.LayingOnGroundFaceUp;
// 从 Comp 中获取属性
public float FuelProductionPerDay => RefuelingVatComp?.FuelProductionPerDay ?? 10f;
public float FuelProductionEfficiency => RefuelingVatComp?.FuelProductionEfficiency ?? 1f;
private Graphic TopGraphic
{
get
{
if (cachedTopGraphic == null)
{
var modExtension = def.GetModExtension<DefModExtension_NutrientVat>();
if (modExtension != null && !modExtension.topGraphicPath.NullOrEmpty())
{
cachedTopGraphic = GraphicDatabase.Get(modExtension.graphicClass, modExtension.topGraphicPath, ShaderDatabase.Transparent, def.graphicData.drawSize, Color.white, Color.white);
}
}
return cachedTopGraphic;
}
}
public override Vector3 PawnDrawOffset => Vector3.zero;
public CompRefuelable RefuelableComp
{
get
{
if (cachedRefuelableComp == null)
{
cachedRefuelableComp = this.TryGetComp<CompRefuelable>();
}
return cachedRefuelableComp;
}
}
public CompRefuelingVat RefuelingVatComp
{
get
{
if (cachedRefuelingVatComp == null)
{
cachedRefuelingVatComp = this.TryGetComp<CompRefuelingVat>();
}
return cachedRefuelingVatComp;
}
}
public CompAutoEjector AutoEjectorComp
{
get
{
if (cachedAutoEjectorComp == null)
{
cachedAutoEjectorComp = this.TryGetComp<CompAutoEjector>();
}
return cachedAutoEjectorComp;
}
}
public bool HasFuelCapacity => RefuelableComp != null && RefuelableComp.Fuel < RefuelableComp.Props.fuelCapacity;
public bool IsFuelFull => RefuelableComp != null && RefuelableComp.Fuel >= RefuelableComp.Props.fuelCapacity;
// 燃料生产速率每Tick
public float FuelProductionPerTick
{
get
{
if (selectedPawn != null && base.Working)
{
return (FuelProductionPerDay * FuelProductionEfficiency) / 60000f;
}
return 0f;
}
}
// 酸蚀伤害间隔每6000 tick约1/10天
private const int AcidDamageInterval = 6000;
private Dictionary<Pawn, int> pawnTickCounters = new Dictionary<Pawn, int>();
public override void SpawnSetup(Map map, bool respawningAfterLoad)
{
base.SpawnSetup(map, respawningAfterLoad);
cachedRefuelableComp = this.TryGetComp<CompRefuelable>();
cachedRefuelingVatComp = this.TryGetComp<CompRefuelingVat>();
cachedAutoEjectorComp = this.TryGetComp<CompAutoEjector>();
}
public override void DeSpawn(DestroyMode mode = DestroyMode.Vanish)
{
if (mode != DestroyMode.WillReplace)
{
if (selectedPawn != null && innerContainer.Contains(selectedPawn))
{
Notify_PawnRemoved();
}
}
base.DeSpawn(mode);
}
private void ApplyAcidDamage(Pawn pawn)
{
try
{
BodyPartRecord targetPart = GetRandomVulnerablePart(pawn);
DamageDef acidDamageDef = DefDatabase<DamageDef>.GetNamed("AcidBurn") ?? DamageDefOf.Burn;
DamageInfo acidDamage = new DamageInfo(
acidDamageDef,
0.1f, // 每次0.1点伤害
2f, // 护甲穿透
-1f, // 随机角度
instigator: null,
hitPart: targetPart
);
// 应用伤害
pawn.TakeDamage(acidDamage);
}
catch (Exception ex)
{
Log.Error($"Error applying acid damage to {pawn}: {ex.Message}");
}
}
private BodyPartRecord GetRandomVulnerablePart(Pawn pawn)
{
// 优先选择外部身体部位
var vulnerableParts = pawn.health.hediffSet.GetNotMissingParts()
.Where(part => part.depth == BodyPartDepth.Outside &&
!part.def.conceptual &&
part.def.hitPoints > 0)
.ToList();
return vulnerableParts.Count > 0 ?
vulnerableParts.RandomElement() :
pawn.RaceProps.body.corePart;
}
protected override void Tick()
{
base.Tick();
if (selectedPawn != null && (selectedPawn.Destroyed || !innerContainer.Contains(selectedPawn)))
{
OnStop();
return;
}
if (base.Working && selectedPawn != null)
{
// 酸蚀伤害逻辑
if (pawnTickCounters.TryGetValue(selectedPawn, out int tickCount))
{
tickCount++;
pawnTickCounters[selectedPawn] = tickCount;
if (tickCount >= AcidDamageInterval)
{
ApplyAcidDamage(selectedPawn);
pawnTickCounters[selectedPawn] = 0;
}
}
else
{
pawnTickCounters[selectedPawn] = 0;
}
// 燃料生产逻辑
if (HasFuelCapacity)
{
float fuelToAdd = FuelProductionPerTick;
RefuelableComp.Refuel(fuelToAdd);
}
// 检查俘虏是否死亡
if (selectedPawn.Dead)
{
Finish();
return;
}
}
}
public override AcceptanceReport CanAcceptPawn(Pawn pawn)
{
if (base.Working)
{
return "Occupied".Translate();
}
if (selectedPawn != null && selectedPawn != pawn)
{
return "WaitingForPawn".Translate(selectedPawn.Named("PAWN"));
}
// 禁止置入虫群成员
if (pawn.health.hediffSet.HasHediff(ARA_HediffDefOf.ARA_HiveMindMaster) ||
pawn.health.hediffSet.HasHediff(ARA_HediffDefOf.ARA_HiveMindDrone) ||
pawn.health.hediffSet.HasHediff(ARA_HediffDefOf.ARA_HiveMindWorker))
{
return "PawnIsHiveMember".Translate(pawn.Named("PAWN"));
}
// 允许殖民者、囚犯和奴隶
bool isColonist = pawn.IsColonist;
bool isPrisoner = pawn.IsPrisonerOfColony;
bool isSlave = pawn.IsSlaveOfColony;
// 允许殖民者、囚犯或奴隶,但不能是任务寄宿者
return (isColonist || isPrisoner || isSlave) && !pawn.IsQuestLodger();
}
public override void TryAcceptPawn(Pawn pawn)
{
if (!CanAcceptPawn(pawn).Accepted)
{
return;
}
selectedPawn = pawn;
bool deselected = pawn.DeSpawnOrDeselect();
if (innerContainer.TryAddOrTransfer(pawn))
{
startTick = Find.TickManager.TicksGame;
pawnTickCounters[pawn] = 0; // 初始化伤害计数器
}
if (deselected)
{
Find.Selector.Select(pawn, playSound: false, forceDesignatorDeselect: false);
}
}
private void Finish()
{
if (selectedPawn != null && innerContainer.Contains(selectedPawn))
{
Notify_PawnRemoved();
innerContainer.TryDrop(selectedPawn, InteractionCell, base.Map, ThingPlaceMode.Near, 1, out var _);
OnStop();
}
}
private void OnStop()
{
if (selectedPawn != null)
{
pawnTickCounters.Remove(selectedPawn);
}
selectedPawn = null;
startTick = -1;
}
private void Notify_PawnRemoved()
{
// 可以在这里添加音效
}
public override IEnumerable<Gizmo> GetGizmos()
{
// 原有的基础Gizmos
foreach (Gizmo gizmo in base.GetGizmos())
{
yield return gizmo;
}
if (base.Working)
{
}
else
{
// 选择殖民者的操作
var command_Action = new Command_Action
{
defaultLabel = "InsertPerson".Translate() + "...",
defaultDesc = "InsertPersonRefuelingVatDesc".Translate(),
icon = Building_GrowthVat.InsertPawnIcon.Texture,
action = () =>
{
List<FloatMenuOption> list = new List<FloatMenuOption>();
foreach (Pawn p in base.Map.mapPawns.AllPawnsSpawned)
{
if (CanAcceptPawn(p).Accepted)
{
list.Add(new FloatMenuOption(p.LabelCap, () => SelectPawn(p), p, Color.white));
}
}
if (!list.Any())
{
list.Add(new FloatMenuOption("NoViablePawns".Translate(), null));
}
Find.WindowStack.Add(new FloatMenu(list));
}
};
if (!base.AnyAcceptablePawns)
{
command_Action.Disable("NoViablePawns".Translate());
}
yield return command_Action;
// 指派搬运囚犯/奴隶的操作
var command_CarryPrisoner = new Command_Action
{
defaultLabel = "AssignCarryPrisoner".Translate() + "...",
defaultDesc = "AssignCarryPrisonerDesc".Translate(),
icon = ContentFinder<Texture2D>.Get("UI/Commands/Attack"),
action = () =>
{
List<FloatMenuOption> list = new List<FloatMenuOption>();
// 获取所有可接受的囚犯和奴隶
foreach (Pawn p in base.Map.mapPawns.AllPawnsSpawned)
{
if (CanAcceptPawn(p).Accepted && (p.IsPrisonerOfColony || p.IsSlaveOfColony))
{
list.Add(new FloatMenuOption(
p.LabelCap + " (" + (p.IsPrisonerOfColony ? "Prisoner" : "Slave") + ")",
() => AssignCarrierForPrisoner(p),
p,
Color.white
));
}
}
if (!list.Any())
{
list.Add(new FloatMenuOption("NoPrisonersOrSlaves".Translate(), null));
}
Find.WindowStack.Add(new FloatMenu(list));
}
};
// 检查是否有可用的囚犯/奴隶
bool hasPrisonersOrSlaves = base.Map.mapPawns.AllPawnsSpawned
.Any(p => CanAcceptPawn(p).Accepted && (p.IsPrisonerOfColony || p.IsSlaveOfColony));
if (!hasPrisonersOrSlaves)
{
command_CarryPrisoner.Disable("NoPrisonersOrSlaves".Translate());
}
yield return command_CarryPrisoner;
}
}
public override string GetInspectString()
{
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append(base.GetInspectString());
if (base.Working && selectedPawn != null)
{
stringBuilder.AppendLineIfNotEmpty().Append("CasketContains".Translate().ToString() + ": " + selectedPawn.NameShortColored.Resolve());
// 显示燃料生产信息
if (HasFuelCapacity)
{
stringBuilder.AppendLineIfNotEmpty().Append("FuelProduction".Translate() + ": " + FuelProductionPerDay.ToString("F1") + " per day");
stringBuilder.AppendLineIfNotEmpty().Append("ProductionEfficiency".Translate() + ": " + FuelProductionEfficiency.ToStringPercent());
// 显示当前燃料状态
if (RefuelableComp != null)
{
stringBuilder.AppendLineIfNotEmpty().Append("CurrentFuel".Translate() + ": " + RefuelableComp.Fuel.ToString("F1") + " / " + RefuelableComp.Props.fuelCapacity);
}
}
else
{
stringBuilder.AppendLineIfNotEmpty().Append("FuelTankFull".Translate());
}
// 显示酸蚀伤害信息
if (pawnTickCounters.TryGetValue(selectedPawn, out int tickCount))
{
float damageProgress = (float)tickCount / AcidDamageInterval;
stringBuilder.AppendLineIfNotEmpty().Append("AcidDamageProgress".Translate() + ": " + damageProgress.ToStringPercent());
}
}
else if (selectedPawn != null)
{
stringBuilder.AppendLineIfNotEmpty().Append("WaitingForPawn".Translate(selectedPawn.Named("PAWN")).Resolve());
}
else
{
// 显示空闲状态信息
stringBuilder.AppendLineIfNotEmpty().Append("RefuelingVatIdle".Translate());
if (RefuelableComp != null)
{
stringBuilder.AppendLineIfNotEmpty().Append("CurrentFuel".Translate() + ": " + RefuelableComp.Fuel.ToString("F1") + " / " + RefuelableComp.Props.fuelCapacity);
}
}
return stringBuilder.ToString();
}
public override IEnumerable<FloatMenuOption> GetFloatMenuOptions(Pawn selPawn)
{
foreach (FloatMenuOption floatMenuOption in base.GetFloatMenuOptions(selPawn))
{
yield return floatMenuOption;
}
if (!selPawn.CanReach(this, PathEndMode.InteractionCell, Danger.Deadly))
{
yield return new FloatMenuOption("CannotEnterBuilding".Translate(this) + ": " + "NoPath".Translate().CapitalizeFirst(), null);
yield break;
}
AcceptanceReport acceptanceReport = CanAcceptPawn(selPawn);
if (acceptanceReport.Accepted)
{
yield return FloatMenuUtility.DecoratePrioritizedTask(new FloatMenuOption("EnterBuilding".Translate(this), () => SelectPawn(selPawn)), selPawn, this);
}
else if (!acceptanceReport.Reason.NullOrEmpty())
{
yield return new FloatMenuOption("CannotEnterBuilding".Translate(this) + ": " + acceptanceReport.Reason.CapitalizeFirst(), null);
}
}
public override void DynamicDrawPhaseAt(DrawPhase phase, Vector3 drawLoc, bool flip = false)
{
if (base.Working && selectedPawn != null && innerContainer.Contains(selectedPawn))
{
selectedPawn.Drawer.renderer.DynamicDrawPhaseAt(phase, drawLoc + PawnDrawOffset, null, neverAimWeapon: true);
}
base.DynamicDrawPhaseAt(phase, drawLoc, flip);
}
protected override void DrawAt(Vector3 drawLoc, bool flip = false)
{
base.DrawAt(drawLoc, flip);
// 绘制顶部图形
if (TopGraphic != null)
{
TopGraphic.Draw(DrawPos + Altitudes.AltIncVect * 2f, base.Rotation, this);
}
}
public Job CreateCarryJobForPrisoner(Pawn prisoner, Pawn carrier)
{
if (prisoner == null || carrier == null)
return null;
if (!CanAcceptPawn(prisoner).Accepted)
return null;
// 创建搬运工作定义 - 使用新的 JobDef
JobDef carryJobDef = DefDatabase<JobDef>.GetNamed("ARA_CarryPrisonerToRefuelingVat");
if (carryJobDef == null)
{
Log.Error("ARA_CarryPrisonerToRefuelingVat JobDef not found!");
return null;
}
Job job = JobMaker.MakeJob(carryJobDef, prisoner, this);
job.count = 1;
return job;
}
public IEnumerable<Pawn> GetAvailableCarriers()
{
foreach (Pawn pawn in base.Map.mapPawns.AllPawnsSpawned)
{
// 检查是否是虫群成员
if (pawn.health.hediffSet.HasHediff(ARA_HediffDefOf.ARA_HiveMindDrone) ||
pawn.health.hediffSet.HasHediff(ARA_HediffDefOf.ARA_HiveMindWorker) ||
pawn.health.hediffSet.HasHediff(ARA_HediffDefOf.ARA_HiveMindMaster))
{
// 检查是否能够工作且不是囚犯
if (pawn.workSettings != null && pawn.workSettings.WorkIsActive(WorkTypeDefOf.Hauling) &&
!pawn.Downed && !pawn.IsPrisoner && pawn.CanReach(this, PathEndMode.InteractionCell, Danger.Some))
{
yield return pawn;
}
}
}
}
public void AssignCarrierForPrisoner(Pawn prisoner)
{
if (prisoner == null)
return;
// 获取可用的搬运者
var availableCarriers = GetAvailableCarriers().ToList();
if (!availableCarriers.Any())
{
Messages.Message("NoAvailableHiveCarriers".Translate(), MessageTypeDefOf.RejectInput);
return;
}
// 创建浮动菜单选择搬运者
List<FloatMenuOption> options = new List<FloatMenuOption>();
foreach (Pawn carrier in availableCarriers)
{
options.Add(new FloatMenuOption(
carrier.LabelCap,
() =>
{
Job carryJob = CreateCarryJobForPrisoner(prisoner, carrier);
if (carryJob != null)
{
carrier.jobs.TryTakeOrderedJob(carryJob, JobTag.MiscWork);
Messages.Message("CarrierAssigned".Translate(carrier.LabelShort, prisoner.LabelShort), MessageTypeDefOf.NeutralEvent);
}
},
carrier,
Color.white
));
}
if (options.Any())
{
Find.WindowStack.Add(new FloatMenu(options));
}
else
{
Messages.Message("NoAvailableCarriers".Translate(), MessageTypeDefOf.RejectInput);
}
}
// 保存和加载数据
public override void ExposeData()
{
base.ExposeData();
Scribe_Collections.Look(ref pawnTickCounters, "pawnTickCounters", LookMode.Reference, LookMode.Value);
}
}
}