Project_WL/Assets/WL/Combat/Reaction/WLSkillHitFeel.cs

96 lines
5.1 KiB
C#
Raw Normal View History

// ─────────────────────────────────────────────────────────────────────────────
// WLSkillHitFeel.cs — 스킬별 피격 반응 덮어쓰기(밀림 · 넉백 · 경직) (#915 · 2026-10-17)
//
// PD 원문: 「검 각성 공격에 적중 된 적은 경직 상태로 살짝만 밀리게 해줘(현재는 밀리는 거리 때문에 가장자리에 있는 적이 밀려나 맞지 않을 수 있음)」
// ■ 그 스킬(맞힌 투사체의 SkillListTableData.e_Skill)에 맞은 몹만:
// · 피격 밀기(MobStagger #903 mobHitPushDistance) 거리 × pushScale
// · 원본 넉백(능력치 AttackKnockBack → Actor.KnockBack) 거리 × knockbackScale(MobKnockbackScale 이 몹 넉백 배율 대신 쓴다)
// · 경직 = max(등급별 경직, staggerSeconds)
// ■ 값 = Resources/WL/WLSkillHitFeel.json (C45) · 끄기 = enabled 0 · RuntimeDisabled(프로브 전후 비교용)
// 🔴 Debug.LogError 금지(원본 팝업).
// ─────────────────────────────────────────────────────────────────────────────
using System.Collections.Generic;
using UnityEngine;
using WL.Combat.Core;
namespace WL.Combat.Reaction
{
[System.Serializable]
public class WLSkillHitFeelRule
{
public string skill = ""; // eEffect 이름(원본 스킬 클래스)
public float pushScale = 1f; // 피격 밀기 거리 배율
public float pushMeters; // #974 > 0 = 피격 밀기 거리 고정(m · pushScale 대신) — PD 「0.2m 정도 넉백」
public float knockbackScale = 1f; // 원본 넉백 거리 배율(몹 넉백 배율 대신)
public float staggerSeconds; // 경직 최소 시간(0 = 등급별 그대로)
}
[System.Serializable]
public class WLSkillHitFeelJson
{
public int enabled = 1;
public WLSkillHitFeelRule[] rules = new WLSkillHitFeelRule[0];
public string note = "";
}
public static class WLSkillHitFeel
{
public const string ResourcesPath = "WL/WLSkillHitFeel";
public static bool RuntimeDisabled;
public static string LastLog = "";
static WLSkillHitFeelJson s_cfg;
static readonly Dictionary<int, WLSkillHitFeelRule> s_rules = new Dictionary<int, WLSkillHitFeelRule>();
static WLSkillHitFeelJson Cfg
{
get
{
if (s_cfg != null) return s_cfg;
s_cfg = new WLSkillHitFeelJson(); s_rules.Clear();
var ta = Resources.Load<TextAsset>(ResourcesPath);
if (ta == null) { LastLog = "설정 없음 " + ResourcesPath; return s_cfg; }
try { JsonUtility.FromJsonOverwrite(ta.text, s_cfg); } catch (System.Exception ex) { LastLog = "설정 파싱 실패 — " + ex.Message; }
if (s_cfg.rules != null)
foreach (var r in s_cfg.rules)
{
eEffect ef;
if (r != null && System.Enum.TryParse(r.skill, out ef)) s_rules[(int)ef]= r;
else LastLog = "스킬 이름 없음 " + (r != null ? r.skill : "null");
}
return s_cfg;
}
}
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
static void Reset() { s_cfg = null; s_rules.Clear(); RuntimeDisabled = false; }
/// <summary>#918 원본 Actor 피해 처리의 넉백 훅 1줄 — 이 피해를 낸 스킬 규칙의 knockbackScale 이 0 이하면 원본 넉백을 아예 시작하지 않는다
/// (넉백 거리 배율은 시작된 뒤에 줄이므로 0 이어도 맞을 때마다 첫 프레임만큼(약 0.07 m) 밀렸다 · 연타 8 회면 약 0.5 m).</summary>
public static bool SkipKnockback(DamageInfo d)
{
if (RuntimeDisabled || d == null) return false;
var c = Cfg;
if (c.enabled == 0 || s_rules.Count == 0) return false;
var pd = d.Beater_pd; var s = pd != null ? pd.m_SkillListTableData : null;
if (s == null) return false;
WLSkillHitFeelRule r;
if (!s_rules.TryGetValue((int)s.e_Skill, out r) || r.knockbackScale > 0f) return false;
KnockbackSkipped++;
return true;
}
public static int KnockbackSkipped;
/// <summary>이 피격을 낸 스킬의 규칙(없으면 null).</summary>
public static WLSkillHitFeelRule For(in HitConfirmedEvent e)
{
if (RuntimeDisabled) return null;
var c = Cfg;
if (c.enabled == 0 || s_rules.Count == 0) return null;
var pd = e.projectile; var s = pd != null ? pd.m_SkillListTableData : null;
if (s == null) return null;
WLSkillHitFeelRule r;
return s_rules.TryGetValue((int)s.e_Skill, out r) ? r : null;
}
}
}