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

137 lines
9.1 KiB
C#
Raw Normal View History

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;
}
}
}