// ==UserScript==
// @name Drawaria OVNI Simulator Mod
// @namespace http://tampermonkey.net/
// @version 1.0
// @description Simulates the impossible maneuvers of UFOs: instantaneous acceleration from subsonic to supersonic speeds!
// @author YouTubeDrawaria
// @match https://drawaria.online/*
// @match https://*.drawaria.online/*
// @grant GM_xmlhttpRequest
// @license MIT
// @icon https://www.google.com/s2/favicons?sz=64&domain=drawaria.online
// ==/UserScript==
(function () {
'use strict';
/* ---------- MANIOBRAS OVNI DOCUMENTADAS ---------- */
const UFO_MANEUVERS = {
'Ninguno': '',
'🛸 Tic Tac - Movimiento Errático': 'maneuver:tic_tac_erratic', // Caso USS Nimitz
'⚡ Aceleración Instantánea': 'maneuver:instant_acceleration', // Subsónica a supersónica
'🌀 Vuelo Parado Absoluto': 'maneuver:absolute_hover', // Sin propulsión visible
'↩️ Curvas Imposibles': 'maneuver:impossible_turns', // Radios constantes indefinidos
'🎯 Evasión Inteligente': 'maneuver:intelligent_evasion', // Acompañar y mantener distancia
'📡 Manifestación Multi-Sensor': 'maneuver:multi_sensor_detection', // Radar + visual simultáneo
'🔄 Giro GIMBAL': 'maneuver:gimbal_rotation', // 90 grados sin perder altitud
'💨 Desaparición Súbita': 'maneuver:sudden_disappearance', // Velocidades superiores a 620 nudos
'🌊 Patrón de Vuelo Oceánico': 'maneuver:oceanic_pattern', // Atracción a masas de agua
'☢️ Monitoreo Nuclear': 'maneuver:nuclear_monitoring' // Apariciones en instalaciones nucleares
};
const UFO_PHENOMENA = {
'Ninguno': '',
'🌟 Encuentro Cercano Tipo I': 'phenomenon:close_encounter_1', // Observación a menos de 150m
'👽 Encuentro Cercano Tipo II': 'phenomenon:close_encounter_2', // Efectos físicos en el entorno
'🛸 Encuentro Cercano Tipo III': 'phenomenon:close_encounter_3', // Avistamiento de ocupantes
'⚫ Fenómeno de Absorción Lumínica': 'phenomenon:light_absorption', // Horizonte de eventos visual
'🌌 Distorsión Espacial Localizada': 'phenomenon:spatial_distortion', // Efectos gravitacionales
'📊 Anomalía Multi-Espectral': 'phenomenon:multispectral_anomaly', // Detección en múltiples sensores
'🔮 Manifestación Plasmática': 'phenomenon:plasma_manifestation', // Efectos electromagnéticos
'🌪️ Vórtice Atmosférico Controlado': 'phenomenon:controlled_vortex', // Manipulación atmosférica
'⭐ Formación en Triángulo': 'phenomenon:triangular_formation' // Caso Phoenix Lights
};
/* ---------- SETUP BÁSICO ---------- */
let socket;
const canvas = document.getElementById('canvas');
const ctx = canvas ? canvas.getContext('2d') : null;
let stopSignal = false;
let stopBtn;
let activeEffectInterval = null;
let isExecuting = false;
const originalSend = WebSocket.prototype.send;
WebSocket.prototype.send = function (...args) {
if (!socket) socket = this;
return originalSend.apply(this, args);
};
/* ---------- INTERFAZ DE USUARIO ---------- */
const container = document.createElement('div');
container.style.cssText = `
position:fixed; bottom:10px; right:10px; z-index:9999;
background:linear-gradient(135deg, #0a0a0a, #1a1a2e, #2d1b69);
color:#00ffff; padding:15px 20px; border-radius:15px;
font-family: 'Courier New', 'Consolas', monospace; font-size:13px;
display:flex; flex-direction:column; gap:12px;
box-shadow: 0 8px 25px rgba(0,255,255,0.4), inset 0 1px 0 rgba(255,255,255,0.1);
border: 2px solid #00ffff;
min-width: 340px;
backdrop-filter: blur(10px);
cursor: default;
`;
const titleBar = document.createElement('div');
titleBar.innerHTML = '🛸 SIMULADOR FENÓMENOS OVNI 🛸';
titleBar.style.cssText = `
font-weight: bold; font-size: 16px; text-align: center; cursor: grab;
background: linear-gradient(45deg, #00ffff, #00bfff, #87ceeb);
-webkit-background-clip: text; -webkit-text-fill-color: transparent;
text-shadow: 0 0 10px rgba(0, 255, 255, 0.5);
margin: -15px -20px 10px -20px; padding: 15px 20px;
border-bottom: 2px solid rgba(0, 255, 255, 0.3);
border-radius: 15px 15px 0 0;
`;
container.appendChild(titleBar);
const contentDiv = document.createElement('div');
contentDiv.style.cssText = `display:flex; flex-direction:column; gap:12px;`;
container.appendChild(contentDiv);
const ufoInputStyle = `
flex-grow: 1; padding: 8px 12px; border-radius: 8px;
border: 2px solid #00ffff; background: rgba(0, 0, 20, 0.9);
color: #00ffff; font-size: 13px; font-family: 'Courier New', monospace;
transition: all 0.3s ease;
appearance: none;
cursor: pointer;
`;
function createUFORow(parent, labelText, inputElement) {
const wrapper = document.createElement('div');
wrapper.style.cssText = `display:flex; align-items:center; gap:12px;`;
const label = document.createElement('span');
label.textContent = labelText;
label.style.cssText = `color: #00ffff; font-weight: bold; min-width: 100px;`;
wrapper.appendChild(label);
wrapper.appendChild(inputElement);
parent.appendChild(wrapper);
return { wrapper, label, inputElement };
}
// Selector de jugadores
const playerSelect = document.createElement('select');
playerSelect.style.cssText = ufoInputStyle;
createUFORow(contentDiv, '🎯 Objetivo:', playerSelect);
// Selector de maniobras
const maneuverSelect = document.createElement('select');
maneuverSelect.style.cssText = ufoInputStyle;
for (const name in UFO_MANEUVERS) {
const opt = document.createElement('option');
opt.value = UFO_MANEUVERS[name];
opt.textContent = name;
maneuverSelect.appendChild(opt);
}
maneuverSelect.value = UFO_MANEUVERS['Ninguno'];
createUFORow(contentDiv, '🛸 Maniobra:', maneuverSelect);
// Selector de fenómenos
const phenomenonSelect = document.createElement('select');
phenomenonSelect.style.cssText = ufoInputStyle;
for (const name in UFO_PHENOMENA) {
const opt = document.createElement('option');
opt.value = UFO_PHENOMENA[name];
opt.textContent = name;
phenomenonSelect.appendChild(opt);
}
phenomenonSelect.value = UFO_PHENOMENA['Ninguno'];
createUFORow(contentDiv, '✨ Fenómeno:', phenomenonSelect);
// Auto-reset de selectores
maneuverSelect.addEventListener('change', () => {
if (maneuverSelect.value !== '') {
phenomenonSelect.value = UFO_PHENOMENA['Ninguno'];
}
});
phenomenonSelect.addEventListener('change', () => {
if (phenomenonSelect.value !== '') {
maneuverSelect.value = UFO_MANEUVERS['Ninguno'];
}
});
// Intensity slider
const intensitySlider = document.createElement('input');
intensitySlider.type = 'range';
intensitySlider.min = '1';
intensitySlider.max = '5';
intensitySlider.value = '3';
intensitySlider.style.cssText = `
flex-grow: 1; -webkit-appearance: none; height: 6px; border-radius: 5px;
background: linear-gradient(to right, #00ffff 0%, #0080ff 100%);
outline: none;
`;
createUFORow(contentDiv, '⚡ Intensidad:', intensitySlider);
// Repeat toggle
const repeatToggle = document.createElement('input');
repeatToggle.type = 'checkbox';
repeatToggle.id = 'ufoRepeatToggle';
repeatToggle.style.cssText = `margin-right: 8px; cursor: pointer; transform: scale(1.3);`;
const repeatLabel = document.createElement('label');
repeatLabel.htmlFor = 'ufoRepeatToggle';
repeatLabel.textContent = ' 🔄 Repetir Fenómeno';
repeatLabel.style.cssText = `display: flex; align-items: center; cursor: pointer; color: #00ffff;`;
const repeatWrapper = document.createElement('div');
repeatWrapper.style.cssText = `display:flex; align-items:center; gap:0;`;
repeatWrapper.appendChild(repeatToggle);
repeatWrapper.appendChild(repeatLabel);
contentDiv.appendChild(repeatWrapper);
// Botones
const executeBtn = document.createElement('button');
executeBtn.textContent = '🛸 INICIAR SIMULACIÓN OVNI';
executeBtn.disabled = true;
executeBtn.style.cssText = `
padding: 12px 20px; border-radius: 10px; border: none;
background: linear-gradient(145deg, #0080ff, #00bfff);
color: white; font-weight: bold; font-size: 15px;
cursor: pointer; transition: all 0.3s ease;
box-shadow: 0 4px 15px rgba(0, 128, 255, 0.4);
text-transform: uppercase; letter-spacing: 1px;
`;
stopBtn = document.createElement('button');
stopBtn.textContent = '🛑 DETENER FENÓMENO';
stopBtn.disabled = true;
stopBtn.style.cssText = `
margin-top: 8px; padding: 10px 18px; border-radius: 8px; border: none;
background: linear-gradient(145deg, #ff1744, #d50000);
color: white; font-weight: bold; font-size: 14px;
cursor: pointer; transition: all 0.3s ease;
box-shadow: 0 4px 12px rgba(255, 23, 68, 0.4);
text-transform: uppercase;
`;
contentDiv.appendChild(executeBtn);
contentDiv.appendChild(stopBtn);
document.body.appendChild(container);
/* ---------- FUNCIONES AUXILIARES ---------- */
function drawUFOCommand(x1, y1, x2, y2, color, thickness) {
x1 = Math.round(x1); y1 = Math.round(y1);
x2 = Math.round(x2); y2 = Math.round(y2);
if (ctx && canvas) {
ctx.strokeStyle = color;
ctx.lineWidth = thickness;
ctx.lineCap = 'round';
ctx.lineJoin = 'round';
ctx.beginPath();
ctx.moveTo(x1, y1);
ctx.lineTo(x2, y2);
ctx.stroke();
}
if (!socket) return;
const normX1 = (x1 / canvas.width).toFixed(4);
const normY1 = (y1 / canvas.height).toFixed(4);
const normX2 = (x2 / canvas.width).toFixed(4);
const normY2 = (y2 / canvas.height).toFixed(4);
const cmd = `42["drawcmd",0,[${normX1},${normY1},${normX2},${normY2},false,${0 - thickness},"${color}",0,0,{}]]`;
socket.send(cmd);
}
function getPlayerCoords(playerId) {
const avatar = document.querySelector(`.spawnedavatar[data-playerid="${playerId}"]`);
if (!avatar) return null;
const cRect = canvas.getBoundingClientRect();
const aRect = avatar.getBoundingClientRect();
return {
x: Math.round((aRect.left - cRect.left) + (aRect.width / 2)),
y: Math.round((aRect.top - cRect.top) + (aRect.height / 2)),
width: aRect.width,
height: aRect.height
};
}
/* ---------- MANIOBRAS OVNI DOCUMENTADAS ---------- */
// 🛸 Tic Tac - Movimiento Errático (Caso USS Nimitz)
async function ticTacErratic(playerId, intensity = 3) {
if (stopSignal) return;
console.log(`🛸 Simulando comportamiento Tic Tac`);
const target = getPlayerCoords(playerId);
if (!target) return;
let currentX = target.x - 100;
let currentY = target.y - 50;
const movementSteps = 40 + intensity * 10;
// Patrón errático: "izquierda, derecha, adelante, atrás, al azar"
const directions = ['left', 'right', 'forward', 'backward', 'random'];
for (let step = 0; step < movementSteps; step++) {
if (stopSignal) break;
// Seleccionar movimiento según patrón Tic Tac
const direction = directions[step % directions.length];
let nextX = currentX;
let nextY = currentY;
switch (direction) {
case 'left':
nextX = currentX - (30 + Math.random() * 40);
break;
case 'right':
nextX = currentX + (30 + Math.random() * 40);
break;
case 'forward':
nextY = currentY - (20 + Math.random() * 30);
break;
case 'backward':
nextY = currentY + (20 + Math.random() * 30);
break;
case 'random':
nextX = currentX + (Math.random() - 0.5) * 80;
nextY = currentY + (Math.random() - 0.5) * 60;
break;
}
// Dibujar cuerpo del OVNI
const ufoSize = 12 + intensity * 2;
for (let segment = 0; segment < 8; segment++) {
const angle = (segment / 8) * Math.PI * 2;
const segmentX = nextX + ufoSize * Math.cos(angle);
const segmentY = nextY + ufoSize * Math.sin(angle) * 0.3;
drawUFOCommand(nextX, nextY, segmentX, segmentY, '#c0c0c0', 4);
}
// Cúpula
for (let dome = 0; dome < 6; dome++) {
const domeAngle = (dome / 6) * Math.PI * 2;
const domeX = nextX + (ufoSize * 0.6) * Math.cos(domeAngle);
const domeY = nextY - 8 + (ufoSize * 0.6) * Math.sin(domeAngle) * 0.4;
drawUFOCommand(nextX, nextY - 8, domeX, domeY, '#87ceeb', 2);
}
// Estela de movimiento
drawUFOCommand(currentX, currentY, nextX, nextY, '#00ffff', 2);
// Luces parpadeantes
if (Math.random() < 0.6) {
const lightColors = ['#ff0000', '#00ff00', '#0000ff', '#ffff00'];
const lightColor = lightColors[Math.floor(Math.random() * lightColors.length)];
drawUFOCommand(nextX - 5, nextY, nextX + 5, nextY, lightColor, 3);
}
currentX = nextX;
currentY = nextY;
await new Promise(r => setTimeout(r, 150 + Math.random() * 100));
}
}
// ⚡ Aceleración Instantánea (Subsónica a Supersónica)
async function instantAcceleration(playerId, intensity = 3) {
if (stopSignal) return;
console.log(`⚡ Simulando aceleración instantánea`);
const target = getPlayerCoords(playerId);
if (!target) return;
const startX = target.x - 200;
const startY = target.y;
const endX = target.x + 200;
const endY = target.y;
// Fase 1: Vuelo parado (subsónico)
for (let hover = 0; hover < 8; hover++) {
if (stopSignal) break;
const ufoSize = 15 + intensity * 3;
// OVNI estático
for (let segment = 0; segment < 12; segment++) {
const angle = (segment / 12) * Math.PI * 2;
const segmentX = startX + ufoSize * Math.cos(angle);
const segmentY = startY + ufoSize * Math.sin(angle) * 0.4;
drawUFOCommand(startX, startY, segmentX, segmentY, '#c0c0c0', 5);
}
// Efecto de suspensión
for (let field = 0; field < 4; field++) {
const fieldAngle = (field / 4) * Math.PI * 2 + hover * 0.3;
const fieldX = startX + (ufoSize + 10) * Math.cos(fieldAngle);
const fieldY = startY + (ufoSize + 10) * Math.sin(fieldAngle) * 0.3;
drawUFOCommand(startX, startY, fieldX, fieldY, '#00ffff', 1);
}
await new Promise(r => setTimeout(r, 200));
}
// Fase 2: Aceleración instantánea (supersónica)
const accelerationSteps = 3; // Muy pocas fases para mostrar instantaneidad
for (let step = 0; step < accelerationSteps; step++) {
if (stopSignal) break;
const progress = step / accelerationSteps;
const currentX = startX + (endX - startX) * Math.pow(progress, 0.3); // Aceleración exponencial
// Estela supersónica
const trailLength = 80 + step * 40;
for (let trail = 0; trail < 8; trail++) {
const trailX = currentX - trailLength - trail * 15;
drawUFOCommand(currentX, startY, trailX, startY, '#ff4500', 6 - trail);
}
// Onda de choque
if (step > 0) {
for (let shock = 0; shock < 6; shock++) {
const shockAngle = (shock / 6) * Math.PI * 2;
const shockRadius = 30 + step * 20;
const shockX = currentX + shockRadius * Math.cos(shockAngle);
const shockY = startY + shockRadius * Math.sin(shockAngle) * 0.6;
drawUFOCommand(currentX, startY, shockX, shockY, '#ffffff', 4);
}
}
await new Promise(r => setTimeout(r, 100));
}
}
// 🌀 Vuelo Parado Absoluto
async function absoluteHover(playerId, intensity = 3) {
if (stopSignal) return;
console.log(`🌀 Simulando vuelo parado absoluto`);
const target = getPlayerCoords(playerId);
if (!target) return;
const hoverX = target.x;
const hoverY = target.y - 60;
const duration = 100 + intensity * 50;
for (let frame = 0; frame < duration; frame++) {
if (stopSignal) break;
const ufoSize = 18 + intensity * 2;
// Cuerpo del OVNI perfectamente estático
for (let segment = 0; segment < 16; segment++) {
const angle = (segment / 16) * Math.PI * 2;
const segmentX = hoverX + ufoSize * Math.cos(angle);
const segmentY = hoverY + ufoSize * Math.sin(angle) * 0.3;
drawUFOCommand(hoverX, hoverY, segmentX, segmentY, '#c0c0c0', 6);
}
// Campo anti-gravitatorio
const fieldIntensity = Math.sin(frame * 0.1) * 5 + 15;
for (let field = 0; field < 8; field++) {
const fieldAngle = (field / 8) * Math.PI * 2;
const fieldX = hoverX + fieldIntensity * Math.cos(fieldAngle);
const fieldY = hoverY + fieldIntensity * Math.sin(fieldAngle);
drawUFOCommand(hoverX, hoverY, fieldX, fieldY, '#9400d3', 2);
}
// Partículas de suspensión
if (frame % 5 === 0) {
for (let particle = 0; particle < 4; particle++) {
const particleX = hoverX + (Math.random() - 0.5) * 40;
const particleY = hoverY + 20 + Math.random() * 20;
drawUFOCommand(hoverX, hoverY + ufoSize, particleX, particleY, '#00ffff', 1);
}
}
await new Promise(r => setTimeout(r, 80));
}
}
// ↩️ Curvas Imposibles
async function impossibleTurns(playerId, intensity = 3) {
if (stopSignal) return;
console.log(`↩️ Simulando curvas imposibles`);
const target = getPlayerCoords(playerId);
if (!target) return;
const centerX = target.x;
const centerY = target.y;
const radius = 60 + intensity * 15;
// Realizar múltiples curvas con radios constantes pero imposibles
const totalRotations = 2 + intensity;
const stepsPerRotation = 24;
for (let rotation = 0; rotation < totalRotations; rotation++) {
for (let step = 0; step < stepsPerRotation; step++) {
if (stopSignal) break;
const angle = (step / stepsPerRotation) * Math.PI * 2;
const currentX = centerX + radius * Math.cos(angle);
const currentY = centerY + radius * Math.sin(angle);
// OVNI en la curva
const ufoSize = 14 + intensity * 2;
for (let segment = 0; segment < 10; segment++) {
const segmentAngle = (segment / 10) * Math.PI * 2 + angle;
const segmentX = currentX + (ufoSize * 0.8) * Math.cos(segmentAngle);
const segmentY = currentY + (ufoSize * 0.8) * Math.sin(segmentAngle) * 0.4;
drawUFOCommand(currentX, currentY, segmentX, segmentY, '#c0c0c0', 4);
}
// Mostrar trayectoria circular perfecta
const nextAngle = ((step + 1) / stepsPerRotation) * Math.PI * 2;
const nextX = centerX + radius * Math.cos(nextAngle);
const nextY = centerY + radius * Math.sin(nextAngle);
drawUFOCommand(currentX, currentY, nextX, nextY, '#00ff00', 3);
// Efectos de fuerza G imposible (debería ser letal para humanos)
if (step % 4 === 0) {
for (let gforce = 0; gforce < 3; gforce++) {
const gAngle = angle + Math.PI / 2 + gforce * 0.5;
const gX = currentX + 25 * Math.cos(gAngle);
const gY = currentY + 25 * Math.sin(gAngle);
drawUFOCommand(currentX, currentY, gX, gY, '#ff0000', 2);
}
}
await new Promise(r => setTimeout(r, 120));
}
}
}
// 🎯 Evasión Inteligente
async function intelligentEvasion(playerId, intensity = 3) {
if (stopSignal) return;
console.log(`🎯 Simulando evasión inteligente`);
const target = getPlayerCoords(playerId);
if (!target) return;
let ufoX = target.x - 80;
let ufoY = target.y - 60;
const pursuitSteps = 30 + intensity * 10;
// Simular persecución de interceptores
for (let step = 0; step < pursuitSteps; step++) {
if (stopSignal) break;
// OVNI mantiene distancia exacta del "observador"
const targetDistance = 100 + intensity * 20;
const currentDistance = Math.sqrt(Math.pow(ufoX - target.x, 2) + Math.pow(ufoY - target.y, 2));
if (currentDistance < targetDistance) {
// Alejarse si está muy cerca
const escapeAngle = Math.atan2(ufoY - target.y, ufoX - target.x);
ufoX += 25 * Math.cos(escapeAngle);
ufoY += 25 * Math.sin(escapeAngle);
} else if (currentDistance > targetDistance + 50) {
// Acercarse si está muy lejos
const approachAngle = Math.atan2(target.y - ufoY, target.x - ufoX);
ufoX += 15 * Math.cos(approachAngle);
ufoY += 15 * Math.sin(approachAngle);
} else {
// Mantener distancia con movimiento lateral
const tangentAngle = Math.atan2(target.y - ufoY, target.x - ufoX) + Math.PI / 2;
ufoX += 20 * Math.cos(tangentAngle + step * 0.2);
ufoY += 20 * Math.sin(tangentAngle + step * 0.2);
}
// Dibujar OVNI
const ufoSize = 16 + intensity * 2;
for (let segment = 0; segment < 12; segment++) {
const angle = (segment / 12) * Math.PI * 2;
const segmentX = ufoX + ufoSize * Math.cos(angle);
const segmentY = ufoY + ufoSize * Math.sin(angle) * 0.35;
drawUFOCommand(ufoX, ufoY, segmentX, segmentY, '#c0c0c0', 5);
}
// Línea de "observación" al objetivo
drawUFOCommand(ufoX, ufoY, target.x, target.y, '#ff00ff', 1);
// Simular interceptores persiguiendo
if (step % 8 === 0) {
const interceptorX = target.x + Math.random() * 100 - 50;
const interceptorY = target.y + Math.random() * 100 - 50;
// Interceptor "convencional"
drawUFOCommand(interceptorX - 10, interceptorY, interceptorX + 10, interceptorY, '#ff0000', 3);
drawUFOCommand(interceptorX, interceptorY - 5, interceptorX, interceptorY + 5, '#ff0000', 3);
// Línea de persecución (siempre un paso atrás)
drawUFOCommand(interceptorX, interceptorY, ufoX, ufoY, '#ff4444', 1);
}
await new Promise(r => setTimeout(r, 180));
}
}
// 📡 Manifestación Multi-Sensor
async function multiSensorDetection(playerId, intensity = 3) {
if (stopSignal) return;
console.log(`📡 Simulando detección multi-sensor`);
const target = getPlayerCoords(playerId);
if (!target) return;
const duration = 80 + intensity * 30;
// Simular diferentes "sensores" o rayos de detección
const sensors = ['radar', 'infrared', 'visual'];
for (let frame = 0; frame < duration; frame++) {
if (stopSignal) break;
sensors.forEach((sensorType, index) => {
const angle = (index / sensors.length) * Math.PI * 2 + frame * 0.1;
const sensorX = target.x + (60 + intensity * 10) * Math.cos(angle);
const sensorY = target.y + (60 + intensity * 10) * Math.sin(angle);
let color;
switch(sensorType) {
case 'radar': color = '#00ff00'; break; // Green for radar
case 'infrared': color = '#ff4500'; break; // Orange-red for IR
case 'visual': color = '#00ffff'; break; // Cyan for visual (lights)
}
// Línea de detección
drawUFOCommand(target.x, target.y, sensorX, sensorY, color, 2);
// Indicador de sensor (punto o pulso)
for (let i = 0; i < 3; i++) {
const pulseRadius = 5 + Math.sin(frame * 0.2 + index * 0.5) * 3;
drawUFOCommand(sensorX - pulseRadius, sensorY, sensorX + pulseRadius, sensorY, color, 3);
}
});
// OVNI central (observando)
const ufoSize = 15 + intensity * 2;
for (let segment = 0; segment < 8; segment++) {
const angle = (segment / 8) * Math.PI * 2;
const segmentX = target.x + ufoSize * Math.cos(angle);
const segmentY = target.y + ufoSize * Math.sin(angle) * 0.3;
drawUFOCommand(target.x, target.y, segmentX, segmentY, '#c0c0c0', 5);
}
await new Promise(r => setTimeout(r, 150));
}
}
// 🔄 Giro GIMBAL
async function gimbalRotation(playerId, intensity = 3) {
if (stopSignal) return;
console.log(`🔄 Simulando giro GIMBAL`);
const target = getPlayerCoords(playerId);
if (!target) return;
const rotations = 2 + intensity; // Number of 90-degree turns
const stepsPerRotation = 36; // Smoothness of rotation
let currentAngle = 0; // Initial "orientation"
const ufoX = target.x - 50;
const ufoY = target.y - 50;
for (let rotation = 0; rotation < rotations; rotation++) {
for (let step = 0; step < stepsPerRotation; step++) {
if (stopSignal) break;
// Calculate the target angle (e.g., a 90-degree turn)
const targetAngle = (rotation + 1) * (Math.PI / 2); // 0.5PI, 1PI, 1.5PI, 2PI...
// Interpolate angle for smooth rotation
currentAngle = currentAngle + ((targetAngle - currentAngle) / (stepsPerRotation - step));
// Draw the UFO as a "gimbal" object (e.g., a rectangle rotating)
const ufoWidth = 30 + intensity * 5;
const ufoHeight = 10 + intensity * 2;
const cosA = Math.cos(currentAngle);
const sinA = Math.sin(currentAngle);
// Simulate "arms" or structure that remains level
const armLength = 40;
drawUFOCommand(ufoX, ufoY, ufoX + armLength * cosA, ufoY + armLength * sinA, '#d3d3d3', 4);
drawUFOCommand(ufoX, ufoY, ufoX - armLength * cosA, ufoY - armLength * sinA, '#d3d3d3', 4);
// Simulate the "body" that rotates independently (e.g., a square)
const bodySize = 15 + intensity * 3;
drawUFOCommand(ufoX - bodySize, ufoY - bodySize, ufoX + bodySize, ufoY - bodySize, '#ff00ff', 2);
drawUFOCommand(ufoX + bodySize, ufoY - bodySize, ufoX + bodySize, ufoY + bodySize, '#ff00ff', 2);
drawUFOCommand(ufoX + bodySize, ufoY + bodySize, ufoX - bodySize, ufoY + bodySize, '#ff00ff', 2);
drawUFOCommand(ufoX - bodySize, ufoY + bodySize, ufoX - bodySize, ufoY - bodySize, '#ff00ff', 2);
// Indicate the "level" axis (e.g., a horizontal line that stays horizontal)
drawUFOCommand(ufoX - 20, ufoY, ufoX + 20, ufoY, '#00ffff', 2);
await new Promise(r => setTimeout(r, 100));
}
}
}
// 💨 Desaparición Súbita
async function suddenDisappearance(playerId, intensity = 3) {
if (stopSignal) return;
console.log(`💨 Simulando desaparición súbita`);
const target = getPlayerCoords(playerId);
if (!target) return;
const ufoX = target.x + 80;
const ufoY = target.y - 40;
const durationVisible = 30; // Frames visible
const durationFade = 10; // Frames to disappear
// Fase 1: OVNI visible
for (let frame = 0; frame < durationVisible; frame++) {
if (stopSignal) break;
const ufoSize = 20 + intensity * 3;
// Draw a solid UFO
for (let segment = 0; segment < 12; segment++) {
const angle = (segment / 12) * Math.PI * 2;
const segmentX = ufoX + ufoSize * Math.cos(angle);
const segmentY = ufoY + ufoSize * Math.sin(angle) * 0.4;
drawUFOCommand(ufoX, ufoY, segmentX, segmentY, '#a9a9a9', 6);
}
// Add a light pulse
drawUFOCommand(ufoX - 10, ufoY + 5, ufoX + 10, ufoY + 5, '#ffff00', 4);
await new Promise(r => setTimeout(r, 150));
}
// Fase 2: Desaparición instantánea con efectos de rastro
for (let fade = 0; fade < durationFade; fade++) {
if (stopSignal) break;
// Simulate rapidly dissipating energy/plasma
const trailLength = (durationFade - fade) * (20 + intensity * 5);
const trailAlpha = (durationFade - fade) / durationFade; // Fade out effect
// Draw a streaking line that fades
drawUFOCommand(ufoX, ufoY, ufoX + trailLength, ufoY - trailLength, `rgba(135,206,250,${trailAlpha})`, 5); // Light blue streaking
drawUFOCommand(ufoX, ufoY, ufoX - trailLength, ufoY + trailLength, `rgba(255,165,0,${trailAlpha})`, 5); // Orange streaking
// Small "burst" or "implosion" at origin point
for (let i = 0; i < 5; i++) {
const burstRadius = (fade * 5) + (Math.random() * 10);
drawUFOCommand(ufoX, ufoY, ufoX + burstRadius * (Math.random() - 0.5), ufoY + burstRadius * (Math.random() - 0.5), `rgba(255,255,255,${1 - fade/durationFade})`, 2);
}
await new Promise(r => setTimeout(r, 80));
}
// Ensure it's completely gone after fading
// No drawing command here means the canvas clears previous drawings implicitly
}
// 🌊 Patrón de Vuelo Oceánico
async function oceanicPattern(playerId, intensity = 3) {
if (stopSignal) return;
console.log(`🌊 Simulando patrón de vuelo oceánico`);
const target = getPlayerCoords(playerId);
if (!target) return;
const duration = 80 + intensity * 30;
const amplitude = 40 + intensity * 10; // Vertical movement
const wavelength = 0.1; // Horizontal speed
for (let frame = 0; frame < duration; frame++) {
if (stopSignal) break;
const currentX = target.x + Math.sin(frame * wavelength) * amplitude * 0.5;
const currentY = target.y + Math.cos(frame * wavelength) * amplitude; // Vertical oscillation
const ufoSize = 15 + intensity * 2;
// Basic UFO drawing
for (let segment = 0; segment < 8; segment++) {
const angle = (segment / 8) * Math.PI * 2;
const segmentX = currentX + ufoSize * Math.cos(angle);
const segmentY = currentY + ufoSize * Math.sin(angle) * 0.4;
drawUFOCommand(currentX, currentY, segmentX, segmentY, '#add8e6', 5); // Light blue for oceanic theme
}
// Water ripples below
for (let ripple = 0; ripple < 3; ripple++) {
const rippleRadius = (frame % 20) + ripple * 10; // Expanding ripple
const rippleAlpha = 1 - (rippleRadius / (20 + 2 * 10 + 20)); // Fade out
drawUFOCommand(currentX - rippleRadius, currentY + ufoSize + 10, currentX + rippleRadius, currentY + ufoSize + 10, `rgba(0,191,255,${Math.max(0, rippleAlpha)})`, 2);
}
await new Promise(r => setTimeout(r, 120));
}
}
// ☢️ Monitoreo Nuclear
async function nuclearMonitoring(playerId, intensity = 3) {
if (stopSignal) return;
console.log(`☢️ Simulando monitoreo nuclear`);
const target = getPlayerCoords(playerId);
if (!target) return;
const duration = 90 + intensity * 40;
const scanRadius = 50 + intensity * 15;
for (let frame = 0; frame < duration; frame++) {
if (stopSignal) break;
const ufoX = target.x + Math.sin(frame * 0.05) * 80;
const ufoY = target.y - 70 + Math.cos(frame * 0.07) * 40;
const ufoSize = 18 + intensity * 2;
// UFO body
for (let segment = 0; segment < 10; segment++) {
const angle = (segment / 10) * Math.PI * 2;
const segmentX = ufoX + ufoSize * Math.cos(angle);
const segmentY = ufoY + ufoSize * Math.sin(angle) * 0.3;
drawUFOCommand(ufoX, ufoY, segmentX, segmentY, '#c0c0c0', 6);
}
// Scanning beam
const beamColor = `rgba(255,255,0,${0.5 + Math.sin(frame * 0.3) * 0.4})`;
for (let beam = 0; beam < 5; beam++) {
drawUFOCommand(ufoX, ufoY + ufoSize / 2, ufoX + (Math.random() - 0.5) * scanRadius * 2, target.y + target.height / 2 + Math.random() * scanRadius, beamColor, 1 + Math.random() * 2);
}
// Radiation symbols (simplified, flickering)
if (frame % 15 === 0) {
// Draw a stylized radiation symbol (3 arcs + central circle)
const radSymbolSize = 15 + intensity * 2;
const radColor = '#ff0000'; // Red for danger
drawUFOCommand(target.x - radSymbolSize, target.y, target.x + radSymbolSize, target.y, radColor, 2);
drawUFOCommand(target.x, target.y - radSymbolSize, target.x, target.y + radSymbolSize, radColor, 2);
drawUFOCommand(target.x - radSymbolSize * 0.7, target.y - radSymbolSize * 0.7, target.x + radSymbolSize * 0.7, target.y + radSymbolSize * 0.7, radColor, 2);
}
await new Promise(r => setTimeout(r, 100));
}
}
/* ---------- FENÓMENOS OVNI DOCUMENTADOS ---------- */
// 🌟 Encuentro Cercano Tipo I
async function closeEncounter1(playerId, intensity = 3) {
if (stopSignal) return;
console.log(`🌟 Simulando Encuentro Cercano Tipo I`);
const target = getPlayerCoords(playerId);
if (!target) return;
// Observación a menos de 150m sin efectos físicos
const observationDistance = 150 - intensity * 20;
const duration = 60 + intensity * 30;
const ufoX = target.x + (Math.random() - 0.5) * 100; // Slightly randomized start
const ufoY = target.y - (100 + Math.random() * 50);
for (let frame = 0; frame < duration; frame++) {
if (stopSignal) break;
const ufoSize = 18 + intensity * 2;
// Simple disc-shaped UFO
for (let segment = 0; segment < 12; segment++) {
const angle = (segment / 12) * Math.PI * 2;
const segmentX = ufoX + ufoSize * Math.cos(angle);
const segmentY = ufoY + ufoSize * Math.sin(angle) * 0.3;
drawUFOCommand(ufoX, ufoY, segmentX, segmentY, '#d3d3d3', 5);
}
// Add subtle lights
if (frame % 10 < 5) { // Flickering effect
drawUFOCommand(ufoX - 8, ufoY + 5, ufoX + 8, ufoY + 5, '#00ffff', 2);
}
await new Promise(r => setTimeout(r, 120));
}
}
// 👽 Encuentro Cercano Tipo II
async function closeEncounter2(playerId, intensity = 3) {
if (stopSignal) return;
console.log(`👽 Simulando Encuentro Cercano Tipo II (Efectos físicos)`);
const target = getPlayerCoords(playerId);
if (!target) return;
const encounterX = target.x + 50;
const encounterY = target.y - 100;
const duration = 100 + intensity * 40;
for (let frame = 0; frame < duration; frame++) {
if (stopSignal) break;
const ufoSize = 20 + intensity * 3;
// Solid UFO body
for (let segment = 0; segment < 16; segment++) {
const angle = (segment / 16) * Math.PI * 2;
const segmentX = encounterX + ufoSize * Math.cos(angle);
const segmentY = encounterY + ufoSize * Math.sin(angle) * 0.4;
drawUFOCommand(encounterX, encounterY, segmentX, segmentY, '#d3d3d3', 6);
}
// Physical effects (e.g., ground disturbance, electromagnetic interference)
if (frame % 8 === 0) {
// Ground disturbance
for (let i = 0; i < 5; i++) {
const randOffset = (Math.random() - 0.5) * 50;
drawUFOCommand(target.x + randOffset, target.y + target.height / 2, target.x + randOffset + 10, target.y + target.height / 2 + 10, '#8b4513', 2); // Brown lines for disturbed ground
}
// Electromagnetic pulse (visualized as expanding rings)
const empRadius = (frame % 30) * (2 + intensity * 0.5);
const empAlpha = 1 - (empRadius / (30 * (2 + intensity * 0.5)));
drawUFOCommand(target.x, target.y, target.x + empRadius, target.y + empRadius, `rgba(0,255,255,${empAlpha})`, 2); // Cyan rings
drawUFOCommand(target.x, target.y, target.x - empRadius, target.y - empRadius, `rgba(0,255,255,${empAlpha})`, 2);
}
await new Promise(r => setTimeout(r, 100));
}
}
// 🛸 Encuentro Cercano Tipo III
async function closeEncounter3(playerId, intensity = 3) {
if (stopSignal) return;
console.log(`🛸 Simulando Encuentro Cercano Tipo III (Avistamiento de ocupantes)`);
const target = getPlayerCoords(playerId);
if (!target) return;
const ufoX = target.x - 100;
const ufoY = target.y - 80;
const duration = 80 + intensity * 30;
for (let frame = 0; frame < duration; frame++) {
if (stopSignal) break;
const ufoSize = 25 + intensity * 4;
// Large, prominent UFO
for (let segment = 0; segment < 20; segment++) {
const angle = (segment / 20) * Math.PI * 2;
const segmentX = ufoX + ufoSize * Math.cos(angle);
const segmentY = ufoY + ufoSize * Math.sin(angle) * 0.3;
drawUFOCommand(ufoX, ufoY, segmentX, segmentY, '#808080', 7);
}
// Beam descending from UFO (for occupants)
const beamHeight = 40 + Math.sin(frame * 0.1) * 10;
const beamWidth = 10 + intensity * 2;
drawUFOCommand(ufoX - beamWidth / 2, ufoY + ufoSize / 2, ufoX - beamWidth / 2, ufoY + ufoSize / 2 + beamHeight, '#ffffcc', 3);
drawUFOCommand(ufoX + beamWidth / 2, ufoY + ufoSize / 2, ufoX + beamWidth / 2, ufoY + ufoSize / 2 + beamHeight, '#ffffcc', 3);
drawUFOCommand(ufoX - beamWidth / 2, ufoY + ufoSize / 2 + beamHeight, ufoX + beamWidth / 2, ufoY + ufoSize / 2 + beamHeight, '#ffffcc', 3);
// Occupant silhouette (very simplified)
if (frame % 20 < 10) { // Flickering
drawUFOCommand(ufoX, ufoY + ufoSize / 2 + beamHeight + 5, ufoX, ufoY + ufoSize / 2 + beamHeight + 25, '#000000', 5); // Body
drawUFOCommand(ufoX, ufoY + ufoSize / 2 + beamHeight, ufoX, ufoY + ufoSize / 2 + beamHeight + 5, '#000000', 8); // Head
}
await new Promise(r => setTimeout(r, 150));
}
}
// ⚫ Fenómeno de Absorción Lumínica
async function lightAbsorption(playerId, intensity = 3) {
if (stopSignal) return;
console.log(`⚫ Simulando absorción lumínica`);
const target = getPlayerCoords(playerId);
if (!target) return;
const duration = 100 + intensity * 40;
const absorptionCenterX = target.x;
const absorptionCenterY = target.y - 30;
for (let frame = 0; frame < duration; frame++) {
if (stopSignal) break;
const maxAbsorbRadius = 60 + intensity * 20;
const currentAbsorbRadius = (frame / duration) * maxAbsorbRadius;
const alpha = 1 - (frame / duration); // Fades out as it "absorbs"
// Darkening/absorbing core
for (let i = 0; i < 10; i++) {
const angle = (i / 10) * Math.PI * 2 + frame * 0.1;
const innerRadius = currentAbsorbRadius * 0.5;
const outerRadius = currentAbsorbRadius;
drawUFOCommand(
absorptionCenterX + innerRadius * Math.cos(angle),
absorptionCenterY + innerRadius * Math.sin(angle),
absorptionCenterX + outerRadius * Math.cos(angle + 0.5), // Offset for a swirl
absorptionCenterY + outerRadius * Math.sin(angle + 0.5),
`rgba(0,0,0,${alpha * 0.8})`, // Black, fading
5
);
}
// "Light particles" being drawn in
if (frame % 5 === 0) {
for (let j = 0; j < 5; j++) {
const particleX = absorptionCenterX + (Math.random() - 0.5) * maxAbsorbRadius;
const particleY = absorptionCenterY + (Math.random() - 0.5) * maxAbsorbRadius;
drawUFOCommand(particleX, particleY, absorptionCenterX, absorptionCenterY, `rgba(255,255,255,${alpha})`, 1);
}
}
await new Promise(r => setTimeout(r, 100));
}
}
// 🌌 Distorsión Espacial Localizada
async function spatialDistortion(playerId, intensity = 3) {
if (stopSignal) return;
console.log(`🌌 Simulando distorsión espacial localizada`);
const target = getPlayerCoords(playerId);
if (!target) return;
const duration = 90 + intensity * 40;
const distortionRadius = 50 + intensity * 20;
for (let frame = 0; frame < duration; frame++) {
if (stopSignal) break;
const centerX = target.x + (Math.sin(frame * 0.08) * 30);
const centerY = target.y + (Math.cos(frame * 0.06) * 20);
// Distorting lines
for (let i = 0; i < 10; i++) {
const startAngle = (i / 10) * Math.PI * 2;
const endAngle = startAngle + Math.sin(frame * 0.1 + i) * 0.5; // Warping effect
const startX = centerX + distortionRadius * Math.cos(startAngle);
const startY = centerY + distortionRadius * Math.sin(startAngle);
const endX = centerX + distortionRadius * 1.2 * Math.cos(endAngle);
const endY = centerY + distortionRadius * 1.2 * Math.sin(endAngle);
drawUFOCommand(startX, startY, endX, endY, '#8a2be2', 1); // Blue-violet for space distortion
}
// Central anomaly
const anomalySize = 10 + Math.sin(frame * 0.2) * 5;
for (let j = 0; j < 6; j++) {
const angle = (j / 6) * Math.PI * 2;
drawUFOCommand(centerX, centerY, centerX + anomalySize * Math.cos(angle), centerY + anomalySize * Math.sin(angle), '#ffffff', 3);
}
await new Promise(r => setTimeout(r, 100));
}
}
// 📊 Anomalía Multi-Espectral
async function multispectralAnomaly(playerId, intensity = 3) {
if (stopSignal) return;
console.log(`📊 Simulando anomalía multi-espectral`);
const target = getPlayerCoords(playerId);
if (!target) return;
const anomalyX = target.x + 30;
const anomalyY = target.y - 50;
const duration = 100 + intensity * 40;
const colors = ['#ff0000', '#00ff00', '#0000ff', '#ffff00', '#ff00ff', '#00ffff']; // RGB, CMY
for (let frame = 0; frame < duration; frame++) {
if (stopSignal) break;
const pulseSize = 20 + Math.sin(frame * 0.1) * 10;
const pulseColor = colors[Math.floor((frame / 5) % colors.length)];
// Central anomaly pulse
for (let i = 0; i < 8; i++) {
const angle = (i / 8) * Math.PI * 2;
const rayX = anomalyX + pulseSize * Math.cos(angle);
const rayY = anomalyY + pulseSize * Math.sin(angle);
drawUFOCommand(anomalyX, anomalyY, rayX, rayY, pulseColor, 4);
}
// Fading rings for different spectrums
for (let layer = 0; layer < 3; layer++) {
const ringRadius = (frame % 40) + layer * 15;
const ringAlpha = 1 - (ringRadius / (40 + 2 * 15));
const ringColor = colors[(layer + frame) % colors.length];
// Draw a circle segment for simplicity
for (let segment = 0; segment < 12; segment++) {
const startAngle = (segment / 12) * Math.PI * 2;
const endAngle = ((segment + 1) / 12) * Math.PI * 2;
drawUFOCommand(anomalyX + ringRadius * Math.cos(startAngle), anomalyY + ringRadius * Math.sin(startAngle),
anomalyX + ringRadius * Math.cos(endAngle), anomalyY + ringRadius * Math.sin(endAngle),
`rgba(${parseInt(ringColor.substring(1,3),16)},${parseInt(ringColor.substring(3,5),16)},${parseInt(ringColor.substring(5,7),16)},${Math.max(0, ringAlpha)})`, 2);
}
}
await new Promise(r => setTimeout(r, 80));
}
}
// 🔮 Manifestación Plasmática
async function plasmaManifestation(playerId, intensity = 3) {
if (stopSignal) return;
console.log(`🔮 Simulando manifestación plasmática`);
const target = getPlayerCoords(playerId);
if (!target) return;
const centerX = target.x;
const centerY = target.y - 60;
const duration = 100 + intensity * 40;
for (let frame = 0; frame < duration; frame++) {
if (stopSignal) break;
const plasmaRadius = 30 + Math.sin(frame * 0.1) * 15;
const plasmaColor = `hsl(${frame * 5 % 360}, 100%, 50%)`; // Hue changes over time
// Plasma core
for (let i = 0; i < 15; i++) {
const angle = (i / 15) * Math.PI * 2 + Math.random() * 0.5;
const dist = plasmaRadius * Math.random();
drawUFOCommand(centerX, centerY, centerX + dist * Math.cos(angle), centerY + dist * Math.sin(angle), plasmaColor, 2);
}
// Flickering arcs
if (frame % 5 === 0) {
for (let j = 0; j < 5; j++) {
const arcAngle = (Math.random() * Math.PI * 2);
const arcX = centerX + (plasmaRadius + 10) * Math.cos(arcAngle);
const arcY = centerY + (plasmaRadius + 10) * Math.sin(arcAngle);
drawUFOCommand(centerX, centerY, arcX, arcY, '#ffd700', 1); // Gold sparks
}
}
await new Promise(r => setTimeout(r, 70));
}
}
// 🌪️ Vórtice Atmosférico Controlado
async function controlledVortex(playerId, intensity = 3) {
if (stopSignal) return;
console.log(`🌪️ Simulando vórtice atmosférico controlado`);
const target = getPlayerCoords(playerId);
if (!target) return;
const vortexX = target.x;
const vortexY = target.y - 50;
const duration = 120 + intensity * 50;
const maxRadius = 80 + intensity * 20;
for (let frame = 0; frame < duration; frame++) {
if (stopSignal) break;
// Spiral lines forming the vortex
for (let i = 0; i < 10; i++) {
const angleOffset = i * 0.5;
const radiusGrowth = frame * 0.8;
const currentAngle = (frame * 0.2) + angleOffset;
const currentRadius = Math.min(radiusGrowth, maxRadius);
const startX = vortexX + (currentRadius - 10) * Math.cos(currentAngle - 0.1);
const startY = vortexY + (currentRadius - 10) * Math.sin(currentAngle - 0.1);
const endX = vortexX + currentRadius * Math.cos(currentAngle);
const endY = vortexY + currentRadius * Math.sin(currentAngle);
drawUFOCommand(startX, startY, endX, endY, '#808080', 2); // Grey for cloud/vortex
}
// Central eye effect
const eyeSize = 5 + Math.sin(frame * 0.1) * 3;
for (let j = 0; j < 4; j++) {
const angle = (j / 4) * Math.PI * 2;
drawUFOCommand(vortexX, vortexY, vortexX + eyeSize * Math.cos(angle), vortexY + eyeSize * Math.sin(angle), '#ffffff', 3);
}
await new Promise(r => setTimeout(r, 90));
}
}
/* ---------- FUNCIONES PRINCIPALES ---------- */
function updatePlayerOptions() {
const currentSelection = playerSelect.value;
playerSelect.innerHTML = '';
const playerElements = document.querySelectorAll('.spawnedavatar[data-playerid], .playerlist-row[data-playerid]');
const validPlayers = [];
playerElements.forEach(el => {
const playerId = el.dataset.playerid;
if (!playerId || playerId === '0' || el.dataset.self === 'true') return;
let playerName = '';
const nicknameEl = el.querySelector('.nickname, .playerlist-name a, .player-name');
if (nicknameEl) {
playerName = nicknameEl.textContent.trim();
}
if (!playerName) {
const parentRow = el.closest('.playerlist-row');
if (parentRow) {
const nameEl = parentRow.querySelector('.playerlist-name a, .player-name');
if (nameEl) playerName = nameEl.textContent.trim();
}
}
if (!playerName) playerName = `Sujeto ${playerId}`;
if (!validPlayers.some(p => p.id === playerId)) {
validPlayers.push({ id: playerId, name: playerName });
}
});
if (validPlayers.length === 0) {
const opt = document.createElement('option');
opt.value = '';
opt.textContent = '❌ No hay objetivos disponibles';
playerSelect.appendChild(opt);
executeBtn.disabled = true;
} else {
validPlayers.forEach(player => {
const opt = document.createElement('option');
opt.value = player.id;
opt.textContent = `🎯 ${player.name}`;
playerSelect.appendChild(opt);
});
const stillExists = validPlayers.some(p => p.id === currentSelection);
if (currentSelection && stillExists) {
playerSelect.value = currentSelection;
} else {
playerSelect.selectedIndex = 0;
}
executeBtn.disabled = false;
}
}
async function executeUFOSimulation() {
if (isExecuting) return;
const playerId = playerSelect.value;
const maneuverType = maneuverSelect.value;
const phenomenonType = phenomenonSelect.value;
const intensity = parseInt(intensitySlider.value);
const shouldRepeat = repeatToggle.checked;
if (!playerId) {
alert('🚫 Por favor selecciona un objetivo válido');
return;
}
if (!maneuverType && !phenomenonType) {
alert('🚫 Por favor selecciona una maniobra o fenómeno');
return;
}
isExecuting = true;
stopSignal = false;
executeBtn.disabled = true;
stopBtn.disabled = false;
do {
try {
if (maneuverType) {
switch (maneuverType) {
case 'maneuver:tic_tac_erratic':
await ticTacErratic(playerId, intensity);
break;
case 'maneuver:instant_acceleration':
await instantAcceleration(playerId, intensity);
break;
case 'maneuver:absolute_hover':
await absoluteHover(playerId, intensity);
break;
case 'maneuver:impossible_turns':
await impossibleTurns(playerId, intensity);
break;
case 'maneuver:intelligent_evasion':
await intelligentEvasion(playerId, intensity);
break;
case 'maneuver:multi_sensor_detection':
await multiSensorDetection(playerId, intensity);
break;
case 'maneuver:gimbal_rotation':
await gimbalRotation(playerId, intensity);
break;
case 'maneuver:sudden_disappearance':
await suddenDisappearance(playerId, intensity);
break;
case 'maneuver:oceanic_pattern':
await oceanicPattern(playerId, intensity);
break;
case 'maneuver:nuclear_monitoring':
await nuclearMonitoring(playerId, intensity);
break;
}
}
if (phenomenonType) {
switch (phenomenonType) {
case 'phenomenon:triangular_formation':
await triangularFormation(playerId, intensity);
break;
case 'phenomenon:close_encounter_1':
await closeEncounter1(playerId, intensity);
break;
case 'phenomenon:close_encounter_2':
await closeEncounter2(playerId, intensity);
break;
case 'phenomenon:close_encounter_3':
await closeEncounter3(playerId, intensity);
break;
case 'phenomenon:light_absorption':
await lightAbsorption(playerId, intensity);
break;
case 'phenomenon:spatial_distortion':
await spatialDistortion(playerId, intensity);
break;
case 'phenomenon:multispectral_anomaly':
await multispectralAnomaly(playerId, intensity);
break;
case 'phenomenon:plasma_manifestation':
await plasmaManifestation(playerId, intensity);
break;
case 'phenomenon:controlled_vortex':
await controlledVortex(playerId, intensity);
break;
}
}
if (shouldRepeat && !stopSignal) {
await new Promise(r => setTimeout(r, 1500));
}
} catch (error) {
console.error('🛸 Error en simulación OVNI:', error);
break;
}
} while (shouldRepeat && !stopSignal);
isExecuting = false;
executeBtn.disabled = false;
stopBtn.disabled = true;
console.log('🛸 Simulación de fenómenos OVNI completada');
}
function stopExecution() {
stopSignal = true;
isExecuting = false;
if (activeEffectInterval) {
clearInterval(activeEffectInterval);
activeEffectInterval = null;
}
executeBtn.disabled = false;
stopBtn.disabled = true;
console.log('🛑 Simulación detenida por el operador');
}
/* ---------- EVENT LISTENERS ---------- */
executeBtn.addEventListener('click', executeUFOSimulation);
stopBtn.addEventListener('click', stopExecution);
setInterval(updatePlayerOptions, 2000);
updatePlayerOptions();
// Hacer el contenedor arrastrable
let isDragging = false;
let dragOffsetX = 0;
let dragOffsetY = 0;
titleBar.addEventListener('mousedown', (e) => {
isDragging = true;
dragOffsetX = e.clientX - container.offsetLeft;
dragOffsetY = e.clientY - container.offsetTop;
titleBar.style.cursor = 'grabbing';
});
document.addEventListener('mousemove', (e) => {
if (isDragging) {
container.style.left = (e.clientX - dragOffsetX) + 'px';
container.style.top = (e.clientY - dragOffsetY) + 'px';
container.style.right = 'auto';
container.style.bottom = 'auto';
}
});
document.addEventListener('mouseup', () => {
isDragging = false;
titleBar.style.cursor = 'grab';
});
console.log('🛸 SIMULADOR DE FENÓMENOS OVNI cargado exitosamente! 🛸');
console.log('📡 Basado en casos documentados del Pentágono - USS Nimitz, GIMBAL, FLIR1');
console.log('⚡ Maniobras imposibles: Tic Tac, aceleración instantánea, curvas indefinidas');
})();