using System; using System.Collections.Generic; using UnityEngine; // 히든 분기 감시 허브 (씬 오브젝트 불필요, 순수 static). // // 대화 노드가 재생되는 동안 DialogPlayer가 Arm(분기 목록)으로 무장하고, 끝나면 Disarm()한다. // 그 창(무장 구간) 안에서 누군가 Fire(key)를 호출하면 키에 맞는 분기가 골라지고, // DialogPlayer가 이를 감지해 Next(또는 선택지) 대신 그 분기로 몰래 이동한다. // Fire를 호출하는 쪽은 캐릭터 부위 터치 존, 증거품 제출 UI 등 무엇이든 될 수 있다. // // 무장돼 있지 않으면 어떤 Fire도 무시된다 → 평소엔 존재하지 않는 것처럼 동작(=히든). public static class HiddenBranchResolver { // 지금 무장된 노드의 히든 분기 목록 (null이면 무장 해제 상태) private static IReadOnlyList _branches; // 지금 히든 분기를 받을 수 있는 상태인가 (노드 재생 중) public static bool Armed => _branches != null; // 이번 무장 구간에서 발동한 분기의 인덱스 (-1이면 아직 발동 안 함) public static int FiredIndex { get; private set; } = -1; // 이번 무장 구간에서 발동했는가 public static bool Fired => FiredIndex >= 0; // 발동 즉시 알림 — 떠 있는 선택지 메뉴를 그 자리에서 취소시키는 용도 public static event Action FiredEvent; // Enter Play Mode(도메인 리로드 off)에서 이전 상태가 안 남게 [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)] private static void ResetStatics() { _branches = null; FiredIndex = -1; FiredEvent = null; } // 노드 진입 시 무장. public static void Arm(IReadOnlyList branches) { _branches = branches; FiredIndex = -1; } // 노드 종료 시 해제. public static void Disarm() { _branches = null; FiredIndex = -1; } // 발동시키는 쪽(터치 존·증거품 UI 등)이 호출. 무장 중이고 키가 맞을 때만 1회 발동. // // 매칭 규칙: 키가 정확히 일치하는 분기가 최우선, 없으면 Key가 빈 분기(catch-all). // 덕분에 "정답 키는 각자 분기로, 나머지는 전부 오답 분기로"가 자연스럽게 나온다. // Destination이 비어 있는 분기는 후보에서 제외한다(아무 데도 못 가는 분기로 새는 것 방지). // // 반환: 이번 호출로 실제 발동했으면 true (호출 측이 "그때만" 연출·아이템 소비 등에 쓸 수 있게). public static bool Fire(string key) { if (_branches == null || FiredIndex >= 0) return false; int exact = -1; int catchAll = -1; for (int i = 0; i < _branches.Count; i++) { var branch = _branches[i]; if (branch == null || branch.Destination == null) continue; if (string.IsNullOrEmpty(branch.Key)) { if (catchAll < 0) catchAll = i; // 첫 catch-all만 사용 } else if (branch.Key == key) { exact = i; break; // 정확 일치는 더 볼 것 없음 } } int picked = exact >= 0 ? exact : catchAll; if (picked < 0) return false; // 맞는 분기 없음 — 아무 일도 안 일어남 FiredIndex = picked; FiredEvent?.Invoke(); return true; } }