using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
namespace TKS.OutGame
{
/// 아웃게임 화면 1장(본영 로비 · 영웅 · 편성 · 거래). OutGameRoot 가 만들고 전환한다.
public abstract class OutGameScreen
{
public OutGameRoot Root;
public RectTransform Rt;
/// 하단 탭 강조(0 영웅 · 4 거래 · −1 없음).
public int Tab = -1;
public OutGameSession S
{
get { return Root.Session; }
}
public abstract void Build();
public virtual void Refresh() { }
public virtual void OnShow() { }
/// 뒤로 가기를 화면 안에서 처리했으면 true.
public virtual bool OnBack() { return false; }
/// 제목 띠(재화 바 아래) · back = 「◀」 버튼.
protected void Header(string title, string sub, bool back)
{
var band = UiKit.TopBand("Header", Rt, OutGameRoot.TopBarH, OutGameRoot.HeaderH);
UiKit.Paint(band, UiKit.Header, false);
float x = 36f;
if (back)
{
UiKit.Btn("Back", band, "◀", 44, UiKit.Dark, UiKit.White, new Vector2(0f, 0.5f), new Vector2(0f, 0.5f), new Vector2(24f, 0f), new Vector2(100f, 76f), () => Root.Back());
x = 146f;
}
var t = UiKit.Label(band, title, 52, UiKit.Ink, TextAnchor.MiddleLeft, new Vector2(0f, 0.5f), new Vector2(0f, 0.5f), new Vector2(x, 0f), new Vector2(360f, 90f));
t.horizontalOverflow = HorizontalWrapMode.Overflow;
UiKit.Label(band, sub, 30, UiKit.InkSoft, TextAnchor.MiddleLeft, new Vector2(0f, 0.5f), new Vector2(0f, 0.5f), new Vector2(x + t.preferredWidth + 18f, -4f), new Vector2(700f, 60f), false);
}
/// 제목 띠 아래 ~ 하단 탭 위 본문.
protected RectTransform Body(string name = "Body")
{
return UiKit.Fill(name, Rt, 0f, 0f, OutGameRoot.TopBarH + OutGameRoot.HeaderH, OutGameRoot.TabBarH);
}
}
///
/// 아웃게임 루트(2026-11-05 #1093 시스템 기획 §1 · §10 A) — 게임 시작 = 본영 로비 · 출정 → 기존 챕터 월드맵 · 편성 · 영웅 · 거래 · 준비 중 팝업 ·
/// 상단 재화 바(골드 · 보옥 · 군량 n/최대 + 회복 타이머 · 월드맵에도 표시) · 하단 탭 5 · 뒤로 가기(◀ · Esc) · 전투 결과 보상 패널.
/// 데이터 = OutGameSession(표 + 세이브) · 화면은 도형 + 글자 와이어프레임(목업 img03·06·08·11 배치).
///
public class OutGameRoot : MonoBehaviour
{
public static OutGameRoot Instance { get; private set; }
public const float TopBarH = 120f;
public const float HeaderH = 104f;
public const float TabBarH = 150f;
public static readonly Vector2 Reference = new Vector2(1080f, 1920f);
public OutGameSession Session { get; private set; }
public BattleManager Battle { get; private set; }
public WorldMapScreen Map { get; private set; }
public Camera Cam { get; private set; }
BattleHUD hud;
SlingshotInput sling;
Canvas mainCanvas;
Canvas topCanvas;
Canvas resultCanvas;
public RectTransform TopRoot { get; private set; }
public LobbyScreen Lobby { get; private set; }
public HeroListScreen HeroList { get; private set; }
public HeroDetailScreen HeroDetail { get; private set; }
public FormationScreen Formation { get; private set; }
public TradeScreen Trade { get; private set; }
readonly List screens = new List();
OutGameScreen current;
RectTransform barRoot;
Text goldText;
Text gemText;
Text staminaText;
Text staminaTimer;
readonly List tabImages = new List();
readonly List tabTexts = new List();
GameObject modal;
GameObject toast;
Text toastText;
float toastUntil;
float nextTick;
BattleResultPanel result;
bool resultDone;
public OutGameScreen Current
{
get { return current; }
}
/// 아웃게임 화면(로비 등)이 보이는가(월드맵·전투 중 = false).
public bool ScreensVisible
{
get { return mainCanvas != null && mainCanvas.gameObject.activeSelf; }
}
public bool LobbyVisible
{
get { return ScreensVisible && current == Lobby; }
}
public bool ModalVisible
{
get { return modal != null; }
}
public bool ResultVisible
{
get { return result != null && result.Visible; }
}
void Awake()
{
Instance = this;
}
void OnDestroy()
{
if (Instance == this) Instance = null;
}
public void Build(BattleManager b, BattleHUD h, SlingshotInput s, WorldMapScreen wm, Camera cam)
{
Battle = b;
hud = h;
sling = s;
Map = wm;
Cam = cam;
Session = OutGameSession.Start(OutGameData.Default, b.Config);
Session.Changed += RefreshAll;
// 전투 연결: 출전 = 편성 프리셋 · 결과 = 보상
b.LineupProvider = Session.BuildLineup;
b.StageStarted += () => resultDone = false;
b.PhaseChanged += OnPhase;
// 월드맵 연결: 팝업 줄 · 군량 · 별 · 소탕 · 본영
if (wm != null)
{
wm.TopInset = TopBarH;
wm.PopupInfo = PopupInfo;
wm.TryEnter = TryEnter;
wm.StarsOf = si => EconomyRules.StarsOf(Session.Save, b.Config.stages[si]);
wm.CanSweep = si => EconomyRules.CanSweep(Session.Save, b.Config.stages[si]);
wm.Sweep = DoSweep;
wm.BackRequested = ShowLobby;
}
mainCanvas = MakeCanvas("OutGameCanvas", 350, 0.45f);
resultCanvas = MakeCanvas("BattleResultCanvas", 200, 0.8f);
topCanvas = MakeCanvas("OutGameTopCanvas", 450, 0.4f);
TopRoot = (RectTransform)topCanvas.transform;
var bg = UiKit.Fill("Bg", mainCanvas.transform);
UiKit.Paint(bg, UiKit.Bg, false, true);
Lobby = Add(new LobbyScreen());
HeroList = Add(new HeroListScreen());
HeroDetail = Add(new HeroDetailScreen());
Formation = Add(new FormationScreen());
Trade = Add(new TradeScreen());
BuildTabBar();
BuildCurrencyBar();
result = new BattleResultPanel(this, (RectTransform)resultCanvas.transform);
mainCanvas.gameObject.SetActive(false);
}
T Add(T scr) where T : OutGameScreen
{
scr.Root = this;
scr.Rt = UiKit.Fill(typeof(T).Name, mainCanvas.transform);
scr.Build();
scr.Rt.gameObject.SetActive(false);
screens.Add(scr);
return scr;
}
Canvas MakeCanvas(string name, int order, float plane)
{
var go = new GameObject(name);
go.transform.SetParent(transform, false);
var c = go.AddComponent