import { resources, elements } from "./planetEconomy.js"; // ── Sort state ──────────────────────────────────────────────────────────────── /** 0=Ressource, 1=Rareté, 2=Valeur, 3=Revenu/s */ let _sortCol = 3; let _sortDir = "desc"; export function setEconSort(col, dir) { _sortCol = col; _sortDir = dir; } export function getEconSort() { return { col: _sortCol, dir: _sortDir }; } // ── Label → resource key lookup ─────────────────────────────────────────────── /** Map from French label string → { cat: "common"|"rare", key: string } */ const LABEL_TO_RESOURCE = (() => { const map = new Map(); for (const [cat, entries] of Object.entries(resources)) { for (const [key, label] of Object.entries(entries)) { map.set(label, { cat, key }); } } return map; })(); // ── Income calculation ──────────────────────────────────────────────────────── /** * Compute income per second for a team based on their discovered planets. * * @param {string} team - "blue" or "red" * @param {Map} cells * @param {object} resourceWorth - { common: { rock: 1, ... }, rare: { rock: 3, ... } } * @returns {{ total: number, byResource: Map }} * byResource keys are resource label strings (French names), values are credits/sec */ export function computeTeamIncome(team, cells, resourceWorth) { /** @type {Map} label → cumulative income/sec */ const byResource = new Map(); let total = 0; for (const [, meta] of cells) { if (meta.discoveredBy !== team) continue; if (!meta.hasPlanet || !meta.planet) continue; const { naturalResources } = meta.planet; if (!naturalResources) continue; for (const [label, pct] of Object.entries(naturalResources)) { const info = LABEL_TO_RESOURCE.get(label); if (!info) continue; const worth = resourceWorth?.[info.cat]?.[info.key] ?? 0; if (worth === 0) continue; const income = (pct / 100) * worth; byResource.set(label, (byResource.get(label) ?? 0) + income); total += income; } } return { total, byResource }; } // ── Element bonus calculation ───────────────────────────────────────────────── /** * Reverse map: French element label → config key * e.g. "Matières premières" → "common", "Hydrocarbures" → "petrol" */ const ELEMENT_LABEL_TO_KEY = Object.fromEntries( Object.entries(elements).map(([key, label]) => [label, key]) ); /** * Compute cumulative element bonus for a team based on their planets' production. * planet.production stores French label strings as keys (values from elements const). * bonus = sum_over_planets( sum_over_elements( elementShare% / 100 * elementWorth[key] ) ) * * @param {string} team * @param {Map} cells * @param {object} elementWorth - { common: 1, petrol: 3, ... } * @returns {number} bonus value (use as %) */ export function computeTeamElementBonus(team, cells, elementWorth) { let bonus = 0; for (const [, meta] of cells) { if (meta.discoveredBy !== team) continue; if (!meta.hasPlanet || !meta.planet) continue; const { production } = meta.planet; if (!production) continue; for (const [elementLabel, pct] of Object.entries(production)) { // production keys are French labels; map back to config key const elementKey = ELEMENT_LABEL_TO_KEY[elementLabel] ?? elementLabel; const worth = elementWorth?.[elementKey] ?? 0; if (worth === 0) continue; bonus += (pct / 100) * worth; } } return bonus; } export { elements }; // ── Resource table for the sidebar ─────────────────────────────────────────── /** * Renders the resource overview table for the economy panel. * * @param {object} resourceWorth - { common: {…}, rare: {…} } * @param {Map} teamByResource - income/sec per label for current team * @returns {string} HTML string */ export function renderResourceTable(resourceWorth, teamByResource) { const rows = []; for (const [cat, entries] of Object.entries(resources)) { for (const [key, label] of Object.entries(entries)) { const worth = resourceWorth?.[cat]?.[key] ?? 0; const income = teamByResource?.get(label) ?? 0; const incomeStr = income > 0 ? `+${income.toFixed(3)}/s` : "—"; const catLabel = cat === "rare" ? "Rare" : "Commun"; rows.push({ label, catLabel, worth, income, incomeStr }); } } // Sort by selected column const mult = _sortDir === "asc" ? 1 : -1; rows.sort((a, b) => { if (_sortCol === 0) return mult * a.label.localeCompare(b.label, "fr"); if (_sortCol === 1) return mult * a.catLabel.localeCompare(b.catLabel, "fr"); if (_sortCol === 2) return mult * (a.worth - b.worth); if (_sortCol === 3) return mult * (a.income - b.income); return b.income - a.income || b.worth - a.worth; }); const tableRows = rows .map(({ label, catLabel, worth, incomeStr, income }) => { const incomeClass = income > 0 ? " econ-income--positive" : ""; return ` ${label} ${catLabel} ${worth} ${incomeStr} `; }) .join(""); const thLabels = ["Ressource", "Rareté", "Valeur", "Revenu/s"]; const headers = thLabels .map((lbl, i) => { const isActive = i === _sortCol; const indicator = isActive ? (_sortDir === "asc" ? " ▲" : " ▼") : " ⇅"; const activeClass = isActive ? " econTh--active" : ""; return `${lbl}${indicator}`; }) .join(""); return `${headers}${tableRows}
`; }