ThreeKingdomsSlingshot/Assets/Scripts/Runtime/Skills/SkillCaptureDriver.cs

188 lines
7.5 KiB
C#
Raw Permalink 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;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
namespace TKS.OutGame
{
/// <summary>
/// 스킬 화면 검증 캡처(에디터 DataImporter.CaptureSkills 가 SessionState 로 출력 폴더를 넘기면 생성 · 세이브 = 메모리 전용 신규 유저 · PD #1093 B).
/// ① 스킬 레벨업(영웅 상세 → 팝업 · 액티브 Lv+1 뒤) ② 스킬 버튼(전투 · 관우 선택) ③ 액티브 발동(장비 장판 일갈 · 이름 글자 + 플래시 + 밀기)
/// ④ 패시브 표시(조운 관통 → 상산의 창 HUD 한 줄). 캡처를 위해 적 1기씩을 아군 앞에 옮겨 둔다(그 밖은 실제 처리).
/// </summary>
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<string> log = new List<string>();
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<SkillCaptureDriver>();
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<string, Unit>();
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
}
}
}