🔬 AI発明ギャラリー o-yuto ポケモンバトルメガ3
🔒 サンドボックス内で実行中 ⛶ 全画面で遊ぶ
HTML / CSS / JS
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Pocket Battle - API Edition</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
    <style>
        @import url('https://fonts.googleapis.com/css2?family=DotGothic16&family=Press+Start+2P&display=swap');
        
        .pixel-font { font-family: 'DotGothic16', sans-serif; }
        .battle-bg {
            background: linear-gradient(to bottom, #87CEEB 0%, #87CEEB 50%, #90EE90 50%, #90EE90 100%);
            background-size: 100% 200%;
            transition: background-position 1s ease;
        }
        .title-float { animation: float 3s ease-in-out infinite; }
        @keyframes float { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-10px); } }
        
        .attack-player { animation: attack-p 0.5s ease-out; }
        @keyframes attack-p { 0% { transform: translateX(0); } 50% { transform: translateX(20px) translateY(-10px); } 100% { transform: translateX(0); } }
        .attack-enemy { animation: attack-e 0.5s ease-out; }
        @keyframes attack-e { 0% { transform: translateX(0); } 50% { transform: translateX(-20px) translateY(10px); } 100% { transform: translateX(0); } }
        
        .loader { border: 4px solid #f3f3f3; border-top: 4px solid #3498db; border-radius: 50%; width: 30px; height: 30px; animation: spin 1s linear infinite; }
        @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
        
        .pixelated { image-rendering: pixelated; }
        .shiny-sparkle { filter: drop-shadow(0 0 5px gold); }
    </style>
</head>
<body class="flex flex-col items-center justify-center min-h-screen p-4 bg-gray-900 text-gray-800">

    <audio id="bgm" loop preload="auto">
        <source src="https://petitacode.web2050.jp/users/original/o-yuto/%E3%81%8D%E3%81%BF%E3%81%AB%E3%81%8D%E3%82%81%E3%81%9F%20(1).mp3" type="audio/mpeg">
    </audio>

    <div id="game-container" class="max-w-lg w-full bg-white rounded-xl shadow-2xl overflow-hidden border-4 border-gray-800 relative min-h-[500px] flex flex-col">
        
        <div id="bgm-controls" class="hidden absolute top-2 right-2 z-50">
            <button onclick="toggleBGM()" id="bgm-btn" class="bg-white/80 hover:bg-white p-2 rounded-full shadow-md text-gray-700 transition-all">
                <i id="bgm-icon" class="fas fa-volume-up"></i>
            </button>
        </div>

        <!-- タイトル画面 -->
        <div id="title-screen" class="flex-grow p-10 flex flex-col items-center justify-center text-center">
            <div class="mb-8 title-float">
                <h1 class="text-4xl font-black text-blue-600 pixel-font tracking-tighter italic">POCKET<br><span class="text-red-500">BATTLE</span></h1>
                <p class="text-xs font-bold text-gray-400 mt-2">API Edition</p>
            </div>
            <div class="w-24 h-24 mb-10 opacity-20">
                <img src="https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/items/poke-ball.png" class="w-full h-full object-contain grayscale">
            </div>
            <button id="start-btn" class="group relative px-8 py-4 bg-red-600 text-white rounded-full font-bold text-xl shadow-[0_4px_0_rgb(153,27,27)] hover:shadow-none hover:translate-y-1 transition-all pixel-font">
                ぼうけんを はじめる
            </button>
        </div>

        <!-- パートナー選択画面 -->
        <div id="starter-selection" class="hidden flex-grow p-4">
            <h2 class="text-xl font-bold mb-4 text-center pixel-font">はじめのパートナーを えらぼう!</h2>
            <div id="selection-loader" class="flex flex-col items-center py-10">
                <div class="loader mb-2"></div>
                <p class="text-xs text-gray-500">よみこみちゅう...</p>
            </div>
            <div id="starter-list" class="grid grid-cols-3 gap-2 overflow-y-auto max-h-[350px] p-2"></div>
        </div>

        <!-- バトル画面 -->
        <div id="battle-area" class="hidden flex-grow flex flex-col">
            <div id="battle-bg" class="battle-bg h-48 relative overflow-hidden border-b-2 border-gray-800">
                <!-- 敵情報 -->
                <div class="absolute top-4 right-8 text-right w-40 bg-white/80 p-1 rounded-lg border border-gray-400">
                    <div id="enemy-name" class="text-[10px] font-bold truncate">---</div>
                    <div class="w-full bg-gray-300 h-2 rounded-full mt-1">
                        <div id="enemy-hp-fill" class="h-full bg-green-500 rounded-full transition-all duration-500" style="width: 100%"></div>
                    </div>
                    <div id="enemy-hp-text" class="text-[8px] text-right font-mono mt-0.5">0 / 0</div>
                </div>
                <img id="enemy-img" src="" class="absolute top-8 right-12 w-24 h-24 object-contain pixelated">

                <!-- プレイヤー情報 -->
                <div class="absolute bottom-4 left-8 w-40 bg-white/80 p-1 rounded-lg border border-gray-400">
                    <div id="player-name" class="text-[10px] font-bold truncate">---</div>
                    <div class="w-full bg-gray-300 h-2 rounded-full mt-1">
                        <div id="player-hp-fill" class="h-full bg-green-500 rounded-full transition-all duration-500" style="width: 100%"></div>
                    </div>
                    <div id="player-hp-text" class="text-[8px] text-right font-mono mt-0.5">0 / 0</div>
                </div>
                <img id="player-img" src="" class="absolute bottom-2 left-12 w-32 h-32 object-contain pixelated z-10">
            </div>

            <!-- メッセージとアクション -->
            <div class="p-3 bg-gray-100 flex-grow border-b-2 border-gray-800">
                <div id="message-text" class="pixel-font text-sm h-12 overflow-hidden leading-tight">ぼうけんが はじまる!</div>
            </div>

            <div id="action-controls" class="grid grid-cols-2 gap-2 p-2 bg-gray-200">
                <div id="move-buttons" class="grid grid-cols-2 gap-1 col-span-2"></div>
                
                <div class="grid grid-cols-2 gap-1 col-span-2 mt-1">
                    <button onclick="toggleBallMenu()" class="bg-orange-500 text-white font-bold py-2 rounded text-[10px] shadow-md border-b-2 border-orange-700 active:border-0 active:translate-y-0.5 transition-all">
                        <i class="fas fa-suitcase mr-1"></i>バッグ
                    </button>
                    <button onclick="healPlayer()" class="bg-green-600 text-white font-bold py-2 rounded text-[10px] shadow-md border-b-2 border-green-800 active:border-0 active:translate-y-0.5 transition-all">
                        <i class="fas fa-heart mr-1"></i>かいふく
                    </button>
                    <button onclick="changeEnemyPokemon()" class="bg-blue-500 text-white font-bold py-2 rounded text-[10px] shadow-md border-b-2 border-blue-700 active:border-0 active:translate-y-0.5 transition-all">
                        <i class="fas fa-search mr-1"></i>別のポケモンをさがす
                    </button>
                    <button onclick="changeEnemyPokemon()" class="bg-gray-500 text-white font-bold py-2 rounded text-[10px] shadow-md border-b-2 border-gray-700 active:border-0 active:translate-y-0.5 transition-all">
                        <i class="fas fa-running mr-1"></i>にげる
                    </button>
                </div>
            </div>

            <!-- ボールメニュー -->
            <div id="ball-selection-menu" class="hidden grid grid-cols-3 gap-2 p-2 bg-gray-300">
                <button onclick="catchWithBall('common')" class="flex flex-col items-center bg-white p-2 rounded border border-gray-400">
                    <img src="https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/items/poke-ball.png" class="w-8 h-8">
                    <span class="text-[8px] font-bold mt-1">モンスター</span>
                </button>
                <button onclick="catchWithBall('great')" class="flex flex-col items-center bg-white p-2 rounded border border-gray-400">
                    <img src="https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/items/great-ball.png" class="w-8 h-8">
                    <span class="text-[8px] font-bold mt-1">スーパー</span>
                </button>
                <button onclick="catchWithBall('ultra')" class="flex flex-col items-center bg-white p-2 rounded border border-gray-400">
                    <img src="https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/items/ultra-ball.png" class="w-8 h-8">
                    <span class="text-[8px] font-bold mt-1">ハイパー</span>
                </button>
                <button onclick="toggleBallMenu()" class="col-span-3 text-[10px] font-bold text-gray-600 py-1 text-center">もどる</button>
            </div>
        </div>

        <!-- フッター -->
        <div id="pokedex-button-container" class="hidden p-2 bg-gray-800 flex justify-between items-center">
            <button onclick="openPokedex()" class="bg-red-500 text-white px-4 py-1 rounded-full text-xs font-bold shadow-lg flex items-center">
                <i class="fas fa-book-open mr-2"></i> ポケモンずかん
            </button>
            <div id="save-status" class="text-[8px] text-gray-400 font-bold"></div>
        </div>

        <div id="main-loader" class="p-8 hidden flex flex-col items-center justify-center flex-grow">
            <div class="loader mb-4"></div>
            <p class="text-gray-600 font-bold">よみこみちゅう...</p>
        </div>
    </div>

    <!-- 所持ポケモン -->
    <div id="collection-area" class="max-w-lg w-full mt-4 p-4 bg-white/10 rounded-xl border-2 border-white/20 hidden">
        <div class="flex justify-between items-center mb-2">
            <h3 class="text-white font-bold text-sm"><i class="fas fa-box-open mr-2"></i> てもちのポケモン</h3>
            <button onclick="manualSave()" class="bg-blue-600 hover:bg-blue-500 text-white text-[9px] px-2 py-0.5 rounded font-bold">セーブ</button>
        </div>
        <div id="collection-list" class="flex flex-wrap gap-2"></div>
    </div>

    <!-- 図鑑モーダル -->
    <div id="pokedex-modal" class="fixed inset-0 bg-black/80 z-[100] hidden flex flex-col items-center justify-center p-4">
        <div class="bg-red-600 w-full max-w-md rounded-2xl border-4 border-gray-900 overflow-hidden flex flex-col max-h-[90vh]">
            <div class="p-4 flex justify-between items-center bg-red-700 border-b-4 border-gray-900">
                <div class="flex items-center gap-3">
                    <div class="w-10 h-10 bg-blue-400 rounded-full border-4 border-white shadow-inner"></div>
                    <h2 class="text-white font-black italic tracking-tighter text-xl">POKEDEX</h2>
                </div>
                <button onclick="closePokedex()" class="text-white text-2xl"><i class="fas fa-times"></i></button>
            </div>
            <div id="pokedex-list" class="flex-grow overflow-y-auto grid grid-cols-4 gap-2 p-4 bg-white"></div>
        </div>
    </div>

    <script type="module">
        import { initializeApp } from "https://www.gstatic.com/firebasejs/11.6.1/firebase-app.js";
        import { getAuth, signInAnonymously, signInWithCustomToken, onAuthStateChanged } from "https://www.gstatic.com/firebasejs/11.6.1/firebase-auth.js";
        import { getFirestore, doc, getDoc, setDoc, onSnapshot } from "https://www.gstatic.com/firebasejs/11.6.1/firebase-firestore.js";

        // 環境変数の安全なチェック
        const safeEnv = (key) => {
            try { return eval(key); } catch (e) { return null; }
        };

        const configRaw = safeEnv('__firebase_config');
        const firebaseConfig = configRaw ? JSON.parse(configRaw) : null;
        const appId = safeEnv('__app_id') || 'pokemon-battle-default';
        const initialToken = safeEnv('__initial_auth_token');

        let app, db, auth;
        if (firebaseConfig) {
            app = initializeApp(firebaseConfig);
            db = getFirestore(app);
            auth = getAuth(app);
        }

        let userId = null;
        let isFirstLoad = true;

        const API_URL = "https://pokeapi.co/api/v2/pokemon/";
        const SHINY_CHANCE = 0.4;
        const LEGENDARY_CHANCE = 0.15;
        const LEGENDARY_IDS = [144, 145, 146, 150, 151, 243, 244, 245, 249, 250, 251, 382, 383, 384, 483, 484, 487, 643, 644, 646, 716, 717, 718, 888, 889, 890];

        window.player = null;
        window.enemy = null;
        window.isProcessing = false;
        window.capturedPokemons = []; 
        window.pokedex = {}; 
        window.hasBgmStarted = false;

        const ballData = { common: { name: "モンスターボール", rate: 1.0 }, great: { name: "スーパーボール", rate: 1.5 }, ultra: { name: "ハイパーボール", rate: 2.5 } };
        const bgm = document.getElementById('bgm');
        let isPlaying = false;

        async function initStarterSelection() {
            const starters = [
                1, 4, 7,          // 第1世代
                152, 155, 158,    // 第2世代
                252, 255, 258,    // 第3世代
                387, 390, 393,    // 第4世代
                722, 725, 728,    // 第7世代
                810, 813, 816,    // 第8世代 (ガラル)
                25, 133, 443      // ピカチュウ, イーブイ, フカマル
            ];
            const starterList = document.getElementById('starter-list');
            if(!starterList) return;
            starterList.innerHTML = '';
            
            for (const id of starters) {
                const pokemon = await fetchPokemon(id);
                if(!pokemon) continue;
                const card = document.createElement('div');
                card.className = `p-2 rounded-lg text-center border-2 cursor-pointer flex flex-col items-center bg-white border-gray-200 hover:border-blue-500`;
                card.onclick = () => {
                    addCollection(pokemon);
                    updatePokedex(pokemon, 'caught');
                    switchActivePokemon(pokemon.id);
                    document.getElementById('starter-selection').classList.add('hidden');
                    showBattleUI();
                    startNewBattle();
                };
                card.innerHTML = `<img src="${pokemon.staticSprite}" class="w-12 h-12 pixelated"><p class="text-[8px] font-bold mt-1">${pokemon.name}</p>`;
                starterList.appendChild(card);
            }
            document.getElementById('selection-loader').classList.add('hidden');
        }

        async function fetchPokemon(idOrName) {
            const isShiny = Math.random() < SHINY_CHANCE;
            try {
                const pokeRes = await fetch(`${API_URL}${idOrName}`);
                const data = await pokeRes.json();
                const speciesRes = await fetch(data.species.url);
                const speciesData = await speciesRes.json();
                const ja = speciesData.names.find(n => n.language.name === 'ja-Hrkt' || n.language.name === 'ja');
                let japaneseName = ja ? ja.name : data.name;
                
                let moves = await Promise.all(data.moves.slice(0, 4).map(async (m) => {
                    const moveRes = await fetch(m.move.url);
                    const moveData = await moveRes.json();
                    const mJa = moveData.names.find(n => n.language.name === 'ja-Hrkt' || n.language.name === 'ja');
                    return { name: mJa ? mJa.name : m.move.name, power: moveData.power || 50 };
                }));

                const sprites = data.sprites.versions['generation-v']?.['black-white']?.animated || data.sprites;
                return {
                    baseId: data.id >= 10000 ? speciesData.id : data.id,
                    id: data.id,
                    name: japaneseName,
                    hp: data.stats[0].base_stat * 2,
                    maxHp: data.stats[0].base_stat * 2,
                    attack: data.stats[1].base_stat,
                    defense: data.stats[2].base_stat,
                    sprite: isShiny ? (sprites.front_shiny || data.sprites.front_shiny) : (sprites.front_default || data.sprites.front_default),
                    backSprite: isShiny ? (sprites.back_shiny || data.sprites.back_shiny) : (sprites.back_default || data.sprites.back_default),
                    staticSprite: isShiny ? data.sprites.front_shiny : data.sprites.front_default,
                    moves: moves,
                    isShiny: isShiny
                };
            } catch(e) { return null; }
        }

        window.startGame = function() {
            startBGM();
            document.getElementById('title-screen').classList.add('hidden');
            if (window.capturedPokemons.length === 0) {
                document.getElementById('starter-selection').classList.remove('hidden');
                initStarterSelection();
            } else {
                showBattleUI();
                startNewBattle();
            }
        };

        window.startNewBattle = async function() {
            if (window.isProcessing) return;
            window.isProcessing = true;
            document.getElementById('main-loader').classList.remove('hidden');
            document.getElementById('battle-area').classList.add('hidden');
            
            // 自分のポケモンがひんし状態なら全回復させる
            if (window.player && window.player.hp <= 0) {
                window.player.hp = window.player.maxHp;
            }
            
            try {
                let randomId = Math.random() < LEGENDARY_CHANCE ? LEGENDARY_IDS[Math.floor(Math.random() * LEGENDARY_IDS.length)] : Math.floor(Math.random() * 800) + 1;
                window.enemy = await fetchPokemon(randomId);
                updatePokedex(window.enemy, 'seen');
                updateUI();
                renderMoves();
                document.getElementById('main-loader').classList.add('hidden');
                document.getElementById('battle-area').classList.remove('hidden');
                updateMessage(`野生の ${window.enemy.name} が とびだしてきた!`);
                window.isProcessing = false;
            } catch (e) { 
                window.isProcessing = false; 
                setTimeout(startNewBattle, 1000); 
            }
        }

        async function handleAttack(move) {
            if (window.isProcessing) return;
            window.isProcessing = true;
            await performMove(window.player, window.enemy, move, 'player');
            if (window.enemy.hp <= 0) {
                updateMessage(`${window.enemy.name} を たおした!`);
                setTimeout(() => {
                    window.isProcessing = false;
                    startNewBattle();
                }, 2000);
                return;
            }
            await enemyTurn();
        }

        async function enemyTurn() {
            await new Promise(r => setTimeout(r, 800));
            const move = window.enemy.moves[Math.floor(Math.random() * window.enemy.moves.length)];
            await performMove(window.enemy, window.player, move, 'enemy');
            
            if (window.player.hp <= 0) {
                updateMessage(`${window.player.name} は たおれてしまった...`);
                setTimeout(() => {
                    updateMessage("近くのポケモンセンターで 回復した!");
                    setTimeout(() => {
                        window.isProcessing = false;
                        startNewBattle();
                    }, 1500);
                }, 2000);
                return;
            }
            window.isProcessing = false;
        }

        async function performMove(attacker, defender, move, role) {
            updateMessage(`${attacker.name} の ${move.name}!`);
            const img = document.getElementById(`${role}-img`);
            img.classList.add(role === 'player' ? 'attack-player' : 'attack-enemy');
            await new Promise(r => setTimeout(r, 500));
            img.classList.remove(role === 'player' ? 'attack-player' : 'attack-enemy');
            
            let damage = (((2 * 50 / 5 + 2) * move.power * (attacker.attack / defender.defense)) / 50) + 2;
            defender.hp = Math.max(0, defender.hp - damage);
            updateHPBar(role === 'player' ? 'enemy' : 'player', defender.hp, defender.maxHp);
        }

        function updateUI() {
            if (!window.player || !window.enemy) return;
            document.getElementById('player-name').innerText = (window.player.isShiny ? '★' : '') + window.player.name;
            document.getElementById('player-img').src = window.player.backSprite || window.player.sprite;
            updateHPBar('player', window.player.hp, window.player.maxHp);
            document.getElementById('enemy-name').innerText = (window.enemy.isShiny ? '★' : '') + window.enemy.name;
            document.getElementById('enemy-img').src = window.enemy.sprite;
            updateHPBar('enemy', window.enemy.hp, window.enemy.maxHp);
        }

        function updateHPBar(who, cur, max) {
            const pct = Math.max(0, (cur / max) * 100);
            document.getElementById(`${who}-hp-fill`).style.width = `${pct}%`;
            document.getElementById(`${who}-hp-text`).innerText = `${Math.ceil(cur)} / ${max}`;
        }

        function updateMessage(text) { document.getElementById('message-text').innerText = text; }

        function renderMoves() {
            const container = document.getElementById('move-buttons');
            container.innerHTML = '';
            window.player.moves.forEach(m => {
                const b = document.createElement('button');
                b.className = `border-2 font-bold py-2 rounded text-[10px] bg-white border-gray-400 active:bg-gray-100`;
                b.innerText = m.name;
                b.onclick = () => handleAttack(m);
                container.appendChild(b);
            });
        }

        window.toggleBallMenu = () => {
            document.getElementById('action-controls').classList.toggle('hidden');
            document.getElementById('ball-selection-menu').classList.toggle('hidden');
        };

        window.catchWithBall = async (type) => {
            toggleBallMenu();
            window.isProcessing = true;
            updateMessage(`${ballData[type].name} を なげた!`);
            await new Promise(r => setTimeout(r, 1000));
            if (Math.random() < (0.4 * ballData[type].rate)) {
                updateMessage(`${window.enemy.name} を つかまえた!`);
                updatePokedex(window.enemy, 'caught');
                addCollection(window.enemy);
                setTimeout(() => {
                    window.isProcessing = false;
                    startNewBattle();
                }, 2000);
            } else { updateMessage("だめだ! もれだしてしまった!"); await enemyTurn(); }
        };

        window.healPlayer = () => {
            if (window.isProcessing) return;
            window.player.hp = Math.min(window.player.maxHp, window.player.hp + 60);
            updateHPBar('player', window.player.hp, window.player.maxHp);
            updateMessage(`${window.player.name} は かいふくした!`);
            enemyTurn();
        };

        window.changeEnemyPokemon = () => window.startNewBattle();

        function addCollection(p) {
            if (!window.capturedPokemons.find(x => x.id === p.id)) {
                window.capturedPokemons.push(p); 
                renderCollection();
                saveToCloud();
            }
        }

        function switchActivePokemon(id) {
            const target = window.capturedPokemons.find(p => p.id === id);
            if (!target) return;
            window.player = JSON.parse(JSON.stringify(target)); 
            updateUI(); renderMoves(); renderCollection();
        }

        function renderCollection() {
            const list = document.getElementById('collection-list');
            list.innerHTML = '';
            window.capturedPokemons.forEach(p => {
                const item = document.createElement('div');
                const isActive = window.player && p.id === window.player.id;
                item.className = `w-10 h-10 bg-white rounded border-2 cursor-pointer flex items-center justify-center ${isActive ? 'border-blue-500' : 'border-gray-300'}`;
                item.innerHTML = `<img src="${p.staticSprite}" class="w-full h-full object-contain pixelated ${p.isShiny ? 'shiny-sparkle' : ''}">`;
                item.onclick = () => !window.isProcessing && switchActivePokemon(p.id);
                list.appendChild(item);
            });
        }

        function updatePokedex(p, status) {
            const id = p.baseId || p.id;
            window.pokedex[id] = { status, name: p.name, sprite: p.staticSprite, id };
            saveToCloud();
        }

        window.openPokedex = () => {
            const m = document.getElementById('pokedex-modal');
            const l = document.getElementById('pokedex-list');
            m.classList.remove('hidden');
            l.innerHTML = '';
            Object.keys(window.pokedex).sort((a,b)=>a-b).forEach(id => {
                const e = window.pokedex[id];
                const c = document.createElement('div');
                c.className = "p-1 border bg-white flex flex-col items-center";
                c.innerHTML = `<img src="${e.sprite}" class="w-8 h-8 pixelated ${e.status === 'seen' ? 'brightness-0' : ''}"><p class="text-[6px]">${e.status === 'caught' ? e.name : '???'}</p>`;
                l.appendChild(c);
            });
        };

        window.closePokedex = () => document.getElementById('pokedex-modal').classList.add('hidden');

        function startBGM() {
            if (!window.hasBgmStarted) {
                bgm.play().then(() => {
                    isPlaying = true;
                    window.hasBgmStarted = true;
                    document.getElementById('bgm-controls').classList.remove('hidden');
                }).catch(() => {});
            }
        }

        window.toggleBGM = () => {
            const icon = document.getElementById('bgm-icon');
            if (isPlaying) { bgm.pause(); icon.className = 'fas fa-volume-mute'; }
            else { bgm.play().catch(() => {}); icon.className = 'fas fa-volume-up'; }
            isPlaying = !isPlaying;
        };

        async function saveToCloud() {
            if (!userId || !db) return;
            try {
                const userDoc = doc(db, 'artifacts', appId, 'users', userId, 'gameData', 'saveSlot');
                await setDoc(userDoc, { capturedPokemons: window.capturedPokemons, pokedex: window.pokedex });
            } catch (e) {}
        }

        function syncData() {
            if (!userId || !db) return;
            const userDoc = doc(db, 'artifacts', appId, 'users', userId, 'gameData', 'saveSlot');
            onSnapshot(userDoc, (docSnap) => {
                if (docSnap.exists() && isFirstLoad) {
                    const d = docSnap.data();
                    window.pokedex = d.pokedex || {};
                    window.capturedPokemons = d.capturedPokemons || [];
                    if (window.capturedPokemons.length > 0) switchActivePokemon(window.capturedPokemons[0].id);
                    isFirstLoad = false;
                }
            });
        }

        window.manualSave = () => saveToCloud();

        function showBattleUI() {
            document.getElementById('collection-area').classList.remove('hidden');
            document.getElementById('pokedex-button-container').classList.remove('hidden');
            document.getElementById('battle-area').classList.remove('hidden');
        }

        window.onload = () => {
            const startBtn = document.getElementById('start-btn');
            if (startBtn) startBtn.onclick = window.startGame;
            if (auth) {
                onAuthStateChanged(auth, (user) => {
                    if (user) { userId = user.uid; syncData(); }
                });
                if (initialToken) signInWithCustomToken(auth, initialToken).catch(()=>signInAnonymously(auth));
                else signInAnonymously(auth);
            }
        };
    </script>
</body>
</html>
✨ ピックアップ

ポケモンバトルメガ3

by o-yuto

ポケモンバトルゲーム

🤖 使用したAI
Gemini
👁 40 回閲覧
📅 投稿:2026年5月16日 🔄 更新:2026年8月12日
応援スタンプを押してみよう!