Files
ArachnaeSwarm/Source/ArachnaeSwarm/Hediffs/HediffComp_ReflectMeleeDamage.cs
2026-03-24 17:32:51 +08:00

299 lines
10 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 ArachnaeSwarm;
using RimWorld;
using System;
using System.Collections.Generic;
using UnityEngine;
using Verse;
namespace ArachnaeSwarmVerse
{
/// <summary>
/// 近战伤害反射组件的属性
/// </summary>
public class HediffCompProperties_ReflectMeleeDamage : HediffCompProperties
{
public float reflectMultiplier = 3.0f; // 反射倍数默认300%
public bool showReflectionEffect = true; // 是否显示反射效果
public bool reflectOnlyMelee = true; // 是否只反射近战伤害
public bool includeToolBasedRanged = false; // 是否包含使用工具的远程伤害
public float minDamageToReflect = 0.1f; // 最小反射伤害阈值
public HediffCompProperties_ReflectMeleeDamage()
{
this.compClass = typeof(HediffComp_ReflectMeleeDamage);
}
}
/// <summary>
/// 近战伤害反射组件
/// 当Pawn受到近战伤害时将300%的伤害反射给攻击者
/// </summary>
public class HediffComp_ReflectMeleeDamage : HediffComp
{
private bool isProcessingReflection = false; // 防止递归调用
private int lastReflectionTick = -100; // 上次反射的tick
private const int MIN_TICKS_BETWEEN_REFLECTIONS = 2; // 最小反射间隔
public HediffCompProperties_ReflectMeleeDamage Props => (HediffCompProperties_ReflectMeleeDamage)props;
/// <summary>
/// 获取反射倍率
/// </summary>
public float ReflectMultiplier => Props.reflectMultiplier;
/// <summary>
/// 检查是否为近战伤害
/// 根据题目要求所有damageinfo有tool的视为近战伤害
/// </summary>
private bool IsMeleeDamage(DamageInfo dinfo)
{
// 如果有Tool视为近战伤害
if (dinfo.Tool != null)
{
return true;
}
// 如果没有Tool进一步检查武器类型
if (dinfo.Weapon != null)
{
// 检查是否为近战武器
if (dinfo.Weapon.IsMeleeWeapon)
{
return true;
}
// 如果设置为包含使用工具的远程伤害,且武器有工具定义
if (Props.includeToolBasedRanged && dinfo.Weapon.tools != null && dinfo.Weapon.tools.Count > 0)
{
return true;
}
}
// 默认情况下,不视为近战伤害
return false;
}
/// <summary>
/// 检查是否应该反射此伤害
/// </summary>
private bool ShouldReflectDamage(DamageInfo dinfo, Pawn pawn)
{
// 防止递归调用
if (isProcessingReflection)
{
return false;
}
// 检查最小伤害阈值
if (dinfo.Amount < Props.minDamageToReflect)
{
return false;
}
// 检查是否只反射近战伤害
if (Props.reflectOnlyMelee && !IsMeleeDamage(dinfo))
{
return false;
}
// 检查伤害来源
if (dinfo.Instigator == null || dinfo.Instigator == pawn)
{
return false;
}
// 检查最小反射间隔
if (Find.TickManager.TicksGame - lastReflectionTick < MIN_TICKS_BETWEEN_REFLECTIONS)
{
return false;
}
// 检查攻击者是否有效
Pawn attacker = dinfo.Instigator as Pawn;
if (attacker != null && (attacker.Dead || attacker.Destroyed))
{
return false;
}
return true;
}
/// <summary>
/// 反射伤害给攻击者
/// </summary>
private void ReflectDamageToAttacker(DamageInfo originalDinfo, Pawn pawn)
{
try
{
isProcessingReflection = true;
lastReflectionTick = Find.TickManager.TicksGame;
// 计算反射伤害
float reflectedAmount = originalDinfo.Amount * ReflectMultiplier;
// 确保有最小伤害
if (reflectedAmount < 1f)
{
reflectedAmount = 1f;
}
// 获取攻击者
Thing attacker = originalDinfo.Instigator;
if (attacker == null || attacker.Destroyed)
{
return;
}
// 创建反射伤害信息
DamageInfo reflectedDinfo = new DamageInfo(
def: originalDinfo.Def,
amount: reflectedAmount,
armorPenetration: originalDinfo.ArmorPenetrationInt,
angle: Rand.Range(0, 359),
instigator: pawn, // 反射者作为伤害来源
hitPart: null,
weapon: originalDinfo.Weapon,
category: DamageInfo.SourceCategory.ThingOrUnknown,
intendedTarget: attacker
);
// 设置反射伤害的特殊属性
reflectedDinfo.SetAllowDamagePropagation(true);
reflectedDinfo.SetIgnoreArmor(false);
// 如果有Tool传递Tool信息但标记为反射伤害
if (originalDinfo.Tool != null)
{
reflectedDinfo.SetTool(originalDinfo.Tool);
}
// 记录日志
if (Prefs.DevMode)
{
Log.Message($"[ReflectMeleeDamage] {pawn.LabelShortCap} reflected {reflectedAmount:F1} damage " +
$"({originalDinfo.Amount:F1} × {ReflectMultiplier:F1}) to {attacker.LabelShortCap}");
}
// 对攻击者造成伤害
attacker.TakeDamage(reflectedDinfo);
// 显示反射效果
if (Props.showReflectionEffect)
{
ShowReflectionEffect(pawn, attacker);
}
// 发送消息
if (pawn.Faction == Faction.OfPlayer && attacker.Faction != Faction.OfPlayer)
{
Messages.Message(
"ASV_ReflectDamageMessage".Translate(
pawn.LabelShort,
attacker.LabelShort,
reflectedAmount.ToString("F0")
),
pawn,
MessageTypeDefOf.NeutralEvent
);
}
}
catch (Exception ex)
{
Log.Error($"[ReflectMeleeDamage] Error reflecting damage: {ex}");
}
finally
{
isProcessingReflection = false;
}
}
/// <summary>
/// 显示反射效果
/// </summary>
private void ShowReflectionEffect(Pawn pawn, Thing attacker)
{
try
{
// 显示反弹粒子
if (pawn.Spawned && attacker.Spawned && pawn.Map == attacker.Map)
{
Vector3 startPos = pawn.DrawPos;
Vector3 endPos = attacker.DrawPos;
// 创建一个从反射者到攻击者的弹道效果
for (int i = 0; i < 3; i++)
{
MoteThrown mote = (MoteThrown)ThingMaker.MakeThing(ARA_ThingDefOf.Mote_SparkSimple, null);
mote.Scale = Rand.Range(0.5f, 0.8f);
mote.exactPosition = startPos + new Vector3(
Rand.Range(-0.3f, 0.3f),
0f,
Rand.Range(-0.3f, 0.3f)
);
mote.SetVelocity(
(endPos - startPos).normalized.x * Rand.Range(15f, 25f),
0f
);
GenSpawn.Spawn(mote, pawn.Position, pawn.Map);
}
}
}
catch (Exception ex)
{
Log.Error($"[ReflectMeleeDamage] Error showing reflection effect: {ex}");
}
}
/// <summary>
/// 在Pawn受到伤害后调用
/// </summary>
public override void Notify_PawnPostApplyDamage(DamageInfo dinfo, float totalDamageDealt)
{
base.Notify_PawnPostApplyDamage(dinfo, totalDamageDealt);
Pawn pawn = this.Pawn;
if (pawn == null || pawn.Dead || pawn.Destroyed)
{
return;
}
// 检查是否应该反射伤害
if (ShouldReflectDamage(dinfo, pawn))
{
// 反射伤害给攻击者
ReflectDamageToAttacker(dinfo, pawn);
}
}
/// <summary>
/// 获取组件描述
/// </summary>
public override string CompTipStringExtra
{
get
{
string tip = "ASV_ReflectMeleeDamage_Tip".Translate(ReflectMultiplier.ToStringPercent());
if (Props.includeToolBasedRanged)
{
tip += "\n" + "ASV_ReflectIncludesToolRanged".Translate();
}
return tip;
}
}
/// <summary>
/// 获取调试信息
/// </summary>
public override string CompDebugString()
{
return $"Reflect multiplier: {ReflectMultiplier:F1}x\n" +
$"Last reflection tick: {lastReflectionTick}\n" +
$"Min damage to reflect: {Props.minDamageToReflect}\n" +
$"Reflects only melee: {Props.reflectOnlyMelee}\n" +
$"Includes tool-based ranged: {Props.includeToolBasedRanged}";
}
}
}