91 lines
3.5 KiB
C#
91 lines
3.5 KiB
C#
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<HiddenBranch> _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<HiddenBranch> 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;
|
|
}
|
|
}
|