Files
adrien d5305da449 Gave the world a simple economy: one pool per nation and a global market
The simple economy is now the default and the old simulation is frozen as the hard model, selectable per game. A nation keeps one resource pool available in every region, fed by public production works rather than private per-region stores, and construction and training begin at once, paced by the region's spare power instead of gathering materials over days.

Money is euro only: a per-inhabitant daily tax funds a treasury spent in a global market, where buy and sell lots trade against the world stock and move its price. The hard economy keeps its per-nation currencies, central banks and exchange rates.

Simple games skip the price-settling warmup and economic migration; the snapshot carries the economy model, the market and the pool figures the client draws. Added the matching test suites and the design briefs under docs/simple_economy.
2026-09-25 14:58:49 +02:00

3.7 KiB

08 — No economic migrations

Depends on: 01-.

Goal

The simple economy has no economic migrations: people do not move between regions chasing income/GDP.

Current behaviour (hard economy)

shared/game_state/politics.js runs a daily migration tick inside _tickPolitics (_tickMigration) that mixes several drivers:

  • Economic / income-chasing flows. Destinations are chosen by income ratio against the origin (MIGRATION.incomeRatioBase, incomeTimePenalty, incomeSharePerDay, incomeGapCap, incomeMaxSharePerDay), plus a daily "equalize" pass over regions (MIGRATION.equalizePasses, equalizeTolerance, minRegionPopulation).
  • Political / policy flows. Expelling people, encouraging immigration (POLICY_IMMIGRATION), war-crime expulsion, airport-driven immigration (BUILDING_MECHANIC.AIR_IMMIGRATION), comfort thresholds.
  • Natural population growth is separate (_tickPopulation).

shared/data/politics.js holds the MIGRATION constants.

Target behaviour

  • In simple mode, disable economic migration only: the income-ratio flows and the equalize pass must not run, so a region's population changes only through natural growth and explicit non-economic effects.
  • Decision to settle first — do non-economic flows stay?
    • Option A (recommended): keep political/policy movement (expel, immigration policy, airports) because it is not "economic"; only strip the income-chasing and equalize passes.
    • Option B: no inter-region migration at all in simple mode (only natural growth), which is the simplest reading of "no economic migrations" but also removes political migration. Confirm with the user before implementing.
  • Keep _tickMigration and all constants intact for hard; gate the economic portion with !isSimpleEconomy().
  • Keep the migration snapshot fields (migrations, migrationGraph) valid: in simple mode with no flows they should be empty rather than undefined, so the client's setMigrationGraph does not regress.

Files

  • shared/game_state/politics.js — _tickMigration and the income/equalize helpers.
  • shared/game_state/simple_economy.js — an override that runs only the non-economic part (if Option A) or a no-op population pass (Option B).
  • shared/game_state/serialization.js — ensure empty migrations / migrationGraph.
  • tests/politics_test.js — keep hard tests; add a simple-mode case asserting no income-driven flows.

Acceptance criteria

  • In simple mode, two regions with very different income do not exchange people over many ticks.
  • Natural population growth still happens.
  • The snapshot's migration fields are present and empty (or policy-only), not missing.
  • Hard economy migration tests pass unchanged.

Notes / decisions

  • The word "economic" is the key ambiguity; record which option was chosen in this file once decided.
  • Decision: Option A. The simple economy retires only the two income-driven mechanisms: _migrateForIncome (the daily income-ratio sweep) and _equalizeRegionIncomes (the start-of-game levelling). Both are overridden to no-ops in shared/game_state/simple_economy.js. Political migration is kept unchanged (_tickMigration: expel, immigration policy, airport traffic), so the "policy-only" migration snapshot fields are valid and empty only when no policy or airport is moving anyone.
  • No change was needed in shared/game_state/serialization.js: migrations and migrationGraph are already initialised in _resetCollections/ _initPolitics and serialise as empty lists.
  • If Option B is chosen, note that the population/ethnicity UI and migrationGraph rendering become inert but must not error.