Files
Battle-for-Tismo/shared/data/technologies.js
T
adrien bd9b206708 Gave the new buildings real effects
The catalogue had grown a barracks, wartime shelters, an air-defense
battery, a warm-water port and a shipyard, but only as data: infantry
still trained without a barracks, shelters did nothing, and an airport was
just an airbase. Each building now names the rule it grants with a
`mechanic` id, so the simulation and the city panel describe the same
thing without magic strings.

- Barracks and shipyards open one more production line each. A line sticks
  to one entry at full rate, so two units build at once rather than the
  head absorbing every line; the base behaviour (one queue, overflow
  carrying into the next entry) is unchanged.
- Wartime shelters keep 10% of civilians per level safe from bombardment
  and are very hard to knock down, and ranged fire can now destroy a
  building level outright, with no refund. Each building rolls its own
  chance per point of damage, from a generator seeded off the world so a
  bombardment replays identically.
- Air defense fires one volley at a hostile aircraft the moment it enters
  the city tile, scaled by its level; a plane shot down never drops its
  bombs.
- A port adds 1000 GDP per capita per level, per adjacent sea tile, to
  every tile in its region.
- An airport draws a daily trickle of people from every other airport city
  in the world, scaled by the destination's level.
- Wired the new effects into the city panel and taught the repeatable
  Industrial Automation to satisfy other technologies' prerequisites.

Added tests for each mechanic and for the parallel lines.
2026-09-21 11:38:01 +02:00

149 lines
4.8 KiB
JavaScript

// Research tree. A technology costs research points and may require earlier
// technologies before it can be started.
//
// Research is focused: a nation picks one technology, and every research point
// it creates is applied to it, month on month, until it is discovered. A
// `repeatable` technology may be researched again and again, each level costing
// `repeatCostGrowth` more than the last, and unlike a discovery it raises no
// news event (it only notifies the player).
import {
EFFECT_GDP,
EFFECT_BUDGET_INCOME,
EFFECT_RESEARCH,
EFFECT_CULTURE,
EFFECT_INFANTRY_ATTACK,
EFFECT_INFANTRY_DEFENSE,
EFFECT_ARTILLERY_ATTACK,
EFFECT_CONSTRUCTION_SPEED,
EFFECT_RAIL_SPEED,
effect,
} from "./effects.js";
// The tabs the technology panel groups research under.
export const TECH_THEMES = [
{ id: "science", name: "Science" },
{ id: "economy", name: "Economy" },
{ id: "society", name: "Society" },
{ id: "military", name: "Military" },
];
export const TECHNOLOGIES = [
{
id: "scientific_method",
name: "Scientific Method",
description: "A disciplined approach to experiment and evidence. Lays the groundwork for every later technology.",
theme: "science",
cost: 20,
prerequisites: [],
effects: [effect(EFFECT_RESEARCH, 1.0, 1.0), effect(EFFECT_GDP, 0.02, 1.0)],
},
{
id: "industrial_automation",
name: "Industrial Automation",
description: "Robotics and control systems take over the factory floor, lifting national output.",
theme: "economy",
repeatable: true,
cost: 60,
prerequisites: ["scientific_method"],
effects: [effect(EFFECT_GDP, 0.08, 1.0)],
},
{
id: "renewable_energy",
name: "Renewable Energy",
description: "Clean generation cuts waste and strengthens the public finances.",
theme: "economy",
cost: 80,
prerequisites: ["scientific_method"],
effects: [effect(EFFECT_GDP, 0.03, 1.0), effect(EFFECT_BUDGET_INCOME, 0.05, 1.0)],
},
{
id: "quantum_computing",
name: "Quantum Computing",
description: "Machines that reason in superposition. A step change in the pace of discovery.",
theme: "science",
cost: 120,
prerequisites: ["scientific_method"],
effects: [effect(EFFECT_RESEARCH, 4.0, 1.0)],
},
{
id: "space_program",
name: "Space Program",
description: "Reaching orbit inspires the nation and spins off technology across the economy.",
theme: "science",
cost: 300,
prerequisites: ["industrial_automation", "quantum_computing"],
effects: [effect(EFFECT_CULTURE, 3.0, 1.0), effect(EFFECT_GDP, 0.05, 1.0)],
},
// Repeatable levels. Each raises a single stat by 1% of its base value.
{
id: "infantry_weapons",
name: "Infantry Weapons",
description: "Better small arms and training raise the damage infantry deal.",
theme: "military",
cost: 40,
repeatable: true,
repeatCostGrowth: 0.02,
prerequisites: ["scientific_method"],
effects: [effect(EFFECT_INFANTRY_ATTACK, 0.01, 1.0)],
},
{
id: "body_armour",
name: "Body Armour",
description: "Personal protection raises infantry base defense.",
theme: "military",
cost: 40,
repeatable: true,
repeatCostGrowth: 0.02,
prerequisites: ["scientific_method"],
effects: [effect(EFFECT_INFANTRY_DEFENSE, 0.01, 1.0)],
},
{
id: "artillery_shells",
name: "Artillery Shells",
description: "Improved propellant and shells raise the damage artillery deal.",
theme: "military",
cost: 50,
repeatable: true,
repeatCostGrowth: 0.02,
prerequisites: ["scientific_method"],
effects: [effect(EFFECT_ARTILLERY_ATTACK, 0.01, 1.0)],
},
{
id: "construction_technology",
name: "Construction Technology",
description: "Better methods and machines speed every building and unit the nation produces.",
theme: "economy",
cost: 50,
repeatable: true,
repeatCostGrowth: 0.02,
prerequisites: ["scientific_method"],
effects: [effect(EFFECT_CONSTRUCTION_SPEED, 0.01, 1.0)],
},
{
id: "trains_technology",
name: "Trains Technology",
description: "Faster locomotives raise movement speed along railways.",
theme: "economy",
cost: 50,
repeatable: true,
repeatCostGrowth: 0.02,
prerequisites: ["scientific_method"],
effects: [effect(EFFECT_RAIL_SPEED, 0.01, 1.0)],
},
];
export function technologyById(id) {
return TECHNOLOGIES.find((t) => t.id === id) || null;
}
// The cost of the next level of a technology given how many times it has been
// researched already. Non-repeatable technologies cost the same either way.
export function technologyCost(proto, repeatCount = 0) {
if (!proto) return 0;
if (!proto.repeatable) return proto.cost;
const growth = proto.repeatCostGrowth || 0;
return proto.cost * Math.pow(1 + growth, Math.max(0, repeatCount));
}