Files
ArachnaeSwarm/Source/ArachnaeSwarm/Abilities/ARA_Morphable/Building_Morphable.cs
2025-09-17 12:54:07 +08:00

276 lines
9.6 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.Text;
using System.Collections.Generic;
using UnityEngine;
using Verse;
namespace ArachnaeSwarm
{
public class Building_Morphable : Building
{
private CompMorphable compMorphable;
private CompRefuelableNutrition compRefuelable;
private Effecter researchEffecter;
public float virtualRest; // Public for external access
private bool forceSleep;
public float VirtualRestMax => 1.0f;
public override void ExposeData()
{
base.ExposeData();
Scribe_Values.Look(ref virtualRest, "virtualRest", 1f);
Scribe_Values.Look(ref forceSleep, "forceSleep", false);
}
public override void SpawnSetup(Map map, bool respawningAfterLoad)
{
base.SpawnSetup(map, respawningAfterLoad);
this.compMorphable = GetComp<CompMorphable>();
this.compRefuelable = GetComp<CompRefuelableNutrition>();
}
protected override void Tick()
{
base.Tick();
if (compMorphable?.StoredPawn == null)
{
StopResearchEffect();
return;
}
Pawn pawn = compMorphable.StoredPawn;
var needs = pawn.needs;
if (needs == null)
{
return;
}
// --- 饮食逻辑 ---
if (needs.food != null && compRefuelable != null)
{
if (compRefuelable.HasFuel)
{
// 模拟消耗
compRefuelable.ConsumeFuel(pawn.needs.food.FoodFallPerTick);
}
else
{
Messages.Message("PawnTransformer_OutOfFuel".Translate(pawn.Named("PAWN")), pawn, MessageTypeDefOf.NegativeEvent);
this.Destroy(DestroyMode.Vanish);
return;
}
}
// --- 休息与研究逻辑 ---
if (needs.rest != null)
{
if (needs.rest.CurLevel <= 0)
{
forceSleep = true;
}
if (forceSleep && needs.rest.CurLevel >= needs.rest.MaxLevel)
{
forceSleep = false;
}
}
TimeAssignmentDef assignment = pawn.timetable?.CurrentAssignment ?? TimeAssignmentDefOf.Anything;
if (forceSleep || assignment == TimeAssignmentDefOf.Sleep || assignment == TimeAssignmentDefOf.Joy)
{
// 休眠期 (只有在强制休眠或日程为睡眠/娱乐时才恢复)
if (needs.rest != null)
{
// 使用XML中定义的乘数
virtualRest = Mathf.Min(VirtualRestMax, virtualRest + (Need_Rest.BaseRestGainPerTick * ((CompProperties_Morphable)compMorphable.props).restGainMultiplier));
}
StopResearchEffect();
}
else // 工作或任意时间 (只要不在休息/娱乐,就下降)
{
// 使用固定的、预估的下降率
if (virtualRest > 0)
{
virtualRest -= (0.66f / 60000f);
}
ResearchProjectDef currentProj = Find.ResearchManager.GetProject();
if (currentProj != null)
{
float researchSpeed = pawn.GetStatValue(StatDefOf.ResearchSpeed);
researchSpeed *= this.GetStatValue(StatDefOf.ResearchSpeedFactor);
Find.ResearchManager.ResearchPerformed(researchSpeed, pawn);
pawn.skills.Learn(SkillDefOf.Intellectual, 0.1f, false);
StartResearchEffect();
}
else
{
StopResearchEffect();
}
}
}
private void StartResearchEffect()
{
if (researchEffecter == null)
{
researchEffecter = EffecterDefOf.Research.Spawn();
}
researchEffecter.EffectTick(this, TargetInfo.Invalid);
}
private void StopResearchEffect()
{
if (researchEffecter != null)
{
researchEffecter.Cleanup();
researchEffecter = null;
}
}
public override string Label
{
get
{
if (compMorphable?.StoredPawn != null)
{
return $"{base.Label} ({compMorphable.StoredPawn.LabelShort})";
}
return base.Label;
}
}
public override string GetInspectString()
{
List<string> inspectStrings = new List<string>();
if (compMorphable?.StoredPawn != null)
{
Pawn pawn = compMorphable.StoredPawn;
// 1. 活动状态 (置于首位)
TimeAssignmentDef assignment = pawn.timetable?.CurrentAssignment ?? TimeAssignmentDefOf.Anything;
bool isWorkingTime = !forceSleep && (assignment == TimeAssignmentDefOf.Work || assignment == TimeAssignmentDefOf.Anything);
string activity;
if (isWorkingTime)
{
ResearchProjectDef currentProj = Find.ResearchManager.GetProject();
if (currentProj != null)
{
activity = "Activity".Translate() + ": " + "Researching".Translate() + $" ({currentProj.LabelCap})";
}
else
{
activity = "Activity".Translate() + ": " + "Idle".Translate();
}
}
else
{
activity = "Activity".Translate() + ": " + "Sleeping".Translate();
}
inspectStrings.Add(activity);
// 2. 智识技能
SkillRecord intellectualSkill = pawn.skills?.GetSkill(SkillDefOf.Intellectual);
if (intellectualSkill != null)
{
inspectStrings.Add($"{SkillDefOf.Intellectual.LabelCap}: {intellectualSkill.Level} ({intellectualSkill.XpProgressPercent:P0})");
}
// 3. 休息需求
Need_Rest restNeed = pawn.needs?.rest;
if (restNeed != null)
{
inspectStrings.Add($"{restNeed.LabelCap}: {virtualRest.ToStringPercent()}");
}
}
// 基础信息如HP最后添加
string baseString = base.GetInspectString();
if (!baseString.NullOrEmpty())
{
inspectStrings.Add(baseString);
}
return string.Join("\n", inspectStrings);
}
public override void PostApplyDamage(DamageInfo dinfo, float totalDamageDealt)
{
base.PostApplyDamage(dinfo, totalDamageDealt);
if (dinfo.Amount <= 0 || this.Destroyed)
{
return;
}
if (compMorphable?.StoredPawn != null)
{
ForceRevert(dinfo);
}
}
private void ForceRevert(DamageInfo dinfo)
{
if (compMorphable?.StoredPawn == null) return;
Pawn pawn = compMorphable.StoredPawn;
// 计算将要对 Pawn 造成的伤害
float damageProportion = dinfo.Amount / this.def.statBases.GetStatValueFromList(StatDefOf.MaxHitPoints, 1f);
float pawnDamage = pawn.MaxHitPoints * damageProportion;
// 关键修复创建一个新的、干净的DamageInfo不指定hitPart让游戏自动选择有效的部位
DamageInfo pawnDinfo = new DamageInfo(
def: dinfo.Def,
amount: pawnDamage,
armorPenetration: dinfo.ArmorPenetrationInt,
angle: dinfo.Angle,
instigator: dinfo.Instigator,
hitPart: null, // 明确设为null防止继承无效上下文
weapon: dinfo.Weapon,
category: dinfo.Category,
intendedTarget: dinfo.IntendedTarget
);
// 调用统一的转换方法它会处理建筑的移除、Pawn的生成和状态同步
compMorphable.TransformBackToPawn();
// 在新生成的 Pawn 身上施加伤害
if(pawn.Spawned)
{
pawn.TakeDamage(pawnDinfo);
}
Messages.Message("PawnTransformer_ForcedRevert".Translate(pawn.Named("PAWN")), pawn, MessageTypeDefOf.NegativeEvent);
}
public override void Destroy(DestroyMode mode)
{
if (researchEffecter != null)
{
researchEffecter.Cleanup();
researchEffecter = null;
}
if (this.Spawned && compMorphable?.StoredPawn != null)
{
Pawn pawn = compMorphable.StoredPawn; // 缓存Pawn的引用
// 调用统一的转换方法
compMorphable.TransformBackToPawn();
// 仅在 DestroyMode.KillFinalize 时显示消息
if (mode == DestroyMode.KillFinalize)
{
Messages.Message("PawnTransformer_BuildingDestroyed".Translate(pawn.Named("PAWN"), this.Named("BUILDING")), pawn, MessageTypeDefOf.NegativeEvent);
}
}
base.Destroy(mode);
}
}
}