feat: Add automatic conversation closing for graceful #end_conversation tag

Implemented proper handling for the #end_conversation tag to automatically
close the conversation UI without requiring manual ESC key press.

Changes:
1. Added event listener for 'npc-conversation-ended' event in setupEventListeners()
   - Saves NPC state when event is received
   - Automatically ends minigame and returns to game
   - Verifies event is for current NPC

2. Updated showCurrentDialogue() to detect graceful conversation endings
   - Checks for #end_conversation tag when story reaches hasEnded
   - If tag present, waits for event handler instead of showing manual exit message
   - Preserves manual exit message for unexpected/error END states

Flow:
- Ink script: #end_conversation -> DONE
- PhoneChatConversation processes tag and dispatches npc-conversation-ended event
- PersonChatMinigame receives event and automatically closes
- Player sees smooth transition back to game

This eliminates the "(End of conversation - press ESC to exit)" message
for normal conversation endings while preserving it as a safety fallback.
This commit is contained in:
Z. Cliffe Schreuders
2025-11-19 13:44:30 +00:00
parent b0c56f2eca
commit 85b620cfcd

View File

@@ -192,7 +192,7 @@ export class PersonChatMinigame extends MinigameScene {
this.handleChoice(choiceIndex);
}
});
// Continue button click handler
if (this.ui.elements.continueButton) {
this.addEventListener(this.ui.elements.continueButton, 'click', (e) => {
@@ -201,6 +201,26 @@ export class PersonChatMinigame extends MinigameScene {
this.handleContinueButtonClick();
});
}
// Listen for conversation end event from the conversation handler
this.addEventListener(window, 'npc-conversation-ended', (e) => {
console.log(`👋 Received npc-conversation-ended event for ${e.detail.npcId}`);
// Verify this event is for our current conversation
if (e.detail.npcId === this.npcId) {
console.log(`✅ Ending minigame - conversation state preserved at mission_hub`);
// Save state before exiting
if (this.inkEngine && this.inkEngine.story) {
npcConversationStateManager.saveNPCState(this.npcId, this.inkEngine.story);
}
// End the minigame and return to game
if (window.MinigameFramework) {
window.MinigameFramework.endMinigame(true, { conversationEnded: true });
}
}
});
}
/**
@@ -368,17 +388,28 @@ export class PersonChatMinigame extends MinigameScene {
*/
showCurrentDialogue() {
if (!this.conversation) return;
try {
// Get current content without advancing
const result = this.conversation.continue();
// Store result for later use
this.lastResult = result;
// Check if story has ended
if (result.hasEnded) {
// Story reached an END - save state and show message
// Check if this is a graceful conversation end (with #end_conversation tag)
const hasEndConversationTag = result.tags?.some(tag =>
tag.trim().toLowerCase() === 'end_conversation'
);
if (hasEndConversationTag) {
// Graceful end - the npc-conversation-ended event will handle closing
console.log('👋 Graceful conversation end detected - waiting for event handler');
return;
}
// Otherwise, it's an unexpected END - save state and show manual exit message
// Player should press ESC to exit and return to hub
if (this.inkEngine && this.inkEngine.story) {
npcConversationStateManager.saveNPCState(this.npcId, this.inkEngine.story);