- 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
3.0 KiB
JavaScript
78 lines
3.0 KiB
JavaScript
// Shared formatting helpers for the modal panels.
|
||
|
||
import { groupDigits } from "../../../shared/text_format.js";
|
||
import { policyById } from "../../../shared/data.js";
|
||
|
||
export function formatEffect(effect, level) {
|
||
const value = level <= 0 ? 0 : effect.baseValue * Math.pow(level, effect.exponent);
|
||
switch (effect.stat) {
|
||
case "gdp":
|
||
return `${value >= 0 ? "+" : ""}${(value * 100).toFixed(1)}% GDP/capita`;
|
||
case "budget_income":
|
||
return `${value >= 0 ? "+" : ""}${(value * 100).toFixed(1)}% tax income`;
|
||
case "research":
|
||
return `${value >= 0 ? "+" : ""}${value.toFixed(2)} research/h`;
|
||
case "culture":
|
||
return `${value >= 0 ? "+" : ""}${value.toFixed(2)} culture/h`;
|
||
case "infantry_attack":
|
||
return `${value >= 0 ? "+" : ""}${(value * 100).toFixed(1)}% infantry attack`;
|
||
case "infantry_defense":
|
||
return `${value >= 0 ? "+" : ""}${(value * 100).toFixed(1)}% infantry defense`;
|
||
case "artillery_attack":
|
||
return `${value >= 0 ? "+" : ""}${(value * 100).toFixed(1)}% artillery attack`;
|
||
case "construction_speed":
|
||
return `${value >= 0 ? "+" : ""}${(value * 100).toFixed(1)}% construction speed`;
|
||
case "rail_speed":
|
||
return `${value >= 0 ? "+" : ""}${(value * 100).toFixed(1)}% railway speed`;
|
||
default:
|
||
return `${effect.stat} ${value.toFixed(2)}`;
|
||
}
|
||
}
|
||
|
||
export function effectsText(effects, level) {
|
||
const parts = effects.map((e) => formatEffect(e, level));
|
||
return parts.length > 0 ? parts.join(" · ") : "No effect";
|
||
}
|
||
|
||
export const SOURCE_LABELS = { building: "building", government: "government", technology: "research" };
|
||
|
||
export function signedMoney(value) {
|
||
return `${value < 0 ? "−" : "+"}€${groupDigits(Math.round(Math.abs(value)))}/h`;
|
||
}
|
||
|
||
export function percent(value) {
|
||
return `${value < 0 ? "−" : "+"}${(Math.abs(value) * 100).toFixed(1)}%`;
|
||
}
|
||
|
||
// Renders one news entry as text, resolving civ indices to names and demonyms.
|
||
export function describeNews(entry, civs) {
|
||
const name = (index) => (civs[index] ? civs[index].name : `Nation ${index + 1}`);
|
||
const people = (index) => {
|
||
const civ = civs[index];
|
||
return civ && civ.demonym ? `The ${civ.demonym}` : name(index);
|
||
};
|
||
switch (entry.type) {
|
||
case "war":
|
||
return `${people(entry.actor)} declared war on ${name(entry.target)}`;
|
||
case "capture":
|
||
return `${people(entry.to)} captured ${entry.city} from ${name(entry.from)}`;
|
||
case "policy": {
|
||
const policy = policyById(entry.policy);
|
||
const policyName = policy ? policy.name : entry.policy;
|
||
const who =
|
||
civs[entry.ethnicity] && civs[entry.ethnicity].demonym
|
||
? `the ${civs[entry.ethnicity].demonym}`
|
||
: name(entry.ethnicity);
|
||
return `${name(entry.civ)} enacted ${policyName} for ${who}`;
|
||
}
|
||
case "technology":
|
||
return entry.repeatable
|
||
? `${name(entry.civ)} improved ${entry.name}`
|
||
: `${name(entry.civ)} discovered ${entry.name}`;
|
||
case "join":
|
||
return `${entry.player} took control of ${name(entry.civ)}`;
|
||
default:
|
||
return entry.type;
|
||
}
|
||
}
|