VSClone/Assets/Editor/EditorRender.Systems.cs

169 lines
12 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;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using VS.Sim;
using VS.View;
namespace VS.EditorTools
{
public static partial class EditorRender
{
static void SystemShots(GameApp app)
{
var g = app.G;
// 3일차 · 선물 해금 → 슬롯 채움 + 채팅 흐름
g.DebugSetPlayDay(3); g.S.giftUnlockedLifetime = true;
g.ActivateX2Boost(); g.ActivateAutoClick();
app.DebugTick(0.25f, 80);
app.CloseAllPopups();
Shot(app, "main_gifts_chat");
int t = -1; foreach (var s in g.GiftSlot) if (s >= 0) { t = s; break; }
if (t < 0) { g.GiftSlot[0] = GiftTypes.BigMoneyPack; t = GiftTypes.BigMoneyPack; }
app.OpenGiftPopup(t); Shot(app, "pop_gift"); app.ClosePopup();
app.OpenBoosterX2(); Shot(app, "pop_booster_x2"); app.ClosePopup();
g.S.afkPending = "987654"; g.AfkSeconds = 5400;
app.OpenAfkPopup(false); Shot(app, "pop_afk"); app.ClosePopup();
app.OpenTasks(); Shot(app, "pop_task"); app.ClosePopup();
app.OpenDaily(); Shot(app, "pop_daily"); app.ClosePopup();
app.OpenTicketShop(); Shot(app, "pop_ticketshop"); app.ClosePopup();
g.S.rankIndex = Math.Max(g.S.rankIndex, g.NextHouseRankReq());
app.OpenBuyNewHouse(); Shot(app, "pop_newhouse"); app.ClosePopup();
g.S.afkPending = "0";
BattleShots(app);
app.SwitchTab(0);
}
// 전투 탭 — 기본 흐름 · 맵 4종 · 성 기믹 3종 · 성 투사체 5종 (카드 = 아래 가운데에서 즉시 소환)
static void BattleShots(GameApp app)
{
var g = app.G;
app.BattleTest = null;
// 스테이지 선택 — 전투 탭 = 고르는 화면부터(첫 화면 = 다음에 깰 스테이지 1) · 잠긴 스테이지 · 지도 = 정보 창 · 시작 = 바로 전투
app.SwitchTab(1); app.RefreshAll();
StageCheck(app, "stage_select", 1, true); Shot(app, "stage_select");
app.ShowStage(3); StageCheck(app, "stage_locked", 3, false); Shot(app, "stage_locked");
app.OpenStageInfo(); Shot(app, "stage_info"); app.ClosePopup();
app.StartStage(1, 5);
if (app.StageRoot.gameObject.activeSelf || !app.BattleRoot.gameObject.activeSelf || app.B.State != BattleState.Fighting || app.B.Stage != 1) { fails++; notes.Add("stage_start: 시작을 눌렀는데 전투 화면이 아님"); }
app.B.Mana = 10;
app.DeployCard(0); app.DebugTick(0.05f, 40); app.DeployCard(0); app.DebugTick(0.05f, 40); app.DeployCard(0);
g.S.battleSlots = 6; app.B.MaxMana = 15; app.B.Mana = 15;
app.DeployCard(1); app.DeployCard(4); app.DeployCard(5);
app.DebugTick(0.05f, 240);
Shot(app, "battle_fight");
RivalCheck(app, "battle_fight");
LayoutCheck(app, "battle_fight");
app.OpenBattleUpgrade(); Shot(app, "battle_upgrade"); app.ClosePopup();
app.OpenBattleTest(); Shot(app, "battle_test"); app.ClosePopup();
app.B.CastleHpDebugKill(); app.DebugTick(0.05f, 2); Shot(app, "battle_won");
// 이긴 뒤 스테이지 선택 = 1 클리어 표시 · 2 열림(첫 화면)
app.OpenStageSelect(1); StageCheck(app, "stage_cleared", 1, true); Shot(app, "stage_cleared");
app.OpenStageSelect(app.G.StageFocus); StageCheck(app, "stage_next", 2, true); Shot(app, "stage_next");
// 맵 4종 (바위·언덕 켬 · 성 공격 끔 — 길 찾기 장면)
string[] mapKey = { "plain", "b1", "b2", "b3" };
for (int k = 0; k < 4; k++)
{
Scene(app, new BattleSetup { mapType = k, obstacles = 1, shots = new List<string>(), gimmicks = new List<string>() }, 30 + k);
app.DebugTick(0.05f, 300);
Shot(app, "battle_map_" + mapKey[k]);
}
// 성 기믹 · 투사체 — 다리 2개 · 장애물 없음 · 그것만 켜고 발동 순간
CastleScene(app, "battle_gim_fireball", L(), L("fireball"), () => app.B.Fx.Exists(f => f.type == "blast"));
CastleScene(app, "battle_gim_lightning", L(), L("lightning"), () => app.B.Fx.Exists(f => f.type == "lightning"));
CastleScene(app, "battle_gim_summon", L(), L("summonMelee", "summonRanged"), () => app.B.Minions.Count >= MaxMinions(app.B) && app.B.Minions.Exists(m => m.attacking));
CastleScene(app, "battle_shot_normal", L("normal"), L(), () => app.B.Shots.Exists(s => s.type == "normal" && UnityEngine.Vector2.Distance(s.pos, app.B.CastlePos) > app.B.C.castle.radius + 0.8f));
CastleScene(app, "battle_shot_splash", L("splash"), L(), () => app.B.Fx.Exists(f => f.type == "blast"));
CastleScene(app, "battle_shot_multi", L("multi"), L(), () => app.B.Shots.FindAll(s => s.type == "multi" && s.left < app.B.Range(s.def) - 1.2f).Count >= 3);
CastleScene(app, "battle_shot_slow", L("slow"), L(), () => app.B.Units.Exists(u => u.slow > 0f) && app.B.Shots.Exists(s => s.type == "slow"));
CastleScene(app, "battle_shot_laser", L("laser"), L(), () => app.B.Fx.Exists(f => f.type == "laser" && f.t < 0.1f));
// 깃발 — 왼쪽 다리 건너편에 꽂으면 전원이 그리로 먼저
Scene(app, new BattleSetup { mapType = 2, obstacles = 0, castleX = 9f, shots = L(), gimmicks = L() }, 41);
app.DebugTick(0.05f, 20);
app.PlaceFlag(new Vector2(app.B.Map.Bridges[0], app.B.C.riverY + 3f));
app.B.Mana = 15; app.DeployCard(0); app.DeployCard(1);
app.DebugTick(0.05f, 110);
var flag = app.BattleRoot.Find("Arena/Flag");
if (flag == null || !flag.gameObject.activeSelf || !app.B.Units.Exists(u => u.flag != app.B.FlagVer)) { fails++; notes.Add("battle_flag: 깃발 · 깃발로 가는 유닛 못 잡음"); }
Shot(app, "battle_flag");
// 물량 — 1단계 성 구성(stageLoadouts)에 검사를 마나 차는 대로 계속 보내 성벽에 많이 붙은 순간 (카드 1장 = 1마리)
var lo1 = g.BC.Loadout(1);
app.BattleTest = new BattleSetup { shots = new List<string>(lo1.shots), gimmicks = new List<string>(lo1.gimmicks) }; app.NewBattleRound(7); app.B.Start();
bool swarm = false;
for (int i = 0; i < 2400 && !swarm; i++) { if (app.B.Mana >= g.BattleUnit(0).cost) app.DeployCard(0); app.DebugTick(0.05f, 1); swarm = app.B.Units.FindAll(u => u.attacking).Count >= 15; }
if (!swarm) { fails++; notes.Add("battle_swarm: 물량 장면 못 잡음"); }
LayoutCheck(app, "battle_swarm");
Shot(app, "battle_swarm");
// 성벽 회복 — 맞은 뒤 regenDelay 초 지나 초록 빛
app.BattleTest = new BattleSetup { mapType = 0, obstacles = 0, castleX = 9f, shots = L(), gimmicks = L() }; app.NewBattleRound(42); app.B.Start();
app.B.HitCastle(app.B.CastleMaxHp * 0.4f);
bool heal = false;
for (int i = 0; i < 400 && !heal; i++) { app.DebugTick(0.05f, 1); heal = app.B.Fx.Exists(f => f.type == "heal" && f.t < 0.15f) && app.B.CastleHeals >= 2; }
if (!heal) { fails++; notes.Add("battle_regen: 회복 장면 못 잡음"); }
Shot(app, "battle_regen");
// 상대방 칸 — 투사체 5 + 기믹 4 전부 켜도 카드 칸과 안 겹침
var all = L(); foreach (var d in g.BC.skills) all.Add(d.id); foreach (var d in g.BC.summons) all.Add(d.id);
Scene(app, new BattleSetup { mapType = 1, obstacles = 0, shots = g.BC.shots.ConvertAll(d => d.id), gimmicks = all }, 43);
app.DebugTick(0.05f, 200);
RivalCheck(app, "battle_rival_all");
Shot(app, "battle_rival_all");
app.BattleTest = null;
}
/// 오른쪽 위 = 상대방 얼굴 + 스킬 줄(성 구성 수만큼) · 남은 시간 칸 없음 · 카드 칸(아래 view.trayH)과 안 겹침
static void RivalCheck(GameApp app, string name)
{
var root = app.BattleRoot; var rv = root.Find("Rival") as RectTransform;
int want = app.B.CastleShots.Count + app.B.CastleSkills.Count + app.B.Summoners.Count, rows = 0;
if (rv != null) foreach (Transform ch in rv) if (ch.name.StartsWith("Skill_")) rows++;
bool timer = root.Find("Timer") != null;
if (timer || rv == null || rows != want) { fails++; notes.Add($"{name}: 상대방 칸 이상 (남은 시간 칸 {timer} · 스킬 줄 {rows}/{want})"); return; }
float h = root.rect.height, bottom = h + rv.anchoredPosition.y - rv.sizeDelta.y;
if (h > 0f && bottom < app.G.BC.view.trayH) { fails++; notes.Add($"{name}: 상대방 칸이 카드 칸과 겹침 (아래 끝 {bottom:0})"); }
}
/// 클래시 로얄 비율(battle.json view) — 맵 18칸이 화면 폭의 85% 이상 · 카드 칸 높이 = trayH · 맵이 카드 칸 위에서 화면 안 · 유닛 그림 한 변 ≥ 1.5칸
static void LayoutCheck(GameApp app, string name)
{
var c = app.G.BC; var v = c.view; var root = app.BattleRoot;
var ar = root.Find("Arena") as RectTransform; var tray = root.Find("CardPanel") as RectTransform;
float w = root.rect.width, h = root.rect.height, playW = c.arenaW * v.tileX, bottom = ar.anchoredPosition.y - ar.sizeDelta.y * 0.5f, top = bottom + ar.sizeDelta.y;
float minUnit = float.MaxValue;
foreach (Transform t in ar.Find("Units")) if (t.name.StartsWith("U")) minUnit = Mathf.Min(minUnit, ((RectTransform)t).sizeDelta.y);
bool ok = w <= 0f || (playW >= w * 0.85f && Mathf.Abs(tray.sizeDelta.y - v.trayH) < 0.5f && bottom >= v.trayH - 0.5f && top <= h + 0.5f && (minUnit == float.MaxValue || minUnit >= 1.5f * v.tileX));
if (!ok) { fails++; notes.Add($"{name}: 화면 비율 이상 (맵 {playW:0}/{w:0} · 카드 칸 {tray.sizeDelta.y:0} · 맵 아래 {bottom:0} 위 {top:0}/{h:0} · 유닛 그림 {minUnit:0})"); }
else Debug.Log($"[VS] LAYOUT {name} 맵 {playW:0}/{w:0} px({playW / Mathf.Max(1f, w) * 100f:0}%) · 칸 {v.tileX:0}×{v.tileY:0} · 카드 칸 {tray.sizeDelta.y:0} · 맵 {bottom:0}~{top:0}/{h:0} · 가장 작은 유닛 그림 {minUnit:0} px");
}
/// 스테이지 선택 화면 — 보임(전투 화면은 숨김) · 제목 「번호. 이름」 · 시작 버튼 열림/잠김 · 화살표(처음 = 왼쪽 없음 · 끝 = 오른쪽 없음) · 클리어 표시
static void StageCheck(GameApp app, string name, int stage, bool open)
{
var root = app.StageRoot; int n = app.G.StageCount;
var title = root.Find("Title")?.GetComponent<Text>(); var start = root.Find("Start")?.GetComponent<Button>();
bool prev = root.Find("Prev").gameObject.activeSelf, next = root.Find("Next").gameObject.activeSelf, clear = root.Find("Clear").gameObject.activeSelf;
bool ok = root.gameObject.activeSelf && !app.BattleRoot.gameObject.activeSelf && title != null && title.text.StartsWith(stage + ". ") && start != null && start.interactable == open
&& prev == (stage > 1) && next == (stage < n) && clear == app.G.StageCleared(stage);
if (!ok) { fails++; notes.Add($"{name}: 스테이지 선택 화면 이상 (제목 {title?.text} · 시작 {start?.interactable} · 화살표 {prev}/{next} · 클리어 {clear})"); }
}
static List<string> L(params string[] s) => new List<string>(s);
static int MaxMinions(Battle b) { int n = 0; foreach (var s in b.Summoners) n += s.def.max; return n; }
static void Scene(GameApp app, BattleSetup s, int seed)
{
app.BattleTest = s; app.NewBattleRound(seed);
app.B.Start(); app.B.MaxMana = 15; app.B.Mana = 15;
app.DeployCard(2); app.DeployCard(1); app.DeployCard(0); app.DeployCard(0); app.DeployCard(4);
}
static void CastleScene(GameApp app, string name, List<string> shots, List<string> gimmicks, Func<bool> moment)
{
Scene(app, new BattleSetup { mapType = 2, obstacles = 0, castleX = 9f, shots = shots, gimmicks = gimmicks }, 40);
bool ok = false;
for (int i = 0; i < 1200 && !ok; i++) { app.DebugTick(0.05f, 1); ok = moment(); }
if (!ok) { fails++; notes.Add(name + ": 발동 장면 못 잡음"); }
Shot(app, name);
}
}
}