diff options
author | elioat <elioat@tilde.institute> | 2024-12-01 15:00:37 -0500 |
---|---|---|
committer | elioat <elioat@tilde.institute> | 2024-12-01 15:00:37 -0500 |
commit | ecff6d35e51ee35dfb34df03acdc9ceb244f7204 (patch) | |
tree | fb4411e2ba51b30b728fa720964e673607ece91b /html/story-teller | |
parent | 1768e1fd0ddc4a059869caa8ff4b08b5734e3982 (diff) | |
download | tour-ecff6d35e51ee35dfb34df03acdc9ceb244f7204.tar.gz |
*
Diffstat (limited to 'html/story-teller')
-rw-r--r-- | html/story-teller/index.html | 13 | ||||
-rw-r--r-- | html/story-teller/js/game.js | 47 | ||||
-rw-r--r-- | html/story-teller/js/renderer.js | 44 | ||||
-rw-r--r-- | html/story-teller/js/scenes.js | 37 | ||||
-rw-r--r-- | html/story-teller/js/state.js | 43 | ||||
-rw-r--r-- | html/story-teller/styles.css | 8 |
6 files changed, 192 insertions, 0 deletions
diff --git a/html/story-teller/index.html b/html/story-teller/index.html new file mode 100644 index 0000000..edd44c2 --- /dev/null +++ b/html/story-teller/index.html @@ -0,0 +1,13 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>Choice-based Game</title> + <link rel="stylesheet" href="./styles.css"> +</head> +<body> + <div id="app"></div> + <script type="module" src="./js/game.js"></script> +</body> +</html> diff --git a/html/story-teller/js/game.js b/html/story-teller/js/game.js new file mode 100644 index 0000000..d3e8144 --- /dev/null +++ b/html/story-teller/js/game.js @@ -0,0 +1,47 @@ +import { createGameState, saveGameState, loadGameState, resetGameState } from './state.js'; +import { renderScene } from './renderer.js'; + +let gameState = loadGameState(); // Load state on initialization + +const updateAndRender = (newState) => { + Object.assign(gameState, newState); + saveGameState(gameState); // Save automatically after each update + renderScene(gameState, updateAndRender); +}; + +document.addEventListener('DOMContentLoaded', () => { + const app = document.getElementById('app'); + + app.innerHTML = ''; + + const controls = document.createElement('div'); + controls.id = 'controls'; + + const saveButton = document.createElement('button'); + saveButton.textContent = 'Save Progress'; + saveButton.onclick = () => saveGameState(gameState); + + const loadButton = document.createElement('button'); + loadButton.textContent = 'Load Progress'; + loadButton.onclick = () => { + const loadedState = loadGameState(); + updateAndRender(loadedState); + }; + + const resetButton = document.createElement('button'); + resetButton.textContent = 'Reset Game'; + resetButton.onclick = () => { + if (confirm('Are you sure you want to reset the game? This will erase all progress.')) { + gameState = resetGameState(); // Clear state and reset game + updateAndRender(gameState); + } + }; + + controls.appendChild(saveButton); + controls.appendChild(loadButton); + controls.appendChild(resetButton); + + app.appendChild(controls); + + updateAndRender(gameState); +}); diff --git a/html/story-teller/js/renderer.js b/html/story-teller/js/renderer.js new file mode 100644 index 0000000..82ab004 --- /dev/null +++ b/html/story-teller/js/renderer.js @@ -0,0 +1,44 @@ +import { scenes } from './scenes.js'; + +export const renderScene = (state, updateState) => { + const scene = scenes[state.currentScene]; + if (!scene) throw new Error(`Scene "${state.currentScene}" not found`); + + const app = document.getElementById('app'); + app.innerHTML = ''; + + const description = document.createElement('p'); + description.textContent = scene.description; + app.appendChild(description); + + const inventory = document.createElement('div'); + inventory.textContent = `Inventory: ${Array.from(state.inventory).join(', ') || 'None'}`; + app.appendChild(inventory); + + const log = document.createElement('div'); + log.innerHTML = `<strong>Action Log:</strong><br>${state.actionLog.join('<br>')}`; + app.appendChild(log); + + scene.choices.forEach((choice) => { + if (choice.condition && !choice.condition(state)) { + return; // Skip choices that don't meet their conditions + } + + const button = document.createElement('button'); + button.textContent = choice.text; + button.onclick = () => { + state.actionLog.push(`You chose: "${choice.text}"`); + if (choice.action) choice.action(state); // Perform any action tied to the choice + + // Consume items if specified + if (choice.consume) { + choice.consume.forEach((item) => state.inventory.delete(item)); + state.actionLog.push(`You used: ${choice.consume.join(', ')}`); + } + + if (choice.nextScene) state.currentScene = choice.nextScene; + updateState(state); // Re-render after state update + }; + app.appendChild(button); + }); +}; diff --git a/html/story-teller/js/scenes.js b/html/story-teller/js/scenes.js new file mode 100644 index 0000000..7b8db35 --- /dev/null +++ b/html/story-teller/js/scenes.js @@ -0,0 +1,37 @@ +export const scenes = { + start: { + description: "You are standing in a dark cave. There's a faint glimmer in the distance, and a torch on the ground.", + choices: [ + { text: "Explore further", nextScene: "deepCave" }, + { text: "Pick up the torch", action: (state) => state.inventory.add("torch") }, + { + text: "Use a torch to illuminate the cave", + nextScene: "litCave", + condition: (state) => state.inventory.has("torch"), + consume: ["torch"] + }, + ], + }, + deepCave: { + description: "The darkness becomes overwhelming. You can't proceed further.", + choices: [ + { text: "Go back", nextScene: "start" }, + ], + }, + litCave: { + description: "With the torchlight, you see glittering gemstones embedded in the walls.", + choices: [ + { text: "Pick up the key", action: (state) => state.inventory.add("key") }, + { text: "Collect a gemstone", action: (state) => state.inventory.add("gemstone") }, + { text: "Go back", nextScene: "start" }, + { text: "Go deeper into the cave", nextScene: "treasureRoom", condition: (state) => state.inventory.has("key") }, + ], + }, + treasureRoom: { + description: "You find a room filled with treasure. You are rich beyond your wildest dreams.", + choices: [ + { text: "Swim in the treasure", nextScene: "treasureRoom" }, + ], + }, + }; + \ No newline at end of file diff --git a/html/story-teller/js/state.js b/html/story-teller/js/state.js new file mode 100644 index 0000000..e6c4fe7 --- /dev/null +++ b/html/story-teller/js/state.js @@ -0,0 +1,43 @@ +export const createGameState = () => ({ + currentScene: 'start', + inventory: new Set(), + actionLog: [], + collectedItems: new Set(), + }); + + + +export const updateGameState = (state, updates) => ({ + ...state, + ...updates, +}); + +const STORAGE_KEY = 'gameState'; + +export const saveGameState = (state) => { + const stateToSave = { + currentScene: state.currentScene, + inventory: Array.from(state.inventory), + actionLog: state.actionLog, + }; + localStorage.setItem(STORAGE_KEY, JSON.stringify(stateToSave)); +}; + +export const loadGameState = () => { + const savedState = localStorage.getItem(STORAGE_KEY); + if (savedState) { + const parsedState = JSON.parse(savedState); + return { + currentScene: parsedState.currentScene, + inventory: new Set(parsedState.inventory), + actionLog: parsedState.actionLog, + }; + } + return createGameState(); +}; + +export const resetGameState = () => { + localStorage.removeItem(STORAGE_KEY); + return createGameState(); + }; + \ No newline at end of file diff --git a/html/story-teller/styles.css b/html/story-teller/styles.css new file mode 100644 index 0000000..51852ba --- /dev/null +++ b/html/story-teller/styles.css @@ -0,0 +1,8 @@ +body { + font-family: 'Roboto', sans-serif; + background-color: #f0f0f0; + margin: 0 auto; + display: block; + padding: 0; + max-width: 42em; +} \ No newline at end of file |