**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
137 lines
6.4 KiB
JavaScript
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"));
|
|
});
|
|
}
|