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

453 lines
27 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 System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
namespace TKS.OutGame
{
/// <summary>영웅·병사 카드(2줄 · 기획 S12 v4) — 좌 초상(★ 는 초상 아래) · 1줄 = 병종 배지 · Lv · 출전 중 · 2줄 = 이름.</summary>
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;
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.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.FillLabel(b.transform, "출전 중", 24, UiKit.White);
}
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, 40f), UiKit.GradeColor(hs.grade));
UiKit.FillLabel(g.transform, UiKit.GradeKo(hs.grade), 24, UiKit.White);
}
var name = 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.Dot("New", cell.transform, new Vector2(0f, 1f), new Vector2(0.5f, 0.5f), new Vector2(14f, -10f), 26f, UiKit.Red);
return cell;
}
}
/// <summary>영웅 탭 = 보유 영웅·병사 목록(장수|병사 · 2줄 카드) → 탭 = 영웅 상세 · 도감.</summary>
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<Image>().color = soldiers ? UiKit.Paper : UiKit.Red;
UiKit.LabelOf(tabHero).color = soldiers ? UiKit.Ink : UiKit.White;
tabSoldier.GetComponent<Image>().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; }
}
}
/// <summary>
/// 영웅 상세(img06 · 기획 S6 v4) — 전투력 · 일러 + 양옆 장비 6칸(빈 칸 탭 = 가방에서 장착 · 1칸 = 1강) · 이름 띠(병종 · 이름 · ★) ·
/// 스킬 정보(액티브·패시브 = 이름·효과·Lv·쿨 · 표시만 · 스킬 레벨업 = B 단계) · Lv/경험 바 + 레벨업(골드) · 승급(6칸) · 조각 바 + 진화 · 상세정보 · 도감 · ◀ ▶ 전환.
/// </summary>
public class HeroDetailScreen : OutGameScreen
{
string id;
readonly List<string> order = new List<string>();
Text power;
RectTransform art;
readonly Image[] slotImg = new Image[6];
readonly Text[] slotName = new Text[6];
readonly Text[] slotState = new Text[6];
Image typeDot;
Text typeMark;
Text nameText;
Text subText;
Text starText;
Text[] skillName = new Text[2];
Text[] skillDesc = new Text[2];
Text[] skillChip = new Text[2];
Text lvText;
Text expText;
RectTransform expBar;
Button levelBtn;
Button promoteBtn;
Text shardText;
RectTransform shardBar;
Button evolveBtn;
Button skillBtn;
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);
}
public override void Build()
{
Tab = 0;
Header("영웅", "레벨 · 승급 · 진화 · 스킬", true);
var body = Body();
// ① 카드: 전투력 · 일러 · 장비 6칸 · 이름 띠
var card = UiKit.TopBand("Card", body, 16f, 720f, 24f, 24f);
var cimg = UiKit.Paint(card, UiKit.Paper);
UiKit.Border(cimg, UiKit.Line, 3f);
UiKit.Dot("Halo", card, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0f, -100f), 500f, new Color(0.93f, 0.9f, 0.84f));
power = UiKit.Label(card, "", 44, UiKit.Ink, TextAnchor.MiddleCenter, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0f, -16f), new Vector2(560f, 70f));
UiKit.Btn("Prev", card, "◀", 40, UiKit.Dark, UiKit.White, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(20f, -16f), new Vector2(96f, 72f), () => Step(-1));
UiKit.Btn("Next", card, "▶", 40, UiKit.Dark, UiKit.White, new Vector2(1f, 1f), new Vector2(1f, 1f), new Vector2(-20f, -16f), new Vector2(96f, 72f), () => Step(1));
art = UiKit.Rect("Art", card, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0f, -96f), new Vector2(560f, 500f));
for (int i = 0; i < 6; i++)
{
int k = i;
bool left = i < 3;
int row = i % 3;
var a = left ? new Vector2(0f, 1f) : new Vector2(1f, 1f);
var b = UiKit.Btn("Slot" + i, card, "", 24, UiKit.Slot, UiKit.Ink, a, a, new Vector2(left ? 22f : -22f, -104f - row * 172f), new Vector2(196f, 156f), () => OnSlot(k));
slotImg[i] = b.GetComponent<Image>();
UiKit.LabelOf(b).text = "";
slotName[i] = UiKit.Label(b.transform, "", 30, UiKit.Ink, TextAnchor.MiddleCenter, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0f, -12f), new Vector2(186f, 84f));
slotState[i] = UiKit.Label(b.transform, "", 24, UiKit.InkSoft, TextAnchor.MiddleCenter, new Vector2(0.5f, 0f), new Vector2(0.5f, 0f), new Vector2(0f, 10f), new Vector2(186f, 44f), false);
}
var band = UiKit.Rect("NameBand", card, new Vector2(0.5f, 0f), new Vector2(0.5f, 0f), Vector2.zero, new Vector2(0f, 116f));
band.anchorMin = new Vector2(0f, 0f);
band.anchorMax = new Vector2(1f, 0f);
band.offsetMin = new Vector2(0f, 0f);
band.offsetMax = new Vector2(0f, 116f);
UiKit.Paint(band, UiKit.Dark);
typeDot = UiKit.Dot("TypeDot", band, new Vector2(0f, 0.5f), new Vector2(0f, 0.5f), new Vector2(24f, 0f), 80f, UiKit.Red);
typeMark = UiKit.FillLabel(typeDot.transform, "", 40, UiKit.White);
nameText = UiKit.Label(band, "", 60, UiKit.White, TextAnchor.MiddleLeft, new Vector2(0f, 0.5f), new Vector2(0f, 0.5f), new Vector2(124f, 4f), new Vector2(300f, 90f));
nameText.horizontalOverflow = HorizontalWrapMode.Overflow;
subText = UiKit.Label(band, "", 28, new Color(0.85f, 0.8f, 0.75f), TextAnchor.MiddleLeft, new Vector2(0f, 0.5f), new Vector2(0f, 0.5f), new Vector2(420f, 0f), new Vector2(330f, 80f), false);
starText = UiKit.Label(band, "", 52, UiKit.Star, TextAnchor.MiddleRight, new Vector2(1f, 0.5f), new Vector2(1f, 0.5f), new Vector2(-24f, 0f), new Vector2(300f, 80f));
// ② 스킬 정보
var skill = UiKit.TopBand("Skill", body, 752f, 400f, 24f, 24f);
var simg = UiKit.Paint(skill, UiKit.Paper);
UiKit.Border(simg, UiKit.Line, 3f);
UiKit.Label(skill, "스킬", 40, UiKit.Ink, TextAnchor.MiddleLeft, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(28f, -14f), new Vector2(300f, 60f));
UiKit.Label(skill, "액티브 1 · 패시브 1", 26, UiKit.InkSoft, TextAnchor.MiddleRight, new Vector2(1f, 1f), new Vector2(1f, 1f), new Vector2(-28f, -14f), new Vector2(400f, 60f), false);
for (int i = 0; i < 2; i++)
{
var c = UiKit.TopBand("Skill" + i, skill, 86f + i * 152f, 140f, 20f, 20f);
var ci = UiKit.Paint(c, new Color(0.98f, 0.96f, 0.9f));
UiKit.Border(ci, UiKit.Line, 2f);
var d = UiKit.Dot("Kind", c, new Vector2(0f, 0.5f), new Vector2(0f, 0.5f), new Vector2(18f, 0f), 92f, i == 0 ? UiKit.Red : UiKit.Dark);
UiKit.FillLabel(d.transform, i == 0 ? "액" : "패", 40, UiKit.White);
skillName[i] = UiKit.Label(c, "", 34, UiKit.Ink, TextAnchor.MiddleLeft, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(128f, -8f), new Vector2(560f, 56f));
skillName[i].horizontalOverflow = HorizontalWrapMode.Overflow;
skillDesc[i] = UiKit.Label(c, "", 26, UiKit.InkSoft, TextAnchor.UpperLeft, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(128f, -64f), new Vector2(840f, 72f), false);
var chip = UiKit.Box("Chip", c, new Vector2(1f, 1f), new Vector2(1f, 1f), new Vector2(-14f, -12f), new Vector2(240f, 46f), i == 0 ? UiKit.Red : UiKit.Dark);
skillChip[i] = UiKit.FillLabel(chip.transform, "", 24, UiKit.White);
}
// ③ 레벨 · 승급
var lvRow = UiKit.TopBand("Level", body, 1168f, 110f, 24f, 24f);
lvText = UiKit.Label(lvRow, "", 42, UiKit.Ink, TextAnchor.MiddleLeft, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(4f, 0f), new Vector2(330f, 60f));
lvText.horizontalOverflow = HorizontalWrapMode.Overflow;
expText = UiKit.Label(lvRow, "", 28, UiKit.Ink, TextAnchor.MiddleRight, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(330f, 0f), new Vector2(230f, 60f));
expBar = UiKit.Bar("ExpBar", lvRow, new Vector2(0f, 0f), new Vector2(0f, 0f), new Vector2(4f, 10f), new Vector2(556f, 30f), new Color(0.86f, 0.82f, 0.75f), new Color(0.47f, 0.38f, 0.32f));
levelBtn = UiKit.Btn("LevelUp", lvRow, "", 30, UiKit.Red, UiKit.White, new Vector2(1f, 0.5f), new Vector2(1f, 0.5f), new Vector2(-252f, 0f), new Vector2(204f, 106f), OnLevelUp);
promoteBtn = UiKit.Btn("Promote", lvRow, "", 30, UiKit.Disabled, UiKit.White, new Vector2(1f, 0.5f), new Vector2(1f, 0.5f), new Vector2(0f, 0f), new Vector2(236f, 106f), OnPromote);
// ④ 조각 · 진화
var shRow = UiKit.TopBand("Shard", body, 1290f, 96f, 24f, 24f);
var sd = UiKit.Dot("ShardDot", shRow, new Vector2(0f, 0.5f), new Vector2(0f, 0.5f), new Vector2(0f, -14f), 54f, UiKit.Purple);
UiKit.FillLabel(sd.transform, "조", 28, UiKit.White);
UiKit.Label(shRow, "영웅 조각", 32, UiKit.Ink, TextAnchor.MiddleLeft, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(64f, 0f), new Vector2(300f, 46f));
shardBar = UiKit.Bar("ShardBar", shRow, new Vector2(0f, 0f), new Vector2(0f, 0f), new Vector2(64f, 4f), new Vector2(690f, 42f), new Color(0.86f, 0.82f, 0.75f), UiKit.Purple);
shardText = UiKit.Label(shardBar.parent, "", 28, UiKit.Ink, TextAnchor.MiddleCenter, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), Vector2.zero, new Vector2(680f, 42f));
evolveBtn = UiKit.Btn("Evolve", shRow, "", 30, UiKit.Red, UiKit.White, new Vector2(1f, 0.5f), new Vector2(1f, 0.5f), new Vector2(0f, 0f), new Vector2(236f, 96f), OnEvolve);
// ⑤ 상세정보 · 도감 · 스킬 레벨업(B)
var btnRow = UiKit.TopBand("Buttons", body, 1402f, 96f, 24f, 24f);
float bw = (1032f - 40f) / 3f;
UiKit.Btn("Detail", btnRow, "상세정보", 36, UiKit.Dark, UiKit.White, new Vector2(0f, 0.5f), new Vector2(0f, 0.5f), Vector2.zero, new Vector2(bw, 96f), ShowStats);
UiKit.Btn("Codex", btnRow, "도감", 36, UiKit.Dark, UiKit.White, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), Vector2.zero, new Vector2(bw, 96f), () => ShowCodex(Root));
skillBtn = UiKit.Btn("SkillUp", btnRow, "스킬 레벨업", 32, UiKit.Red, UiKit.White, new Vector2(1f, 0.5f), new Vector2(1f, 0.5f), Vector2.zero, new Vector2(bw, 96f), OnSkillUp);
}
void Step(int d)
{
if (order.Count == 0) return;
int i = Mathf.Max(0, order.IndexOf(id));
id = order[(i + d + order.Count) % order.Count];
Refresh();
}
public override void Refresh()
{
var h = S.Def(id);
if (h == null) return;
var db = S.Db;
var lv = S.Save.Level(id);
var hs = S.Save.Hero(id);
var st = S.StatsOf(id);
power.text = "전투력 " + st.power.ToString("N0");
UiKit.Clear(art);
UiKit.Portrait("Hero", art, h, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), Vector2.zero, new Vector2(560f, 500f), false, 1f, new Color(1f, 1f, 1f, 0f));
for (int i = 0; i < 6; i++)
{
string need = h.isSoldier ? null : HeroRules.RequiredGear(db, h, hs, i);
var g = db.Gear.Get(need);
bool on = hs != null && i < hs.gear.Count && !string.IsNullOrEmpty(hs.gear[i]);
int have = need != null ? S.Save.inv.GearCount(need) : 0;
slotImg[i].gameObject.SetActive(need != null);
if (need == null) continue;
slotName[i].text = g != null ? g.nameKo : need;
if (on)
{
slotImg[i].color = new Color(0.9f, 0.95f, 0.86f);
slotState[i].text = "<color=#3a6a30>○ 장착</color> · " + UiKit.GradeKo(g != null ? g.grade : "");
}
else if (have > 0)
{
slotImg[i].color = new Color(1f, 0.93f, 0.86f);
slotState[i].text = "<color=#a03a22>탭하여 장착 ×" + have + "</color>";
}
else
{
slotImg[i].color = UiKit.Slot;
slotState[i].text = "없음 · " + UiKit.GradeKo(g != null ? g.grade : "");
}
}
typeDot.color = UiKit.TypeColor(h.type);
typeMark.text = UnitTypeInfo.Mark(h.type);
nameText.text = h.nameKo;
subText.text = UnitTypeInfo.Korean(h.type) + " · " + (h.isSoldier ? "병사 유닛" : UiKit.GradeKo(hs.grade) + " 등급");
starText.text = h.isSoldier ? UiKit.Stars(h.rarity, 3) : UiKit.Stars(hs.star, db.Evolve.MaxStar);
var skills = new[] { db.Skills.Get(h.skillActive), db.Skills.Get(h.skillPassive) };
for (int i = 0; i < 2; i++)
{
int cap = SkillRules.Cap(db, h, hs, i); // 등급 + ★3 액티브 +1(PD #1093 B)
var sk = skills[i];
if (sk == null)
{
skillName[i].text = h.isSoldier ? "병사 유닛 — 스킬 없음" : "—";
skillDesc[i].text = "";
skillChip[i].transform.parent.gameObject.SetActive(false);
continue;
}
skillChip[i].transform.parent.gameObject.SetActive(true);
skillName[i].text = sk.nameKo + (string.IsNullOrEmpty(sk.hanja) ? "" : "(" + sk.hanja + ")") + " · " + (sk.kind == "active" ? "액티브" : "패시브");
skillDesc[i].text = SkillInfoDb.DisplayDesc(sk);
int slv = hs != null && hs.skillLv != null && hs.skillLv.Length > i ? hs.skillLv[i] : 1;
skillChip[i].text = "Lv " + slv + "/" + cap + (sk.kind == "active" ? " · 쿨 " + sk.cooldown + "턴" : (hs != null && SkillRules.PassiveMult(db, hs.star) > 1f ? " · ★×" + SkillRules.PassiveMult(db, hs.star).ToString("0.##") : ""));
}
bool canSkill = !h.isSoldier && hs != null && (SkillRules.CanLevelUp(db, S.Save, h, hs, 0) == null || SkillRules.CanLevelUp(db, S.Save, h, hs, 1) == null);
UiKit.LabelOf(skillBtn).text = "스킬 레벨업\n<size=22>" + (h.isSoldier ? "병사 = 스킬 없음" : "스킬서 " + S.Save.inv.books.skill) + "</size>";
skillBtn.GetComponent<Image>().color = canSkill ? UiKit.Red : UiKit.Disabled;
int lvCap = HeroRules.LevelCap(db, S.Save);
var row = db.Levels.Get(lv.lv);
lvText.text = "Lv " + lv.lv + " / " + lvCap + (lvCap < db.Levels.MaxLevel ? "" : "");
float pct = row != null && row.expToNext > 0 ? lv.exp / (float)row.expToNext : 1f;
expText.text = lv.lv >= db.Levels.MaxLevel ? "최고 레벨" : pct >= 1f ? "경험치 100% ↑" : "경험치 " + (pct * 100f).ToString("0.00") + "%";
UiKit.SetBar(expBar, pct);
var lvWhy = HeroRules.CanLevelUp(db, S.Save, lv);
UiKit.LabelOf(levelBtn).text = "레벨업\n<size=24>" + (row != null && lv.lv < db.Levels.MaxLevel ? "골드 " + row.goldCost.ToString("N0") : "최고") + "</size>";
levelBtn.GetComponent<Image>().color = lvWhy == null ? UiKit.Red : UiKit.Disabled;
var promoWhy = HeroRules.CanPromote(db, h, hs);
var gearList = h.isSoldier ? null : db.Heroes.GearFor(h, hs.grade);
UiKit.LabelOf(promoteBtn).text = h.isSoldier ? "승급\n<size=24>병사 없음</size>"
: gearList == null ? "승급\n<size=24>최고 등급</size>"
: "승급\n<size=24>장비 " + HeroRules.EquippedCount(hs) + "/" + gearList.Count + "칸</size>";
promoteBtn.GetComponent<Image>().color = promoWhy == null ? UiKit.Red : UiKit.Disabled;
int need2 = HeroRules.ShardsForNext(db, hs);
if (h.isSoldier)
{
shardText.text = "병사 유닛 — 진화 없음 (중복 = 골드)";
UiKit.SetBar(shardBar, 0f);
UiKit.LabelOf(evolveBtn).text = "진화\n<size=24>없음</size>";
evolveBtn.GetComponent<Image>().color = UiKit.Disabled;
}
else
{
shardText.text = need2 > 0 ? hs.shards + " / " + need2 : hs.shards + " · 최고 ★";
UiKit.SetBar(shardBar, need2 > 0 ? hs.shards / (float)need2 : 1f);
UiKit.LabelOf(evolveBtn).text = hs.star >= db.Evolve.MaxStar ? "진화\n<size=24>최고 ★</size>" : "진화\n<size=24>다음 ★" + (hs.star + 1) + "</size>";
evolveBtn.GetComponent<Image>().color = HeroRules.CanEvolve(db, h, hs) == null ? UiKit.Red : UiKit.Disabled;
}
}
void OnSlot(int i)
{
var h = S.Def(id);
var hs = S.Save.Hero(id);
if (h == null || hs == null) return;
var need = HeroRules.RequiredGear(S.Db, h, hs, i);
var g = S.Db.Gear.Get(need);
if (need == null) return;
if (!string.IsNullOrEmpty(hs.gear[i]))
{
Root.Toast("장착됨: " + (g != null ? g.nameKo : need) + " — 6칸을 모두 채우면 승급");
return;
}
var why = S.Equip(id, i);
if (why == null)
{
Root.Toast((g != null ? g.nameKo : need) + " 장착 · 1칸 = 1강(누적 " + hs.gearTotal + ")");
return;
}
string from = g != null ? g.dropFromChapter + "장~ 스테이지 드랍" : "";
Root.Modal("필요 장비", (g != null ? g.nameKo + " (" + UiKit.GradeKo(g.grade) + " 등급)" : need) + "\n보유 0\n\n획득: " + from + " · 거래 > 상점(흰/녹)" +
(g != null && g.craftCount > 0 ? "\n합성 = 하위 " + g.craftCount + "개 + 도면 " + g.craftBlueprint + " (2차)" : ""),
new OutGameRoot.ModalButton("상점 가기", UiKit.Red, () => Root.Trade.OpenShop()),
new OutGameRoot.ModalButton("닫기", UiKit.Dark, null));
}
void OnLevelUp()
{
var why = S.LevelUp(id);
Root.Toast(why ?? S.Def(id).nameKo + " Lv " + S.Save.Level(id).lv + "!");
}
void OnPromote()
{
var h = S.Def(id);
var why = S.Promote(id);
Root.Toast(why ?? h.nameKo + " 승급 → " + UiKit.GradeKo(S.Save.Hero(id).grade) + " 등급 · 새 장비 6칸");
}
/// <summary>스킬 레벨업(PD #1093 B): 액티브·패시브 중 고르기 → 스킬서 + 골드(skill_levels.csv) · 상한 = 등급 + ★3 액티브 +1.</summary>
public void OnSkillUp()
{
var h = S.Def(id);
var hs = S.Save.Hero(id);
if (h == null || hs == null || h.isSoldier)
{
Root.Toast("병사 유닛은 스킬이 없습니다");
return;
}
var db = S.Db;
var buttons = new List<OutGameRoot.ModalButton>();
var body = new System.Text.StringBuilder("보유 스킬서 " + S.Save.inv.books.skill + " · 골드 " + S.Save.gold.ToString("N0") + "\n");
for (int i = 0; i < 2; i++)
{
int k = i;
var sk = SkillRules.Skill(db, h, i);
if (sk == null) continue;
int lv = SkillRules.Level(hs, i);
var cost = db.Skills.CostTo(lv + 1);
var why = SkillRules.CanLevelUp(db, S.Save, h, hs, i);
body.Append("\n").Append(i == 0 ? "액티브 " : "패시브 ").Append(sk.nameKo).Append(" Lv ").Append(lv).Append(" / ").Append(SkillRules.Cap(db, h, hs, i));
if (cost != null && lv < sk.lvMax) body.Append(" → 스킬서 ").Append(cost.books).Append(" · 골드 ").Append(cost.gold.ToString("N0"));
if (why != null) body.Append("\n <color=#a03a22>").Append(why).Append("</color>");
buttons.Add(new OutGameRoot.ModalButton((i == 0 ? "액티브" : "패시브") + " Lv+1", why == null ? UiKit.Red : UiKit.Disabled, () =>
{
var r = SkillRules.LevelUp(S.Db, S.Save, h, hs, k);
if (r == null) S.Commit();
Refresh();
if (r == null) OnSkillUp(); // 이어서 올릴 수 있게 다시 연다
Root.Toast(r ?? sk.nameKo + " Lv " + SkillRules.Level(hs, k) + "!");
}));
}
buttons.Add(new OutGameRoot.ModalButton("닫기", UiKit.Dark, null));
Root.Modal("스킬 레벨업 — " + h.nameKo, body.ToString(), buttons.ToArray());
}
void OnEvolve()
{
var why = S.Evolve(id);
Root.Toast(why ?? S.Def(id).nameKo + " 진화 → ★" + S.Save.Hero(id).star);
}
void ShowStats()
{
var h = S.Def(id);
var st = S.StatsOf(id);
var e = S.Db.Economy;
var hs = S.Save.Hero(id);
string body =
"기본(" + UnitTypeInfo.Korean(h.type) + ") HP " + st.baseHp + " · 공 " + st.baseAtk + " · 방 " + st.baseDef + "\n" +
"영웅 배율 ×" + st.hpMult + " · ×" + st.atkMult + " · ×" + st.defMult + "\n" +
"레벨 Lv " + S.Save.Level(id).lv + " +" + st.lvPct.ToString("0.#") + "%\n" +
"승급 " + (hs != null ? UiKit.GradeKo(hs.grade) : "—") + " +" + st.promoPct.ToString("0.#") + "% · 장비 누적 " + (hs != null ? hs.gearTotal : 0) + "개 +" + st.gearPct.ToString("0.#") + "%\n" +
"진화 " + (hs != null ? "★" + hs.star : "—") + " +" + st.starPct.ToString("0.#") + "%\n" +
"훈련(내정 · 2차) +" + st.trainPct.ToString("0.#") + "%\n\n" +
"<size=40>HP " + st.Hp + " · 공 " + st.Atk + " · 방 " + st.Def + "</size>\n" +
"전투력 " + st.power.ToString("N0") + " = HP/" + e.PowerHpDiv + " + 공×" + e.PowerAtkW + " + 방×" + e.PowerDefW;
Root.Modal("상세정보 — " + h.nameKo, body, new OutGameRoot.ModalButton("닫기", UiKit.Dark, null));
}
/// <summary>도감 = 전 영웅·병사(미보유 회색).</summary>
public static void ShowCodex(OutGameRoot root)
{
var s = root.Session;
int owned = 0;
foreach (var h in s.Db.Heroes.heroes)
if (s.Save.Owns(h.id)) owned++;
var content = root.ModalCustom("도감 " + owned + " / " + s.Db.Heroes.heroes.Count, 1560f, new OutGameRoot.ModalButton("닫기", UiKit.Dark, null));
ScrollRect sr;
var grid = UiKit.ScrollGrid("Codex", content, 0f, 0f, 0f, 0f, new Vector2(420f, 140f), new Vector2(20f, 14f), 2, out sr);
foreach (var h in s.Db.Heroes.heroes)
{
bool own = s.Save.Owns(h.id);
var hero = h;
var cell = HeroCards.Card(grid, s, h, false, own, () => root.Toast(hero.nameKo + (string.IsNullOrEmpty(hero.hanja) ? "" : "(" + hero.hanja + ")") + " · " +
UnitTypeInfo.Korean(hero.type) + " · ★" + hero.rarity + (hero.isSoldier ? " · 병사 유닛" : "") + (own ? " · 보유" : " · 미보유 — 거래 > 뽑기")));
if (!own) cell.color = new Color(0.78f, 0.76f, 0.73f);
}
}
}
}