- Tile improvements (fortifications, radar towers, coastal cannons), trenches, zone of control, support-unit capture and launch transports, with parabolic barrage arcs drawn between attacker and target. - Focused research that pours points straight into the chosen technology, with per-technology progress kept when the focus changes, plus repeatable levels. - Popularity reworked to integer points, war and pillage effects, minority policies and month-over-month arrows on the nation summary. - City progress bars, square improvement buttons, a technology tab of wide short cards with progress bars, transport cargo readout and double-click to open a city panel.
78 lines
2.5 KiB
JavaScript
78 lines
2.5 KiB
JavaScript
// The economic map modes: a colour scale that turns a per-tile figure (GDP per
|
|
// capita or raw population) into a hex colour, plus the catalogue describing
|
|
// each mode.
|
|
//
|
|
// The gradient runs from yellow (poorest / smallest) to blue (richest /
|
|
// largest). Those two hues are the pair most colour-blind players can still
|
|
// tell apart, and the stops are the reversed cividis palette, which keeps a
|
|
// monotonic lightness across the whole ramp so the magnitude also reads without
|
|
// colour vision.
|
|
|
|
import { parseColour } from "./utils.js";
|
|
import { groupDigits } from "../../../shared/text_format.js";
|
|
|
|
export const ECONOMIC_GRADIENT = [
|
|
"#ffea46",
|
|
"#e4cf5b",
|
|
"#c4b56c",
|
|
"#a69d75",
|
|
"#8a8779",
|
|
"#707173",
|
|
"#575d6c",
|
|
"#39486b",
|
|
"#00306f",
|
|
"#00204d",
|
|
];
|
|
|
|
// A population map is dominated by a handful of huge cities, which would
|
|
// otherwise crush every smaller settlement to the bottom of the scale, so it is
|
|
// read logarithmically; GDP per capita stays linear.
|
|
export const ECONOMIC_MODES = {
|
|
gdp: {
|
|
id: "gdp",
|
|
label: "GDP per capita",
|
|
format: (value) => `€${groupDigits(Math.round(value))}`,
|
|
},
|
|
population: {
|
|
id: "population",
|
|
label: "Population",
|
|
format: (value) => groupDigits(Math.round(value)),
|
|
scale: (value) => Math.log1p(Math.max(0, value)),
|
|
},
|
|
};
|
|
|
|
export function isEconomicMode(mode) {
|
|
return mode === "gdp" || mode === "population";
|
|
}
|
|
|
|
// Where a value sits on the scale, clamped to 0..1. A flat range (every tile
|
|
// the same) sits in the middle so the map reads as a single mid colour. An
|
|
// optional `scale` maps the values first (the population mode reads its log).
|
|
export function economicFraction(value, min, max, scale = null) {
|
|
if (scale) {
|
|
value = scale(value);
|
|
min = scale(min);
|
|
max = scale(max);
|
|
}
|
|
if (!(max > min)) return 0.5;
|
|
const t = (value - min) / (max - min);
|
|
return Math.max(0, Math.min(1, t));
|
|
}
|
|
|
|
// The colour for a value, as a "#rrggbb" string, interpolated between the two
|
|
// gradient stops that bracket it.
|
|
export function economicColour(value, min, max, stops = ECONOMIC_GRADIENT, scale = null) {
|
|
const t = economicFraction(value, min, max, scale);
|
|
const scaled = t * (stops.length - 1);
|
|
const index = Math.min(stops.length - 2, Math.floor(scaled));
|
|
const blend = scaled - index;
|
|
const a = parseColour(stops[index]);
|
|
const b = parseColour(stops[index + 1]);
|
|
const channel = (i) => Math.round(a[i] + (b[i] - a[i]) * blend);
|
|
return `#${toHex(channel(0))}${toHex(channel(1))}${toHex(channel(2))}`;
|
|
}
|
|
|
|
function toHex(value) {
|
|
return value.toString(16).padStart(2, "0");
|
|
}
|