← Worms results

Worms

Qwen 3.6 27B Fable Fusion 711 Uncensored Heretic NM DAU NEO MAX MTP GGUF · full

Initial view of Worms

Reviews & generation details

Reviews

No human review yet. Unreviewed does not mean unsuccessful.

Generation context

Imported historical artifact. Its exact original instructions and lineage are not known.

Generation prompt · exact text unavailable

See the current prompt for reference. It may differ from the instructions used to generate this artifact.

Inspect original source 100,263 bytes · SHA-256 dce881006588
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Worms Wars - Artillery Game</title>
<style>
*{margin:0;padding:0;box-sizing:border-box}
html,body{width:100%;height:100%;overflow:hidden;background:#0a0a1a;font-family:'Segoe UI',system-ui,sans-serif;color:#fff}
#game-container{position:relative;width:100%;height:100%}
#gameCanvas{display:block;position:absolute;top:0;left:0;width:100%;height:100%;object-fit:contain}
canvas:focus{outline:none}

/* HUD Overlay */
#hud{position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none}

/* Top Bar */
#top-bar{position:absolute;top:0;left:0;right:0;height:44px;display:flex;align-items:center;justify-content:space-between;padding:0 12px;background:linear-gradient(180deg,rgba(10,10,30,0.95) 0%,rgba(10,10,30,0.7) 100%);backdrop-filter:blur(8px);pointer-events:auto;z-index:10}
#wind-indicator{display:flex;align-items:center;gap:6px;font-size:13px;color:#8ec8ff}
#wind-arrow{font-size:18px;transition:transform 0.3s}
#wind-value{font-weight:700;color:#fff}
#turn-timer-container{position:relative;width:140px;height:20px;background:rgba(255,255,255,0.08);border-radius:10px;overflow:hidden;border:1px solid rgba(255,255,255,0.1)}
#turn-timer-fill{height:100%;background:linear-gradient(90deg,#4ecdc4,#ffe66d);transition:width 0.1s linear;border-radius:10px}
#turn-timer-fill.danger{background:linear-gradient(90deg,#ff6b6b,#ee5a24);animation:pulse-danger 0.3s ease infinite alternate}
@keyframes pulse-danger{from{opacity:1}to{opacity:0.7}}
#turn-timer-text{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);font-size:11px;font-weight:700;color:#fff;text-shadow:0 1px 2px rgba(0,0,0,0.5)}
#team-info{display:flex;align-items:center;gap:8px;font-size:13px}
#team-color-dot{width:10px;height:10px;border-radius:50%;border:2px solid rgba(255,255,255,0.3)}
#team-name{font-weight:600}
#worm-name{color:#ffd700;font-weight:700}

/* Health Bars */
#team-health{position:absolute;top:48px;left:8px;display:flex;flex-direction:column;gap:2px;pointer-events:auto;z-index:10}
.team-health-row{display:flex;gap:4px}
.worm-health{width:52px;height:14px;background:rgba(0,0,0,0.6);border-radius:3px;position:relative;overflow:hidden;border:1px solid rgba(255,255,255,0.15);transition:all 0.3s}
.worm-health.active{border-color:#ffd700;box-shadow:0 0 8px rgba(255,215,0,0.4)}
.worm-health.dead{opacity:0.3}
.worm-health-bar{height:100%;border-radius:2px;transition:width 0.4s ease}
.worm-health-label{position:absolute;top:0;left:0;right:0;bottom:0;display:flex;align-items:center;justify-content:center;font-size:8px;font-weight:700;color:#fff;text-shadow:0 1px 2px rgba(0,0,0,0.8)}

/* Bottom Control Panel */
#control-panel{position:absolute;bottom:0;left:0;right:0;height:100px;display:flex;align-items:flex-end;justify-content:center;gap:8px;padding:8px 12px;pointer-events:auto;z-index:10}
#weapon-panel{display:flex;gap:4px;background:rgba(10,10,30,0.9);backdrop-filter:blur(10px);border-radius:12px;padding:6px 8px;border:1px solid rgba(255,255,255,0.1)}
.weapon-slot{width:56px;height:56px;background:rgba(255,255,255,0.05);border-radius:8px;border:2px solid rgba(255,255,255,0.1);display:flex;flex-direction:column;align-items:center;justify-content:center;cursor:pointer;transition:all 0.2s;position:relative;user-select:none}
.weapon-slot:hover{background:rgba(255,255,255,0.12);transform:translateY(-2px)}
.weapon-slot.selected{border-color:#4ecdc4;background:rgba(78,205,196,0.15);box-shadow:0 0 12px rgba(78,205,196,0.3)}
.weapon-slot .icon{font-size:22px}
.weapon-slot .count{font-size:9px;color:#aaa;position:absolute;bottom:3px;right:5px}
.weapon-slot .key{position:absolute;top:2px;left:5px;font-size:8px;color:#666}
.weapon-slot.exhausted{opacity:0.4;pointer-events:none}
.weapon-slot .tooltip{display:none;position:absolute;bottom:62px;left:50%;transform:translateX(-50%);background:rgba(0,0,0,0.95);color:#fff;font-size:11px;padding:4px 8px;border-radius:6px;white-space:nowrap;border:1px solid rgba(255,255,255,0.1);z-index:100}
.weapon-slot:hover .tooltip{display:block}
.weapon-slot .ammo-badge{position:absolute;top:-4px;right:-4px;background:#ff6b6b;color:#fff;font-size:8px;padding:1px 4px;border-radius:8px;font-weight:700}

#items-panel{display:flex;flex-direction:column;gap:4px;align-items:center}
.item-row{display:flex;gap:3px}
.item-slot{width:36px;height:36px;background:rgba(255,255,255,0.05);border-radius:6px;border:1px solid rgba(255,255,255,0.1);display:flex;align-items:center;justify-content:center;cursor:pointer;font-size:16px;transition:all 0.2s;position:relative}
.item-slot:hover{background:rgba(255,255,255,0.12);transform:scale(1.1)}
.item-slot.no-items{opacity:0.3;pointer-events:none}
.item-slot .item-count{position:absolute;top:-4px;right:-4px;font-size:8px;color:#ffd700;background:rgba(0,0,0,0.7);padding:0 3px;border-radius:4px}

/* End Turn Button */
#end-turn-btn{position:absolute;bottom:12px;right:16px;padding:8px 16px;background:linear-gradient(135deg,#e74c3c,#c0392b);color:#fff;border:none;border-radius:8px;font-size:13px;font-weight:700;cursor:pointer;transition:all 0.2s;box-shadow:0 4px 15px rgba(231,76,60,0.4);pointer-events:auto;z-index:10}
#end-turn-btn:hover{transform:translateY(-2px);box-shadow:0 6px 20px rgba(231,76,60,0.6)}

/* Menu Screen */
#menu-screen,#game-over-screen{position:absolute;top:0;left:0;width:100%;height:100%;display:flex;flex-direction:column;align-items:center;justify-content:center;background:linear-gradient(135deg,#0a0a1a 0%,#1a1a3e 50%,#0d2b45 100%);z-index:100}
#game-over-screen{display:none}
.game-title{font-size:64px;font-weight:900;background:linear-gradient(135deg,#ffd700,#ff6b6b,#4ecdc4);-webkit-background-clip:text;-webkit-text-fill-color:transparent;margin-bottom:8px;text-shadow:none;letter-spacing:-1px}
.game-subtitle{font-size:16px;color:#8ec8ff;margin-bottom:32px;letter-spacing:2px;text-transform:uppercase}
.menu-section{margin-bottom:16px;text-align:center}
.menu-label{font-size:12px;color:#8ec8ff;text-transform:uppercase;letter-spacing:1px;margin-bottom:6px}
.menu-buttons{display:flex;gap:8px;justify-content:center}
.menu-btn{padding:10px 20px;background:rgba(255,255,255,0.08);color:#fff;border:1px solid rgba(255,255,255,0.15);border-radius:8px;font-size:14px;cursor:pointer;transition:all 0.2s;font-weight:600}
.menu-btn:hover{background:rgba(255,255,255,0.16);transform:translateY(-1px)}
.menu-btn.active{background:rgba(78,205,196,0.2);border-color:#4ecdc4;color:#4ecdc4}
.start-btn{margin-top:24px;padding:14px 48px;background:linear-gradient(135deg,#4ecdc4,#44a08d);color:#fff;border:none;border-radius:10px;font-size:18px;font-weight:800;cursor:pointer;transition:all 0.2s;box-shadow:0 6px 25px rgba(78,205,196,0.4);letter-spacing:1px;text-transform:uppercase}
.start-btn:hover{transform:translateY(-3px) scale(1.02);box-shadow:0 10px 35px rgba(78,205,196,0.6)}

/* Game Over */
.game-over-title{font-size:48px;font-weight:900;color:#ffd700;margin-bottom:16px}
.winner-info{font-size:24px;color:#fff;margin-bottom:32px}
.game-over-buttons{display:flex;gap:12px}

/* Turn Announcement */
#turn-announcement{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);font-size:32px;font-weight:900;color:#ffd700;text-shadow:0 4px 20px rgba(0,0,0,0.8),0 0 40px rgba(255,215,0,0.3);opacity:0;transition:opacity 0.3s;pointer-events:none;z-index:50;text-align:center}
#turn-announcement.show{opacity:1}
#turn-announcement .team-color{font-size:40px}
#turn-announcement .worm-name-display{font-size:28px;margin-top:4px;color:#fff}

/* Crosshair overlay */
#crosshair-hint{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);font-size:13px;color:rgba(255,255,255,0.6);pointer-events:none;z-index:5;text-align:center}

/* Water indicator */
#water-level-line{position:absolute;left:0;right:0;height:2px;background:rgba(78,205,196,0.3);pointer-events:none;z-index:5}
</style>
</head>
<body>
<div id="game-container">
<canvas id="gameCanvas"></canvas>

<div id="hud" style="display:none">
<div id="top-bar">
<div id="wind-indicator">
<span style="color:#666;font-size:10px">WIND</span>
<span id="wind-arrow">→</span>
<span id="wind-value">0.0</span>
</div>
<div id="turn-timer-container">
<div id="turn-timer-fill"></div>
<span id="turn-timer-text">30</span>
</div>
<div id="team-info">
<div id="team-color-dot"></div>
<span id="worm-name"></span>
<span style="color:#666">of</span>
<span id="team-name"></span>
</div>
</div>
<div id="team-health"></div>
<div id="control-panel">
<div id="weapon-panel"></div>
<div id="items-panel">
<div class="item-row" id="items-row"></div>
</div>
</div>
<button id="end-turn-btn">⏩ End Turn</button>
<div id="turn-announcement"></div>
<div id="crosshair-hint">Left Click to fire • Drag mouse to aim</div>
</div>

<div id="menu-screen">
<div class="game-title">WORMS WARS</div>
<div class="game-subtitle">Artillery Tactics</div>
<div class="menu-section">
<div class="menu-label">Teams</div>
<div class="menu-buttons">
<button class="menu-btn active" data-teams="2">2 Teams</button>
<button class="menu-btn" data-teams="3">3 Teams</button>
<button class="menu-btn" data-teams="4">4 Teams</button>
</div>
</div>
<div class="menu-section">
<div class="menu-label">CPU Difficulty</div>
<div class="menu-buttons">
<button class="menu-btn active" data-difficulty="medium">Medium</button>
<button class="menu-btn" data-difficulty="easy">Easy</button>
<button class="menu-btn" data-difficulty="hard">Hard</button>
</div>
</div>
<div class="menu-section">
<div class="menu-label">Terrain</div>
<div class="menu-buttons">
<button class="menu-btn active" data-terrain="island">Island</button>
<button class="menu-btn" data-terrain="cave">Cave</button>
<button class="menu-btn" data-terrain="dual">Dual Islands</button>
</div>
</div>
<div class="menu-section">
<div class="menu-label">CPU Players</div>
<div class="menu-buttons">
<button class="menu-btn" data-cpu="0">None</button>
<button class="menu-btn" data-cpu="1">1</button>
<button class="menu-btn" data-cpu="2" style="background:rgba(78,205,196,0.2);border-color:#4ecdc4;color:#4ecdc4">2</button>
<button class="menu-btn" data-cpu="3">3</button>
</div>
</div>
<button class="start-btn" id="start-btn">▶ START BATTLE</button>
</div>

<div id="game-over-screen">
<div class="game-over-title">🎉 VICTORY</div>
<div class="winner-info" id="winner-info"></div>
<div class="game-over-buttons">
<button class="start-btn" id="restart-btn">Play Again</button>
<button class="menu-btn" id="menu-btn">Main Menu</button>
</div>
</div>
</div>

<script>
// ============================================================
// WORMS WARS - Complete Game Implementation
// ============================================================

const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');

// ==================== CONSTANTS ====================
const GAME_WIDTH = 2000;
const GAME_HEIGHT = 800;
const WATER_LEVEL = 680;
const GRAVITY = 0.35;
const UNIT_MAX_SPEED = 3;
const UNIT_JUMP_FORCE = -8;
const TURN_TIME = 30;
const FALL_DAMAGE_THRESHOLD = 14;
const WORM_RADIUS = 12;

// Set canvas to game dimensions, CSS will scale it
canvas.width = GAME_WIDTH;
canvas.height = GAME_HEIGHT;

// ==================== AUDIO ENGINE ====================
const AudioEngine = {
    ctx: null,
    masterGain: null,
    init() {
        if (this.ctx) return;
        this.ctx = new (window.AudioContext || window.webkitAudioContext)();
        this.masterGain = this.ctx.createGain();
        this.masterGain.gain.value = 0.3;
        this.masterGain.connect(this.ctx.destination);
    },
    play(type, params = {}) {
        if (!this.ctx) return;
        const t = this.ctx.currentTime;
        switch(type) {
            case 'explosion-small': this._explosion(t, 150, 0.3, params); break;
            case 'explosion-medium': this._explosion(t, 100, 0.5, params); break;
            case 'explosion-large': this._explosion(t, 60, 0.8, params); break;
            case 'explosion-nuke': this._explosion(t, 40, 1.5, params); break;
            case 'shot': this._shot(t); break;
            case 'hit': this._hit(t); break;
            case 'jump': this._jump(t); break;
            case 'click': this._click(t); break;
            case 'menu-hover': this._click(t, 0.8); break;
            case 'menu-select': this._click(t, 1.2); break;
            case 'timer-tick': this._timerTick(t); break;
            case 'timer-urgent': this._timerTick(t, 800); break;
            case 'drown': this._drown(t); break;
            case 'splash': this._splash(t); break;
            case 'powerup': this._powerup(t); break;
            case 'banana': this._banana(t); break;
            case 'laser': this._laser(t); break;
            case 'freeze': this._freeze(t); break;
            case 'cheer': this._cheer(t); break;
        }
    },
    _explosion(t, freq, duration, params) {
        const gain = this.ctx.createGain();
        gain.gain.setValueAtTime(0.8, t);
        gain.gain.exponentialRampToValueAtTime(0.001, t + duration);
        gain.connect(this.masterGain);
        const noise = this.ctx.createBufferSource();
        const bufSize = this.ctx.sampleRate * duration;
        const buf = this.ctx.createBuffer(1, bufSize, this.ctx.sampleRate);
        const data = buf.getChannelData(0);
        for(let i = 0; i < bufSize; i++) data[i] = (Math.random() * 2 - 1) * Math.exp(-i / (bufSize * 0.2));
        noise.buffer = buf;
        const filter = this.ctx.createBiquadFilter();
        filter.type = 'lowpass';
        filter.frequency.value = freq + (params.extraLow ? -50 : 0);
        noise.connect(filter);
        filter.connect(gain);
        noise.start(t);
        const osc = this.ctx.createOscillator();
        osc.frequency.setValueAtTime(freq, t);
        osc.frequency.exponentialRampToValueAtTime(30, t + duration);
        osc.connect(gain);
        osc.start(t);
        osc.stop(t + duration);
    },
    _shot(t) {
        const osc = this.ctx.createOscillator();
        const gain = this.ctx.createGain();
        osc.type = 'sawtooth';
        osc.frequency.setValueAtTime(600, t);
        osc.frequency.exponentialRampToValueAtTime(200, t + 0.15);
        gain.gain.setValueAtTime(0.3, t);
        gain.gain.exponentialRampToValueAtTime(0.001, t + 0.15);
        osc.connect(gain);
        gain.connect(this.masterGain);
        osc.start(t);
        osc.stop(t + 0.15);
    },
    _hit(t) {
        const osc = this.ctx.createOscillator();
        const gain = this.ctx.createGain();
        osc.frequency.value = 300;
        gain.gain.setValueAtTime(0.4, t);
        gain.gain.exponentialRampToValueAtTime(0.001, t + 0.08);
        osc.connect(gain);
        gain.connect(this.masterGain);
        osc.start(t);
        osc.stop(t + 0.08);
    },
    _jump(t) {
        const osc = this.ctx.createOscillator();
        const gain = this.ctx.createGain();
        osc.type = 'sine';
        osc.frequency.setValueAtTime(300, t);
        osc.frequency.linearRampToValueAtTime(500, t + 0.1);
        gain.gain.setValueAtTime(0.2, t);
        gain.gain.exponentialRampToValueAtTime(0.001, t + 0.12);
        osc.connect(gain);
        gain.connect(this.masterGain);
        osc.start(t);
        osc.stop(t + 0.12);
    },
    _click(t, vol = 1) {
        const osc = this.ctx.createOscillator();
        const gain = this.ctx.createGain();
        osc.type = 'square';
        osc.frequency.value = 800;
        gain.gain.setValueAtTime(0.15 * vol, t);
        gain.gain.exponentialRampToValueAtTime(0.001, t + 0.05);
        osc.connect(gain);
        gain.connect(this.masterGain);
        osc.start(t);
        osc.stop(t + 0.05);
    },
    _timerTick(t, freq = 1200) {
        const osc = this.ctx.createOscillator();
        const gain = this.ctx.createGain();
        osc.type = 'sine';
        osc.frequency.value = freq;
        gain.gain.setValueAtTime(0.15, t);
        gain.gain.exponentialRampToValueAtTime(0.001, t + 0.06);
        osc.connect(gain);
        gain.connect(this.masterGain);
        osc.start(t);
        osc.stop(t + 0.06);
    },
    _drown(t) {
        for(let i = 0; i < 3; i++) {
            const osc = this.ctx.createOscillator();
            const gain = this.ctx.createGain();
            osc.type = 'sine';
            osc.frequency.setValueAtTime(400 - i*100, t + i*0.1);
            gain.gain.setValueAtTime(0.2, t + i*0.1);
            gain.gain.exponentialRampToValueAtTime(0.001, t + i*0.1 + 0.2);
            osc.connect(gain);
            gain.connect(this.masterGain);
            osc.start(t + i*0.1);
            osc.stop(t + i*0.1 + 0.2);
        }
    },
    _splash(t) {
        const gain = this.ctx.createGain();
        gain.gain.setValueAtTime(0.4, t);
        gain.gain.exponentialRampToValueAtTime(0.001, t + 0.3);
        gain.connect(this.masterGain);
        const noise = this.ctx.createBufferSource();
        const buf = this.ctx.createBuffer(1, this.ctx.sampleRate * 0.3, this.ctx.sampleRate);
        const data = buf.getChannelData(0);
        for(let i = 0; i < buf.length; i++) data[i] = (Math.random() * 2 - 1) * Math.exp(-i / (buf.length * 0.3));
        noise.buffer = buf;
        const filter = this.ctx.createBiquadFilter();
        filter.type = 'bandpass';
        filter.frequency.value = 800;
        noise.connect(filter);
        filter.connect(gain);
        noise.start(t);
    },
    _powerup(t) {
        [400, 500, 600, 800].forEach((f, i) => {
            const osc = this.ctx.createOscillator();
            const gain = this.ctx.createGain();
            osc.type = 'sine';
            osc.frequency.value = f;
            gain.gain.setValueAtTime(0, t + i*0.05);
            gain.gain.linearRampToValueAtTime(0.2, t + i*0.05 + 0.02);
            gain.gain.exponentialRampToValueAtTime(0.001, t + i*0.05 + 0.1);
            osc.connect(gain);
            gain.connect(this.masterGain);
            osc.start(t + i*0.05);
            osc.stop(t + i*0.05 + 0.1);
        });
    },
    _banana(t) {
        const osc = this.ctx.createOscillator();
        const gain = this.ctx.createGain();
        osc.type = 'sine';
        osc.frequency.setValueAtTime(600, t);
        osc.frequency.linearRampToValueAtTime(200, t + 0.2);
        gain.gain.setValueAtTime(0.3, t);
        gain.gain.exponentialRampToValueAtTime(0.001, t + 0.2);
        osc.connect(gain);
        gain.connect(this.masterGain);
        osc.start(t);
        osc.stop(t + 0.2);
    },
    _laser(t) {
        const osc = this.ctx.createOscillator();
        const gain = this.ctx.createGain();
        osc.type = 'sawtooth';
        osc.frequency.setValueAtTime(2000, t);
        osc.frequency.exponentialRampToValueAtTime(400, t + 0.4);
        gain.gain.setValueAtTime(0.2, t);
        gain.gain.exponentialRampToValueAtTime(0.001, t + 0.4);
        osc.connect(gain);
        gain.connect(this.masterGain);
        osc.start(t);
        osc.stop(t + 0.4);
    },
    _freeze(t) {
        const osc = this.ctx.createOscillator();
        const gain = this.ctx.createGain();
        osc.type = 'sine';
        osc.frequency.setValueAtTime(800, t);
        osc.frequency.linearRampToValueAtTime(2000, t + 0.3);
        gain.gain.setValueAtTime(0.2, t);
        gain.gain.exponentialRampToValueAtTime(0.001, t + 0.3);
        osc.connect(gain);
        gain.connect(this.masterGain);
        osc.start(t);
        osc.stop(t + 0.3);
    },
    _cheer(t) {
        const osc = this.ctx.createOscillator();
        const gain = this.ctx.createGain();
        osc.type = 'triangle';
        osc.frequency.setValueAtTime(400, t);
        osc.frequency.linearRampToValueAtTime(600, t + 0.1);
        osc.frequency.linearRampToValueAtTime(800, t + 0.2);
        gain.gain.setValueAtTime(0.3, t);
        gain.gain.exponentialRampToValueAtTime(0.001, t + 0.5);
        osc.connect(gain);
        gain.connect(this.masterGain);
        osc.start(t);
        osc.stop(t + 0.5);
    }
};

const TEAM_COLORS = [
    {name:'Red Team', color:'#e74c3c', light:'#ff6b6b', dark:'#c0392b'},
    {name:'Blue Team', color:'#3498db', light:'#5dade2', dark:'#2980b9'},
    {name:'Green Team', color:'#2ecc71', light:'#58d68d', dark:'#27ae60'},
    {name:'Purple Team', color:'#9b59b6', light:'#bb8fce', dark:'#8e44ad'}
];

const WORM_NAMES = [
    'Sgt. Stinky', 'Lt. Loopy', 'Cpl. Wiggles', 'Pvt. Gloop',
    'Capt. Crunch', 'Maj. Fluffy', 'Gen. Ooze', 'Brig. Squish',
    'Sgt. Noodle', 'Lt. Puddle', 'Cpl. Bouncy', 'Pvt. Splat',
    'Capt. Wobble', 'Maj. Gooey', 'Gen. Fartington', 'Brig. Sludge'
];

// ==================== WEAPONS DEFINITION ====================
const WEAPONS = {
    bazooka: {
        name:'Bazooka', icon:'🚀', type:'indirect', damage:25, radius:50,
        speed:7, gravity:0.15, fuse:40, color:'#ff9800', sound:'explosion-small',
        ammo:5, desc:'Reliable rocket launcher'
    },
    grenade: {
        name:'Grenade', icon:'💣', type:'indirect', damage:20, radius:40,
        speed:9, gravity:0.25, fuse:50, color:'#4caf50', sound:'explosion-small',
        ammo:8, desc:'Hand-thrown explosive'
    },
    shotgun: {
        name:'Shotgun', icon:'🔫', type:'direct', damage:35, radius:15,
        speed:15, spread:0.3, pellets:5, color:'#9e9e9e', sound:'shot', instant:true,
        ammo:3, desc:'Close-range devastation'
    },
    cluster: {
        name:'Cluster Bomb', icon:'🎯', type:'indirect', damage:15, radius:80,
        speed:6, gravity:0.12, fuse:60, color:'#ff5722', sound:'explosion-medium',
        submunitions:8, subRadius:25, subDamage:10, ammo:2, desc:'Area denial weapon'
    },
    super: {
        name:'Super-explosive', icon:'💥', type:'aoe', damage:45, radius:100,
        speed:5, gravity:0.1, fuse:50, color:'#f44336', sound:'explosion-large',
        ammo:1, desc:'Massive destruction'
    },
    laser: {
        name:'Laser', icon:'⚡', type:'direct', damage:30, radius:5,
        speed:25, color:'#e91e63', sound:'laser', instant:true, ammo:4,
        desc:'Instant hit energy beam'
    },
    uzi: {
        name:'Uzi', icon:'🔫', type:'direct', damage:4, radius:10,
        speed:12, gravity:0.05, ammo:50, burst:15, color:'#2196f3', sound:'shot',
        desc:'Rapid fire submachine gun'
    },
    bananabomb: {
        name:'Banana Bomb', icon:'🍌', type:'indirect', damage:20, radius:45,
        speed:8, gravity:0.2, fuse:120, color:'#ffeb3b', sound:'banana', ammo:3,
        desc:'Tactical fruit weapon'
    },
    nuke: {
        name:'Nuclear Bomb', icon:'☢️', type:'aoe', damage:80, radius:200,
        speed:4, gravity:0.08, fuse:80, color:'#76ff03', sound:'explosion-nuke',
        ammo:1, desc:'MAP WIPING'
    },
    dynamite: {
        name:'Dynamite', icon:'🧨', type:'indirect', damage:30, radius:55,
        speed:7, gravity:0.2, fuse:90, color:'#ff9800', sound:'explosion-medium',
        ammo:4, desc:'Pick up and place explosive'
    }
};

const ITEMS = {
    medkit: {name:'Medkit', icon:'❤️', action:'heal', amount:50},
    parachute: {name:'Parachute', icon:'🪂', action:'parachute'},
    speed: {name:'Speed Boost', icon:'⚡', action:'speed', duration:200},
    freeze: {name:'Ice Bomb', icon:'❄️', action:'freeze_enemy', duration:180, radius:100},
    extraTime: {name:'Extra Time', icon:'⏰', action:'extra_time', amount:15}
};

// ==================== GAME STATE ====================
const game = {
    state: 'menu',
    width: GAME_WIDTH,
    height: GAME_HEIGHT,
    teams: [],
    worms: [],
    currentTeamIndex: 0,
    currentWormIndex: 0,
    turnTimer: TURN_TIME,
    lastTick: 0,
    wind: 0,
    projectiles: [],
    particles: [],
    floatingTexts: [],
    debris: [],
    terrain: null,
    terrainData: null,
    waterData: null,
    selectedWeapon: 0,
    isAiming: false,
    aimStart: null,
    aimEnd: null,
    camera: {x:0, y:0, zoom:1, targetX:0, targetY:0, targetZoom:1},
    shake: {x:0, y:0, intensity:0, decay:0.9},
    freezeTimer: 0,
    config: {
        numTeams: 2,
        cpuCount: 2,
        difficulty: 'medium',
        terrain: 'island'
    },
    terrainOffsetY: 150,
    waterLine: WATER_LEVEL
};

// ==================== TERRAIN GENERATION ====================
const TerrainGen = {
    generate(type) {
        const w = GAME_WIDTH;
        const h = GAME_HEIGHT;
        const imageData = ctx.createImageData(w, h);
        const data = imageData.data;

        // Generate height map
        const heights = new Float32Array(w);

        switch(type) {
            case 'island': this._generateIsland(heights, w); break;
            case 'cave': this._generateCave(heights, w, imageData); break;
            case 'dual': this._generateDualIslands(heights, w); break;
        }

        // Fill terrain from heights
        if(type !== 'cave') {
            const skyGradient = this._generateSky(data, w, h);
            for(let x = 0; x < w; x++) {
                const groundY = heights[x];
                for(let y = 0; y < h; y++) {
                    const idx = (y * w + x) * 4;
                    if(y < groundY) {
                        // Sky - use gradient
                        // Already set
                    } else if(y === groundY) {
                        // Grass top
                        const v = 0.35 + Math.random() * 0.15;
                        data[idx] = Math.floor(34 * v);
                        data[idx+1] = Math.floor(139 * v);
                        data[idx+2] = Math.floor(34 * v);
                        data[idx+3] = 255;
                    } else if(y < groundY + 25) {
                        // Dirt
                        const v = 0.4 + Math.random() * 0.2;
                        data[idx] = Math.floor(120 * v);
                        data[idx+1] = Math.floor(80 * v);
                        data[idx+2] = Math.floor(50 * v);
                        data[idx+3] = 255;
                    } else {
                        // Rock
                        const v = 0.3 + Math.random() * 0.15;
                        data[idx] = Math.floor(80 * v);
                        data[idx+1] = Math.floor(80 * v);
                        data[idx+2] = Math.floor(85 * v);
                        data[idx+3] = 255;
                    }
                }
            }
        }

        // Water
        this._generateWater(data, w, h);

        return {imageData, heights};
    },

    _noise(x, seed) {
        const n = Math.sin(x * 12.9898 + seed * 78.233) * 43758.5453;
        return n - Math.floor(n);
    },

    _smoothNoise(x, seed) {
        const i = Math.floor(x);
        const f = x - i;
        const a = this._noise(i, seed);
        const b = this._noise(i + 1, seed);
        return a + (b - a) * (f * f * (3 - 2 * f));
    },

    _fbm(x, seed, octaves = 4) {
        let val = 0, amp = 1, freq = 1, max = 0;
        for(let i = 0; i < octaves; i++) {
            val += this._smoothNoise(x * freq, seed + i * 10) * amp;
            max += amp;
            amp *= 0.5;
            freq *= 2;
        }
        return val / max;
    },

    _generateIsland(heights, w) {
        const baseHeight = GAME_HEIGHT * 0.55;
        for(let x = 0; x < w; x++) {
            const nx = x / w;
            // Island shape - higher in middle, slopes to edges
            const islandShape = 1 - Math.pow(Math.abs(nx - 0.5) * 2, 1.5);
            const noise = this._fbm(nx * 8, 42);
            const height = baseHeight - islandShape * 180 + noise * 60;
            heights[x] = Math.min(Math.max(height, 100), GAME_HEIGHT - 80);
        }
    },

    _generateDualIslands(heights, w) {
        const baseHeight = GAME_HEIGHT * 0.55;
        for(let x = 0; x < w; x++) {
            const nx = x / w;
            // Two peaks
            const d1 = Math.abs(nx - 0.28);
            const d2 = Math.abs(nx - 0.72);
            const island = Math.max(
                1 - Math.pow(d1 * 4, 1.2),
                1 - Math.pow(d2 * 4, 1.2)
            );
            const noise = this._fbm(nx * 10, 99);
            const height = baseHeight - island * 200 + noise * 50;
            heights[x] = Math.min(Math.max(height, 100), GAME_HEIGHT - 80);
        }
    },

    _generateCave(heights, w, imageData) {
        const data = imageData.data;
        const ceilingY = GAME_HEIGHT * 0.25;
        const floorBase = GAME_HEIGHT * 0.55;

        // Generate floor with noise
        for(let x = 0; x < w; x++) {
            const nx = x / w;
            const noise = this._fbm(nx * 6, 77);
            heights[x] = floorBase + noise * 40;
        }

        // Fill cave - dark background
        for(let i = 0; i < data.length; i += 4) {
            data[i] = 30; data[i+1] = 25; data[i+2] = 35; data[i+3] = 255;
        }

        // Cave ceiling
        const ceilingHeights = new Float32Array(w);
        for(let x = 0; x < w; x++) {
            const nx = x / w;
            const noise = this._fbm(nx * 7, 55);
            ceilingHeights[x] = ceilingY + noise * 50;
        }

        for(let x = 0; x < w; x++) {
            const cy = ceilingHeights[x];
            const fy = heights[x];
            for(let y = 0; y < GAME_HEIGHT; y++) {
                const idx = (y * w + x) * 4;
                if(y >= cy && y < fy) {
                    // Air in cave - dark
                    const depth = (y - cy) / (fy - cy);
                    const v = 0.15 - depth * 0.08;
                    data[idx] = Math.floor(40 * v);
                    data[idx+1] = Math.floor(35 * v);
                    data[idx+2] = Math.floor(55 * v);
                }
            }
        }

        // Ceiling rock
        for(let x = 0; x < w; x++) {
            for(let y = 0; y < ceilingHeights[x]; y++) {
                const idx = (y * w + x) * 4;
                const v = 0.3 + Math.random() * 0.15;
                data[idx] = Math.floor(70 * v);
                data[idx+1] = Math.floor(65 * v);
                data[idx+2] = Math.floor(75 * v);
            }
        }

        // Floor terrain
        for(let x = 0; x < w; x++) {
            const fy = heights[x];
            for(let y = fy; y < GAME_HEIGHT; y++) {
                const idx = (y * w + x) * 4;
                const v = 0.3 + Math.random() * 0.15;
                if(y < fy + 20) {
                    data[idx] = Math.floor(100 * v);
                    data[idx+1] = Math.floor(90 * v);
                    data[idx+2] = Math.floor(100 * v);
                } else {
                    data[idx] = Math.floor(60 * v);
                    data[idx+1] = Math.floor(55 * v);
                    data[idx+2] = Math.floor(65 * v);
                }
            }
        }

        // Water in cave (at bottom)
        this._generateWater(data, w, GAME_HEIGHT);
    },

    _generateSky(data, w, h) {
        for(let y = 0; y < GAME_HEIGHT; y++) {
            const t = Math.min(y / 400, 1);
            const r = 15 + t * 40;
            const g = 20 + t * 50;
            const b = 60 + t * 80;
            for(let x = 0; x < w; x++) {
                const idx = (y * w + x) * 4;
                data[idx] = r;
                data[idx+1] = g;
                data[idx+2] = b;
                data[idx+3] = 255;
            }
        }
    },

    _generateWater(data, w, h) {
        const waterY = WATER_LEVEL;
        for(let y = waterY; y < h; y++) {
            const depth = (y - waterY) / (h - waterY);
            const r = Math.floor(30 - depth * 20);
            const g = Math.floor(80 + depth * 20);
            const b = Math.floor(140 + depth * 40);
            for(let x = 0; x < w; x++) {
                const idx = (y * w + x) * 4;
                // Only color if this is water area (not terrain)
                if(data[idx+3] === 255 && (depth > 0.1 || Math.random() > 0.3)) {
                    data[idx] = r;
                    data[idx+1] = g;
                    data[idx+2] = b;
                    data[idx+3] = Math.floor(200 + depth * 55);
                }
            }
        }
    },

    _isTerrain(x, y) {
        if(x < 0 || x >= GAME_WIDTH || y < 0 || y >= GAME_HEIGHT) return true;
        const idx = (Math.floor(y) * GAME_WIDTH + Math.floor(x)) * 4;
        // If pixel is opaque and not sky/water colored
        const a = game.terrainData.data[idx + 3];
        if(a < 128) return false;
        const r = game.terrainData.data[idx];
        const g = game.terrainData.data[idx + 1];
        const b = game.terrainData.data[idx + 2];
        // Sky: dark blue-purple; Water: teal-blue
        if(r < 40 && g < 40 && b < 100 && y < WATER_LEVEL - 50) return false;
        if(r > 25 && g > 70 && b > 130 && y > WATER_LEVEL - 20) return false;
        return true;
    },

    _isAir(x, y) {
        if(x < 0 || x >= GAME_WIDTH || y < 0 || y >= GAME_HEIGHT) return false;
        const idx = (Math.floor(y) * GAME_WIDTH + Math.floor(x)) * 4;
        const a = game.terrainData.data[idx + 3];
        const r = game.terrainData.data[idx];
        const g = game.terrainData.data[idx + 1];
        const b = game.terrainData.data[idx + 2];
        // Sky area
        if(r < 60 && g < 70 && b < 140 && y < WATER_LEVEL - 50) return true;
        // Cave air
        if(r < 30 && g < 30 && b < 50 && y < WATER_LEVEL - 50) return true;
        // Water
        if(y >= WATER_LEVEL - 10 && r >= 25 && g >= 70 && b >= 130 && a > 180) return true;
        return false;
    },

    _isWater(x, y) {
        if(y < WATER_LEVEL - 5) return false;
        if(x < 0 || x >= GAME_WIDTH || y < 0 || y >= GAME_HEIGHT) return false;
        const idx = (Math.floor(y) * GAME_WIDTH + Math.floor(x)) * 4;
        const r = game.terrainData.data[idx];
        const g = game.terrainData.data[idx + 1];
        const b = game.terrainData.data[idx + 2];
        return r >= 25 && g >= 70 && b >= 130 && game.terrainData.data[idx + 3] > 180;
    },

    _setAir(x, y) {
        if(x < 0 || x >= GAME_WIDTH || y < 0 || y >= GAME_HEIGHT) return;
        const idx = (Math.floor(y) * GAME_WIDTH + Math.floor(x)) * 4;
        game.terrainData.data[idx] = 15;
        game.terrainData.data[idx+1] = 20;
        game.terrainData.data[idx+2] = 60;
        game.terrainData.data[idx+3] = 255;
    },

    _sampleHeight(x) {
        const xi = Math.floor(x);
        if(xi < 0 || xi >= GAME_WIDTH) return GAME_HEIGHT;
        for(let y = 0; y < GAME_HEIGHT; y++) {
            if(this._isTerrain(xi, y)) return y;
        }
        return GAME_HEIGHT;
    }
};

// ==================== PARTICLE SYSTEM ====================
const Particles = {
    create(x, y, type, count, color, params) {
        for(let i = 0; i < count; i++) {
            const angle = Math.random() * Math.PI * 2;
            const speed = (params?.speedMin || 1) + Math.random() * ((params?.speedMax || 4) - (params?.speedMin || 1));
            const life = (params?.lifeMin || 20) + Math.random() * ((params?.lifeMax || 40) - (params?.lifeMin || 20));
            game.particles.push({
                x, y,
                vx: Math.cos(angle) * speed + (params?.vx || 0),
                vy: Math.sin(angle) * speed + (params?.vy || 0) - (params?.lift || 0),
                life, maxLife: life,
                size: (params?.sizeMin || 2) + Math.random() * ((params?.sizeMax || 5) - (params?.sizeMin || 2)),
                color: color || `hsl(${30 + Math.random()*30}, 100%, ${50 + Math.random()*30}%)`,
                type: type || 'default',
                gravity: params?.gravity || 0.05,
                friction: params?.friction || 0.98,
                shape: params?.shape || 'circle',
                trail: params?.trail || false,
                glow: params?.glow || false,
                rotation: Math.random() * Math.PI * 2,
                rotSpeed: (Math.random() - 0.5) * 0.2,
                colorEnd: params?.colorEnd || null,
                sizeEnd: params?.sizeEnd || null
            });
        }
    },

    update() {
        for(let i = game.particles.length - 1; i >= 0; i--) {
            const p = game.particles[i];
            p.life--;
            p.vx *= p.friction;
            p.vy *= p.friction;
            p.vy += p.gravity;
            p.x += p.vx;
            p.y += p.vy;
            p.rotation += p.rotSpeed;
            if(p.type === 'spark') {
                p.size *= 0.96;
            }
            if(p.type === 'smoke') {
                p.size *= 1.02;
            }
            if(p.type === 'debris') {
                if(TerrainGen._isTerrain(p.x, p.y + p.size)) {
                    p.vy *= -0.3;
                    p.vx *= 0.7;
                    p.y -= p.size;
                }
            }
            if(p.life <= 0 || p.x < -50 || p.x > GAME_WIDTH + 50 || p.y > GAME_HEIGHT + 50) {
                game.particles.splice(i, 1);
            }
        }
    },

    draw(ctx) {
        for(const p of game.particles) {
            const alpha = p.life / p.maxLife;
            let color = p.color;
            if(p.colorEnd && alpha < 1) {
                color = this._lerpColor(p.color, p.colorEnd, 1 - alpha);
            }
            const size = p.sizeEnd ? p.size * (alpha * 0.5 + 0.5) : p.size * (alpha * 0.7 + 0.3);

            ctx.save();
            ctx.globalAlpha = alpha;
            ctx.translate(p.x, p.y);
            ctx.rotate(p.rotation);

            if(p.glow) {
                ctx.shadowBlur = 10;
                ctx.shadowColor = color;
            }

            if(p.shape === 'circle') {
                ctx.fillStyle = color;
                ctx.beginPath();
                ctx.arc(0, 0, size, 0, Math.PI * 2);
                ctx.fill();
            } else if(p.shape === 'square') {
                ctx.fillStyle = color;
                ctx.fillRect(-size/2, -size/2, size, size);
            } else if(p.shape === 'star') {
                ctx.fillStyle = color;
                this._drawStar(ctx, 0, 0, 5, size, size * 0.4);
            } else if(p.shape === 'line') {
                ctx.strokeStyle = color;
                ctx.lineWidth = 1;
                ctx.beginPath();
                ctx.moveTo(-size, 0);
                ctx.lineTo(size, 0);
                ctx.stroke();
            }

            ctx.restore();
        }
    },

    _drawStar(ctx, cx, cy, spikes, outerR, innerR) {
        let rot = Math.PI / 2 * 3;
        const step = Math.PI / spikes;
        ctx.beginPath();
        ctx.moveTo(cx, cy - outerR);
        for(let i = 0; i < spikes; i++) {
            ctx.lineTo(cx + Math.cos(rot) * outerR, cy + Math.sin(rot) * outerR);
            rot += step;
            ctx.lineTo(cx + Math.cos(rot) * innerR, cy + Math.sin(rot) * innerR);
            rot += step;
        }
        ctx.closePath();
        ctx.fill();
    },

    _lerpColor(c1, c2, t) {
        if(!c1 || !c2) return c1 || c2;
        if(c1.startsWith('hsl')) return c1;
        const r1 = parseInt(c1.slice(1,3),16), g1 = parseInt(c1.slice(3,5),16), b1 = parseInt(c1.slice(5,7),16);
        const r2 = parseInt(c2.slice(1,3),16), g2 = parseInt(c2.slice(3,5),16), b2 = parseInt(c2.slice(5,7),16);
        const r = Math.round(r1 + (r2-r1)*t);
        const g = Math.round(g1 + (g2-g1)*t);
        const b = Math.round(b1 + (b2-b1)*t);
        return `rgb(${r},${g},${b})`;
    },

    explosion(x, y, radius, color) {
        // Fire
        this.create(x, y, 'fire', 30, null, {
            speedMin: 2, speedMax: 8, lifeMin: 15, lifeMax: 35,
            sizeMin: 3, sizeMax: 10, gravity: -0.1, lift: 2, shape:'circle',
            glow: true, colorEnd: '#333333'
        });
        // Sparks
        this.create(x, y, 'spark', 20, '#ffd700', {
            speedMin: 4, speedMax: 12, lifeMin: 20, lifeMax: 50,
            sizeMin: 1, sizeMax: 3, gravity: 0.15, shape:'circle'
        });
        // Smoke
        this.create(x, y, 'smoke', 15, null, {
            speedMin: 1, speedMax: 4, lifeMin: 40, lifeMax: 80,
            sizeMin: 5, sizeMax: 15, gravity: -0.08, lift: 1, shape:'circle',
            colorEnd: '#555555'
        });
    },

    nuke(x, y) {
        // Massive explosion
        this.explosion(x, y, 200, null);
        this.create(x, y, 'fire', 80, null, {
            speedMin: 5, speedMax: 18, lifeMin: 30, lifeMax: 80,
            sizeMin: 8, sizeMax: 25, gravity: -0.05, lift: 3, shape:'circle', glow:true
        });
        // Shockwave ring particles
        this.create(x, y, 'shockwave', 40, '#ff4444', {
            speedMin: 12, speedMax: 16, lifeMin: 20, lifeMax: 40,
            sizeMin: 3, sizeMax: 6, gravity: 0, friction: 0.96, shape:'circle', glow:true
        });
    },

    debris(x, y, count) {
        const colors = ['#8B4513','#654321','#A0522D','#556B2F','#696969'];
        this.create(x, y, 'debris', count, null, {
            speedMin: 1, speedMax: 5, lifeMin: 60, lifeMax: 150,
            sizeMin: 3, sizeMax: 8, gravity: 0.2, friction: 0.99,
            shape:'square'
        });
    },

    splash(x, y) {
        this.create(x, y, 'splash', 20, '#4fc3f7', {
            speedMin: 2, speedMax: 6, lifeMin: 15, lifeMax: 30,
            sizeMin: 2, sizeMax: 5, gravity: 0.15, vy: -3, shape:'circle'
        });
    },

    muzzleFlash(x, y, dir) {
        this.create(x, y, 'spark', 8, '#ffff00', {
            speedMin: 3, speedMax: 8, lifeMin: 5, lifeMax: 12,
            sizeMin: 2, sizeMax: 5, vx: Math.cos(dir)*5, vy: Math.sin(dir)*5,
            shape:'circle', glow:true
        });
    },

    trail(x, y) {
        this.create(x, y, 'smoke', 1, '#aaaaaa', {
            speedMin: 0, speedMax: 1, lifeMin: 15, lifeMax: 25,
            sizeMin: 2, sizeMax: 4, gravity: -0.05, shape:'circle'
        });
    },

    landing(x, y) {
        this.create(x, y, 'dust', 12, '#d4a76a', {
            speedMin: 1, speedMax: 3, lifeMin: 15, lifeMax: 30,
            sizeMin: 2, sizeMax: 6, gravity: -0.05, vy:-1, shape:'circle'
        });
    },

    freezeEffect(x, y, radius) {
        this.create(x, y, 'spark', 30, '#00bcd4', {
            speedMin: 2, speedMax: 8, lifeMin: 30, lifeMax: 60,
            sizeMin: 2, sizeMax: 8, gravity: -0.05, shape:'star', glow:true
        });
    }
};

// ==================== FLOATING TEXT ====================
const FloatingText = {
    add(x, y, text, color, size = 16) {
        game.floatingTexts.push({
            x, y, text, color, size,
            life: 60, maxLife: 60,
            vy: -1.5, scale: 1.2
        });
    },
    update() {
        for(let i = game.floatingTexts.length - 1; i >= 0; i--) {
            const ft = game.floatingTexts[i];
            ft.life--;
            ft.y += ft.vy;
            ft.vy *= 0.95;
            ft.scale = 1 + (ft.life / ft.maxLife) * 0.3;
            if(ft.life <= 0) game.floatingTexts.splice(i, 1);
        }
    },
    draw(ctx) {
        ctx.textAlign = 'center';
        for(const ft of game.floatingTexts) {
            const alpha = ft.life / ft.maxLife;
            ctx.globalAlpha = alpha;
            ctx.font = `bold ${ft.size * ft.scale}px "Segoe UI", sans-serif`;
            ctx.fillStyle = '#000';
            ctx.fillText(ft.text, ft.x + 1, ft.y + 1);
            ctx.fillStyle = ft.color;
            ctx.fillText(ft.text, ft.x, ft.y);
        }
        ctx.globalAlpha = 1;
    }
};

// ==================== WORM CLASS ====================
class Worm {
    constructor(team, name, color) {
        this.team = team;
        this.name = name;
        this.color = color;
        this.x = 0;
        this.y = 0;
        this.vx = 0;
        this.vy = 0;
        this.hp = 100;
        this.maxHp = 100;
        this.alive = true;
        this.radius = WORM_RADIUS;
        this.onGround = false;
        this.facing = 1;
        this.moveSpeed = UNIT_MAX_SPEED;
        this.parachute = false;
        this.frozen = 0;
        this.invincible = 0;
        this.drowning = 0;
        this.lastFallVY = 0;
        this.turnStartTime = 0;
        this.weaponAmmo = {};
        for(const key in WEAPONS) this.weaponAmmo[key] = WEAPONS[key].ammo;
        this.items = [];
        this.emoteTimer = 0;
    }

    startTurn() {
        this.turnStartTime = Date.now();
        this.invincible = 30;
    }

    update() {
        if(!this.alive) return;

        this.emoteTimer--;

        if(this.frozen > 0) {
            this.frozen--;
            if(this.frozen <= 0) {
                Particles.freezeEffect(this.x, this.y, 30);
            }
            return;
        }

        if(this.invincible > 0) this.invincible--;

        // Apply wind to projectile-like movement
        if(this.parachute) {
            this.vx += game.wind * 0.02;
        }

        // Gravity
        if(!this.onGround || this.parachute) {
            this.vy += GRAVITY;
        }

        // Check water
        const inWater = TerrainGen._isWater(this.x, this.y + this.radius);
        if(inWater && !this.parachute) {
            this.drowning++;
            this.vy *= 0.85;
            this.vx *= 0.85;
            if(this.drowning > 180) {
                this.hp -= 1;
                if(this.hp <= 0) {
                    this.die();
                    return;
                }
                if(this.drowning % 30 === 0) {
                    Particles.splash(this.x, this.y);
                    AudioEngine.play('drown');
                }
            }
        } else {
            this.drowning = Math.max(0, this.drowning - 5);
        }

        // Parachute physics
        if(this.parachute) {
            this.vy = Math.min(this.vy, 1.5);
        }

        // Move
        this.x += this.vx;
        this.y += this.vy;

        // Terrain collision
        this._collideTerrain();

        // Fall damage tracking
        this.lastFallVY = this.vy;

        // Boundaries
        if(this.x < this.radius) { this.x = this.radius; this.vx *= -0.3; }
        if(this.x > GAME_WIDTH - this.radius) { this.x = GAME_WIDTH - this.radius; this.vx *= -0.3; }

        // Check if fallen out of map
        if(this.y > GAME_HEIGHT + 50) {
            this.hp -= 40;
            if(this.hp <= 0) this.die();
            else {
                this.hp -= 40;
                FloatingText.add(this.x, GAME_HEIGHT - 50, 'FELL OUT!', '#ff4444', 18);
                this.respawn();
            }
        }
    }

    _collideTerrain() {
        const r = this.radius;
        let groundY = GAME_HEIGHT;
        let onGround = false;

        // Check ground
        const gx = Math.floor(this.x);
        for(let y = Math.floor(this.y + r); y >= 0; y--) {
            if(TerrainGen._isTerrain(gx, y)) {
                groundY = y;
                break;
            }
        }

        if(this.y + r >= groundY && !TerrainGen._isWater(this.x, this.y + r)) {
            this.y = groundY - r;
            this.vy = 0;
            onGround = true;

            // Fall damage
            if(this.lastFallVY > FALL_DAMAGE_THRESHOLD) {
                const dmg = Math.floor((this.lastFallVY - FALL_DAMAGE_THRESHOLD) * 3);
                this.takeDamage(dmg);
                FloatingText.add(this.x, this.y - 20, `-${dmg} FALL`, '#ffaa00', 14);
                Particles.landing(this.x, groundY);
            }
        }

        // Side collision
        const leftX = Math.floor(this.x - r);
        const rightX = Math.floor(this.x + r);
        const wormY = Math.floor(this.y);

        if(onGround && this.vx !== 0) {
            for(let yOff = -r + 2; yOff <= r - 2; yOff++) {
                const checkY = Math.floor(this.y + yOff);
                if(this.vx > 0 && TerrainGen._isTerrain(rightX, checkY) && !TerrainGen._isAir(rightX, checkY)) {
                    this.x = rightX - r;
                    this.vx = 0;
                }
                if(this.vx < 0 && TerrainGen._isTerrain(leftX, checkY) && !TerrainGen._isAir(leftX, checkY)) {
                    this.x = leftX + r;
                    this.vx = 0;
                }
            }
        }

        this.onGround = onGround;
    }

    jump() {
        if(this.onGround && !this.frozen && this.alive) {
            this.vy = UNIT_JUMP_FORCE;
            this.onGround = false;
            AudioEngine.play('jump');
            Particles.landing(this.x, this.y + this.radius);
            this.emoteTimer = 10;
        }
    }

    takeDamage(amount) {
        if(this.invincible > 0 || !this.alive) return;
        this.hp -= amount;
        if(this.hp <= 0) {
            this.die();
        } else {
            this.hp = Math.max(0, this.hp);
        }
    }

    die() {
        if(!this.alive) return;
        this.alive = false;
        Particles.explosion(this.x, this.y, 30, this.color);
        Particles.create(this.x, this.y, 'debris', 10, '#8B4513', {
            speedMin: 2, speedMax: 6, lifeMin: 40, lifeMax: 100,
            sizeMin: 4, sizeMax: 10, gravity: 0.2, friction: 0.99, shape:'square'
        });
        FloatingText.add(this.x, this.y - 20, '💀 DEAD!', '#ff0000', 20);
        AudioEngine.play('explosion-medium');
        game.shake.intensity = 5;
    }

    respawn() {
        // Find nearest friendly landing spot
        const teamWorms = game.worms.filter(w => w.team === this.team && w.alive);
        let bestX = GAME_WIDTH / 2;
        let bestY = 100;
        for(const w of teamWorms) {
            const dist = Math.abs(w.x - this.x);
            if(dist < Math.abs(bestX - this.x)) {
                bestX = w.x + (Math.random() > 0.5 ? 80 : -80);
            }
        }
        bestX = Math.max(100, Math.min(GAME_WIDTH - 100, bestX));
        for(let y = 0; y < GAME_HEIGHT; y++) {
            if(TerrainGen._isTerrain(Math.floor(bestX), y) && y < WATER_LEVEL - 20) {
                bestY = y - 30;
                break;
            }
        }
        this.x = bestX;
        this.y = bestY;
        this.vx = 0;
        this.vy = 0;
        this.parachute = true;
        this.hp = 50;
        AudioEngine.play('powerup');
        FloatingText.add(this.x, this.y - 20, 'RESPAWN!', '#4ecdc4', 16);
        Particles.create(this.x, this.y, 'spark', 20, '#4ecdc4', {
            speedMin: 2, speedMax: 6, lifeMin: 20, lifeMax: 40,
            sizeMin: 2, sizeMax: 5, shape:'circle', glow:true
        });
    }

    draw(ctx) {
        if(!this.alive) return;

        ctx.save();
        ctx.translate(this.x, this.y);

        // Invincibility flash
        if(this.invincible > 0 && Math.floor(this.invincible / 4) % 2 === 0) {
            ctx.globalAlpha = 0.5;
        }

        // Frozen effect
        if(this.frozen > 0) {
            ctx.fillStyle = 'rgba(0,188,212,0.3)';
            ctx.beginPath();
            ctx.arc(0, 0, this.radius + 4, 0, Math.PI * 2);
            ctx.fill();
        }

        // Parachute
        if(this.parachute) {
            ctx.strokeStyle = '#ffffff';
            ctx.lineWidth = 1;
            ctx.beginPath();
            ctx.moveTo(-8, -30);
            ctx.lineTo(0, -15);
            ctx.moveTo(8, -30);
            ctx.lineTo(0, -15);
            ctx.stroke();
            ctx.fillStyle = '#ff5722';
            ctx.beginPath();
            ctx.arc(-8, -32, 6, Math.PI, 0);
            ctx.arc(8, -32, 6, Math.PI, 0);
            ctx.fill();
        }

        // Drowning indicator
        if(this.drowning > 60) {
            const bubbleY = -this.radius - 5 - (Math.sin(Date.now()/200) * 3);
            ctx.fillStyle = 'rgba(100,200,255,0.7)';
            ctx.beginPath();
            ctx.arc(8 + Math.sin(Date.now()/300)*5, bubbleY - this.drowning % 30 * 0.5, 3, 0, Math.PI*2);
            ctx.fill();
        }

        // Worm body - segmented
        const segments = 4;
        const segWidth = this.radius * 1.5;
        const time = Date.now() / 100;

        for(let i = segments - 1; i >= 0; i--) {
            const segX = (i - (segments-1)/2) * (segWidth * 0.5);
            const wave = Math.sin(time + i * 0.8) * 2;
            const segRadius = this.radius * (1 - Math.abs(i - (segments-1)/2) * 0.15);

            ctx.fillStyle = this.color;
            ctx.beginPath();
            ctx.ellipse(segX, wave, segRadius * 1.3, segRadius, 0, 0, Math.PI * 2);
            ctx.fill();

            // Highlight
            ctx.fillStyle = this.color.light || this.color;
            ctx.globalAlpha = ctx.globalAlpha || 1;
            const highlightAlpha = 0.3 * ctx.globalAlpha;
            ctx.fillStyle = `rgba(255,255,255,${highlightAlpha})`;
            ctx.beginPath();
            ctx.ellipse(segX - 2, wave - 2, segRadius * 0.5, segRadius * 0.3, -0.3, 0, Math.PI * 2);
            ctx.fill();
        }

        ctx.globalAlpha = 1;

        // Face (on front segment)
        const faceX = this.facing * segWidth * 0.35;
        const faceWave = Math.sin(time + (segments-1) * 0.8) * 2;

        // Eyes
        ctx.fillStyle = '#fff';
        ctx.beginPath();
        ctx.arc(faceX - 3 * this.facing, faceWave - 3, 4, 0, Math.PI * 2);
        ctx.fill();
        ctx.fillStyle = '#000';
        ctx.beginPath();
        ctx.arc(faceX - 2 * this.facing, faceWave - 3, 2, 0, Math.PI * 2);
        ctx.fill();

        // Mouth
        ctx.strokeStyle = '#000';
        ctx.lineWidth = 1.5;
        ctx.beginPath();
        if(this.emoteTimer > 0) {
            // Happy/open mouth when jumping
            ctx.arc(faceX, faceWave + 3, 3, 0, Math.PI);
        } else {
            // Neutral smile
            ctx.arc(faceX, faceWave + 1, 2.5, 0.2, Math.PI - 0.2);
        }
        ctx.stroke();

        // Drowning sad face
        if(this.drowning > 120) {
            ctx.strokeStyle = '#000';
            ctx.lineWidth = 1.5;
            ctx.beginPath();
            ctx.arc(faceX, faceWave + 5, 2.5, Math.PI + 0.2, -0.2);
            ctx.stroke();
        }

        // Health bar
        const barWidth = 24;
        const barHeight = 3;
        const barX = -barWidth / 2;
        const barY = -this.radius - 10;
        const hpRatio = this.hp / this.maxHp;

        ctx.fillStyle = 'rgba(0,0,0,0.5)';
        ctx.fillRect(barX, barY, barWidth, barHeight);
        ctx.fillStyle = hpRatio > 0.5 ? '#4caf50' : hpRatio > 0.25 ? '#ff9800' : '#f44336';
        ctx.fillRect(barX, barY, barWidth * hpRatio, barHeight);

        ctx.restore();
    }
}

// ==================== PROJECTILE CLASS ====================
class Projectile {
    constructor(x, y, vx, vy, weapon, owner) {
        this.x = x;
        this.y = y;
        this.vx = vx;
        this.vy = vy;
        this.weapon = weapon;
        this.owner = owner;
        this.life = weapon.fuse || 300;
        this.active = true;
        this.radius = 4;
        this.trailTimer = 0;
        this.isDynamite = weapon.name === 'Dynamite';
        this.pickedUp = false;
        this.carrier = null;
    }

    update() {
        if(!this.active) return;

        // Wind effect
        this.vx += game.wind * this.weapon.gravity * 0.3;

        // Gravity
        this.vy += this.weapon.gravity || 0;

        if(this.isDynamite && this.pickedUp) {
            this.x = this.carrier.x;
            this.y = this.carrier.y - 20;
            return;
        }

        this.x += this.vx;
        this.y += this.vy;

        this.trailTimer++;
        if(this.trailTimer % 3 === 0 && !this.weapon.instant) {
            Particles.trail(this.x, this.y);
        }

        // Terrain collision
        if(TerrainGen._isTerrain(this.x, this.y) && !TerrainGen._isAir(this.x, this.y)) {
            this.explode();
            return;
        }

        // Water collision
        if(TerrainGen._isWater(this.x, this.y)) {
            Particles.splash(this.x, this.y);
            AudioEngine.play('splash');
            this.explode();
            return;
        }

        // Worm collision
        for(const worm of game.worms) {
            if(!worm.alive || worm.team === this.owner.team) continue;
            const dx = this.x - worm.x;
            const dy = this.y - worm.y;
            if(Math.sqrt(dx*dx + dy*dy) < worm.radius + this.radius) {
                this.explode();
                return;
            }
        }

        // Fuse
        this.life--;
        if(this.life <= 0) {
            this.explode();
        }

        // Out of bounds
        if(this.x < -50 || this.x > GAME_WIDTH + 50 || this.y > GAME_HEIGHT + 50) {
            this.active = false;
        }
    }

    explode() {
        this.active = false;

        const w = this.weapon;
        let explosionRadius = w.radius;
        let damage = w.damage;

        // Sound based on weapon type
        AudioEngine.play(w.sound);

        // Visual effects
        if(w.name === 'Nuclear Bomb') {
            Particles.nuke(this.x, this.y);
            FloatingText.add(this.x, this.y - 30, '☢️ NUKED!', '#76ff03', 24);
            game.freezeTimer = 25;
            game.shake.intensity = 20;
        } else if(w.name === 'Super-explosive') {
            Particles.explosion(this.x, this.y, explosionRadius);
            Particles.debris(this.x, this.y, 15);
            game.freezeTimer = 15;
            game.shake.intensity = 12;
        } else {
            Particles.explosion(this.x, this.y, explosionRadius);
            Particles.debris(this.x, this.y, 8);
            game.shake.intensity = Math.max(3, explosionRadius / 10);
        }

        // Terrain destruction
        this._destroyTerrain();

        // Damage worms
        for(const worm of game.worms) {
            if(!worm.alive) continue;
            const dx = this.x - worm.x;
            const dy = this.y - worm.y;
            const dist = Math.sqrt(dx*dx + dy*dy);
            if(dist < explosionRadius + worm.radius) {
                const falloff = 1 - (dist / (explosionRadius + worm.radius));
                const actualDamage = Math.max(1, Math.floor(damage * falloff));
                worm.takeDamage(actualDamage);
                FloatingText.add(worm.x, worm.y - 15, `-${actualDamage}`, '#ff4444', 18);
                worm.vx += (dx / dist) * explosionRadius * 0.15;
                worm.vy += (dy / dist) * explosionRadius * 0.15 - 3;
            }
        }

        // Cluster bomb submunitions
        if(w.submunitions) {
            for(let i = 0; i < w.submunitions; i++) {
                const angle = Math.random() * Math.PI * 2;
                const speed = 3 + Math.random() * 4;
                const proj = new Projectile(this.x, this.y,
                    Math.cos(angle) * speed + game.wind * 0.5,
                    Math.sin(angle) * speed - 2,
                    {damage: w.subDamage, radius: w.subRadius, fuse: 40, sound: 'explosion-small', name:'Sub'},
                    this.owner
                );
                game.projectiles.push(proj);
            }
        }
    }

    _destroyTerrain() {
        const w = this.weapon;
        const r = w.radius;
        const sx = Math.max(0, Math.floor(this.x - r));
        const ex = Math.min(GAME_WIDTH, Math.ceil(this.x + r));
        const sy = Math.max(0, Math.floor(this.y - r));
        const ey = Math.min(GAME_HEIGHT, Math.ceil(this.y + r));

        const data = game.terrainData.data;

        for(let y = sy; y < ey; y++) {
            for(let x = sx; x < ex; x++) {
                const dx = x - this.x;
                const dy = y - this.y;
                const dist = Math.sqrt(dx*dx + dy*dy);
                if(dist < r && TerrainGen._isTerrain(x, y)) {
                    TerrainGen._setAir(x, y);
                }
            }
        }

        ctx.putImageData(game.terrainData, 0, 0);
    }

    draw(ctx) {
        if(!this.active || (this.isDynamite && this.pickedUp)) return;

        ctx.save();
        ctx.translate(this.x, this.y);

        const w = this.weapon;

        if(w.name === 'Laser') {
            ctx.strokeStyle = '#e91e63';
            ctx.lineWidth = 3;
            ctx.shadowBlur = 8;
            ctx.shadowColor = '#e91e63';
            ctx.beginPath();
            ctx.moveTo(-8, 0);
            ctx.lineTo(8, 0);
            ctx.stroke();
        } else if(w.name === 'Banana Bomb') {
            ctx.fillStyle = '#ffeb3b';
            ctx.beginPath();
            ctx.arc(0, 0, 5, 0, Math.PI * 2);
            ctx.fill();
            ctx.fillStyle = '#f57f17';
            ctx.beginPath();
            ctx.arc(0, 0, 2, 0, Math.PI * 2);
            ctx.fill();
        } else if(w.name === 'Nuclear Bomb') {
            // Pulsing glow
            const pulse = 1 + Math.sin(Date.now() / 100) * 0.3;
            ctx.fillStyle = '#76ff03';
            ctx.shadowBlur = 15;
            ctx.shadowColor = '#76ff03';
            ctx.beginPath();
            ctx.arc(0, 0, 6 * pulse, 0, Math.PI * 2);
            ctx.fill();
            ctx.fillStyle = '#33691e';
            ctx.font = 'bold 10px sans-serif';
            ctx.textAlign = 'center';
            ctx.fillText('☢', 0, 4);
        } else if(w.name === 'Dynamite') {
            ctx.fillStyle = '#8d6e63';
            ctx.fillRect(-3, -6, 6, 12);
            ctx.fillStyle = '#ff9800';
            ctx.fillRect(-2, -8, 4, 3);
            // Fuse spark
            if(this.life % 4 < 2) {
                ctx.fillStyle = '#ffeb3b';
                ctx.beginPath();
                ctx.arc(0, -10, 2, 0, Math.PI * 2);
                ctx.fill();
            }
        } else {
            // Default projectile
            ctx.fillStyle = w.color || '#ff9800';
            ctx.beginPath();
            ctx.arc(0, 0, 4, 0, Math.PI * 2);
            ctx.fill();
            // Trail glow
            ctx.fillStyle = 'rgba(255,255,255,0.5)';
            ctx.beginPath();
            ctx.arc(-1, -1, 2, 0, Math.PI * 2);
            ctx.fill();
        }

        ctx.restore();
    }
}

// ==================== AI ====================
const AI = {
    decideAction(worm) {
        if(!worm.alive || worm.frozen > 0) return {action:'wait'};

        const enemies = game.worms.filter(w => w.alive && w.team !== worm.team);
        if(enemies.length === 0) return {action:'wait'};

        const difficultyMod = game.config.difficulty === 'hard' ? 0.85 :
                             game.config.difficulty === 'easy' ? 0.6 : 0.75;

        // Risk assessment - avoid dangerous positions
        const risk = this._assessRisk(worm);
        if(risk.high) {
            return {action:'move_to_safety', x: risk.safeX};
        }

        // Choose target
        const target = this._chooseTarget(worm, enemies);
        if(!target) return {action:'wait'};

        // Choose weapon
        const weaponKey = this._chooseWeapon(worm, target);
        if(!weaponKey) return {action:'wait'};

        const weapon = WEAPONS[weaponKey];
        if(!weapon) return {action:'wait'};

        // Calculate aim
        const aim = this._calculateAim(worm, target, weapon, difficultyMod);
        if(!aim) return {action:'wait'};

        return {
            action:'fire',
            weapon: weaponKey,
            aimX: aim.x,
            aimY: aim.y
        };
    },

    _assessRisk(worm) {
        // Check if near edge
        const heightAtPos = TerrainGen._sampleHeight(worm.x);
        const leftHeight = TerrainGen._sampleHeight(worm.x - 30);
        const rightHeight = TerrainGen._sampleHeight(worm.x + 30);

        if(leftHeight > heightAtPos + 40) return {high:true, safeX: worm.x - 40};
        if(rightHeight > heightAtPos + 40) return {high:true, safeX: worm.x + 40};

        // Check if near water
        if(TerrainGen._isWater(worm.x, worm.y + worm.radius + 5)) {
            return {high:true, safeX: worm.x - 50};
        }

        return {high:false};
    },

    _chooseTarget(worm, enemies) {
        let bestTarget = null;
        let bestScore = -Infinity;

        for(const enemy of enemies) {
            const dx = enemy.x - worm.x;
            const dy = enemy.y - worm.y;
            const dist = Math.sqrt(dx*dx + dy*dy);

            let score = 0;
            // Lower HP enemies are easier targets
            score += (enemy.hp / enemy.maxHp) * -100;
            // Closer enemies are better
            score += Math.max(0, 300 - dist);
            // Enemies exposed (not in tunnels) are better
            if(!this._isInTunnel(enemy)) score += 50;

            if(score > bestScore) {
                bestScore = score;
                bestTarget = enemy;
            }
        }

        return bestTarget;
    },

    _isInTunnel(worm) {
        // Check if surrounded by terrain above
        let terrainAbove = 0;
        for(let dx = -10; dx <= 10; dx += 2) {
            const x = Math.floor(worm.x + dx);
            const y = Math.floor(worm.y - 15);
            if(TerrainGen._isTerrain(x, y)) terrainAbove++;
        }
        return terrainAbove > 6;
    },

    _chooseWeapon(worm, target) {
        const dx = target.x - worm.x;
        const dy = target.y - worm.y;
        const dist = Math.sqrt(dx*dx + dy*dy);

        const availableWeapons = Object.entries(WEAPONS)
            .filter(([k, w]) => worm.weaponAmmo[k] > 0);

        if(availableWeapons.length === 0) return null;

        let bestWeapon = null;
        let bestScore = -Infinity;

        for(const [key, weapon] of availableWeapons) {
            let score = 0;

            if(weapon.type === 'direct' && weapon.instant) {
                if(dist < 400 && this._hasLineOfSight(worm, target)) {
                    score += 80;
                } else {
                    score -= 50;
                }
            } else if(weapon.type === 'indirect') {
                score += 30;
                // Prefer weapons with good range
                const maxRange = weapon.speed * weapon.fuse;
                if(maxRange > dist * 0.8) score += 20;
            } else if(weapon.type === 'aoe') {
                // Only use big weapons when multiple enemies nearby
                const nearbyEnemies = game.worms.filter(e => {
                    if(!e.alive || e.team === worm.team) return false;
                    return Math.sqrt((e.x-worm.x)**2 + (e.y-worm.y)**2) < weapon.radius * 2;
                }).length;
                score += nearbyEnemies * 40;
                if(dist > 200) score += 20;
            }

            // Weapon effectiveness bonus
            if(weapon.damage > 30) score += 10;
            if(weapon.radius > 60) score += 5;

            if(score > bestScore) {
                bestScore = score;
                bestWeapon = key;
            }
        }

        return bestWeapon;
    },

    _hasLineOfSight(from, to) {
        const dx = to.x - from.x;
        const dy = to.y - from.y;
        const dist = Math.sqrt(dx*dx + dy*dy);
        const steps = Math.floor(dist / 10);

        for(let i = 1; i < steps; i++) {
            const t = i / steps;
            const x = from.x + dx * t;
            const y = from.y + dy * t;
            if(TerrainGen._isTerrain(x, y) && !TerrainGen._isAir(x, y)) return false;
        }
        return true;
    },

    _calculateAim(worm, target, weapon, accuracy) {
        const dx = target.x - worm.x;
        const dy = target.y - worm.y;
        const dist = Math.sqrt(dx*dx + dy*dy);

        if(weapon.instant) {
            return {x: target.x, y: target.y};
        }

        // Add inaccuracy based on difficulty
        const inaccuracy = (1 - accuracy) * 80;
        const aimX = target.x + (Math.random() - 0.5) * inaccuracy;
        const aimY = target.y + (Math.random() - 0.5) * inaccuracy;

        // Calculate angle using physics
        const g = weapon.gravity || 0.1;
        const speed = weapon.speed;

        // For indirect fire, aim for a point above target
        const targetYAbove = aimY - 50 - Math.random() * 100;

        // Solve trajectory equation
        const angle = this._calculateAngle(worm.x, worm.y, aimX, targetYAbove, speed, g);
        if(angle === null) return null;

        return {x: aimX, y: aimY};
    },

    _calculateAngle(x1, y1, x2, y2, speed, g) {
        const dx = x2 - x1;
        const dy = y2 - y1;

        // Adjust for wind
        const windAdj = game.wind * 2;

        // Calculate required angle
        const discriminant = g * g * dx * dx + (2 * g * dy - speed * speed * speed * speed) * dx * dx + speed * speed * speed * speed * speed * speed;

        // Simplified approach
        const baseAngle = Math.atan2(dy, dx);
        // Add arc for indirect weapons
        const arcAngle = baseAngle - 0.4;
        return arcAngle;
    }
};

// ==================== GAME LOGIC ====================
function initGame(config) {
    AudioEngine.init();
    game.config = config;
    game.teams = [];
    game.worms = [];
    game.projectiles = [];
    game.particles = [];
    game.floatingTexts = [];
    game.debris = [];
    game.selectedWeapon = 0;
    game.isAiming = false;
    game.freezeTimer = 0;
    game.shake.intensity = 0;
    game.wind = (Math.random() - 0.5) * 4;

    // Generate terrain
    const terrainResult = TerrainGen.generate(config.terrain);
    game.terrainData = terrainResult.imageData;
    ctx.putImageData(game.terrainData, 0, 0);

    // Create teams and worms
    const numTeams = config.numTeams;
    const names = [...WORM_NAMES].sort(() => Math.random() - 0.5);
    let nameIdx = 0;

    for(let t = 0; t < numTeams; t++) {
        const teamColor = TEAM_COLORS[t % TEAM_COLORS.length];
        game.teams.push({
            id: t,
            name: teamColor.name,
            color: teamColor.color,
            light: teamColor.light,
            dark: teamColor.dark,
            worms: [],
            cpu: t >= numTeams - config.cpuCount
        });
    }

    // Place worms on terrain
    for(let t = 0; t < numTeams; t++) {
        const team = game.teams[t];
        const baseX = (t + 0.5) * (GAME_WIDTH / numTeams);

        for(let w = 0; w < 4; w++) {
            const worm = new Worm(t, names[nameIdx++], team.color);
            // Find landing position
            let placeX = baseX + (w - 1.5) * 40;
            placeX = Math.max(80, Math.min(GAME_WIDTH - 80, placeX));

            let placeY = 100;
            for(let y = 0; y < GAME_HEIGHT - 50; y++) {
                if(TerrainGen._isTerrain(Math.floor(placeX), y) && y < WATER_LEVEL - 30) {
                    placeY = y - 25;
                    break;
                }
            }

            worm.x = placeX;
            worm.y = placeY;
            worm.team = t;

            game.worms.push(worm);
            team.worms.push(worm);
        }
    }

    // Start first turn
    game.currentTeamIndex = 0;
    game.currentWormIndex = 0;
    startTurn();
}

function startTurn() {
    // Find next alive worm
    let attempts = 0;
    while(attempts < 100) {
        const team = game.teams[game.currentTeamIndex];
        const aliveWorms = team.worms.filter(w => w.alive);
        if(aliveWorms.length === 0) {
            // Team eliminated
            game.currentTeamIndex = (game.currentTeamIndex + 1) % game.teams.length;
            attempts++;
            continue;
        }

        const worm = aliveWorms[game.currentWormIndex % aliveWorms.length];
        if(!worm.alive) {
            game.currentWormIndex = (game.currentWormIndex + 1) % aliveWorms.length;
            attempts++;
            continue;
        }

        worm.startTurn();
        game.turnTimer = TURN_TIME;
        game.lastTick = Date.now();
        game.isAiming = false;

        // Camera to worm
        game.camera.targetX = worm.x;
        game.camera.targetY = worm.y;

        // Announce turn
        showTurnAnnouncement(team, worm);

        // Wind change
        if(Math.random() < 0.4) {
            game.wind = (Math.random() - 0.5) * 4;
            FloatingText.add(GAME_WIDTH/2, 100, 'WIND CHANGE!', '#8ec8ff', 14);
        }

        updateHUD();

        // CPU turn
        if(team.cpu) {
            game.state = 'playing';
            setTimeout(() => executeAITurn(worm), 500);
        } else {
            // Human turn - enable controls
            game.state = 'playing';
        }
    }
}

function showTurnAnnouncement(team, worm) {
    const el = document.getElementById('turn-announcement');
    el.innerHTML = `<div class="team-color" style="color:${team.color}">${team.name}</div><div class="worm-name-display">${worm.name}</div>`;
    el.classList.add('show');
    AudioEngine.play('powerup');
    setTimeout(() => el.classList.remove('show'), 1500);
}

function updateHUD() {
    const team = game.teams[game.currentTeamIndex];
    const aliveWorms = team.worms.filter(w => w.alive);
    const worm = aliveWorms[game.currentWormIndex % aliveWorms.length];

    if(!worm) return;

    // Team info
    document.getElementById('team-color-dot').style.backgroundColor = team.color;
    document.getElementById('worm-name').textContent = worm.name;
    document.getElementById('team-name').textContent = team.name;

    // Health bars
    const healthContainer = document.getElementById('team-health');
    healthContainer.innerHTML = '';

    for(const t of game.teams) {
        if(t.worms.length === 0) continue;
        const row = document.createElement('div');
        row.className = 'team-health-row';
        for(const w of t.worms) {
            const div = document.createElement('div');
            div.className = 'worm-health' + (!w.alive ? ' dead' : '') +
                (w === worm ? ' active' : '');
            const hpRatio = Math.max(0, w.hp / w.maxHp);
            const hpColor = hpRatio > 0.5 ? '#4caf50' : hpRatio > 0.25 ? '#ff9800' : '#f44336';
            div.innerHTML = `
                <div class="worm-health-bar" style="width:${hpRatio*100}%;background:${hpColor}"></div>
                <div class="worm-health-label">${w.alive ? w.hp : '✕'}</div>
            `;
            row.appendChild(div);
        }
        healthContainer.appendChild(row);
    }

    // Weapon panel
    const weaponPanel = document.getElementById('weapon-panel');
    weaponPanel.innerHTML = '';
    const weaponKeys = Object.keys(WEAPONS);
    const keys = '1234567890';

    weaponKeys.forEach((key, i) => {
        const w = WEAPONS[key];
        const hasAmmo = worm.weaponAmmo[key] > 0;
        const slot = document.createElement('div');
        slot.className = 'weapon-slot' + (i === game.selectedWeapon ? ' selected' : '') +
            (!hasAmmo ? ' exhausted' : '');
        slot.innerHTML = `
            <span class="key">${keys[i] || ''}</span>
            <span class="icon">${w.icon}</span>
            <span class="count">${w.name}</span>
            <span class="ammo-badge">${worm.weaponAmmo[key]}</span>
            <div class="tooltip">${w.name} (${w.type})<br>${w.desc}</div>
        `;
        if(hasAmmo) {
            slot.onclick = () => {
                game.selectedWeapon = i;
                AudioEngine.play('menu-hover');
                updateHUD();
            };
        }
        weaponPanel.appendChild(slot);
    });

    // Items panel
    const itemsRow = document.getElementById('items-row');
    itemsRow.innerHTML = '';
    for(let i = 0; i < 4; i++) {
        const itemKey = Object.keys(ITEMS)[i];
        const item = ITEMS[itemKey];
        const hasItem = worm.items.includes(itemKey);
        const slot = document.createElement('div');
        slot.className = 'item-slot' + (!hasItem ? ' no-items' : '');
        slot.innerHTML = `<span>${item.icon}</span>`;
        if(hasItem) {
            slot.onclick = () => useItem(worm, itemKey);
        }
        itemsRow.appendChild(slot);
    }
}

function useItem(worm, itemKey) {
    const item = ITEMS[itemKey];
    if(!worm.items.includes(itemKey)) return;

    worm.items = worm.items.filter(i => i !== itemKey);
    AudioEngine.play('powerup');

    switch(item.action) {
        case 'heal':
            worm.hp = Math.min(worm.maxHp, worm.hp + item.amount);
            FloatingText.add(worm.x, worm.y - 20, `+${item.amount} HP`, '#4caf50', 18);
            Particles.create(worm.x, worm.y, 'spark', 15, '#4caf50', {
                speedMin: 1, speedMax: 4, lifeMin: 15, lifeMax: 30,
                sizeMin: 2, sizeMax: 5, gravity: -0.1, shape:'circle'
            });
            break;

        case 'parachute':
            worm.parachute = true;
            FloatingText.add(worm.x, worm.y - 20, '🪂!', '#ffffff', 16);
            break;

        case 'speed':
            worm.moveSpeed = UNIT_MAX_SPEED * 2;
            setTimeout(() => worm.moveSpeed = UNIT_MAX_SPEED, (item.duration || 200) * 16.67);
            FloatingText.add(worm.x, worm.y - 20, '⚡ SPEED!', '#ffeb3b', 16);
            break;

        case 'freeze_enemy':
            for(const other of game.worms) {
                if(!other.alive || other.team === worm.team) continue;
                const dist = Math.sqrt((other.x-worm.x)**2 + (other.y-worm.y)**2);
                if(dist < item.radius) {
                    other.frozen = item.duration;
                    FloatingText.add(other.x, other.y - 20, '❄️ FROZEN!', '#00bcd4', 18);
                }
            }
            Particles.freezeEffect(worm.x, worm.y, item.radius);
            AudioEngine.play('freeze');
            break;

        case 'extra_time':
            game.turnTimer = Math.min(TURN_TIME, game.turnTimer + item.amount);
            FloatingText.add(GAME_WIDTH/2, GAME_HEIGHT/2 - 50, `+${item.amount}s`, '#4ecdc4', 20);
            break;
    }

    updateHUD();
}

function executeAITurn(worm) {
    if(!worm.alive) { endTurn(); return; }

    const action = AI.decideAction(worm);

    if(action.action === 'wait' || action.action === 'move_to_safety') {
        endTurn();
        return;
    }

    if(action.action === 'fire') {
        const weaponKey = action.weapon;
        if(worm.weaponAmmo[weaponKey] > 0) {
            const weapon = WEAPONS[weaponKey];
            const dx = action.aimX - worm.x;
            const dy = action.aimY - worm.y;
            const dist = Math.sqrt(dx*dx + dy*dy) || 1;
            const angle = Math.atan2(dy, dx);

            // Adjust angle for indirect weapons
            let finalAngle = angle;
            if(weapon.type === 'indirect' || weapon.type === 'aoe') {
                finalAngle = Math.min(angle - 0.3, -0.2);
            }

            fireWeapon(worm, weaponKey, finalAngle);
        }
    }

    setTimeout(() => endTurn(), 1500);
}

function fireWeapon(worm, weaponKey, angle) {
    const weapon = WEAPONS[weaponKey];
    if(!weapon || worm.weaponAmmo[weaponKey] <= 0) return;

    worm.weaponAmmo[weaponKey]--;

    let proj;

    if(weapon.instant) {
        // Direct hit laser/shotgun - instant damage
        const dx = Math.cos(angle) * 500;
        const dy = Math.sin(angle) * 500;

        if(weapon.name === 'Laser') {
            AudioEngine.play('laser');
            // Check line for damage
            for(const target of game.worms) {
                if(!target.alive || target.team === worm.team) continue;
                const tdx = target.x - worm.x;
                const tdy = target.y - worm.y;
                const tAngle = Math.atan2(tdy, tdx);
                if(Math.abs(tAngle - angle) < 0.08) {
                    target.takeDamage(weapon.damage);
                    FloatingText.add(target.x, target.y - 15, `-${weapon.damage}`, '#ff4444', 20);
                    Particles.create(target.x, target.y, 'spark', 15, '#e91e63', {
                        speedMin: 2, speedMax: 6, lifeMin: 10, lifeMax: 25,
                        sizeMin: 2, sizeMax: 5, shape:'circle', glow:true
                    });
                }
            }
            // Terrain damage along line
            const steps = 50;
            for(let i = 0; i < steps; i++) {
                const t = i / steps;
                const px = worm.x + dx * t;
                const py = worm.y + dy * t;
                if(TerrainGen._isTerrain(px, py)) {
                    const r = 3;
                    for(let ox = -r; ox <= r; ox++) {
                        for(let oy = -r; oy <= r; oy++) {
                            if(ox*ox + oy*oy < r*r && TerrainGen._isTerrain(px+ox, py+oy)) {
                                TerrainGen._setAir(px+ox, py+oy);
                            }
                        }
                    }
                    i = steps; // stop at first hit
                }
            }
            ctx.putImageData(game.terrainData, 0, 0);
            Particles.create(worm.x + dx * 0.5, worm.y + dy * 0.5, 'spark', 10, '#e91e63', {
                speedMin: 1, speedMax: 4, lifeMin: 10, lifeMax: 20, glow:true
            });
        } else if(weapon.name === 'Shotgun') {
            AudioEngine.play('shot');
            Particles.muzzleFlash(
                worm.x + Math.cos(angle) * worm.radius,
                worm.y + Math.sin(angle) * worm.radius,
                angle
            );
            for(let p = 0; p < weapon.pellets; p++) {
                const pelletAngle = angle + (Math.random() - 0.5) * weapon.spread;
                const target = findWormInLine(worm.x, worm.y, pelletAngle, 500);
                if(target) {
                    target.takeDamage(Math.floor(weapon.damage / weapon.pellets));
                    FloatingText.add(target.x, target.y - 15, `-${Math.floor(weapon.damage/weapon.pellets)}`, '#ff4444', 14);
                }
            }
        }
        updateHUD();
        return;
    }

    if(weapon.name === 'Uzi') {
        for(let b = 0; b < weapon.burst && worm.weaponAmmo[weaponKey] >= 0; b++) {
            setTimeout(() => {
                if(worm.weaponAmmo[weaponKey] < 0) return;
                const spreadAngle = angle + (Math.random() - 0.5) * 0.3;
                const p = new Projectile(
                    worm.x + Math.cos(spreadAngle) * worm.radius,
                    worm.y + Math.sin(spreadAngle) * worm.radius,
                    Math.cos(spreadAngle) * weapon.speed + game.wind * 0.5,
                    Math.sin(spreadAngle) * weapon.speed,
                    {damage: weapon.damage, radius: weapon.radius, fuse:60, sound:'shot', name:'Uzi'},
                    worm.team
                );
                game.projectiles.push(p);
                AudioEngine.play('shot');
            }, b * 50);
        }
        updateHUD();
        return;
    }

    const vx = Math.cos(angle) * weapon.speed;
    const vy = Math.sin(angle) * weapon.speed;

    proj = new Projectile(
        worm.x + Math.cos(angle) * (worm.radius + 5),
        worm.y + Math.sin(angle) * (worm.radius + 5),
        vx, vy, weapon, worm.team
    );

    game.projectiles.push(proj);
    AudioEngine.play('shot');
    Particles.muzzleFlash(
        worm.x + Math.cos(angle) * worm.radius,
        worm.y + Math.sin(angle) * worm.radius,
        angle
    );
    updateHUD();
}

function findWormInLine(x, y, angle, maxDist) {
    let closest = null;
    let closestDist = maxDist;
    for(const worm of game.worms) {
        if(!worm.alive || worm.team === 0) continue;
        const dx = worm.x - x;
        const dy = worm.y - y;
        const dist = Math.sqrt(dx*dx + dy*dy);
        if(dist > maxDist) continue;
        const wormAngle = Math.atan2(dy, dx);
        if(Math.abs(wormAngle - angle) < 0.05 && dist < closestDist) {
            closestDist = dist;
            closest = worm;
        }
    }
    return closest;
}

function endTurn() {
    const team = game.teams[game.currentTeamIndex];
    const aliveWorms = team.worms.filter(w => w.alive);
    game.currentWormIndex++;

    if(game.currentWormIndex >= aliveWorms.length || !team.worms.some(w => w.alive)) {
        game.currentWormIndex = 0;
        game.currentTeamIndex = (game.currentTeamIndex + 1) % game.teams.length;

        // Award random item
        const nextTeam = game.teams[game.currentTeamIndex];
        const nextAlive = nextTeam.worms.filter(w => w.alive);
        if(nextAlive.length > 0) {
            const itemKeys = Object.keys(ITEMS);
            const randomItem = itemKeys[Math.floor(Math.random() * itemKeys.length)];
            const worm = nextAlive[Math.floor(Math.random() * nextAlive.length)];
            if(worm.items.length < 4) {
                worm.items.push(randomItem);
                FloatingText.add(worm.x, worm.y - 30, `${ITEMS[randomItem].icon} ${ITEMS[randomItem].name}!`, '#ffd700', 16);
                AudioEngine.play('powerup');
            }
        }
    }

    checkGameEnd();
    startTurn();
}

function checkGameEnd() {
    const aliveTeams = game.teams.filter(t => t.worms.some(w => w.alive));
    if(aliveTeams.length === 1) {
        game.state = 'gameover';
        const winner = aliveTeams[0];
        document.getElementById('winner-info').textContent = `${winner.name} Wins!`;
        document.getElementById('winner-info').style.color = winner.color;
        document.getElementById('game-over-screen').style.display = 'flex';
        AudioEngine.play('cheer');
    }
}

// ==================== INPUT HANDLING ====================
let mouseX = 0, mouseY = 0;
let screenMouseX = 0, screenMouseY = 0;
let keysDown = {};
let aimMode = false;

canvas.addEventListener('mousedown', (e) => {
    if(game.state !== 'playing') return;
    if(game.teams[game.currentTeamIndex].cpu) return;

    const rect = canvas.getBoundingClientRect();
    screenMouseX = e.clientX - rect.left;
    screenMouseY = e.clientY - rect.top;
    mouseX = screenMouseX / game.camera.zoom + game.camera.x;
    mouseY = screenMouseY / game.camera.zoom + game.camera.y;

    const team = game.teams[game.currentTeamIndex];
    const aliveWorms = team.worms.filter(w => w.alive);
    const worm = aliveWorms[game.currentWormIndex % aliveWorms.length];
    if(!worm || worm.frozen > 0) return;

    // Check dynamite pickup
    for(const proj of game.projectiles) {
        if(proj.weapon.name === 'Dynamite' && proj.life > 0 && !proj.pickedUp) {
            const dx = mouseX - proj.x;
            const dy = mouseY - proj.y;
            if(Math.sqrt(dx*dx + dy*dy) < 30) {
                proj.pickedUp = true;
                proj.carrier = worm;
                proj.life = 150; // Reset fuse on pickup
                AudioEngine.play('powerup');
                FloatingText.add(proj.x, proj.y - 20, 'PICKED UP!', '#ff9800', 14);
                return;
            }
        }
    }

    aimMode = true;
    game.aimStart = {x: mouseX, y: mouseY};
    game.aimEnd = {x: mouseX, y: mouseY};
    AudioEngine.play('click');
});

canvas.addEventListener('mousemove', (e) => {
    const rect = canvas.getBoundingClientRect();
    screenMouseX = e.clientX - rect.left;
    screenMouseY = e.clientY - rect.top;
    mouseX = screenMouseX / game.camera.zoom + game.camera.x;
    mouseY = screenMouseY / game.camera.zoom + game.camera.y;

    if(aimMode && game.aimStart) {
        game.aimEnd = {x: mouseX, y: mouseY};
    }
});

canvas.addEventListener('mouseup', (e) => {
    if(!aimMode || game.state !== 'playing') {
        aimMode = false;
        return;
    }

    const team = game.teams[game.currentTeamIndex];
    if(team.cpu) { aimMode = false; return; }

    const aliveWorms = team.worms.filter(w => w.alive);
    const worm = aliveWorms[game.currentWormIndex % aliveWorms.length];
    if(!worm || worm.frozen > 0) { aimMode = false; return; }

    // Check if dropped dynamite
    for(const proj of game.projectiles) {
        if(proj.pickedUp && proj.carrier === worm) {
            proj.x = mouseX;
            proj.y = mouseY;
            proj.pickedUp = false;
            proj.carrier = null;
            proj.vx = 0;
            proj.vy = -2;
            AudioEngine.play('hit');
            FloatingText.add(proj.x, proj.y - 20, 'DROPPED!', '#ff9800', 14);
            aimMode = false;
            return;
        }
    }

    // Fire weapon
    const weaponKey = Object.keys(WEAPONS)[game.selectedWeapon];
    const weapon = WEAPONS[weaponKey];

    if(weapon && worm.weaponAmmo[weaponKey] > 0) {
        const dx = game.aimEnd.x - worm.x;
        const dy = game.aimEnd.y - worm.y;
        const dist = Math.sqrt(dx*dx + dy*dy);

        if(dist > 20) {
            let angle = Math.atan2(dy, dx);

            // Force arc for indirect weapons if aim is too direct
            if((weapon.type === 'indirect' || weapon.type === 'aoe') && angle > -0.15) {
                angle = -0.6 + (Math.random() - 0.5) * 0.1;
            }

            fireWeapon(worm, weaponKey, angle);
        }
    }

    aimMode = false;
});

document.addEventListener('keydown', (e) => {
    keysDown[e.key] = true;

    if(game.state !== 'playing') return;
    const team = game.teams[game.currentTeamIndex];
    if(team.cpu) return;

    const aliveWorms = team.worms.filter(w => w.alive);
    const worm = aliveWorms[game.currentWormIndex % aliveWorms.length];
    if(!worm || !worm.alive || worm.frozen > 0) return;

    // Number keys for weapon selection
    const num = parseInt(e.key);
    if(num >= 1 && num <= Object.keys(WEAPONS).length) {
        if(worm.weaponAmmo[Object.keys(WEAPONS)[num-1]] > 0) {
            game.selectedWeapon = num - 1;
            AudioEngine.play('menu-hover');
            updateHUD();
        }
    }

    // Jump
    if(e.key === ' ' || e.key === 'ArrowUp' || e.key === 'w' || e.key === 'W') {
        worm.jump();
    }

    // Zoom
    if(e.key === '+' || e.key === '=') {
        game.camera.targetZoom = Math.min(2, game.camera.zoom + 0.1);
    }
    if(e.key === '-' || e.key === '_') {
        game.camera.targetZoom = Math.max(0.5, game.camera.zoom - 0.1);
    }
});

document.addEventListener('keyup', (e) => {
    keysDown[e.key] = false;
});

document.getElementById('end-turn-btn').addEventListener('click', () => {
    AudioEngine.play('click');
    endTurn();
});

// Menu handlers
document.querySelectorAll('[data-teams]').forEach(btn => {
    btn.addEventListener('click', () => {
        AudioEngine.init();
        AudioEngine.play('menu-hover');
        document.querySelectorAll('[data-teams]').forEach(b => b.classList.remove('active'));
        btn.classList.add('active');
    });
});
document.querySelectorAll('[data-difficulty]').forEach(btn => {
    btn.addEventListener('click', () => {
        AudioEngine.init();
        AudioEngine.play('menu-hover');
        document.querySelectorAll('[data-difficulty]').forEach(b => b.classList.remove('active'));
        btn.classList.add('active');
    });
});
document.querySelectorAll('[data-terrain]').forEach(btn => {
    btn.addEventListener('click', () => {
        AudioEngine.init();
        AudioEngine.play('menu-hover');
        document.querySelectorAll('[data-terrain]').forEach(b => b.classList.remove('active'));
        btn.classList.add('active');
    });
});
document.querySelectorAll('[data-cpu]').forEach(btn => {
    btn.addEventListener('click', () => {
        AudioEngine.init();
        AudioEngine.play('menu-hover');
        document.querySelectorAll('[data-cpu]').forEach(b => b.classList.remove('active'));
        btn.classList.add('active');
    });
});

document.getElementById('start-btn').addEventListener('click', () => {
    AudioEngine.play('menu-select');
    const teamsBtn = document.querySelector('[data-teams].active');
    const diffBtn = document.querySelector('[data-difficulty].active');
    const terrainBtn = document.querySelector('[data-terrain].active');
    const cpuBtn = document.querySelector('[data-cpu].active');

    const config = {
        numTeams: parseInt(teamsBtn.dataset.teams),
        cpuCount: parseInt(cpuBtn.dataset.cpu),
        difficulty: diffBtn.dataset.difficulty,
        terrain: terrainBtn.dataset.terrain
    };

    document.getElementById('menu-screen').style.display = 'none';
    document.getElementById('hud').style.display = 'block';
    initGame(config);
});

document.getElementById('restart-btn').addEventListener('click', () => {
    AudioEngine.play('menu-select');
    document.getElementById('game-over-screen').style.display = 'none';
    document.getElementById('menu-screen').style.display = 'flex';
    game.state = 'menu';
});

document.getElementById('menu-btn').addEventListener('click', () => {
    AudioEngine.play('menu-select');
    document.getElementById('game-over-screen').style.display = 'none';
    document.getElementById('menu-screen').style.display = 'flex';
    game.state = 'menu';
});

// ==================== RENDERING ====================
function render() {
    const w = canvas.width;
    const h = canvas.height;

    // Clear
    ctx.fillStyle = '#0a0a1a';
    ctx.fillRect(0, 0, w, h);

    // Camera update
    const targetX = game.camera.targetX;
    const targetY = game.camera.targetY;
    const targetZoom = game.camera.targetZoom;

    // Smooth camera
    game.camera.x += (targetX - game.camera.x) * 0.05;
    game.camera.y += (targetY - game.camera.y) * 0.05;
    game.camera.zoom += (targetZoom - game.camera.zoom) * 0.05;

    // Screen shake
    if(game.shake.intensity > 0.5) {
        game.shake.x = (Math.random() - 0.5) * game.shake.intensity;
        game.shake.y = (Math.random() - 0.5) * game.shake.intensity;
        game.shake.intensity *= game.shake.decay;
    } else {
        game.shake.x = 0;
        game.shake.y = 0;
        game.shake.intensity = 0;
    }

    ctx.save();

    // Apply camera transform
    const centerX = w / 2;
    const centerY = h / 2;
    ctx.translate(centerX + game.shake.x, centerY + game.shake.y);
    ctx.scale(game.camera.zoom, game.camera.zoom);
    ctx.translate(-game.camera.x, -game.camera.y);

    // Draw terrain
    if(game.terrainData) {
        ctx.putImageData(game.terrainData, 0, 0);
    } else {
        // Show loading screen
        ctx.fillStyle = '#0a0a1a';
        ctx.fillRect(0, 0, GAME_WIDTH, GAME_HEIGHT);
        ctx.fillStyle = '#ffd700';
        ctx.font = 'bold 36px "Segoe UI", sans-serif';
        ctx.textAlign = 'center';
        ctx.fillText('WORMS WARS', GAME_WIDTH/2, GAME_HEIGHT/2 - 20);
        ctx.fillStyle = '#8ec8ff';
        ctx.font = '18px "Segoe UI", sans-serif';
        ctx.fillText('Configure your game on the menu screen', GAME_WIDTH/2, GAME_HEIGHT/2 + 20);
    }

    // Draw water line effect
    ctx.strokeStyle = 'rgba(78,205,196,0.3)';
    ctx.lineWidth = 2;
    ctx.setLineDash([10, 5]);
    ctx.beginPath();
    ctx.moveTo(0, WATER_LEVEL);
    ctx.lineTo(GAME_WIDTH, WATER_LEVEL);
    ctx.stroke();
    ctx.setLineDash([]);

    // Freeze effect
    if(game.freezeTimer > 0) {
        game.freezeTimer--;
        ctx.fillStyle = `rgba(200,240,255,${game.freezeTimer / 25 * 0.3})`;
        ctx.fillRect(0, 0, GAME_WIDTH, GAME_HEIGHT);
    }

    // Draw worms
    for(const worm of game.worms) {
        worm.draw(ctx);
    }

    // Draw projectiles
    for(const proj of game.projectiles) {
        proj.draw(ctx);
    }

    // Draw particles
    Particles.draw(ctx);

    // Draw floating texts
    FloatingText.draw(ctx);

    // Draw aiming trajectory
    if(aimMode && game.aimStart && game.state === 'playing') {
        drawAimingTrajectory();
    }

    ctx.restore();

    // Wind indicator update
    const windArrow = document.getElementById('wind-arrow');
    const windValue = document.getElementById('wind-value');
    windArrow.style.transform = `scaleX(${game.wind >= 0 ? 1 : -1})`;
    windValue.textContent = Math.abs(game.wind).toFixed(1);
}

function drawAimingTrajectory() {
    const team = game.teams[game.currentTeamIndex];
    const aliveWorms = team.worms.filter(w => w.alive);
    const worm = aliveWorms[game.currentWormIndex % aliveWorms.length];
    if(!worm) return;

    const weaponKey = Object.keys(WEAPONS)[game.selectedWeapon];
    const weapon = WEAPONS[weaponKey];
    if(!weapon || weapon.instant) return;

    const dx = game.aimEnd.x - worm.x;
    const dy = game.aimEnd.y - worm.y;
    const dist = Math.sqrt(dx*dx + dy*dy);

    if(dist < 20) return;

    let angle = Math.atan2(dy, dx);
    if((weapon.type === 'indirect' || weapon.type === 'aoe') && angle > -0.15) {
        angle = -0.6;
    }

    const speed = weapon.speed;
    const g = weapon.gravity || 0.1;
    const vx = Math.cos(angle) * speed;
    const vy = Math.sin(angle) * speed;

    ctx.strokeStyle = 'rgba(255,255,255,0.4)';
    ctx.lineWidth = 2;
    ctx.setLineDash([4, 4]);
    ctx.beginPath();

    let px = worm.x;
    let py = worm.y;
    let pvx = vx;
    let pvy = vy;

    ctx.moveTo(px, py);

    for(let i = 0; i < 60; i++) {
        pvx += game.wind * g * 0.3;
        pvy += g;
        px += pvx;
        py += pvy;

        if(py > GAME_HEIGHT || px < 0 || px > GAME_WIDTH || TerrainGen._isTerrain(px, py)) {
            break;
        }

        ctx.lineTo(px, py);
    }

    ctx.stroke();
    ctx.setLineDash([]);

    // Draw explosion preview
    const finalDist = Math.sqrt((px-worm.x)**2 + (py-worm.y)**2);
    ctx.strokeStyle = weapon.color || '#ff9800';
    ctx.lineWidth = 1;
    ctx.globalAlpha = 0.4;
    ctx.beginPath();
    ctx.arc(px, py, weapon.radius, 0, Math.PI * 2);
    ctx.stroke();
    ctx.globalAlpha = 1;
}

// ==================== GAME LOOP ====================
let lastTime = 0;

function gameLoop(timestamp) {
    const dt = timestamp - lastTime;
    lastTime = timestamp;

    if(game.state === 'playing' || game.state === 'gameover') {
        update(dt);
    }

    render();
    requestAnimationFrame(gameLoop);
}

function update(dt) {
    // Timer
    if(game.state === 'playing' && !game.teams[game.currentTeamIndex].cpu) {
        const now = Date.now();
        const elapsed = (now - game.lastTick) / 1000;
        game.turnTimer -= elapsed;
        game.lastTick = now;

        // Timer warning sounds
        if(game.turnTimer <= 5 && game.turnTimer > 4 && Math.floor(now/500)%2===0) {
            AudioEngine.play('timer-tick');
        }
        if(game.turnTimer <= 2 && game.turnTimer > 1) {
            AudioEngine.play('timer-urgent');
        }

        if(game.turnTimer <= 0) {
            endTurn();
            return;
        }
    }

    // Update timer UI
    const timerFill = document.getElementById('turn-timer-fill');
    const timerText = document.getElementById('turn-timer-text');
    const timerPct = Math.max(0, game.turnTimer / TURN_TIME);
    timerFill.style.width = (timerPct * 100) + '%';
    timerText.textContent = Math.ceil(game.turnTimer);

    if(timerPct < 0.2) {
        timerFill.classList.add('danger');
    } else {
        timerFill.classList.remove('danger');
    }

    // Worm movement
    const team = game.teams[game.currentTeamIndex];
    if(team && !team.cpu) {
        const aliveWorms = team.worms.filter(w => w.alive);
        const worm = aliveWorms[game.currentWormIndex % aliveWorms.length];
        if(worm && worm.alive) {
            if(keysDown['ArrowLeft'] || keysDown['a'] || keysDown['A']) {
                worm.vx = -worm.moveSpeed;
                worm.facing = -1;
            } else if(keysDown['ArrowRight'] || keysDown['d'] || keysDown['D']) {
                worm.vx = worm.moveSpeed;
                worm.facing = 1;
            } else if(worm.onGround) {
                worm.vx *= 0.7;
            }
        }
    }

    // Update worms
    for(const worm of game.worms) {
        worm.update();
    }

    // Update projectiles
    for(let i = game.projectiles.length - 1; i >= 0; i--) {
        game.projectiles[i].update();
        if(!game.projectiles[i].active && !game.projectiles[i].isDynamite) {
            game.projectiles.splice(i, 1);
        }
    }

    // Update particles
    Particles.update();

    // Update floating texts
    FloatingText.update();

    // Check game end
    if(game.state === 'playing') {
        checkGameEnd();
    }
}

// ==================== RESIZE ====================
// Remove resize - canvas keeps fixed internal resolution, CSS scales it
window.addEventListener('resize', () => {});

// Start game loop
requestAnimationFrame(gameLoop);

</script>
</body>
</html>
<!-- agent-meta {"model":"Qwen3.6-27B-Fable-Fusion-711-Uncensored-Heretic-NM-DAU-NEO-MAX-MTP-GGUF","provider":"brigid","persona":"full","sessionId":"6cd5413f-485c-4374-81b1-e390e53703b1","tokensIn":3300288,"tokensOut":39111,"tokensTotal":3339399,"cost":0,"turns":39,"toolCalls":38,"failedToolCalls":0,"timestamp":"2026-08-06T03:33:12.149Z"} -->