// ───────────────────────────────────────────────────────────────────────────── // WLPartSkillText.cs — 파츠 스킬 표시 문구(장비 화면 · 스킬 상세 · 도감) (PD 지시 #879 · 기획 v2 18 · 19장) // 문구의 숫자 = 레벨표 행(FR 원본) 그대로 + 설정 환산(거리 m). 등급 → 단계 = WLPartSkill.json tierLevel/tierMult. // ───────────────────────────────────────────────────────────────────────────── using System.Text; using UnityEngine; using WL.Equip; namespace WL.PartSkill { public static class WLPartSkillText { public static string AttrName(string attr) { switch (attr) { case "attack": return "공격"; case "defense": return "방어"; case "passive": return "패시브"; case "weapon": return "무기 시너지"; } return ""; } public static string PartName(eFREquipmentType p) { return WLEquipTables.SlotName(p); } static string N(float v) { return Mathf.Abs(v - Mathf.Round(v)) < 0.01f ? Mathf.Round(v).ToString("0") : v.ToString("0.#"); } /// 단계 1행 요약 — 「개수 4 · 피해 90% · 범위 2.1m · 쿨 7초」(패시브 = 값). public static string LevelSummary(WLPartSkillDef d, int level, float mult) { return LevelSummary(d, level, mult, 99); } /// 항목 수 상한(장비 팝업 한 줄용 · #881) public static string LevelSummary(WLPartSkillDef d, int level, float mult, int maxParts) { if (d == null) return ""; var S = WLPartSkillData.S; if (d.kind == WLPartKind.Passive) { var p = WLPartSkillData.Passive(d.lvId, Mathf.Max(1, level)); if (p == null) return ""; string s = "+" + N(p.v0 * mult) + "%"; if (p.v1 > 0f) s += " · +" + N(p.v1 * mult) + "%"; if (d.behavior == "regen") s = (d.v1 > 0f ? N(d.v1) : "5") + "초마다 " + N(p.v0 * mult) + "% 회복"; return s; } var r = WLPartSkillData.Level(d.lvSrc, d.lvId, Mathf.Max(1, level)); if (r == null) return ""; var sb = new StringBuilder(); int parts = 0; System.Action add = x => { if (parts >= maxParts) return; if (sb.Length > 0) sb.Append(" · "); sb.Append(x); parts++; }; if (r.count > 1f) add("개수 " + N(r.count)); if (r.dmgPct > 0f && d.behavior != "heal_heart") add("피해 " + N(r.dmgPct * mult) + "%"); if (r.Has("Heal")) add("회복 " + N(r.Eff("Heal", "Percent", 0f) * mult) + "%"); float hit = r.hitRange > 0f ? r.hitRange : r.splash; if (hit > 0f && d.behavior != "blades" && d.behavior != "homing") add("범위 " + Mathf.Max(S.minRadius, hit * S.distanceScale).ToString("0.0") + "m"); if (r.Has("Stun")) add("기절 " + N(r.Eff("Stun", "Duration", 0f)) + "초"); if (r.Has("Daze")) add("감속 " + N(r.Eff("Daze", "DecreaseMovePercentage", 0f)) + "%"); if (r.Has("Invincible")) add("무적 " + N(r.Eff("Invincible", "Duration", 0f)) + "초"); if (r.Has("DotDamageAddiction")) add("지속 피해 " + N(r.Eff("DotDamageAddiction", "DamagePercentage", 0f)) + "%"); if (r.duration < 0f) add("상시"); else if (r.cool > 0f) add("쿨 " + N(r.cool) + "초"); return sb.ToString(); } /// 등급(1~7) 행 문구 — 「Lv3 · 개수 3 · 피해 60%」 · 불멸 · 신화 = 「Lv5 수치 × 1.2」. public static string TierRow(WLPartSkillDef d, int tier) { return TierRow(d, tier, 99); } public static string TierRow(WLPartSkillDef d, int tier, int maxParts) { int lv = WLPartSkillData.TierLevel(tier); float m = WLPartSkillData.TierMult(tier); if (lv <= 0) return "닫힘"; if (m > 1.0001f) return "Lv" + lv + " 수치 × " + m.ToString("0.0#"); return "Lv" + lv + " · " + LevelSummary(d, lv, 1f, maxParts); } /// 시너지 조건 · 상태 한 줄. public static string SynergyLine(WLPartSlot s, bool rich) { if (s == null || s.def == null) return ""; var d = s.def; var S = WLPartSkillData.S; int need = S.synergyLevel; if (!string.IsNullOrEmpty(d.combineKey)) { var other = WLPartSkillData.Def(d.combineKey); string on = s.synergy ? (rich ? "★ 시너지 [정령왕]" : "★ 시너지 [정령왕]") : "둘 다 " + need + "단계면 [정령왕]"; return d.name + " " + s.level + " + " + (other != null ? other.name : "?") + " " + s.synPartnerLevel + " = " + on; } if (string.IsNullOrEmpty(d.synKey)) return ""; var p = WLPartSkillData.Def(d.synKey); string pn = p != null ? p.name + "(" + PartName(p.part) + ")" : "?"; if (d.kind == WLPartKind.WeaponSyn) { // #895 무기와 무관 — 장착 장비 조건(짝 패시브 [+ req_key])만 string cond = pn + " " + s.synPartnerLevel; if (!string.IsNullOrEmpty(d.reqKey)) { var q = WLPartSkillData.Def(d.reqKey); cond += " + " + (q != null ? q.name + "(" + PartName(q.part) + ")" : d.reqKey); } if (s.synergy) return cond + " = " + (rich ? "★ 무기 시너지 [" + d.synName + "]" : "★ 무기 시너지 [" + d.synName + "]"); return cond + " · " + need + "단계면 무기 시너지 [" + d.synName + "] (무기 무관)"; } string head = d.name + " " + s.level + " + " + pn + " " + s.synPartnerLevel; if (s.synergy) return head + " = " + (rich ? "★ 시너지 [" + d.synName + "]" : "★ 시너지 [" + d.synName + "]"); return head + " · 둘 다 " + need + "단계면 시너지"; } } }