/** * Plot Progression Module * Handles plot buttons (Random/Natural) UI setup and plot progression logic */ import { togglePlotButtons } from '../ui/layout.js'; import { extensionSettings, setIsPlotProgression } from '../../core/state.js'; import { DEFAULT_HTML_PROMPT } from '../generation/promptBuilder.js'; import { Generate } from '../../../../../../../script.js'; /** * Sets up the plot progression buttons inside the send form area. * @param {Function} handlePlotClick - Callback function to handle plot button clicks * @param {Function} handleEncounterClick - Callback function to handle encounter button click */ export function setupPlotButtons(handlePlotClick, handleEncounterClick) { // Remove existing buttons if any $('#rpg-plot-buttons').remove(); // Create wrapper if it doesn't exist (shared with other extensions like Spotify) if ($('#extension-buttons-wrapper').length === 0) { $('#send_form').prepend('
'); } // Create the button container const buttonHtml = ` `; // Insert into the wrapper $('#extension-buttons-wrapper').append(buttonHtml); // Add event handlers for buttons $('#rpg-plot-random').on('click', () => handlePlotClick('random')); $('#rpg-plot-natural').on('click', () => handlePlotClick('natural')); $('#rpg-encounter-button').on('click', () => handleEncounterClick()); // Show/hide based on setting togglePlotButtons(); } /** * Sends a plot progression request and appends the result to the last message. * @param {string} type - 'random' or 'natural' */ export async function sendPlotProgression(type) { if (!extensionSettings.enabled) { // console.log('[RPG Companion] Extension is disabled'); return; } // Disable buttons to prevent multiple clicks $('#rpg-plot-random, #rpg-plot-natural').prop('disabled', true).css('opacity', '0.5'); // Store original enabled state and temporarily disable extension // This prevents RPG tracker instructions from being injected during plot progression const wasEnabled = extensionSettings.enabled; extensionSettings.enabled = false; try { // console.log(`[RPG Companion] Sending ${type} plot progression request...`); // Build the prompt based on type let prompt = ''; if (type === 'random') { prompt = 'Actually, the scene is getting stale. Introduce {{random::stakes::a plot twist::a new character::a cataclysm::a fourth-wall-breaking joke::a sudden atmospheric phenomenon::a plot hook::a running gag::an ecchi scenario::Death from Discworld::a new stake::a drama::a conflict::an angered entity::a god::a vision::a prophetic dream::Il Dottore from Genshin Impact::a new development::a civilian in need::an emotional bit::a threat::a villain::an important memory recollection::a marriage proposal::a date idea::an angry horde of villagers with pitchforks::a talking animal::an enemy::a cliffhanger::a short omniscient POV shift to a completely different character::a quest::an unexpected revelation::a scandal::an evil clone::death of an important character::harm to an important character::a romantic setup::a gossip::a messenger::a plot point from the past::a plot hole::a tragedy::a ghost::an otherworldly occurrence::a plot device::a curse::a magic device::a rival::an unexpected pregnancy::a brothel::a prostitute::a new location::a past lover::a completely random thing::a what-if scenario::a significant choice::war::love::a monster::lewd undertones::Professor Mari::a travelling troupe::a secret::a fortune-teller::something completely different::a killer::a murder mystery::a mystery::a skill check::a deus ex machina::three raccoons in a trench coat::a pet::a slave::an orphan::a psycho::tentacles::"there is only one bed" trope::accidental marriage::a fun twist::a boss battle::sexy corn::an eldritch horror::a character getting hungry, thirsty, or exhausted::horniness::a need for a bathroom break need::someone fainting::an assassination attempt::a meta narration of this all being an out of hand DND session::a dungeon::a friend in need::an old friend::a small time skip::a scene shift::Aurora Borealis, at this time of year, at this time of day, at this part of the country::a grand ball::a surprise party::zombies::foreshadowing::a Spanish Inquisition (nobody expects it)::a natural plot progression}} to make things more interesting! Be creative, but stay grounded in the setting.'; } else { prompt = 'Actually, the scene is getting stale. Progress it, to make things more interesting! Reintroduce an unresolved plot point from the past, or push the story further towards the current main goal. Be creative, but stay grounded in the setting.'; } // Add HTML prompt if enabled if (extensionSettings.enableHtmlPrompt) { // Use custom HTML prompt if set, otherwise use default const htmlPromptText = extensionSettings.customHtmlPrompt || DEFAULT_HTML_PROMPT; prompt += '\n\n' + htmlPromptText; } // Set flag to indicate we're doing plot progression // This will be used by onMessageReceived to clear the prompt after generation completes setIsPlotProgression(true); // console.log('[RPG Companion] Calling Generate with continuation and plot prompt'); // console.log('[RPG Companion] Full prompt:', prompt); // Pass the prompt via options with the correct property name // Based on /continue slash command implementation, it uses quiet_prompt (underscore, not camelCase) const options = { quiet_prompt: prompt, // Use underscore notation, not camelCase quietToLoud: true }; // Call Generate with 'continue' type and our custom prompt await Generate('continue', options); // console.log('[RPG Companion] Plot progression generation triggered'); } catch (error) { console.error('[RPG Companion] Error sending plot progression:', error); setIsPlotProgression(false); } finally { // Restore original enabled state and re-enable buttons after a delay setTimeout(() => { extensionSettings.enabled = wasEnabled; $('#rpg-plot-random, #rpg-plot-natural').prop('disabled', false).css('opacity', '1'); }, 1000); } }