Named the actors behind government news

This commit is contained in:
2026-09-21 13:49:42 +02:00
parent 2005cac7f7
commit 75bddddb7f
2 changed files with 62 additions and 10 deletions
+18 -7
View File
@@ -70,18 +70,29 @@ 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.
// Renders one news entry as text. Government actions name the specific actors
// doing them — "French troops", "French scientists" — rather than the nation as
// a whole, and the victim or target is named in the people's form ("the
// Vietnamese").
export function describeNews(entry, civs) {
const name = (index) => (civs[index] ? civs[index].name : `Nation ${index + 1}`);
// The attributive form of a nation, for putting before an actor noun. It
// falls back to the demonym, which doubles as an adjective for most of them;
// the few person-nouns (New Zealander, New Hampshirite) carry an explicit one.
const adjective = (index) => {
const civ = civs[index];
if (!civ) return `Nation ${index + 1}`;
return civ.adjective || civ.demonym || civ.name;
};
const people = (index) => {
const civ = civs[index];
return civ && civ.demonym ? `The ${civ.demonym}` : name(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)}`;
return `${adjective(entry.actor)} leaders have declared war on ${name(entry.target)}`;
case "capture":
return `${people(entry.to)} captured ${entry.city} from ${name(entry.from)}`;
return `${adjective(entry.to)} troops have captured ${entry.city} from ${people(entry.from)}`;
case "policy": {
const policy = policyById(entry.policy);
const policyName = policy ? policy.name : entry.policy;
@@ -89,12 +100,12 @@ export function describeNews(entry, civs) {
civs[entry.ethnicity] && civs[entry.ethnicity].demonym
? `the ${civs[entry.ethnicity].demonym}`
: name(entry.ethnicity);
return `${name(entry.civ)} enacted ${policyName} for ${who}`;
return `${adjective(entry.civ)} lawmakers have enacted ${policyName} for ${who}`;
}
case "technology":
return entry.repeatable
? `${name(entry.civ)} improved ${entry.name}`
: `${name(entry.civ)} discovered ${entry.name}`;
? `${adjective(entry.civ)} scientists have improved ${entry.name}`
: `${adjective(entry.civ)} scientists have discovered ${entry.name}`;
case "join":
return `${entry.player} took control of ${name(entry.civ)}`;
default:
+44 -3
View File
@@ -1,7 +1,7 @@
import { TestCase } from "./framework/test_case.js";
import { setupDom, teardownDom } from "./framework/dom.js";
import { CityModal, NationModal, ConfirmModal, NewsModal } from "../client/js/modals.js";
import { buildingEffectText } from "../client/js/modals/format.js";
import { buildingEffectText, describeNews } from "../client/js/modals/format.js";
import { BUILDINGS, GOVERNMENTS, TECHNOLOGIES, PROTO_UNITS } from "../shared/data.js";
export class CityModalTest extends TestCase {
@@ -640,9 +640,13 @@ export class NewsModalTest extends TestCase {
modal.show(news, civs);
const items = env.$("#news-list .news-item");
this.assertSize(items, 2);
this.assertTrue(items.eq(0).find(".news-text").text().includes("The French captured Lyon from Britain"));
this.assertTrue(
items.eq(0).find(".news-text").text().includes("French troops have captured Lyon from the British")
);
this.assertTrue(items.eq(0).find(".news-date").text().includes("05:00"));
this.assertTrue(items.eq(1).find(".news-text").text().includes("The French declared war on Britain"));
this.assertTrue(
items.eq(1).find(".news-text").text().includes("French leaders have declared war on Britain")
);
modal.refresh([], civs);
this.assertEqual(env.$("#news-list .news-item").length, 0);
@@ -653,4 +657,41 @@ export class NewsModalTest extends TestCase {
teardownDom(env);
}
}
test_news_names_the_actors_doing_the_action() {
const civs = [
{ name: "France", demonym: "French" },
{ name: "Vietnam", demonym: "Vietnamese" },
{ name: "Aotearoa", demonym: "New Zealander", adjective: "New Zealand" },
];
this.assertEqual(
describeNews({ type: "capture", city: "Saigon", from: 1, to: 0 }, civs),
"French troops have captured Saigon from the Vietnamese"
);
this.assertEqual(
describeNews({ type: "technology", civ: 0, name: "Radio" }, civs),
"French scientists have discovered Radio"
);
this.assertEqual(
describeNews({ type: "technology", civ: 0, name: "Railways", repeatable: true }, civs),
"French scientists have improved Railways"
);
this.assertEqual(
describeNews({ type: "war", actor: 0, target: 1 }, civs),
"French leaders have declared war on Vietnam"
);
this.assertEqual(
describeNews({ type: "policy", civ: 0, policy: "some_policy", ethnicity: 1 }, civs),
"French lawmakers have enacted some_policy for the Vietnamese"
);
this.assertEqual(
describeNews({ type: "join", player: "Alice", civ: 1 }, civs),
"Alice took control of Vietnam"
);
// Person-noun demonyms carry an explicit attributive form.
this.assertEqual(
describeNews({ type: "technology", civ: 2, name: "Radio" }, civs),
"New Zealand scientists have discovered Radio"
);
}
}