using System.Collections.Generic; using UnityEngine; // 스토리 비트 전체 목록 — "누가 어디서 언제 무슨 대화를 하는가"의 단일 원본. // 캐릭터 슬롯 활성화(HasPlayableBeat)와 DialogPlayer의 대화 후보(GetPlayableBeats)가 // 전부 이 에셋을 조회한다. 게임에 하나만 만들어 LocationManager에 꽂아 쓴다. [CreateAssetMenu(menuName = "Story/Story Database")] public class StoryDatabase : ScriptableObject { [Tooltip("스토리 비트 목록 — 위에 있을수록 대화 선택 메뉴에서 우선순위가 높다. " + "진행도 순으로 정렬해 두면 이 목록이 곧 시나리오 진행표가 된다")] [SerializeField] private List _beats = new(); public IReadOnlyList Beats => _beats; // 이 장소·캐릭터의 비트 중 지금 조건을 만족하는 것들 (목록 순서 유지) public List GetPlayableBeats(LocationData location, CharacterData character) { var result = new List(); foreach (var beat in _beats) if (IsPlayable(beat, location, character)) result.Add(beat); return result; } // 이 장소에서 이 캐릭터가 걸 수 있는 대화가 하나라도 있는가 (캐릭터 슬롯 활성화 판정) public bool HasPlayableBeat(LocationData location, CharacterData character) { foreach (var beat in _beats) if (IsPlayable(beat, location, character)) return true; return false; } // 강제 재생(DialogPlayer.PlayGroup)용 — 이 그룹이 등록된 첫 비트 (없으면 null) public StoryBeat FindBeat(DialogGroup group) { if (group == null) return null; foreach (var beat in _beats) if (beat.Group == group) return beat; return null; } // character가 null이면 "장소 비트"(Character를 비워 둔 항목)를 찾는다 — // 말을 거는 대상 없이 장소 입장 시 자동 재생되는 대화다. private static bool IsPlayable(StoryBeat beat, LocationData location, CharacterData character) { if (beat.Location != location || beat.Character != character || beat.Group == null) return false; // 1회성 비트는 완료 이력이 있으면 후보에서 빠진다 (장소 비트가 입장마다 반복되는 것 방지) if (beat.OnceOnly) { var story = StoryManager.Instance; if (story != null && story.IsDialogCompleted(beat.Group.name)) return false; } return beat.Condition == null || beat.Condition.IsMet(character); } }