188 lines
7.5 KiB
C#
188 lines
7.5 KiB
C#
|
|
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
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|