Files
builazoo/web/js/ui-grid-drag.js
ncantu c7d389ecbb 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
2026-03-04 15:32:27 +01:00

137 lines
6.4 KiB
JavaScript

/**
* Drag-related helpers for grid cells: set DataTransfer for dragstart, attach drag listeners, handle drop.
*/
import { tryBuyEgg, tryPlaceEgg, placeMatureBabyOnCell, placeReceptionAnimalOnCell } from "./zoo.js";
import { moveCell } from "./placement.js";
import { t, errorMessage } from "./texts-fr.js";
/**
* @param {{ state: import("./types.js").GameState, setState: () => void, setError: (s: string) => void, playSound: (s: string) => void, lastActionWasDrop: { current: boolean } }} ctx
* @param {DragEvent} e
* @param {{ x: number, y: number, empty: boolean }} target
* @returns {boolean}
*/
export function handleCellDropNurseryReceptionToken(ctx, e, target) {
const { state, setState, setError, playSound } = ctx;
const { x: toX, y: toY, empty } = target;
const nurseryCellKey = e.dataTransfer.getData("application/x-builazoo-nursery-cell-key");
if (nurseryCellKey && empty) {
const nowUnix = Math.floor(Date.now() / 1000);
const [ok, reason] = placeMatureBabyOnCell(state, { nurseryCellKey, toX, toY, nowUnix });
if (ok) { setError(""); playSound("place"); } else { setError(String(t.errorPrefix).replace("%s", errorMessage[reason] ?? reason)); playSound("error"); }
ctx.lastActionWasDrop.current = true;
setState();
return true;
}
const receptionCellKey = e.dataTransfer.getData("application/x-builazoo-reception-cell-key");
if (receptionCellKey && empty) {
const nowUnix = Math.floor(Date.now() / 1000);
const [ok, reason] = placeReceptionAnimalOnCell(state, { receptionCellKey, toX, toY, nowUnix });
if (ok) { setError(""); playSound("place"); } else { setError(String(t.errorPrefix).replace("%s", errorMessage[reason] ?? reason)); playSound("error"); }
ctx.lastActionWasDrop.current = true;
setState();
return true;
}
const tokenIdStr = e.dataTransfer.getData("application/x-builazoo-tokenid");
if (tokenIdStr && empty) {
const tokenId = Number(tokenIdStr);
if (!Number.isNaN(tokenId)) {
const nowUnix = Math.floor(Date.now() / 1000);
const [placeOk, placeReason] = tryPlaceEgg(state, { tokenId, x: toX, y: toY, nowUnix });
if (placeOk) { setError(""); playSound("place"); } else { setError(String(t.errorPrefix).replace("%s", errorMessage[placeReason] ?? placeReason)); playSound("error"); }
ctx.lastActionWasDrop.current = true;
setState();
}
return true;
}
return false;
}
/**
* @param {{ state: import("./types.js").GameState, setState: () => void, setError: (s: string) => void, playSound: (s: string) => void, lastActionWasDrop: { current: boolean } }} ctx
* @param {DragEvent} e
* @param {{ x: number, y: number, empty: boolean }} target
* @returns {boolean}
*/
export function handleCellDropEggTypeOrMove(ctx, e, target) {
const { state, setState, setError, playSound } = ctx;
const { x: toX, y: toY, empty } = target;
const eggTypeFromConveyor = e.dataTransfer.getData("application/x-builazoo-eggtype");
if (eggTypeFromConveyor && empty) {
const [buyOk, buyResult] = tryBuyEgg(state, eggTypeFromConveyor);
if (!buyOk) { setError(String(t.buyFailed).replace("%s", errorMessage[buyResult] ?? buyResult)); playSound("error"); } else {
const tokenId = buyResult.tokenId;
const nowUnix = Math.floor(Date.now() / 1000);
const [placeOk, placeReason] = tryPlaceEgg(state, { tokenId, x: toX, y: toY, nowUnix });
if (placeOk) { setError(""); playSound("place"); } else { setError(String(t.errorPrefix).replace("%s", errorMessage[placeReason] ?? placeReason)); playSound("error"); }
}
ctx.lastActionWasDrop.current = true;
setState();
return true;
}
const raw = e.dataTransfer.getData("text/plain");
if (!raw || !/^\d+_\d+$/.test(raw)) return true;
const [sx, sy] = raw.split("_").map(Number);
const [ok, reason] = moveCell(state, { fromX: sx, fromY: sy, toX, toY });
if (!ok) setError(String(t.errorPrefix).replace("%s", errorMessage[reason] ?? reason)); else setError("");
ctx.lastActionWasDrop.current = true;
setState();
return true;
}
/**
* @param {HTMLElement} div
* @param {import("./types.js").GridCell | null | undefined} cell
* @param {{ x: number, y: number }} pos
* @param {DataTransfer} dt
*/
export function setCellDragData(div, cell, pos, dt) {
const { x, y } = pos;
let dragX = x;
let dragY = y;
if (div.dataset.nurseryCellKey) {
dt.setData("application/x-builazoo-nursery-cell-key", div.dataset.nurseryCellKey);
dt.effectAllowed = "move";
} else if (div.dataset.receptionCellKey) {
dt.setData("application/x-builazoo-reception-cell-key", div.dataset.receptionCellKey);
dt.effectAllowed = "move";
} else if (cell && cell.kind === "animal" && cell.originKey !== null && cell.originKey !== undefined) {
const m = cell.originKey.match(/^(\d+)_(\d+)$/);
if (m) { dragX = Number(m[1]); dragY = Number(m[2]); }
}
if (!div.dataset.nurseryCellKey && !div.dataset.receptionCellKey) dt.setData("text/plain", `${dragX}_${dragY}`);
if (cell && cell.kind === "nursery" && cell.tokenId !== null && cell.tokenId !== undefined) {
dt.setData("application/x-builazoo-tokenid", String(cell.tokenId));
}
dt.effectAllowed = dt.effectAllowed || "move";
}
/**
* @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 attachDragListeners(ctx, opts) {
const { div, cell } = opts;
const { gridEl } = ctx;
const isDraggable = cell !== null && cell !== undefined && (
cell.kind === "egg" || cell.kind === "animal" ||
(cell.kind === "nursery" && (cell.tokenId !== null && cell.tokenId !== undefined || div.dataset.nurseryCellKey)) ||
(cell.kind === "reception" && div.dataset.receptionCellKey)
);
if (!isDraggable) return;
div.addEventListener("dragstart", (e) => {
setCellDragData(div, cell, { x: opts.x, y: opts.y }, e.dataTransfer);
div.classList.add("dragging");
const ghost = div.cloneNode(true);
ghost.classList.add("drag-ghost");
ghost.style.opacity = "1";
document.body.appendChild(ghost);
e.dataTransfer.setDragImage(ghost, 24, 24);
div.addEventListener("dragend", () => { ghost.remove(); }, { once: true });
});
div.addEventListener("dragend", () => {
div.classList.remove("dragging");
gridEl.querySelectorAll(".cell").forEach((c) => c.classList.remove("dragover"));
});
}