Lint: fix errors and remove unused variables
**Motivations:** - Ensure lint config is not degraded and fix all lint errors for pousse workflow. **Root causes:** - Unused variables kept with _ prefix instead of removed (_row, _questReward, _i). - getAnimalBlockOrigin had 5 parameters (max 4). - use of continue statement (no-continue rule). **Correctifs:** - ESLint config verified; no eslint-disable in codebase. - Removed unused variable _row (biome-rules); removed dead function _questReward (quests); removed unused map param _i (state.js). - getAnimalBlockOrigin refactored to 4 params (pos object instead of x, y). - Replaced continue with if (cell) block in normalizeLoadedCells (state.js). - JSDoc param names aligned with _height, _y (biome-rules). **Evolutions:** - (none) **Pages affectées:** - web/js/biome-rules.js - web/js/quests.js - web/js/state.js - web/js/placement.js
This commit is contained in:
257
web/js/ui-grid-handlers.js
Normal file
257
web/js/ui-grid-handlers.js
Normal file
@@ -0,0 +1,257 @@
|
||||
import { tryPlaceEgg, getNurseryCellKeysOrdered } from "./zoo.js";
|
||||
import { tryUpgradeSchool } from "./conveyor.js";
|
||||
import {
|
||||
tryBuildNursery,
|
||||
tryBuildSouvenirShop,
|
||||
tryBuildResearch,
|
||||
tryBuildBilleterie,
|
||||
tryBuildFood,
|
||||
tryBuildReception,
|
||||
tryBuildBiomeChangeColor,
|
||||
tryBuildBiomeChangeTemp,
|
||||
tryUpgradeNursery,
|
||||
tryUpgradeSouvenirShop,
|
||||
tryUpgradeResearch,
|
||||
tryUpgradeBilleterie,
|
||||
tryUpgradeFood,
|
||||
tryUpgradeReception,
|
||||
tryUpgradeBiomeChangeColor,
|
||||
tryUpgradeBiomeChangeTemp,
|
||||
} from "./placement.js";
|
||||
import { t, errorMessage } from "./texts-fr.js";
|
||||
import { attachDragListeners, handleCellDropNurseryReceptionToken, handleCellDropEggTypeOrMove } from "./ui-grid-drag.js";
|
||||
|
||||
const BUILD_FNS = [
|
||||
["nursery", tryBuildNursery],
|
||||
["shop", tryBuildSouvenirShop],
|
||||
["research", tryBuildResearch],
|
||||
["billeterie", tryBuildBilleterie],
|
||||
["food", tryBuildFood],
|
||||
["reception", tryBuildReception],
|
||||
["biomeColor", tryBuildBiomeChangeColor],
|
||||
["biomeTemp", tryBuildBiomeChangeTemp],
|
||||
];
|
||||
|
||||
/**
|
||||
* @param {{ state: import("./types.js").GameState, setState: () => void, setError: (s: string) => void, playSound: (s: string) => void, emptyCellChoice: { x: number, y: number } | null, selectedTokenId: number | null, lastActionWasDrop: boolean, clampSelection: () => void, selected: { x: number, y: number } }} ctx
|
||||
* @param {string} choice
|
||||
* @param {number} x
|
||||
* @param {number} y
|
||||
*/
|
||||
export function handleCellClickChoice(ctx, choice, x, y) {
|
||||
const { state, setError } = ctx;
|
||||
for (const [name, fn] of BUILD_FNS) {
|
||||
if (choice === name) {
|
||||
const [ok, reason] = fn(state, x, y);
|
||||
if (!ok) setError(String(t.errorPrefix).replace("%s", errorMessage[reason] ?? reason));
|
||||
else setError("");
|
||||
ctx.emptyCellChoice.current = null;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {{ state: import("./types.js").GameState, setState: () => void, setError: (s: string) => void, playSound: (s: string) => void }} ctx
|
||||
* @param {import("./types.js").GridCell} cell
|
||||
* @param {number} x
|
||||
* @param {number} y
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function handleCellClickUpgradeShops(ctx, cell, x, y) {
|
||||
const { state, setState, setError, playSound } = ctx;
|
||||
if (cell.kind === "souvenirShop") {
|
||||
const [ok, reason] = tryUpgradeSouvenirShop(state, x, y);
|
||||
if (ok) { setError(""); playSound("upgrade"); } else if (reason !== "SouvenirShopMaxLevel") { setError(String(t.upgradeConveyorFailed).replace("%s", errorMessage[reason] ?? reason)); playSound("error"); }
|
||||
setState();
|
||||
return true;
|
||||
}
|
||||
if (cell.kind === "research") {
|
||||
const [ok, reason] = tryUpgradeResearch(state, x, y);
|
||||
if (ok) { setError(""); playSound("upgrade"); } else if (reason !== "ResearchMaxLevel") { setError(String(t.upgradeConveyorFailed).replace("%s", errorMessage[reason] ?? reason)); playSound("error"); }
|
||||
setState();
|
||||
return true;
|
||||
}
|
||||
if (cell.kind === "billeterie") {
|
||||
const [ok, reason] = tryUpgradeBilleterie(state, x, y);
|
||||
if (ok) { setError(""); playSound("upgrade"); } else if (reason !== "BilleterieMaxLevel") { setError(String(t.upgradeConveyorFailed).replace("%s", errorMessage[reason] ?? reason)); playSound("error"); }
|
||||
setState();
|
||||
return true;
|
||||
}
|
||||
if (cell.kind === "food") {
|
||||
const [ok, reason] = tryUpgradeFood(state, x, y);
|
||||
if (ok) { setError(""); playSound("upgrade"); } else if (reason !== "FoodMaxLevel") { setError(String(t.upgradeConveyorFailed).replace("%s", errorMessage[reason] ?? reason)); playSound("error"); }
|
||||
setState();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {{ state: import("./types.js").GameState, setState: () => void, setError: (s: string) => void, playSound: (s: string) => void }} ctx
|
||||
* @param {import("./types.js").GridCell} cell
|
||||
* @param {{ x: number, y: number, key: string }} pos
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function handleCellClickUpgradeRest(ctx, cell, pos) {
|
||||
const { x, y, key } = pos;
|
||||
const { state, setState, setError, playSound } = ctx;
|
||||
if (cell.kind === "reception") {
|
||||
const hasAnimal = (state.receptionAnimals ?? []).some((r) => r.receptionCellKey === key);
|
||||
if (!hasAnimal) {
|
||||
const [ok, reason] = tryUpgradeReception(state, x, y);
|
||||
if (ok) { setError(""); playSound("upgrade"); } else if (reason !== "ReceptionMaxLevel") { setError(String(t.upgradeConveyorFailed).replace("%s", errorMessage[reason] ?? reason)); playSound("error"); }
|
||||
}
|
||||
setState();
|
||||
return true;
|
||||
}
|
||||
if (cell.kind === "biomeChangeColor") {
|
||||
const [ok, reason] = tryUpgradeBiomeChangeColor(state, x, y);
|
||||
if (ok) { setError(""); playSound("upgrade"); } else if (reason !== "BiomeChangeColorMaxLevel") { setError(String(t.upgradeConveyorFailed).replace("%s", errorMessage[reason] ?? reason)); playSound("error"); }
|
||||
setState();
|
||||
return true;
|
||||
}
|
||||
if (cell.kind === "biomeChangeTemp") {
|
||||
const [ok, reason] = tryUpgradeBiomeChangeTemp(state, x, y);
|
||||
if (ok) { setError(""); playSound("upgrade"); } else if (reason !== "BiomeChangeTempMaxLevel") { setError(String(t.upgradeConveyorFailed).replace("%s", errorMessage[reason] ?? reason)); playSound("error"); }
|
||||
setState();
|
||||
return true;
|
||||
}
|
||||
if (cell.kind === "school") {
|
||||
const [ok, reason] = tryUpgradeSchool(state, x, y);
|
||||
if (!ok) { setError(String(t.upgradeConveyorFailed).replace("%s", errorMessage[reason] ?? reason)); playSound("error"); } else { setError(""); playSound("schoolUpgrade"); }
|
||||
setState();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {{ state: import("./types.js").GameState, setState: () => void, setError: (s: string) => void, playSound: (s: string) => void, selectedTokenId: number | null, emptyCellChoice: { x: number, y: number } | null }} ctx
|
||||
* @param {boolean} empty
|
||||
* @param {number} x
|
||||
* @param {number} y
|
||||
*/
|
||||
export function handleCellClickPlaceOrSelect(ctx, empty, x, y) {
|
||||
const { state, setState, setError, playSound } = ctx;
|
||||
const nurseryKeys = getNurseryCellKeysOrdered(state);
|
||||
let firstTokenId = null;
|
||||
for (const k of nurseryKeys) {
|
||||
const c = state.grid.cells[k];
|
||||
if (c && c.kind === "nursery" && c.tokenId !== null && c.tokenId !== undefined) {
|
||||
firstTokenId = c.tokenId;
|
||||
break;
|
||||
}
|
||||
}
|
||||
const tokenId = ctx.selectedTokenId.current ?? firstTokenId;
|
||||
if (empty && tokenId !== null && tokenId !== undefined) {
|
||||
const nowUnix = Math.floor(Date.now() / 1000);
|
||||
const [ok, reason] = tryPlaceEgg(state, { tokenId, x, y, nowUnix });
|
||||
if (ok) { ctx.selectedTokenId.current = null; setError(""); playSound("place"); } else { setError(String(t.errorPrefix).replace("%s", errorMessage[reason] ?? reason)); playSound("error"); }
|
||||
setState();
|
||||
return;
|
||||
}
|
||||
if (empty) ctx.emptyCellChoice.current = { x, y };
|
||||
setState();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {{ state: import("./types.js").GameState, setState: () => void, setError: (s: string) => void, playSound: (s: string) => void, gridEl: HTMLElement }} ctx
|
||||
* @param {{ div: HTMLElement, cell: import("./types.js").GridCell | null | undefined, x: number, y: number, key: string }} opts
|
||||
*/
|
||||
export function attachCellListeners(ctx, opts) {
|
||||
const { div, cell, x, y, key } = opts;
|
||||
attachDragListeners(ctx, opts);
|
||||
div.addEventListener("dragover", (e) => {
|
||||
e.preventDefault();
|
||||
const hasEggType = e.dataTransfer.types.includes("application/x-builazoo-eggtype");
|
||||
const hasTokenId = e.dataTransfer.types.includes("application/x-builazoo-tokenid");
|
||||
const hasNurseryKey = e.dataTransfer.types.includes("application/x-builazoo-nursery-cell-key");
|
||||
const hasReceptionKey = e.dataTransfer.types.includes("application/x-builazoo-reception-cell-key");
|
||||
e.dataTransfer.dropEffect = hasEggType || hasTokenId ? "copy" : "move";
|
||||
if ((cell === null || cell === undefined) && (hasEggType || hasTokenId || hasNurseryKey || hasReceptionKey)) {
|
||||
div.classList.add("dragover");
|
||||
}
|
||||
});
|
||||
div.addEventListener("dragleave", () => div.classList.remove("dragover"));
|
||||
div.addEventListener("drop", (e) => {
|
||||
e.preventDefault();
|
||||
div.classList.remove("dragover");
|
||||
handleCellDrop(ctx, e, { toX: Number(div.dataset.x), toY: Number(div.dataset.y), cell });
|
||||
});
|
||||
div.addEventListener("click", (e) => handleCellClick(ctx, { e, cell, x, y, key }));
|
||||
div.addEventListener("keydown", (e) => {
|
||||
if (e.key === "Enter" || e.key === " ") { e.preventDefault(); div.click(); }
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {{ state: import("./types.js").GameState, setState: () => void, setError: (s: string) => void, playSound: (s: string) => void, gridEl: HTMLElement }} ctx
|
||||
* @param {DragEvent} e
|
||||
* @param {{ toX: number, toY: number, cell: import("./types.js").GridCell | null | undefined }} target
|
||||
*/
|
||||
function handleCellDrop(ctx, e, target) {
|
||||
const { toX, toY, cell } = target;
|
||||
const empty = cell === null || cell === undefined;
|
||||
if (handleCellDropNurseryReceptionToken(ctx, e, { x: toX, y: toY, empty })) return;
|
||||
handleCellDropEggTypeOrMove(ctx, e, { x: toX, y: toY, empty });
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {{ state: import("./types.js").GameState, setState: () => void, setError: (s: string) => void, playSound: (s: string) => void, emptyCellChoice: { x: number, y: number } | null, selectedTokenId: number | null, lastActionWasDrop: boolean, clampSelection: () => void, selected: { x: number, y: number } }} ctx
|
||||
* @param {{ e: Event, cell: import("./types.js").GridCell | null | undefined, x: number, y: number, key: string }} opts
|
||||
*/
|
||||
function handleCellClick(ctx, opts) {
|
||||
const { e, cell, x, y, key } = opts;
|
||||
const { state, setState, setError, playSound } = ctx;
|
||||
if (ctx.lastActionWasDrop.current) {
|
||||
ctx.lastActionWasDrop.current = false;
|
||||
return;
|
||||
}
|
||||
const choiceBtn = e.target.closest(".cell-choice-btn");
|
||||
const empty = cell === null || cell === undefined;
|
||||
if (choiceBtn && empty && ctx.emptyCellChoice.current && ctx.emptyCellChoice.current.x === x && ctx.emptyCellChoice.current.y === y) {
|
||||
handleCellClickChoice(ctx, choiceBtn.dataset.choice, x, y);
|
||||
setState();
|
||||
return;
|
||||
}
|
||||
if (cell !== null && cell !== undefined && cell.kind === "nursery" && cell.tokenId !== null && cell.tokenId !== undefined) {
|
||||
ctx.selectedTokenId.current = cell.tokenId;
|
||||
setState();
|
||||
return;
|
||||
}
|
||||
if (cell !== null && cell !== undefined && cell.kind === "nursery" && (cell.tokenId === null || cell.tokenId === undefined)) {
|
||||
const hasBaby = (state.pendingBabies ?? []).some((p) => p.nurseryCellKey === key);
|
||||
if (!hasBaby) {
|
||||
const [ok, reason] = tryUpgradeNursery(state, x, y);
|
||||
if (ok) { setError(""); playSound("upgrade"); } else if (reason !== "NurseryMaxLevel") { setError(String(t.upgradeConveyorFailed).replace("%s", errorMessage[reason] ?? reason)); playSound("error"); }
|
||||
}
|
||||
setState();
|
||||
return;
|
||||
}
|
||||
if (handleCellClickUpgrade(ctx, { cell, x, y, key })) return;
|
||||
ctx.selected.x = x;
|
||||
ctx.selected.y = y;
|
||||
ctx.clampSelection();
|
||||
if (empty && ctx.emptyCellChoice.current && ctx.emptyCellChoice.current.x === x && ctx.emptyCellChoice.current.y === y) {
|
||||
ctx.emptyCellChoice.current = null;
|
||||
setState();
|
||||
return;
|
||||
}
|
||||
handleCellClickPlaceOrSelect(ctx, empty, x, y);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {{ state: import("./types.js").GameState, setState: () => void, setError: (s: string) => void, playSound: (s: string) => void }} ctx
|
||||
* @param {{ cell: import("./types.js").GridCell | null | undefined, x: number, y: number, key: string }} opts
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function handleCellClickUpgrade(ctx, opts) {
|
||||
const { cell, x, y, key } = opts;
|
||||
if (cell === null || cell === undefined) return false;
|
||||
if (handleCellClickUpgradeShops(ctx, cell, x, y)) return true;
|
||||
if (handleCellClickUpgradeRest(ctx, cell, { x, y, key })) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
export { handleCellDrop, handleCellClick };
|
||||
Reference in New Issue
Block a user