feat: Adding economic system to do scoring
This commit is contained in:
125
public/src/economy.js
Normal file
125
public/src/economy.js
Normal file
@@ -0,0 +1,125 @@
|
||||
import { resources } 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<string, { discoveredBy: string, hasPlanet: boolean, planet: object|null }>} cells
|
||||
* @param {object} resourceWorth - { common: { rock: 1, ... }, rare: { rock: 3, ... } }
|
||||
* @returns {{ total: number, byResource: Map<string, number> }}
|
||||
* byResource keys are resource label strings (French names), values are credits/sec
|
||||
*/
|
||||
export function computeTeamIncome(team, cells, resourceWorth) {
|
||||
/** @type {Map<string, number>} 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 };
|
||||
}
|
||||
|
||||
// ── Resource table for the sidebar ───────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* Renders the resource overview table for the economy panel.
|
||||
*
|
||||
* @param {object} resourceWorth - { common: {…}, rare: {…} }
|
||||
* @param {Map<string, number>} 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 `<tr>
|
||||
<td class="econ-label">${label}</td>
|
||||
<td class="econ-cat econ-cat--${catLabel.toLowerCase()}">${catLabel}</td>
|
||||
<td class="econ-worth">${worth}</td>
|
||||
<td class="econ-income${incomeClass}">${incomeStr}</td>
|
||||
</tr>`;
|
||||
})
|
||||
.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 `<th class="econTh${activeClass}" data-sort-col="${i}">${lbl}<span class="econSortIcon">${indicator}</span></th>`;
|
||||
})
|
||||
.join("");
|
||||
|
||||
return `<table class="econTable">
|
||||
<thead><tr>${headers}</tr></thead>
|
||||
<tbody>${tableRows}</tbody>
|
||||
</table>`;
|
||||
}
|
||||
Reference in New Issue
Block a user