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:
ncantu
2026-03-04 15:32:27 +01:00
parent d8a55daf3f
commit c7d389ecbb
57 changed files with 4664 additions and 3049 deletions

View File

@@ -0,0 +1,224 @@
import { tryUpgradeWorldMap, tryUpgradePlot } from "./zoo.js";
import { tryUpgradeTruck } from "./conveyor.js";
import { getTruckUpgradeCost } from "./economy.js";
import { playSound } from "./audio.js";
import { t, errorMessage, sellZoneTitle, sellZoneShortLabel } from "./texts-fr.js";
import { GameConfig } from "./config.js";
import { handleWorldMapTruckDrop, handleSellZoneDrop } from "./ui-render-dom-drops.js";
/**
* @param {HTMLElement} panelWorld
* @param {{ state: import("./types.js").GameState }} setup
* @returns {{ worldMapEl: HTMLElement, worldMapTruckEl: HTMLElement, worldMapNpcTrucksEl: HTMLElement }}
*/
function buildWorldMapWrap(panelWorld, setup) {
const { state } = setup;
const worldMapWrap = document.createElement("div");
worldMapWrap.className = "world-map-wrap world-map-wrap-square";
const worldMapEl = document.createElement("div");
worldMapEl.className = "world-map world-map-biomes";
const mapLevel = state.worldMapLevel ?? 1;
const zoom = Math.min(0.65 + (mapLevel - 1) * 0.2, 1.45);
worldMapEl.style.transformOrigin = "50% 50%";
worldMapEl.style.transform = `scale(${zoom})`;
worldMapWrap.appendChild(worldMapEl);
const worldMapTruckEl = document.createElement("div");
worldMapTruckEl.className = "world-map-truck";
worldMapTruckEl.setAttribute("aria-hidden", "true");
worldMapWrap.appendChild(worldMapTruckEl);
const worldMapNpcTrucksEl = document.createElement("div");
worldMapNpcTrucksEl.className = "world-map-trucks";
worldMapNpcTrucksEl.setAttribute("aria-hidden", "true");
worldMapWrap.appendChild(worldMapNpcTrucksEl);
panelWorld.appendChild(worldMapWrap);
return { worldMapEl, worldMapTruckEl, worldMapNpcTrucksEl };
}
/**
* @param {{ state: import("./types.js").GameState, setState: () => void, setError: (s: string) => void }} setup
* @returns {HTMLElement}
*/
function buildWorldMapUpgradeZone(setup) {
const { state, setState, setError } = setup;
const worldMapUpgradeZone = document.createElement("div");
worldMapUpgradeZone.className = "world-map-upgrade-zone";
worldMapUpgradeZone.setAttribute("aria-label", "Agrandir la carte");
worldMapUpgradeZone.title = "Agrandir la carte";
worldMapUpgradeZone.innerHTML = "<span class=\"world-map-upgrade-zone-icon\" aria-hidden=\"true\">🗺️</span><span class=\"world-map-upgrade-zone-label\">Agrandir carte</span><span class=\"world-map-upgrade-zone-cost\" aria-hidden=\"true\"></span><span class=\"world-map-upgrade-zone-arrow\" aria-hidden=\"true\">▲</span>";
worldMapUpgradeZone.setAttribute("role", "button");
worldMapUpgradeZone.setAttribute("tabindex", "0");
worldMapUpgradeZone.addEventListener("click", () => {
const [ok, reason] = tryUpgradeWorldMap(state);
if (!ok) {
setError(String(t.upgradeWorldMapFailed).replace("%s", errorMessage[reason] ?? reason));
playSound("error");
} else {
setError("");
playSound("worldMapUpgrade");
}
setState();
});
worldMapUpgradeZone.addEventListener("keydown", (e) => {
if (e.key === "Enter" || e.key === " ") {
e.preventDefault();
worldMapUpgradeZone.click();
}
});
return worldMapUpgradeZone;
}
/**
* @param {{ state: import("./types.js").GameState, setState: () => void, setError: (s: string) => void }} setup
* @returns {HTMLElement}
*/
function buildWorldMapTruckDropZone(setup) {
const worldMapTruckDropZone = document.createElement("div");
worldMapTruckDropZone.className = "world-map-truck-drop-zone";
worldMapTruckDropZone.setAttribute("aria-label", "Camion pour acheter un œuf");
worldMapTruckDropZone.title = "Glissez un œuf ici pour l'acheter";
worldMapTruckDropZone.innerHTML = "<span class=\"world-map-truck-drop-icon\" aria-hidden=\"true\">🚚</span><span class=\"world-map-truck-drop-label\">Acheter œuf</span>";
worldMapTruckDropZone.addEventListener("dragover", (e) => {
e.preventDefault();
const hasOffer = e.dataTransfer.types.includes("application/x-builazoo-eggtype")
|| e.dataTransfer.types.includes("application/x-builazoo-baby-offer")
|| e.dataTransfer.types.includes("application/x-builazoo-animal-offer");
e.dataTransfer.dropEffect = hasOffer ? "copy" : "none";
if (hasOffer) worldMapTruckDropZone.classList.add("dragover");
});
worldMapTruckDropZone.addEventListener("dragleave", () => worldMapTruckDropZone.classList.remove("dragover"));
worldMapTruckDropZone.addEventListener("drop", (ev) => handleWorldMapTruckDrop(ev, setup));
return worldMapTruckDropZone;
}
/**
* @param {{ state: import("./types.js").GameState, setState: () => void, setError: (s: string) => void }} setup
* @returns {{ worldMapUpgradeZone: HTMLElement, worldMapCounters: HTMLElement, worldMapTruckDropZone: HTMLElement, worldMapActions: HTMLElement }}
*/
function buildWorldMapActions(setup) {
const worldMapActions = document.createElement("div");
worldMapActions.className = "world-map-actions";
const worldMapUpgradeZone = buildWorldMapUpgradeZone(setup);
worldMapActions.appendChild(worldMapUpgradeZone);
const worldMapCounters = document.createElement("div");
worldMapCounters.className = "world-map-counters";
worldMapCounters.setAttribute("aria-label", "Compteurs carte du monde");
worldMapActions.appendChild(worldMapCounters);
const worldMapTruckDropZone = buildWorldMapTruckDropZone(setup);
worldMapActions.appendChild(worldMapTruckDropZone);
return { worldMapUpgradeZone, worldMapCounters, worldMapTruckDropZone, worldMapActions };
}
/**
* @param {HTMLElement} panelWorld
* @param {{ state: import("./types.js").GameState, setState: () => void, setError: (s: string) => void, playSound: (s: string) => void }} setup
* @returns {{ worldMapEl: HTMLElement, worldMapTruckEl: HTMLElement, worldMapNpcTrucksEl: HTMLElement, worldMapUpgradeZone: HTMLElement, worldMapCounters: HTMLElement }}
*/
export function buildWorldMapSection(panelWorld, setup) {
const wrapResult = buildWorldMapWrap(panelWorld, setup);
const actionsResult = buildWorldMapActions(setup);
panelWorld.appendChild(actionsResult.worldMapActions);
return { ...wrapResult, worldMapUpgradeZone: actionsResult.worldMapUpgradeZone, worldMapCounters: actionsResult.worldMapCounters };
}
/**
* @param {{ state: import("./types.js").GameState, setState: () => void, setError: (s: string) => void }} setup
* @returns {HTMLElement}
*/
function buildPlotUpgradeZone(setup) {
const { state, setState, setError } = setup;
const plotUpgradeZone = document.createElement("div");
plotUpgradeZone.className = "plot-upgrade-zone";
plotUpgradeZone.setAttribute("aria-label", t.upgradePlot);
plotUpgradeZone.title = t.upgradePlot;
plotUpgradeZone.innerHTML = "<span class=\"plot-upgrade-zone-icon\" aria-hidden=\"true\">📐</span><span class=\"plot-upgrade-zone-label\">Agrandir zoo</span><span class=\"plot-upgrade-zone-arrow\" aria-hidden=\"true\">▲</span>";
plotUpgradeZone.setAttribute("role", "button");
plotUpgradeZone.setAttribute("tabindex", "0");
plotUpgradeZone.addEventListener("click", () => {
const [ok, reason] = tryUpgradePlot(state);
if (!ok) {
setError(String(t.upgradePlotFailed).replace("%s", errorMessage[reason] ?? reason));
playSound("error");
} else {
setError("");
playSound("plotUpgrade");
}
setState();
});
plotUpgradeZone.addEventListener("keydown", (e) => {
if (e.key === "Enter" || e.key === " ") {
e.preventDefault();
plotUpgradeZone.click();
}
});
return plotUpgradeZone;
}
/**
* @param {HTMLElement} panelZoo
* @param {{ state: import("./types.js").GameState, setState: () => void, setError: (s: string) => void, playSound: (s: string) => void, lastActionWasDropRef: { current: boolean }, sellZoneJustDroppedRef: { current: boolean } }} setup
* @returns {{ gridEl: HTMLElement, plotUpgradeZone: HTMLElement, sellZone: HTMLElement }}
*/
export function buildGridSection(panelZoo, setup) {
const gridWrap = document.createElement("div");
gridWrap.className = "grid-wrap";
const gridEl = document.createElement("div");
gridEl.className = "grid";
gridWrap.appendChild(gridEl);
const plotUpgradeZone = buildPlotUpgradeZone(setup);
gridWrap.appendChild(plotUpgradeZone);
const sellZone = document.createElement("div");
sellZone.className = "sell-zone";
sellZone.setAttribute("aria-label", sellZoneTitle);
sellZone.title = sellZoneTitle;
sellZone.innerHTML = "<span class=\"sell-zone-icon\" aria-hidden=\"true\">🚚</span><span class=\"sell-zone-label\">" + sellZoneShortLabel + "</span><span class=\"sell-zone-upgrade-arrow\" aria-hidden=\"true\">▲</span>";
attachSellZoneListeners(sellZone, setup);
gridWrap.appendChild(sellZone);
const visitorsLayer = document.createElement("div");
visitorsLayer.className = "visitors-layer";
visitorsLayer.setAttribute("aria-hidden", "true");
gridWrap.appendChild(visitorsLayer);
panelZoo.appendChild(gridWrap);
return { gridEl, plotUpgradeZone, sellZone };
}
/**
* @param {HTMLElement} sellZone
* @param {{ state: import("./types.js").GameState, setState: () => void, setError: (s: string) => void, playSound: (s: string) => void, lastActionWasDropRef: { current: boolean }, sellZoneJustDroppedRef: { current: boolean } }} setup
* @returns {void}
*/
function attachSellZoneListeners(sellZone, setup) {
sellZone.addEventListener("dragover", (e) => {
e.preventDefault();
const hasCell = e.dataTransfer.types.includes("text/plain");
e.dataTransfer.dropEffect = hasCell ? "move" : "none";
if (hasCell) sellZone.classList.add("dragover");
});
sellZone.addEventListener("dragleave", () => sellZone.classList.remove("dragover"));
sellZone.addEventListener("drop", (e) => handleSellZoneDrop(e, setup));
sellZone.addEventListener("click", () => handleSellZoneClick(setup));
}
/**
* @param {{ state: import("./types.js").GameState, setState: () => void, setError: (s: string) => void, sellZoneJustDroppedRef: { current: boolean } }} setup
* @returns {void}
*/
function handleSellZoneClick(setup) {
if (setup.sellZoneJustDroppedRef.current) {
setup.sellZoneJustDroppedRef.current = false;
return;
}
const state = setup.state;
const truckLevel = state.truckLevel ?? 1;
const truckMax = (GameConfig.Truck && GameConfig.Truck.MaxLevel) || 5;
if (truckLevel >= truckMax) return;
if (state.coins < getTruckUpgradeCost(truckLevel)) return;
const [ok, reason] = tryUpgradeTruck(state);
if (!ok) {
setup.setError(String(t.upgradeConveyorFailed).replace("%s", errorMessage[reason] ?? reason));
playSound("error");
} else {
setup.setError("");
playSound("truckUpgrade");
}
setup.setState();
}