Skip to content

Fix AGENTS.md location guidance in code modernization cookbook#38

Open
yishangupenn wants to merge 1 commit into
mainfrom
upstream-pr-2341
Open

Fix AGENTS.md location guidance in code modernization cookbook#38
yishangupenn wants to merge 1 commit into
mainfrom
upstream-pr-2341

Conversation

@yishangupenn

@yishangupenn yishangupenn commented Mar 10, 2026

Copy link
Copy Markdown

Copied from upstream: openai/openai-cookbook#2341
Original author: @heathdutton
Originally opened: 2026-01-02


Summary

Corrects the AGENTS.md file location guidance in the code modernization cookbook. The docs previously suggested placing AGENTS.md in a .agent/ folder, but Codex CLI only auto-discovers AGENTS.md from directories along the path from repo root to the current working directory.

Motivation

Fixes openai#2311. Users following the current instructions would create .agent/AGENTS.md, which Codex won't automatically load when running from the repository root.

@bendasgfyug

Copy link
Copy Markdown
<title>Complete War Simulator - Summoner Edition</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; }
    body {
        font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
        overflow: hidden;
        background: linear-gradient(to bottom, #87CEEB 0%, #90EE90 70%, #8B4513 70%, #654321 100%);
        height: 100vh;
        display: flex;
        flex-direction: column;
    }

    #gameContainer {
        position: relative;
        flex: 1;
        display: flex;
        flex-direction: column;
    }

    /* Control Panel */
    #controlPanel {
        background: rgba(0, 0, 0, 0.85);
        padding: 15px;
        display: flex;
        flex-wrap: wrap;
        gap: 15px;
        align-items: center;
        justify-content: center;
        border-bottom: 3px solid #444;
        box-shadow: 0 4px 15px rgba(0,0,0,0.5);
    }

    .control-group {
        display: flex;
        flex-direction: column;
        gap: 5px;
    }

    .control-label {
        color: #fff;
        font-size: 12px;
        font-weight: bold;
        text-transform: uppercase;
        letter-spacing: 1px;
    }

    /* Team Selection */
    .team-selector {
        display: flex;
        gap: 10px;
    }

    .team-btn {
        padding: 10px 20px;
        border: 3px solid;
        border-radius: 8px;
        cursor: pointer;
        font-weight: bold;
        transition: all 0.3s;
        background: rgba(255,255,255,0.1);
        color: white;
    }

    .team-btn.red {
        border-color: #ff4444;
    }

    .team-btn.red.active, .team-btn.red:hover {
        background: #ff4444;
        box-shadow: 0 0 15px #ff4444;
    }

    .team-btn.blue {
        border-color: #4444ff;
    }

    .team-btn.blue.active, .team-btn.blue:hover {
        background: #4444ff;
        box-shadow: 0 0 15px #4444ff;
    }

    /* Unit Selection */
    .unit-grid {
        display: grid;
        grid-template-columns: repeat(5, 1fr);
        gap: 8px;
    }

    .unit-btn {
        width: 70px;
        height: 70px;
        border: 2px solid #666;
        border-radius: 10px;
        cursor: pointer;
        background: rgba(255,255,255,0.1);
        color: white;
        font-size: 11px;
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        gap: 3px;
        transition: all 0.2s;
        position: relative;
        overflow: hidden;
    }

    .unit-btn:hover {
        transform: translateY(-2px);
        border-color: #fff;
        background: rgba(255,255,255,0.2);
    }

    .unit-btn.active {
        border-color: #ffd700;
        background: rgba(255,215,0,0.3);
        box-shadow: 0 0 10px #ffd700;
    }

    .unit-icon {
        font-size: 24px;
    }

    /* Action Buttons */
    .action-buttons {
        display: flex;
        gap: 10px;
    }

    .action-btn {
        padding: 15px 30px;
        border: none;
        border-radius: 8px;
        cursor: pointer;
        font-weight: bold;
        font-size: 14px;
        text-transform: uppercase;
        transition: all 0.3s;
    }

    .start-btn {
        background: #00cc66;
        color: white;
    }

    .start-btn:hover {
        background: #00aa55;
        box-shadow: 0 0 15px #00cc66;
    }

    .pause-btn {
        background: #ffaa00;
        color: white;
    }

    .pause-btn:hover {
        background: #dd9900;
        box-shadow: 0 0 15px #ffaa00;
    }

    .reset-btn {
        background: #ff4444;
        color: white;
    }

    .reset-btn:hover {
        background: #cc3333;
        box-shadow: 0 0 15px #ff4444;
    }

    /* Canvas Area */
    #canvasWrapper {
        flex: 1;
        position: relative;
        overflow: hidden;
    }

    #gameCanvas {
        display: block;
        cursor: crosshair;
        touch-action: none;
    }

    /* Status Bar */
    #statusBar {
        background: rgba(0, 0, 0, 0.9);
        padding: 10px 20px;
        display: flex;
        justify-content: space-around;
        align-items: center;
        color: white;
        font-family: 'Courier New', monospace;
        border-top: 3px solid #444;
    }

    .status-item {
        display: flex;
        align-items: center;
        gap: 10px;
        font-size: 14px;
    }

    .status-label {
        color: #aaa;
        text-transform: uppercase;
        font-size: 12px;
    }

    .status-value {
        font-weight: bold;
        font-size: 16px;
    }

    .red-count { color: #ff6666; }
    .blue-count { color: #6666ff; }
    .fps-count { color: #66ff66; }
    .total-count { color: #ffff66; }

    .game-status {
        padding: 5px 15px;
        border-radius: 20px;
        font-weight: bold;
        text-transform: uppercase;
    }

    .status-waiting { background: #666; }
    .status-running { background: #00cc66; animation: pulse 2s infinite; }
    .status-paused { background: #ffaa00; }
    .status-finished { background: #ff4444; }

    @keyframes pulse {
        0%, 100% { opacity: 1; }
        50% { opacity: 0.7; }
    }

    /* Instructions */
    #instructions {
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        background: rgba(0,0,0,0.8);
        color: white;
        padding: 30px;
        border-radius: 15px;
        text-align: center;
        pointer-events: none;
        opacity: 0;
        transition: opacity 0.5s;
    }

    #instructions.show {
        opacity: 1;
    }

    /* Unit Info Tooltip */
    #tooltip {
        position: absolute;
        background: rgba(0,0,0,0.9);
        color: white;
        padding: 10px;
        border-radius: 8px;
        font-size: 12px;
        pointer-events: none;
        display: none;
        z-index: 1000;
        border: 1px solid #666;
    }

    /* Responsive */
    @media (max-width: 900px) {
        .unit-grid {
            grid-template-columns: repeat(3, 1fr);
        }
        .unit-btn {
            width: 60px;
            height: 60px;
            font-size: 10px;
        }
    }
</style>
Select Team
🔴 Red Team 🔵 Blue Team
        <div class="control-group">
            <span class="control-label">Select Unit</span>
            <div class="unit-grid">
                <button class="unit-btn active" onclick="selectUnit('swordsman')" title="Balanced melee fighter">
                    <span class="unit-icon">⚔️</span>
                    <span>Swordsman</span>
                </button>
                <button class="unit-btn" onclick="selectUnit('archer')" title="Ranged attacker">
                    <span class="unit-icon">🏹</span>
                    <span>Archer</span>
                </button>
                <button class="unit-btn" onclick="selectUnit('knight')" title="Heavy melee with charge">
                    <span class="unit-icon">🐴</span>
                    <span>Knight</span>
                </button>
                <button class="unit-btn" onclick="selectUnit('tank')" title="High health, slow">
                    <span class="unit-icon">🛡️</span>
                    <span>Tank</span>
                </button>
                <button class="unit-btn" onclick="selectUnit('mage')" title="Area damage, low health">
                    <span class="unit-icon">🔮</span>
                    <span>Mage</span>
                </button>
                <button class="unit-btn" onclick="selectUnit('assassin')" title="Fast, high damage, stealth">
                    <span class="unit-icon">🗡️</span>
                    <span>Assassin</span>
                </button>
                <button class="unit-btn" onclick="selectUnit('medic')" title="Heals allies">
                    <span class="unit-icon">💚</span>
                    <span>Medic</span>
                </button>
                <button class="unit-btn" onclick="selectUnit('summoner')" title="Summons minions">
                    <span class="unit-icon">👻</span>
                    <span>Summoner</span>
                </button>
                <button class="unit-btn" onclick="selectUnit('bomber')" title="Explodes on death">
                    <span class="unit-icon">💣</span>
                    <span>Bomber</span>
                </button>12
            </div>
        </div>4fg

        <div class="control-group">
            <span class="control-label">Game Controls</span>
            <div class="action-buttons">
                <button class="action-btn start-btn" onclick="startGame()">▶ Start</button>
                <button class="action-btn pause-btn" onclick="pauseGame()">⏸ Pause</button>
                <button class="action-btn reset-btn" onclick="resetGame()">↺ Reset</button>
            </div>
        </div>
    </div>

    <!-- Canvas -->
    <div id="canvasWrapper">
        <canvas id="gameCanvas"></canvas>
        <div id="instructions">
            <h2>🎮 How to Play</h2>
            <p>Click or touch anywhere on the battlefield to place units</p>
            <p>Select different teams and unit types from the control panel</p>
            <p>Press Start to begin the battle!</p>
        </div>d3rerse
    </div>pul

    <!-- Status Bar -->
    <div id="statusBar">
        <div class="status-item">
            <span class="status-label">Red Team:</span>rug
            <span class="status-value red-count" id="redCount">0</span>
        </div>bright
        <div class="status-item">
            <span class="status-label">Blue Team:</span>que
            <span class="status-value blue-count" id="blueCount">0</span>
        </div>formal
        <div class="status-item">
            <span class="status-label">Total Units:</span>
            <span class="status-value total-count" id="totalCount">0</span>
        </div>elite
        <div class="status-item">
            <span class="status-label">FPS:</span>
            <span class="status-value fps-count" id="fpsCount">60</span>
        </div>1
        <div class="status-item">
            <span class="status-label">Status:</span>
            <span class="game-status status-waiting" id="gameStatus">Waiting</span>
        </div>7
    </div>5
</div>22

<div id="tooltip"></div>

<script>
    // Game Configuration
    const canvas = document.getElementById('gameCanvas');
    const ctx = canvas.getContext('2d');
    
    // Game State
    let gameState = 'waiting'; // waiting, running, paused, finished
    let selectedTeam = 'red';
    let selectedUnitType = 'swordsman';
    let units = [];
    let projectiles = [];
    let particles = [];
    let lastTime = 0;
    let frameCount = 0;
    let fps = 60;
    let fpsUpdateTime = 0;
    let gameLoopId = null;

    // Unit Definitions
    const unitTypes = {
        swordsman: {
            name: 'Swordsman',
            icon: '⚔️',
            health: 100,
            damage: 20,
            speed: 2,
            range: 40,
            attackSpeed: 1000,
            color: '#ff6666',
            size: 15,
            description: 'Balanced melee fighter'
        },
        archer: {bendas
            name: 'Archer',
            icon: '🏹',
            health: 60,
            damage: 25,
            speed: 1.5,
            range: 150,
            attackSpeed: 1500,
            color: '#ff9966',
            size: 12,
            projectile: true,
            description: 'Ranged attacker'
        },
        knight: {
            name: 'Knight',
            icon: '🐴',
            health: 150,
            damage: 35,
            speed: 3,
            range: 50,
            attackSpeed: 1200,
            color: '#cc9966',
            size: 18,
            charge: true,
            description: 'Heavy melee with charge'
        },
        tank: {
            name: 'Tank',bendas
            icon: '🛡️',
            health: 300,
            damage: 15,
            speed: 0.8,
            range: 35,
            attackSpeed: 2000,00
            color: '#666666',
            size: 22,
            armor: 0.5,
            description: 'High health, slow'
        },
        mage: {3/43
            name: 'Mage',
            icon: '🔮',40
            health: 50,
            damage: 40,
            speed: 1.2,
            range: 120,
            attackSpeed: 2000,
            color: '#9966ff',
            size: 14,
            aoe: true,
            description: 'Area damage, low health'
        },
        assassin: {
            name: 'Assassin',
            icon: '🗡️',
            health: 70,
            damage: 45,
            speed: 3.5,
            range: 30,
            attackSpeed: 800,000
            color: '#6600cc',
            size: 12,
            stealth: true,
            description: 'Fast, high damage, stealth'
        },
        medic: {
            name: 'Medic',
            icon: '💚',
            health: 80,
            damage: 5,
            speed: 1.8,
            range: 100,
            attackSpeed: 1500,
            color: '#00cc66',
            size: 13,
            heal: true,
            description: 'Heals allies'
        },
        summoner: {
            name: 'Summoner',
            icon: '👻',
            health: 90,
            damage: 10,
            speed: 1.3,
            range: 80,
            attackSpeed: 3000,
            color: '#cc00cc',
            size: 14,
            summon: true,
            description: 'Summons minions'
        },
        bomber: {
            name: 'Bomber',
            icon: '💣',
            health: 40,
            damage: 100,
            speed: 2.5,
            range: 25,
            attackSpeed: 100,
            color: '#ff3300',
            size: 16,
            explode: true,
            description: 'Explodes on death'
        }
    };

    // Resize canvas
    function resizeCanvas() {
        const wrapper = document.getElementById('canvasWrapper');
        canvas.width = wrapper.clientWidth;
        canvas.height = wrapper.clientHeight;
    }
    window.addEventListener('resize', resizeCanvas);
    resizeCanvas();

    // Unit Class
    class Unit {
        constructor(x, y, team, type) {
            this.x = x;
            this.y = y;
            this.team = team;
            this.type = type;
            this.stats = {...unitTypes[type]};
            this.maxHealth = this.stats.health;
            this.health = this.stats.health;
            this.target = null;
            this.lastAttack = 0;
            this.id = Math.random().toString(36).substr(2, 9);
            this.vx = 0;
            this.vy = 0;
            this.stealthTimer = 0;
            this.summonTimer = 0;
            this.charging = false;
            this.chargeTimer = 0;
        }

        update(deltaTime) {
            // Find nearest enemy
            let nearest = null;
            let minDist = Infinity;
            
            for (let unit of units) {
                if (unit.team !== this.team && unit.health > 0) {
                    const dist = Math.hypot(unit.x - this.x, unit.y - this.y);
                    if (dist < minDist) {
                        minDist = dist;
                        nearest = unit;
                    }
                }
            }

            this.target = nearest;

            // Movement and combat
            if (this.target) {
                const dx = this.target.x - this.x;
                const dy = this.target.y - this.y;
                const dist = Math.hypot(dx, dy);

                // Knight charge ability
                if (this.stats.charge && !this.charging && dist > 100 && this.chargeTimer <= 0) {
                    this.charging = true;
                    this.chargeTimer = 3000;
                }

                if (this.charging) {
                    this.chargeTimer -= deltaTime;
                    if (this.chargeTimer <= 0) this.charging = false;
                }

                let speed = this.stats.speed;
                if (this.charging) speed *= 2;

                // Move towards target if out of range
                if (dist > this.stats.range) {
                    this.vx = (dx / dist) * speed;
                    this.vy = (dy / dist) * speed;
                    this.x += this.vx;
                    this.y += this.vy;
                } else {
                    // Attack
                    const now = Date.now();
                    if (now - this.lastAttack > this.stats.attackSpeed) {
                        this.attack(this.target);
                        this.lastAttack = now;
                    }
                }
            }

            // Medic healing
            if (this.stats.heal) {
                let healTarget = null;
                let minHealDist = Infinity;
                for (let unit of units) {
                    if (unit.team === this.team && unit !== this && unit.health < unit.maxHealth) {
                        const dist = Math.hypot(unit.x - this.x, unit.y - this.y);
                        if (dist < minHealDist && dist < this.stats.range) {
                            minHealDist = dist;
                            healTarget = unit;
                        }
                    }
                }
                if (healTarget) {
                    const now = Date.now();
                    if (now - this.lastAttack > this.stats.attackSpeed) {
                        healTarget.health = Math.min(healTarget.health + 30, healTarget.maxHealth);
                        createParticle(healTarget.x, healTarget.y, '#00ff00', 5);
                        this.lastAttack = now;
                    }
                }
            }

            // Summoner ability
            if (this.stats.summon) {
                this.summonTimer += deltaTime;
                if (this.summonTimer > 5000) {
                    this.summonMinion();
                    this.summonTimer = 0;
                }
            }

            // Keep within bounds
            this.x = Math.max(20, Math.min(canvas.width - 20, this.x));
            this.y = Math.max(20, Math.min(canvas.height - 20, this.y));

            // Update stealth
            if (this.stats.stealth) {
                this.stealthTimer += deltaTime;
            }
        }

        attack(target) {
            if (this.stats.projectile) {
                // Create projectile
                projectiles.push({
                    x: this.x,
                    y: this.y,
                    target: target,
                    damage: this.stats.damage,
                    team: this.team,
                    speed: 8,
                    color: this.team === 'red' ? '#ff6666' : '#6666ff'
                });
            } else if (this.stats.aoe) {
                // Area damage
                createParticle(target.x, target.y, '#9966ff', 20);
                for (let unit of units) {
                    if (unit.team !== this.team) {
                        const dist = Math.hypot(unit.x - target.x, unit.y - target.y);
                        if (dist < 60) {
                            unit.takeDamage(this.stats.damage);
                        }
                    }
                }
            } else {
                // Melee attack
                target.takeDamage(this.stats.damage);
                createParticle(target.x, target.y, '#ffff00', 3);
            }
        }

        summonMinion() {
            const offsetX = (Math.random() - 0.5) * 40;
            const offsetY = (Math.random() - 0.5) * 40;
            const minion = new Unit(this.x + offsetX, this.y + offsetY, this.team, 'swordsman');
            minion.stats.health = 50;
            minion.health = 50;
            minion.stats.damage = 10;
            minion.stats.size = 10;
            minion.isMinion = true;
            units.push(minion);
            createParticle(minion.x, minion.y, '#cc00cc', 10);
        }

        takeDamage(damage) {
            if (this.stats.armor) {
                damage *= (1 - this.stats.armor);
            }
            this.health -= damage;
            
            // Bomber explosion
            if (this.stats.explode && this.health <= 0) {
                createParticle(this.x, this.y, '#ff3300', 40);
                for (let unit of units) {
                    const dist = Math.hypot(unit.x - this.x, unit.y - this.y);
                    if (dist < 80) {
                        unit.takeDamage(60);
                    }
                }
            }
        }

        draw() {
            // Stealth effect
            let alpha = 1;
            if (this.stats.stealth && this.stealthTimer % 2000 < 1000) {
                alpha = 0.3;
            }

            ctx.globalAlpha = alpha;

            // Team color
            const teamColor = this.team === 'red' ? '#ff4444' : '#4444ff';
            const darkerTeamColor = this.team === 'red' ? '#cc3333' : '#3333cc';

            // Body
            ctx.beginPath();
            ctx.arc(this.x, this.y, this.stats.size, 0, Math.PI * 2);
            ctx.fillStyle = this.stats.color;
            ctx.fill();
            ctx.strokeStyle = teamColor;
            ctx.lineWidth = 3;
            ctx.stroke();

            // Team indicator
            ctx.beginPath();
            ctx.arc(this.x, this.y, this.stats.size * 0.6, 0, Math.PI * 2);
            ctx.fillStyle = teamColor;
            ctx.fill();

            // Health bar
            const barWidth = 30;
            const barHeight = 4;
            const healthPercent = this.health / this.maxHealth;
            
            ctx.fillStyle = '#333';
            ctx.fillRect(this.x - barWidth/2, this.y - this.stats.size - 10, barWidth, barHeight);
            
            ctx.fillStyle = healthPercent > 0.5 ? '#00ff00' : healthPercent > 0.25 ? '#ffff00' : '#ff0000';
            ctx.fillRect(this.x - barWidth/2, this.y - this.stats.size - 10, barWidth * healthPercent, barHeight);

            // Icon
            ctx.font = `${this.stats.size}px Arial`;
            ctx.textAlign = 'center';
            ctx.textBaseline = 'middle';
            ctx.fillStyle = 'white';
            ctx.fillText(this.stats.icon, this.x, this.y);

            // Minion indicator
            if (this.isMinion) {
                ctx.strokeStyle = '#ffff00';
                ctx.lineWidth = 2;
                ctx.beginPath();
                ctx.arc(this.x, this.y, this.stats.size + 3, 0, Math.PI * 2);
                ctx.stroke();
            }

            // Charging effect
            if (this.charging) {
                ctx.beginPath();
                ctx.arc(this.x, this.y, this.stats.size + 8, 0, Math.PI * 2);
                ctx.strokeStyle = '#ffff00';
                ctx.lineWidth = 2;
                ctx.stroke();
            }

            ctx.globalAlpha = 1;
        }
    }

    // Particle System
    function createParticle(x, y, color, size) {
        for (let i = 0; i < 5; i++) {
            particles.push({
                x: x,
                y: y,
                vx: (Math.random() - 0.5) * 4,
                vy: (Math.random() - 0.5) * 4,
                life: 30,
                color: color,
                size: size / 2
            });
        }
    }

    function updateParticles() {
        for (let i = particles.length - 1; i >= 0; i--) {
            const p = particles[i];
            p.x += p.vx;
            p.y += p.vy;
            p.life--;
            if (p.life <= 0) {
                particles.splice(i, 1);
            }
        }
    }

    function drawParticles() {
        for (let p of particles) {
            ctx.globalAlpha = p.life / 30;
            ctx.fillStyle = p.color;
            ctx.beginPath();
            ctx.arc(p.x, p.y, p.size, 0, Math.PI * 2);
            ctx.fill();
        }
        ctx.globalAlpha = 1;
    }

    // Projectile System
    function updateProjectiles() {
        for (let i = projectiles.length - 1; i >= 0; i--) {
            const p = projectiles[i];
            if (!p.target || p.target.health <= 0) {
                projectiles.splice(i, 1);
                continue;
            }

            const dx = p.target.x - p.x;
            const dy = p.target.y - p.y;
            const dist = Math.hypot(dx, dy);

            if (dist < p.speed) {
                p.target.takeDamage(p.damage);
                createParticle(p.target.x, p.target.y, p.color, 5);
                projectiles.splice(i, 1);
            } else {
                p.x += (dx / dist) * p.speed;
                p.y += (dy / dist) * p.speed;
            }
        }
    }

    function drawProjectiles() {
        for (let p of projectiles) {
            ctx.beginPath();
            ctx.arc(p.x, p.y, 5, 0, Math.PI * 2);
            ctx.fillStyle = p.color;
            ctx.fill();
            
            // Trail
            ctx.beginPath();
            ctx.moveTo(p.x, p.y);
            ctx.lineTo(p.x - p.vx * 3, p.y - p.vy * 3);
            ctx.strokeStyle = p.color;
            ctx.lineWidth = 2;
            ctx.stroke();
        }
    }

    // Game Loop
    function gameLoop(currentTime) {
        if (gameState !== 'running') return;

        const deltaTime = currentTime - lastTime;
        lastTime = currentTime;

        // Update FPS
        frameCount++;
        if (currentTime - fpsUpdateTime > 1000) {
            fps = frameCount;
            frameCount = 0;
            fpsUpdateTime = currentTime;
            document.getElementById('fpsCount').textContent = fps;
        }

        // Clear canvas
        ctx.clearRect(0, 0, canvas.width, canvas.height);

        // Draw background gradient
        const gradient = ctx.createLinearGradient(0, 0, 0, canvas.height);
        gradient.addColorStop(0, '#87CEEB');
        gradient.addColorStop(0.7, '#90EE90');
        gradient.addColorStop(0.7, '#8B4513');
        gradient.addColorStop(1, '#654321');
        ctx.fillStyle = gradient;
        ctx.fillRect(0, 0, canvas.width, canvas.height);

        // Draw ground line
        ctx.strokeStyle = '#5D4037';
        ctx.lineWidth = 3;
        ctx.beginPath();
        ctx.moveTo(0, canvas.height * 0.7);
        ctx.lineTo(canvas.width, canvas.height * 0.7);
        ctx.stroke();

        // Update and draw units
        for (let i = units.length - 1; i >= 0; i--) {
            const unit = units[i];
            if (unit.health > 0) {
                unit.update(deltaTime);
                unit.draw();
            } else {
                createParticle(unit.x, unit.y, '#ff0000', 10);
                units.splice(i, 1);
            }
        }

        // Update projectiles
        updateProjectiles();
        drawProjectiles();

        // Update particles
        updateParticles();
        drawParticles();

        // Update counts
        updateCounts();

        // Check win condition
        const redUnits = units.filter(u => u.team === 'red').length;
        const blueUnits = units.filter(u => u.team === 'blue').length;
        
        if (redUnits === 0 && blueUnits === 0 && units.length > 0) {
            endGame('draw');
        } else if (redUnits === 0 && units.length > 0) {
            endGame('blue');
        } else if (blueUnits === 0 && units.length > 0) {
            endGame('red');
        }

        gameLoopId = requestAnimationFrame(gameLoop);
    }

    // UI Functions
    function selectTeam(team) {
        selectedTeam = team;
        document.querySelectorAll('.team-btn').forEach(btn => btn.classList.remove('active'));
        document.querySelector(`.team-btn.${team}`).classList.add('active');
    }

    function selectUnit(type) {
        selectedUnitType = type;
        document.querySelectorAll('.unit-btn').forEach(btn => btn.classList.remove('active'));
        event.currentTarget.classList.add('active');
    }

    function startGame() {
        if (units.length < 2) {
            alert('Place at least 2 units to start!');
            return;
        }
        gameState = 'running';
        lastTime = performance.now();
        fpsUpdateTime = performance.now();
        document.getElementById('gameStatus').textContent = 'Running';
        document.getElementById('gameStatus').className = 'game-status status-running';
        gameLoop(performance.now());
    }

    function pauseGame() {
        if (gameState === 'running') {
            gameState = 'paused';
            cancelAnimationFrame(gameLoopId);
            document.getElementById('gameStatus').textContent = 'Paused';
            document.getElementById('gameStatus').className = 'game-status status-paused';
        } else if (gameState === 'paused') {
            gameState = 'running';
            lastTime = performance.now();
            document.getElementById('gameStatus').textContent = 'Running';
            document.getElementById('gameStatus').className = 'game-status status-running';
            gameLoop(performance.now());
        }
    }

    function resetGame() {
        gameState = 'waiting';
        cancelAnimationFrame(gameLoopId);
        units = [];
        projectiles = [];
        particles = [];
        document.getElementById('gameStatus').textContent = 'Waiting';
        document.getElementById('gameStatus').className = 'game-status status-waiting';
        updateCounts();
        
        // Redraw empty canvas
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        const gradient = ctx.createLinearGradient(0, 0, 0, canvas.height);
        gradient.addColorStop(0, '#87CEEB');
        gradient.addColorStop(0.7, '#90EE90');
        gradient.addColorStop(0.7, '#8B4513');
        gradient.addColorStop(1, '#654321');
        ctx.fillStyle = gradient;
        ctx.fillRect(0, 0, canvas.width, canvas.height);
        
        ctx.strokeStyle = '#5D4037';
        ctx.lineWidth = 3;
        ctx.beginPath();
        ctx.moveTo(0, canvas.height * 0.7);
        ctx.lineTo(canvas.width, canvas.height * 0.7);
        ctx.stroke();
    }

    function endGame(winner) {
        gameState = 'finished';
        cancelAnimationFrame(gameLoopId);
        document.getElementById('gameStatus').textContent = winner === 'draw' ? 'Draw!' : `${winner.toUpperCase()} Wins!`;
        document.getElementById('gameStatus').className = 'game-status status-finished';
        
        setTimeout(() => {
            alert(winner === 'draw' ? "It's a draw!" : `${winner.toUpperCase()} Team Wins!`);
        }, 100);
    }

    function updateCounts() {
        const redCount = units.filter(u => u.team === 'red').length;
        const blueCount = units.filter(u => u.team === 'blue').length;
        document.getElementById('redCount').textContent = redCount;
        document.getElementById('blueCount').textContent = blueCount;
        document.getElementById('totalCount').textContent = units.length;
    }

    // Input Handling
    function placeUnit(x, y) {
        if (gameState === 'running') return; // Can't place during battle
        
        const unit = new Unit(x, y, selectedTeam, selectedUnitType);
        units.push(unit);
        createParticle(x, y, selectedTeam === 'red' ? '#ff4444' : '#4444ff', 8);
        updateCounts();
    }

    // Mouse input
    canvas.addEventListener('click', (e) => {
        const rect = canvas.getBoundingClientRect();
        placeUnit(e.clientX - rect.left, e.clientY - rect.top);
    });

    // Touch input
    canvas.addEventListener('touchstart', (e) => {
        e.preventDefault();
        const rect = canvas.getBoundingClientRect();
        const touch = e.touches[0];
        placeUnit(touch.clientX - rect.left, touch.clientY - rect.top);
    });

    // Tooltip handling
    const tooltip = document.getElementById('tooltip');
    document.querySelectorAll('.unit-btn').forEach(btn => {
        btn.addEventListener('mouseenter', (e) => {
            const type = btn.getAttribute('onclick').match(/'(\w+)'/)[1];
            const stats = unitTypes[type];
            tooltip.innerHTML = `
                <strong>${stats.name}</strong><br>
                ❤️ ${stats.health} | ⚔️ ${stats.damage}<br>
                🏃 ${stats.speed} | 📏 ${stats.range}<br>
                <em>${stats.description}</em>
            `;
            tooltip.style.display = 'block';
        });
        
        btn.addEventListener('mousemove', (e) => {
            tooltip.style.left = e.pageX + 10 + 'px';
            tooltip.style.top = e.pageY + 10 + 'px';
        });
        
        btn.addEventListener('mouseleave', () => {
            tooltip.style.display = 'none';
        });
    });

    // Show instructions briefly
    window.addEventListener('load', () => {
        const instructions = document.getElementById('instructions');
        instructions.classList.add('show');
        setTimeout(() => {
            instructions.classList.remove('show');
        }, 4000);
    });

    // Initial render
    resizeCanvas();
    ctx.fillStyle = '#87CEEB';
    ctx.fillRect(0, 0, canvas.width, canvas.height);
</script>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Suggested AGENTS.md location in examples/codex/code_modernization.md is not loaded automatically

3 participants