diff --git a/index.js b/index.js index 0cd0cb0..afd3d80 100644 --- a/index.js +++ b/index.js @@ -332,6 +332,11 @@ async function initUI() { updateSectionVisibility(); }); + $('#rpg-toggle-narrator-mode').on('change', function() { + extensionSettings.narratorMode = $(this).prop('checked'); + saveSettings(); + }); + $('#rpg-toggle-inventory').on('change', function() { extensionSettings.showInventory = $(this).prop('checked'); saveSettings(); @@ -420,6 +425,10 @@ async function initUI() { $('#rpg-avatar-llm-instruction').on('input', function() { extensionSettings.avatarLLMCustomInstruction = $(this).val().trim(); saveSettings(); + $('#rpg-toggle-dice-display').on('change', function() { + extensionSettings.showDiceDisplay = $(this).prop('checked'); + saveSettings(); + updateDiceDisplay(); }); $('#rpg-manual-update').on('click', async function() { @@ -502,6 +511,7 @@ async function initUI() { $('#rpg-toggle-user-stats').prop('checked', extensionSettings.showUserStats); $('#rpg-toggle-info-box').prop('checked', extensionSettings.showInfoBox); $('#rpg-toggle-thoughts').prop('checked', extensionSettings.showCharacterThoughts); + $('#rpg-toggle-narrator-mode').prop('checked', extensionSettings.narratorMode); $('#rpg-toggle-inventory').prop('checked', extensionSettings.showInventory); $('#rpg-toggle-quests').prop('checked', extensionSettings.showQuests); $('#rpg-toggle-thoughts-in-chat').prop('checked', extensionSettings.showThoughtsInChat); @@ -525,6 +535,7 @@ async function initUI() { $('#rpg-avatar-options').hide(); } + $('#rpg-toggle-dice-display').prop('checked', extensionSettings.showDiceDisplay); $('#rpg-stat-bar-color-low').val(extensionSettings.statBarColorLow); $('#rpg-stat-bar-color-high').val(extensionSettings.statBarColorHigh); $('#rpg-theme-select').val(extensionSettings.theme); diff --git a/src/core/state.js b/src/core/state.js index fdeef1b..03fabf9 100644 --- a/src/core/state.js +++ b/src/core/state.js @@ -21,6 +21,7 @@ export let extensionSettings = { showInventory: true, // Show inventory section (v2 system) showQuests: true, // Show quests section showThoughtsInChat: true, // Show thoughts overlay in chat + narratorMode: false, // Use character card as narrator instead of fixed character references enableHtmlPrompt: false, // Enable immersive HTML prompt injection customHtmlPrompt: '', // Custom HTML prompt text (empty = use default) skipInjectionsForGuided: 'none', // skip injections for instruct injections and quiet prompts (GuidedGenerations compatibility) @@ -158,6 +159,7 @@ export let extensionSettings = { cha: 10 }, lastDiceRoll: null, // Store last dice roll result + showDiceDisplay: true, // Show the "Last Roll" display in the panel collapsedInventoryLocations: [], // Array of collapsed storage location names inventoryViewModes: { onPerson: 'list', // 'list' or 'grid' view mode for On Person section diff --git a/src/i18n/en.json b/src/i18n/en.json index 3cc46e4..f657e0e 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -29,6 +29,8 @@ "template.settingsModal.display.showUserStats": "Show User Stats", "template.settingsModal.display.showInfoBox": "Show Info Box", "template.settingsModal.display.showPresentCharacters": "Show Present Characters", + "template.settingsModal.display.narratorMode": "Narrator Mode", + "template.settingsModal.display.narratorModeNote": "Use character card as narrator. Infer characters from context instead of using fixed character references.", "template.settingsModal.display.showInventory": "Show Inventory", "template.settingsModal.display.showQuests": "Show Quests", "template.settingsModal.display.showThoughtsInChat": "Show Thoughts in Chat", @@ -39,6 +41,8 @@ "template.settingsModal.display.enableAnimationsNote": "Smooth transitions for stats, content updates, and dice rolls", "template.settingsModal.display.showPlotProgressionButtons": "Show Plot Progression Buttons", "template.settingsModal.display.showPlotProgressionButtonsNote": "Display buttons above chat input for plot progression prompts", + "template.settingsModal.display.showDiceDisplay": "Show Dice Roll Display", + "template.settingsModal.display.showDiceDisplayNote": "Display the \"Last Roll\" indicator in the panel.", "template.settingsModal.display.enableDebugMode": "Enable Debug Mode", "template.settingsModal.display.enableDebugModeNote": "Shows parser logs in a mobile-friendly UI panel. Useful for troubleshooting. Look for the red bug button.", "template.settingsModal.display.autoGenerateAvatars": "Auto-generate Missing Avatars", diff --git a/src/systems/features/dice.js b/src/systems/features/dice.js index fe5a0c4..0f8bbb9 100644 --- a/src/systems/features/dice.js +++ b/src/systems/features/dice.js @@ -85,6 +85,15 @@ export async function executeRollCommand(command) { * Updates the dice display in the sidebar. */ export function updateDiceDisplay() { + // Hide the entire dice display if showDiceDisplay is false + const $display = $('#rpg-dice-display'); + if (!extensionSettings.showDiceDisplay) { + $display.hide(); + return; + } else { + $display.show(); + } + const lastRoll = extensionSettings.lastDiceRoll; const label = i18n.getTranslation('template.mainPanel.lastRoll') || 'Last Roll: '; const noneValue = i18n.getTranslation('global.none') || 'None'; @@ -98,6 +107,7 @@ export function updateDiceDisplay() { /** * Clears the last dice roll. + * Called when the x button is clicked. */ export function clearDiceRoll() { extensionSettings.lastDiceRoll = null; diff --git a/src/systems/generation/promptBuilder.js b/src/systems/generation/promptBuilder.js index 658af1f..28cc9c8 100644 --- a/src/systems/generation/promptBuilder.js +++ b/src/systems/generation/promptBuilder.js @@ -23,6 +23,27 @@ export const DEFAULT_HTML_PROMPT = `If appropriate, include inline HTML, CSS, an async function getCharacterCardsInfo() { let characterInfo = ''; + // Narrator mode: use character card as narrator context, infer characters from story context + if (extensionSettings.narratorMode) { + if (this_chid !== undefined && characters && characters[this_chid]) { + const character = characters[this_chid]; + characterInfo += 'You are acting as the narrator for this story. The narrator card provides context for the story tone and style:\n\n'; + characterInfo += `\n`; + + if (character.description) { + characterInfo += `${character.description}\n`; + } + + if (character.personality) { + characterInfo += `${character.personality}\n`; + } + + characterInfo += `\n\n`; + characterInfo += `Infer the identity and details of characters present in each scene from the story context below. Do not use fixed character references - instead, identify characters naturally based on their actions, dialogue, and descriptions in the narrative.\n\n`; + } + return characterInfo; + } + // Check if in group chat if (selected_group) { // Find the current group directly from the groups array @@ -331,7 +352,11 @@ export function generateTrackerInstructions(includeHtmlPrompt = true, includeCon .join(' | '); // Character block format - instructions += `- [Name (do not include ${userName}; state "Unavailable" if no major characters are present in the scene)]\n`; + if (extensionSettings.narratorMode) { + instructions += `- [Character Name (infer from story context; do not include ${userName}; state "Unavailable" if no other characters are present in the scene)]\n`; + } else { + instructions += `- [Name (do not include ${userName}; state "Unavailable" if no major characters are present in the scene)]\n`; + } // Details line with emoji and custom fields if (fieldPlaceholders) { @@ -358,7 +383,11 @@ export function generateTrackerInstructions(includeHtmlPrompt = true, includeCon instructions += `${thoughtsName}: [${thoughtsDescription}]\n`; } - instructions += `- … (Repeat the format above for every other present major character)\n`; + if (extensionSettings.narratorMode) { + instructions += `- … (Repeat the format above for every other character present in the scene, inferred from story context)\n`; + } else { + instructions += `- … (Repeat the format above for every other present major character)\n`; + } instructions += codeBlockMarker + '\n\n'; } diff --git a/src/systems/rendering/thoughts.js b/src/systems/rendering/thoughts.js index b75f5d8..f52bf33 100644 --- a/src/systems/rendering/thoughts.js +++ b/src/systems/rendering/thoughts.js @@ -454,8 +454,8 @@ export function renderThoughts() { debugLog('[RPG Thoughts] ==================== BUILDING HTML ===================='); debugLog('[RPG Thoughts] Starting HTML generation for', presentCharacters.length + ' characters'); - // If no characters parsed, show a placeholder editable card - if (presentCharacters.length === 0) { + // If no characters parsed, show a placeholder editable card (if narrator mode is disabled) + if (presentCharacters.length === 0 && !extensionSettings.narratorMode) { debugLog('[RPG Thoughts] ⚠ No characters parsed - showing placeholder card'); // Get default character portrait let defaultPortrait = FALLBACK_AVATAR_DATA_URI; diff --git a/template.html b/template.html index b115459..4da836a 100644 --- a/template.html +++ b/template.html @@ -180,6 +180,14 @@ Show Present Characters + + + Use character card as narrator. Infer characters from context instead of using fixed character references. + +