using UnityEngine; using UnityEngine.InputSystem; using Yarn.Unity; using NightclubArcadia.Core; namespace NightclubArcadia.Dialogue { /// /// Trigger-zone interactable: player walks in range, presses E, and this /// starts the given Yarn node. The reverse of DialogueTransitionController's /// <> — this is the "step into dialogue" half of the loop. /// public class DialogueInteractable : MonoBehaviour { [SerializeField] private DialogueRunner dialogueRunner; [SerializeField] private GameObject dialogueUI; [SerializeField] private string yarnNodeName = "Bartender_Chat"; private bool playerInRange; private InputAction interactAction; void Awake() { // Best-effort and silent; the real lookup happens at the point of use, since // Systems may not have loaded when this level object awakes. See Runner. dialogueRunner = SceneServices.TryResolve(dialogueRunner); interactAction = new InputAction("Interact"); interactAction.AddBinding("/e"); interactAction.AddBinding("/buttonNorth"); interactAction.performed += _ => { if (playerInRange) { StartConversation(); } }; } /// /// The dialogue runner, resolved on demand rather than in Awake, so that load /// order between this level scene and Systems does not matter. Cached once found. /// DialogueRunner Runner => dialogueRunner != null ? dialogueRunner : dialogueRunner = SceneServices.TryResolve(null); void OnEnable() => interactAction?.Enable(); void OnDisable() => interactAction?.Disable(); void OnTriggerEnter(Collider other) { if (other.CompareTag("Player")) { playerInRange = true; } } void OnTriggerExit(Collider other) { if (other.CompareTag("Player")) { playerInRange = false; } } async void StartConversation() { var runner = Runner; if (runner == null) { Debug.LogError( $"[DialogueInteractable] {name}: no DialogueRunner in any loaded scene. " + "It lives in Systems.unity — open Bootstrap, or Tools → Nightclub Arcadia → " + "Open Game Scenes.", this); return; } // Player controls are locked by DialogueTransitionController off the // runner's onDialogueStart event — nothing to do for that here. if (DialogueUIVisibility.Show(dialogueUI)) { // Only reached if the UI was found deactivated; give TMP a // frame to re-cache its Canvas in OnEnable before any text is // generated. await Awaitable.NextFrameAsync(); } await runner.StartDialogue(yarnNodeName); } } }