Drawaria Battle! 🔥 Tik Tok vs. сонечка

2D fighting game with Language/Character selection and improved combat mechanics into drawaria.online.

// ==UserScript==
// @name         Drawaria Battle! 🔥 Tik Tok vs. сонечка
// @namespace    http://tampermonkey.net/
// @version      1.4
// @description  2D fighting game with Language/Character selection and improved combat mechanics into drawaria.online.
// @author       YouTubeDrawaria
// @match        *://drawaria.online/*
// @match        *://*drawaria.online/*
// @grant        GM_addStyle
// @run-at       document-idle
// @license      MIT
// @icon         https://fonts.gstatic.com/s/e/notoemoji/latest/1f525/512.webp
// @match        https://drawaria.online/profile/?uid=1f400b90-8e8c-11ed-9fd3-c3a00b129da4
// @match        https://drawaria.online/profile/?uid=7dda2280-618f-11ef-acaf-250da20bac69
// ==/UserScript==

(function() {
    'use strict';

    // --- L10N: TRANSLATIONS ---
    const translations = {
        'en': {
            lang_question: "Choose your language:",
            fight_title: "Drawaria Battle! 🔥 Tik Tok vs. сонечка",
            epic_brawl: "EPIC BRAWL BEGINS!",
            select_char: "Select your fighter:",
            play_as: "Play as",
            controls_title: "Controls (Player):",
            p1_controls: "P1 (Human): ← (Left), → (Right), ↑ (Jump), Space (Attack)", // Unified controls
            p2_controls: "P2 (Bot): Automatic Movement & Attacks",
            audio_note: "Click on the game to enable background music.",
            start_button: "FIGHT!",
            game_over: "GAME OVER",
            ko_message: "WINS by KO!",
            time_advantage: "WINS by Health Advantage!",
            draw_message: "Time Up! It's a DRAW!",
            restart_button: "CONTINUE / PLAY AGAIN", // Updated text
            ko: "KO!",
            round: "Round",
            match_over: "MATCH OVER" // New text
        },
        'ru': {
            lang_question: "Выберите ваш язык:",
            fight_title: "Drawaria Battle! 🔥 Tik Tok vs. сонечка",
            epic_brawl: "ЭПИЧЕСКАЯ БИТВА НАЧИНАЕТСЯ!",
            select_char: "Выберите вашего бойца:",
            play_as: "Играть за",
            controls_title: "Управление (Игрок):",
            p1_controls: "P1 (Человек): ← (Влево), → (Вправо), ↑ (Прыжок), Пробел (Атака)", // Unified controls
            p2_controls: "P2 (Бот): Автоматическое движение и атаки",
            audio_note: "Нажмите на игру, чтобы включить фоновую музыку.",
            start_button: "СРАЖАТЬСЯ!",
            game_over: "ИГРА ОКОНЧЕНА",
            ko_message: "ПОБЕДА нокаутом!",
            time_advantage: "ПОБЕДА по преимуществу здоровья!",
            draw_message: "Время вышло! НИЧЬЯ!",
            restart_button: "ПРОДОЛЖИТЬ / ИГРАТЬ СНОВА", // Updated text
            ko: "НОКАУТ!",
            round: "Раунд",
            match_over: "МАТЧ ОКОНЧЕН" // New text
        }
    };

    let currentLang = 'en'; // Default language

    // --- USERSCRIPT STYLES & HTML INJECTION ---
    const GAME_WIDTH = 1200;
    const GAME_HEIGHT = 700;
    const STAGE_GROUND = 60;
    const TT_AVATAR_URL = 'https://yt3.googleusercontent.com/Fh3avs1Wt0eckLYBbX-DTGoCkiQ0tsBpZLU7k6lpKeSLcAwikIUOOb1vKrCzlnsHtnXFmVGCNQI=s120-c-k-c0x00ffffff';
    const SONECKA_AVATAR_URL = 'https://yt3.googleusercontent.com/Rz25VO6HQZ_vhE2gJMgBOjzbSiqaVrSExTZOkTeL9gLTPXPJI1Pad-ozGSMm9QIDFyOR8pCHn4s=s120-c-k-c0x00ffffff-no-rj';
    const TOTAL_ROUNDS = 3; // New constant for total rounds

    // The styles were kept from the previous version, focusing on functionality here.
    GM_addStyle(`
        @keyframes pulse { 0% { transform: scale(1); opacity: 0.8; } 100% { transform: scale(1.05); opacity: 1; } }
        #fighting-game-container { position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); z-index: 99999; border: 5px solid gold; box-shadow: 0 0 30px rgba(255, 69, 0, 0.9); background: #111; }
        #game-canvas { display: block; background: linear-gradient(to bottom, red 0%, yellow 50%); }
        #ui-overlay { position: absolute; top: 0; left: 0; width: 100%; pointer-events: none; }
        .ui-bar { height: 30px; background: rgba(0, 0, 0, 0.7); border: 2px solid white; position: relative; display: inline-block; box-shadow: 0 0 10px rgba(255, 0, 0, 0.5); }
        .health-bar { height: 100%; transition: width 0.1s ease-out; }
        #p1-health-container, #p2-health-container { width: 40%; margin-top: 20px; }
        #p1-health-container { float: left; margin-left: 50px; }
        #p2-health-container { float: right; margin-right: 50px; }
        .health-text { position: absolute; top: 0; left: 50%; transform: translateX(-50%); color: white; font-size: 18px; font-weight: bold; text-shadow: 1px 1px 3px #000; line-height: 30px; }
        .player-info { position: absolute; top: 5px; color: white; font-size: 14px; text-shadow: 1px 1px 2px #000; }
        .player-info img { width: 60px; height: 60px; border-radius: 50%; border: 3px solid gold; vertical-align: middle; margin: 0 5px; }
        #p1-info { left: 0; }
        #p2-info { right: 0; text-align: right; }
        #timer { position: absolute; top: 15px; left: 50%; transform: translateX(-50%); color: gold; font-size: 40px; font-weight: bold; background: rgba(0, 0, 0, 0.8); padding: 5px 20px; border-radius: 10px; border: 3px solid red; line-height: 1; }
        #lang-select-screen, #char-select-screen, #end-screen { position: absolute; color: white; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0, 0, 0, 0.98); color: white; display: flex; flex-direction: column; justify-content: center; align-items: center; text-align: center; border: 5px solid gold; }
        #lang-select-screen h1 { margin-bottom: 20px; color: white; }
        #lang-select-screen button { background: none; border: none; cursor: pointer; margin: 0 20px; font-size: 30px; }
        #lang-select-screen button img { width: 80px; height: 50px; border: 2px solid white; vertical-align: middle; margin-right: 10px;}
        #char-select-screen h1 { color: gold; text-shadow: 0 0 15px red, 0 0 30px orange; font-size: 64px; margin-bottom: 30px; animation: pulse 1s infinite alternate; }
        .char-button { display: inline-flex; flex-direction: column; align-items: center; background: linear-gradient(to right, #FF4500, #FFD700); color: white; border: 3px solid white; border-radius: 8px; margin: 0 30px; padding: 15px 40px; font-size: 24px; cursor: pointer; box-shadow: 0 5px #900; transition: all 0.1s; }
        .char-button:hover { transform: translateY(-2px); box-shadow: 0 7px #900; }
        .char-button img { width: 120px; height: 120px; border-radius: 50%; margin-bottom: 10px; }
        #end-screen h1 { font-size: 48px; }
        #end-screen button { padding: 15px 40px; font-size: 28px; cursor: pointer; background: linear-gradient(to right, #FF4500, #FFD700); color: white; border: 3px solid white; border-radius: 8px; margin-top: 30px; box-shadow: 0 5px #900; transition: all 0.1s; }
        #round-display { position: absolute; top: 5px; left: 50%; transform: translateX(-50%); color: white; font-size: 24px; font-weight: bold; text-shadow: 1px 1px 3px #000; }
    `);

    // HTML Structure (Kept the same structure, updated text via JS)
    const gameContainer = document.createElement('div');
    gameContainer.id = 'fighting-game-container';
    gameContainer.style.width = `${GAME_WIDTH}px`;
    gameContainer.style.height = `${GAME_HEIGHT}px`;

    gameContainer.innerHTML = `
        <canvas id="game-canvas" width="${GAME_WIDTH}" height="${GAME_HEIGHT}"></canvas>
        <div id="ui-overlay">
            <div id="p1-info" class="player-info">
                <img id="p1-avatar-ui" src="${TT_AVATAR_URL}">
                <span id="p1-name">Tik Tok Minecraft</span>
            </div>
            <div id="p2-info" class="player-info">
                <span id="p2-name">Сонечка</span>
                <img id="p2-avatar-ui" src="${SONECKA_AVATAR_URL}">
            </div>
            <div id="p1-health-container" class="ui-bar">
                <div id="p1-health-bar" class="health-bar" style="background: red; width: 100%;"></div>
                <span id="p1-health-text" class="health-text">100</span>
            </div>
            <div id="p2-health-container" class="ui-bar">
                <div id="p2-health-bar" class="health-bar" style="background: blue; width: 100%;"></div>
                <span id="p2-health-text" class="health-text">100</span>
            </div>
            <div id="timer">60</div>
            <div id="round-display"></div>
        </div>

        <div id="lang-select-screen">
            <h1 id="lang-question-text"></h1>
            <button id="lang-en"><img src="https://flagcdn.com/w80/us.png" alt="English Flag">English</button>
            <button id="lang-ru"><img src="https://flagcdn.com/w80/ru.png" alt="Russian Flag">Русский</button>
        </div>

        <div id="char-select-screen" style="display: none;">
            <h1 id="char-title"></h1>
            <h2 id="char-subtitle"></h2>
            <div>
                <button id="select-tt" class="char-button">
                    <img src="${TT_AVATAR_URL}">
                    <span id="tt-button-text"></span>
                </button>
                <button id="select-sonechka" class="char-button">
                    <img src="${SONECKA_AVATAR_URL}">
                    <span id="sonechka-button-text"></span>
                </button>
            </div>
            <h2 id="controls-title" style="margin-top: 40px;"></h2>
            <p id="p1-controls-text"></p>
            <p id="p2-controls-text"></p>
            <p id="audio-note-text"></p>
        </div>

        <div id="end-screen" style="display: none;">
            <h1 id="end-title"></h1>
            <h2 id="winner-message"></h2>
            <button id="restart-button"></button>
        </div>

        <audio id="bg-music" src="https://www.myinstants.com/media/sounds/kenstheme.mp3" loop></audio>
    `;

    document.body.appendChild(gameContainer);

    // --- GAME SETUP & CONSTANTS ---
    const canvas = document.getElementById('game-canvas');
    const ctx = canvas.getContext('2d');
    const bgMusic = document.getElementById('bg-music');
    const winnerMessage = document.getElementById('winner-message');

    const GRAVITY = 0.8;
    const MAX_HEALTH = 100;
    const ROUND_TIME = 60;

    let gameState = {
        isRunning: false,
        time: ROUND_TIME,
        timerId: null,
        gameOver: false,
        lastTime: 0,
        deltaTime: 0,
        playerChar: null,
        botChar: null,
        round: 1, // Current round
        ttWins: 0, // Win counter for TT
        sonechkaWins: 0, // Win counter for Sonechka
        selectedPlayerKey: null // Stores the character chosen by the human
    };

    let particles = [];

    // --- L10N FUNCTIONS (unchanged) ---
    function updateText() {
        const t = translations[currentLang];
        document.getElementById('lang-question-text').textContent = t.lang_question;
        document.getElementById('char-title').textContent = t.fight_title;
        document.getElementById('char-subtitle').textContent = t.select_char;
        document.getElementById('tt-button-text').textContent = `${t.play_as} Tik Tok Minecraft`;
        document.getElementById('sonechka-button-text').textContent = `${t.play_as} Сонечка`;
        document.getElementById('controls-title').textContent = t.controls_title;
        document.getElementById('p1-controls-text').textContent = t.p1_controls; // Uses unified controls text
        document.getElementById('p2-controls-text').textContent = t.p2_controls;
        document.getElementById('audio-note-text').textContent = t.audio_note;
        document.getElementById('end-title').textContent = t.ko;
        document.getElementById('restart-button').textContent = t.restart_button;
        updateRoundDisplay(); // Update round display text
    }

    function setCurrentLanguage(lang) {
        currentLang = lang;
        updateText();
        document.getElementById('lang-select-screen').style.display = 'none';
        document.getElementById('char-select-screen').style.display = 'flex';
    }

    // --- AUDIO, PARTICLE SYSTEM & FIGHTER CLASS (Fighter class updated for unified controls) ---

    let audioContext;
    function initAudioContext() {
        if (!audioContext) {
            audioContext = new (window.AudioContext || window.webkitAudioContext)();
        }
    }
    function playSound(frequency, duration, type = 'sine', volume = 0.5) {
        initAudioContext();
        if (!audioContext) return;
        const oscillator = audioContext.createOscillator();
        const gainNode = audioContext.createGain();
        oscillator.type = type;
        oscillator.frequency.setValueAtTime(frequency, audioContext.currentTime);
        gainNode.gain.setValueAtTime(volume, audioContext.currentTime);
        oscillator.connect(gainNode);
        gainNode.connect(audioContext.destination);
        oscillator.start();
        oscillator.stop(audioContext.currentTime + duration);
    }
    const soundEffects = {
        attack: () => playSound(600, 0.05, 'sawtooth', 0.4),
        hit: () => playSound(180, 0.15, 'square', 0.7),
        ko: () => playSound(100, 0.8, 'square', 0.8),
        jump: () => playSound(660, 0.08, 'sine', 0.3)
    };

    class Particle {
        // ... (Particle class remains unchanged)
        constructor({ x, y, color }) {
            this.x = x;
            this.y = y;
            this.velocity = { x: (Math.random() - 0.5) * 5, y: (Math.random() - 0.5) * 5 - 2 };
            this.size = Math.random() * 5 + 3;
            this.color = color;
            this.opacity = 1;
            this.friction = 0.99;
        }
        update() {
            this.velocity.x *= this.friction;
            this.velocity.y *= this.friction;
            this.x += this.velocity.x;
            this.y += this.velocity.y;
            this.opacity -= 0.03;
            this.size -= 0.1;
        }
        draw() {
            ctx.save();
            ctx.globalAlpha = Math.max(0, this.opacity);
            ctx.fillStyle = this.color;
            ctx.beginPath();
            ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
            ctx.fill();
            ctx.restore();
        }
    }

    class Fighter {
        // Updated controls parameter to match unified keys
        constructor({ x, name, avatarUrl, side }) {
            this.name = name;
            this.width = 80;
            this.height = 120;
            this.position = { x: x, y: GAME_HEIGHT - this.height - STAGE_GROUND };
            this.avatar = new Image();
            this.avatar.src = avatarUrl;
            this.loaded = false;
            this.avatar.onload = () => { this.loaded = true; };
            this.velocity = { x: 0, y: 0 };
            this.isGrounded = true;
            this.health = MAX_HEALTH;
            this.isAttacking = false;
            this.attackBox = {
                position: { x: this.position.x, y: this.position.y },
                width: 100,
                height: 30,
                offset: side === 'left' ? 80 : -100
            };
            // Set unified controls for the human player (Logic handles which fighter is the human)
            this.controls = { left: 'arrowleft', right: 'arrowright', jump: 'arrowup', attack: ' ' };
            this.side = side;
            this.isHit = false;
            this.hitTimer = 0;
            this.knockbackX = 0;
            this.damage = 10;
            this.isBot = false;
            this.wins = 0; // Win count for this fighter
        }

        update(keys) {
            if (!gameState.isRunning || this.health <= 0) return;

            // Apply gravity
            this.position.y += this.velocity.y;
            this.velocity.y += GRAVITY;

            const groundY = GAME_HEIGHT - this.height - STAGE_GROUND;
            if (this.position.y >= groundY) {
                this.position.y = groundY;
                this.velocity.y = 0;
                this.isGrounded = true;
            }

            let moveSpeed = 5;
            this.velocity.x = 0;

            // **IMPROVEMENT: Prevent movement during attack/hit**
            // Human player controls logic uses the unified key mapping regardless of which fighter it is
            if (!this.isAttacking && !this.isHit && !this.isBot && keys) {
                // UNIFIED CONTROLS LOGIC: Always use Arrow Keys and Space for the human player
                if (keys[this.controls.left].pressed) {
                    this.velocity.x = -moveSpeed;
                } else if (keys[this.controls.right].pressed) {
                    this.velocity.x = moveSpeed;
                }
                if (keys[this.controls.jump].pressed && this.isGrounded) {
                    this.velocity.y = -18;
                    this.isGrounded = false;
                    soundEffects.jump();
                }
                if (keys[this.controls.attack].pressed && !this.isAttacking && this.knockbackX === 0) {
                    this.attack();
                }
            } else if (this.isBot && !this.isAttacking && !this.isHit) {
                // Bot velocity set by botUpdate
            }

            // Apply knockback
            if (this.knockbackX !== 0) {
                this.velocity.x += this.knockbackX;
                this.knockbackX *= 0.9;
                if (Math.abs(this.knockbackX) < 0.5) this.knockbackX = 0;
            }

            this.position.x += this.velocity.x;

            if (this.position.x < 0) this.position.x = 0;
            if (this.position.x + this.width > GAME_WIDTH) this.position.x = GAME_WIDTH - this.width;

            this.attackBox.position.x = this.position.x + this.attackBox.offset;
            this.attackBox.position.y = this.position.y + 30;

            if (this.isHit) {
                this.hitTimer += gameState.deltaTime;
                if (this.hitTimer > 200) {
                    this.isHit = false;
                    this.hitTimer = 0;
                }
            }
        }

        attack() {
            // Prevent multiple attack calls during the attack window
            if (this.isAttacking) return;

            this.isAttacking = true;
            soundEffects.attack();

            // Attack window duration
            setTimeout(() => {
                this.isAttacking = false;
            }, 250); // Slightly longer attack animation time
        }

        takeHit(damage, attackerSide) {
            if (this.health <= 0 || this.isHit) return;
            this.health = Math.max(0, this.health - damage);
            this.isHit = true;
            this.hitTimer = 0; // Reset timer on new hit
            soundEffects.hit();
            this.updateUI();

            const knockbackForce = 18;
            this.knockbackX = attackerSide === 'left' ? knockbackForce : -knockbackForce;

            for (let i = 0; i < 15; i++) {
                particles.push(new Particle({
                    x: this.position.x + this.width / 2,
                    y: this.position.y + this.height / 2,
                    color: 'rgba(255, 100, 0, 1)'
                }));
            }

            if (this.health === 0) {
                // Do not call endGame immediately, set flag for main loop to handle round end
                gameState.gameOver = true;
            }
        }

        updateUI() {
            const healthPercent = (this.health / MAX_HEALTH) * 100;
            const barId = this.side === 'left' ? 'p1-health-bar' : 'p2-health-bar';
            const textId = this.side === 'left' ? 'p1-health-text' : 'p2-health-text';
            const nameId = this.side === 'left' ? 'p1-name' : 'p2-name';

            document.getElementById(barId).style.width = `${healthPercent}%`;
            document.getElementById(textId).textContent = this.health;
            document.getElementById(nameId).textContent = this.name + (this.isBot ? " (BOT)" : "");
        }

        draw() {
            // ... (Draw logic remains unchanged)
            const spriteSize = 100;
            let avatarX = this.position.x + (this.width - spriteSize) / 2;
            let avatarY = this.position.y + (this.height - spriteSize) / 2;
            let drawW = spriteSize;
            let drawH = spriteSize;
            let hitRecoilY = 0;

            // Guard against null reference if one fighter is somehow not initialized in update() loop
            const opponentX = this.side === 'left' && p2 ? p2.position.x : (p1 ? p1.position.x : this.position.x + 1);
            const isFacingRight = this.position.x < opponentX;

            // **IMPROVEMENT: Visual Attack/Hit effects**
            if (this.isAttacking) {
                drawW *= 1.1;
                drawH *= 1.1;
                // Simple forward lunge visual
                avatarX += isFacingRight ? 10 : -10;
            }

            if (this.isHit) {
                // Vertical jiggle/recoil visual
                hitRecoilY = Math.sin(this.hitTimer / 50) * 5;
            }

            ctx.save();

            // Flipping logic
            if (!isFacingRight) {
                ctx.translate(avatarX + drawW, 0); // Move origin to the right edge of the drawn sprite
                ctx.scale(-1, 1);
                // Draw the image at (0, Y + recoil) after translation/scaling
                ctx.drawImage(this.avatar, 0, avatarY + hitRecoilY, drawW, drawH);
            } else {
                ctx.drawImage(this.avatar, avatarX, avatarY + hitRecoilY, drawW, drawH);
            }

            ctx.restore();

            // Hit state (flashing effect)
            if (this.isHit) {
                ctx.fillStyle = `rgba(255, 255, 255, ${Math.abs(Math.sin(performance.now() / 30))})`; // Very fast white flash
                ctx.fillRect(this.position.x, this.position.y, this.width, this.height);
            }

            // Attack state (Hitbox visual)
            if (this.isAttacking) {
                ctx.fillStyle = 'rgba(255, 255, 0, 0.2)';
                ctx.fillRect(this.attackBox.position.x, this.attackBox.position.y, this.attackBox.width, this.attackBox.height);
            }
        }
    }


    // --- AI LOGIC (BOT) (Unchanged) ---

    function botUpdate(bot, target) {
        if (bot.isHit || bot.knockbackX !== 0 || bot.isAttacking) {
            bot.update(null); // Only physics/state updates
            return;
        }

        const distance = target.position.x - bot.position.x;
        const absDistance = Math.abs(distance);
        const attackRange = bot.width + 50;

        // 1. Attack Logic
        if (absDistance < attackRange && bot.isGrounded && Math.random() < 0.1) {
            bot.attack();
        }

        // 2. Movement Logic
        const followDistance = 150;
        const tooCloseDistance = 50;

        if (absDistance > followDistance) {
            // Chase
            bot.velocity.x = distance > 0 ? 4 : -4;
        } else if (absDistance < tooCloseDistance) {
            // Step back (sometimes)
            if (Math.random() < 0.05) {
                bot.velocity.x = distance > 0 ? -2 : 2;
            } else {
                bot.velocity.x = 0;
            }
        } else {
            // Stay within range/stop
            bot.velocity.x = 0;
        }

        // 3. Jump Logic (Simple random jump/avoidance)
        if (bot.isGrounded && Math.random() < 0.005) {
            bot.velocity.y = -18;
            bot.isGrounded = false;
        }

        // Apply bot-set velocity
        bot.position.x += bot.velocity.x;
        bot.update(null); // Update physics/collision/boundaries
    }

    // --- GAME STATE & INSTANTIATION (Updated fighterData and resetGame logic) ---

    // Updated keys to only track the UNIFIED controls
    const keys = {
        'arrowleft': { pressed: false }, 'arrowright': { pressed: false }, 'arrowup': { pressed: false }, ' ': { pressed: false }
    };

    // Removed specific P1/P2 controls from data, as they are now unified/bot
    const fighterData = {
        tt: {
            name: 'Tik Tok Minecraft',
            avatarUrl: TT_AVATAR_URL,
            side: 'left',
            x: 100
        },
        sonechka: {
            name: 'Сонечка',
            avatarUrl: SONECKA_AVATAR_URL,
            side: 'right',
            x: GAME_WIDTH - 100 - 80
        }
    };

    let p1, p2;

    function updateRoundDisplay() {
        const t = translations[currentLang];
        document.getElementById('round-display').textContent = `${t.round} ${gameState.round}/${TOTAL_ROUNDS} | TT: ${gameState.ttWins} - S: ${gameState.sonechkaWins}`;
    }

    // New function to reset the round state (health, position, etc.)
    function resetRound() {
        p1.health = MAX_HEALTH;
        p2.health = MAX_HEALTH;

        // Reset positions
        p1.position = { x: fighterData.tt.x, y: GAME_HEIGHT - p1.height - STAGE_GROUND };
        p2.position = { x: fighterData.sonechka.x, y: GAME_HEIGHT - p2.height - STAGE_GROUND };

        // Reset velocity/state
        p1.velocity = { x: 0, y: 0 };
        p2.velocity = { x: 0, y: 0 };
        p1.isAttacking = p2.isAttacking = false;
        p1.isHit = p2.isHit = false;
        p1.knockbackX = p2.knockbackX = 0;

        p1.updateUI();
        p2.updateUI();

        gameState.gameOver = false;
        gameState.time = ROUND_TIME;
        document.getElementById('timer').textContent = ROUND_TIME;
        particles = [];
    }


    function setupGame(selectedCharKey) {
        // This function runs once at the start of the match
        gameState.selectedPlayerKey = selectedCharKey;
        gameState.round = 1;
        gameState.ttWins = 0;
        gameState.sonechkaWins = 0;

        const p1_data = fighterData.tt;
        const p2_data = fighterData.sonechka;

        p1 = new Fighter(p1_data);
        p2 = new Fighter(p2_data);

        // Assign player/bot roles based on selection
        if (selectedCharKey === 'tt') {
            gameState.playerChar = p1;
            gameState.botChar = p2;
            p2.isBot = true;
        } else { // selectedCharKey === 'sonechka'
            gameState.playerChar = p2;
            gameState.botChar = p1;
            p1.isBot = true;
        }

        // Initialize display
        updateRoundDisplay();
        resetRound();
    }


    // --- COLLISION LOGIC (Unchanged) ---

    function rectangularCollision({ rectangle1, rectangle2 }) {
        return (
            rectangle1.position.x + rectangle1.width >= rectangle2.position.x &&
            rectangle1.position.x <= rectangle2.position.x + rectangle2.width &&
            rectangle1.position.y + rectangle1.height >= rectangle2.position.y &&
            rectangle1.position.y <= rectangle2.position.y + rectangle2.height
        );
    }

    function checkAttacks(attacker, target) {
        // IMPROVEMENT: Attack hits only if target is not currently being hit AND attacker is in attack state
        if (attacker.isAttacking && !target.isHit) {
            const hit = rectangularCollision({ rectangle1: attacker.attackBox, rectangle2: target });
            if (hit) {
                target.takeHit(attacker.damage, attacker.side);
                attacker.isAttacking = false; // Attack only hits once per animation
            }
        }
    }

    // --- GAME LOOP & RENDER (Unchanged logic, just references updated fighter variables) ---

    function drawBackground() {
        ctx.fillStyle = '#696969';
        ctx.beginPath();
        ctx.moveTo(0, GAME_HEIGHT - STAGE_GROUND - 100);
        ctx.lineTo(200, GAME_HEIGHT - STAGE_GROUND - 220);
        ctx.lineTo(450, GAME_HEIGHT - STAGE_GROUND - 150);
        ctx.lineTo(GAME_WIDTH, GAME_HEIGHT - STAGE_GROUND - 200);
        ctx.lineTo(GAME_WIDTH, GAME_HEIGHT - STAGE_GROUND);
        ctx.lineTo(0, GAME_HEIGHT - STAGE_GROUND);
        ctx.fill();

        const groundY = GAME_HEIGHT - STAGE_GROUND;
        const groundGradient = ctx.createLinearGradient(0, groundY, 0, GAME_HEIGHT);
        groundGradient.addColorStop(0, '#556B2F');
        groundGradient.addColorStop(1, '#8B4513');
        ctx.fillStyle = groundGradient;
        ctx.fillRect(0, groundY, GAME_WIDTH, STAGE_GROUND);

        ctx.fillStyle = 'rgba(0, 0, 0, 0.4)';
        ctx.fillRect(0, groundY, GAME_WIDTH, 5);
    }

    function render() {
        ctx.clearRect(0, 0, GAME_WIDTH, GAME_HEIGHT);
        drawBackground();

        if (p1) p1.draw();
        if (p2) p2.draw();

        particles.forEach((p, i) => {
            p.update();
            p.draw();
            if (p.opacity <= 0.05 || p.size <= 1) {
                particles.splice(i, 1);
            }
        });
    }

    function update() {
        if (!gameState.isRunning || gameState.gameOver) return;

        // Player (Human) update uses keys, Bot update calls its own logic
        if (!gameState.playerChar.isBot) {
            gameState.playerChar.update(keys);
            botUpdate(gameState.botChar, gameState.playerChar);
        } else { // Human is P2
            gameState.botChar.update(keys); // BotChar is now P1, but gets the keys object
            botUpdate(gameState.playerChar, gameState.botChar); // PlayerChar is P2, and is the bot's target
        }

        // Correcting the check: playerChar is the human, botChar is the bot regardless of P1/P2
        if (gameState.playerChar.isBot) { // If player is the bot (i.e., the human chose Sonechka, which makes P1 the bot)
            gameState.botChar.update(keys); // P1 (Tik Tok) is the human, P2 (Sonechka) is the bot
            botUpdate(gameState.playerChar, gameState.botChar); // P2 (Sonechka) is the human, P1 (Tik Tok) is the bot

            // Re-assigning for clarity and to follow the original structure, though the underlying logic is better:
            // Let's rely on p1 and p2 directly for attack checks, as they are static.
            p1.update(p1.isBot ? null : keys);
            p2.update(p2.isBot ? null : keys);

            if (p1.isBot) botUpdate(p1, p2);
            if (p2.isBot) botUpdate(p2, p1);


        } else { // Human chose Tik Tok (p1 is human, p2 is bot)
            gameState.playerChar.update(keys);
            botUpdate(gameState.botChar, gameState.playerChar);
        }

        // Apply attack checks
        checkAttacks(p1, p2);
        checkAttacks(p2, p1);

        if (p1.health <= 0 || p2.health <= 0) {
            gameState.gameOver = true;
            endRound(p1.health <= 0 ? p2 : p1); // Pass the winner (or who didn't lose)
        }
    }

    function gameLoop(currentTime) {
        const elapsed = currentTime - gameState.lastTime;
        gameState.deltaTime = elapsed;
        gameState.lastTime = currentTime;

        update();
        render();

        if (!gameState.gameOver) {
            window.requestAnimationFrame(gameLoop);
        }
    }

    // --- GAME CONTROL FUNCTIONS (Updated for round system) ---

    function startTimer() {
        if (gameState.timerId) clearInterval(gameState.timerId);
        const timerDisplay = document.getElementById('timer');
        gameState.time = ROUND_TIME;
        timerDisplay.textContent = gameState.time;
        gameState.timerId = setInterval(() => {
            if (!gameState.isRunning || gameState.gameOver) {
                clearInterval(gameState.timerId);
                return;
            }
            gameState.time--;
            timerDisplay.textContent = gameState.time;
            if (gameState.time <= 0) {
                clearInterval(gameState.timerId);
                gameState.gameOver = true;
                endRound(null, true); // Time up, no KO winner
            }
        }, 1000);
    }

    function startGame(selectedCharKey) {
        document.getElementById('char-select-screen').style.display = 'none';
        document.getElementById('end-screen').style.display = 'none';

        // Only run setupGame if it's the very first time (or after a full match ends)
        if (gameState.round === 1 && gameState.ttWins === 0 && gameState.sonechkaWins === 0) {
            setupGame(selectedCharKey);
        } else {
            // Otherwise, it's a new round in the same match
            resetRound();
        }

        gameState.isRunning = true;
        startTimer();
        gameState.lastTime = performance.now();
        window.requestAnimationFrame(gameLoop);
    }

    function endRound(winner, timeUp = false) {
        gameState.isRunning = false;
        clearInterval(gameState.timerId);
        const t = translations[currentLang];

        let message = '';

        if (timeUp) {
            if (p1.health > p2.health) {
                winner = p1;
                message = `${winner.name} ${t.time_advantage}`;
            } else if (p2.health > p1.health) {
                winner = p2;
                message = `${winner.name} ${t.time_advantage}`;
            } else {
                message = t.draw_message;
            }
        } else {
            // KO win
            message = `${winner.name} ${t.ko_message}`;
        }

        if (winner) {
            if (winner === p1) {
                gameState.ttWins++;
            } else if (winner === p2) {
                gameState.sonechkaWins++;
            }
        }

        // Update win counters and round display before moving on
        updateRoundDisplay();

        // Check for match end
        if (gameState.round >= TOTAL_ROUNDS || gameState.ttWins >= Math.ceil(TOTAL_ROUNDS/2) || gameState.sonechkaWins >= Math.ceil(TOTAL_ROUNDS/2) ) {
            // Final Game Over
            let finalWinner = null;
            if (gameState.ttWins > gameState.sonechkaWins) finalWinner = p1;
            else if (gameState.sonechkaWins > gameState.ttWins) finalWinner = p2;

            if (finalWinner) {
                document.getElementById('winner-message').textContent = `${finalWinner.name} ${t.match_over}! (${gameState.ttWins}-${gameState.sonechkaWins})`;
            } else {
                document.getElementById('winner-message').textContent = `${t.match_over}! ${t.draw_message} (${gameState.ttWins}-${gameState.sonechkaWins})`;
            }
            document.getElementById('end-title').textContent = t.game_over;
            document.getElementById('restart-button').textContent = t.restart_button.split(' / ')[1]; // PLAY AGAIN
            document.getElementById('end-screen').style.display = 'flex';

            // Next click will go back to char select
            document.getElementById('restart-button').onclick = () => {
                document.getElementById('char-select-screen').style.display = 'flex';
                document.getElementById('end-screen').style.display = 'none';
            };


        } else {
            // Next Round
            gameState.round++;
            document.getElementById('winner-message').textContent = message + ` - ${t.round} ${gameState.round}`;
            document.getElementById('end-title').textContent = t.ko;
            document.getElementById('restart-button').textContent = t.restart_button.split(' / ')[0]; // CONTINUE
            document.getElementById('end-screen').style.display = 'flex';

            // Next click starts the next round
            document.getElementById('restart-button').onclick = () => {
                startGame(gameState.selectedPlayerKey);
            };
        }
    }

    // --- EVENT LISTENERS BINDING (Updated to use startGame with selectedCharKey) ---

    document.getElementById('lang-en').addEventListener('click', () => setCurrentLanguage('en'));
    document.getElementById('lang-ru').addEventListener('click', () => setCurrentLanguage('ru'));

    document.getElementById('select-tt').addEventListener('click', () => {
        // First round start, setup the game state
        setupGame('tt');
        startGame('tt');
    });
    document.getElementById('select-sonechka').addEventListener('click', () => {
        // First round start, setup the game state
        setupGame('sonechka');
        startGame('sonechka');
    });

    // Initial click handler for restart button (for when the match is fully over)
    document.getElementById('restart-button').addEventListener('click', () => {
        if (!gameState.isRunning && gameState.round > TOTAL_ROUNDS) { // Only go back to char select if match is truly over
            document.getElementById('char-select-screen').style.display = 'flex';
            document.getElementById('end-screen').style.display = 'none';
        }
    });


    // **UNIFIED KEYBOARD LISTENER LOGIC**
    window.addEventListener('keydown', (event) => {
        const key = event.key.toLowerCase();
        // Check if the key is one of the unified controls
        if (keys[key] && gameState.isRunning) {
            keys[key].pressed = true;
            // Prevent default action for game keys
            if (['arrowleft', 'arrowright', 'arrowup', ' '].includes(key)) {
                event.preventDefault();
            }
        }
    });

    window.addEventListener('keyup', (event) => {
        const key = event.key.toLowerCase();
        if (keys[key]) {
            keys[key].pressed = false;
        }
    });

    document.body.addEventListener('click', () => {
        initAudioContext();
        if (bgMusic.paused) {
            bgMusic.play().catch(e => console.error("Autoplay failed:", e));
        }
    }, { once: true });

    // Initial setup
    updateText();
    document.getElementById('lang-select-screen').style.display = 'flex';
})();