XTaylorSpenceX

Echo Chamber Escape

Oct 9th, 2025
68
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
HTML 29.07 KB | None | 0 0
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4.     <meta charset="UTF-8">
  5.     <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6.     <title>Echo Chamber Escape</title>
  7.     <style>
  8.         * {
  9.             margin: 0;
  10.             padding: 0;
  11.             box-sizing: border-box;
  12.         }
  13.  
  14.         body {
  15.             background: linear-gradient(135deg, #0a0e27 0%, #1a0b2e 50%, #16213e 100%);
  16.             color: #e0e0e0;
  17.             font-family: 'Courier New', monospace;
  18.             min-height: 100vh;
  19.             display: flex;
  20.             justify-content: center;
  21.             align-items: center;
  22.             overflow: hidden;
  23.             position: relative;
  24.         }
  25.  
  26.         body::before {
  27.             content: '';
  28.             position: absolute;
  29.             width: 200%;
  30.             height: 200%;
  31.             background: repeating-linear-gradient(
  32.                 0deg,
  33.                 transparent,
  34.                 transparent 2px,
  35.                 rgba(255, 0, 255, 0.03) 2px,
  36.                 rgba(255, 0, 255, 0.03) 4px
  37.             );
  38.             animation: scanlines 8s linear infinite;
  39.             pointer-events: none;
  40.         }
  41.  
  42.         @keyframes scanlines {
  43.             0% { transform: translateY(0); }
  44.             100% { transform: translateY(10px); }
  45.         }
  46.  
  47.         .game-container {
  48.             width: 95%;
  49.             max-width: 1000px;
  50.             background: rgba(10, 14, 39, 0.9);
  51.             border: 2px solid rgba(0, 255, 255, 0.3);
  52.             border-radius: 15px;
  53.             padding: 30px;
  54.             box-shadow:
  55.                 0 0 50px rgba(0, 255, 255, 0.2),
  56.                 inset 0 0 30px rgba(255, 0, 255, 0.1);
  57.             position: relative;
  58.             z-index: 1;
  59.         }
  60.  
  61.         .title {
  62.             font-size: 2.5em;
  63.             text-align: center;
  64.             background: linear-gradient(45deg, #00ffff, #ff00ff, #00ffff);
  65.             background-size: 200% 200%;
  66.             -webkit-background-clip: text;
  67.             -webkit-text-fill-color: transparent;
  68.             animation: gradient 3s ease infinite;
  69.             margin-bottom: 20px;
  70.             text-shadow: 0 0 30px rgba(0, 255, 255, 0.5);
  71.         }
  72.  
  73.         @keyframes gradient {
  74.             0% { background-position: 0% 50%; }
  75.             50% { background-position: 100% 50%; }
  76.             100% { background-position: 0% 50%; }
  77.         }
  78.  
  79.         .room-display {
  80.             background: rgba(0, 0, 0, 0.5);
  81.             border: 1px solid rgba(0, 255, 255, 0.2);
  82.             border-radius: 10px;
  83.             padding: 20px;
  84.             margin-bottom: 20px;
  85.             min-height: 150px;
  86.             position: relative;
  87.             overflow: hidden;
  88.         }
  89.  
  90.         .room-name {
  91.             color: #00ffff;
  92.             font-size: 1.3em;
  93.             margin-bottom: 10px;
  94.             text-transform: uppercase;
  95.             letter-spacing: 2px;
  96.         }
  97.  
  98.         .room-description {
  99.             color: #b0b0b0;
  100.             line-height: 1.6;
  101.             margin-bottom: 15px;
  102.         }
  103.  
  104.         .passages-container {
  105.             background: rgba(255, 0, 255, 0.05);
  106.             border: 1px solid rgba(255, 0, 255, 0.2);
  107.             border-radius: 10px;
  108.             padding: 15px;
  109.             margin-bottom: 20px;
  110.         }
  111.  
  112.         .passages-label {
  113.             color: #ff00ff;
  114.             font-style: italic;
  115.             margin-bottom: 10px;
  116.         }
  117.  
  118.         .passage-buttons {
  119.             display: flex;
  120.             flex-wrap: wrap;
  121.             gap: 10px;
  122.         }
  123.  
  124.         .passage-btn {
  125.             background: linear-gradient(135deg, rgba(0, 255, 255, 0.1), rgba(255, 0, 255, 0.1));
  126.             border: 1px solid rgba(0, 255, 255, 0.3);
  127.             border-radius: 8px;
  128.             color: #00ffff;
  129.             padding: 10px 15px;
  130.             font-family: inherit;
  131.             cursor: pointer;
  132.             transition: all 0.3s;
  133.             flex: 0 0 auto;
  134.             min-width: 100px;
  135.         }
  136.  
  137.         .passage-btn:hover {
  138.             background: linear-gradient(135deg, rgba(0, 255, 255, 0.3), rgba(255, 0, 255, 0.3));
  139.             transform: scale(1.05);
  140.             box-shadow: 0 0 20px rgba(0, 255, 255, 0.4);
  141.         }
  142.  
  143.         .echo-display {
  144.             background: rgba(0, 0, 0, 0.6);
  145.             border: 1px solid rgba(255, 0, 255, 0.2);
  146.             border-radius: 10px;
  147.             padding: 15px;
  148.             margin-bottom: 20px;
  149.             min-height: 100px;
  150.             max-height: 200px;
  151.             overflow-y: auto;
  152.             position: relative;
  153.         }
  154.  
  155.         .echo-line {
  156.             margin: 5px 0;
  157.             opacity: 0;
  158.             animation: fadeInEcho 0.5s forwards;
  159.             position: relative;
  160.         }
  161.  
  162.         @keyframes fadeInEcho {
  163.             0% {
  164.                 opacity: 0;
  165.                 transform: translateX(-20px);
  166.             }
  167.             100% {
  168.                 opacity: 1;
  169.                 transform: translateX(0);
  170.             }
  171.         }
  172.  
  173.         .original-echo {
  174.             color: #00ffff;
  175.             display: inline-block;
  176.             margin-right: 10px;
  177.         }
  178.  
  179.         .distorted-echo {
  180.             color: #ff00ff;
  181.             display: inline-block;
  182.             position: relative;
  183.             animation: glitch 2s infinite;
  184.         }
  185.  
  186.         @keyframes glitch {
  187.             0%, 100% { text-shadow: 0 0 5px rgba(255, 0, 255, 0.5); }
  188.             25% { text-shadow: -2px 0 #ff00ff, 2px 0 #00ffff; }
  189.             50% { text-shadow: 2px 0 #ff00ff, -2px 0 #00ffff; }
  190.             75% { text-shadow: 0 0 10px rgba(255, 0, 255, 0.8); }
  191.         }
  192.  
  193.         .echo-trail {
  194.             position: absolute;
  195.             color: rgba(255, 0, 255, 0.3);
  196.             animation: trail 2s linear forwards;
  197.             pointer-events: none;
  198.             z-index: -1;
  199.         }
  200.  
  201.         @keyframes trail {
  202.             0% {
  203.                 opacity: 0.5;
  204.                 transform: translateX(0) scale(1);
  205.             }
  206.             100% {
  207.                 opacity: 0;
  208.                 transform: translateX(50px) scale(0.8);
  209.             }
  210.         }
  211.  
  212.         .input-section {
  213.             display: flex;
  214.             gap: 10px;
  215.         }
  216.  
  217.         #command-input {
  218.             flex: 1;
  219.             background: rgba(0, 0, 0, 0.7);
  220.             border: 2px solid rgba(0, 255, 255, 0.3);
  221.             border-radius: 5px;
  222.             color: #00ffff;
  223.             padding: 12px;
  224.             font-size: 1em;
  225.             font-family: inherit;
  226.             transition: all 0.3s;
  227.         }
  228.  
  229.         #command-input:focus {
  230.             outline: none;
  231.             border-color: #00ffff;
  232.             box-shadow: 0 0 20px rgba(0, 255, 255, 0.3);
  233.         }
  234.  
  235.         #submit-btn {
  236.             background: linear-gradient(45deg, #00ffff, #ff00ff);
  237.             border: none;
  238.             border-radius: 5px;
  239.             color: white;
  240.             padding: 12px 25px;
  241.             font-size: 1em;
  242.             font-family: inherit;
  243.             cursor: pointer;
  244.             transition: all 0.3s;
  245.             text-transform: uppercase;
  246.             letter-spacing: 1px;
  247.         }
  248.  
  249.         #submit-btn:hover {
  250.             transform: scale(1.05);
  251.             box-shadow: 0 0 25px rgba(255, 0, 255, 0.5);
  252.         }
  253.  
  254.         .status {
  255.             text-align: center;
  256.             margin-top: 20px;
  257.             padding: 10px;
  258.             background: rgba(0, 255, 255, 0.1);
  259.             border-radius: 5px;
  260.             color: #00ffff;
  261.         }
  262.  
  263.         .victory, .defeat {
  264.             position: fixed;
  265.             top: 50%;
  266.             left: 50%;
  267.             transform: translate(-50%, -50%);
  268.             background: linear-gradient(135deg, #0a0e27, #1a0b2e);
  269.             padding: 40px;
  270.             border-radius: 20px;
  271.             text-align: center;
  272.             z-index: 1000;
  273.             display: none;
  274.             animation: victoryPulse 1s ease-in-out;
  275.         }
  276.  
  277.         .victory {
  278.             border: 3px solid #00ffff;
  279.         }
  280.  
  281.         .defeat {
  282.             border: 3px solid #ff0000;
  283.         }
  284.  
  285.         @keyframes victoryPulse {
  286.             0% { transform: translate(-50%, -50%) scale(0); }
  287.             50% { transform: translate(-50%, -50%) scale(1.1); }
  288.             100% { transform: translate(-50%, -50%) scale(1); }
  289.         }
  290.  
  291.         .victory h2 {
  292.             color: #00ffff;
  293.             font-size: 2em;
  294.             margin-bottom: 20px;
  295.         }
  296.  
  297.         .defeat h2 {
  298.             color: #ff0000;
  299.             font-size: 2em;
  300.             margin-bottom: 20px;
  301.         }
  302.  
  303.         .help-text {
  304.             color: #808080;
  305.             font-size: 0.9em;
  306.             text-align: center;
  307.             margin-top: 15px;
  308.             font-style: italic;
  309.         }
  310.  
  311.         ::-webkit-scrollbar {
  312.             width: 8px;
  313.         }
  314.  
  315.         ::-webkit-scrollbar-track {
  316.             background: rgba(0, 0, 0, 0.3);
  317.             border-radius: 4px;
  318.         }
  319.  
  320.         ::-webkit-scrollbar-thumb {
  321.             background: linear-gradient(45deg, #00ffff, #ff00ff);
  322.             border-radius: 4px;
  323.         }
  324.     </style>
  325. </head>
  326. <body>
  327.     <div class="game-container">
  328.         <h1 class="title">ECHO CHAMBER ESCAPE</h1>
  329.        
  330.         <div class="room-display" id="room-display">
  331.             <div class="room-name" id="room-name">Loading...</div>
  332.             <div class="room-description" id="room-description"></div>
  333.         </div>
  334.  
  335.         <div class="passages-container">
  336.             <div class="passages-label">Passages:</div>
  337.             <div class="passage-buttons" id="passage-buttons"></div>
  338.         </div>
  339.  
  340.         <div class="echo-display" id="echo-display">
  341.             <div style="color: #666; text-align: center;">Your echoes will appear here...</div>
  342.         </div>
  343.  
  344.         <div class="input-section">
  345.             <input type="text" id="command-input" placeholder="Type a direction or command..." autofocus>
  346.             <button id="submit-btn">ECHO</button>
  347.         </div>
  348.  
  349.         <div class="status" id="status">
  350.             Moves: <span id="move-count">0</span> | Rooms Explored: <span id="rooms-explored">1</span>/20
  351.         </div>
  352.  
  353.         <div class="help-text">
  354.             Tip: Click passages to travel, or type directions to move. Find the Victory Room to win!
  355.         </div>
  356.     </div>
  357.  
  358.     <div class="victory" id="victory">
  359.         <h2>🎉 ESCAPE SUCCESSFUL! 🎉</h2>
  360.         <p style="color: #ff00ff;">You've mastered the echoes and found freedom!</p>
  361.         <p style="color: #00ffff;">Total moves: <span id="final-moves"></span></p>
  362.         <button id="restart-btn" style="margin-top: 20px; padding: 10px 20px; background: linear-gradient(45deg, #00ffff, #ff00ff); border: none; border-radius: 5px; color: white; cursor: pointer;">PLAY AGAIN</button>
  363.     </div>
  364.  
  365.     <div class="defeat" id="defeat">
  366.         <h2>💀 TRAPPED FOREVER! 💀</h2>
  367.         <p style="color: #ff6b6b;">The Echo Chamber has consumed you...</p>
  368.         <p style="color: #ff0000;">Total moves: <span id="defeat-moves"></span></p>
  369.         <button id="restart-btn-defeat" style="margin-top: 20px; padding: 10px 20px; background: linear-gradient(45deg, #ff0000, #ff6b6b); border: none; border-radius: 5px; color: white; cursor: pointer;">TRY AGAIN</button>
  370.     </div>
  371.  
  372.     <script>
  373.         class EchoChamberGame {
  374.             constructor() {
  375.                 this.moves = 0;
  376.                 this.currentRoom = 'room1';
  377.                 this.echoHistory = [];
  378.                 this.visitedRooms = new Set(['room1']);
  379.                 this.victoryRoom = '';
  380.                 this.defeatRoom = '';
  381.                
  382.                 // Define room properties
  383.                 this.roomNames = [
  384.                     'The Resonant Entrance', 'The Harmonic Hallway', 'The Whispering Gallery',
  385.                     'The Lexicon Library', 'The Echo Chamber Core', 'The Sonic Vault',
  386.                     'The Sound Observatory', 'The Echo Crypt', 'The Resonant Void',
  387.                     'The Final Antechamber', 'The Prism Passage', 'The Timbre Tunnel',
  388.                     'The Cadence Cathedral', 'The Melody Maze', 'The Rhythm Ruins',
  389.                     'The Pitch Palace', 'The Tempo Temple', 'The Dynamics Dungeon',
  390.                     'The Fortress of Frequencies', 'The Citadel of Sound'
  391.                 ];
  392.                
  393.                 this.roomDescriptions = [
  394.                     'Crystalline walls pulse with each sound you make. The air itself seems to listen.',
  395.                     'Echoes bounce endlessly between mirrored surfaces. Each reflection changes the sound.',
  396.                     'Soft murmurs transform into thunderous proclamations. Silence has never been louder.',
  397.                     'Books whisper their contents as echoes. Words float through the air like butterflies.',
  398.                     'The heart of the maze. All sounds converge here in a symphonic chaos.',
  399.                     'Ancient echoes are stored here, each one a key to understanding.',
  400.                     'From here you can see the patterns of all echoes, mapped across crystalline surfaces.',
  401.                     'Where forgotten words come to rest. The silence here is absolute, yet deafening.',
  402.                     'A place between places. All paths converge here, yet none are visible.',
  403.                     'The exit glimmers just beyond. One last echo stands between you and freedom.',
  404.                     'Light refracts through sound waves, creating a rainbow of audible colors.',
  405.                     'The walls hum with a steady rhythm that seems to guide your steps.',
  406.                     'Vast arches amplify every whisper into a chorus of harmonic voices.',
  407.                     'Twisting corridors create a labyrinth of sound that challenges your perception.',
  408.                     'Broken pillars resonate with forgotten melodies from ages past.',
  409.                     'Grand halls where pitch-perfect notes hang suspended in the air.',
  410.                     'A sacred space where time itself seems to beat in perfect rhythm.',
  411.                     'Caverns where volume swells and recedes like ocean tides.',
  412.                     'Impenetrable walls that vibrate with the fundamental frequencies of existence.',
  413.                     'The highest point in the chamber, where all sounds converge into one perfect note.'
  414.                 ];
  415.                
  416.                 // Direction names for passages
  417.                 this.directions = [
  418.                     'north', 'south', 'east', 'west', 'up', 'down',
  419.                     'northeast', 'northwest', 'southeast', 'southwest',
  420.                     'portal', 'tunnel', 'archway', 'corridor', 'staircase',
  421.                     'ladder', 'bridge', 'gate', 'passage', 'doorway'
  422.                 ];
  423.                
  424.                 this.distortionPatterns = [
  425.                     { pattern: /n/g, replacement: () => Math.random() > 0.5 ? 't' : 'tch' },
  426.                     { pattern: /t/g, replacement: () => Math.random() > 0.5 ? 'n' : 'th' },
  427.                     { pattern: /th/g, replacement: 'f' },
  428.                     { pattern: /s/g, replacement: () => Math.random() > 0.5 ? 'z' : 'sh' },
  429.                     { pattern: /p/g, replacement: () => Math.random() > 0.5 ? 'b' : 'pe' },
  430.                     { pattern: /k/g, replacement: () => Math.random() > 0.5 ? 'c' : 'ck' },
  431.                     { pattern: /r/g, replacement: () => Math.random() > 0.5 ? 'w' : 'rr' },
  432.                     { pattern: /l/g, replacement: () => Math.random() > 0.5 ? 'll' : 'r' },
  433.                     { pattern: /or/g, replacement: 'oh' },
  434.                     { pattern: /ea/g, replacement: () => Math.random() > 0.5 ? 'ee' : 'a' },
  435.                     { pattern: /oo/g, replacement: 'u' },
  436.                     { pattern: /ou/g, replacement: 'ow' },
  437.                     { pattern: /ing$/g, replacement: 'in\'' },
  438.                     { pattern: /ed$/g, replacement: 'id' },
  439.                     { pattern: /ly$/g, replacement: 'lee' },
  440.                     { pattern: /([aeiou])([bcdfghjklmnpqrstvwxyz])/g,
  441.                       replacement: (match, v, c) => Math.random() > 0.7 ? c + v : match }
  442.                 ];
  443.  
  444.                 // Generate random room layout
  445.                 this.rooms = this.generateRandomRooms();
  446.                
  447.                 this.init();
  448.             }
  449.  
  450.             generateRandomRooms() {
  451.                 const rooms = {};
  452.                 const roomCount = 20;
  453.                
  454.                 // Create rooms with random names and descriptions
  455.                 for (let i = 1; i <= roomCount; i++) {
  456.                    const roomId = `room${i}`;
  457.                    const nameIndex = Math.floor(Math.random() * this.roomNames.length);
  458.                    const descIndex = Math.floor(Math.random() * this.roomDescriptions.length);
  459.                    
  460.                    rooms[roomId] = {
  461.                        name: this.roomNames[nameIndex],
  462.                        description: this.roomDescriptions[descIndex],
  463.                        exits: {}
  464.                    };
  465.                    
  466.                    // Remove used names/descriptions to avoid duplicates
  467.                    this.roomNames.splice(nameIndex, 1);
  468.                    this.roomDescriptions.splice(descIndex, 1);
  469.                }
  470.                
  471.                // Randomly assign victory and defeat rooms
  472.                const roomIds = Object.keys(rooms);
  473.                this.victoryRoom = roomIds[Math.floor(Math.random() * roomIds.length)];
  474.                do {
  475.                    this.defeatRoom = roomIds[Math.floor(Math.random() * roomIds.length)];
  476.                } while (this.defeatRoom === this.victoryRoom);
  477.                
  478.                // Add special properties to victory and defeat rooms
  479.                rooms[this.victoryRoom].victory = true;
  480.                rooms[this.victoryRoom].name = "THE VICTORY CHAMBER";
  481.                rooms[this.victoryRoom].description = "A brilliant light washes over you. You've found the way out!";
  482.                
  483.                rooms[this.defeatRoom].defeat = true;
  484.                rooms[this.defeatRoom].name = "THE ABYSS OF SILENCE";
  485.                rooms[this.defeatRoom].description = "An eternal, crushing silence envelops you. All hope is lost...";
  486.                
  487.                // Create random connections between rooms
  488.                for (let i = 0; i < roomIds.length; i++) {
  489.                    const currentRoom = roomIds[i];
  490.                    const numExits = Math.floor(Math.random() * 4) + 2; // 2-5 exits per room
  491.                    
  492.                    for (let j = 0; j < numExits; j++) {
  493.                        // Find a random room to connect to
  494.                        let targetRoom;
  495.                        do {
  496.                            targetRoom = roomIds[Math.floor(Math.random() * roomIds.length)];
  497.                        } while (targetRoom === currentRoom || rooms[currentRoom].exits[this.directions[j]]);
  498.                        
  499.                        // Use a random direction name
  500.                        const direction = this.directions[Math.floor(Math.random() * this.directions.length)];
  501.                        
  502.                        // Create bidirectional connection
  503.                        rooms[currentRoom].exits[direction] = targetRoom;
  504.                        
  505.                        // Find a different direction for the return path
  506.                        let returnDirection;
  507.                        do {
  508.                            returnDirection = this.directions[Math.floor(Math.random() * this.directions.length)];
  509.                        } while (rooms[targetRoom].exits[returnDirection]);
  510.                        
  511.                        rooms[targetRoom].exits[returnDirection] = currentRoom;
  512.                    }
  513.                }
  514.                
  515.                return rooms;
  516.            }
  517.  
  518.            init() {
  519.                this.updateRoom();
  520.                this.bindEvents();
  521.            }
  522.  
  523.            bindEvents() {
  524.                const input = document.getElementById('command-input');
  525.                const submitBtn = document.getElementById('submit-btn');
  526.                const restartBtn = document.getElementById('restart-btn');
  527.                const restartBtnDefeat = document.getElementById('restart-btn-defeat');
  528.  
  529.                const processCommand = () => {
  530.                     const command = input.value.trim().toLowerCase();
  531.                     if (command) {
  532.                         this.processCommand(command);
  533.                         input.value = '';
  534.                     }
  535.                 };
  536.  
  537.                 submitBtn.addEventListener('click', processCommand);
  538.                 input.addEventListener('keypress', (e) => {
  539.                     if (e.key === 'Enter') processCommand();
  540.                 });
  541.  
  542.                 restartBtn.addEventListener('click', () => {
  543.                     location.reload();
  544.                 });
  545.  
  546.                 restartBtnDefeat.addEventListener('click', () => {
  547.                     location.reload();
  548.                 });
  549.             }
  550.  
  551.             clickPassage(direction) {
  552.                 const room = this.rooms[this.currentRoom];
  553.                 if (room.exits[direction]) {
  554.                     this.moves++;
  555.                     this.currentRoom = room.exits[direction];
  556.                     this.updateRoom();
  557.                    
  558.                     if (this.rooms[this.currentRoom].victory) {
  559.                         this.showVictory();
  560.                     } else if (this.rooms[this.currentRoom].defeat) {
  561.                         this.showDefeat();
  562.                     }
  563.                 }
  564.             }
  565.  
  566.             distortCommand(command) {
  567.                 let distorted = command.toLowerCase();
  568.                
  569.                 const iterations = Math.floor(Math.random() * 3) + 1;
  570.                 for (let i = 0; i < iterations; i++) {
  571.                    const patterns = [...this.distortionPatterns].sort(() => Math.random() - 0.5);
  572.                     patterns.slice(0, Math.floor(Math.random() * 4) + 2).forEach(({ pattern, replacement }) => {
  573.                         if (typeof replacement === 'function') {
  574.                             distorted = distorted.replace(pattern, replacement);
  575.                         } else {
  576.                             distorted = distorted.replace(pattern, replacement);
  577.                         }
  578.                     });
  579.                 }
  580.  
  581.                 return distorted;
  582.             }
  583.  
  584.             processCommand(command) {
  585.                 this.moves++;
  586.                 const distorted = this.distortCommand(command);
  587.                
  588.                 this.addEcho(command, distorted);
  589.                 this.updateStatus();
  590.                
  591.                 // Check if command matches any direction from current room
  592.                 const room = this.rooms[this.currentRoom];
  593.                 for (let direction in room.exits) {
  594.                     if (this.fuzzyMatch(command, direction) || command.includes(direction.substring(0, 2))) {
  595.                         this.currentRoom = room.exits[direction];
  596.                         this.updateRoom();
  597.                        
  598.                         if (this.rooms[this.currentRoom].victory) {
  599.                             this.showVictory();
  600.                         } else if (this.rooms[this.currentRoom].defeat) {
  601.                             this.showDefeat();
  602.                         }
  603.                         return;
  604.                     }
  605.                 }
  606.  
  607.                 // If no direction matched, show a random response
  608.                 const responses = [
  609.                     'The echo dissipates into silence...',
  610.                     'The walls absorb your words...',
  611.                     'Your voice returns as whispers...',
  612.                     'The chamber hums with confusion...',
  613.                     'Your words echo back unchanged...',
  614.                     'The sound reverberates through the chamber...'
  615.                 ];
  616.                 this.addSystemMessage(responses[Math.floor(Math.random() * responses.length)]);
  617.             }
  618.  
  619.             fuzzyMatch(str1, str2) {
  620.                 const threshold = 0.6;
  621.                 const longer = str1.length > str2.length ? str1 : str2;
  622.                 const shorter = str1.length > str2.length ? str2 : str1;
  623.                
  624.                 if (longer.length === 0) return 1.0;
  625.                 const editDistance = this.levenshtein(longer, shorter);
  626.                 return (longer.length - editDistance) / parseFloat(longer.length) >= threshold;
  627.             }
  628.  
  629.             levenshtein(s1, s2) {
  630.                 const costs = [];
  631.                 for (let i = 0; i <= s2.length; i++) {
  632.                    let lastValue = i;
  633.                    for (let j = 0; j <= s1.length; j++) {
  634.                        if (i === 0) costs[j] = j;
  635.                        else if (j > 0) {
  636.                             let newValue = costs[j - 1];
  637.                             if (s1.charAt(j - 1) !== s2.charAt(i - 1))
  638.                                 newValue = Math.min(Math.min(newValue, lastValue), costs[j]) + 1;
  639.                             costs[j - 1] = lastValue;
  640.                             lastValue = newValue;
  641.                         }
  642.                     }
  643.                     if (i > 0) costs[s1.length] = lastValue;
  644.                 }
  645.                 return costs[s1.length];
  646.             }
  647.  
  648.             addEcho(original, distorted) {
  649.                 const echoDisplay = document.getElementById('echo-display');
  650.                
  651.                 if (echoDisplay.querySelector('[style*="color: #666"]')) {
  652.                     echoDisplay.innerHTML = '';
  653.                 }
  654.  
  655.                 const echoLine = document.createElement('div');
  656.                 echoLine.className = 'echo-line';
  657.                 echoLine.innerHTML = `
  658.                     <span class="original-echo">${original}</span> →
  659.                     <span class="distorted-echo">${distorted}</span>
  660.                 `;
  661.  
  662.                 for (let i = 0; i < 3; i++) {
  663.                    setTimeout(() => {
  664.                         const trail = document.createElement('span');
  665.                         trail.className = 'echo-trail';
  666.                         trail.textContent = distorted;
  667.                         trail.style.left = (150 + i * 30) + 'px';
  668.                         trail.style.top = '0';
  669.                         echoLine.appendChild(trail);
  670.                     }, i * 200);
  671.                 }
  672.  
  673.                 echoDisplay.appendChild(echoLine);
  674.                 echoDisplay.scrollTop = echoDisplay.scrollHeight;
  675.  
  676.                 while (echoDisplay.children.length > 10) {
  677.                     echoDisplay.removeChild(echoDisplay.firstChild);
  678.                 }
  679.             }
  680.  
  681.             addSystemMessage(message) {
  682.                 const echoDisplay = document.getElementById('echo-display');
  683.                 const msgLine = document.createElement('div');
  684.                 msgLine.className = 'echo-line';
  685.                 msgLine.style.color = '#00ffff';
  686.                 msgLine.style.fontStyle = 'italic';
  687.                 msgLine.textContent = message;
  688.                 echoDisplay.appendChild(msgLine);
  689.                 echoDisplay.scrollTop = echoDisplay.scrollHeight;
  690.             }
  691.  
  692.             updateRoom() {
  693.                 const room = this.rooms[this.currentRoom];
  694.                 document.getElementById('room-name').textContent = room.name;
  695.                 document.getElementById('room-description').textContent = room.description;
  696.                
  697.                 // Track visited rooms
  698.                 if (!this.visitedRooms.has(this.currentRoom)) {
  699.                     this.visitedRooms.add(this.currentRoom);
  700.                 }
  701.                
  702.                 // Update passage buttons
  703.                 const buttonContainer = document.getElementById('passage-buttons');
  704.                 buttonContainer.innerHTML = '';
  705.                
  706.                 for (let dir in room.exits) {
  707.                     const btn = document.createElement('button');
  708.                     btn.className = 'passage-btn';
  709.                    
  710.                     // Capitalize first letter
  711.                     btn.textContent = dir.charAt(0).toUpperCase() + dir.slice(1);
  712.                    
  713.                     btn.onclick = () => this.clickPassage(dir);
  714.                     buttonContainer.appendChild(btn);
  715.                 }
  716.                
  717.                 this.updateStatus();
  718.             }
  719.  
  720.             updateStatus() {
  721.                 document.getElementById('move-count').textContent = this.moves;
  722.                 document.getElementById('rooms-explored').textContent = this.visitedRooms.size;
  723.             }
  724.  
  725.             showVictory() {
  726.                 document.getElementById('final-moves').textContent = this.moves;
  727.                 document.getElementById('victory').style.display = 'block';
  728.             }
  729.  
  730.             showDefeat() {
  731.                 document.getElementById('defeat-moves').textContent = this.moves;
  732.                 document.getElementById('defeat').style.display = 'block';
  733.             }
  734.         }
  735.  
  736.         // Start game
  737.         window.addEventListener('DOMContentLoaded', () => {
  738.             new EchoChamberGame();
  739.         });
  740.     </script>
  741. </body>
  742. </html>
  743.  
Advertisement
Add Comment
Please, Sign In to add comment