2026-11-05 16:20:07 +00:00
|
|
|
using System.Collections;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using UnityEngine;
|
|
|
|
|
|
|
|
|
|
namespace TKS
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 가상 실행(dry-run · PD #1098 적 AI 예측 시뮬레이션): Active 동안 ActionResolver 가 연출 없이 한 프레임 안에 끝난다 —
|
|
|
|
|
/// Fx 이동·대기·투사체 = 즉시 · 팝업·광역 터짐 = 없음 · 유닛 표시(UnitView) 갱신 없음 · 피해 난수 = 분산 0 · 전투 이벤트 카운터 없음.
|
|
|
|
|
/// 상태는 Snapshot 으로 떠 두고 Restore 로 되돌린다(유닛 · 스킬 상태 · 기믹 레이어).
|
|
|
|
|
/// </summary>
|
|
|
|
|
public static class Sim
|
|
|
|
|
{
|
|
|
|
|
public static bool Active;
|
|
|
|
|
|
|
|
|
|
/// <summary>코루틴을 이 프레임 안에서 끝까지 돌린다(중첩 IEnumerator 포함 · null/기타 yield = 즉시 진행).</summary>
|
|
|
|
|
public static void Run(IEnumerator routine)
|
|
|
|
|
{
|
|
|
|
|
if (routine == null) return;
|
|
|
|
|
var stack = new Stack<IEnumerator>();
|
|
|
|
|
stack.Push(routine);
|
|
|
|
|
int guard = 0;
|
|
|
|
|
while (stack.Count > 0)
|
|
|
|
|
{
|
|
|
|
|
if (++guard > 200000)
|
|
|
|
|
{
|
|
|
|
|
Debug.LogError("[TKS] 가상 실행 루프 상한 초과 — 중단");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
var top = stack.Peek();
|
|
|
|
|
if (!top.MoveNext())
|
|
|
|
|
{
|
|
|
|
|
stack.Pop();
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
var cur = top.Current as IEnumerator;
|
|
|
|
|
if (cur != null) stack.Push(cur);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public class UnitSnap
|
|
|
|
|
{
|
|
|
|
|
public Unit U;
|
|
|
|
|
public Vector2 Pos;
|
|
|
|
|
public int Hp, MaxHp, Atk, Def;
|
|
|
|
|
public bool Acted, Bonus, Overwatch, Collider, Active;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public class Snapshot
|
|
|
|
|
{
|
|
|
|
|
public readonly List<UnitSnap> Units = new List<UnitSnap>();
|
2026-11-10 10:00:18 +00:00
|
|
|
/// <summary>스킬 상태 전부(유닛별 값 · 시한 효과 · 상태 이상 · 지대 · 2026-11-10 #1112).</summary>
|
|
|
|
|
public SkillSystem.State Skills;
|
2026-11-05 16:20:07 +00:00
|
|
|
public GimmickLayer.Snapshot Gimmicks;
|
|
|
|
|
public string Message;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static Snapshot Take(BattleManager bm)
|
|
|
|
|
{
|
|
|
|
|
var s = new Snapshot { Message = bm.LastMessage };
|
|
|
|
|
foreach (var u in bm.Units)
|
|
|
|
|
{
|
|
|
|
|
if (u == null) continue;
|
|
|
|
|
s.Units.Add(new UnitSnap
|
|
|
|
|
{
|
|
|
|
|
U = u, Pos = u.Position, Hp = u.Hp, MaxHp = u.MaxHp, Atk = u.Atk, Def = u.Def, Acted = u.ActedThisTurn, Bonus = u.BonusMoveAvailable,
|
|
|
|
|
Overwatch = u.Overwatch, Collider = u.Collider != null && u.Collider.enabled, Active = u.gameObject.activeSelf
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
var sys = bm.Skills;
|
2026-11-10 10:00:18 +00:00
|
|
|
if (sys != null) s.Skills = sys.TakeState();
|
2026-11-05 16:20:07 +00:00
|
|
|
if (GimmickLayer.Current != null) s.Gimmicks = GimmickLayer.Current.Take();
|
|
|
|
|
return s;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void Restore(BattleManager bm, Snapshot s)
|
|
|
|
|
{
|
|
|
|
|
foreach (var x in s.Units)
|
|
|
|
|
{
|
|
|
|
|
var u = x.U;
|
|
|
|
|
if (u == null) continue;
|
|
|
|
|
u.Position = x.Pos;
|
|
|
|
|
u.Hp = x.Hp;
|
|
|
|
|
u.MaxHp = x.MaxHp;
|
|
|
|
|
u.Atk = x.Atk;
|
|
|
|
|
u.Def = x.Def;
|
|
|
|
|
u.ActedThisTurn = x.Acted;
|
|
|
|
|
u.BonusMoveAvailable = x.Bonus;
|
|
|
|
|
u.Overwatch = x.Overwatch;
|
|
|
|
|
if (u.Collider != null) u.Collider.enabled = x.Collider;
|
|
|
|
|
if (u.gameObject.activeSelf != x.Active) u.gameObject.SetActive(x.Active);
|
|
|
|
|
}
|
|
|
|
|
var sys = bm.Skills;
|
2026-11-10 10:00:18 +00:00
|
|
|
if (sys != null) sys.RestoreState(s.Skills);
|
2026-11-05 16:20:07 +00:00
|
|
|
if (GimmickLayer.Current != null && s.Gimmicks != null) GimmickLayer.Current.Restore(s.Gimmicks);
|
|
|
|
|
bm.LastMessage = s.Message;
|
|
|
|
|
Physics2D.SyncTransforms();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|