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);
}
}
}