ThreeKingdomsSlingshot/Assets/Scripts/OutGame/UI/HeroInfoPopup.cs

137 lines
9.1 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 UnityEngine;
using UnityEngine.UI;
namespace TKS.OutGame
{
/// <summary>
/// 영웅 상세 정보 팝업(PD 2026-11-13 명장 등용 「상세 정보를 누르면 해당 영웅의 풀 성장 스펙 및 스킬 정보를 볼 수 있는 팝업」) —
/// 머리(초상 · 이름 · 진영 · 병종 · ★(등급만 켜짐) · 전투력) → 풀 성장 능력치(HP · 공격력 · 방어력 = HeroRules.Compute(FullGrowth) · 비교 = 처음 얻었을 때) →
/// 스킬 2행(액티브 · 패시브 = 아이콘 · 이름 · 한자 · 쿨 · 최고 레벨 · 설명). 부품·색 = 영웅 상세 화면(HeroDetailScreen) 것 그대로 · 보유하지 않은 영웅도 열린다.
/// 값 = 표(hero_levels · promotion · evolve · hero_gear · skills) — 훈련·보물 효과는 유저마다 달라 넣지 않는다.
/// </summary>
public static class HeroInfoPopup
{
const float W = 860f; // 팝업 내용 칸 폭(ModalCustom 940 − 좌우 40)
const float RowIcon = 126f;
/// <summary>마지막으로 연 팝업의 풀 성장 수치(테스트·캡처 로그).</summary>
public static HeroRules.Stats LastStats { get; private set; }
public static string LastHeroId { get; private set; }
public static bool Show(OutGameRoot root, string heroId)
{
var s = root.Session;
var db = s.Db;
var h = s.Def(heroId);
if (h == null) return false;
var full = HeroRules.FullGrowth(db, h);
var st = HeroRules.Compute(db, s.Cfg, h, full);
var first = HeroRules.Compute(db, s.Cfg, h, HeroRules.NewHero(db, h, 0));
LastStats = st;
LastHeroId = heroId;
var c = root.ModalCustom("상세 정보", 1200f, new OutGameRoot.ModalButton("닫기", UiKit.Dark, null));
string g = h.isSoldier ? "white" : full.grade;
// ① 머리 = 초상(최고 등급 색 틀) · 이름 · 한자 · 진영 배지 · 병종 · ★ · 전투력
UiKit.Portrait("Face", c, h, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(0f, -4f), new Vector2(204f, 204f), false, 1f, UiKit.Col("grade_" + g + "_card_bg", UiKit.Coin));
var name = HeroDetailScreen.Txt(c, h.nameKo, 228f, 6f, 60, "white");
if (!string.IsNullOrEmpty(h.hanja)) HeroDetailScreen.Txt(c, h.hanja, 228f + name.preferredWidth + 14f, 32f, 30, "text_soft", TextAnchor.MiddleLeft, 0f, false, 0f, false);
UiKit.DropShadow(UiKit.FactionBadge(c, h.faction, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(228f, -88f), 64f), 3f);
HeroDetailScreen.Ico(c, UiKit.TypeSymbolId(h.type), 304f, 90f, 60f, 60f);
HeroDetailScreen.Txt(c, UnitTypeInfo.Korean(h.type), 372f, 104f, 30, "text_type", TextAnchor.MiddleLeft, 0f, false, 0f, false);
// 머리 별 = 그 영웅의 등급(배너·카드와 같은 수) · 풀 성장 ★ 까지 남은 칸 = 꺼진 별(QA r1 M6 「배너 ★3 ↔ 팝업 ★5」)
int stars = h.isSoldier ? h.rarity : full.star;
for (int i = 0; i < stars; i++) HeroDetailScreen.Ico(c, i < h.rarity ? "star_l" : "star_off", 228f + i * 50f, 160f, 48f, 50f, i < h.rarity ? 3f : 0f);
var pw = HeroDetailScreen.Spr(c, "Power", "chip", W - 316f, 150f, 316f, 66f, "chip_dark").transform;
HeroDetailScreen.Ico(pw, "sword", 14f, 4f, 58f, 58f);
HeroDetailScreen.Txt(pw, "전투력", 78f, 21f, 26, "text_soft", TextAnchor.MiddleLeft, 0f, true, 0f, false);
HeroDetailScreen.Txt(pw, st.power.ToString("N0"), 164f, 12f, 44, "white");
// ② 풀 성장 능력치 = 기준 줄 + 칸 3(큰 값 = 풀 성장 · 아래 = 처음 얻었을 때)
float y = 236f;
UiKit.SubTitle(c, "풀 성장 능력치", 0f, y, W, 34);
string basis = h.isSoldier
? "Lv " + full.lv + " 기준"
: "Lv " + full.lv + " · " + UiKit.GradeKo(full.grade) + " 등급 · ★" + full.star + " · 승급 장비 " + full.gearTotal + "개 기준";
HeroDetailScreen.Txt(c, basis, 0f, y + 52f, 26, "text_soft", TextAnchor.MiddleCenter, W, false, 0f, false);
y += 100f;
string[] names = { "HP", "공격력", "방어력" };
string[] icons = { "dom_stat_hp", "dom_stat_atk", "dom_stat_def" };
int[] now = { st.Hp, st.Atk, st.Def };
int[] was = { first.Hp, first.Atk, first.Def };
const float tw = 276f, th = 150f;
for (int i = 0; i < 3; i++)
{
var tile = HeroDetailScreen.Spr(c, "Stat" + i, "panel12", i * (tw + 16f), y, tw, th, "grade_" + g + "_row").transform;
HeroDetailScreen.Ico(tile, icons[i], 14f, 14f, 52f, 52f, 3f);
HeroDetailScreen.Txt(tile, names[i], 76f, 22f, 30, "white", TextAnchor.MiddleLeft, 0f, true);
HeroDetailScreen.Txt(tile, now[i].ToString("N0"), 0f, 62f, 48, "white", TextAnchor.MiddleCenter, tw);
HeroDetailScreen.Txt(tile, "처음 " + was[i].ToString("N0"), 0f, 116f, 22, "text_soft", TextAnchor.MiddleCenter, tw, false, 0f, false);
}
y += th + 14f;
HeroDetailScreen.Txt(c, "내정 훈련 · 보물 효과는 포함하지 않은 값", 0f, y, 22, "text_soft", TextAnchor.MiddleCenter, W, false, 0f, false);
y += 46f;
// ③ 스킬 2행(액티브 · 패시브) — 행 높이 = 설명 줄 수에 맞춤
UiKit.SubTitle(c, "스킬", 0f, y, W, 34);
y += 58f;
if (h.isSoldier)
{
HeroDetailScreen.Txt(c, "병사 유닛은 스킬이 없습니다", 0f, y + 10f, 28, "text_soft", TextAnchor.MiddleCenter, W, false, 0f, false);
y += 70f;
}
else
{
string tk = UiKit.TypeKey(h.type);
for (int i = 0; i < 2; i++)
{
var sk = SkillRules.Skill(db, h, i);
if (sk == null) continue;
var row = HeroDetailScreen.Spr(c, "Skill" + i, "panel12", 0f, y, W, 160f, "grade_" + g + "_row");
var rt = row.transform;
string iconId = "skill_" + sk.id;
bool hasIcon = UISkin.Theme != null && UISkin.Theme.IconEntryOf(iconId) != null;
// 아이콘 = 영웅 상세와 같은 규칙(256² 사각 아이콘 + 병종 얇은 틀 · 아이콘이 없으면 두꺼운 틀 + 병종 기호)
if (hasIcon)
{
HeroDetailScreen.Ico(rt, iconId, 14f + 10.34f, 16f + 10.34f, 105.33f, 105.33f);
if (tk != null) HeroDetailScreen.Ico(rt, "skill_ring_" + tk, 14f, 16f, RowIcon, RowIcon, 4f);
}
else
{
if (tk != null) HeroDetailScreen.Ico(rt, "skill_" + tk + "_a", 14f, 16f, RowIcon, RowIcon, 4f);
HeroDetailScreen.Ico(rt, UiKit.TypeSymbolId(h.type), 36f, 38f, 82f, 82f);
}
float x = 158f;
var kind = HeroDetailScreen.Spr(rt, "Kind", "chip", x, 14f, 116f, 44f, i == 0 ? "chip_cool" : "chip_dark");
HeroDetailScreen.Txt(kind.transform, i == 0 ? "액티브" : "패시브", 0f, 9f, 26, "white", TextAnchor.MiddleCenter, 116f, true, 3f);
if (i == 0 && sk.cooldown > 0)
{
var cool = HeroDetailScreen.Spr(rt, "Cool", "chip", x + 126f, 14f, 124f, 44f, "chip_dark");
HeroDetailScreen.Txt(cool.transform, "쿨 " + sk.cooldown + "턴", 0f, 9f, 26, "white", TextAnchor.MiddleCenter, 124f, false, 3f);
}
var lv = HeroDetailScreen.Spr(rt, "Lv", "chip", W - 176f, 14f, 160f, 44f, "chip_dark");
HeroDetailScreen.Txt(lv.transform, "최고 Lv " + SkillRules.Level(full, i), 0f, 9f, 26, "white", TextAnchor.MiddleCenter, 160f, true, 3f);
var nm = HeroDetailScreen.Txt(rt, sk.nameKo, x, 66f, 38, "white");
if (!string.IsNullOrEmpty(sk.hanja)) HeroDetailScreen.Txt(rt, sk.hanja, x + nm.preferredWidth + 10f, 76f, 26, "grade_" + g + "_label", TextAnchor.MiddleLeft, 0f, false, 0f, false);
var desc = HeroDetailScreen.Desc(rt, x, 118f, W - x - 20f);
desc.fontSize = 24;
desc.text = SkillInfoDb.DisplayDesc(sk);
desc.verticalOverflow = VerticalWrapMode.Overflow;
float dh = Mathf.Ceil(desc.preferredHeight);
desc.rectTransform.sizeDelta = new Vector2(desc.rectTransform.sizeDelta.x, dh);
float rh = Mathf.Max(160f, 118f + dh + 18f);
row.rectTransform.sizeDelta = new Vector2(W, rh);
y += rh + 14f;
}
}
// 팝업 높이 = 내용에 맞춤(제목 띠 130 + 아래 버튼 줄 160)
var panel = (RectTransform)c.parent;
panel.sizeDelta = new Vector2(panel.sizeDelta.x, Mathf.Clamp(y + 300f, 600f, 1620f));
return true;
}
}
}