Files
ArachnaeSwarm/Source/ArachnaeSwarm/Hediffs/ProphecyGearEffect.cs
2025-09-17 12:54:07 +08:00

211 lines
7.8 KiB
C#

using System;
using System.Collections.Generic;
using System.Reflection;
using HarmonyLib;
using RimWorld;
using UnityEngine;
using Verse;
namespace ArachnaeSwarm
{
public class ProphecyGearEffect : DefModExtension
{
public HediffDef hediffToApply;
public float severityPerDamage = 0f;
public float minSeverity = 0f;
public float maxSeverity = 1f;
public bool enableHediffEffect = true;
public float extraDamageFactor = 0f;
public DamageDef extraDamageType;
public float armorPenetration = 0f;
public BodyPartDef targetBodyPart;
public bool enableExtraDamage = true;
// 新添加:触发效果所需的仿生体 Hediff
public HediffDef requiredBionicHediff;
}
[HarmonyPatch(typeof(Pawn), "PostApplyDamage")]
public static class DRM_ProphecyGear_Patch
{
private static readonly FieldInfo damageInfoWeaponField =
typeof(DamageInfo).GetField("weapon", BindingFlags.Instance | BindingFlags.NonPublic);
private static bool isApplyingExtraDamage = false;
public static void Postfix(Pawn __instance, DamageInfo dinfo, float totalDamageDealt)
{
if (isApplyingExtraDamage) return;
try
{
if (__instance == null || __instance.Dead || __instance.health == null) return;
if (!(dinfo.Instigator is Pawn attacker) || attacker.apparel == null) return;
if (totalDamageDealt <= 0) return;
// 收集所有可能的效果来源
var effectsToApply = new List<ProphecyGearEffect>();
// 1. 从装备收集效果
foreach (var apparel in attacker.apparel.WornApparel)
{
var effect = apparel.def.GetModExtension<ProphecyGearEffect>();
if (effect != null && IsEffectValid(effect, attacker))
{
effectsToApply.Add(effect);
}
}
// 2. 从仿生体 Hediff 收集效果
foreach (var hediff in attacker.health.hediffSet.hediffs)
{
var effect = hediff.def.GetModExtension<ProphecyGearEffect>();
if (effect != null && IsEffectValid(effect, attacker))
{
effectsToApply.Add(effect);
}
}
// 应用所有效果
foreach (var effect in effectsToApply)
{
if (effect.enableHediffEffect && effect.hediffToApply != null)
{
ApplyHediffEffect(__instance, effect, totalDamageDealt);
}
if (effect.enableExtraDamage &&
effect.extraDamageFactor > 0 &&
effect.extraDamageType != null)
{
isApplyingExtraDamage = true;
ApplyExtraDamage(__instance, effect, totalDamageDealt, dinfo);
isApplyingExtraDamage = false;
}
}
}
catch (Exception ex)
{
isApplyingExtraDamage = false;
Log.Error($"[ArachnaeSwarm] Error in PostApplyDamage patch: {ex}");
}
}
// 检查效果是否有效(满足仿生体要求)
private static bool IsEffectValid(ProphecyGearEffect effect, Pawn attacker)
{
// 如果没有要求仿生体,则始终有效
if (effect.requiredBionicHediff == null)
return true;
// 检查攻击者是否拥有所需的仿生体
return attacker.health.hediffSet.HasHediff(effect.requiredBionicHediff);
}
private static void ApplyHediffEffect(Pawn target, ProphecyGearEffect effect, float damageDealt)
{
try
{
double severityToAdd = (double)damageDealt * (double)effect.severityPerDamage;
float finalSeverity = (float)severityToAdd;
if (finalSeverity < 0.001f) return;
var existingHediff = target.health.hediffSet.GetFirstHediffOfDef(effect.hediffToApply);
if (existingHediff == null)
{
Hediff newHediff = HediffMaker.MakeHediff(effect.hediffToApply, target);
if (newHediff != null)
{
newHediff.Severity = finalSeverity;
if (effect.minSeverity > 0)
newHediff.Severity = Math.Max(newHediff.Severity, effect.minSeverity);
if (effect.maxSeverity > 0)
newHediff.Severity = Math.Min(newHediff.Severity, effect.maxSeverity);
target.health.AddHediff(newHediff);
}
}
else
{
float newSeverity = existingHediff.Severity + finalSeverity;
if (effect.minSeverity > 0)
newSeverity = Math.Max(newSeverity, effect.minSeverity);
if (effect.maxSeverity > 0)
newSeverity = Math.Min(newSeverity, effect.maxSeverity);
existingHediff.Severity = newSeverity;
if (existingHediff is HediffWithComps hwc)
{
var comp = hwc.TryGetComp<HediffComp_Disappears>();
if (comp != null)
{
comp.ticksToDisappear = comp.Props.disappearsAfterTicks.max;
}
}
}
}
catch (Exception ex)
{
Log.Error($"[ArachnaeSwarm] Error in ApplyHediffEffect: {ex}");
}
}
private static void ApplyExtraDamage(
Pawn target,
ProphecyGearEffect effect,
float baseDamage,
DamageInfo originalDinfo)
{
try
{
float extraDamageAmount = baseDamage * effect.extraDamageFactor;
if (extraDamageAmount < 0.5f) extraDamageAmount = 0.5f;
if (extraDamageAmount <= 0) return;
Thing weapon = null;
if (damageInfoWeaponField != null)
{
weapon = damageInfoWeaponField.GetValue(originalDinfo) as Thing;
}
BodyPartRecord hitPart = null;
if (effect.targetBodyPart != null)
{
var bodyPartDef = DefDatabase<BodyPartDef>.GetNamedSilentFail(effect.targetBodyPart.defName);
if (bodyPartDef != null)
{
hitPart = target.RaceProps.body.GetPartsWithDef(bodyPartDef).FirstOrFallback();
}
}
else
{
hitPart = originalDinfo.HitPart;
}
DamageInfo extraDinfo = new DamageInfo(
def: effect.extraDamageType,
amount: extraDamageAmount,
armorPenetration: effect.armorPenetration,
angle: -1f,
instigator: originalDinfo.Instigator,
hitPart: hitPart,
weapon: originalDinfo.Weapon,
category: DamageInfo.SourceCategory.ThingOrUnknown,
intendedTarget: target
);
target.TakeDamage(extraDinfo);
}
catch (Exception ex)
{
Log.Error($"[ArachnaeSwarm] Error in ApplyExtraDamage: {ex}");
}
}
}
}