// ==UserScript==
// @name Drawaria Graveyard Script (Halloween)
// @namespace http://tampermonkey.net/
// @version 3.0
// @description A large, dynamic Halloween scene (The Eerie Graveyard) drawn in the lower-right canvas quadrant, changing between day and night based on local time.
// @author YouTubeDrawaria
// @match https://drawaria.online/*
// @match https://*.drawaria.online/*
// @grant none
// @license MIT
// @icon https://www.google.com/s2/favicons?sz=64&domain=drawaria.online
// @run-at document-idle
// ==/UserScript==
(function() {
'use strict';
// --- GRIMORIO CONSTANTS & HALLOWEEN PALETTE ---
const C_STONE_RED = '#900000'; // Blood Red for stone toggle
const C_STONE_GREEN = '#4F7942'; // Slime Green for stone toggle
const themes = {
day: {
BG: '#C0C0C0', // Misty Gray
LINES: '#5D4037', // Dark Earth/Brown
GHOST: '#E0E0E0', // Faint White
TREE: '#5D4037',
},
night: {
BG: '#1A1A1A', // Deep Black
LINES: '#B0C4DE', // Bone White
GHOST: '#B0C4DE',
TREE: '#B0C4DE',
}
};
// --- LETTER PATHS (clean & unified) --- (KEPT FOR TEXT RENDERING)
const letterPaths = {
a: [[10, 40], [20, 0], [30, 40], [25, 20], [15, 20]],
b: [[0, 0], [0, 40], [15, 40], [20, 35], [20, 25], [15, 20], [0, 20], [15, 20], [20, 15], [20, 5], [15, 0], [0, 0]],
c: [[20, 0], [0, 0], [0, 40], [20, 40]],
d: [[0, 0], [0, 40], [15, 40], [30, 20], [15, 0], [0, 0]],
e: [[30, 0], [0, 0], [0, 20], [20, 20], [0, 20], [0, 40], [30, 40]],
f: [[0, 0], [0, 40], [20, 40], null, [0, 20], [15, 20]],
g: [[30, 10], [20, 0], [10, 0], [0, 10], [0, 30], [10, 40], [20, 40], [30, 30], [20, 20]],
i: [[10, 0], [10, 40]],
j: [[20, 0], [20, 40], [10, 40], [0, 30]],
l: [[0, 0], [0, 40], [20, 40]],
m: [[0, 40], [0, 0], [10, 20], [20, 0], [20, 40]],
n: [[0, 40], [0, 0], [20, 40], [20, 0]],
o: [[10, 0], [20, 0], [30, 10], [30, 30], [20, 40], [10, 40], [0, 30], [0, 10], [10, 0]],
p: [[0, 40], [0, 0], [10, 0], [20, 10], [10, 20], [0, 20]],
r: [[0, 40], [0, 0], [20, 0], [20, 20], [0, 20], [20, 40]],
s: [[20, 0], [10, 0], [0, 10], [20, 20], [30, 30], [20, 40], [10, 40], [0, 30]],
t: [[10, 0], [10, 40], null, [1, 0], [20, 0]],
u: [[0, 0], [0, 30], [10, 40], [20, 40], [30, 30], [30, 0]],
v: [[0, 0], [15, 40], [30, 0]],
z: [[7.5, 35], [9, 36]],
' ': [[0, 0]], // Path vacío para el espacio
// números:
0: [[10, 0], [20, 0], [30, 10], [30, 30], [20, 40], [10, 40], [0, 30], [0, 10], [10, 0]],
1: [[15, 0], [15, 40], null, [15, 0], [10, 10], null, [10, 40], [20, 40]],
2: [[0, 10], [10, 0], [20, 0], [30, 10], [0, 40], [30, 40]],
3: [[0, 10], [10, 0], [20, 0], [30, 10], [20, 20], [30, 30], [20, 40], [10, 40], [0, 30]],
4: [[20, 0], [20, 40], null, [0, 20], [25, 20], null, [0, 20], [20, 0]],
5: [[30, 0], [0, 0], [0, 20], [20, 20], [30, 30], [20, 40], [10, 40], [0, 30]],
6: [[30, 10], [20, 0], [10, 0], [0, 10], [0, 30], [10, 40], [20, 40], [30, 30], [20, 20], [10, 20], [0, 20], [0, 10]],
7: [[0, 0], [30, 0], [15, 40]],
8: [[15, 0], [25, 10], [15, 20], [5, 10], [15, 0], null, [15, 20], [25, 30], [15, 40], [5, 30], [15, 20]],
9: [[5, 35], [15, 40], [25, 30], [30, 10], [20, 0], [10, 0], [0, 10], [5, 20], [15, 20], [25, 20], [27.5, 20]],
o: [[10, 0], [20, 0], [30, 10], [30, 30], [20, 40], [10, 40], [0, 30], [0, 10], [10, 0]],
};
function drawLetter(path, startX, startY, fontSize, color, thickness) {
const scale = fontSize / 40;
for (let i = 0; i < path.length - 1; i++) {
if (path[i] === null || path[i + 1] === null) continue;
const [x1, y1] = path[i], [x2, y2] = path[i + 1];
drawLineServerLocal(
startX + x1 * scale, startY + y1 * scale,
startX + x2 * scale, startY + y2 * scale,
color, thickness
);
}
}
function drawText(str, x, y, color, thickness = 2, fontSize = 18) {
let cx = x;
for (const char of str) {
const path = letterPaths[char.toLowerCase()];
if (path) {
drawLetter(path, cx, y, fontSize, color, thickness);
}
cx += fontSize * 0.6;
}
}
// --- DRAWARIA ADAPTERS (UNCHANGED) ---
let drawariaSocket = null, drawariaCanvas = null, drawariaCtx = null;
function waitUntilReady() { /* ... unchanged ... */
return new Promise(resolve => {
const check = () => {
drawariaCanvas = drawariaCanvas || document.getElementById('canvas');
if (drawariaCanvas) {
drawariaCtx = drawariaCtx || drawariaCanvas.getContext('2d');
}
if (!drawariaSocket && window.WebSocket && window.WebSocket.prototype) {
const origSend = WebSocket.prototype.send;
WebSocket.prototype.send = function(...args) {
if (this.url && this.url.includes('drawaria')) {
drawariaSocket = this;
WebSocket.prototype.send = origSend; // Restore original send
resolve();
}
return origSend.apply(this, args);
};
}
if (drawariaCanvas && drawariaCtx && drawariaSocket) {
resolve();
} else {
setTimeout(check, 250);
}
};
check();
});
}
function drawLineServerLocal(x1, y1, x2, y2, color = '#222', thickness = 3) { /* ... unchanged ... */
if (!drawariaSocket || !drawariaCanvas) return;
const nx1 = (x1 / drawariaCanvas.width).toFixed(4), ny1 = (y1 / drawariaCanvas.height).toFixed(4),
nx2 = (x2 / drawariaCanvas.width).toFixed(4), ny2 = (y2 / drawariaCanvas.height).toFixed(4);
const cmd = `42["drawcmd",0,[${nx1},${ny1},${nx2},${ny2},false,${-Math.abs(thickness)},"${color}",0,0,{}]]`;
drawariaSocket.send(cmd);
drawariaCtx.save();
drawariaCtx.strokeStyle = color;
drawariaCtx.lineWidth = thickness;
drawariaCtx.lineCap = 'round';
drawariaCtx.beginPath();
drawariaCtx.moveTo(x1, y1);
drawariaCtx.lineTo(x2, y2);
drawariaCtx.stroke();
drawariaCtx.restore();
}
function drawFilledRect(x, y, w, h, color) {
// Fills the area efficiently using drawLineServerLocal (as mandated by original script structure)
for (let i = 0; i < h; i += 4) drawLineServerLocal(x, y + i, x + w, y + i, color, 4);
}
// --- SCENE STATE & UTILITIES ---
let isGraveyardActive = false;
let currentTombstoneColor = C_STONE_GREEN; // Default interactive color
function getGraveyardState() {
// 6 PM (18) to 6 AM (6) is night
const hour = new Date().getHours();
return (hour >= 18 || hour < 6) ? 'night' : 'day';
}
function getSceneRect(W, H) {
// Lower-right quadrant (x=W/2, y=H/2 to x=W, y=H)
return {
x: W / 2, y: H / 2,
w: W / 2, h: H / 2
};
}
// --- MAIN RENDER ---
function drawGraveyardScene() {
if (!drawariaCanvas || !isGraveyardActive) return;
const W = drawariaCanvas.width, H = drawariaCanvas.height;
const rect = getSceneRect(W, H);
const { x: sx, y: sy, w: sw, h: sh } = rect;
const state = getGraveyardState();
const theme = themes[state];
// 1. Clear BG
drawFilledRect(sx, sy, sw, sh, theme.BG);
// 2. Dead Trees (Using lines for branch structure)
const branchThickness = 6;
const drawTree = (baseX, baseY) => {
drawLineServerLocal(baseX, baseY, baseX, baseY - sh * 0.25, theme.TREE, branchThickness); // Trunk (thick line for base)
// Branches (thinner lines)
drawLineServerLocal(baseX, baseY - sh * 0.2, baseX - sw * 0.05, baseY - sh * 0.35, theme.TREE, branchThickness / 2);
drawLineServerLocal(baseX, baseY - sh * 0.2, baseX + sw * 0.04, baseY - sh * 0.37, theme.TREE, branchThickness / 2);
drawLineServerLocal(baseX, baseY - sh * 0.1, baseX - sw * 0.08, baseY - sh * 0.15, theme.TREE, branchThickness / 3);
};
drawTree(sx + sw * 0.15, sy + sh * 0.9); // Left Tree
drawTree(sx + sw * 0.85, sy + sh * 0.9); // Right Tree
// 3. Central Tombstone with "R.I.P."
const tsW = sw * 0.2, tsH = sh * 0.35;
const tsX = sx + sw * 0.5 - tsW / 2, tsY = sy + sh * 0.9 - tsH;
const tsLineColor = theme.LINES;
// Tombstone shape (simple rectangle for efficiency, with thick lines for presence)
drawLineServerLocal(tsX, tsY, tsX + tsW, tsY, tsLineColor, 4); // Top
drawLineServerLocal(tsX + tsW, tsY, tsX + tsW, tsY + tsH, tsLineColor, 4); // Right
drawLineServerLocal(tsX, tsY + tsH, tsX + tsW, tsY + tsH, tsLineColor, 4); // Bottom
drawLineServerLocal(tsX, tsY, tsX, tsY + tsH, tsLineColor, 4); // Left
// Tombstone Text ("R.I.P.") - uses the interactive color
drawText("R. I. P.", tsX + 8, tsY + tsH / 2, currentTombstoneColor, 3, 20);
// 4. Ghosts (Simple 'o' letter path for a loop shape)
const drawGhost = (gx, gy) => {
drawLetter(letterPaths.o, gx, gy, 12, theme.GHOST, 2);
drawLineServerLocal(gx+6, gy+12, gx+6, gy+18, theme.GHOST, 2); // 'legs'
drawLineServerLocal(gx+18, gy+12, gx+18, gy+18, theme.GHOST, 2);
};
drawGhost(sx + sw * 0.3, sy + sh * 0.4);
drawGhost(sx + sw * 0.7, sy + sh * 0.6);
drawGhost(sx + sw * 0.55, sy + sh * 0.75);
}
// --- HANDLE CLICK ---
function getMouseCanvasCoords(e) {
const rect = drawariaCanvas.getBoundingClientRect();
return {
x: (e.clientX - rect.left) * (drawariaCanvas.width / rect.width),
y: (e.clientY - rect.top) * (drawariaCanvas.height / rect.height)
};
}
function onCanvasClick(e) {
if (!isGraveyardActive || !drawariaCanvas) return;
const { x: cx, y: cy } = getMouseCanvasCoords(e);
const W = drawariaCanvas.width, H = drawariaCanvas.height;
const rect = getSceneRect(W, H);
// Check if click is within the Graveyard bounds
if (cx >= rect.x && cx <= rect.x + rect.w && cy >= rect.y && cy <= rect.y + rect.h) {
// Toggle the central tombstone color
currentTombstoneColor = (currentTombstoneColor === C_STONE_GREEN) ? C_STONE_RED : C_STONE_GREEN;
drawGraveyardScene(); // Redraw the scene to show the new color
}
}
// --- MAIN BOOT ---
waitUntilReady().then(() => {
// --- CONTROL MENU (Simplified for Scene Toggling) ---
const menu = document.createElement('div');
menu.id = 'drawaria-graveyard-menu';
menu.style.cssText = `
position: absolute;
top: 20px;
left: 20px;
width: 200px;
background: linear-gradient(135deg, #444 0%, #222 100%);
border-radius: 12px;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.6);
color: #fff;
font-family: Arial, sans-serif;
z-index: 10000;
padding: 15px;
cursor: move;
`;
menu.innerHTML = `
<h4 style="margin: 0 0 10px; font-weight: bold; text-align: center; color: #FF8C00;">Graveyard Scene (Halloween)</h4>
<button id="toggle-scene" style="
padding: 8px;
border: none;
border-radius: 8px;
background-color: #900000;
color: white;
font-size: 14px;
font-weight: bold;
cursor: pointer;
width: 100%;
transition: background-color 0.3s;
">Activate Graveyard</button>
`;
document.body.appendChild(menu);
// Make the menu draggable (Logic kept from previous version)
let isDragging = false;
let offset = { x: 0, y: 0 };
const header = menu.querySelector('h4');
header.addEventListener('mousedown', (e) => {
isDragging = true;
offset.x = e.clientX - menu.offsetLeft;
offset.y = e.clientY - menu.offsetTop;
menu.style.cursor = 'grabbing';
e.preventDefault();
});
document.addEventListener('mousemove', (e) => {
if (isDragging) {
menu.style.left = `${e.clientX - offset.x}px`;
menu.style.top = `${e.clientY - offset.y}px`;
}
});
document.addEventListener('mouseup', () => {
isDragging = false;
menu.style.cursor = 'move';
});
// Toggle Button Logic
const toggleButton = document.getElementById('toggle-scene');
toggleButton.addEventListener('click', () => {
isGraveyardActive = !isGraveyardActive;
if (isGraveyardActive) {
toggleButton.textContent = 'Deactivate Graveyard';
toggleButton.style.backgroundColor = '#4F7942';
drawGraveyardScene();
} else {
toggleButton.textContent = 'Activate Graveyard';
toggleButton.style.backgroundColor = '#900000';
// Clear the scene area on turn off (draw a white box)
const W = drawariaCanvas.width, H = drawariaCanvas.height;
const rect = getSceneRect(W, H);
drawFilledRect(rect.x, rect.y, rect.w, rect.h, '#FFFFFF');
}
});
// --- DYNAMIC LOOP ---
// Real-time clock update loop every 3 seconds
setInterval(drawGraveyardScene, 3000);
drawariaCanvas.addEventListener('click', onCanvasClick);
});
})();