/** * Gamemaster Utilities * Functions for fetching and processing PokeMiners gamemaster data */ const POKEMINERS_GAMEMASTER_URL = 'https://raw.githubusercontent.com/PokeMiners/game_masters/master/latest/latest.json'; /** * Fetch latest gamemaster data from PokeMiners GitHub * @returns {Promise} Gamemaster data array */ export async function fetchLatestGamemaster() { try { const response = await fetch(POKEMINERS_GAMEMASTER_URL); if (!response.ok) { throw new Error(`Failed to fetch gamemaster: ${response.statusText}`); } return await response.json(); } catch (error) { console.error('Error fetching gamemaster:', error); throw error; } } /** * Break up gamemaster into separate categories * @param {Array} gamemaster - Full gamemaster data * @returns {Object} Separated data {pokemon, pokemonAllForms, moves} */ export function breakUpGamemaster(gamemaster) { const regionCheck = ['alola', 'galarian', 'hisuian', 'paldea']; const result = gamemaster.reduce( (acc, item) => { const templateId = item.templateId; // POKEMON FILTER // If the templateId begins with 'V' AND includes 'pokemon' if ( templateId.startsWith('V') && templateId.toLowerCase().includes('pokemon') ) { const pokemonSettings = item.data?.pokemonSettings; const pokemonId = pokemonSettings?.pokemonId; // Add to allFormsCostumes (includes everything) acc.pokemonAllForms.push(item); // Add to pokemon (filtered - first occurrence OR regional forms) // Check if this is a regional form by looking at the form string const form = pokemonSettings?.form; const isRegionalForm = form && typeof form === 'string' ? regionCheck.includes(form.split('_')[1]?.toLowerCase()) : false; if ( !acc.pokemonSeen.has(pokemonId) || (acc.pokemonSeen.has(pokemonId) && isRegionalForm) ) { acc.pokemonSeen.add(pokemonId); acc.pokemon.push(item); } } // POKEMON MOVE FILTER if ( templateId.startsWith('V') && templateId.toLowerCase().includes('move') ) { const moveSettings = item.data?.moveSettings; const moveId = moveSettings?.movementId; if (!acc.moveSeen.has(moveId)) { acc.moveSeen.add(moveId); acc.moves.push(item); } } return acc; }, { pokemon: [], pokemonAllForms: [], moves: [], pokemonSeen: new Set(), moveSeen: new Set() } ); // Clean up the Sets before returning delete result.pokemonSeen; delete result.moveSeen; return result; } /** * Download JSON data as a file * @param {Object|Array} data - Data to download * @param {string} filename - Filename for download */ export function downloadJson(data, filename) { const json = JSON.stringify(data, null, 2); const blob = new Blob([json], { type: 'application/json' }); const url = URL.createObjectURL(blob); const link = document.createElement('a'); link.href = url; link.download = filename; document.body.appendChild(link); link.click(); document.body.removeChild(link); URL.revokeObjectURL(url); } /** * Calculate file size in MB * @param {Object|Array} data - Data to measure * @returns {string} Size in MB formatted */ export function calculateFileSize(data) { const json = JSON.stringify(data); const bytes = new Blob([json]).size; const mb = bytes / (1024 * 1024); return `${mb.toFixed(2)} MB`; } /** * Get statistics about gamemaster data * @param {Object} brokenUpData - Result from breakUpGamemaster * @returns {Object} Statistics */ export function getGamemasterStats(brokenUpData) { return { pokemonCount: brokenUpData.pokemon.length, allFormsCount: brokenUpData.pokemonAllForms.length, movesCount: brokenUpData.moves.length, pokemonSize: calculateFileSize(brokenUpData.pokemon), allFormsSize: calculateFileSize(brokenUpData.pokemonAllForms), movesSize: calculateFileSize(brokenUpData.moves) }; }