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

idnameraritycategorymax rankstats touched
healthHealthcommondefense20hpMax, damageReduction, hpRegen
shieldShielduncommondefense20shieldMax, shieldRegenRate, shieldRegenDelay
speedSpeedcommonutility20thrust, drag, maxSpeed
heatHeatuncommonutility20heatBurnRate
magnetMagnetcommonutility20magnetRange
xp_gainXP Gaincommonutility20xpGainMult
luckLuckcommonutility20luckMult
vitalityVitalityuncommondefense20hpRegen
bulwarkBulwarkuncommondefense20damageReduction
chargeChargeuncommondefense20shieldRegenRate
overshieldOvershielduncommondefense20shieldMax
leechLeechrareoffense20lifeSteal
thrustThrustuncommonutility20thrust

k-mode scaling math

getModifierValue(effect, level) in data/modifiers.ts reads effect.k and returns one of four values:

kmode nameformulameaning
-1flatbaseconstant per pick; every rank delivers the same increment
0front-loaded harmonicbase * 5 / levelbig rank-1 increment, diminishing per rank
1linearbase * levelback-loaded; rank N delivers N times the rank-1 increment
>1legacy diminishingbase + 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

BundleStatModePer rankAt L20
HealthhpMaxpercent+15%+300%
HealthdamageReductionflat+0.75+15
HealthhpRegenflat+0.5 HP/s+10 HP/s
ShieldshieldMaxpercent+15%+300%
ShieldshieldRegenRatepercent+7.5%+150%
ShieldshieldRegenDelaypercent-4.5%-90%
Speedthrustpercent+30%+600%
Speeddragpercent-10%clamped 0 at L10+
SpeedmaxSpeedpercent+30%+600%

Single-stat bundles

BundleStatModePer rankAt L20
HeatheatBurnRatepercent-7.5%-150%
MagnetmagnetRangeflat+40 units+800 units
XP GainxpGainMultflat+0.04+0.80
LuckluckMultflat+0.10+2.00
VitalityhpRegenflat+1.0 HP/s+20 HP/s
BulwarkdamageReductionflat+2.0+40
ChargeshieldRegenRatepercent+12%+240%
OvershieldshieldMaxpercent+25%+500%
LeechlifeStealflat+0.005 (0.5%)+0.10 (10%)
Thrustthrustpercent+50%+1000%