您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
A highly ambitious, procedural Tampermonkey script for Drawaria.online, injecting Donkey Kong Bananza elements: complex UI, character animations, advanced particles, generative music, and more, all without external assets. Corrected audio errors.
// ==UserScript== // @name Donkey Kong Bananza for Drawaria // @namespace http://tampermonkey.net/ // @version 1.0 // @description A highly ambitious, procedural Tampermonkey script for Drawaria.online, injecting Donkey Kong Bananza elements: complex UI, character animations, advanced particles, generative music, and more, all without external assets. Corrected audio errors. // @author AI (Ambitious Intelligence) // @match https://drawaria.online/* // @grant none // @license MIT // @icon https://www.google.com/s2/favicons?sz=64&domain=drawaria.online // ==/UserScript== (function() { 'use strict'; // --- Configuración Global --- const config = { maxBgElements: 30, // Más elementos de fondo maxParticles: 100, // Más partículas para efectos bananaPerLevel: 25, // Plátanos necesarios para subir de nivel characterSpawnInterval: 15000, // Intervalo para que aparezcan los personajes (ms) characterMoveSpeed: 1, // Velocidad de movimiento de los personajes (px/frame) musicVolume: 0.3, // Volumen inicial de la música (0.0 a 1.0) }; // --- Colores y Estilos DK --- const DK_COLORS = { brownDark: '#4A2B18', brownMedium: '#5C3A21', brownLight: '#7B5F45', yellowBanana: '#FFD700', yellowGold: '#FFAC33', greenJungle: '#228B22', redStrong: '#B22222', blueSky: '#4682B4', darkGrey: '#222', lightGrey: '#AAA', white: '#FFF', black: '#000', goldShine: '#FFFACD', paulineRed: '#DC143C', paulineHair: '#3A1E00', paulineSkin: '#F5DEB3', }; // --- 1. Inyección de CSS (Global y Elementos Específicos) --- function injectGlobalCSS() { const style = document.createElement('style'); style.id = 'dk-bananza-ultimate-style'; style.innerHTML = ` :root { --dk-brown-dark: ${DK_COLORS.brownDark}; --dk-brown-medium: ${DK_COLORS.brownMedium}; --dk-brown-light: ${DK_COLORS.brownLight}; --dk-yellow-banana: ${DK_COLORS.yellowBanana}; --dk-yellow-gold: ${DK_COLORS.yellowGold}; --dk-green-jungle: ${DK_COLORS.greenJungle}; --dk-red-strong: ${DK_COLORS.redStrong}; --dk-blue-sky: ${DK_COLORS.blueSky}; --dk-dark-grey: ${DK_COLORS.darkGrey}; --dk-light-grey: ${DK_COLORS.lightGrey}; --dk-white: ${DK_COLORS.white}; --dk-black: ${DK_COLORS.black}; --dk-gold-shine: ${DK_COLORS.goldShine}; --dk-pauline-red: ${DK_COLORS.paulineRed}; --dk-pauline-hair: ${DK_COLORS.paulineHair}; --dk-pauline-skin: ${DK_COLORS.paulineSkin}; } /* Custom Cursor */ body { cursor: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="30" height="30" viewBox="0 0 100 100"><g><circle cx="50" cy="50" r="45" fill="${DK_COLORS.brownDark}"/><rect x="30" y="20" width="40" height="60" rx="10" ry="10" fill="${DK_COLORS.brownMedium}"/><path d="M50 10 L65 30 L35 30 Z" fill="${DK_COLORS.brownLight}"/><rect x="45" y="40" width="10" height="30" rx="3" ry="3" fill="${DK_COLORS.black}" opacity="0.2"/><text x="50" y="65" font-family="monospace" font-size="30" fill="${DK_COLORS.yellowBanana}" text-anchor="middle" font-weight="bold">B</text></g></svg>') 15 15, auto !important; } button, a, input[type="text"] { cursor: pointer !important; /* Mantener cursor de puntero para interacción */ } /* Contenedor principal para la interfaz de usuario de Bananza */ #dk-bananza-hud { position: fixed; top: 20px; right: 20px; /* Cambiado a la derecha para no chocar con elementos preexistentes */ background: linear-gradient(160deg, var(--dk-brown-dark) 0%, var(--dk-brown-medium) 50%, var(--dk-brown-light) 100%); border: 4px solid var(--dk-dark-grey); border-radius: 25px; padding: 25px 30px; font-family: 'Press Start 2P', cursive; /* Fuente retro si está disponible, o fallback */ color: var(--dk-yellow-gold); z-index: 10000; box-shadow: 0 10px 25px rgba(0, 0, 0, 0.9), inset 0 0 20px rgba(255, 255, 255, 0.4); transition: transform 0.3s ease-in-out, box-shadow 0.2s ease-in-out; cursor: grab; background-size: 200% 200%; animation: backgroundPan 15s infinite alternate ease-in-out; width: 280px; /* Ancho fijo para consistencia */ text-align: center; overflow: hidden; /* Para contener los elementos internos */ } #dk-bananza-hud::before { /* Borde interno brillante */ content: ''; position: absolute; top: 5px; left: 5px; right: 5px; bottom: 5px; border: 2px dashed rgba(255, 255, 255, 0.3); border-radius: 20px; pointer-events: none; } #dk-bananza-hud:hover { box-shadow: 0 12px 30px rgba(0, 0, 0, 1), inset 0 0 25px rgba(255, 255, 255, 0.5); } #dk-bananza-hud:active { cursor: grabbing; transform: scale(0.99); } #dk-bananza-hud h2 { margin-top: 0; margin-bottom: 15px; font-size: 26px; text-align: center; text-shadow: 4px 4px 8px rgba(0, 0, 0, 0.9), 0 0 18px var(--dk-gold-shine); animation: pulse 2s infinite alternate ease-in-out, neonGlow 2.5s infinite alternate; letter-spacing: 2px; line-height: 1.2; position: relative; } #dk-bananza-hud h2::after { content: '¡EXPLOSIÓN DE SABOR!'; display: block; font-size: 14px; color: var(--dk-white); text-shadow: 2px 2px 4px rgba(0,0,0,0.8); margin-top: 5px; } .dk-section { background-color: rgba(0, 0, 0, 0.4); border: 2px solid var(--dk-dark-grey); border-radius: 15px; padding: 15px; margin-bottom: 20px; box-shadow: inset 0 0 10px rgba(0, 0, 0, 0.6), 0 5px 15px rgba(0, 0, 0, 0.7); } #banana-stats { display: flex; flex-direction: column; align-items: center; } #banana-counter-display { display: flex; align-items: center; justify-content: center; font-size: 48px; font-weight: bold; text-shadow: 5px 5px 10px rgba(0, 0, 0, 0.9), 0 0 12px var(--dk-yellow-banana); margin-bottom: 10px; } .banana-icon-lg { width: 50px; height: 50px; margin-right: 15px; background-color: var(--dk-yellow-banana); border-radius: 0 70% 70% 0 / 0 45% 45% 0; position: relative; transform: rotate(-25deg); box-shadow: 3px 3px 8px rgba(0, 0, 0, 0.7), inset 0 0 10px rgba(255, 255, 255, 0.6); animation: bobbing 1.8s infinite ease-in-out, colorShift 5s infinite alternate; } .banana-icon-lg::before { content: ''; position: absolute; top: -10px; left: -4px; width: 12px; height: 12px; background-color: var(--dk-brown-dark); border-radius: 50%; transform: rotate(45deg); box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.4); } #banana-level-progress { width: 90%; height: 25px; background-color: var(--dk-dark-grey); border-radius: 12px; overflow: hidden; border: 2px solid var(--dk-black); box-shadow: inset 0 0 8px rgba(0,0,0,0.8); margin-top: 10px; } #banana-progress-bar { height: 100%; width: 0%; background: linear-gradient(90deg, var(--dk-green-jungle), var(--dk-yellow-banana), var(--dk-green-jungle)); background-size: 200% 100%; border-radius: 12px; transition: width 0.5s ease-out, background-position 0.5s ease-out; position: relative; animation: progressBarShine 2s infinite linear; } #banana-progress-bar::after { content: attr(data-label); position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); color: var(--dk-black); font-size: 14px; font-weight: bold; text-shadow: 1px 1px 2px var(--dk-white); } .dk-button { background: linear-gradient(180deg, var(--dk-green-jungle) 0%, #3CB371 100%); color: white; border: 3px solid var(--dk-dark-grey); padding: 12px 25px; border-radius: 15px; cursor: pointer; font-weight: bold; font-size: 18px; text-transform: uppercase; box-shadow: 4px 4px 10px rgba(0,0,0,0.7), inset 0 0 12px rgba(255,255,255,0.5); transition: background 0.2s, transform 0.1s, box-shadow 0.2s; display: block; width: calc(100% - 6px); text-align: center; margin-top: 15px; letter-spacing: 1px; } .dk-button:hover { background: linear-gradient(180deg, #3CB371 0%, var(--dk-green-jungle) 100%); transform: translateY(-3px); box-shadow: 6px 6px 15px rgba(0,0,0,0.9), inset 0 0 18px rgba(255,255,255,0.7); } .dk-button:active { background: var(--dk-brown-dark); transform: translateY(0); box-shadow: 2px 2px 5px rgba(0,0,0,0.6); } /* Sección de Audio */ #audio-controls { display: flex; flex-direction: column; align-items: center; } #music-toggle-btn { background: linear-gradient(180deg, var(--dk-blue-sky) 0%, #6A5ACD 100%); border: 3px solid var(--dk-dark-grey); color: white; padding: 10px 20px; border-radius: 15px; font-weight: bold; font-size: 16px; margin-bottom: 10px; box-shadow: 3px 3px 8px rgba(0,0,0,0.6); transition: background 0.2s; } #music-toggle-btn.active { background: linear-gradient(180deg, #6A5ACD 0%, var(--dk-blue-sky) 100%); } #music-toggle-btn:hover { transform: translateY(-2px); } #music-volume-slider { width: 90%; -webkit-appearance: none; height: 10px; background: var(--dk-dark-grey); outline: none; border-radius: 5px; box-shadow: inset 0 0 5px rgba(0,0,0,0.8); } #music-volume-slider::-webkit-slider-thumb { -webkit-appearance: none; appearance: none; width: 20px; height: 20px; border-radius: 50%; background: var(--dk-yellow-gold); cursor: pointer; border: 3px solid var(--dk-dark-grey); box-shadow: 1px 1px 5px rgba(0,0,0,0.6); } /* Elementos de fondo animados (ej. plátanos cayendo) */ .dk-bg-element { position: fixed; background-color: var(--dk-yellow-banana); border-radius: 0 55% 55% 0 / 0 35% 35% 0; animation: fallRotate linear infinite; opacity: 0.8; z-index: -1; pointer-events: none; box-shadow: 1px 1px 8px rgba(0, 0, 0, 0.4); } /* Lienzos para partículas y efectos */ #dk-particle-canvas, #dk-barrel-canvas { position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; pointer-events: none; z-index: 9999; } #dk-barrel-canvas { z-index: 9998; /* Un poco por debajo de las partículas normales */ } /* === Character Styles (Procedural CSS) === */ .dk-character { position: fixed; z-index: 1000; transform-style: preserve-3d; transition: transform 0.1s linear; /* Para el movimiento horizontal suave */ cursor: pointer; /*outline: 1px solid red; /* Debug */ } /* Donkey Kong */ .dk-character.donkey-kong { width: 100px; height: 100px; bottom: -100px; /* Empieza fuera de pantalla */ } .dk-character.donkey-kong .body { width: 80px; height: 80px; background-color: var(--dk-brown-dark); border-radius: 50%; position: absolute; top: 20px; left: 10px; box-shadow: 0 5px 10px rgba(0,0,0,0.5); } .dk-character.donkey-kong .head { width: 60px; height: 60px; background-color: var(--dk-brown-dark); border-radius: 50%; position: absolute; top: 0; left: 20px; box-shadow: 0 3px 8px rgba(0,0,0,0.5); } .dk-character.donkey-kong .snout { width: 30px; height: 20px; background-color: var(--dk-brown-light); border-radius: 50%; position: absolute; top: 30px; left: 35px; border: 2px solid var(--dk-brown-dark); } .dk-character.donkey-kong .eye { width: 8px; height: 8px; background-color: var(--dk-white); border-radius: 50%; position: absolute; top: 25px; border: 1px solid var(--dk-black); } .dk-character.donkey-kong .eye.left { left: 40px; } .dk-character.donkey-kong .eye.right { left: 55px; } .dk-character.donkey-kong .pupil { width: 4px; height: 4px; background-color: var(--dk-black); border-radius: 50%; position: absolute; top: 27px; } .dk-character.donkey-kong .pupil.left { left: 42px; } .dk-character.donkey-kong .pupil.right { left: 57px; } /* Pauline */ .dk-character.pauline { width: 60px; height: 120px; bottom: -120px; /* Empieza fuera de pantalla */ } .dk-character.pauline .head { width: 40px; height: 40px; background-color: var(--dk-pauline-skin); border-radius: 50%; position: absolute; top: 0; left: 10px; box-shadow: 0 2px 5px rgba(0,0,0,0.3); } .dk-character.pauline .hair { width: 50px; height: 30px; background-color: var(--dk-pauline-hair); border-radius: 50% / 100% 100% 0 0; position: absolute; top: 0; left: 5px; transform: rotate(-10deg); box-shadow: inset 0 3px 5px rgba(0,0,0,0.3); } .dk-character.pauline .dress { width: 55px; height: 70px; background-color: var(--dk-pauline-red); border-radius: 0 0 20px 20px; position: absolute; top: 40px; left: 2.5px; box-shadow: 0 5px 10px rgba(0,0,0,0.5); clip-path: polygon(10% 0, 90% 0, 100% 100%, 0% 100%); /* Forma de vestido */ } .dk-character.pauline .belt { width: 45px; height: 8px; background-color: var(--dk-black); position: absolute; top: 45px; left: 7.5px; } .dk-character.pauline .eye { width: 5px; height: 5px; background-color: var(--dk-black); border-radius: 50%; position: absolute; top: 15px; } .dk-character.pauline .eye.left { left: 20px; } .dk-character.pauline .eye.right { left: 35px; } /* Keyframe Animations */ @keyframes pulse { 0% { transform: scale(1); text-shadow: 4px 4px 8px rgba(0, 0, 0, 0.9), 0 0 18px var(--dk-gold-shine); } 50% { transform: scale(1.02); text-shadow: 5px 5px 10px rgba(0, 0, 0, 1), 0 0 22px var(--dk-gold-shine); } 100% { transform: scale(1); text-shadow: 4px 4px 8px rgba(0, 0, 0, 0.9), 0 0 18px var(--dk-gold-shine); } } @keyframes neonGlow { 0%, 100% { filter: brightness(1) drop-shadow(0 0 8px var(--dk-yellow-gold)); } 50% { filter: brightness(1.3) drop-shadow(0 0 20px var(--dk-gold-shine)); } } @keyframes bobbing { 0%, 100% { transform: translateY(0) rotate(-25deg); } 50% { transform: translateY(-7px) rotate(-28deg); } } @keyframes colorShift { 0%, 100% { background-color: var(--dk-yellow-banana); } 50% { background-color: var(--dk-yellow-gold); } } @keyframes fallRotate { 0% { transform: translateY(-150px) rotate(0deg) scale(0.7); opacity: 0; } 10% { opacity: 0.8; } 100% { transform: translateY(calc(100vh + 150px)) rotate(1440deg) scale(1.5); opacity: 0; } } @keyframes backgroundPan { 0% { background-position: 0% 50%; } 100% { background-position: 100% 50%; } } @keyframes progressBarShine { 0% { background-position: 200% 0; } 100% { background-position: -200% 0; } } @keyframes characterWalk { 0% { transform: translateY(0); } 25% { transform: translateY(-5px); } 50% { transform: translateY(0); } 75% { transform: translateY(5px); } 100% { transform: translateY(0); } } @keyframes characterPop { 0% { transform: scale(1); opacity: 1; } 50% { transform: scale(1.3); opacity: 0.7; } 100% { transform: scale(0); opacity: 0; } } `; document.head.appendChild(style); // Intentar cargar la fuente "Press Start 2P" desde Google Fonts para mejor estética const fontLink = document.createElement('link'); fontLink.href = 'https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap'; fontLink.rel = 'stylesheet'; document.head.appendChild(fontLink); } // --- 2. Creación del HUD de Bananza (Ampliación) --- let bananaCount = 0; let bananaLevel = 1; function createHUD() { const hud = document.createElement('div'); hud.id = 'dk-bananza-hud'; hud.innerHTML = ` <h2>Donkey Kong Bananza!</h2> <div class="dk-section" id="banana-stats"> <h3>Recuento de Plátanos</h3> <div id="banana-counter-display"> <span class="banana-icon-lg"></span> <span id="banana-count-value">0</span> </div> <div id="banana-level-progress"> <div id="banana-progress-bar" data-label="Nivel 1 (0/${config.bananaPerLevel})"></div> </div> </div> <div class="dk-section" id="actions-section"> <button id="collect-banana-btn" class="dk-button"> ¡Recoge Plátano! </button> <button id="trigger-barrel-blast-btn" class="dk-button" style="display:none;"> ¡Barrel Blast! </button> </div> <div class="dk-section" id="audio-controls"> <h3>Música Selvática</h3> <button id="music-toggle-btn" class="dk-button active"> <span class="music-icon">🎵</span> Música ON </button> <input type="range" id="music-volume-slider" min="0" max="1" step="0.01" value="${config.musicVolume}"> </div> `; document.body.appendChild(hud); const bananaCountValue = document.getElementById('banana-count-value'); const bananaProgressBar = document.getElementById('banana-progress-bar'); const collectButton = document.getElementById('collect-banana-btn'); const triggerBlastButton = document.getElementById('trigger-barrel-blast-btn'); const musicToggleButton = document.getElementById('music-toggle-btn'); const musicVolumeSlider = document.getElementById('music-volume-slider'); // Inicializar la barra de progreso updateBananaProgress(); collectButton.addEventListener('click', () => { bananaCount++; bananaCountValue.textContent = bananaCount; triggerCoinSound(); triggerBananaParticles(); updateBananaProgress(); // Pequeño efecto visual al contador bananaCountValue.style.transform = 'scale(1.2)'; bananaCountValue.style.transition = 'transform 0.1s ease-out'; setTimeout(() => { bananaCountValue.style.transform = 'scale(1)'; }, 100); }); triggerBlastButton.addEventListener('click', () => { triggerBarrelBlast(); triggerBlastButton.style.display = 'none'; // Ocultar después de usar triggerBlastButton.style.animation = ''; // Limpiar animación }); // Música musicToggleButton.addEventListener('click', () => { if (backgroundMusic.isStarted) { backgroundMusic.stop(); musicToggleButton.classList.remove('active'); musicToggleButton.innerHTML = '<span class="music-icon">🔇</span> Música OFF'; } else { backgroundMusic.play(); // CORRECCIÓN: Llamar a .play() musicToggleButton.classList.add('active'); musicToggleButton.innerHTML = '<span class="music-icon">🎵</span> Música ON'; } }); musicVolumeSlider.addEventListener('input', (e) => { config.musicVolume = parseFloat(e.target.value); if (backgroundMusic.gainNode) { backgroundMusic.gainNode.gain.setValueAtTime(config.musicVolume, audioContext.currentTime); } }); // Hacer el HUD arrastrable let isDragging = false; let offsetX, offsetY; hud.addEventListener('mousedown', (e) => { isDragging = true; hud.style.cursor = 'grabbing'; offsetX = e.clientX - hud.getBoundingClientRect().left; offsetY = e.clientY - hud.getBoundingClientRect().top; e.preventDefault(); }); document.addEventListener('mousemove', (e) => { if (!isDragging) return; hud.style.left = `${e.clientX - offsetX}px`; hud.style.top = `${e.clientY - offsetY}px`; }); document.addEventListener('mouseup', () => { isDragging = false; hud.style.cursor = 'grab'; }); function updateBananaProgress() { const progress = bananaCount % config.bananaPerLevel; const percentage = (progress / config.bananaPerLevel) * 100; bananaProgressBar.style.width = `${percentage}%`; bananaProgressBar.setAttribute('data-label', `Nivel ${bananaLevel} (${progress}/${config.bananaPerLevel})`); // Check if a new level is reached and it's not the initial 0 bananas if (bananaCount > 0 && progress === 0 && bananaCount / config.bananaPerLevel === bananaLevel) { levelUp(); } } function levelUp() { bananaLevel++; console.log(`¡Nivel ${bananaLevel} alcanzado!`); // Efecto visual de nivel bananaCountValue.style.animation = 'pulse 0.5s 3 alternate'; bananaCountValue.style.color = DK_COLORS.yellowGold; setTimeout(() => { bananaCountValue.style.animation = ''; bananaCountValue.style.color = ''; }, 1500); // Sonido de nivel triggerLevelUpSound(); // Activar Barrel Blast triggerBlastButton.style.display = 'block'; triggerBlastButton.style.animation = 'pulse 1s infinite alternate'; } } // --- 3. Web Audio API para sonidos simples y música (sin .mp3) --- let audioContext; function initAudioContext() { if (!audioContext) { audioContext = new (window.AudioContext || window.webkitAudioContext)(); } } function triggerCoinSound() { initAudioContext(); if (!audioContext) return; const oscillator = audioContext.createOscillator(); const gainNode = audioContext.createGain(); oscillator.connect(gainNode); gainNode.connect(audioContext.destination); oscillator.type = 'triangle'; const now = audioContext.currentTime; oscillator.frequency.setValueAtTime(880, now); gainNode.gain.setValueAtTime(0.7, now); gainNode.gain.exponentialRampToValueAtTime(0.001, now + 0.2); oscillator.start(now); // CORRECCIÓN: Asegurar que start() se llama antes y con tiempo explícito oscillator.stop(now + 0.2); } function triggerLevelUpSound() { initAudioContext(); if (!audioContext) return; const now = audioContext.currentTime; const o1 = audioContext.createOscillator(); const g1 = audioContext.createGain(); o1.connect(g1); g1.connect(audioContext.destination); o1.type = 'sine'; o1.frequency.setValueAtTime(500, now); g1.gain.setValueAtTime(0.5, now); o1.frequency.linearRampToValueAtTime(1000, now + 0.2); g1.gain.linearRampToValueAtTime(0, now + 0.5); o1.start(now); o1.stop(now + 0.5); const o2 = audioContext.createOscillator(); const g2 = audioContext.createGain(); o2.connect(g2); g2.connect(audioContext.destination); o2.type = 'triangle'; o2.frequency.setValueAtTime(800, now + 0.1); g2.gain.setValueAtTime(0.4, now + 0.1); o2.frequency.linearRampToValueAtTime(1500, now + 0.3); g2.gain.linearRampToValueAtTime(0, now + 0.6); o2.start(now + 0.1); o2.stop(now + 0.6); } // Música de fondo generativa (melodía simple) const backgroundMusic = { isStarted: false, oscillatorNodes: [], gainNode: null, loopTimeout: null, // Para manejar el timeout del loop play: function() { // CORRECCIÓN: La función se llama 'play' initAudioContext(); if (this.isStarted || !audioContext) return; this.isStarted = true; this.gainNode = audioContext.createGain(); this.gainNode.gain.setValueAtTime(config.musicVolume, audioContext.currentTime); this.gainNode.connect(audioContext.destination); const tempo = 120; // BPM const beat = 60 / tempo; // Duración de un cuarto de nota en segundos const melody = [ // Simulación de una melodía simple tipo DK { note: 392, duration: 0.5 }, { note: 440, duration: 0.5 }, { note: 392, duration: 0.5 }, { note: 349, duration: 0.5 }, // G4, A4, G4, F4 { note: 523, duration: 0.5 }, { note: 440, duration: 0.5 }, { note: 392, duration: 1 }, // C5, A4, G4 { note: 392, duration: 0.5 }, { note: 440, duration: 0.5 }, { note: 392, duration: 0.5 }, { note: 349, duration: 0.5 }, { note: 494, duration: 0.5 }, { note: 392, duration: 0.5 }, { note: 330, duration: 1 }, // B4, G4, E4 ]; let currentTime = audioContext.currentTime; let totalMelodyDuration = 0; // Calcular la duración total de la melodía const playNote = (frequency, duration) => { const osc = audioContext.createOscillator(); osc.type = 'square'; // Un sonido más 'pixelado' osc.frequency.setValueAtTime(frequency, currentTime); const noteGain = audioContext.createGain(); noteGain.gain.setValueAtTime(1, currentTime); noteGain.gain.exponentialRampToValueAtTime(0.001, currentTime + duration * 0.9); // Decay osc.connect(noteGain); noteGain.connect(this.gainNode); osc.start(currentTime); osc.stop(currentTime + duration); this.oscillatorNodes.push(osc); // Mantener referencia para detener }; melody.forEach(phrase => { const noteDuration = phrase.duration * beat; playNote(phrase.note, noteDuration); currentTime += noteDuration; totalMelodyDuration += noteDuration; }); // Loop la melodía this.loopTimeout = setTimeout(() => { if (this.isStarted) { this.play(); // Reiniciar la reproducción } }, totalMelodyDuration * 1000); // Duración total en ms }, stop: function() { this.isStarted = false; clearTimeout(this.loopTimeout); this.oscillatorNodes.forEach(osc => { try { // Solo detener si el oscilador está en un estado válido (PENDING o PLAYING) if (osc.playbackState === AudioBufferSourceNode.PLAYING || osc.playbackState === AudioBufferSourceNode.SCHEDULED) { osc.stop(); } } catch (e) { //console.warn("Error stopping oscillator:", e); // Para depuración, si ocurre alguna excepción } }); this.oscillatorNodes = []; if (this.gainNode) { this.gainNode.disconnect(); this.gainNode = null; } } }; // --- 4. Canvas para efectos de partículas (mejorado) --- let particleCanvas, particleCtx; const particles = []; function initParticleCanvas() { particleCanvas = document.createElement('canvas'); particleCanvas.id = 'dk-particle-canvas'; document.body.appendChild(particleCanvas); particleCtx = particleCanvas.getContext('2d'); resizeCanvas(particleCanvas); window.addEventListener('resize', () => resizeCanvas(particleCanvas)); requestAnimationFrame(animateParticles); } function resizeCanvas(canvas) { canvas.width = window.innerWidth; canvas.height = window.innerHeight; } class Particle { constructor(x, y, type = 'banana') { this.x = x; this.y = y; this.type = type; this.size = Math.random() * 8 + 3; this.speedX = (Math.random() - 0.5) * 8; this.speedY = Math.random() * -10 - 2; this.gravity = 0.3; this.alpha = 1; this.decay = Math.random() * 0.04 + 0.01; this.rotation = Math.random() * Math.PI * 2; this.rotationSpeed = (Math.random() - 0.5) * 0.3; if (type === 'banana') { this.color = DK_COLORS.yellowBanana; } else if (type === 'star') { this.color = DK_COLORS.goldShine; } else if (type === 'sparkle') { this.color = `rgba(255, 255, 255, ${this.alpha})`; this.size = Math.random() * 3 + 1; this.speedX *= 0.5; this.speedY *= 0.5; this.gravity = 0.1; this.decay = Math.random() * 0.08 + 0.02; } } update() { this.speedY += this.gravity; this.x += this.speedX; this.y += this.speedY; this.alpha -= this.decay; this.rotation += this.rotationSpeed; } draw() { particleCtx.save(); particleCtx.globalAlpha = this.alpha; particleCtx.fillStyle = this.color; particleCtx.translate(this.x, this.y); particleCtx.rotate(this.rotation); if (this.type === 'banana') { particleCtx.beginPath(); particleCtx.moveTo(0, -this.size * 0.7); particleCtx.bezierCurveTo(this.size * 0.8, -this.size * 0.7, this.size * 0.8, this.size * 0.7, 0, this.size * 0.7); particleCtx.bezierCurveTo(-this.size * 0.4, this.size * 0.4, -this.size * 0.4, -this.size * 0.4, 0, -this.size * 0.7); particleCtx.fill(); } else if (this.type === 'star') { // Dibujar una estrella de 5 puntas const outerRadius = this.size; const innerRadius = this.size / 2; particleCtx.beginPath(); for (let i = 0; i < 5; i++) { let angle = Math.PI / 2 + (i * 2 * Math.PI / 5); particleCtx.lineTo(outerRadius * Math.cos(angle), outerRadius * Math.sin(angle)); angle += Math.PI / 5; particleCtx.lineTo(innerRadius * Math.cos(angle), innerRadius * Math.sin(angle)); } particleCtx.closePath(); particleCtx.fill(); } else if (this.type === 'sparkle') { // Pequeño círculo brillante particleCtx.beginPath(); particleCtx.arc(0, 0, this.size, 0, Math.PI * 2); particleCtx.fill(); } particleCtx.restore(); } } function triggerBananaParticles() { const hudRect = document.getElementById('dk-bananza-hud').getBoundingClientRect(); const startX = hudRect.left + hudRect.width / 2; const startY = hudRect.top + hudRect.height / 2; for (let i = 0; i < 20; i++) { if (particles.length < config.maxParticles) { particles.push(new Particle(startX, startY, 'banana')); } } } function animateParticles() { particleCtx.clearRect(0, 0, particleCanvas.width, particleCanvas.height); for (let i = particles.length - 1; i >= 0; i--) { const p = particles[i]; p.update(); p.draw(); if (p.alpha <= 0.02 || p.y > particleCanvas.height + p.size) { particles.splice(i, 1); } } requestAnimationFrame(animateParticles); } // --- 5. Barrel Blast Canvas y Efecto --- let barrelCanvas, barrelCtx; const barrels = []; function initBarrelCanvas() { barrelCanvas = document.createElement('canvas'); barrelCanvas.id = 'dk-barrel-canvas'; document.body.appendChild(barrelCanvas); barrelCtx = barrelCanvas.getContext('2d'); resizeCanvas(barrelCanvas); window.addEventListener('resize', () => resizeCanvas(barrelCanvas)); requestAnimationFrame(animateBarrels); } class Barrel { constructor(x, y, radius) { this.x = x; this.y = y; this.radius = radius; this.speedX = (Math.random() - 0.5) * 15; this.speedY = Math.random() * -20 - 5; this.gravity = 0.8; this.rotation = Math.random() * Math.PI * 2; this.rotationSpeed = (Math.random() - 0.5) * 0.5; this.alpha = 1; this.decay = 0.02; this.color1 = DK_COLORS.brownMedium; this.color2 = DK_COLORS.brownDark; } update() { this.speedY += this.gravity; this.x += this.speedX; this.y += this.speedY; this.alpha -= this.decay; this.rotation += this.rotationSpeed; } draw() { barrelCtx.save(); barrelCtx.globalAlpha = this.alpha; barrelCtx.translate(this.x, this.y); barrelCtx.rotate(this.rotation); // Cuerpo del barril barrelCtx.fillStyle = this.color1; barrelCtx.beginPath(); barrelCtx.ellipse(0, 0, this.radius, this.radius * 0.7, 0, 0, Math.PI * 2); barrelCtx.fill(); // Bordes del barril barrelCtx.strokeStyle = this.color2; barrelCtx.lineWidth = 3; barrelCtx.beginPath(); barrelCtx.ellipse(0, -this.radius * 0.6, this.radius, this.radius * 0.2, 0, 0, Math.PI * 2); barrelCtx.stroke(); barrelCtx.beginPath(); barrelCtx.ellipse(0, this.radius * 0.6, this.radius, this.radius * 0.2, 0, 0, Math.PI * 2); barrelCtx.stroke(); // Letra DK barrelCtx.font = `${this.radius * 0.8}px 'Press Start 2P'`; barrelCtx.fillStyle = DK_COLORS.yellowBanana; barrelCtx.textAlign = 'center'; barrelCtx.textBaseline = 'middle'; barrelCtx.fillText('DK', 0, 0); barrelCtx.restore(); } } function triggerBarrelBlast() { const hudRect = document.getElementById('dk-bananza-hud').getBoundingClientRect(); const startX = hudRect.left + hudRect.width / 2; const startY = hudRect.top + hudRect.height / 2; for (let i = 0; i < 15; i++) { // 15 barriles barrels.push(new Barrel(startX, startY, Math.random() * 15 + 15)); // Radio entre 15 y 30 } for (let i = 0; i < 50; i++) { // Muchas chispas/estrellas particles.push(new Particle(startX, startY, Math.random() < 0.5 ? 'star' : 'sparkle')); } // Sonido de explosión initAudioContext(); if (!audioContext) return; const now = audioContext.currentTime; const o = audioContext.createOscillator(); const g = audioContext.createGain(); o.connect(g); g.connect(audioContext.destination); o.type = 'square'; o.frequency.setValueAtTime(100, now); g.gain.setValueAtTime(0.7, now); o.frequency.exponentialRampToValueAtTime(50, now + 0.5); g.gain.exponentialRampToValueAtTime(0.001, now + 0.8); o.start(now); o.stop(now + 0.8); } function animateBarrels() { barrelCtx.clearRect(0, 0, barrelCanvas.width, barrelCanvas.height); for (let i = barrels.length - 1; i >= 0; i--) { const b = barrels[i]; b.update(); b.draw(); if (b.alpha <= 0.01 || b.y > barrelCanvas.height + b.radius) { barrels.splice(i, 1); } } requestAnimationFrame(animateBarrels); } // --- 6. Elementos de fondo animados (plátanos cayendo) --- const backgroundElements = []; function createBgElement() { const element = document.createElement('div'); element.classList.add('dk-bg-element'); element.style.width = `${Math.random() * 30 + 20}px`; element.style.height = `${Math.random() * 40 + 30}px`; element.style.left = `${Math.random() * 100}vw`; element.style.animationDuration = `${Math.random() * 15 + 8}s`; element.style.animationDelay = `${Math.random() * 8}s`; document.body.appendChild(element); backgroundElements.push(element); element.addEventListener('animationend', () => { element.remove(); backgroundElements.splice(backgroundElements.indexOf(element), 1); if (backgroundElements.length < config.maxBgElements) { createBgElement(); } }); } function initBackgroundElements() { for (let i = 0; i < config.maxBgElements; i++) { createBgElement(); } } // --- 7. Personajes Animados (Donkey Kong y Pauline) --- const charactersOnScreen = []; let characterSpawnTimer; class Character { constructor(type) { this.type = type; this.element = document.createElement('div'); this.element.classList.add('dk-character', type); this.element.innerHTML = this.getHTML(); document.body.appendChild(this.element); this.width = type === 'donkey-kong' ? 100 : 60; this.height = type === 'donkey-kong' ? 100 : 120; this.speed = config.characterMoveSpeed * (Math.random() > 0.5 ? 1 : -1); // Dirección aleatoria this.element.style.bottom = `-5px`; // Siempre en la parte inferior de la pantalla if (this.speed < 0) { // Si va a la izquierda, flip horizontalmente this.element.style.transform = 'scaleX(-1)'; this.x = window.innerWidth; // Empieza a la derecha } else { this.x = -this.width; // Empieza a la izquierda } this.element.style.left = `${this.x}px`; this.element.style.animation = `characterWalk 0.8s infinite steps(4)`; // Animación de caminar this.element.addEventListener('click', () => this.react()); this.animationFrame = null; this.startMoving(); } getHTML() { if (this.type === 'donkey-kong') { return ` <div class="body"></div> <div class="head"></div> <div class="snout"></div> <div class="eye left"></div> <div class="eye right"></div> <div class="pupil left"></div> <div class="pupil right"></div> `; } else if (this.type === 'pauline') { return ` <div class="head"></div> <div class="hair"></div> <div class="dress"></div> <div class="belt"></div> <div class="eye left"></div> <div class="eye right"></div> `; } return ''; } startMoving() { const move = () => { this.x += this.speed; this.element.style.left = `${this.x}px`; const reachedEnd = (this.speed > 0 && this.x > window.innerWidth) || (this.speed < 0 && this.x < -this.width); if (reachedEnd) { this.destroy(); } else { this.animationFrame = requestAnimationFrame(move); } }; this.animationFrame = requestAnimationFrame(move); } react() { console.log(`¡${this.type === 'donkey-kong' ? 'Donkey Kong' : 'Pauline'} reaccionó!`); bananaCount += 5; // Más plátanos por interactuar con personajes document.getElementById('banana-count-value').textContent = bananaCount; updateBananaProgress(); // Actualizar barra de progreso triggerCoinSound(); // Sonido al "recolectar" // Efecto visual de "desaparición" this.element.style.animation = 'characterPop 0.5s forwards'; const charX = this.element.getBoundingClientRect().left + this.width / 2; const charY = this.element.getBoundingClientRect().top + this.height / 2; for (let i = 0; i < 15; i++) { // Partículas al desaparecer particles.push(new Particle(charX, charY, Math.random() < 0.7 ? 'banana' : 'star')); } setTimeout(() => { this.destroy(); }, 500); } destroy() { if (this.animationFrame) { cancelAnimationFrame(this.animationFrame); } if (this.element.parentNode) { this.element.parentNode.removeChild(this.element); } const index = charactersOnScreen.indexOf(this); if (index > -1) { charactersOnScreen.splice(index, 1); } } } function spawnCharacter() { if (charactersOnScreen.length < 3) { // Limitar el número de personajes en pantalla const type = Math.random() < 0.5 ? 'donkey-kong' : 'pauline'; charactersOnScreen.push(new Character(type)); } } function initCharacterSpawning() { spawnCharacter(); // Spawn inicial characterSpawnTimer = setInterval(spawnCharacter, config.characterSpawnInterval); } function updateBananaProgress() { const bananaCountValue = document.getElementById('banana-count-value'); const bananaProgressBar = document.getElementById('banana-progress-bar'); const triggerBlastButton = document.getElementById('trigger-barrel-blast-btn'); const progress = bananaCount % config.bananaPerLevel; const percentage = (progress / config.bananaPerLevel) * 100; bananaProgressBar.style.width = `${percentage}%`; bananaProgressBar.setAttribute('data-label', `Nivel ${bananaLevel} (${progress}/${config.bananaPerLevel})`); if (bananaCount > 0 && progress === 0 && bananaCount / config.bananaPerLevel === bananaLevel) { levelUp(); } } // --- Ejecutar todo --- function initializeBananzaUltimateScript() { console.log('Donkey Kong Bananza! Ultimate Enhancement for Drawaria Loaded...'); injectGlobalCSS(); createHUD(); initParticleCanvas(); initBarrelCanvas(); initBackgroundElements(); initCharacterSpawning(); // Iniciar la música de fondo backgroundMusic.play(); console.warn('Nota de Renderizado: Los personajes y elementos gráficos son generados PROCEDURALMENTE con CSS y Canvas. Su "realismo" es una representación estilizada y abstracta, no fotorrealista, debido a las restricciones de no usar imágenes preexistentes o archivos de audio. Los personajes NO son "jugables" en el sentido de controlar su movimiento dentro del juego, sino elementos animados que cruzan la pantalla.'); console.log('¡Donkey Kong Bananza! Ultimate Enhancement for Drawaria Cargado Exitosamente. ¡A dibujar!'); } // Asegurarse de que el DOM esté completamente cargado antes de ejecutar el script if (document.readyState === 'complete' || document.readyState === 'interactive') { initializeBananzaUltimateScript(); } else { document.addEventListener('DOMContentLoaded', initializeBananzaUltimateScript); } })();