Hopp til hovedinnhold

Xstoryplayer [hot] (COMPLETE – Solution)

// apply a choice by target id makeChoice(targetId) if (!targetId) return false; // check if target exists in graph or fallback let targetNode = this.graph[targetId]; if (!targetNode) // if invalid, maybe use fallback as new node, but also preserve history targetNode = this.fallback; targetId = targetNode.id; // push current node into history before transition this.history.push(this.currentNodeId); this.currentNodeId = targetId; this._notify(); return true;

// full reset to start, clearing history reset() this.history = []; this.currentNodeId = this.startId; this._notify();

const STORY = // opening - the call to adventure "start": id: "start", text: "🌙 You stand at the edge of the Whispering Woods. Ancient runes glow softly on moss-covered stones. A hooded figure emerges from the mist, offering two paths. One leads to the Sunken Citadel, the other to the Starless Sea. Your pulse quickens — which destiny will you carve?", choices: [ text: "⚔️ Venture toward the Sunken Citadel (courage)", targetId: "citadel_gate" , text: "🌊 Follow the path to the Starless Sea (mystery)", targetId: "sea_shore" ] , "citadel_gate": id: "citadel_gate", text: "🏰 The Citadel looms before you, half-swallowed by thorny vines. A rusted gatekeeper automaton awakens with a grinding sound. 'State your purpose, wanderer.' You can attempt to outsmart it or fight the construct.", choices: [ text: "🧠 'I seek the Crown of Echoes' — deceive the guardian", targetId: "citadel_deceive" , text: "🗡️ Draw your blade and attack the guardian", targetId: "citadel_fight" ] , "citadel_deceive": id: "citadel_deceive", text: "🤫 You recite an old mage's password, and the automaton bows low. Inside, you find the Crown of Echoes, but touching it shows you visions of a fallen kingdom. You earn the right to become its phantom ruler. ✨ [GOOD ENDING: Phantom Sovereign]", choices: [] // ending node , "citadel_fight": id: "citadel_fight", text: "💥 Steel clashes against ancient alloy. You manage to destroy the automaton but trigger a collapse. As stones rain, you leap into a hidden tunnel and escape, but the Crown is lost forever. You wander as a scarred adventurer. 🏁 [NEUTRAL ENDING: Wandering Veteran]", choices: [] , "sea_shore": id: "sea_shore", text: "🌊 At the Starless Sea, the water is black as ink, reflecting no stars. A siren emerges, offering you a riddle. 'What can run but never walks, has a mouth but never talks?' Solve correctly or fall into an enchanted slumber.", choices: [ text: "💧 Answer: 'A river'", targetId: "siren_reward" , text: "😵 Answer incorrectly: 'The wind'", targetId: "siren_sleep" ] , "siren_reward": id: "siren_reward", text: "🧜‍♀️ The siren smiles, revealing a sunken library beneath the waves. You gain the Tome of Tides, granting you eternal wisdom and the ability to breathe underwater. You become the guardian of forgotten lore. 🌟 [GREAT ENDING: Lorekeeper of the Abyss]", choices: [] , "siren_sleep": id: "siren_sleep", text: "😴 The siren's lullaby wraps around you. You fall into a thousand-year dream, living countless imagined lives. When you wake, the world has moved on, but your spirit remains eternal dreamer. ✨ [MYSTICAL ENDING: The Eternal Dreamer]", choices: [] , // deeper branch after some choices: additional hidden node if the player comes from? Actually we create optional expand: but we can add alternative start path easter egg from reset? not needed. // Add an extra branch from "citadel_deceive"? no, already ending. But we want more replayability — also can add an extra node for a special choice in the middle but it's rich. // Additional twist: if the player reaches certain endings we might display flavor but it's fine. For extra "secret" we add a backdoor from any non-terminal? // But to demonstrate full feature, we also include a "secret" continuation: add a hidden path from sea_shore? Already covered. But to show multiple depth, we add an intermediate node after "citadel_deceive" no, its ending. good. ; xstoryplayer

// extra polish: Keyboard navigation? add simple number key support for choices (1-9) function handleKeyboard(e) const key = e.key; if (key >= '1' && key <= '9') const index = parseInt(key, 10) - 1; const btns = document.querySelectorAll('.choice-btn'); if (btns[index] && btns[index].dataset && btns[index].dataset.target) btns[index].click(); e.preventDefault();

<div class="story-core"> <div class="story-text" id="storyText"> Loading the realm of stories... </div> <div class="choices-area" id="choicesContainer"> <!-- dynamic choice buttons appear here --> </div> </div> // apply a choice by target id makeChoice(targetId) if (

// DOM elements const storyTextEl = document.getElementById("storyText"); const choicesContainer = document.getElementById("choicesContainer"); const undoBtn = document.getElementById("undoBtn"); const resetBtn = document.getElementById("resetBtn"); const historyDepthSpan = document.getElementById("historyDepth"); const nodeCounterSpan = document.getElementById("nodeCounter");

/* mobile adjustments */ @media (max-width: 550px) .story-player border-radius: 1.8rem; .story-core padding: 1.5rem; .story-text font-size: 1.2rem; .choice-btn padding: 12px 16px; font-size: 0.9rem; .control-bar padding: 1rem 1.5rem; One leads to the Sunken Citadel, the other

// Extra secret node: we can add a bonus branch after a second-level choice? already, but for safety and demonstration we also add a "hidden" path if player clicks undo then makes different route etc. But story is solid.