**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
225 lines
10 KiB
JavaScript
225 lines
10 KiB
JavaScript
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();
|
|
}
|