using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
namespace TKS.OutGame
{
/// 영웅·병사 카드(2줄 · 기획 S12 v4) — 좌 초상(★ 는 초상 아래) · 1줄 = 병종 배지 · Lv · 출전 중 · 2줄 = 이름.
public static class HeroCards
{
public static Image Card(Transform content, OutGameSession s, HeroDb.Hero h, bool deployed, bool owned, System.Action onTap)
{
var cell = UiKit.Cell(content, "Card_" + h.id, owned ? UiKit.Paper : new Color(0.86f, 0.84f, 0.8f), onTap);
UiKit.Border(cell, deployed ? UiKit.Red : UiKit.Line, deployed ? 4f : 2f);
var lv = s.Save.Level(h.id);
var hs = s.Save.Hero(h.id);
UiKit.Portrait("Face", cell.transform, h, new Vector2(0f, 0.5f), new Vector2(0f, 0.5f), new Vector2(12f, 8f), new Vector2(116f, 108f), false, 2f, new Color(0.9f, 0.86f, 0.8f));
int star = hs != null ? hs.star : h.rarity;
if (UISkin.Icon("star_on") != null) UiKit.StarRow(cell.transform, star, star, new Vector2(0f, 0f), new Vector2(0f, 0f), new Vector2(14f, 2f), 24f);
else UiKit.Label(cell.transform, UiKit.Stars(star, star), 22, UiKit.Star, TextAnchor.MiddleCenter, new Vector2(0f, 0f), new Vector2(0f, 0f), new Vector2(12f, 2f), new Vector2(116f, 30f));
UiKit.TypeBadge(cell.transform, h.type, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(142f, -16f), 40f);
UiKit.Title(UiKit.Label(cell.transform, owned ? "Lv " + (lv != null ? lv.lv : 1) : "미보유", 30, UiKit.Ink, TextAnchor.MiddleLeft, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(204f, -12f), new Vector2(150f, 48f)));
if (deployed)
{
var b = UiKit.Box("Deployed", cell.transform, new Vector2(1f, 1f), new Vector2(1f, 1f), new Vector2(-12f, -14f), new Vector2(124f, 44f), UiKit.Red);
UiKit.Title(UiKit.FillLabel(b.transform, "출전 중", 24, UiKit.White), true);
}
if (hs != null)
{
var g = UiKit.Box("Grade", cell.transform, new Vector2(1f, 0f), new Vector2(1f, 0f), new Vector2(-12f, 14f), new Vector2(56f, 48f), UiKit.GradeColor(hs.grade));
UiKit.GradeFrame(g, hs.grade);
UiKit.Title(UiKit.FillLabel(g.transform, UiKit.GradeKo(hs.grade), 24, UiKit.White), true);
}
var name = UiKit.Title(UiKit.Label(cell.transform, h.nameKo, 44, owned ? UiKit.Ink : UiKit.InkSoft, TextAnchor.MiddleLeft, new Vector2(0f, 0f), new Vector2(0f, 0f), new Vector2(142f, 12f), new Vector2(290f, 66f)));
name.horizontalOverflow = HorizontalWrapMode.Overflow;
if (owned && s.CanGrowAny(h.id) && UiKit.Icon(cell.transform, "new_dot", new Vector2(0f, 1f), new Vector2(0.5f, 0.5f), new Vector2(14f, -10f), 34f) == null)
UiKit.Dot("New", cell.transform, new Vector2(0f, 1f), new Vector2(0.5f, 0.5f), new Vector2(14f, -10f), 26f, UiKit.Red);
return cell;
}
}
/// 영웅 탭 = 보유 영웅·병사 목록(장수|병사 · 2줄 카드) → 탭 = 영웅 상세 · 도감.
public class HeroListScreen : OutGameScreen
{
bool soldiers;
RectTransform content;
ScrollRect scroll;
Button tabHero;
Button tabSoldier;
public bool ShowingSoldiers
{
get { return soldiers; }
}
public override void Build()
{
Tab = 0;
Header("영웅", "레벨 · 승급 · 진화 · 스킬", true);
var body = Body();
tabHero = UiKit.Btn("TabHero", body, "장수", 36, UiKit.Red, UiKit.White, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(24f, -20f), new Vector2(220f, 84f), () => SetFilter(false));
tabSoldier = UiKit.Btn("TabSoldier", body, "병사", 36, UiKit.Paper, UiKit.Ink, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(258f, -20f), new Vector2(220f, 84f), () => SetFilter(true));
UiKit.Btn("Codex", body, "도감", 36, UiKit.Dark, UiKit.White, new Vector2(1f, 1f), new Vector2(1f, 1f), new Vector2(-24f, -20f), new Vector2(220f, 84f), () => HeroDetailScreen.ShowCodex(Root));
content = UiKit.ScrollGrid("List", body, 24f, 24f, 124f, 16f, new Vector2(506f, 150f), new Vector2(20f, 18f), 2, out scroll);
}
public void SetFilter(bool soldier)
{
soldiers = soldier;
Refresh();
}
public override void Refresh()
{
tabHero.GetComponent().color = soldiers ? UiKit.Paper : UiKit.Red;
UiKit.LabelOf(tabHero).color = soldiers ? UiKit.Ink : UiKit.White;
tabSoldier.GetComponent().color = soldiers ? UiKit.Red : UiKit.Paper;
UiKit.LabelOf(tabSoldier).color = soldiers ? UiKit.White : UiKit.Ink;
UiKit.LabelOf(tabHero).text = "장수 " + S.Owned(false).Count;
UiKit.LabelOf(tabSoldier).text = "병사 " + S.Owned(true).Count;
UiKit.Clear(content);
foreach (var h in S.Owned(soldiers))
{
var id = h.id;
HeroCards.Card(content, S, h, S.InActivePreset(id), true, () => Root.ShowHero(id));
}
}
public int CardCount
{
get { return content.childCount; }
}
}
///
/// 영웅 상세(UI 상업용 재설계 ① · PD 2026-11-09 확정 목업 hero_detail.html = 좌표·부품·색 SOT · 본문 y = 목업 y − 224) —
/// 등급 색 바탕(글로우 + 문양 · 화면 전체) · 전투력 칩 · 일러(좌우 밀기 = 영웅 전환) + 양옆 장비 6칸 · 레벨 행(레벨업 · 승급) · 이름 띠(세력 · 병종 · 등급 · ★) ·
/// 스킬 패널(액티브 · 패시브 · 행마다 레벨업) · 메뉴 4버튼(정보 = 상세정보 + 도감 · 진화 = 조각 팝업 · 각성 · 외형 = 준비 중). 색·스프라이트 = 테마 표(ui_theme.csv) id.
///
public class HeroDetailScreen : OutGameScreen
{
const float SwipeMin = 80f; // 일러 밀기 = 가로 80 px 이상(기준 해상도 px)
static readonly string[] MenuNames = { "정보", "진화", "각성", "외형" };
static readonly string[] MenuIcons = { "info", "star_l", "fire", "top" };
static readonly Vector2[] MenuIconSize = { new Vector2(26f, 60f), new Vector2(58f, 62f), new Vector2(64f, 50f), new Vector2(62f, 46f) };
string id;
readonly List order = new List();
Image bgFill;
Image bgGlow;
Text ownedText;
Text power;
RectTransform art;
float dragX;
readonly GameObject[] slotRoot = new GameObject[6];
readonly Image[] slotGlow = new Image[6];
readonly Image[] slotBg = new Image[6];
readonly Image[] slotDeco = new Image[6];
readonly Image[] slotLight = new Image[6];
readonly Image[] slotIcon = new Image[6];
readonly Text[] slotName = new Text[6];
readonly Image[] slotCheck = new Image[6];
readonly Image[] slotBag = new Image[6];
Text lvBadge;
Text lvText;
Text expText;
RectTransform expFill;
Image levelImg;
Text levelLabel;
Text levelCost;
Image goldIcon;
Image promoteImg;
Text promoteSub;
Image bandImg;
Image flagIcon;
Image clsIcon;
Image paraImg;
Text gradeText;
Text nameText;
Text typeText;
RectTransform starRow;
Image panelImg;
GameObject coolChip;
Text coolText;
readonly Image[] rowImg = new Image[2];
readonly Image[] skFrame = new Image[2];
readonly Image[] skCls = new Image[2];
readonly Text[] skName = new Text[2];
readonly Text[] skHanja = new Text[2];
readonly Text[] skDesc = new Text[2];
readonly Text[] skLv = new Text[2];
readonly Image[] skBtn = new Image[2];
readonly Text[] skBtnText = new Text[2];
readonly Text[] skBtnSub = new Text[2];
readonly GameObject[] skCost = new GameObject[2];
readonly Text[] skBooks = new Text[2];
readonly Text[] skGold = new Text[2];
Image evolveDot;
public string HeroId
{
get { return id; }
}
public void Select(string heroId)
{
id = heroId;
var h = S.Def(heroId);
order.Clear();
if (h != null)
foreach (var o in S.Owned(h.isSoldier)) order.Add(o.id);
}
// ---------- 목업 좌표 도우미(부모 왼쪽 위 기준 · y 아래로) ----------
static Color Col(string colorId)
{
return UISkin.Col(colorId, Color.white);
}
static RectTransform At(Transform p, string name, float x, float y, float w, float h)
{
return UiKit.Rect(name, p, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(x, -y), new Vector2(w, h));
}
static Image Spr(Transform p, string name, string skin, float x, float y, float w, float h, string color, bool raycast = false)
{
return UiKit.Skin(At(p, name, x, y, w, h), skin, Col(color), raycast);
}
Image Press(Transform p, string name, string skin, float x, float y, float w, float h, string color, System.Action onClick)
{
var img = Spr(p, name, skin, x, y, w, h, color, true);
img.gameObject.AddComponent