ThreeKingdomsSlingshot/Assets/Scripts/OutGame/Arena/ArenaScreen.cs

360 lines
21 KiB
C#
Raw Normal View History

아웃게임 2차(PD #1093 세션 C) — 내정(훈련·순찰·개발) · 보물(수집품·세트·상자) · 연무장(탑·일일 던전·투기장·적장 토벌) · 거래 상자 탭 + 영웅 56명 확장(PD #1096 · 신규 effect_key 4) - 데이터: C 표 10장(training · training_ranks · patrol · dev_tree · treasures · treasure_sets · chests(+iron/buy 열) · tower · dungeons(+reward_amount) · arena(+상점 키)) + economy.csv C 키 24 → 임포트 18 자산(OutGameTables.C.cs 검증: 행·연속 Lv/랭크/층·참조·확률 합 1·선행 노드·효과 키 처리기·카운터 키 · 오류 시 자산 불변) - 영웅 56명: heroes 71 · skills 112 · hero_gear 1344 · gacha_pool 71 재복사 · 신규 키 4(team_dmg_pct_turn · cooldown_add · charm · heal_self_pct) + 기존 키 조건 열(받는 피해 p2 HP 임계/보스/근접 · p3 출전 인원 아군 전원 · 최대 HP·반격 아군 전원 · 피해 % 발동 턴) · 대장군 키는 표 미사용(처리기 유지) - 내정: 훈련(병종 5 · 3항목 Lv · cost_mult · 랭크 승급 · train_bonus → §3-2 항목별) · 순찰(챕터 행 × 시간 · 오프라인 · 상한 12h + 농업 · 소수점 이월 · 광고 2배 스텁 · 즉시 수확 보옥) · 개발(갈래 3 · 선행 · 골드·도면 비용 · 효과 키 → 군량·보상·상점·순찰·상자 적용 지점 · 초기화 보옥 + 도면 환급) - 보물: 보유 중(4열 · 등급 색 · 상세·강화) · 세트(단계 효과) · 상자(포인트 → 명장 · 확률 · 중복 조각) · 효과 hp/atk/def → HeroRules · crit/range/splash → BattleManager.SideEffectsProvider → SkillMods · 조건 카운터 8종 = Runtime/BattleEvents(전투 코드 Raise 1줄씩 · 아군만) · 스테이지 청동 상자 10 % - 연무장: BattleManager.StartMode(BattleMode = 적 편성·제한 턴·onExit) · 탑 100층(입장권·층 배율·보상·10층 상자) · 던전 3(요일·2/일·보상) · 투기장(샘플 10 · EnemyAI 방어 · 메달·주간 순위·조각 상점) · 적장 토벌(주간 순환·hp ×20·5턴·누적 피해·명장 상자·천기) · 결과 패널 → 탭 = 연무장 - 거래: 상자 탭(구매 = 골드/보옥/포인트 · 거래 할인) · 패스·월정액·챕터 팩·첫 결제 팩 = 준비 중 스텁 · 스킬서 임시 판매 제거(사당 던전) - 테스트 87/87(기존 73 유지 · 갱신 3 = 로비 탭 · 표 키 목록 · 상점 스킬서 칸 / 신규 14 = OutGameCTests 12 + 확장 키 2) · console error 0 · 캡처 = DataImporter.CaptureC Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 15:22:54 +00:00
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
namespace TKS.OutGame
{
/// <summary>
/// 연무장(로비 출정 우측 · 기획 S13 · 목업 img09 · PD #1093 C) — 첫 페이지 = 모드 카드 4(규칙 · 보상 · 입장) → 카드 탭 = 모드 페이지:
/// ① 천하제일 탑(다음 층 · 적 템플릿 · 배율 · 보상 · 입장권 + 광고) ② 일일 던전 3(요일 · 남은 입장 · 보상) ③ 투기장(메달 · 주간 순위 · 샘플 상대 10 · 메달 상점)
/// ④ 적장 토벌(이번 주 보스 · 누적 피해 · 하루 1). 도전 = OutGameRoot.StartMode → BattleManager.StartMode(적 편성 · 배율 · 제한 턴) → 결과 패널 → 탭 = 이 페이지로.
/// </summary>
public class ArenaScreen : OutGameScreen
{
public static readonly string[] ModeNames = { "천하제일 탑", "일일 던전 3", "투기장", "적장 토벌" };
int page;
RectTransform root;
/// <summary>0 = 카드 · 1 탑 · 2 던전 · 3 투기장 · 4 적장 토벌.</summary>
public int Page
{
get { return page; }
}
public override void Build()
{
Header("연무장", "탑 · 일일 던전 · 투기장 · 적장 토벌", true);
root = Body();
}
public void SetPage(int p)
{
page = Mathf.Clamp(p, 0, 4);
Refresh();
}
public override void OnShow()
{
S.Do(() =>
{
ArenaRules.RollDaily(S.Db, S.Save, S.Now);
ArenaRules.EnsureSeason(S.Db, S.Save, S.Now, S.Rng);
ArenaRules.RaidBoss(S.Db, S.Save, S.Now);
return null;
});
}
public override bool OnBack()
{
if (page == 0) return false;
SetPage(0);
return true;
}
public override void Refresh()
{
UiKit.Clear(root);
switch (page)
{
case 0: BuildCards(); break;
case 1: BuildTower(); break;
case 2: BuildDungeons(); break;
case 3: BuildArena(); break;
case 4: BuildRaid(); break;
}
}
// ---------- 카드 4 ----------
void BuildCards()
{
var db = S.Db;
var d = S.Save;
var e = db.Economy;
var now = S.Now;
string boss = db.Heroes.Get(ArenaRules.RaidBoss(db, d, now)) != null ? db.Heroes.Get(ArenaRules.RaidBoss(db, d, now)).nameKo : "";
string[,] text =
{
{ "100층 · 층마다 고정 편성 적 · 10층마다 보스", "보옥 · 도면 · 10층마다 보물 금 상자", "입장권 하루 " + e.TowerTicketsDaily + "(광고 +" + e.TowerAdTickets + ") · 진행 저장", "다음 " + ArenaRules.TowerNext(db, d) + "층 · 입장권 " + d.arena.towerTickets },
{ "군량고(골드) · 대장간(승급 장비·운철) · 사당(스킬서·영웅 조각) — 요일 순환", "던전별 재화", "각 하루 " + (db.Dungeons.dungeons.Count > 0 ? db.Dungeons.dungeons[0].entriesPerDay : 0) + "(패스 +1 준비 중)", "오늘 열림 " + OpenCount(now) + "곳" },
{ "비동기 5v5 · 상대 편성은 AI 가 조작(적 AI 재사용) · 주간 랭킹", "투기장 메달 → 영웅 조각 상점", "하루 " + db.Arena.EntriesPerDay, "메달 " + d.arena.medals + " · " + ArenaRules.Rank(d) + "위 · 남은 " + ArenaRules.ArenaLeft(db, d, now) },
{ "주간 보스(여포·조조 …) · 누적 피해", "보물 명장 상자", "하루 " + e.RaidDaily, "이번 주 " + boss + " · 누적 " + d.arena.raidDamage.ToString("N0") },
};
float w = 508f, h = 700f;
for (int i = 0; i < 4; i++)
{
int k = i;
float x = 24f + (i % 2) * (w + 16f);
float y = -18f - (i / 2) * (h + 20f);
var card = UiKit.Btn("Card" + i, root, "", 30, UiKit.Paper, UiKit.Ink, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(x, y), new Vector2(w, h), () => SetPage(k + 1));
UiKit.Border(card.GetComponent<Image>(), UiKit.Line, 3f);
var head = UiKit.TopBand("Head", card.transform, 0f, 110f);
UiKit.Paint(head, UiKit.Red);
UiKit.FillLabel(head, ModeNames[i] + (i == 3 ? "\n<size=26>(이벤트)</size>" : ""), 44, UiKit.White);
string[] tags = { "규칙", "보상", "입장" };
for (int t = 0; t < 3; t++)
{
float ty = -128f - t * 160f;
var tag = UiKit.Box("Tag" + t, card.transform, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(20f, ty), new Vector2(96f, 44f), UiKit.Dark);
tag.raycastTarget = false;
UiKit.FillLabel(tag.transform, tags[t], 24, UiKit.White);
UiKit.Label(card.transform, text[i, t], 28, UiKit.Ink, TextAnchor.UpperLeft, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(20f, ty - 52f), new Vector2(w - 40f, 104f), false);
}
var st = UiKit.Box("Status", card.transform, new Vector2(0.5f, 0f), new Vector2(0.5f, 0f), new Vector2(0f, 16f), new Vector2(w - 32f, 70f), new Color(0.95f, 0.9f, 0.8f));
st.raycastTarget = false;
UiKit.FillLabel(st.transform, text[i, 3], 26, UiKit.Red);
}
}
int OpenCount(System.DateTime now)
{
int n = 0;
foreach (var dg in S.Db.Dungeons.dungeons)
if (ArenaRules.OpenToday(dg, now)) n++;
return n;
}
RectTransform Panel(string name, float top, float h)
{
var band = UiKit.TopBand(name, root, top, h, 24f, 24f);
var img = UiKit.Paint(band, UiKit.Paper);
UiKit.Border(img, UiKit.Line, 3f);
return band;
}
void Title(string t)
{
var band = UiKit.TopBand("Title", root, 12f, 96f, 24f, 24f);
UiKit.Paint(band, UiKit.Red);
UiKit.FillLabel(band, t, 48, UiKit.White);
}
// ---------- ① 천하제일 탑 ----------
void BuildTower()
{
var db = S.Db;
var d = S.Save;
Title("천하제일 탑");
int next = ArenaRules.TowerNext(db, d);
var f = db.Tower.Get(next);
var stage = ArenaRules.TowerStage(db, Root.Battle.Config, next);
var info = Panel("Floor", 124f, 520f);
UiKit.Label(info, next + "층", 110, UiKit.Ink, TextAnchor.MiddleCenter, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0f, -20f), new Vector2(600f, 140f));
var sb = new System.Text.StringBuilder();
sb.Append("클리어 최고 ").Append(d.arena.towerFloor).Append("층 / ").Append(db.Tower.Top).Append("층\n");
if (f != null)
{
sb.Append("적 편성 = ").Append(f.templateStage).Append(stage != null ? " 「" + stage.subtitle + "」 · " + stage.enemies.Count + "기" : " (템플릿 없음)").Append("\n");
sb.Append("적 HP ×").Append(f.hpMult.ToString("0.00")).Append(" · 공격 ×").Append(f.atkMult.ToString("0.00")).Append("\n");
sb.Append("보상 보옥 ").Append(f.rewardGem).Append(" · 도면 ").Append(f.rewardBlueprint);
if (f.chest.Length > 0) sb.Append(" · ").Append(db.Chests.Get(f.chest).nameKo);
}
UiKit.Label(info, sb.ToString(), 34, UiKit.Ink, TextAnchor.UpperCenter, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0f, -180f), new Vector2(980f, 320f), false).lineSpacing = 1.2f;
var tk = Panel("Tickets", 664f, 150f);
UiKit.Label(tk, "입장권 " + d.arena.towerTickets + " <size=28>(매일 " + db.Economy.TowerTicketsDaily + "장까지 채움 · 입장 = 1장)</size>", 40, UiKit.Ink, TextAnchor.MiddleLeft, new Vector2(0f, 0.5f), new Vector2(0f, 0.5f), new Vector2(24f, 0f), new Vector2(720f, 80f));
var ad = UiKit.Btn("Ad", tk, "광고 +" + db.Economy.TowerAdTickets + "\n<size=24>(시험 · " + d.dailyC.towerAd + "/1)</size>", 32, UiKit.Grain, UiKit.White, new Vector2(1f, 0.5f), new Vector2(1f, 0.5f), new Vector2(-16f, 0f), new Vector2(240f, 110f), () =>
Root.Toast(S.Do(() => ArenaRules.TowerAd(S.Db, S.Save, S.Now)) ?? "입장권 +" + S.Db.Economy.TowerAdTickets + " (광고 SDK 미연동 · 시험 지급)"));
ad.interactable = d.dailyC.towerAd < 1;
var why = ArenaRules.CanTower(db, d, S.Now);
if (stage == null && why == null) why = "템플릿 스테이지 없음";
var go = UiKit.Btn("Go", root, why == null ? "도전 — " + next + "층" : why, 48, why == null ? UiKit.Red : UiKit.Disabled, UiKit.White, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0f, -840f), new Vector2(1032f, 150f), () =>
{
var w = S.Do(() => ArenaRules.EnterTower(S.Db, S.Save, S.Now));
if (w != null)
{
Root.Toast(w);
return;
}
Root.StartMode(ArenaRules.Tower, "", next, ArenaRules.TowerStage(S.Db, Root.Battle.Config, next), 0, 1);
});
go.interactable = why == null;
UiKit.Label(root, "진행 저장 · 패배해도 층 유지(입장권만 소모)", 28, UiKit.InkSoft, TextAnchor.MiddleCenter, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0f, -1010f), new Vector2(1000f, 50f), false);
}
// ---------- ② 일일 던전 ----------
void BuildDungeons()
{
var db = S.Db;
var d = S.Save;
var now = S.Now;
Title("일일 던전");
var today = DungeonDb.Weekdays[(int)now.ToLocalTime().DayOfWeek];
UiKit.Label(root, "오늘 = " + DayKo(today) + "요일 · 요일 순환 · 승리 시 입장 1회 소모", 30, UiKit.InkSoft, TextAnchor.MiddleCenter, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0f, -116f), new Vector2(1000f, 50f), false);
for (int i = 0; i < db.Dungeons.dungeons.Count; i++)
{
var dg = db.Dungeons.dungeons[i];
bool open = ArenaRules.OpenToday(dg, now);
int left = ArenaRules.DungeonLeft(db, d, dg, now);
var box = Panel("Dungeon_" + dg.id, 180f + i * 330f, 310f);
box.GetComponent<Image>().color = open ? UiKit.Paper : new Color(0.88f, 0.85f, 0.8f);
UiKit.Label(box, dg.nameKo, 52, UiKit.Ink, TextAnchor.MiddleLeft, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(28f, -16f), new Vector2(400f, 76f));
var days = new List<string>();
foreach (var w in dg.weekdays) days.Add(w == today ? "<color=#b0301e>" + DayKo(w) + "</color>" : DayKo(w));
UiKit.Label(box, "요일 " + string.Join(" · ", days.ToArray()), 30, UiKit.Ink, TextAnchor.MiddleLeft, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(28f, -100f), new Vector2(600f, 50f), false);
var rw = new List<string>();
foreach (var k in dg.rewardKinds) rw.Add(RewardKo(k) + " " + dg.Amount(k));
UiKit.Label(box, "보상 " + string.Join(" · ", rw.ToArray()), 30, UiKit.Ink, TextAnchor.MiddleLeft, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(28f, -152f), new Vector2(640f, 50f), false);
UiKit.Label(box, "적 = " + dg.templateStage + " 편성 · HP ×" + dg.hpMult.ToString("0.0#"), 28, UiKit.InkSoft, TextAnchor.MiddleLeft, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(28f, -204f), new Vector2(640f, 50f), false);
string id = dg.id;
var why = ArenaRules.CanDungeon(db, d, id, now);
var b = UiKit.Btn("Go", box, open ? "입장\n<size=26>남은 " + left + "/" + dg.entriesPerDay + "</size>" : "닫힘", 40, why == null ? UiKit.Red : UiKit.Disabled, UiKit.White, new Vector2(1f, 0.5f), new Vector2(1f, 0.5f), new Vector2(-24f, 0f), new Vector2(300f, 170f), () =>
{
var w = ArenaRules.CanDungeon(S.Db, S.Save, id, S.Now);
if (w != null)
{
Root.Toast(w);
return;
}
Root.StartMode(ArenaRules.Dungeon, id, 0, ArenaRules.DungeonStage(S.Db, Root.Battle.Config, id), 0, 2);
});
b.interactable = why == null;
}
}
static string DayKo(string w)
{
switch (w)
{
case "sun": return "일";
case "mon": return "월";
case "tue": return "화";
case "wed": return "수";
case "thu": return "목";
case "fri": return "금";
case "sat": return "토";
}
return w;
}
static string RewardKo(string k)
{
switch (k)
{
case "gold": return "골드";
case "gear": return "승급 장비";
case "iron": return "운철";
case "skill_book": return "스킬서";
case "shards": return "영웅 조각";
}
return k;
}
// ---------- ③ 투기장 ----------
void BuildArena()
{
var db = S.Db;
var d = S.Save;
var now = S.Now;
Title("투기장");
var me = Panel("Me", 124f, 200f);
int left = ArenaRules.ArenaLeft(db, d, now);
UiKit.Label(me, "메달 " + d.arena.medals + " · 주간 점수 " + d.arena.seasonScore + " · " + ArenaRules.Rank(d) + "위 / " + (d.arena.samples.Count + 1), 36, UiKit.Ink, TextAnchor.MiddleLeft, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(24f, -14f), new Vector2(980f, 56f));
var start = SaveStore.ParseIso(d.arena.seasonStart, now);
int daysLeft = Mathf.Max(0, db.Arena.SeasonDays - (int)(now - start).TotalDays);
UiKit.Label(me, "전적 " + d.arena.wins + "승 " + d.arena.losses + "패 · 오늘 남은 도전 " + left + "/" + db.Arena.EntriesPerDay + " · 시즌 " + daysLeft + "일 남음 · 승 +" + db.Arena.MedalWin + " / 패 +" + db.Arena.MedalLose + "\n" +
"<size=26>순위 보상 1~10위 보옥 " + db.Arena.RewardTop10Gem + " · 그 밖 " + db.Arena.RewardTop100Gem + (d.arena.lastSeason.Length > 0 ? " · " + d.arena.lastSeason : "") + "</size>",
30, UiKit.InkSoft, TextAnchor.UpperLeft, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(24f, -76f), new Vector2(980f, 110f), false);
UiKit.Btn("Shop", me, "메달 상점", 30, UiKit.Jade, UiKit.White, new Vector2(1f, 1f), new Vector2(1f, 1f), new Vector2(-16f, -12f), new Vector2(200f, 60f), MedalShop);
ScrollRect sr;
var list = UiKit.ScrollGrid("Opponents", root, 24f, 24f, 344f, 16f, new Vector2(1032f, 130f), new Vector2(0f, 12f), 1, out sr);
for (int i = 0; i < d.arena.samples.Count; i++)
{
var s = d.arena.samples[i];
int k = i;
var cell = UiKit.Cell(list, "Opp" + i, UiKit.Paper, null);
UiKit.Border(cell, UiKit.Line, 2f);
int power = 0;
for (int j = 0; j < s.heroes.Count; j++)
{
var h = db.Heroes.Get(s.heroes[j]);
if (h == null) continue;
power += HeroRules.Compute(db, Root.Battle.Config, h, new HeroState { id = h.id, lv = s.lv, grade = db.Promotion.FirstGrade, star = Mathf.Clamp(h.rarity, 1, db.Evolve.MaxStar) }).power;
UiKit.Portrait("H" + j, cell.transform, h, new Vector2(0f, 0.5f), new Vector2(0f, 0.5f), new Vector2(16f + j * 92f, 0f), new Vector2(84f, 104f), false, 1.8f, new Color(0.9f, 0.86f, 0.8f));
}
UiKit.Label(cell.transform, s.name + "\n<size=26>전투력 " + power.ToString("N0") + " · 점수 " + s.score + "</size>", 30, UiKit.Ink, TextAnchor.MiddleLeft, new Vector2(0f, 0.5f), new Vector2(0f, 0.5f), new Vector2(490f, 0f), new Vector2(330f, 110f));
var why = ArenaRules.CanArena(db, d, k, now);
var b = UiKit.Btn("Go", cell.transform, "도전", 34, why == null ? UiKit.Red : UiKit.Disabled, UiKit.White, new Vector2(1f, 0.5f), new Vector2(1f, 0.5f), new Vector2(-16f, 0f), new Vector2(180f, 96f), () =>
{
var w = ArenaRules.CanArena(S.Db, S.Save, k, S.Now);
if (w != null)
{
Root.Toast(w);
return;
}
Root.StartMode(ArenaRules.Arena, "", k, ArenaRules.ArenaStage(S.Db, Root.Battle.Config, S.Save.arena.samples[k]), 0, 3);
});
b.interactable = why == null;
}
}
public void MedalShop()
{
var db = S.Db;
var d = S.Save;
var content = Root.ModalCustom("메달 상점 — 영웅 조각", 1500f, new OutGameRoot.ModalButton("닫기", UiKit.Dark, null));
UiKit.Label(content, "메달 " + d.arena.medals + " · " + db.Arena.ShopPrice + "메달 = 조각 " + db.Arena.ShopShards + " · 오늘 " + d.dailyC.arenaShop + "/" + db.Arena.ShopDaily, 30, UiKit.Ink, TextAnchor.MiddleCenter,
new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), Vector2.zero, new Vector2(860f, 50f));
ScrollRect sr;
var grid = UiKit.ScrollGrid("Heroes", content, 0f, 0f, 60f, 0f, new Vector2(200f, 260f), new Vector2(12f, 12f), 4, out sr);
foreach (var hs in d.heroes)
{
var h = db.Heroes.Get(hs.id);
if (h == null) continue;
string id = h.id;
var cell = UiKit.Cell(grid, "Buy_" + id, UiKit.Paper, () =>
{
var w = S.Do(() => ArenaRules.BuyShards(S.Db, S.Save, id, S.Now));
Root.Toast(w ?? h.nameKo + " 조각 +" + S.Db.Arena.ShopShards);
if (w == null) MedalShop();
});
UiKit.Portrait("Face", cell.transform, h, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0f, -8f), new Vector2(150f, 150f), false, 1.8f, new Color(0.9f, 0.86f, 0.8f));
UiKit.Label(cell.transform, h.nameKo + "\n<size=22>조각 " + hs.shards + " · ★" + hs.star + "</size>", 26, UiKit.Ink, TextAnchor.MiddleCenter, new Vector2(0.5f, 0f), new Vector2(0.5f, 0f), new Vector2(0f, 8f), new Vector2(190f, 90f));
}
}
// ---------- ④ 적장 토벌 ----------
void BuildRaid()
{
var db = S.Db;
var d = S.Save;
var now = S.Now;
var e = db.Economy;
Title("적장 토벌 (이벤트)");
string bossId = ArenaRules.RaidBoss(db, d, now);
var h = db.Heroes.Get(bossId);
var stage = ArenaRules.RaidStage(db, Root.Battle.Config, bossId);
var box = Panel("Boss", 124f, 640f);
UiKit.Portrait("Boss", box, h, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0f, -20f), new Vector2(320f, 320f), false, 1f, new Color(0.85f, 0.8f, 0.75f));
var sb = new System.Text.StringBuilder();
sb.Append("<size=52><b>이번 주 보스 — ").Append(h != null ? h.nameKo : bossId).Append("</b></size>\n");
sb.Append("보스 HP ×").Append(e.RaidHpMult.ToString("0.#")).Append(" · ").Append(e.RaidTurns).Append("턴 동안 피해를 누적").Append(stage != null ? " · 적 " + stage.enemies.Count + "기" : "").Append("\n");
sb.Append("이번 주 누적 피해 ").Append(d.arena.raidDamage.ToString("N0")).Append(" (").Append(d.arena.raidWeek).Append(" 주)\n");
sb.Append("보상 ").Append(db.Chests.Get(e.RaidChest).nameKo).Append(" · 천기 보물 확률 ").Append((e.RaidArcanaPct * 100f).ToString("0.#")).Append("%");
UiKit.Label(box, sb.ToString(), 32, UiKit.Ink, TextAnchor.UpperCenter, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0f, -360f), new Vector2(980f, 270f), false).lineSpacing = 1.15f;
var why = ArenaRules.CanRaid(db, d, now);
if (stage == null && why == null) why = "보스 편성 없음";
var go = UiKit.Btn("Go", root, why == null ? "토벌 — 남은 " + ArenaRules.RaidLeft(db, d, now) + "/" + e.RaidDaily : why, 48, why == null ? UiKit.Red : UiKit.Disabled, UiKit.White,
new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0f, -790f), new Vector2(1032f, 150f), () =>
{
var w = ArenaRules.CanRaid(S.Db, S.Save, S.Now);
if (w != null)
{
Root.Toast(w);
return;
}
Root.StartMode(ArenaRules.Raid, bossId, 0, ArenaRules.RaidStage(S.Db, Root.Battle.Config, bossId), S.Db.Economy.RaidTurns, 4);
});
go.interactable = why == null;
UiKit.Label(root, "주간 보스 = 여포·조조 순환 · 주가 바뀌면 누적 초기화 · 천기 = 적장 토벌 전용", 28, UiKit.InkSoft, TextAnchor.MiddleCenter, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0f, -960f), new Vector2(1000f, 50f), false);
}
}
}