import { getNurseryBuildCost, getSouvenirShopBuildCost, getResearchBuildCost, getBilleterieBuildCost, getFoodBuildCost, getReceptionBuildCost, getBiomeChangeColorBuildCost, getBiomeChangeTempBuildCost, getSchoolUpgradeCost, getReceptionUpgradeCost, getNurseryUpgradeCost, getSouvenirShopUpgradeCost, getResearchUpgradeCost, getBilleterieUpgradeCost, getFoodUpgradeCost, getBiomeChangeColorUpgradeCost, getBiomeChangeTempUpgradeCost, } from "./economy.js"; import { getAnimalVisualState } from "./animal-visual-state.js"; import { GameConfig } from "./config.js"; import { eggTypeLabel, animalLabel } from "./texts-fr.js"; const EGG_EMOJI = "🥚"; /** * @param {{ state: import("./types.js").GameState, setState: () => void, setError: (s: string) => void, playSound: (s: string) => void, gridEl: HTMLElement, getHatched: () => Array<{ x: number, y: number }>, selected: { x: number, y: number }, emptyCellChoice: { x: number, y: number } | null, selectedTokenId: number | null, lastActionWasDrop: boolean, clampSelection: () => void, animalEmoji: Record }} ctx * @param {HTMLElement} divEl * @param {import("./types.js").ReceptionCell} receptionCell * @param {string} cellKey */ export function fillReceptionCell(ctx, divEl, receptionCell, cellKey) { const { state, animalEmoji } = ctx; divEl.classList.add("reception"); const level = receptionCell.level ?? 1; const maxLevel = GameConfig.Reception?.MaxLevel ?? 7; const canUpgrade = level < maxLevel && state.coins >= getReceptionUpgradeCost(level); if (canUpgrade) divEl.classList.add("can-upgrade"); const recAnimal = (state.receptionAnimals ?? []).find((r) => r.receptionCellKey === cellKey); const nowUnix = Math.floor(Date.now() / 1000); if (recAnimal) { const isReady = nowUnix >= recAnimal.readyAt; const emoji = animalEmoji[recAnimal.animalId] ?? "🐾"; const label = isReady ? "Animal prêt" : "Acclimatation…"; divEl.classList.add("cell-draggable"); divEl.draggable = isReady; const arrow = canUpgrade ? '' : ""; divEl.innerHTML = `${emoji}${label}${arrow}`; if (isReady) divEl.dataset.receptionCellKey = cellKey; } else { const arrow = canUpgrade ? '' : ""; divEl.innerHTML = `📥Accueil ${level}${arrow}`; } } /** * @param {{ state: import("./types.js").GameState, animalEmoji: Record }} ctx * @param {HTMLElement} divEl * @param {import("./types.js").NurseryCell} nurseryCell * @param {string} cellKey */ export function fillNurseryCell(ctx, divEl, nurseryCell, cellKey) { const { state, animalEmoji } = ctx; divEl.classList.add("nursery"); const nurseryLevel = nurseryCell.level ?? 1; const nurseryMax = GameConfig.Nursery?.MaxLevel ?? 7; const canUpgradeNursery = nurseryLevel < nurseryMax && state.coins >= getNurseryUpgradeCost(nurseryLevel); if (canUpgradeNursery) divEl.classList.add("can-upgrade"); const pendingBaby = (state.pendingBabies ?? []).find((p) => p.nurseryCellKey === cellKey); const token = nurseryCell.tokenId !== null && nurseryCell.tokenId !== undefined ? state.pendingEggTokens.find((tok) => tok.tokenId === nurseryCell.tokenId) : null; if (pendingBaby) { const nowUnix = Math.floor(Date.now() / 1000); const isMature = nowUnix >= pendingBaby.readyAt; const emoji = animalEmoji[pendingBaby.animalId] ?? "🐾"; const label = isMature ? "Bébé prêt" : "Bébé…"; divEl.classList.add("cell-draggable"); divEl.draggable = isMature; divEl.innerHTML = `${emoji}${label}`; if (isMature) divEl.dataset.nurseryCellKey = cellKey; } else if (token) { divEl.classList.add("cell-draggable"); divEl.draggable = true; const label = eggTypeLabel[token.eggType] ?? token.eggType; divEl.innerHTML = `${EGG_EMOJI}${label}`; divEl.dataset.tokenId = String(nurseryCell.tokenId); } else { const arrow = canUpgradeNursery ? '' : ""; divEl.innerHTML = `🐣Nurserie ${nurseryLevel}${arrow}`; } } /** * @param {{ state: import("./types.js").GameState, animalEmoji: Record }} ctx * @param {HTMLElement} divEl * @param {import("./types.js").AnimalCell} animalCell * @param {string} cellKey */ export function fillAnimalCell(ctx, divEl, animalCell, cellKey) { const { state, animalEmoji } = ctx; divEl.classList.add("animal", "cell-draggable"); divEl.draggable = true; const w = animalCell.cellsWide ?? 1; const h = animalCell.cellsHigh ?? 1; const isMulti = w > 1 || h > 1; const isOrigin = animalCell.originKey === null || animalCell.originKey === undefined || animalCell.originKey === cellKey; const originKey = isOrigin ? cellKey : (animalCell.originKey ?? cellKey); const originCell = isOrigin ? animalCell : state.grid.cells[originKey]; if (originCell && originCell.kind === "animal") { const visual = getAnimalVisualState(originCell, state, state.grid, originKey); if (visual.cold) divEl.classList.add("animal-cold"); if (visual.hot) divEl.classList.add("animal-hot"); if (visual.hungry) divEl.classList.add("animal-hungry"); if (visual.sick) divEl.classList.add("animal-sick"); if (visual.happy) divEl.classList.add("animal-happy"); } if (isMulti) divEl.classList.add("multi-cell"); if (isMulti && isOrigin) divEl.classList.add("multi-cell-origin"); const emoji = animalEmoji[animalCell.id] ?? "🐾"; const label = animalLabel[animalCell.id] ?? animalCell.id; divEl.innerHTML = `${emoji}${label}`; } /** * @param {{ state: import("./types.js").GameState }} ctx * @param {HTMLElement} div * @param {number} x * @param {number} y */ export function fillEmptyCell(ctx, div, x, y) { const { state } = ctx; const emptyCellChoice = ctx.emptyCellChoice.current; div.classList.add("empty"); if (emptyCellChoice && emptyCellChoice.x === x && emptyCellChoice.y === y) { const nurseryCost = getNurseryBuildCost(); const shopCost = getSouvenirShopBuildCost(); const researchCost = getResearchBuildCost(); const billeterieCost = getBilleterieBuildCost(); const foodCost = getFoodBuildCost(); const receptionCost = getReceptionBuildCost(); const biomeColorCost = getBiomeChangeColorBuildCost(); const biomeTempCost = getBiomeChangeTempBuildCost(); const canNursery = state.coins >= nurseryCost; const canShop = state.coins >= shopCost; const canResearch = state.coins >= researchCost; const canBilleterie = state.coins >= billeterieCost; const canFood = state.coins >= foodCost; const canReception = state.coins >= receptionCost; const canBiomeColor = state.coins >= biomeColorCost; const canBiomeTemp = state.coins >= biomeTempCost; div.innerHTML = ``; div.classList.add("empty-choice"); } else { div.textContent = ""; } } function fillSchoolCell(ctx, div, cell) { const { state } = ctx; div.classList.add("school"); const schoolMaxLevel = (GameConfig.School && GameConfig.School.MaxLevel) || 8; const canUpgradeSchool = cell.level < schoolMaxLevel && state.coins >= getSchoolUpgradeCost(cell.level); if (canUpgradeSchool) div.classList.add("can-upgrade"); const arrow = canUpgradeSchool ? '' : ""; div.innerHTML = `🏫École ${cell.level}${arrow}`; } function fillSouvenirShopCell(ctx, div, cell) { const { state } = ctx; div.classList.add("souvenir-shop"); const shopLevel = cell.level ?? 1; const shopMax = GameConfig.SouvenirShop?.MaxLevel ?? 7; const canUpgradeShop = shopLevel < shopMax && state.coins >= getSouvenirShopUpgradeCost(shopLevel); if (canUpgradeShop) div.classList.add("can-upgrade"); const arrow = canUpgradeShop ? '' : ""; div.innerHTML = `🛒Boutique ${shopLevel}${arrow}`; } function fillResearchCell(ctx, div, cell) { const { state } = ctx; div.classList.add("research"); const level = cell.level ?? 1; const maxLevel = GameConfig.Research?.MaxLevel ?? 7; const canUpgrade = level < maxLevel && state.coins >= getResearchUpgradeCost(level); if (canUpgrade) div.classList.add("can-upgrade"); const arrow = canUpgrade ? '' : ""; div.innerHTML = `🔬Recherche ${level}${arrow}`; } function fillBilleterieCell(ctx, div, cell) { const { state } = ctx; div.classList.add("billeterie"); const level = cell.level ?? 1; const maxLevel = GameConfig.Billeterie?.MaxLevel ?? 7; const canUpgrade = level < maxLevel && state.coins >= getBilleterieUpgradeCost(level); if (canUpgrade) div.classList.add("can-upgrade"); const arrow = canUpgrade ? '' : ""; div.innerHTML = `🎫Billeterie ${level}${arrow}`; } function fillFoodCell(ctx, div, cell) { const { state } = ctx; div.classList.add("food"); const level = cell.level ?? 1; const maxLevel = GameConfig.Food?.MaxLevel ?? 7; const canUpgrade = level < maxLevel && state.coins >= getFoodUpgradeCost(level); if (canUpgrade) div.classList.add("can-upgrade"); const arrow = canUpgrade ? '' : ""; div.innerHTML = `🥗Nourriture ${level}${arrow}`; } function fillBiomeChangeColorCell(ctx, div, cell) { const { state } = ctx; div.classList.add("biome-change-color"); const level = cell.level ?? 1; const maxLevel = GameConfig.BiomeChangeColor?.MaxLevel ?? 7; const canUpgrade = level < maxLevel && state.coins >= getBiomeChangeColorUpgradeCost(level); if (canUpgrade) div.classList.add("can-upgrade"); const arrow = canUpgrade ? '' : ""; div.innerHTML = `🎨Couleur ${level}${arrow}`; } function fillBiomeChangeTempCell(ctx, div, cell) { const { state } = ctx; div.classList.add("biome-change-temp"); const level = cell.level ?? 1; const maxLevel = GameConfig.BiomeChangeTemp?.MaxLevel ?? 7; const canUpgrade = level < maxLevel && state.coins >= getBiomeChangeTempUpgradeCost(level); if (canUpgrade) div.classList.add("can-upgrade"); const arrow = canUpgrade ? '' : ""; div.innerHTML = `🌡️Temp ${level}${arrow}`; } function fillEggCell(ctx, div, cell) { div.classList.add("egg", "cell-draggable"); div.draggable = true; const label = eggTypeLabel[cell.eggType] ?? cell.eggType; div.innerHTML = `${EGG_EMOJI}${label}`; } /** * @param {{ state: import("./types.js").GameState, setState: () => void, setError: (s: string) => void, playSound: (s: string) => void, gridEl: HTMLElement, getHatched: () => Array<{ x: number, y: number }>, selected: { x: number, y: number }, emptyCellChoice: { current: { x: number, y: number } | null }, selectedTokenId: { current: number | null }, lastActionWasDrop: { current: boolean }, clampSelection: () => void, animalEmoji: Record }} ctx * @param {HTMLElement} div * @param {{ cell: import("./types.js").GridCell | null | undefined, key: string, x: number, y: number }} cellInfo */ export function fillCellContent(ctx, div, cellInfo) { const { cell, key, x, y } = cellInfo; if (cell === null || cell === undefined) { fillEmptyCell(ctx, div, x, y); return; } const filler = FILL_BY_KIND[cell.kind]; if (filler) { filler(ctx, div, cell, key); return; } fillAnimalCell(ctx, div, cell, key); } const FILL_BY_KIND = { school: (ctx, div, cell) => fillSchoolCell(ctx, div, cell), nursery: (ctx, div, cell, key) => fillNurseryCell(ctx, div, cell, key), souvenirShop: (ctx, div, cell) => fillSouvenirShopCell(ctx, div, cell), research: (ctx, div, cell) => fillResearchCell(ctx, div, cell), billeterie: (ctx, div, cell) => fillBilleterieCell(ctx, div, cell), food: (ctx, div, cell) => fillFoodCell(ctx, div, cell), reception: (ctx, div, cell, key) => fillReceptionCell(ctx, div, cell, key), biomeChangeColor: (ctx, div, cell) => fillBiomeChangeColorCell(ctx, div, cell), biomeChangeTemp: (ctx, div, cell) => fillBiomeChangeTempCell(ctx, div, cell), egg: (ctx, div, cell) => fillEggCell(ctx, div, cell), }; export { EGG_EMOJI };