using System.Collections.Generic; using UnityEngine; // 노드의 역할. 서로 배타적이므로 플래그 여러 개가 아니라 하나의 종류로 둔다. public enum DialogNodeKind { [InspectorName("대사")] Line, // 평범한 대사 노드 [InspectorName("호감도 분기")] AffectionCheck, // 대사 없이 조건만 검사해 즉시 라우팅 [InspectorName("종료")] End, // 대화를 끝낸다 (BGM 처리만 정함) } [CreateAssetMenu(menuName = "Communication/Dialog Node")] public class DialogNode : ScriptableObject { [Tooltip("이 노드의 역할. 그래프에서 어떤 노드를 썼는지에 따라 임포터가 정한다")] public DialogNodeKind Kind = DialogNodeKind.Line; [Header("Speaker")] public CharacterData Speaker; [Tooltip("비우면 Speaker의 이름 그대로, 채우면 이 이름으로 표시 (예: ???)")] public string SpeakerNameOverride; [Header("Content")] [TextArea(2,5)] public string TalkText; public GestureData Gesture; public ExpressionData Expression; public VoiceClip Voice; // 진행은 항상 플레이어 입력(OnDialogNext)으로 넘어간다. [Header("Presentation")] [Tooltip("있으면 이 대사부터 이 BGM으로 갈아탄다. 비우면 변경 없음 — " + "다시 바꾸기 전까지 계속 이어진다")] public AudioClip Bgm; [Tooltip("이 대사가 시작될 때 한 번 재생할 효과음 (문 여는 소리, 쿵 소리 등). " + "BGM과 달리 이어지지 않고 1회성이다")] public AudioClip Sfx; [Tooltip("이 대사만의 타이핑 연출(속도·글자색·타이핑 사운드). " + "비우면 DialogHud의 기본 스타일을 쓴다")] public TypewriterStyle Typewriter; [Header("Stage")] [Tooltip("이 대사 동안 배경 앞·캐릭터 뒤에 띄울 장면 그림 (설명용 컷인, 증언 장면 등). " + "비우면 사라진다 — 여러 대사에 걸쳐 보이려면 그 대사마다 같은 그림을 지정할 것. " + "캐릭터보다 앞에 보여야 하면 Pose를 '숨김'으로 내리면 된다")] public Sprite SceneScreen; [Tooltip("이 대사부터 바꿀 포즈. '변경 없음'이 기본이라 인물이 서 있는 동안 매 대사에 " + "다시 꽂을 필요가 없고, '숨김'을 고르면 화면에서 내린다. " + "대화가 끝나면 대화 전 포즈로 되돌아간다")] public Pose Pose; [Tooltip("위 Pose를 적용할 대상. 화자와 다를 수 있어서 Speaker와 별개다 — " + "나루호도가 말하는 동안 화면의 마요이가 표정을 바꾸는 식. " + "Pose가 '변경 없음'이면 비워두면 되고, 포즈를 골랐는데 비어 있으면 아무 일도 일어나지 않는다")] public CharacterData PoseTarget; [Tooltip("이 대사에만 번쩍 뜨는 그림 — '이의있음!' '받아랏!' 같은 연출. " + "다음 대사로 넘어가면 자동으로 사라진다 (SFX와 같은 1회성). 비우면 안 뜬다")] public Sprite FrontSprite; [Tooltip("이 대사 동안 화면 옆(왼쪽)에 놓을 그림. 제시한 물건을 놓고 설명할 때 쓴다. " + "비우면 사라진다 — 여러 대사에 걸쳐 보이려면 그 대사마다 같은 그림을 지정할 것")] public Sprite SideSprite; [Header("Flow")] public DialogNode Next; // 선택지 없을 때 자동으로 갈 노드 public List Choices; // 있으면 플레이어 선택 대기 [Header("Hidden Branch")] [Tooltip("이 대사가 재생되는 동안 특정 행동(부위 터치·증거품 제출 등)을 하면 " + "Next/선택지 대신 몰래 분기한다. 키마다 다른 목적지를 줄 수 있고, " + "Key가 빈 항목은 나머지 전부를 받는 catch-all이 된다. " + "비우면 히든 분기 없음 — 평소엔 존재하지 않는 것처럼 보인다")] public List HiddenBranches = new(); [Header("Affection Branch")] [Tooltip("(Kind = 호감도 분기 전용) 검사할 호감도 조건들 (캐릭터·연산자·값 + 다음 조건과의 and/or). " + "캐릭터를 비우면 대화 주인 NPC. AND가 OR보다 우선. 비어 있으면 무조건 통과")] public List AffectionRequirements = new(); [Tooltip("조건을 만족했을 때 갈 노드 (실패하면 Next로)")] public DialogNode AffectionPassBranch; [Header("End")] [Tooltip("(Kind = 종료 전용) 켜면 대화가 끝나도 마지막에 재생 중이던 BGM을 유지한다. " + "끄면 장소 BGM으로 복귀. 종료 노드마다 따로 정할 수 있어서 분기별로 다르게 끝낼 수 있다")] public bool KeepBgmOnEnd; [Header("ChoiceQuestion")] [TextArea(2,5)] public string ChoiceQuestion; [Header("Story")] [Tooltip("0이 아니면 이 노드 재생 시 화자(비우면 대화 주인 NPC)의 호감도를 이만큼 증감")] public int Affection; [Tooltip("0이 아니면 이 노드 재생 시 메인 진행도를 이만큼 증가. " + "분기 끝 노드마다 다른 값을 주면 선택지에 따라 진행도를 다르게 줄 수 있다")] public int Progress; }