using UnityEngine; using Unheimlich.Features.Dialogue.Data; using Unheimlich.Features.Dialogue; using Unheimlich.Features.Dialogue.UI; using Unheimlich.Core.Events; namespace Unheimlich.Features.Dialogue { /// /// Trigger zone that starts a dialogue sequence when player enters. /// Supports pause/resume on exit/enter and optional one-time triggering. /// public class DialogueTriggerZone : TriggerZoneBase { [Header("Dialogue Reference")] [Tooltip("DialogueConversation to use for this trigger zone")] [SerializeField] private DialogueConversation _conversation; [Header("Trigger Settings")] [Tooltip("Can the dialogue be retriggered after completion")] [SerializeField] private bool _isRetriggerable = false; protected override bool IsRetriggerable => _isRetriggerable; [Header("Distance Check")] [Tooltip("Pause dialogue if player exits the trigger zone")] [SerializeField] private bool _pauseOnExit = true; [Header("Floating Word Anchor")] [SerializeField] private Transform _floatingWordAnchor; [Header("Animation Settings")] [SerializeField] private DialogueAnimationSettings _animationSettings; [Header("UI Reference")] [Tooltip("Local DialogueUI for this trigger zone. Uses DialogueManager's UI if null")] [SerializeField] private DialogueUI _localDialogueUI; [Header("Blur Effect")] [Tooltip("Enable blur effect when dialogue starts")] [SerializeField] private bool _enableBlurEffect = true; private bool _hasTriggered = false; private DialogueStateHandler _dialogueState; protected override void Awake() { base.Awake(); _dialogueState = new DialogueStateHandler(this); if (_floatingWordAnchor == null) _floatingWordAnchor = transform; } protected override void OnPlayerEntered(Collider playerCollider) { if (_dialogueState.IsCompleted && !_isRetriggerable) return; if (_dialogueState.HasPausedDialogue) { _dialogueState.ResumeDialogue(); } else if (!_hasTriggered || (_isRetriggerable && _dialogueState.IsCompleted)) { TriggerDialogue(); } } protected override void OnPlayerExited(Collider playerCollider) { if (_pauseOnExit && DialogueManager.Instance != null && DialogueManager.Instance.IsDialogueActive) { if ((Object)DialogueManager.Instance.CurrentOwner == this) _dialogueState.PauseDialogue(); } } private void TriggerDialogue() { if (DialogueManager.Instance == null) { Debug.LogError("DialogueManager not found in scene!", this); return; } if (_conversation == null) { Debug.LogError($"{gameObject.name}: No conversation assigned!", this); return; } _hasTriggered = true; DialogueManager.Instance.StartConversation( _conversation, _floatingWordAnchor, _animationSettings, _localDialogueUI, this, _enableBlurEffect ); DialogueManager.Instance.OnDialogueCompleted += OnDialogueCompleted; } private void OnDialogueCompleted(object owner) { if ((Object)owner == this) { _dialogueState.MarkAsCompleted(); if (_isRetriggerable) { _hasTriggered = false; _dialogueState.AllowRetrigger(); } } if (DialogueManager.Instance != null) DialogueManager.Instance.OnDialogueCompleted -= OnDialogueCompleted; } public void ResetTrigger() { _hasTriggered = false; _dialogueState.Reset(); ResetZone(); } private void OnDestroy() { if (DialogueManager.Instance != null) DialogueManager.Instance.OnDialogueCompleted -= OnDialogueCompleted; } private void OnValidate() { if (_localDialogueUI == null) Debug.LogWarning($"[DialogueTriggerZone] '{gameObject.name}' has no Local Dialogue UI assigned. Assign the appropriate DialogueUI prefab variant (World, NPC, Room, Screen, etc.).", this); } private void OnDrawGizmosSelected() { if (_floatingWordAnchor != null) { Gizmos.color = Color.cyan; Gizmos.DrawWireSphere(_floatingWordAnchor.position, 0.2f); } } } }