Terraforming¶
✅ Shipped — five-level project ladder, flat-column persistence, habitability-points model.
Long-term improvements to existing colonies' habitability. Distinct from Genesis Devices (which create planets — see galaxy/genesis-devices.md).
The model is habitability points, not growth percentages: each level adds a fixed integer to Planet.habitability_score (0–100), and habitability drives population cap, growth multiplier, and morale through a single shared formula in planetary_service.get_habitability_effects. See ADR-0002 for the design rationale.
Five-level project ladder¶
Authoritative source: services/gameserver/src/services/terraforming_service.py:TERRAFORMING_LEVELS.
| Level | Name | Cost (cr) | Duration (h) | Habitability boost | Organics | Equipment |
|---|---|---|---|---|---|---|
| 1 | Basic Atmospheric | 100,000 | 72 | +10 | 500 | 200 |
| 2 | Climate Stabilization | 250,000 | 120 | +15 | 1,500 | 500 |
| 3 | Ecosystem Seeding | 500,000 | 168 | +20 | 3,000 | 1,000 |
| 4 | Biome Engineering | 1,000,000 | 240 | +25 | 5,000 | 2,000 |
| 5 | Full Terraformation | 2,000,000 | 336 | +30 | 10,000 | 5,000 |
Boost is applied as a single integer addition to habitability_score, capped at TERRAFORMING_MAX_HABITABILITY = 100.
Resource sourcing: organics and equipment are drawn from the planet's own stockpile (Planet.organics, Planet.equipment) — not from the player's ship cargo. The level cannot start if either stock is below the requirement. Credits are deducted from the player.
Levels are independent, not sequential. The code does not enforce "Level 2 requires Level 1 complete" or any citadel-level prerequisite. Any owned planet below the skip threshold can start any level if resources are available.
Mechanics¶
services/terraforming_service.py:start_terraforming:
- Verify planet is owned by the player.
- Verify
habitability_score < TERRAFORMING_MIN_TARGET(90). - Verify no terraforming already active on the planet.
- Verify player credits and planet stockpile cover the level's recipe.
- Deduct credits from player; deduct organics + equipment from planet stockpile.
- Set
Planet.terraforming_active = True,terraforming_target,terraforming_start_time,terraforming_progress = 0.0,status = TERRAFORMING. - Push a metadata entry into the planet's
active_eventsJSONB list with shape{type: "terraforming", level, level_name, credit_cost, organics_cost, equipment_cost, habitability_boost, duration_hours, started_at, start_habitability, last_tick_at}. The two trailing fields support lazy tick advancement:start_habitabilityrecords the score at project start (used by cancellation to revert), andlast_tick_atis the timestamp the lazy reader divides againstTICK_PERIODto compute due ticks.
Tick-based progression¶
✅ Shipped — lazy advance-on-read. process_terraforming_tick(planet_id) advances habitability by 1–3 points, scaled by population:
- Base increment:
TERRAFORMING_BASE_INCREMENT = 1. - Population bonus:
+1perTERRAFORMING_POPULATION_SCALE = 1000colonists/population. - Cap:
TERRAFORMING_MAX_INCREMENT = 3.
So a planet with ≥ 2,000 population terraforms at the maximum 3 points/tick; a planet with < 1,000 progresses at the minimum 1 point/tick.
Rather than a background scheduler, ticks are applied lazily when terraforming status is read: the wall time elapsed since the last tick is divided by the tick period, and the resulting number of due ticks is applied in one pass before the status is returned. The tick period derives from the level's documented duration so that a minimum-speed (< 1,000 pop) planet finishes in exactly the level's duration_hours, while a populous planet (up to the 3-points/tick cap) finishes up to 3× faster: TICK_PERIOD = duration_hours / total_points, where total_points is the level's habitability boost. This derivation is canon (blessed by Max 2026-06-14).
Completion¶
_complete_terraforming runs when habitability_score reaches terraforming_target:
- Apply the level's
habitability_boost(capped at 100). - Recompute
max_population = habitability_score × 1,000(canonical formula, see./colonization.md#population-capacity). The recompute is a fresh evaluation of the formula, not a multiplicative shrink of the current value — terraforming raises habitability and therefore raises the cap.max_colonistsis not touched here; it is citadel-bound, not habitability-bound. - Floor
population_growthat: - 2.0 if habitability ≥ 80,
- 1.5 if habitability ≥ 60,
- 1.0 if habitability ≥ 40.
- Clear
terraforming_active,terraforming_target,terraforming_start_time; setterraforming_progress = 100.0. - Remove the terraforming entry from
active_events. - Set
status = COLONIZED(if populated) orHABITABLE(if empty).
Cancellation¶
TERRAFORMING_CANCEL_REFUND = 0.50 — cancelling a project refunds 50% of the credit cost. Organics and equipment are not refunded (treated as consumed in-process). Cancellation also reverts habitability_score to start_habitability (the value recorded at project start), so any habitability gained from lazy ticks before the cancel is rolled back. This is an anti-arbitrage measure: without the revert, a player could repeatedly start, let a few ticks bank habitability, then cancel for the 50% refund and keep the gains.
Skip threshold¶
Planets with habitability_score ≥ 90 (TERRAFORMING_MIN_TARGET) cannot start a new project — start_terraforming raises.
Habitability effects¶
planetary_service.get_habitability_effects:
effective_max_colonists = base_max_colonists * (habitability / 100).growth_multiplier = habitability / 100(applied to base growth).morale_bonus = +1per 10 habitability above 50.
Population growth in _calculate_production: colonist_rate = colonists * 0.01 * (habitability / 100) per day.
This is how habitability points translate to the growth-rate intuition. A Level 1 terraform on a starting-habitability-50 planet (+10 → 60) raises the growth multiplier from 0.50 to 0.60, a 20% relative increase. A Level 5 from 50 to 80 takes it from 0.50 to 0.80, a 60% relative increase.
Planet model state¶
The terraforming columns on planets (added in migration b2c3d4e5f6a7_add_terraforming_columns_to_planets):
| Column | Type | Purpose |
|---|---|---|
terraforming_active |
Boolean | Project is in progress. |
terraforming_target |
Integer (nullable) | Target habitability score for the active project. |
terraforming_start_time |
DateTime (nullable) | When the active project began. |
terraforming_progress |
Float | 0.0–100.0, percentage of target reached. |
Per-level metadata (cost, boost, duration, level name) lives in the planet's active_events JSONB column under a {type: "terraforming"} entry, along with the two tick-support fields start_habitability and last_tick_at. There is no separate terraforming_projects table — see ADR-0002. Multiple concurrent projects on a single planet are not representable.
Planet types¶
The full enum is in DATA_MODELS/planets.md (12 values: TERRA, MOUNTAINOUS, OCEANIC, DESERT, VOLCANIC, BARREN, ICE, JUNGLE, ARCTIC, TROPICAL, GAS_GIANT, ARTIFICIAL). The seven types in active gameplay use, with their per-type production multipliers, storage caps, base growth rates, and habitability ranges, are catalogued in colonization.md.
JUNGLE, ARCTIC, TROPICAL, GAS_GIANT, and ARTIFICIAL are present in the enum but have no production-multiplier definitions in colonization.md. Treat them as design-only until those biomes are specified.
📐 Design-only — planet-type reclassification. The legacy design specified that completing Level 5 may upgrade a hostile planet's type (BARREN → VOLCANIC, ICE → DESERT). The implemented _complete_terraforming does not modify planet.type; only habitability_score changes. If reclassification becomes desired again, the rule belongs in _complete_terraforming and would need a deliberate ADR amendment.
🚧 Partial — cost scaling at high habitability. The level's credit cost scales by the planet's current habitability: ×1.25 above 40, ×1.5 above 70 (TERRAFORMING_COST_SCALE_LOW / TERRAFORMING_COST_SCALE_HIGH in terraforming_service.py, bands inclusive-exclusive — "above N" is strictly greater than N). The ×2.0-above-90 band is moot because the skip threshold at 90 (TERRAFORMING_MIN_TARGET) blocks new projects there. Organics and equipment costs are not scaled.
📐 Design-only — Terraform Engineers profession. The legacy PLANETARY_COLONIZATION.md design includes a Terraform Engineers profession (training queue, monthly progress driven by engineer count, scaling resource costs). No profession system exists in code today. The current model derives tick speed from total population, not specialised engineers.
Strategic considerations¶
- Early game: prefer Genesis Devices for new planets — much cheaper than full terraforming an existing hostile world.
- Mid game: Level 1–2 terraform on M/L/O-Class planets to lift habitability into the 60–80 band where the growth multiplier and morale bonus compound.
- Late game: Level 5 to push strategically-located worlds (e.g. a Barren planet on a critical trade route) toward 100 habitability, unlocking maximum population cap and growth.
ROI sketch:
- Advanced Genesis (250,000 cr per ADR-0012, plus the sacrificed Colony Ship hull at ~500,000 cr per ADR-0013) → ~30 days to break-even on Settlement-phase production.
- Full sequence Level 1 → 5 (3,850,000 cr + 20,000 organics + 8,700 equipment) → ~180 days to break-even on a rescued Barren world (capped at 100 habitability, but the climb from 0 takes the full ladder).
The terraform path makes sense only when the planet's location justifies the long payoff.
Player-facing affordances¶
- Terraforming panel per planet showing current habitability, active project, time remaining, expected boost.
- Cost preview before starting (credits + planet-stockpile organics + planet-stockpile equipment).
- Cancel button surfacing the 50%-credits refund warning and that resources are not refunded.
- Empire view showing terraforming progress across all owned planets.
Source map¶
| Topic | Path |
|---|---|
| Terraforming service | services/gameserver/src/services/terraforming_service.py |
| Habitability effects on capacity / growth / morale | services/gameserver/src/services/planetary_service.py:get_habitability_effects |
| Per-day colonist growth | services/gameserver/src/services/planetary_service.py:_calculate_production |
| Planet model | services/gameserver/src/models/planet.py |
| Terraforming columns migration | services/gameserver/alembic/versions/b2c3d4e5f6a7_add_terraforming_columns_to_planets.py |
| Genesis (related) | services/gameserver/src/services/genesis_service.py |
| Planet API | services/gameserver/src/api/routes/planets.py |
| Admin terraforming view | services/gameserver/src/api/routes/admin_colonization.py |
| Design rationale | ADR/0002-terraforming-formula-model.md |