fix: Making the scoreBoard clearer
This commit is contained in:
@@ -90,6 +90,8 @@
|
||||
<!-- Team score display -->
|
||||
<div class="scoreBoard" id="scoreBoard">
|
||||
<img src="./graphism/logo_resistance.svg" alt="Resistance" class="team-logo" />
|
||||
<div class="scoreBoardContent">
|
||||
<div class="scoreBoardRow">
|
||||
<div class="scoreTeam scoreTeam--blue">
|
||||
<span class="scoreTeamName">Résistance</span>
|
||||
<div class="scoreStats">
|
||||
@@ -117,6 +119,31 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Income summary + cumulative economic score (inside scoreBoard) -->
|
||||
<div class="scoreBoardEcon">
|
||||
<div class="econSummaryRow">
|
||||
<span class="econSummaryTeam econSummaryTeam--blue econSummaryTeam--center">
|
||||
<span class="econSummaryVal" id="incomeBlue">+0.000/s</span>
|
||||
</span>
|
||||
<span class="econSummarySep">—</span>
|
||||
<span class="econSummaryTeam econSummaryTeam--red econSummaryTeam--center">
|
||||
<span class="econSummaryVal" id="incomeRed">+0.000/s</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="econSummaryRow econSummaryRow--score">
|
||||
<span class="econSummaryTeam econSummaryTeam--blue econSummaryTeam--center">
|
||||
<span class="econScoreVal" id="econScoreBlue">0.000</span>
|
||||
<span class="econDelta" id="econDeltaBlue"></span>
|
||||
</span>
|
||||
<span class="econSummarySep">—</span>
|
||||
<span class="econSummaryTeam econSummaryTeam--red econSummaryTeam--center">
|
||||
<span class="econDelta" id="econDeltaRed"></span>
|
||||
<span class="econScoreVal" id="econScoreRed">0.000</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<img src="./graphism/logo_first_order.svg" alt="First Order" class="team-logo" />
|
||||
</div>
|
||||
|
||||
@@ -164,34 +191,6 @@
|
||||
<pre id="details" class="details details--hidden">Les stats sont vides sauf à cliquer sur une tuile exploitable.</pre>
|
||||
</details>
|
||||
|
||||
<!-- Team income summary + cumulative economic score -->
|
||||
<div class="econSummary">
|
||||
<!-- Row 1: income per second -->
|
||||
<div class="econSummaryRow">
|
||||
<span class="econSummaryTeam econSummaryTeam--blue">
|
||||
<span class="econSummaryLabel">Résistance</span>
|
||||
<span class="econSummaryVal" id="incomeBlue">+0.000/s</span>
|
||||
</span>
|
||||
<span class="econSummarySep">—</span>
|
||||
<span class="econSummaryTeam econSummaryTeam--red">
|
||||
<span class="econSummaryVal" id="incomeRed">+0.000/s</span>
|
||||
<span class="econSummaryLabel">Premier Ordre</span>
|
||||
</span>
|
||||
</div>
|
||||
<!-- Row 2: cumulative economic score -->
|
||||
<div class="econSummaryRow econSummaryRow--score">
|
||||
<span class="econSummaryTeam econSummaryTeam--blue">
|
||||
<span class="econScoreVal" id="econScoreBlue">0.000</span>
|
||||
<span class="econDelta" id="econDeltaBlue"></span>
|
||||
</span>
|
||||
<span class="econSummarySep">—</span>
|
||||
<span class="econSummaryTeam econSummaryTeam--red">
|
||||
<span class="econDelta" id="econDeltaRed"></span>
|
||||
<span class="econScoreVal" id="econScoreRed">0.000</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Resources overview (collapsible) -->
|
||||
<details class="panel panelCollapsible">
|
||||
<summary class="panelTitle panelTitleSummary">💰 Ressources</summary>
|
||||
@@ -200,10 +199,10 @@
|
||||
</div>
|
||||
</details>
|
||||
|
||||
<!-- Element bonus section -->
|
||||
<div class="elemBonusSection">
|
||||
<div class="elemBonusSectionTitle">⚡ Bonus d'exploration</div>
|
||||
<div class="elemBonusRow">
|
||||
<!-- Element bonus (collapsible) -->
|
||||
<details class="panel panelCollapsible">
|
||||
<summary class="panelTitle panelTitleSummary">⚡ Bonus d'exploration</summary>
|
||||
<div class="elemBonusTotals">
|
||||
<span class="elemBonusTeam elemBonusTeam--blue">
|
||||
<span class="elemBonusLabel">Résistance</span>
|
||||
<span class="elemBonusVal" id="elemBonusBlue">0.00</span>
|
||||
@@ -215,12 +214,15 @@
|
||||
<span class="elemBonusUnit">%</span>
|
||||
<span class="elemBonusLabel">Premier Ordre</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="elemBonusDetail">
|
||||
<span class="elemBonusDetailLabel">Recharge d'équipe :</span>
|
||||
<span class="elemBonusEffective">
|
||||
<span class="elemBonusDetailLabel">Recharge :</span>
|
||||
<span class="elemBonusDetailVal" id="effectiveCooldown">—</span>
|
||||
</span>
|
||||
</div>
|
||||
<div id="elementBonusTableBody" class="econTableWrap">
|
||||
<p class="econEmpty">Chargement…</p>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
<!-- Admin / options section -->
|
||||
<div class="infoSection infoSection--options">
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { resources, elements } from "./planetEconomy.js";
|
||||
|
||||
// ── Sort state ────────────────────────────────────────────────────────────────
|
||||
// ── Sort state (resources) ────────────────────────────────────────────────────
|
||||
|
||||
/** 0=Ressource, 1=Rareté, 2=Valeur, 3=Revenu/s */
|
||||
let _sortCol = 3;
|
||||
@@ -15,6 +15,21 @@ export function getEconSort() {
|
||||
return { col: _sortCol, dir: _sortDir };
|
||||
}
|
||||
|
||||
// ── Sort state (elements) ─────────────────────────────────────────────────────
|
||||
|
||||
/** 0=Élément, 1=Valeur/élément, 2=Bonus % */
|
||||
let _elemSortCol = 2;
|
||||
let _elemSortDir = "desc";
|
||||
|
||||
export function setElemSort(col, dir) {
|
||||
_elemSortCol = col;
|
||||
_elemSortDir = dir;
|
||||
}
|
||||
|
||||
export function getElemSort() {
|
||||
return { col: _elemSortCol, dir: _elemSortDir };
|
||||
}
|
||||
|
||||
// ── Label → resource key lookup ───────────────────────────────────────────────
|
||||
|
||||
/** Map from French label string → { cat: "common"|"rare", key: string } */
|
||||
@@ -102,6 +117,35 @@ export function computeTeamElementBonus(team, cells, elementWorth) {
|
||||
return bonus;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute per-element bonus breakdown for a team.
|
||||
*
|
||||
* @param {string} team
|
||||
* @param {Map<string, { discoveredBy: string, hasPlanet: boolean, planet: object|null }>} cells
|
||||
* @param {object} elementWorth - { common: 1, petrol: 3, ... }
|
||||
* @returns {{ total: number, byElement: Map<string, number> }}
|
||||
* byElement keys are French element label strings, values are cumulative bonus %
|
||||
*/
|
||||
export function computeTeamElementBonusDetailed(team, cells, elementWorth) {
|
||||
const byElement = new Map();
|
||||
let total = 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)) {
|
||||
const elementKey = ELEMENT_LABEL_TO_KEY[elementLabel] ?? elementLabel;
|
||||
const worth = elementWorth?.[elementKey] ?? 0;
|
||||
if (worth === 0) continue;
|
||||
const bonus = (pct / 100) * worth;
|
||||
byElement.set(elementLabel, (byElement.get(elementLabel) ?? 0) + bonus);
|
||||
total += bonus;
|
||||
}
|
||||
}
|
||||
return { total, byElement };
|
||||
}
|
||||
|
||||
export { elements };
|
||||
|
||||
// ── Resource table for the sidebar ───────────────────────────────────────────
|
||||
@@ -163,3 +207,61 @@ export function renderResourceTable(resourceWorth, teamByResource) {
|
||||
<tbody>${tableRows}</tbody>
|
||||
</table>`;
|
||||
}
|
||||
|
||||
// ── Element bonus table for the sidebar ──────────────────────────────────────
|
||||
|
||||
/**
|
||||
* Renders the element bonus breakdown table.
|
||||
*
|
||||
* @param {object} elementWorth - { common: 1, petrol: 3, ... }
|
||||
* @param {Map<string, number>} teamByElement - bonus per element label for current team
|
||||
* @returns {string} HTML string
|
||||
*/
|
||||
export function renderElementBonusTable(elementWorth, teamByElement) {
|
||||
const rows = [];
|
||||
|
||||
for (const [key, label] of Object.entries(elements)) {
|
||||
const worth = elementWorth?.[key] ?? 0;
|
||||
const bonus = teamByElement?.get(label) ?? 0;
|
||||
const bonusStr = bonus > 0 ? `+${bonus.toFixed(3)}%` : "—";
|
||||
rows.push({ label, worth, bonus, bonusStr });
|
||||
}
|
||||
|
||||
const mult = _elemSortDir === "asc" ? 1 : -1;
|
||||
rows.sort((a, b) => {
|
||||
if (_elemSortCol === 0) return mult * a.label.localeCompare(b.label, "fr");
|
||||
if (_elemSortCol === 1) return mult * (a.worth - b.worth);
|
||||
if (_elemSortCol === 2) return mult * (a.bonus - b.bonus);
|
||||
return b.bonus - a.bonus || b.worth - a.worth;
|
||||
});
|
||||
|
||||
if (rows.every(r => r.bonus === 0)) {
|
||||
return `<p class="econEmpty">Aucune tuile conquise avec des éléments de production.</p>`;
|
||||
}
|
||||
|
||||
const tableRows = rows
|
||||
.map(({ label, worth, bonus, bonusStr }) => {
|
||||
const bonusClass = bonus > 0 ? " econ-income--positive" : "";
|
||||
return `<tr>
|
||||
<td class="econ-label">${label}</td>
|
||||
<td class="econ-worth">${worth}</td>
|
||||
<td class="econ-income${bonusClass}">${bonusStr}</td>
|
||||
</tr>`;
|
||||
})
|
||||
.join("");
|
||||
|
||||
const thLabels = ["Élément", "Val./élément", "Bonus %"];
|
||||
const headers = thLabels
|
||||
.map((lbl, i) => {
|
||||
const isActive = i === _elemSortCol;
|
||||
const indicator = isActive ? (_elemSortDir === "asc" ? " ▲" : " ▼") : " ⇅";
|
||||
const activeClass = isActive ? " econTh--active" : "";
|
||||
return `<th class="econTh${activeClass}" data-elem-sort-col="${i}">${lbl}<span class="econSortIcon">${indicator}</span></th>`;
|
||||
})
|
||||
.join("");
|
||||
|
||||
return `<table class="econTable">
|
||||
<thead><tr>${headers}</tr></thead>
|
||||
<tbody>${tableRows}</tbody>
|
||||
</table>`;
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import { fnv1a32, hash2u32, mulberry32 } from "./rng.js";
|
||||
import { formatPlanet, generatePlanet } from "./planetGeneration.js";
|
||||
import { apiFetchConfig, apiFetchScores, apiFetchGrid, apiRevealCell, apiFetchEconScores, apiTickEconScores, apiFetchElementBonus, apiTickElementBonus, apiFetchDbInfo, apiFetchVictoryPoints } from "./api.js";
|
||||
import { computeTeamIncome, computeTeamElementBonus, renderResourceTable, setEconSort, getEconSort } from "./economy.js";
|
||||
import { computeTeamIncome, computeTeamElementBonus, computeTeamElementBonusDetailed, renderResourceTable, renderElementBonusTable, setEconSort, getEconSort, setElemSort, getElemSort } from "./economy.js";
|
||||
|
||||
// ── Constants ─────────────────────────────────────────────────────────────────
|
||||
|
||||
@@ -163,6 +163,7 @@ const econScoreBlueEl = document.getElementById("econScoreBlue");
|
||||
const econScoreRedEl = document.getElementById("econScoreRed");
|
||||
const econDeltaBlueEl = document.getElementById("econDeltaBlue");
|
||||
const econDeltaRedEl = document.getElementById("econDeltaRed");
|
||||
const elemBonusTableEl = document.getElementById("elementBonusTableBody");
|
||||
const teamCorner = document.getElementById("teamCorner");
|
||||
const teamTrack = document.getElementById("teamSegmentedTrack");
|
||||
const teamBlueBtn = document.getElementById("teamBlue");
|
||||
@@ -333,6 +334,14 @@ export function updateEconomyDisplay() {
|
||||
if (resourceTableEl) {
|
||||
resourceTableEl.innerHTML = renderResourceTable(worth, teamIncome.byResource);
|
||||
}
|
||||
|
||||
const elemWorth = GAME_CONFIG.elementWorth;
|
||||
const teamElemBonus = currentTeam === "blue"
|
||||
? computeTeamElementBonusDetailed("blue", cells, elemWorth)
|
||||
: computeTeamElementBonusDetailed("red", cells, elemWorth);
|
||||
if (elemBonusTableEl) {
|
||||
elemBonusTableEl.innerHTML = renderElementBonusTable(elemWorth, teamElemBonus.byElement);
|
||||
}
|
||||
}
|
||||
|
||||
// ── Economic score ────────────────────────────────────────────────────────────
|
||||
@@ -718,6 +727,18 @@ resourceTableEl?.addEventListener("click", (ev) => {
|
||||
updateEconomyDisplay();
|
||||
});
|
||||
|
||||
elemBonusTableEl?.addEventListener("click", (ev) => {
|
||||
const th = ev.target.closest("th[data-elem-sort-col]");
|
||||
if (!th) return;
|
||||
const col = Number(th.dataset.elemSortCol);
|
||||
const { col: curCol, dir: curDir } = getElemSort();
|
||||
const newDir = col === curCol
|
||||
? (curDir === "asc" ? "desc" : "asc")
|
||||
: (col === 0 ? "asc" : "desc");
|
||||
setElemSort(col, newDir);
|
||||
updateEconomyDisplay();
|
||||
});
|
||||
|
||||
canvas.addEventListener("mousemove", (ev) => { lastPointerEvent = ev; refreshCursor(ev); });
|
||||
canvas.addEventListener("mouseleave", () => { lastPointerEvent = null; canvas.style.cursor = "default"; });
|
||||
canvas.addEventListener("click", onCanvasClick);
|
||||
|
||||
@@ -276,8 +276,8 @@ body {
|
||||
|
||||
.scoreBoard {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 8px;
|
||||
padding: 10px 12px;
|
||||
border-radius: 14px;
|
||||
@@ -287,6 +287,29 @@ body {
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
.scoreBoardContent {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.scoreBoardRow {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.scoreBoardEcon {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
padding: 8px 0 0;
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.08);
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.team-logo {
|
||||
width: 54px;
|
||||
height: 54px;
|
||||
@@ -676,15 +699,6 @@ button:hover {
|
||||
|
||||
/* ── Team income summary ──────────────────────────────────────────────────── */
|
||||
|
||||
.econSummary {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
padding: 8px 12px;
|
||||
font-family: "Courier New", Courier, monospace;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.econSummaryTeam {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -700,10 +714,12 @@ button:hover {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.econSummaryTeam--blue .econSummaryLabel { color: rgba(90, 200, 255, 0.85); }
|
||||
.econSummaryTeam--blue .econSummaryVal { color: rgba(90, 200, 255, 1); font-weight: 700; }
|
||||
.econSummaryTeam--red .econSummaryLabel { color: rgba(220, 75, 85, 0.85); }
|
||||
.econSummaryTeam--red .econSummaryVal { color: rgba(220, 75, 85, 1); font-weight: 700; }
|
||||
.econSummaryTeam--blue .econSummaryLabel { color: rgba(90, 200, 255, 0.85); font-size: 12px; }
|
||||
.econSummaryTeam--blue .econSummaryVal { color: rgba(90, 200, 255, 1); font-weight: 700; font-size: 12px; }
|
||||
.econSummaryTeam--red .econSummaryLabel { color: rgba(220, 75, 85, 0.85); font-size: 12px; }
|
||||
.econSummaryTeam--red .econSummaryVal { color: rgba(220, 75, 85, 1); font-weight: 700; font-size: 12px; }
|
||||
|
||||
.econSummaryTeam--center { justify-content: center; }
|
||||
|
||||
.econSummarySep {
|
||||
opacity: 0.3;
|
||||
@@ -872,20 +888,29 @@ button:hover {
|
||||
|
||||
/* ── Element bonus section ────────────────────────────────────────────────── */
|
||||
|
||||
.elemBonusSection {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
padding: 8px 12px;
|
||||
font-family: "Courier New", Courier, monospace;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.elemBonusRow {
|
||||
.elemBonusTotals {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0;
|
||||
padding: 8px 12px 4px;
|
||||
font-family: "Courier New", Courier, monospace;
|
||||
font-size: 12px;
|
||||
flex-wrap: wrap;
|
||||
row-gap: 4px;
|
||||
}
|
||||
|
||||
.elemBonusEffective {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 5px;
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.06);
|
||||
padding-top: 5px;
|
||||
margin-top: 2px;
|
||||
font-size: 11px;
|
||||
font-family: "Courier New", Courier, monospace;
|
||||
}
|
||||
|
||||
.elemBonusTeam {
|
||||
@@ -919,16 +944,6 @@ button:hover {
|
||||
margin: 0 6px;
|
||||
}
|
||||
|
||||
.elemBonusDetail {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.06);
|
||||
padding-top: 6px;
|
||||
margin-top: 2px;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.elemBonusDetailLabel {
|
||||
opacity: 0.55;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user