HP Regen System
ship.hpRegen is the rate (HP per second) at which the player’s hull self-repairs back toward ship.hpMax during a run. It’s the slow, always-on sustain stream that complements the burstier shield-recovery cycle and the spike-style heals (life steal, regen stations, pickups).
The stat
hpRegen lives directly on ShipState alongside hp and hpMax:
// engine/core/state.ts (makeShip)
hp: 80,
hpMax: 80,
hpRegen: 0,The starting ship rolls in with hpRegen: 0 — no passive healing until something scales it up. The field is typed on ShipState in engine/core/types.ts and is one of the canonical combat stats sourced from RunDefinition.ship.combatStats at run start (engine/bridge.ts writes ship.hpRegen = cs.hpRegen alongside hpMax, shieldMax, etc.).
Per-ship base values are authored in data/ships.ts (every ship in the catalog ships hpRegen: 0 by default; specific ship variants and stat overrides bump it up).
Application
Regen accrues during normal gameplay and tops the hull bar up toward hpMax. The cap is hard: regen never overheals — once ship.hp >= ship.hpMax the stream is wasted. Other heal sources (life steal, regen stations, capsule pickups) all clamp the same way:
// engine/combat/damage.ts — life steal example, same clamp pattern
if (ship.lifeSteal > 0) {
const healAmt = rawDmg * ship.lifeSteal;
ship.hp = Math.min(ship.hpMax, ship.hp + healAmt);
}// engine/bridge.ts — regen station inside-zone heal
if (ship.hp < ship.hpMax) {
ship.hp = Math.min(ship.hpMax, ship.hp + ship.hpMax * 0.01 * dt);
}Distinct from shield regen
The two regen systems share a name but are wholly separate machines.
| Stat | Mechanic |
|---|---|
shieldRegenRate | Fills the shield 0 → shieldMax after shieldRegenDelay seconds of no damage. Timer resets on any hit (ship.shieldRegenTimer = ship.shieldRegenDelay in damagePlayer). Shield only fills uninterrupted: in-progress regen is cancelled by a hit (ship._shieldBackgroundRegen = 0). |
hpRegen | Direct HP/sec stream, no delay state. There is no hpRegenDelay, hpRegenTimer, or “no-damage timer” on the hull side — the only timer-gated regen system is the shield’s. |
Practically: shield regen is a post-combat refill with a punishing delay; HP regen is a constant trickle that ticks during combat too. Both clamp at their respective maxes and neither bleeds into the other (shield is never a buffer for HP, and HP regen never spills into shield).
How the value scales
ship.hpRegen starts at whatever the run’s chosen ship rolls (default 0 for the baseline ship) and is bumped by level-up rewards.
Health bundle (common, defense)
The health modifier ships a small regen primer alongside HP-pool and DR:
// data/modifiers.ts — id: 'health'
{ stat: 'hpRegen', mode: 'flat', base: 0.5, perLevel: 0, k: -1 },k: -1 (flat per rank): +0.5 HP/s every Health pick. At L20 that’s +10 HP/s from the bundle. Health’s identity is “pool + armor” — the regen primer is a sweetener so the picks feel like more than just bar inflation.
Vitality (uncommon, defense)
The dedicated sustained-healing modifier:
// data/modifiers.ts — id: 'vitality'
{ stat: 'hpRegen', mode: 'flat', base: 1.0, perLevel: 0, k: -1 },+1.0 HP/s per rank, +20 HP/s at L20. Uncommon rarity puts Vitality one tier above Health, so the dedicated regen build path costs slightly rarer rolls. Vitality complements Health rather than replacing it — Health gives the bigger pool to soak into, Vitality gives the faster refill.
Other sources
- Ship variants: specific ships in
data/ships.tscan authorhpRegenbaselines above 0. - Passives:
Void Siphon(per the passives table) restores HP per second at flat rates per tier. - Test scaffolding: perf-test mode and the
vitality_surgeartifact scenario inengine/testing/sethpRegen: 15/hpRegen: 3for stress runs.
All sources stack additively into ship.hpRegen via the central modifier aggregation pass.
Build implications
- Tanky pool-and-armor build — stack Health: bigger bar to bleed against, +0.5/rank trickle keeps the bar from staying low forever.
- Dedicated regen build — Vitality first, Health second. The +1.0/rank rate is fast enough that mid-combat sustain becomes real, not just between-fight cleanup.
- No “between-fight” gate — unlike shield, HP regen doesn’t punish you for staying in danger. You don’t have to disengage for X seconds to start refilling.
- Capped by
hpMax— overhealing is wasted output. Pair regen with a big pool (Health) or with damage avoidance (DR / dodge) so the trickle has somewhere to go. - Doesn’t break kill streaks — only hull damage breaks the streak. Regen filling the bar back up doesn’t affect streak state.
Reading
src/starship-survivors/engine/core/state.ts—makeShip()initial value.src/starship-survivors/engine/core/types.ts—ShipState.hpRegendeclaration.src/starship-survivors/engine/bridge.ts— run-start application fromRunDefinition.src/starship-survivors/engine/combat/damage.ts—damagePlayer(no hpRegen reset; shield-side reset only).src/starship-survivors/data/modifiers.ts—healthandvitalitymodifier definitions.src/starship-survivors/data/ships.ts— per-shiphpRegenbaselines.