using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
namespace TKS.OutGame
{
///
/// 스킬 화면 검증 캡처(에디터 DataImporter.CaptureSkills 가 SessionState 로 출력 폴더를 넘기면 생성 · 세이브 = 메모리 전용 신규 유저 · PD #1093 B).
/// ① 스킬 레벨업(영웅 상세 → 팝업 · 액티브 Lv+1 뒤) ② 스킬 버튼(전투 · 관우 선택) ③ 액티브 발동(장비 장판 일갈 · 이름 글자 + 플래시 + 밀기)
/// ④ 패시브 표시(조운 관통 → 상산의 창 HUD 한 줄). 캡처를 위해 적 1기씩을 아군 앞에 옮겨 둔다(그 밖은 실제 처리).
///
public class SkillCaptureDriver : MonoBehaviour
{
public const string DirKey = "TKS_SKILL_CAPTURE_DIR";
public string OutputDir;
public int Width = 720;
public int Height = 1280;
readonly List log = new List();
int shot = 1;
#if UNITY_EDITOR
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)]
static void AutoSpawn()
{
string dir = UnityEditor.SessionState.GetString(DirKey, "");
if (string.IsNullOrEmpty(dir)) return;
UnityEditor.SessionState.EraseString(DirKey);
var d = new GameObject("SkillCaptureDriver").AddComponent();
d.OutputDir = dir;
}
#endif
IEnumerator Start()
{
Directory.CreateDirectory(OutputDir);
yield return null;
yield return null;
var root = OutGameRoot.Instance;
var cam = Camera.main;
if (root == null || cam == null)
{
Log("FAIL: OutGameRoot 또는 카메라 없음");
Finish(1);
yield break;
}
var s = root.Session;
Log("memoryOnly=" + SaveStore.MemoryOnly + " newUser=" + s.IsNewUser + " books=" + s.Save.inv.books.skill + " gold=" + s.Save.gold);
// ① 스킬 레벨업: 첫 시작 영웅(★3 = 액티브 상한 +1) 액티브 Lv1 → 2
var id = s.Db.Economy.StartHeroes[0];
var h = s.Def(id);
var hs = s.Save.Hero(id);
root.ShowHero(id);
yield return Wait();
Log("skill cap active=" + SkillRules.Cap(s.Db, h, hs, 0) + " passive=" + SkillRules.Cap(s.Db, h, hs, 1) + " star=" + hs.star + " grade=" + hs.grade);
Log("levelup active → " + (SkillRules.LevelUp(s.Db, s.Save, h, hs, 0) ?? "ok") + " lv=" + hs.skillLv[0] + " books=" + s.Save.inv.books.skill + " gold=" + s.Save.gold);
s.Commit();
root.HeroDetail.Refresh();
root.HeroDetail.OnSkillUp();
yield return Wait();
yield return Shot(cam, "skill_levelup_" + id);
root.CloseModal();
// 전투 1-1
root.ShowLobby();
root.OpenWorldMap();
yield return Wait();
var wm = root.Map;
wm.OpenPopup(0);
yield return Wait();
wm.ConfirmPopup();
var bm = root.Battle;
float t0 = Time.realtimeSinceStartup;
while (bm.Phase != BattlePhase.PlayerTurn && Time.realtimeSinceStartup - t0 < 10f) yield return null;
var byHero = new Dictionary();
foreach (var u in bm.Units)
{
if (u == null || u.Faction != Faction.Player) continue;
var us = bm.Skills.Of(u);
Log(" " + u.DisplayName + " " + u.Type + " active=" + (us != null && us.Active != null ? us.Active.Id + " Lv" + us.ActiveLv : "-") + " passive=" + (us != null && us.Passive != null ? us.Passive.Id + " ×" + us.PassiveMult : "-") + " hp" + u.MaxHp + " @" + u.Position);
if (us != null) byHero[us.HeroId] = u;
}
// ② 스킬 버튼: 관우 선택(다음 행동형 · 사용 가능)
Unit gy;
if (byHero.TryGetValue("guanyu", out gy))
{
bm.Sling.Select(gy);
yield return Wait();
Log("button: " + bm.Hud.SkillButtonText);
yield return Shot(cam, "skill_button_guanyu");
}
// ③ 액티브 발동: 장비 장판 일갈(즉시 · 반경 안 적 밀기 + 이번 적 턴 교전 반응 없음)
Unit zf;
if (byHero.TryGetValue("zhangfei", out zf))
{
var foe = Nearest(bm, zf);
if (foe != null) foe.Position = zf.Position + new Vector2(0f, 2f);
Vector2 before = foe != null ? foe.Position : Vector2.zero;
bm.Sling.Select(zf);
yield return null;
Log("press: " + bm.Hud.PressSkill());
yield return new WaitForSecondsRealtime(0.18f);
yield return Shot(cam, "active_zhangfei");
t0 = Time.realtimeSinceStartup;
while (bm.Phase != BattlePhase.PlayerTurn && Time.realtimeSinceStartup - t0 < 10f) yield return null;
Log("pushed " + (foe != null ? foe.DisplayName + " " + before + "→" + foe.Position : "-") + " readyTurn=" + bm.Skills.Of(zf).ReadyTurn + " acted=" + zf.ActedThisTurn);
}
// ④ 패시브 표시: 조운 관통(상산의 창 = 넉백 ×) → HUD 한 줄
Unit zy;
if (byHero.TryGetValue("zhaoyun", out zy))
{
var foe = Nearest(bm, zy);
if (foe != null)
{
foe.Position = zy.Position + new Vector2(0f, 3.5f);
bm.RequestPlayerAction(zy, foe.Position);
t0 = Time.realtimeSinceStartup;
while (bm.Phase != BattlePhase.PlayerTurn && Time.realtimeSinceStartup - t0 < 10f) yield return null;
}
bm.Sling.Select(zy);
yield return null;
Log("log: " + string.Join(" / ", bm.Skills.RecentLog(30f, 8).ToArray()));
Log("msg: " + bm.LastMessage);
yield return Shot(cam, "passive_zhaoyun");
}
Finish(0);
}
static Unit Nearest(BattleManager bm, Unit from)
{
Unit best = null;
float bd = float.MaxValue;
foreach (var e in bm.AliveUnits(Faction.Enemy))
{
float d = Vector2.Distance(e.Position, from.Position);
if (d < bd)
{
bd = d;
best = e;
}
}
return best;
}
static IEnumerator Wait()
{
yield return null;
yield return new WaitForSecondsRealtime(0.3f);
}
IEnumerator Shot(Camera cam, string name)
{
string file = Path.Combine(OutputDir, shot.ToString("00") + "_" + name + ".png");
shot++;
yield return CaptureUtil.Capture(cam, Width, Height, file);
Log("shot " + file);
}
void Log(string s)
{
log.Add(s);
Debug.Log("[SkillCapture] " + s);
try
{
File.WriteAllLines(Path.Combine(OutputDir, "capture_log.txt"), log.ToArray());
}
catch
{
}
}
void Finish(int code)
{
Log("finish code=" + code);
#if UNITY_EDITOR
UnityEditor.EditorApplication.Exit(code);
#else
Application.Quit(code);
#endif
}
}
}