Files
WulaFallenEmpireRW/Source/WulaFallenEmpire/HediffComp/WULA_TimedExplosion/HediffComp_TimedExplosion.cs
2026-02-25 12:00:37 +08:00

245 lines
8.1 KiB
C#

using RimWorld;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
using Verse;
using Verse.Noise;
namespace WulaFallenEmpire
{
public class HediffComp_TimedExplosion : HediffComp
{
// 倒计时相关字段
public int ticksToDisappear;
public int disappearsAfterTicks;
public int seed;
// 配置属性快捷访问
public HediffCompProperties_TimedExplosion Props =>
(HediffCompProperties_TimedExplosion)props;
// 消失判定属性
public override bool CompShouldRemove
{
get
{
if (ticksToDisappear > 0) return false;
if (Props.requiredMentalState != null)
{
return parent.pawn.MentalStateDef != Props.requiredMentalState;
}
return true;
}
}
// 进度计算
public float Progress =>
1f - (float)ticksToDisappear / Mathf.Max(1, disappearsAfterTicks);
public int EffectiveTicksToDisappear => ticksToDisappear / TicksLostPerTick;
public float NoisyProgress => AddNoiseToProgress(Progress, seed);
public virtual int TicksLostPerTick => 1;
public override string CompLabelInBracketsExtra
{
get
{
if (Props.showRemainingTime)
{
if (EffectiveTicksToDisappear < 2500)
{
return EffectiveTicksToDisappear.ToStringSecondsFromTicks("F0");
}
return EffectiveTicksToDisappear.ToStringTicksToPeriod(allowSeconds: true, shortForm: true, canUseDecimals: true, allowYears: true, Props.canUseDecimalsShortForm);
}
return base.CompLabelInBracketsExtra;
}
}
private static float AddNoiseToProgress(float progress, int seed)
{
float num = (float)Perlin.GetValue(progress, 0.0, 0.0, 9.0, seed);
float num2 = 0.25f * (1f - progress);
return Mathf.Clamp01(progress + num2 * num);
}
// 初始化
public override void CompPostMake()
{
base.CompPostMake();
disappearsAfterTicks = Props.disappearsAfterTicks.RandomInRange;
seed = Rand.Int;
ticksToDisappear = disappearsAfterTicks;
}
// 每帧更新
public override void CompPostTick(ref float severityAdjustment)
{
ticksToDisappear--;
if (CompShouldRemove)
{
parent.pawn.health.RemoveHediff(parent);
}
}
// 移除后处理
public override void CompPostPostRemoved()
{
base.CompPostPostRemoved();
// 处理新鲜伤口状态
if (!Props.leaveFreshWounds && parent.Part != null)
{
foreach (BodyPartRecord part in parent.Part.GetPartAndAllChildParts())
{
Hediff_MissingPart hediff = parent.pawn.health.hediffSet.GetMissingPartFor(part) as Hediff_MissingPart;
if (hediff != null)
{
hediff.IsFresh = false;
}
}
}
// 触发爆炸逻辑
if (ShouldTriggerExplosion())
{
TriggerExplosion();
DestroyGearIfNeeded();
}
// 发送消息通知
if (!Props.messageOnDisappear.NullOrEmpty() && PawnUtility.ShouldSendNotificationAbout(parent.pawn))
{
Messages.Message(
Props.messageOnDisappear.Formatted(parent.pawn.Named("PAWN")),
parent.pawn,
MessageTypeDefOf.NeutralEvent
);
}
// 发送信件通知
if (!Props.letterTextOnDisappear.NullOrEmpty() &&
!Props.letterLabelOnDisappear.NullOrEmpty() &&
PawnUtility.ShouldSendNotificationAbout(parent.pawn))
{
Find.LetterStack.ReceiveLetter(
Props.letterLabelOnDisappear.Formatted(parent.pawn.Named("PAWN")),
Props.letterTextOnDisappear.Formatted(parent.pawn.Named("PAWN")),
LetterDefOf.NegativeEvent,
parent.pawn
);
}
}
// 爆炸条件检查
private bool ShouldTriggerExplosion()
{
return parent.pawn.Spawned &&
Props.explosionRadius > 0.01f &&
Props.damageDef != null &&
parent.pawn.Map != null;
}
// 执行爆炸
private void TriggerExplosion()
{
GenExplosion.DoExplosion(
center: parent.pawn.Position,
map: parent.pawn.Map,
radius: Props.explosionRadius,
damType: Props.damageDef,
instigator: parent.pawn,
damAmount: Props.damageAmount,
armorPenetration: Props.armorPenetration,
explosionSound: Props.soundDef,
weapon: null,
projectile: null,
intendedTarget: null,
postExplosionSpawnThingDef: Props.postExplosionSpawnThingDef,
postExplosionSpawnChance: Props.postExplosionSpawnChance,
postExplosionSpawnThingCount: Props.postExplosionSpawnThingCount,
postExplosionGasType: null,
applyDamageToExplosionCellsNeighbors: false,
chanceToStartFire: Props.chanceToStartFire,
damageFalloff: Props.damageFalloff,
direction: null,
ignoredThings: new List<Thing> { parent.pawn }
);
}
// 装备销毁
private void DestroyGearIfNeeded()
{
if (!Props.destroyGear) return;
if (parent.pawn.equipment != null)
{
parent.pawn.equipment.DestroyAllEquipment(DestroyMode.Vanish);
}
if (parent.pawn.apparel != null)
{
parent.pawn.apparel.DestroyAll(DestroyMode.Vanish);
}
}
// 数据持久化
public override void CompExposeData()
{
Scribe_Values.Look(ref ticksToDisappear, "ticksToDisappear", 0);
Scribe_Values.Look(ref disappearsAfterTicks, "disappearsAfterTicks", 0);
Scribe_Values.Look(ref seed, "seed", 0);
}
// 调试信息
public override string CompDebugString()
{
return $"倒计时: {ticksToDisappear}\n爆炸半径: {Props.explosionRadius}";
}
}
public class HediffCompProperties_TimedExplosion : HediffCompProperties
{
[Header("消失设置")]
public IntRange disappearsAfterTicks = new IntRange(600, 1200);
public bool showRemainingTime = true;
public bool canUseDecimalsShortForm;
public MentalStateDef requiredMentalState;
public bool leaveFreshWounds = true;
[Header("爆炸设置")]
public float explosionRadius = 3f;
public DamageDef damageDef;
public int damageAmount = 20;
public float armorPenetration;
public SoundDef soundDef;
public float chanceToStartFire;
public bool damageFalloff = true;
[Header("后续效果")]
public bool destroyGear;
public GasType gasType;
public ThingDef postExplosionSpawnThingDef;
public float postExplosionSpawnChance;
public int postExplosionSpawnThingCount = 1;
[Header("通知设置")]
[MustTranslate]
public string messageOnDisappear;
[MustTranslate]
public string letterLabelOnDisappear;
[MustTranslate]
public string letterTextOnDisappear;
public bool sendLetterOnDisappearIfDead = true;
public HediffCompProperties_TimedExplosion()
{
compClass = typeof(HediffComp_TimedExplosion);
}
}
}