Gun Modules
Gun modules are containers that change which weapon the player's gunboots fire. They are found in safe zones. During the boss fight, heart-type modules spawn inside the arena's sections (the module type is forced to heart in area 5, at most one per section). Each module is stamped with a letter showing which weapon it holds, and picking one up always swaps your current weapon for the new one; a module never contains the weapon you are already carrying, unless it is re-rolled with Reverse Engineering.
Weapons edit
Module types edit
Every module also comes in one of two container types, granting a small bonus on pickup:
Trivia edit
- Shooting a gun module while the Reverse Engineering upgrade is active re-rolls the weapon inside. A re-rolled module may contain the weapon you already have, which is the only way that can happen.
Implementation edit
Every weapon is a row in one data table. No weapon has its own object or script.
The weapon table edit
bStatInitLevel1.gml builds parallel arrays named global.bStat*[id][level]. A counter (gunnum) starts at 0 and is incremented between blocks, so each block of assignments defines one weapon: Machinegun is id 0, Shotgun 1, Laser 2, Triple 3, Puncher 4, Burst 5, Noppy 6. The file ends with global.bulletMaxNum = gunnum;, which records the highest valid id. Every stat has two entries per weapon: [id][0] holds the normal values and [id][1] the Gem High values.
A new weapon is a new block in this file (with its own gunnum += 1) placed before the bulletMaxNum line. Gun modules roll irandom(global.bulletMaxNum), so a new id enters the pickup pool with no other change.
Fields edit
| Field | Verified behaviour |
|---|---|
bStatName |
Text shown on pickup. bStatJp.gml overwrites ids 0 to 6 with Japanese names when the language is Japanese.
|
bStatGunSprite |
Frame index into the sprModText sprite: the letter glyph drawn on the module (frame 12 is M, 18 is S, 11 is L, 19 is T, 15 is P, 1 is B, 13 is N).
|
bStatObject |
The projectile object created per shot. Ids 0, 1, 3, 4, 5, 6 use bulletRanged; the Laser uses bulletLaser.
|
bStatBulletSprite, bStatSound, bStatMuzzle |
Sprite, sound and muzzle-effect assets, per level. |
bStatConRate |
Charge consumed per shot. |
bStatRof |
Shot cooldown: the firing script sets its cooldown alarm to abs(Rof) frames, and a negative value additionally marks the shot non-automatic (the button must be released before the next shot).
|
bStatRecoil |
Applied to the player's vertical speed; negative values push upward. |
bStatScreenShake, bStatScreenShakeDur |
Screen shake strength and duration per shot. |
bStatBurst, bStatBurstRate, bStatBurstAmount |
With Burst set to 1, one press fires BurstAmount rounds spaced BurstRate frames apart. The Shotgun uses rate 0 (all pellets at once); Burst uses rate 5.
|
bStatDamage, bStatSpeed, bStatAccuracy, bStatPierce |
Damage per projectile, projectile speed (0 for the instant laser beam), random angular spread, and whether the projectile passes through enemies. |
bStatSpType, bStatSp1, bStatSp2 |
Shot pattern. Type 0 fires one projectile. Type 1 adds a pair per step of Sp1, angled ±(Sp2 × step) degrees (Triple: Sp1 1, Sp2 14, giving 3 bullets in a fan). Type 2 adds a pair per step, offset ±(Sp2 × step) pixels horizontally with the same direction (Puncher: Sp1 1, Sp2 5, giving 3 parallel bullets).
|
bStatAimAngleLimit |
Maximum aim tilt in degrees toward the movement direction (25 for Noppy, 0 for the rest, with AimAngleAccl/Dccl controlling the tilt rate).
|
bStatDelayKill, bStatWave, bStatExplode, bStatRangeRandom, bStatRangeTimer, bStatSp3 |
Present in the table and copied like the others; the shipped weapons vary them little. |
How the table is used edit
bStatUpdate(id, level) copies one weapon's row into live global.pBul* variables. It runs when a module is picked up (gun_module's player collision sets global.pGunType and calls it) and when the gem streak crosses the Gem High threshold in either direction (scrControlBeginstepCheck.gml switches the level between 0 and 1). bStatInitialize.gml calls it with id 0 at the start of a run, which is why the Machinegun is the starting weapon.
The firing script (scrPlayerShootN.gml) reads only the pBul* variables: it emits pBulObject through the pattern logic in scrPlayerEmitBullet.gml, subtracts pBulConRate from the charge, and sets the cooldown from pBulRof.