weapon-icons.ts

Single source of truth for weapon and modifier icon asset paths and emoji fallbacks. Replaces duplicate WEAPON_EMOJIS maps previously scattered across hud.ts, ShipSelectOverlay.tsx, and LeaderboardWrapper.tsx.

River — purpose

Resolves a weapon or modifier ID to its icon asset path on disk (with cache-buster) or, failing that, to an emoji glyph. Consumers: HUD weapon strip, ship-select overlay, leaderboard wrapper, anywhere a weapon ID needs visual representation.

Cocytus — symbols

WEAPON_ICON_IDS (private Set<string>)

13 weapon IDs with PNG icon assets at /weapons/{id}.png:

sweep, barrier, shotgun, disc, lightning, flame,
line, railgun, mortar, revolver, rifle,
missile, cannon

MODIFIER_ICON_IDS (private Set<string>)

5 modifier IDs with PNG icon assets at /upgrades/{id}.png. Keyed with mod_ prefix to avoid collision with weapon IDs:

mod_health, mod_shield, mod_speed, mod_damage, mod_heat

getWeaponIconPath(id: string): string | null (exported)

Returns the asset URL for a weapon or modifier icon, with ?v=${BUILD_VERSION} appended as cache-buster (prevents stale SW/CDN serving HTML). Returns null if the ID has no PNG asset.

  • Weapon match → /weapons/{id}.png?v={BUILD_VERSION}
  • Modifier match → /upgrades/{id-stripped-of-mod_-prefix}.png?v={BUILD_VERSION} (strips first 4 chars via id.slice(4))
  • No match → null

Note: the doc comment on line 24 mentions .jpg, but the actual implementation emits .png for both weapons and modifiers.

hasWeaponIcon(id: string): boolean (exported)

Returns true iff id exists in either set (weapon or modifier).

WEAPON_EMOJIS (exported Record<string, string>)

Emoji fallback map for IDs without PNG assets, or where caller chose emoji.

Standard weapons (14 entries): rifle🔫, shotgun🎯, railgun⚡, missile🚀, lightning🌩️, revolver🎖️, cannon💣, mortar💥, disc🥏, flame🔥, sweep⚔️, line➖, barrier🛡️, plus environmental projectiles fire_trail🔥, fire_ring🔆, burst🔫.

Legendary weapons (merge-only, 10 entries — distinct glyphs until PNG assets exist): lgd_autocannon💫, lgd_blackhole_cluster🕳️, lgd_railstorm🌀, lgd_inferno🔥, lgd_flak_rifle💢, lgd_railslug💠, lgd_incendiary_rifle☄️, lgd_plasma_launcher🌌, lgd_napalm_mortar🧨, lgd_arc_flame⚡.

Lethe — imports

  • BUILD_VERSION from ../engine/core/config — appended as ?v={BUILD_VERSION} query string for cache-busting.

Phlegethon — invariants

  • All weapons in WEAPON_ICON_IDS overlap with WEAPON_EMOJIS keys (PNG path takes precedence at consumer level; emoji is fallback only).
  • Modifier IDs are namespaced with mod_ prefix to prevent collision with weapon IDs in the same lookup.
  • Legendary weapons (lgd_* prefix) have emoji-only representation — no PNG assets yet.
  • All returned URLs are root-relative paths (/weapons/..., /upgrades/...) — assumes the public asset folder layout.

Acheron — EXTRACT-CANDIDATE

  • The two Set literals (WEAPON_ICON_IDS, MODIFIER_ICON_IDS) plus the WEAPON_EMOJIS map are pure data. Candidate for migration to a weapon-icons.json if data-driven authoring is desired, but at 18 IDs + 24 emoji entries the inline-TS form is fine.
  • The .jpg mention in the line-24 doc comment is stale (implementation uses .png) — minor doc-fix candidate.
  • The id.slice(4) magic offset in getWeaponIconPath is the length of the 'mod_' prefix; replacing with id.slice('mod_'.length) or a named constant MOD_PREFIX = 'mod_' would satisfy the “every number traces to a named constant” rule.