Weapon Merge Rules (Legendary Fusion)

Two equipped non-legendary weapons that have reached the cap (level 20) become eligible to fuse into a single legendary weapon. The merge is offered as a card in the level-up reward UI; picking it consumes both parents and adds the legendary at level 1, which then scales 1→20 through the normal level-up pool.

Eligibility

A pair of equipped weapons becomes a merge candidate when all of the following hold:

  • Both weapons are at the maximum weapon level (MERGE_ELIGIBLE_LEVEL = 20).
  • Neither weapon is itself a legendary (merging is single-layer — legendaries cannot merge further).
  • Both weapons have a damageTag of bullet, energy, bomb, or fire.
  • The ship currently holds at least two such qualifying weapons.

The unordered pair of damage tags determines which legendary is produced. The lookup is canonicalised via pairKey(a, b) (alphabetical sort: bomb < bullet < energy < fire) so order does not matter.

The 10 Tag Pairings

Four base tags pair with each other — including with themselves — producing 10 unordered pairings, each mapped to exactly one legendary weapon. Same-tag merges (e.g. bullet + bullet) are explicitly supported and produce a legendary identical to the cross-tag pairings.

Tag PairLegendaryWeapon ID
bullet + bulletMega Bulletlgd_autocannon
bomb + bombHellrainlgd_blackhole_cluster
energy + energyStar Halolgd_railstorm
fire + firePhoenixlgd_inferno
bomb + bullet4-Way Burstlgd_flak_rifle
bullet + energyWave Gunlgd_railslug
bullet + fireTrailblazerlgd_incendiary_rifle
bomb + energyRailstormlgd_plasma_launcher
bomb + fireCarpet Bomberlgd_napalm_mortar
energy + firePlasma Mortarlgd_arc_flame

The map is built at module load by walking LEGENDARY_WEAPONS and indexing each entry by pairKey(...w.mergeParents). getLegendaryForPair(a, b) throws if a pair has no legendary defined — there is no silent fallback.

Merge Offer Card

When the ship has 2+ level-20 non-legendary weapons at level-up time, the reward pool prepends one or more merge offer cards ahead of the normal weapon-upgrade / modifier slots:

  • All unordered candidate pairs are enumerated and shuffled.
  • At least one merge slot is reserved whenever merges are eligible, but merge cards are capped at ceil(count/2) so they never crowd out the full pool.
  • Each card is keyed by the specific (weaponA, weaponB) slot pair so the same offer is never duplicated within one pull.
  • The card displays the legendary’s name and a parentA + parentB → legendary slug; it is flagged as isNew: true with rarity legendary.
  • Players may banish a specific merge by its weapon_merge|<legendaryId> key, suppressing future offers for that legendary.

Legendaries are merge-only — they never appear from chests, level-up weapon slots, or any other source.

Picking a Merge Card

When a weapon_merge choice is applied:

  1. Both parent weapons are located on the ship by weaponId. The two slots must be distinct (same weaponId is allowed if the ship holds two separate instances — see same-tag merges).
  2. Both parents are spliced out of the ship’s weapon list (higher index first, to keep the lower index valid).
  3. The legendary is inserted at the leftmost parent’s original slot so the HUD weapon bar keeps a stable left-to-right order and the merge cinematic lands the new icon where the leftmost parent used to sit.
  4. The legendary starts at level: 1, with cooldown = 1 / fireRate.base and a randomised initial fireTimer (to desync from other weapons).
  5. The legendary’s weaponId is appended to game.tracking.weaponsFound, and the pick is logged as merge_<aId>_<bId> in upgradesChosen.

If any precondition fails (either parent not found, either parent is a legendary, no damageTag, no legendary defined for the pair), mergeWeapons returns null and no state mutation occurs.

VFX Scaling Convention

Per the module header in data/weapons/legendaries.ts, legendary spatial parameters (acquireRange, travelRangeMult, projectileSize, blastRadius, beamWidth, chainRadius, scatterRadius, coneWidth) and pulse/glow values are ×5 versus their base-weapon counterparts. postFxSec is ×2 only (screen-flash cap to avoid nausea). Particle/shell/chain counts stay low on high-fire-rate weapons; slow weapons get modest ×2 count bumps.

Source Files

  • src/starship-survivors/data/weapons/legendaries.ts — legendary specs, WeaponTag, sortTagPair, pairKey, LEGENDARY_WEAPONS, LEGENDARY_PAIR_MAP, getLegendaryForPair.
  • src/starship-survivors/engine/world/merge-system.tsMERGE_ELIGIBLE_LEVEL, MergeCandidate, findMergeCandidates, mergeWeapons.
  • src/starship-survivors/engine/world/leveling.ts — merge-card insertion into the reward pool (weapon_merge entries, mergeCap, dedupe key) and case 'weapon_merge' choice application.