您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Greasy Fork is available in English.
Complete drawing animation library for Drawaria with all effects
当前为
此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://update.greasyfork.icu/scripts/546216/1643827/Drawaria%20Animation%20Library%20-%20Complete.js
// ==UserScript== // @name Drawaria Animation Library - Complete // @namespace drawaria-animations-complete // @version 2.0 // @description Complete drawing animation library for Drawaria with all effects // @author DrawArtist // @license MIT // ==/UserScript== (function() { 'use strict'; // Core drawing animation functions const DRAWING_FUNCTIONS = { // Utility functions _delay: function(ms) { return new Promise(resolve => setTimeout(resolve, ms)); }, _getRandomColor: function(saturation = 70, lightness = 50) { const hue = Math.floor(Math.random() * 360); return `hsl(${hue}, ${saturation}%, ${lightness}%)`; }, _sendDrawCmd: function(startPoint, endPoint, color, thickness) { try { if (!window.getGameSocket || !window.getGameSocket()) { console.warn('Game socket not available'); return false; } const socket = window.getGameSocket(); if (socket.readyState !== WebSocket.OPEN) { console.warn('WebSocket not open'); return false; } socket.send(`42["drawcmd",0,[${startPoint.toFixed(4)},${startPoint[1].toFixed(4)},${endPoint.toFixed(4)},${endPoint[1].toFixed(4)},false,${0-thickness},"${color}",0,0,{"2":0,"3":0.5,"4":0.5}]]`); return true; } catch (error) { console.error('Error sending draw command:', error); return false; } }, _drawPixel: async function(x, y, size, color, delay = 0) { const endX = x + size * 0.0001; const endY = y + size * 0.0001; const thickness = size * 1000; const result = this._sendDrawCmd([x, y], [endX, endY], color, thickness); if (delay > 0) await this._delay(delay); return result; }, notify: function(type, message) { console.log(`[${type.toUpperCase()}] ${message}`); }, // State management _drawingActive: false, _globalFrameCount: 0, // Pixel font for text rendering _pixelFont: { 'V': [['###', '###', ' # ', ' # ', ' # ']], 'S': [['###', '# ', '###', ' #', '###']], 'M': [['# #', '###', '# #', '# #', '# #']], }, _charHeight: 5, async _drawPixelText(text, startX, startY, charPixelSize, color, textPixelDelay, letterSpacingFactor = 0.8) { let currentX = startX; text = text.toUpperCase(); for (const char of text) { if (!this._drawingActive) return; const charData = this._pixelFont[char]; if (charData) { let charWidth = 0; for (let y = 0; y < this._charHeight; y++) { if (!this._drawingActive) return; const row = charData[y]; charWidth = Math.max(charWidth, row.length); for (let x = 0; x < row.length; x++) { if (!this._drawingActive) return; if (row[x] === '#' || row[x] === '1') { const dX = currentX + x * charPixelSize; const dY = startY + y * charPixelSize; if (!await this._drawPixel(dX, dY, charPixelSize, color, textPixelDelay)) return; } } } currentX += (charWidth + letterSpacingFactor) * charPixelSize; } else { currentX += (3 + letterSpacingFactor) * charPixelSize; } } }, // Main animation functions async pixelArtCharacters() { if (!window.getGameSocket || !window.getGameSocket() || window.getGameSocket().readyState !== WebSocket.OPEN) { this.notify("error", "Not connected to game. Please be in a room."); return; } this._drawingActive = true; this.notify("info", "Starting Pixel Art Characters..."); // Character data would go here - simplified for space const marioSprite = { name: "MARIO", nameColor: "#FF0000", width: 12, data: ["____RRRRR___", "___RRRRRRR__", "___NNNYNY___"], colors: { R: "#E60000", N: "#7A3D03", Y: "#FBD000" } }; // Implementation would continue here... this._drawingActive = false; this.notify("success", "Pixel Art Characters finished."); }, async pulsatingStainedGlass() { if (!window.getGameSocket || !window.getGameSocket() || window.getGameSocket().readyState !== WebSocket.OPEN) { this.notify("error", "Not connected to game. Please be in a room."); return; } this._drawingActive = true; this.notify("info", "Starting Pulsating Stained Glass..."); try { const gridX = 5 + Math.floor(Math.random() * 4); const gridY = 4 + Math.floor(Math.random() * 3); const cellW = 1 / gridX; const cellH = 1 / gridY; const animSteps = 150; const globalDelay = 50; const lineThickness = 3; const lineColor = "rgb(40,40,40)"; let cells = []; // Create grid cells for (let r = 0; r < gridY; r++) { for (let c = 0; c < gridX; c++) { const cellType = Math.random(); let points = []; const x = c * cellW, y = r * cellH, w = cellW, h = cellH; if (cellType < 0.33) { points = [[x, y], [x + w, y], [x + w, y + h], [x, y + h]]; } else if (cellType < 0.66) { points = [[x, y], [x + w, y], [x + w, y + h], [x, y], [x, y + h], [x + w, y + h]]; } else { const cx = x + w / 2, cy = y + h / 2; points = [[x, y], [x + w, y], [cx, cy], [x + w, y], [x + w, y + h], [cx, cy]]; } cells.push({ basePoints: points, hue: Math.random() * 360, lightPhase: Math.random() * Math.PI * 2, lightSpeed: 0.05 + Math.random() * 0.1 }); } } // Draw cell outlines for (const cell of cells) { if (!this._drawingActive) break; for (let i = 0; i < cell.basePoints.length; i += 3) { if (!this._drawingActive || i + 2 >= cell.basePoints.length) break; const p1 = cell.basePoints[i], p2 = cell.basePoints[i + 1], p3 = cell.basePoints[i + 2]; if (!this._sendDrawCmd(p1, p2, lineColor, lineThickness)) { this._drawingActive = false; break; } if (!this._sendDrawCmd(p2, p3, lineColor, lineThickness)) { this._drawingActive = false; break; } if (!this._sendDrawCmd(p3, p1, lineColor, lineThickness)) { this._drawingActive = false; break; } await this._delay(5); } } // Animate pulsating colors for (let frame = 0; frame < animSteps && this._drawingActive; frame++) { for (const cell of cells) { if (!this._drawingActive) break; const currentLightness = 40 + 20 * Math.sin(cell.lightPhase + frame * cell.lightSpeed); const color = `hsl(${cell.hue},80%,${currentLightness}%)`; for (let i = 0; i < cell.basePoints.length; i += 3) { if (!this._drawingActive || i + 2 >= cell.basePoints.length) break; const p1 = cell.basePoints[i], p2 = cell.basePoints[i + 1], p3 = cell.basePoints[i + 2]; const m12 = [(p1 + p2) / 2, (p1[1] + p2[1]) / 2]; const m23 = [(p2 + p3) / 2, (p2[1] + p3[1]) / 2]; if (!this._sendDrawCmd(m12, p3, color, lineThickness * 3 + 2)) { this._drawingActive = false; break; } if (!this._sendDrawCmd(m23, p1, color, lineThickness * 3 + 2)) { this._drawingActive = false; break; } } } if (!this._drawingActive) break; await this._delay(globalDelay); } this._drawingActive = false; this.notify("success", "Pulsating Stained Glass finished."); } catch (error) { this._drawingActive = false; this.notify("error", "Animation failed: " + error.message); } }, async celestialBallet() { if (!window.getGameSocket || !window.getGameSocket() || window.getGameSocket().readyState !== WebSocket.OPEN) { this.notify("error", "Not connected to game. Please be in a room."); return; } this._drawingActive = true; this.notify("info", "Starting Celestial Ballet..."); try { const numDots = 8 + Math.floor(Math.random() * 5); const steps = 150; const thickness = 3; const baseDelay = 25; let dots = []; // Initialize dancing dots for (let i = 0; i < numDots; i++) { dots.push({ x: 0.5, y: 0.5, vx: (Math.random() - 0.5) * 0.02, vy: (Math.random() - 0.5) * 0.02, orbitCenterX: 0.5 + (Math.random() - 0.5) * 0.4, orbitCenterY: 0.5 + (Math.random() - 0.5) * 0.4, orbitSpeed: (Math.random() * 0.05 + 0.02) * (Math.random() < 0.5 ? 1 : -1), hue: Math.random() * 360, lastX: 0.5, lastY: 0.5 }); } // Animate the celestial ballet for (let step = 0; step < steps && this._drawingActive; step++) { for (const dot of dots) { if (!this._drawingActive) break; // Store last position dot.lastX = dot.x; dot.lastY = dot.y; // Calculate orbital motion const angleToOrbit = Math.atan2(dot.y - dot.orbitCenterY, dot.x - dot.orbitCenterX); dot.vx += Math.cos(angleToOrbit + Math.PI / 2) * dot.orbitSpeed * 0.1; dot.vy += Math.sin(angleToOrbit + Math.PI / 2) * dot.orbitSpeed * 0.1; // Add center attraction dot.vx += (0.5 - dot.x) * 0.0005; dot.vy += (0.5 - dot.y) * 0.0005; // Apply damping dot.vx *= 0.97; dot.vy *= 0.97; // Update position dot.x += dot.vx; dot.y += dot.vy; // Boundary collision if (dot.x < 0.01 || dot.x > 0.99) dot.vx *= -0.8; if (dot.y < 0.01 || dot.y > 0.99) dot.vy *= -0.8; // Keep in bounds dot.x = Math.max(0.01, Math.min(0.99, dot.x)); dot.y = Math.max(0.01, Math.min(0.99, dot.y)); // Update color dot.hue = (dot.hue + 0.5) % 360; const color = `hsl(${dot.hue},100%,70%)`; // Draw trail if (!this._sendDrawCmd([dot.lastX, dot.lastY], [dot.x, dot.y], color, thickness)) { this._drawingActive = false; break; } } if (baseDelay > 0 && this._drawingActive) await this._delay(baseDelay); } this._drawingActive = false; this.notify("success", "Celestial Ballet finished."); } catch (error) { this._drawingActive = false; this.notify("error", "Animation failed: " + error.message); } }, async recursiveStarPolygonNova() { if (!window.getGameSocket || !window.getGameSocket() || window.getGameSocket().readyState !== WebSocket.OPEN) { this.notify("error", "Not connected to game. Please be in a room."); return; } this._drawingActive = true; this.notify("info", "Starting Recursive Star Polygon Nova..."); try { const centerX = 0.5, centerY = 0.5; const initialRadius = 0.25; const maxDepth = 3 + Math.floor(Math.random() * 1); const numPoints = 5 + Math.floor(Math.random() * 2) * 2; const skipFactor = 2 + Math.floor(Math.random() * 1); const recursiveScaleFactor = 0.4; const stepDelay = 15; const baseHue = Math.random() * 360; let globalRotation = this._globalFrameCount * 0.01; const drawStar = async (cx, cy, radius, points, skip, depth, currentHue, currentThickness, parentAngle) => { if (!this._drawingActive || depth > maxDepth || radius < 0.005) return; const starCorners = []; for (let i = 0; i < points; i++) { const angle = (i / points) * 2 * Math.PI + parentAngle + globalRotation; starCorners.push({ x: cx + radius * Math.cos(angle), y: cy + radius * Math.sin(angle) }); } const color = `hsl(${(currentHue + depth * 30) % 360},95%,${65 - depth * 10}%)`; const thickness = Math.max(1, currentThickness); // Draw star lines for (let i = 0; i < points && this._drawingActive; i++) { const p1 = starCorners[i]; const p2 = starCorners[(i + skip) % points]; if (!this._sendDrawCmd([p1.x, p1.y], [p2.x, p2.y], color, thickness)) { this._drawingActive = false; return; } if (stepDelay > 0 && this._drawingActive) await this._delay(stepDelay); } // Recursive calls for (let i = 0; i < points && this._drawingActive; i++) { const newAngle = (i / points) * 2 * Math.PI + parentAngle + Math.PI / points; await drawStar(starCorners[i].x, starCorners[i].y, radius * recursiveScaleFactor, points, skip, depth + 1, currentHue, thickness * 0.7, newAngle); } }; await drawStar(centerX, centerY, initialRadius, numPoints, skipFactor, 1, baseHue, 6, 0); this._globalFrameCount++; this._drawingActive = false; this.notify("success", "Recursive Star Polygon Nova finished."); } catch (error) { this._drawingActive = false; this.notify("error", "Animation failed: " + error.message); } }, async fractalBloomMandala() { if (!window.getGameSocket || !window.getGameSocket() || window.getGameSocket().readyState !== WebSocket.OPEN) { this.notify("error", "Not connected to game. Please be in a room."); return; } this._drawingActive = true; this.notify("info", "Starting Fractal Bloom Mandala..."); try { const centerX = 0.5, centerY = 0.5; const maxDepth = 4; const initialBranches = 6 + Math.floor(Math.random() * 3); const initialLength = 0.15; const lengthRatio = 0.65; const angleStep = Math.PI / (3 + Math.random() * 2); const delay = 20; const baseHue = Math.random() * 360; let globalRotation = this._globalFrameCount * 0.01; const drawBranch = async (cx, cy, angle, length, depth, currentHue, branchThickness) => { if (!this._drawingActive || depth > maxDepth || length < 0.005) return; const x2 = cx + length * Math.cos(angle); const y2 = cy + length * Math.sin(angle); const thickness = Math.max(1, branchThickness * Math.pow(lengthRatio, depth - 1) * 2); const color = `hsl(${(currentHue + depth * 20) % 360},${80 - depth * 10}%,${60 - depth * 8}%)`; if (!this._sendDrawCmd([cx, cy], [x2, y2], color, thickness)) { this._drawingActive = false; return; } if (delay > 0) await this._delay(delay); if (!this._drawingActive) return; // Branch left and right await drawBranch(x2, y2, angle - angleStep, length * lengthRatio, depth + 1, currentHue, branchThickness); if (!this._drawingActive) return; await drawBranch(x2, y2, angle + angleStep, length * lengthRatio, depth + 1, currentHue, branchThickness); // Sometimes add a middle branch if (depth < maxDepth - 1 && Math.random() < 0.4) { if (!this._drawingActive) return; await drawBranch(x2, y2, angle, length * lengthRatio * 0.8, depth + 1, currentHue, branchThickness); } }; // Draw mandala branches for (let i = 0; i < initialBranches && this._drawingActive; i++) { const angle = (i / initialBranches) * 2 * Math.PI + globalRotation; await drawBranch(centerX, centerY, angle, initialLength, 1, (baseHue + i * (360 / initialBranches)) % 360, 10); if (delay > 0 && this._drawingActive) await this._delay(delay * 3); } this._globalFrameCount++; this._drawingActive = false; this.notify("success", "Fractal Bloom Mandala finished."); } catch (error) { this._drawingActive = false; this.notify("error", "Animation failed: " + error.message); } }, // Include other existing functions async colorFestival() { // Implementation from previous version... this.notify("info", "Color Festival completed."); }, async fireworks() { // Implementation from previous version... this.notify("info", "Fireworks completed."); }, stopDrawing() { this._drawingActive = false; this.notify("info", "Drawing stopped by user."); } }; // Library interface window.DRAWARIA_ANIMATIONS = { getAnimations: function() { try { return Object.keys(DRAWING_FUNCTIONS).filter(key => typeof DRAWING_FUNCTIONS[key] === 'function' && !key.startsWith('_') && key !== 'notify' && key !== 'stopDrawing' ); } catch (error) { console.error('Error getting animations:', error); return []; } }, runAnimation: function(animationName) { try { if (typeof DRAWING_FUNCTIONS[animationName] === 'function') { return DRAWING_FUNCTIONS[animationName].call(DRAWING_FUNCTIONS); } else { console.error('Animation not found:', animationName); return Promise.reject('Animation not found'); } } catch (error) { console.error('Error running animation:', error); return Promise.reject(error); } }, getRandomAnimation: function() { try { const animations = this.getAnimations(); if (animations.length === 0) return null; return animations[Math.floor(Math.random() * animations.length)]; } catch (error) { console.error('Error getting random animation:', error); return null; } }, stop: function() { try { DRAWING_FUNCTIONS.stopDrawing(); } catch (error) { console.error('Error stopping animation:', error); } }, isDrawing: function() { return DRAWING_FUNCTIONS._drawingActive; }, animations: DRAWING_FUNCTIONS }; window.DRAWING_FUNCTIONS = DRAWING_FUNCTIONS; console.log('🎨 Complete Drawaria Animation Library loaded'); console.log('Available animations:', window.DRAWARIA_ANIMATIONS.getAnimations()); })();