Initial commit
**Motivations:** - Initialisation du versionning git pour le projet **Root causes:** - N/A (Nouveau projet) **Correctifs:** - N/A **Evolutions:** - Structure initiale du projet - Ajout du .gitignore **Pages affectées:** - Tous les fichiers
This commit is contained in:
112
web/js/hatching.js
Normal file
112
web/js/hatching.js
Normal file
@@ -0,0 +1,112 @@
|
||||
import { GameConfig } from "./config.js";
|
||||
import { LootTables } from "./loot-tables.js";
|
||||
import { getMutationEntries, getIncomeMultiplier } from "./mutation-rules.js";
|
||||
import { getCellBiome, getBiomesCompatibleWithCell } from "./biome-rules.js";
|
||||
import { cellKey } from "./grid-utils.js";
|
||||
import { fillAnimalBlock, canPlaceMultiCell } from "./placement.js";
|
||||
import { createSeededRng, pickId } from "./weighted-random.js";
|
||||
|
||||
const BIOME_TO_EGG_TYPE = { Meadow: "Color_1", Ocean: "Color_6", Mountain: "Color_11", Forest: "Color_1", Freshwater: "Color_6" };
|
||||
|
||||
/**
|
||||
* Loot entries for animals that match the cell biome. If the egg type has none, use the egg type for that biome.
|
||||
* @param {string} cellBiome
|
||||
* @param {Array<{ id: string, weight: number }>} loot
|
||||
* @returns {Array<{ id: string, weight: number }>}
|
||||
*/
|
||||
function lootForBiome(cellBiome, loot) {
|
||||
const allowedBiomes = getBiomesCompatibleWithCell(cellBiome);
|
||||
const allowed = loot.filter((entry) => {
|
||||
const def = LootTables.Animals[entry.id];
|
||||
return def && allowedBiomes.includes(def.biome);
|
||||
});
|
||||
if (allowed.length > 0) return allowed;
|
||||
const eggType = BIOME_TO_EGG_TYPE[cellBiome];
|
||||
const fallbackDef = eggType ? LootTables.EggTypes[eggType] : null;
|
||||
return fallbackDef ? fallbackDef.loot : loot;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} animalId
|
||||
* @param {string} mutationId
|
||||
* @param {number} nowUnix
|
||||
* @param {{ cellsWide?: number, cellsHigh?: number }} dimensions
|
||||
* @returns {import("./types.js").AnimalCell}
|
||||
*/
|
||||
function buildAnimalCell(animalId, mutationId, nowUnix, dimensions = {}) {
|
||||
return {
|
||||
kind: "animal",
|
||||
id: animalId,
|
||||
mutation: mutationId,
|
||||
level: 1,
|
||||
placedAt: nowUnix,
|
||||
lastVisitedAt: nowUnix,
|
||||
lastFedAt: nowUnix,
|
||||
...dimensions,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("./types.js").GameState} state
|
||||
* @param {{ x: number, y: number, nowUnix: number, eventModifiers: { incomeMultiplier: number, mutationBonus: number } }} opts
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function tryHatchCell(state, opts) {
|
||||
const { x, y, nowUnix, eventModifiers } = opts;
|
||||
const key = cellKey(x, y);
|
||||
const cell = state.grid.cells[key];
|
||||
if (cell === null || cell === undefined || cell.kind !== "egg") return false;
|
||||
if (nowUnix < cell.hatchAt) return false;
|
||||
|
||||
const eggDef = LootTables.EggTypes[cell.eggType];
|
||||
if (eggDef === null || eggDef === undefined) throw new Error("HatchingService: unknown egg type");
|
||||
|
||||
const cellBiome = getCellBiome(state.grid.width, state.grid.height, x, y);
|
||||
const loot = lootForBiome(cellBiome, eggDef.loot);
|
||||
if (loot.length === 0) return false;
|
||||
|
||||
const rng = createSeededRng(cell.seed);
|
||||
const pickedAnimalId = pickId(rng, loot);
|
||||
const animalDef = LootTables.Animals[pickedAnimalId];
|
||||
if (animalDef === null || animalDef === undefined) return false;
|
||||
|
||||
const mutationChance = GameConfig.Mutation.BaseChance + eventModifiers.mutationBonus;
|
||||
let mutationId = "none";
|
||||
if (rng() < mutationChance) mutationId = pickId(rng, getMutationEntries());
|
||||
if (getIncomeMultiplier(mutationId) === undefined) mutationId = "none";
|
||||
|
||||
const w = animalDef.cellsWide ?? 1;
|
||||
const h = animalDef.cellsHigh ?? 1;
|
||||
const [canPlace, _reason] = canPlaceMultiCell(state, { originX: x, originY: y, w, h, excludeOriginKey: key });
|
||||
if (!canPlace) return false;
|
||||
const animalData = buildAnimalCell(pickedAnimalId, mutationId, nowUnix, {
|
||||
cellsWide: w,
|
||||
cellsHigh: h,
|
||||
});
|
||||
fillAnimalBlock(state, x, y, animalData);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("./types.js").GameState} state
|
||||
* @param {number} nowUnix
|
||||
* @param {{ incomeMultiplier: number, mutationBonus: number }} eventModifiers
|
||||
* @returns {{ changed: boolean, hatched: Array<{ x: number, y: number }> }}
|
||||
*/
|
||||
export function run(state, nowUnix, eventModifiers) {
|
||||
const hatched = [];
|
||||
const keysToProcess = [];
|
||||
for (const [key, cell] of Object.entries(state.grid.cells)) {
|
||||
if (cell.kind === "egg" && nowUnix >= cell.hatchAt) keysToProcess.push(key);
|
||||
}
|
||||
for (const key of keysToProcess) {
|
||||
const m = key.match(/^(\d+)_(\d+)$/);
|
||||
if (m) {
|
||||
const x = Number(m[1]);
|
||||
const y = Number(m[2]);
|
||||
const didHatch = tryHatchCell(state, { x, y, nowUnix, eventModifiers });
|
||||
if (didHatch && state.grid.cells[cellKey(x, y)]?.kind === "animal") hatched.push({ x, y });
|
||||
}
|
||||
}
|
||||
return { changed: hatched.length > 0, hatched };
|
||||
}
|
||||
Reference in New Issue
Block a user