您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Your personal c00lkidd agent on Drawaria.online! Walks, jumps, talks, and reacts dynamically to you.
// ==UserScript== // @name Drawaria C00LKIDD Mod // @namespace http://tampermonkey.net/ // @version 4.0 // @description Your personal c00lkidd agent on Drawaria.online! Walks, jumps, talks, and reacts dynamically to you. // @match https://drawaria.online/* // @license MIT // @icon https://shapes.inc/api/public/avatar/c00lkidd-twp2 // @grant GM_addStyle // @run-at document-start // ==/UserScript== (function() { 'use strict'; // --- Global Configuration (Minimal, as requested) --- const ENABLE_C00LKIDD_AGENT = true; // Set to false to disable the entire script const ENABLE_C00LKIDD_SOUNDS = true; // Master toggle for all sounds const C00LKIDD_AGENT_MASTER_VOLUME = 0.6; // Adjust agent's sound volume (0.0 to 1.0) const C00LKIDD_AGENT_RANDOM_MOVEMENT = true; // Allow c00lkidd to move to random spots const C00LKIDD_AGENT_DIALOGUE = true; // Enable speech/thought bubbles const C00LKIDD_AGENT_CLICK_INTERACTION = true; // Allow clicking the agent for reactions const C00LKIDD_AGENT_DRAW_TRAIL = false; // Enable particle trail when you draw (can be performance heavy) // --- C00LKIDD Appearance (Pure CSS Colors) --- const C00LKIDD_PRIMARY_COLOR = '#ff0000'; // Signature red const C00LKIDD_HIGHLIGHT_COLOR = '#ffff00'; // Yellow highlight/glow const C00LKIDD_ACCENT_COLOR = '#000000'; // Black for eyes/mouth // --- Internal Variables --- let audioContext; let mainGainNode; let currentPlayerUID = null; let c00lkiddAgentElement = null; // The main on-screen c00lkidd character let c00lkiddCurrentMood = 'normal'; let c00lkiddMoodTimeout = null; let lastPlayerStatus = {}; const C00LKIDD_PHRASES = [ "What's up, pal?", "Ready to draw!", "Let's play!", "I'm here for you!", "Cool!", "Awesome!", "You got this!", "Team c00lkidd!", "Thinking..." ]; // --- Web Audio API for Sound Generation (all programmatic, no files) --- function initAudioContext() { if (!audioContext) { audioContext = new (window.AudioContext || window.webkitAudioContext)(); mainGainNode = audioContext.createGain(); mainGainNode.connect(audioContext.destination); mainGainNode.gain.value = C00LKIDD_AGENT_MASTER_VOLUME; } } function playTone(frequency, duration, type = 'sine', volume = 0.5, delay = 0) { if (!ENABLE_C00LKIDD_SOUNDS) return; if (!audioContext) initAudioContext(); setTimeout(() => { const oscillator = audioContext.createOscillator(); const gainNode = audioContext.createGain(); oscillator.type = type; oscillator.frequency.setValueAtTime(frequency, audioContext.currentTime); gainNode.gain.setValueAtTime(volume, audioContext.currentTime); oscillator.connect(gainNode); gainNode.connect(mainGainNode); oscillator.start(); oscillator.stop(audioContext.currentTime + duration); gainNode.gain.exponentialRampToValueAtTime(0.00001, audioContext.currentTime + duration); oscillator.onended = () => { oscillator.disconnect(); gainNode.disconnect(); }; }, delay * 1000); } function playC00lkiddChirp() { playTone(880, 0.05, 'triangle', 0.7); playTone(987, 0.05, 'triangle', 0.7, 0.05); } function playSuccessChime() { playTone(783.99, 0.1, 'triangle', 0.7); // G5 playTone(987.77, 0.1, 'triangle', 0.7, 0.05); // B5 playTone(1174.66, 0.1, 'triangle', 0.7, 0.1); // D6 } function playFailBuzz() { playTone(220, 0.2, 'sawtooth', 0.5); // A3 playTone(185, 0.2, 'sawtooth', 0.5, 0.1); // F#3 } function playJumpBoing() { playTone(400, 0.1, 'sine', 0.8); playTone(600, 0.1, 'sine', 0.8, 0.05); } function playSwingWhoosh() { playTone(1000, 0.05, 'triangle', 0.6); playTone(800, 0.05, 'triangle', 0.6, 0.05); } // --- Dynamic Mood System (CSS-driven) --- function setC00lkiddMood(mood) { if (!ENABLE_C00LKIDD_AGENT || !c00lkiddAgentElement) return; c00lkiddCurrentMood = mood; const head = c00lkiddAgentElement.querySelector('.c00lkidd-avatar-head'); if (head) { head.classList.remove('mood-normal', 'mood-happy', 'mood-thoughtful', 'mood-sad'); head.classList.add(`mood-${mood}`); } // Auto-revert to normal mood after a duration if (c00lkiddMoodTimeout) clearTimeout(c00lkiddMoodTimeout); if (mood !== 'normal') { c00lkiddMoodTimeout = setTimeout(() => setC00lkiddMood('normal'), 3000); // Revert after 3 seconds } } // --- Dialogue/Thought Bubble System (Pure CSS/HTML) --- function showC00lkiddDialogue(text, isThought = false) { if (!ENABLE_C00LKIDD_AGENT || !C00LKIDD_AGENT_DIALOGUE || !c00lkiddAgentElement) return; let bubble = c00lkiddAgentElement.querySelector('.c00lkidd-dialogue-bubble'); if (!bubble) { bubble = document.createElement('div'); bubble.className = 'c00lkidd-dialogue-bubble'; c00lkiddAgentElement.appendChild(bubble); } bubble.innerText = text; bubble.classList.toggle('thought', isThought); bubble.style.display = 'block'; if (bubble.timeout) clearTimeout(bubble.timeout); bubble.timeout = setTimeout(() => { bubble.style.display = 'none'; }, 3000); // Hide after 3 seconds } // --- Pure CSS Graphics for c00lkidd Avatar and Agent --- GM_addStyle(` /* Dynamic Colors from Configuration */ :root { --c00lkidd-color: ${C00LKIDD_PRIMARY_COLOR}; --c00lkidd-highlight: ${C00LKIDD_HIGHLIGHT_COLOR}; --c00lkidd-accent: ${C00LKIDD_ACCENT_COLOR}; } /* Keyframes for c00lkidd specific animations */ @keyframes c00lkiddGrowShrink { 0% { transform: scale(1); } 50% { transform: scale(1.2); filter: drop-shadow(0 0 15px var(--c00lkidd-highlight)); } 100% { transform: scale(1); } } @keyframes c00lkiddSwordSwing { 0% { transform: rotateY(0deg) rotateZ(0deg) translateX(0); opacity: 1; } 25% { transform: rotateY(30deg) rotateZ(15deg) translateX(10px); } 50% { transform: rotateY(0deg) rotateZ(30deg) translateX(0); } 75% { transform: rotateY(-30deg) rotateZ(15deg) translateX(-10px); } 100% { transform: rotateY(0deg) rotateZ(0deg) translateX(0); opacity: 0; } } @keyframes c00lkiddIdleWobble { 0%, 100% { transform: translateY(0) rotate(0); } 25% { transform: translateY(-1px) rotate(0.5deg); } 75% { transform: translateY(1px) rotate(-0.5deg); } } @keyframes c00lkiddJump { 0% { transform: translateY(0); } 50% { transform: translateY(-50px) scaleY(1.1); } /* Jump height */ 100% { transform: translateY(0); } } @keyframes c00lkiddWalk { 0%, 100% { transform: translateX(0); } 50% { transform: translateX(5px); } /* Subtle horizontal bob */ } /* Base c00lkidd avatar and agent style */ .c00lkidd-avatar-wrapper { position: absolute; top: 0; left: 0; width: 100%; height: 100%; display: flex; justify-content: center; align-items: center; z-index: 1; /* Ensure it's above original elements */ } .c00lkidd-avatar, .c00lkidd-agent { position: relative; width: 100%; height: 100%; overflow: hidden; display: flex; justify-content: center; align-items: center; flex-direction: column; background: transparent !important; transform-origin: bottom center; } /* Specific sizing for the main agent */ .c00lkidd-agent { position: fixed; /* Fixed position for the companion */ width: 80px; /* Base size for the agent */ height: 100px; bottom: 20px; left: 20px; /* Default position */ cursor: pointer; z-index: 5000; /* High z-index to be on top */ transition: all 0.5s cubic-bezier(0.68, -0.55, 0.265, 1.55); /* Smooth movement transition */ animation: c00lkiddIdleWobble 4s ease-in-out infinite; /* Subtle idle animation */ } .c00lkidd-agent.jumping { animation: c00lkiddJump 0.6s ease-out; } .c00lkidd-agent.walking { animation: c00lkiddWalk 1.5s ease-in-out infinite; } .c00lkidd-avatar-body { width: 70%; height: 80%; background-color: var(--c00lkidd-color); position: relative; box-shadow: inset 0 0 5px rgba(0,0,0,0.5); } .c00lkidd-avatar-head { width: 60%; height: 50%; background-color: var(--c00lkidd-color); position: absolute; top: -20%; left: 20%; border-radius: 5%; box-shadow: inset 0 0 5px rgba(0,0,0,0.5); display: flex; flex-direction: column; justify-content: center; align-items: center; z-index: 10; } /* Eyes */ .c00lkidd-avatar-head::before, .c00lkidd-avatar-head::after { content: ''; position: absolute; width: 15%; height: 15%; background-color: var(--c00lkidd-accent); top: 30%; border-radius: 50%; transition: all 0.3s ease; } .c00lkidd-avatar-head::before { left: 25%; } .c00lkidd-avatar-head::after { right: 25%; } /* Mouth (smiley) */ .c00lkidd-avatar-head .mouth { position: absolute; width: 40%; height: 20%; border-radius: 0 0 50% 50% / 0 0 100% 100%; border: 2px solid var(--c00lkidd-accent); border-top: none; bottom: 15%; transition: all 0.3s ease; } /* Mood-specific facial expressions */ .c00lkidd-avatar-head.mood-happy .mouth { height: 25%; border-radius: 0 0 70% 70% / 0 0 150% 150%; transform: scaleX(1.1); } .c00lkidd-avatar-head.mood-thoughtful .mouth { border-radius: 0; border-bottom: none; height: 5px; width: 30%; } .c00lkidd-avatar-head.mood-sad .mouth { border-radius: 50% 50% 0 0 / 100% 100% 0 0; border-bottom: 2px solid var(--c00lkidd-accent); border-top: none; bottom: 20%; } /* Eyes for thoughtful/sad */ .c00lkidd-avatar-head.mood-thoughtful::before, .c00lkidd-avatar-head.mood-thoughtful::after { top: 35%; height: 5%; } .c00lkidd-avatar-head.mood-sad::before, .c00lkidd-avatar-head.mood-sad::after { top: 25%; transform: rotate(-15deg); } /* Arms */ .c00lkidd-avatar-arm.left, .c00lkidd-avatar-arm.right { position: absolute; width: 30%; height: 60%; background-color: var(--c00lkidd-color); top: 10%; box-shadow: inset 0 0 3px rgba(0,0,0,0.4); z-index: 5; } .c00lkidd-avatar-arm.left { left: -35%; } .c00lkidd-avatar-arm.right { right: -35%; } /* Legs */ .c00lkidd-avatar-leg.left, .c00lkidd-avatar-leg.right { position: absolute; width: 30%; height: 40%; background-color: var(--c00lkidd-color); bottom: -40%; box-shadow: inset 0 0 3px rgba(0,0,0,0.4); z-index: 5; } .c00lkidd-avatar-leg.left { left: 15%; } .c00lkidd-avatar-leg.right { right: 15%; } /* Sword for gestures */ .c00lkidd-sword { position: absolute; bottom: -50%; left: 50%; width: 5px; height: 60px; background-color: #555; transform-origin: bottom center; animation: none; z-index: 100; box-shadow: 0 0 5px rgba(255,255,255,0.7); display: none; } .c00lkidd-sword::before { content: ''; position: absolute; bottom: -5px; left: -5px; width: 15px; height: 5px; background-color: #8B4513; } /* Spark effect for sword swing */ .c00lkidd-sword-spark { position: absolute; width: 8px; height: 8px; background-color: var(--c00lkidd-highlight); border-radius: 50%; opacity: 0; animation: sparkFadeOut 0.5s ease-out forwards; z-index: 101; box-shadow: 0 0 10px var(--c00lkidd-highlight); } @keyframes sparkFadeOut { 0% { transform: scale(0.5); opacity: 1; } 100% { transform: scale(2); opacity: 0; } } /* Particle burst for agent interactions */ .c00lkidd-burst-particle { position: absolute; background-color: var(--c00lkidd-highlight); border-radius: 50%; opacity: 0; animation: burstParticle 0.8s ease-out forwards; box-shadow: 0 0 5px var(--c00lkidd-highlight); } @keyframes burstParticle { 0% { transform: scale(0) translate(0,0); opacity: 1; } 50% { opacity: 0.8; } 100% { transform: scale(1) translate(var(--x), var(--y)); opacity: 0; } } /* Hide ORIGINAL avatar images only for the current player's elements */ #selfavatarimage, .playerlist-avatarimg[data-uid="${currentPlayerUID}"] img, .playerlist-avatar[data-uid="${currentPlayerUID}"] img, .spawnedavatar[data-uid="${currentPlayerUID}"] img { display: none !important; opacity: 0 !important; } /* Override backgrounds/borders for c00lkidd avatar containers */ #selfavatarimage + .c00lkidd-avatar-wrapper, .playerlist-avatarimg[data-uid="${currentPlayerUID}"], .playerlist-avatar[data-uid="${currentPlayerUID}"], .spawnedavatar[data-uid="${currentPlayerUID}"] { background-color: transparent !important; border-radius: 0 !important; overflow: visible !important; display: flex !important; justify-content: center !important; align-items: center !important; } /* Drawing Trail */ .c00lkidd-trail-block { position: absolute; width: 8px; height: 8px; background-color: var(--c00lkidd-color); border: 1px solid var(--c00lkidd-highlight); opacity: 0.8; border-radius: 2px; pointer-events: none; animation: fadeOutTrail 0.5s forwards; z-index: 999; } @keyframes fadeOutTrail { 0% { opacity: 0.8; transform: scale(1); } 100% { opacity: 0; transform: scale(0.5); } } /* Dialogue Bubble */ .c00lkidd-dialogue-bubble { position: absolute; bottom: 110%; /* Above the agent */ left: 50%; transform: translateX(-50%); background: #fff; color: var(--c00lkidd-accent); border: 2px solid var(--c00lkidd-color); border-radius: 10px; padding: 5px 10px; font-family: 'Arial', sans-serif; font-size: 0.9em; white-space: nowrap; z-index: 102; box-shadow: 0 2px 5px rgba(0,0,0,0.3); display: none; } .c00lkidd-dialogue-bubble::after { /* Tail */ content: ''; position: absolute; left: 50%; top: 100%; transform: translateX(-50%); width: 0; height: 0; border-left: 10px solid transparent; border-right: 10px solid transparent; border-top: 10px solid var(--c00lkidd-color); } .c00lkidd-dialogue-bubble.thought { background: #e0e0e0; color: #555; border-style: dotted; /* Thought bubble style */ } .c00lkidd-dialogue-bubble.thought::after { border-top: 10px solid #e0e0e0; } `); // --- Dynamic C00LKIDD Avatar Injection (for game's default avatar slots) --- function injectC00lkiddAvatar(targetElement) { if (!ENABLE_C00LKIDD_AGENT) return; // Ensure current player UID is set for specific targeting if (!currentPlayerUID && window.LOGUID && window.LOGUID.length > 0) { currentPlayerUID = window.LOGUID[0]; document.documentElement.style.setProperty('--current-player-uid', currentPlayerUID); } if (!targetElement || targetElement.querySelector('.c00lkidd-avatar-wrapper')) { return; } const targetUID = targetElement.id === 'selfavatarimage' ? currentPlayerUID : targetElement.dataset.uid; if (!currentPlayerUID || targetUID !== currentPlayerUID) { return; // Not the current player's avatar slot, skip injection } const avatarWrapper = document.createElement('div'); avatarWrapper.className = 'c00lkidd-avatar-wrapper'; avatarWrapper.style.cssText = ` position: absolute; top: 0; left: 0; width: 100%; height: 100%; display: flex; justify-content: center; align-items: center; pointer-events: none; /* Do not block clicks on elements behind */ `; const c00lkiddHTML = ` <div class="c00lkidd-avatar"> <div class="c00lkidd-avatar-body"> <div class="c00lkidd-avatar-head"><div class="mouth"></div></div> <div class="c00lkidd-avatar-arm left"></div> <div class="c00lkidd-avatar-arm right"></div> <div class="c00lkidd-avatar-leg left"></div> <div class="c00lkidd-avatar-leg right"></div> </div> <div class="c00lkidd-sword"></div> </div> `; avatarWrapper.innerHTML = c00lkiddHTML; const originalImg = targetElement.querySelector('img') || targetElement; if (originalImg && originalImg.tagName === 'IMG') { originalImg.style.display = 'none'; } if (targetElement.id === 'selfavatarimage') { targetElement.parentNode.appendChild(avatarWrapper); } else { targetElement.appendChild(avatarWrapper); } setC00lkiddMood(c00lkiddCurrentMood); // Set initial mood const resizeObserver = new ResizeObserver(entries => { for (let entry of entries) { const parentWidth = entry.contentRect.width; const parentHeight = entry.contentRect.height; const scale = Math.min(parentWidth / 100, parentHeight / 100); avatarWrapper.style.setProperty('--c00lkidd-scale', scale); } }); resizeObserver.observe(targetElement); } // --- Main C00LKIDD Agent (The Companion) Logic --- function createC00lkiddAgent() { if (!ENABLE_C00LKIDD_AGENT) return; c00lkiddAgentElement = document.createElement('div'); c00lkiddAgentElement.id = 'c00lkidd-agent'; c00lkiddAgentElement.className = 'c00lkidd-agent'; c00lkiddAgentElement.innerHTML = ` <div class="c00lkidd-avatar-body"> <div class="c00lkidd-avatar-head"><div class="mouth"></div></div> <div class="c00lkidd-avatar-arm left"></div> <div class="c00lkidd-avatar-arm right"></div> <div class="c00lkidd-avatar-leg left"></div> <div class="c00lkidd-avatar-leg right"></div> </div> `; document.body.appendChild(c00lkiddAgentElement); setC00lkiddMood(c00lkiddCurrentMood); // Set initial mood for the agent // Click interaction for the agent if (C00LKIDD_AGENT_CLICK_INTERACTION) { c00lkiddAgentElement.addEventListener('click', () => { if (c00lkiddAgentElement.classList.contains('jumping')) return; // Avoid spamming jump playJumpBoing(); c00lkiddAgentElement.classList.add('jumping'); c00lkiddAgentElement.addEventListener('animationend', () => { c00lkiddAgentElement.classList.remove('jumping'); }, { once: true }); showC00lkiddDialogue(C00LKIDD_PHRASES[Math.floor(Math.random() * C00LKIDD_PHRASES.length)]); createParticleBurst(c00lkiddAgentElement, 15); setC00lkiddMood('happy'); }); } // Random Movement Logic if (C00LKIDD_AGENT_RANDOM_MOVEMENT) { const positions = [ { bottom: '20px', left: '20px' }, // Bottom-left { bottom: '20px', right: '20px', left: 'auto' }, // Bottom-right { top: '150px', left: '20px', bottom: 'auto' }, // Top-left (adjust to avoid main UI) { top: '150px', right: '20px', bottom: 'auto', left: 'auto' }, // Top-right (adjust to avoid main UI) { bottom: '50%', left: '50%', transform: 'translate(-50%, 50%)' } // Center-ish ]; let currentPosIndex = 0; function moveC00lkiddRandomly() { if (!ENABLE_C00LKIDD_AGENT) return; let newIndex; do { newIndex = Math.floor(Math.random() * positions.length); } while (newIndex === currentPosIndex); // Ensure different position const targetPos = positions[newIndex]; c00lkiddAgentElement.style.transition = 'all 2s cubic-bezier(0.68, -0.55, 0.265, 1.55)'; // Smoother slide c00lkiddAgentElement.style.bottom = targetPos.bottom || 'auto'; c00lkiddAgentElement.style.left = targetPos.left || 'auto'; c00lkiddAgentElement.style.right = targetPos.right || 'auto'; c00lkiddAgentElement.style.top = targetPos.top || 'auto'; c00lkiddAgentElement.style.transform = targetPos.transform || 'none'; // Add a "walking" animation class during movement c00lkiddAgentElement.classList.add('walking'); setTimeout(() => { c00lkiddAgentElement.classList.remove('walking'); }, 2000); // Remove walking class after transition currentPosIndex = newIndex; } setInterval(moveC00lkiddRandomly, 15000); // Move every 15 seconds } } // --- Particle Burst Effect --- function createParticleBurst(sourceElement, count) { if (!ENABLE_C00LKIDD_AGENT) return; const rect = sourceElement.getBoundingClientRect(); const centerX = rect.left + rect.width / 2; const centerY = rect.top + rect.height / 2; for (let i = 0; i < count; i++) { const particle = document.createElement('div'); particle.className = 'c00lkidd-burst-particle'; document.body.appendChild(particle); const size = Math.random() * 5 + 3; // 3-8px particle.style.width = `${size}px`; particle.style.height = `${size}px`; particle.style.left = `${centerX}px`; particle.style.top = `${centerY}px`; const angle = Math.random() * 2 * Math.PI; const distance = Math.random() * 50 + 20; // 20-70px const translateX = distance * Math.cos(angle); const translateY = distance * Math.sin(angle); particle.style.setProperty('--x', `${translateX}px`); particle.style.setProperty('--y', `${translateY}px`); particle.addEventListener('animationend', () => particle.remove()); } } // --- Game Event Monitoring for Moods and Sounds --- function monitorGameEvents() { // Observe chat messages for system events and player actions const chatMessagesObserver = new MutationObserver(mutations => { mutations.forEach(mutation => { mutation.addedNodes.forEach(node => { if (node.nodeType === 1 && node.classList.contains('bubble')) { const messageText = node.innerText.toLowerCase(); const isSystemMessage = node.classList.contains('systemchatmessage'); if (isSystemMessage) { if (messageText.includes('guessed the word!') || messageText.includes('adivinó la palabra!')) { if (messageText.includes(window.playername) || messageText.includes('you')) { // Check if it's YOUR guess if (ENABLE_C00LKIDD_AGENT) { playSuccessChime(); setC00lkiddMood('happy'); showC00lkiddDialogue("Great guess!", false); createParticleBurst(c00lkiddAgentElement, 10); } } else { // Someone else guessed if (ENABLE_C00LKIDD_AGENT) { setC00lkiddMood('thoughtful'); showC00lkiddDialogue("Good job!", true); // Thought bubble for others' success } } } else if (messageText.includes('is drawing') || messageText.includes('está dibujando')) { if (messageText.includes(window.playername) || messageText.includes('you')) { // Check if it's YOUR turn if (ENABLE_C00LKIDD_AGENT) { playC00lkiddChirp(); setC00lkiddMood('thoughtful'); showC00lkiddDialogue("My turn! Time to create!", false); } } } else if (messageText.includes('turn aborted') || messageText.includes('ronda terminada')) { if (ENABLE_C00LKIDD_AGENT) { playFailBuzz(); setC00lkiddMood('sad'); showC00lkiddDialogue("Oh no...", true); } } } } }); }); }); const chatMessagesContainer = document.getElementById('chatbox_messages'); if (chatMessagesContainer) { chatMessagesObserver.observe(chatMessagesContainer, { childList: true, subtree: true }); } else { // If chat not present yet, observe body to find it const chatObserverFallback = new MutationObserver((mutations, obs) => { const foundChat = document.getElementById('chatbox_messages'); if (foundChat) { chatMessagesObserver.observe(foundChat, { childList: true, subtree: true }); obs.disconnect(); } }); chatObserverFallback.observe(document.body, { childList: true, subtree: true }); } // Monitor player list for "my turn" indication (for mood and dialogue) const playerlistObserver = new MutationObserver(mutations => { mutations.forEach(mutation => { if (mutation.type === 'attributes' && mutation.attributeName === 'class') { const myPlayerRow = document.querySelector(`.playerlist-row[data-uid="${currentPlayerUID}"]`); if (myPlayerRow) { const isMyTurnNow = myPlayerRow.classList.contains('active-drawer'); if (isMyTurnNow && !lastPlayerStatus.isMyTurn && ENABLE_C00LKIDD_AGENT) { playC00lkiddChirp(); setC00lkiddMood('thoughtful'); showC00lkiddDialogue("Draw something cool!", false); } lastPlayerStatus.isMyTurn = isMyTurnNow; } } }); }); const playerListContainer = document.getElementById('playerlist'); if (playerListContainer) { playerlistObserver.observe(playerListContainer, { attributes: true, subtree: true }); } } // --- Initialization and Observers --- function initialize() { if (!ENABLE_C00LKIDD_AGENT) { console.log("C00LKIDD Agent is disabled by configuration."); return; } initAudioContext(); // Set global CSS variables for colors document.documentElement.style.setProperty('--c00lkidd-color', C00LKIDD_PRIMARY_COLOR); document.documentElement.style.setProperty('--c00lkidd-highlight', C00LKIDD_HIGHLIGHT_COLOR); document.documentElement.style.setProperty('--c00lkidd-accent', C00LKIDD_ACCENT_COLOR); // Try to get the current player's UID from the global LOGUID variable if (window.LOGUID && window.LOGUID.length > 0) { currentPlayerUID = window.LOGUID[0]; document.documentElement.style.setProperty('--current-player-uid', currentPlayerUID); } else { const uidObserver = new MutationObserver((mutations, obs) => { if (window.LOGUID && window.LOGUID.length > 0) { currentPlayerUID = window.LOGUID[0]; document.documentElement.style.setProperty('--current-player-uid', currentPlayerUID); // Reload CSS to apply UID-specific rules once UID is known GM_addStyle(` #selfavatarimage, .playerlist-avatarimg[data-uid="${currentPlayerUID}"] img, .playerlist-avatar[data-uid="${currentPlayerUID}"] img, .spawnedavatar[data-uid="${currentPlayerUID}"] img { display: none !important; opacity: 0 !important; } `); obs.disconnect(); } }); uidObserver.observe(document.body, { childList: true, subtree: true }); } // Observe body for dynamically added avatar elements for YOUR player only const avatarObserver = new MutationObserver(mutations => { mutations.forEach(mutation => { mutation.addedNodes.forEach(node => { if (node.nodeType === 1) { if (node.id === 'selfavatarimage' || (node.classList && (node.classList.contains('playerlist-avatarimg') || node.classList.contains('playerlist-avatar') || node.classList.contains('spawnedavatar'))) ) { injectC00lkiddAvatar(node); } } }); }); }); avatarObserver.observe(document.body, { childList: true, subtree: true }); // Initial injection for already existing elements (e.g., on page load) const selfAvatarImg = document.getElementById('selfavatarimage'); if (selfAvatarImg) { injectC00lkiddAvatar(selfAvatarImg); } document.querySelectorAll('.playerlist-avatarimg, .playerlist-avatar, .spawnedavatar').forEach(avatarDiv => { injectC00lkiddAvatar(avatarDiv); }); // Create the main interactive c00lkidd agent createC00lkiddAgent(); // Overwrite Drawaria's gesture handler to inject our animation for YOUR player const gestureHookInterval = setInterval(() => { if (window.spawnedavatar && typeof window.spawnedavatar.gesture === 'function') { const originalGestureHandler = window.spawnedavatar.gesture; window.spawnedavatar.gesture = function(player, gestureType) { originalGestureHandler(player, gestureType); // Only apply our custom sword animation to YOUR c00lkidd avatar if (currentPlayerUID && player.uid === currentPlayerUID) { const selfC00lkiddSword = document.querySelector(`.spawnedavatar[data-uid="${currentPlayerUID}"] .c00lkidd-sword`) || document.querySelector(`.playerlist-avatar[data-uid="${currentPlayerUID}"] .c00lkidd-sword`); if (selfC00lkiddSword) { selfC00lkiddSword.style.display = 'block'; selfC00lkiddSword.style.animation = 'c00lkiddSwordSwing 0.5s ease-out forwards'; playSwingWhoosh(); selfC00lkiddSword.addEventListener('animationend', () => { selfC00lkiddSword.style.animation = ''; selfC00lkiddSword.style.display = 'none'; }, { once: true }); } } }; clearInterval(gestureHookInterval); } }, 100); // Drawing trail if (C00LKIDD_AGENT_DRAW_TRAIL) { const canvas = document.getElementById('canvas'); if (canvas) { canvas.addEventListener('mousemove', (e) => { if (e.buttons === 1 || e.buttons === 2) { // Only when mouse button is pressed (drawing) handleDrawingTrail(e); } }); } else { const canvasObserver = new MutationObserver((mutations, obs) => { const foundCanvas = document.getElementById('canvas'); if (foundCanvas) { foundCanvas.addEventListener('mousemove', (e) => { if (e.buttons === 1 || e.buttons === 2) { handleDrawingTrail(e); } }); obs.disconnect(); } }); canvasObserver.observe(document.body, { childList: true, subtree: true }); } } // Initialize and monitor game events for moods and sounds monitorGameEvents(); // Show welcome message once (session-based) if (!sessionStorage.getItem('c00lkidd_agent_welcomed')) { const welcomeMessage = document.createElement('div'); welcomeMessage.className = 'c00lkidd-welcome-message'; welcomeMessage.innerHTML = ` <p>Hello, Player! <br>Your personal C00LKIDD Agent is here to help you dominate Drawaria!</p> <p style="font-size: 0.7em;">Click on me to interact!</p> `; document.body.appendChild(welcomeMessage); sessionStorage.setItem('c00lkidd_agent_welcomed', 'true'); } } // Ensure DOM is fully loaded before initialization if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', initialize); } else { initialize(); } })();