Modifier Bundles
What this is
Modifier bundles are the non-damage entries in the level-up modifier pool. Each is a single ModifierTypeDef in data/modifiers.ts whose effects[] lists one or more ModifierEffect rows, each carrying a stat, a mode (flat or percent), a base, and a scaling exponent k. Picking a bundle increments game.upgradeCounts[modId], then _applyModifierPick in engine/world/leveling.ts calls getModifierValue(eff, currentLvl) and registers the result through Modifiers.add with source level_up:<modId>:<stat> and duration 0 (permanent). HP/Shield maxes are settled by Modifiers.recalc immediately after, and current HP/shield are bumped by the gained max delta so the pick is not a free full heal.
Three bundles touch multiple stats at once (Health, Shield, Speed) — these are the historical “bundled horizontals” that combine pool, regen, and handling stats per pick. The remaining ten are single-stat picks that act as dedicated build pillars (Heat, Magnet, XP, Luck, Vitality, Bulwark, Charge, Overshield, Leech, Thrust). Damage modifiers are documented separately under horizontal-modifiers and are not covered here.
A pick’s effective value is also multiplied by the card’s rarityMult at apply time, so a legendary pick of the same modifier delivers a larger increment than a common pick. Rarity multipliers are not baked into the per-rank tables below.
The bundles
| id | name | rarity | category | max rank | stats touched |
|---|---|---|---|---|---|
| health | Health | common | defense | 20 | hpMax, damageReduction, hpRegen |
| shield | Shield | uncommon | defense | 20 | shieldMax, shieldRegenRate, shieldRegenDelay |
| speed | Speed | common | utility | 20 | thrust, drag, maxSpeed |
| heat | Heat | uncommon | utility | 20 | heatBurnRate |
| magnet | Magnet | common | utility | 20 | magnetRange |
| xp_gain | XP Gain | common | utility | 20 | xpGainMult |
| luck | Luck | common | utility | 20 | luckMult |
| vitality | Vitality | uncommon | defense | 20 | hpRegen |
| bulwark | Bulwark | uncommon | defense | 20 | damageReduction |
| charge | Charge | uncommon | defense | 20 | shieldRegenRate |
| overshield | Overshield | uncommon | defense | 20 | shieldMax |
| leech | Leech | rare | offense | 20 | lifeSteal |
| thrust | Thrust | uncommon | utility | 20 | thrust |
k-mode scaling math
getModifierValue(effect, level) in data/modifiers.ts reads effect.k and returns one of four values:
| k | mode name | formula | meaning |
|---|---|---|---|
| -1 | flat | base | constant per pick; every rank delivers the same increment |
| 0 | front-loaded harmonic | base * 5 / level | big rank-1 increment, diminishing per rank |
| 1 | linear | base * level | back-loaded; rank N delivers N times the rank-1 increment |
| >1 | legacy diminishing | base + perLevel * level / (level + k) | asymptotic, legacy field — not used by any current bundle |
Every non-damage modifier bundle currently in MODIFIER_TYPES uses k = -1. Each rank adds the same amount, so cumulative total at level L is base * L * rarityMult for that stat. Mode (flat vs percent) controls how the value is consumed by the modifier system — percent adds to a multiplier (final stat = base * (1 + sum_of_percents)), flat adds to the stat directly.
Drag uses a negative percent base, so the multiplier 1 + sumPct falls toward 0 as ranks accumulate. At rank 10 of Speed the drag multiplier is exactly 0, clamped non-negative by Math.max(0, 1 + sumPct) in engine/core/modifiers.ts.
Per-bundle per-rank values
All values shown are getModifierValue(effect, 1) — the per-pick increment. Because every bundle is k = -1, the rank-L total is exactly L * per-pick. Multiply by the pick’s rarityMult (1.0 common → 2.0 legendary) for actual applied magnitude.
Multi-stat bundles
| Bundle | Stat | Mode | Per rank | At L20 |
|---|---|---|---|---|
| Health | hpMax | percent | +15% | +300% |
| Health | damageReduction | flat | +0.75 | +15 |
| Health | hpRegen | flat | +0.5 HP/s | +10 HP/s |
| Shield | shieldMax | percent | +15% | +300% |
| Shield | shieldRegenRate | percent | +7.5% | +150% |
| Shield | shieldRegenDelay | percent | -4.5% | -90% |
| Speed | thrust | percent | +30% | +600% |
| Speed | drag | percent | -10% | clamped 0 at L10+ |
| Speed | maxSpeed | percent | +30% | +600% |
Single-stat bundles
| Bundle | Stat | Mode | Per rank | At L20 |
|---|---|---|---|---|
| Heat | heatBurnRate | percent | -7.5% | -150% |
| Magnet | magnetRange | flat | +40 units | +800 units |
| XP Gain | xpGainMult | flat | +0.04 | +0.80 |
| Luck | luckMult | flat | +0.10 | +2.00 |
| Vitality | hpRegen | flat | +1.0 HP/s | +20 HP/s |
| Bulwark | damageReduction | flat | +2.0 | +40 |
| Charge | shieldRegenRate | percent | +12% | +240% |
| Overshield | shieldMax | percent | +25% | +500% |
| Leech | lifeSteal | flat | +0.005 (0.5%) | +0.10 (10%) |
| Thrust | thrust | percent | +50% | +1000% |