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.
86 lines
3.5 KiB
JavaScript
86 lines
3.5 KiB
JavaScript
// Combat, garrison and pillage rules. Shared so the server (which applies them)
|
|
// and the browser (which forecasts them) compute the same numbers.
|
|
|
|
// Units garrisoned in a friendly city regain this many hit points each hour.
|
|
export const CITY_GARRISON_HEAL_PER_HOUR = 1;
|
|
|
|
// Combat is fought on a single tile: the attacking stack charges onto the
|
|
// defending stack's tile and the two share it until one side is wiped out.
|
|
// Every day a battle lasts the tile loses this fraction of its population and
|
|
// of its GDP per capita. Once the fighting stops, GDP per capita recovers by
|
|
// `recoveryPerDay` each day, starting `recoveryDelayDays` after the last battle.
|
|
export const BATTLE = {
|
|
populationLossPerDay: 0.3,
|
|
gdpPerCapitaLossPerDay: 0.3,
|
|
recoveryDelayDays: 30,
|
|
recoveryPerDay: 100,
|
|
// Structures on a battlefield take this much damage each day of fighting.
|
|
structureDamagePerDay: 120,
|
|
};
|
|
|
|
// Pillaging: each unit removes this fraction of the tile's remaining
|
|
// population, cuts its GDP per capita by this multiplier, and heals one hit
|
|
// point per this many people driven off.
|
|
export const PILLAGE = {
|
|
populationLoss: 0.1,
|
|
gdpPenalty: 0.7,
|
|
healPerPeople: 1000,
|
|
};
|
|
|
|
// Trenches: infantry dug into a tile are much harder to dislodge, at the cost
|
|
// of the local economy. The defense figures are multipliers on a unit's base
|
|
// defense; melee attackers get no bonus, artillery is heavily blunted.
|
|
export const TRENCH = {
|
|
gdpMultiplier: 0.8,
|
|
meleeDefenseMultiplier: 2.0,
|
|
artilleryDefenseMultiplier: 3.0,
|
|
};
|
|
|
|
// Sustained bombardment: a ground or naval battery ordered onto a target fires
|
|
// one volley every in-game hour. Each volley deals this fraction of the damage
|
|
// a single strike would (attack minus the defender's effective defense), so a
|
|
// unit under fire is worn down over many hours instead of erased in one salvo.
|
|
export const BOMBARD = {
|
|
hourlyDamageFraction: 0.1,
|
|
};
|
|
|
|
// Bombarding a city that has no garrison left: each point of damage kills this
|
|
// many people and leaves the usual battle scar on its tile. A blow can also
|
|
// knock a building down a level; each building rolls its own chance per point
|
|
// of damage, scaled by its `destructionResistance` (wartime shelters resist
|
|
// almost all of it and never shield the rest of the city).
|
|
export const CITY_BOMBARD = {
|
|
populationPerDamage: 10,
|
|
buildingDestructionChancePerDamage: 0.0004,
|
|
};
|
|
|
|
// Aircraft sorties: a plane flies to its target, bombs once, returns to a
|
|
// friendly airport and then cannot strike again for `cooldownHours` (two days).
|
|
// Each attacking aircraft costs `cost` from its nation's budget, charged up
|
|
// front so bombing cannot be spammed for free.
|
|
export const AIR_STRIKE = {
|
|
cost: 10_000_000,
|
|
cooldownHours: 48,
|
|
};
|
|
|
|
// A city's air defense fires one volley at a hostile aircraft the moment it
|
|
// enters the city's tile. Damage scales with the building's level.
|
|
export const AIR_DEFENSE = {
|
|
damagePerLevel: 150,
|
|
};
|
|
|
|
// The result of pillaging a tile with `count` units in sequence, starting from
|
|
// its current population. Each step removes a tenth of what is left and heals
|
|
// for the people it removed; the GDP-per-capita multiplier compounds. Shared so
|
|
// the server and the forecast tooltip compute the same numbers.
|
|
export function pillageSteps(population, count) {
|
|
const steps = [];
|
|
let remaining = population;
|
|
for (let i = 0; i < count; i++) {
|
|
const removed = remaining * PILLAGE.populationLoss;
|
|
remaining -= removed;
|
|
steps.push({ removed, remaining, heal: removed / PILLAGE.healPerPeople });
|
|
}
|
|
return { steps, gdpMultiplier: Math.pow(PILLAGE.gdpPenalty, count) };
|
|
}
|