276 lines
9.6 KiB
C#
276 lines
9.6 KiB
C#
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);
|
||
}
|
||
}
|
||
} |