Preparing the incubator...
Hatch Eggs!
Evolution Line
${pokemon.evolution}
Hatch Steps
~${pokemon.hatchSteps} steps
`;
return card;
};
// --- CORE LOGIC ---
const hatchSingleEgg = async () => {
const randomSpeciesRef = allPokemonSpecies[Math.floor(Math.random() * allPokemonSpecies.length)];
const speciesData = await fetchJson(randomSpeciesRef.url);
if (!speciesData || speciesData.is_legendary || speciesData.is_mythical || speciesData.hatch_counter === -1) {
console.log(`Skipping non-hatchable Pokémon: ${randomSpeciesRef.name}. Retrying...`);
return hatchSingleEgg();
}
const pokemonData = await fetchJson(`${API_BASE_URL}pokemon/${speciesData.name}`);
if (!pokemonData) throw new Error(`Failed to fetch pokemon data for ${speciesData.name}`);
const evolution = await parseEvolutionChain(speciesData.evolution_chain.url);
const flavorText = getFlavorText(speciesData);
const isShiny = Math.random() < SHINY_CHANCE;
const sprite = isShiny ? pokemonData.sprites.front_shiny : pokemonData.sprites.front_default;
return {
name: capitalize(pokemonData.name),
sprite: sprite || pokemonData.sprites.front_default,
isShiny: isShiny,
types: pokemonData.types,
flavorText: flavorText,
evolution: evolution,
hatchSteps: (speciesData.hatch_counter + 1) * 255,
};
};
const startHatchingSequence = async () => {
if (hatchBtn.disabled) return;
// NEW: Ensure audio is ready on the first click
setupAudio();
hatchBtn.disabled = true;
hatchBtn.textContent = 'Hatching...';
resultsContainer.innerHTML = '';
const count = parseInt(eggCountInput.value, 10);
if (isNaN(count) || count < 1 || count > 12) {
const tempAlert = document.createElement('div');
tempAlert.textContent = 'Please enter a number between 1 and 12.';
tempAlert.style.color = 'red';
tempAlert.style.textAlign = 'center';
tempAlert.style.marginBottom = '1rem';
resultsContainer.appendChild(tempAlert);
hatchBtn.disabled = false;
hatchBtn.textContent = 'Hatch Eggs!';
return;
}
const eggElements = Array.from({ length: count }, () => {
const eggEl = createEggElement();
resultsContainer.appendChild(eggEl);
return eggEl;
});
const hatchPromises = Array.from({ length: count }, hatchSingleEgg);
const hatchedResults = await Promise.allSettled(hatchPromises);
for (let i = 0; i < eggElements.length; i++) {
const eggContainer = eggElements[i];
const egg = eggContainer.querySelector('.peg-egg');
const result = hatchedResults[i];
egg.classList.add('is-hatching');
await new Promise(res => setTimeout(res, 1500));
egg.classList.remove('is-hatching');
egg.classList.add('is-cracking');
// NEW: Play sound effect here
playHatchSound();
await new Promise(res => setTimeout(res, 500));
if (result.status === 'fulfilled' && result.value) {
const pokemonCard = createPokemonCard(result.value);
eggContainer.replaceWith(pokemonCard);
} else {
eggContainer.innerHTML = `A problem occurred while hatching this egg. Please try again.
`;
console.error("Hatching failed for one egg:", result.reason);
}
}
hatchBtn.disabled = false;
hatchBtn.textContent = 'Hatch Eggs!';
};
const initialize = async () => {
const allSpeciesData = await fetchJson(`${API_BASE_URL}pokemon-species?limit=2000`);
if (!allSpeciesData || !allSpeciesData.results) {
loader.querySelector('.peg-loader-text').textContent = "Error: Could not connect to the PokéAPI. Please refresh and try again.";
return;
}
allPokemonSpecies = allSpeciesData.results.filter(s => {
if(s.name.includes('-') && !s.name.startsWith('porygon')) return false;
const id = parseInt(s.url.split('/').filter(Boolean).pop(), 10);
return id < 10000;
});
isInitialized = true;
loader.classList.remove('peg-active');
controls.style.display = 'flex';
hatchBtn.addEventListener('click', startHatchingSequence);
};
initialize();
})();