What this is

The v2 enemy rarity system. Every base archetype (16 of them: orb, charger, shooter, mortar, gunner, field, sniper, racer, brute, wisp, lurker, bombardier, sprinter, spitter, burner, suppressor) is multiplied across 5 rarity tiers — common, uncommon, rare, epic, legendary — to produce the full ENEMY_TYPES table.

Two parallel tables drive this:

  • RARITY_MULTS — per-rarity stat multipliers applied to the base archetype’s hp, xp, speed, radius, and damage fields. Results are Math.round()-ed at type-build time in buildEnemyTypes().
  • RARITY_TINTS — per-rarity polygon stroke color baked onto every variant’s tint field.

The id of each generated type is ${archetype}_${rarity} (e.g. orb_common, mortar_legendary). Iteration order is RARITY_ORDER = ['common', 'uncommon', 'rare', 'epic', 'legendary'].

Source of truth: src/starship-survivors/data/enemies/_types.ts. Re-exported from src/starship-survivors/data/enemies/index.ts and src/starship-survivors/data/enemies.ts.

RARITY_MULTS table

Applied multiplicatively to base archetype stats. damage is used only by archetypes that scale damage per rarity (orb AOE, mortar/bombardier blast, sniper beam, field/burner field, gunner/suppressor not directly here).

Rarityhpxpspeedradiusdamage
common2.73.01.401.003.0
uncommon4.956.01.471.154.5
rare6.9312.01.571.306.6
epic9.918.01.681.408.4
legendary11.8824.01.821.5010.5

Notes:

  • hp, speed, radius, xp are applied to every variant via Math.round(base.X * m.X).
  • damage is applied selectively in buildEnemyTypes():
    • orbaoeDamage
    • mortar / bombardier — implicit via blastRadius scaling formula 1 + tierIndex * 0.15 (blast radius), with fuseTime left at base.
    • field / burnerfieldDamage (multiplied by m.damage), plus fieldRadius = base * (1 + tierIndex * 0.15), fieldDuration x1.5 only on legendary.
    • snipersniperBeamDamage (multiplied by m.damage).
    • gunner / suppressor — separate burstMults = [1.0, 1.0, 1.2, 1.4, 2.0] and cdMults = [1.0, 0.9, 0.8, 0.65, 0.5]; m.damage is not used directly.
  • Orb AOE also uses two per-rarity helper tables (not part of RARITY_MULTS):
    • aoeRadius = base * (1 + tierIndex * 0.20)
    • aoeCooldown = base * [1.0, 0.85, 0.7, 0.35, 0.35][tierIndex]
  • Sniper uses chargeMults = [1.0, 0.9, 0.8, 0.7, 0.5] against sniperChargeTime.

RARITY_TINTS table

Polygon stroke color baked into each variant’s tint. Boss-roster enemies override tint per faction-specific id and ignore this table.

RarityTint hexColor
common#cccccclight gray
uncommon#33cc55green
rare#3388ffblue
epic#aa44ffpurple
legendary#ff8800orange

A second, legacy color table ENEMY_TIER_COLORS in data/enemies/index.ts uses different values for common (#cc3333), no epic entry, and matching values for uncommon / rare / legendary. RARITY_TINTS is the live source for variant tints; ENEMY_TIER_COLORS is a parallel UI palette.

Where consumed

  • src/starship-survivors/data/enemies/index.tsbuildEnemyTypes() consumes both tables to produce every entry in ENEMY_TYPES and ENEMY_TYPE_MAP.
  • src/starship-survivors/data/enemies.ts — re-exports RARITY_MULTS and RARITY_TINTS for legacy import paths.
  • src/starship-survivors/screens/RunStatsScreen.tsx — uses RARITY_TINTS for end-of-run kill breakdown swatches and per-enemy row tint fallback.
  • src/starship-survivors/screens/playground/EnemiesTab.tsx — references RARITY_MULTS in commentary on assembled stats.
  • Renderer reads each enemy’s baked tint field at draw time; it does not re-read RARITY_TINTS at runtime.