**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
102 lines
4.0 KiB
JavaScript
102 lines
4.0 KiB
JavaScript
/**
|
|
* Visual state of an animal cell for feedback (no gauges). Used by UI to add CSS classes.
|
|
* Refs: docs/specs/animal_generique.md, temperature.md.
|
|
*/
|
|
|
|
import { LootTables } from "./loot-tables.js";
|
|
import { getDisplayTemperature } from "./biome-rules.js";
|
|
import { getCurrentSeason, getSeasonTemperatureModifier } from "./seasons.js";
|
|
import { GameConfig } from "./config.js";
|
|
|
|
/**
|
|
* @param {number} cellTemp
|
|
* @param {number} idealTemp
|
|
* @param {number} tolerance
|
|
* @returns {{ cold: boolean, hot: boolean }}
|
|
*/
|
|
function getTemperatureState(cellTemp, idealTemp, tolerance) {
|
|
return {
|
|
cold: cellTemp < idealTemp - tolerance,
|
|
hot: cellTemp > idealTemp + tolerance,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* @param {{ fedAgo: number, visitAgo: number, maxFood: number, maxVisit: number, cold: boolean, hot: boolean }} opts
|
|
* @returns {{ hungry: boolean, sick: boolean, happy: boolean }}
|
|
*/
|
|
function getCareState(opts) {
|
|
const { fedAgo, visitAgo, maxFood, maxVisit, cold, hot } = opts;
|
|
const hungry = fedAgo > maxFood * 0.6;
|
|
const sick = cold || hot || hungry || visitAgo > maxVisit * 0.8;
|
|
const happy = !sick && fedAgo < maxFood * 0.3 && visitAgo < maxVisit * 0.3
|
|
&& !cold && !hot;
|
|
return { hungry, sick, happy };
|
|
}
|
|
|
|
const EMPTY_VISUAL = { cold: false, hot: false, hungry: false, sick: false, happy: false };
|
|
|
|
/**
|
|
* @param {import("./types.js").AnimalCell} cell
|
|
* @param {import("./types.js").GameState} state
|
|
* @param {{ width: number, height: number }} grid
|
|
* @param {string} originKey
|
|
* @returns {{ cellTemp: number, idealTemp: number, tolerance: number } | null}
|
|
*/
|
|
function getAnimalTempInputs(cell, state, grid, originKey) {
|
|
const def = LootTables.Animals[cell.id];
|
|
if (!def) return null;
|
|
const m = originKey.match(/^(\d+)_(\d+)$/);
|
|
if (!m) return null;
|
|
const ox = Number(m[1]);
|
|
const oy = Number(m[2]);
|
|
const baseTemp = getDisplayTemperature(ox, oy, grid);
|
|
const seasonMod = getSeasonTemperatureModifier(getCurrentSeason(state));
|
|
const cellTemp = baseTemp + seasonMod;
|
|
const idealTemp = def.idealTemperature ?? 18;
|
|
const tolerance = def.temperatureTolerance ?? 5;
|
|
return { cellTemp, idealTemp, tolerance };
|
|
}
|
|
|
|
/**
|
|
* @param {import("./types.js").AnimalCell} cell
|
|
* @returns {{ fedAgo: number, visitAgo: number, maxFood: number, maxVisit: number }}
|
|
*/
|
|
function getAnimalTimeInputs(cell) {
|
|
const nowUnix = Math.floor(Date.now() / 1000);
|
|
const lastFed = cell.lastFedAt ?? cell.placedAt ?? nowUnix;
|
|
const lastVisited = cell.lastVisitedAt ?? cell.placedAt ?? nowUnix;
|
|
const maxFood = GameConfig.Food?.MaxSecondsWithoutFood ?? 120;
|
|
const maxVisit = GameConfig.Visitor?.MaxSecondsWithoutVisit ?? 300;
|
|
return { fedAgo: nowUnix - lastFed, visitAgo: nowUnix - lastVisited, maxFood, maxVisit };
|
|
}
|
|
|
|
/**
|
|
* @param {import("./types.js").AnimalCell} cell
|
|
* @param {import("./types.js").GameState} state
|
|
* @param {{ width: number, height: number }} grid
|
|
* @param {string} originKey
|
|
* @returns {{ cellTemp: number, idealTemp: number, tolerance: number, fedAgo: number, visitAgo: number, maxFood: number, maxVisit: number } | null}
|
|
*/
|
|
function getAnimalVisualInputs(cell, state, grid, originKey) {
|
|
const temp = getAnimalTempInputs(cell, state, grid, originKey);
|
|
if (!temp) return null;
|
|
const time = getAnimalTimeInputs(cell);
|
|
return { ...temp, ...time };
|
|
}
|
|
|
|
/**
|
|
* @param {import("./types.js").AnimalCell} cell Origin animal cell.
|
|
* @param {import("./types.js").GameState} state
|
|
* @param {{ width: number, height: number }} grid
|
|
* @param {string} originKey "x_y" of origin cell.
|
|
* @returns {{ cold: boolean, hot: boolean, hungry: boolean, sick: boolean, happy: boolean }}
|
|
*/
|
|
export function getAnimalVisualState(cell, state, grid, originKey) {
|
|
const inputs = getAnimalVisualInputs(cell, state, grid, originKey);
|
|
if (!inputs) return EMPTY_VISUAL;
|
|
const { cold, hot } = getTemperatureState(inputs.cellTemp, inputs.idealTemp, inputs.tolerance);
|
|
const { hungry, sick, happy } = getCareState({ fedAgo: inputs.fedAgo, visitAgo: inputs.visitAgo, maxFood: inputs.maxFood, maxVisit: inputs.maxVisit, cold, hot });
|
|
return { cold, hot, hungry, sick, happy };
|
|
}
|