data/claims/dr-mario.yamlDr. Mario (NES) (Nostaljipi/dr-mario-disassembly)
Game: Dr. Mario (NES).
With completeCleanup = 0 and ver_revA = 1, the disassembly builds the No-Intro Dr. Mario (Japan, USA) (Rev 1) ROM byte for byte, apart from its 16-byte header. dr-mario/rom-is-disassembly
Value: 59b43881456c0720e9a35e391b11c4b2c55a8f91
CodeDr. Mario (NES) Disassembly ·build_config.asm#L2completeCleanup = 1 ;Set to 1 to set all build config optionsDr. Mario (NES) Disassembly · build_config.asm#L24ver_revA = 1 ;Set only one of these to 1Dr. Mario (Japan, USA) (Rev 1) · 0x0-0xF — the header the comparison skipsChecked by claude, 2026-10-21 — built drmario.asm at the pinned commit with asm6f (.cache/repos/asm6f) after setting completeCleanup = 0; the output and the ROM, each without its 16-byte header, share the SHA-1 in `value`So the lines cited below, on their original-build paths, are code in this ROM.
Cited by: Dr. Mario (NES)
fallingPill_checkYMove counts frames at the pill's row and drops it when the count passes an entry of speedCounterTable, so a row takes the entry plus one frame. The speed setting picks the starting entry, index 15, 25, or 31 for Low, Med, and Hi, which is 40, 20, or 14 frames per row; entries 0 to 14 are never reached. dr-mario/frames-per-row
About: Dr. Mario (NES) Drop speed
Value
{
"low": 40,
"med": 20,
"hi": 14
}prg/drmario_prg_game_logic.asm#L242-L252inc currentP_speedCounter ;Down not pressed, get amount of frames (speed counter) spent at this vertical position so far … lda baseSpeedSettingValue,X … adc currentP_speedIndex … lda speedCounterTable,X … cmp currentP_speedCounter ;The speed counter must be over the data in the table for the gravity to occur … bcs @exit_fallingPill_checkYMoveDr. Mario (NES) Disassembly · prg/drmario_prg_game_logic.asm#L253-L256dec currentP_fallingPillY ;Decrease the pill's y position … lda #$00 ;Reset the speed counter … sta currentP_speedCounterDr. Mario (NES) Disassembly · data/drmario_data_game.asm#L422-L423.db $0F,$19,$1F ;Low ($0F = $27), Med ($19 = $13), Hi ($1F = $0D)Dr. Mario (NES) Disassembly · data/drmario_data_game.asm#L778-L789speedCounterTable:
if !ver_EU
.db $45,$43,$41,$3F,$3D,$3B,$39,$37
.db $35,$33,$31,$2F,$2D,$2B,$29,$27 ;Slowest actually starts at $27 (index $0F)
.db $25,$23,$21,$1F,$1D,$1B,$19,$17
.db $15,$13,$12,$11,$10,$0F,$0E,$0DChecked by claude, 2026-10-21 — read fallingPill_checkYMove, baseSpeedSettingValue, and speedCounterTable at the pinned commit; the count is incremented before the compare, so a drop comes when it reaches the entry plus oneCited by: Dr. Mario (NES), Drop speed
Every 10th pill moves the speed one step further along speedCounterTable, up to 49 steps, and each level past 20 starts a step further. After 49 steps a row takes 4 frames at Low, 2 at Med, and 1 at Hi, the table's last entry. dr-mario/speed-ups
About: Dr. Mario (NES) Drop speed
Value
{
"everyPills": 10,
"maxSteps": 49,
"lastLow": 4,
"lastMed": 2,
"lastHi": 1
}prg/drmario_prg_game_logic.asm#L532-L546lda currentP_pillsCounter_decimal … and #$0F ;Every 10 pills, check if we speed up … cmp #speedUps_max ;Prevents speed increase after 49 increases … inc currentP_speedUps ;We speed up, play the associated sfx,Dr. Mario (NES) Disassembly · defines/drmario_constants.asm#L14speedUps_max = $31 ;Prevents speed increase after $31 (49) increasesDr. Mario (NES) Disassembly · prg/drmario_prg_level_init.asm#L121-L122lda lvlsOver20 … sta currentP_speedUps ;Starts 1 step further in speed table for each level over 20Dr. Mario (NES) Disassembly · data/drmario_data_game.asm#L784-L790.db $0C,$0B,$0A,$09,$09,$08,$08,$07 … .db $04,$04,$04,$04,$03,$03,$03,$03 … .db $03,$02,$02,$02,$02,$02,$01,$01 … .db $01,$01,$01,$01,$01,$01,$01,$01 … .db $00Checked by claude, 2026-10-21 — read generateNextPill's speed-up check and the table's tail; indices 15+49, 25+49, and 31+49 hold $03, $01, and $00Cited by: Dr. Mario (NES), Drop speed
Holding Down, and no other direction, drops the pill a row on every other frame, and the drop resets the gravity count. dr-mario/soft-drop
About: Dr. Mario (NES) Drop speed
Value: 2 frames/row
CodeDr. Mario (NES) Disassembly ·prg/drmario_prg_game_logic.asm#L233-L240lda frameCounter … and #fast_drop_speed … beq @checkGravity ;Down button is only checked every 2 frames … cmp #btn_down ;This implies that ONLY down must be pressed on the d-pad for the fast drop to occur … beq @lowerPillYChecked by claude, 2026-10-21 — read fallingPill_checkYMove at the pinned commitCited by: Dr. Mario (NES)
When a drop is blocked, the pill moves back up and is placed in the bottle at once, so a pill resting on the stack locks at its next gravity step. dr-mario/no-lock-delay
About: Dr. Mario (NES) Lock delay
CodeDr. Mario (NES) Disassembly ·prg/drmario_prg_game_logic.asm#L257-L266jsr pillMoveValidation ;Checks if move is valid, returns zero if valid … bne @pillHasLanded ;If can't move down anymore, the pill has landed … inc currentP_fallingPillY ;Returns Y to its previous value because it couldn't be lowered … jsr confirmPlacement ;"Print" (or "cement") the pill in positionChecked by claude, 2026-10-21 — read fallingPill_checkYMove at the pinned commitCited by: Dr. Mario (NES), Lock delay
A press of Left or Right moves the pill at once and zeroes currentP_horVelocity; held, the count rises each frame and at 16 the pill moves and the count restarts at 10, so it moves again 16 frames after the press and then every 6. The European build uses 13 and 5. dr-mario/das
About: Dr. Mario (NES) Delayed auto shift
Value
{
"delay": 16,
"repeat": 6,
"palDelay": 13,
"palRepeat": 5
}prg/drmario_prg_game_logic.asm#L291-L308inc currentP_horVelocity ;If held, we increase the horizontal velocity … cmp #hor_accel_speed ;Takes 16 frames for initial build up of speed … lda #hor_accel_speed - hor_max_speed ;Then it takes 6 frames for subsequent movements … lda #$00 ;If btn was instead pressed, reset horizontal velocityDr. Mario (NES) Disassembly · defines/drmario_constants.asm#L81-L87hor_accel_speed = $10 … hor_max_speed = $06 … hor_accel_speed = $0D … hor_max_speed = $05Checked by claude, 2026-10-21 — read fallingPill_checkXMove and the timing constants at the pinned commitCited by: Delayed auto shift, Dr. Mario (NES)
A blocked shift sets the count to 15, so a pill held against a wall or the stack moves on the first frame the way is clear. dr-mario/das-wall-charge
About: Dr. Mario (NES) Delayed auto shift
Value: 15
CodeDr. Mario (NES) Disassembly ·prg/drmario_prg_game_logic.asm#L326-L331@cantMove_right: … dec currentP_fallingPillX ;Restore the previous x value … lda #hor_accel_speed-1 ;This makes so that as soon as the pill can move, it will move without delay with regard to velocityChecked by claude, 2026-10-21 — read fallingPill_checkXMove at the pinned commitCited by: Delayed auto shift, Dr. Mario (NES)
At the start of each level generatePillsReserve deals 128 pills, shared by both players. Each pill is one of 9 color pairs, found by adding a random 0 to 15 to the previous pill's index and subtracting 9 until it fits; the game reads the reserve in a loop, so the same 128 pills come round again. dr-mario/pill-reserve
About: Dr. Mario (NES) Piece randomizer
Value
{
"reserve": 128,
"pairs": 9
}prg/drmario_prg_level_init.asm#L169-L194lda #pillsReserveSize ;Equals to the number of pills to generate … lda rng0 ;Max the rng value at 15 … and #$0F … adc pillId … cmp #colorCombination_right - colorCombination_left … bcc @storePill ;If within the array size (9), is a valid pill index … sbc #colorCombination_right - colorCombination_left … sta pillsReserve,X ;Starts from the end of the arrayDr. Mario (NES) Disassembly · prg/drmario_prg_level_init.asm#L124jsr generatePillsReserve ;Same reserve used by both playersDr. Mario (NES) Disassembly · prg/drmario_prg_game_logic.asm#L464-L475ldx currentP_pillsCounter ;If not demo, then use the player's pill reserve … lda pillsReserve,X … inc currentP_pillsCounter ;Increase the pills counter … and #pillsReserveSize-1 ;Wraparound over $7F because we have a maximum of 128 pills storedDr. Mario (NES) Disassembly · data/drmario_data_game.asm#L824-L829colorCombination_left:
.db $00,$00,$00,$01,$01,$01,$02,$02
.db $02
colorCombination_right:
.db $00,$01,$02,$00,$01,$02,$00,$01
.db $02Checked by claude, 2026-10-21 — read generatePillsReserve, generateNextPill, and the color tables at the pinned commitCited by: Demo playback, Dr. Mario (NES), Piece randomizer
Because the 16 random values wrap at 9, steps of 0 to 6 from the previous pill's index each come from two values and steps of 7 and 8 from one, so the same pill follows itself with chance 2/16, where a uniform pick would give 1/9. dr-mario/pill-step-bias
About: Dr. Mario (NES) Piece randomizer
Value: 0.125
CodeDr. Mario (NES) Disassembly ·prg/drmario_prg_level_init.asm#L182-L192and #$0F … clc ;Add to index of previous pill (probably as a means to improve random) … adc pillId … cmp #colorCombination_right - colorCombination_left … sbc #colorCombination_right - colorCombination_left … jmp @checkIfValidIndexChecked by claude, 2026-10-21 — read generatePillsReserve; (0..15) mod 9 hits 0..6 twice and 7, 8 onceThe arithmetic assumes the low four bits of rng0 are uniform; the generator itself hasn't been analysed.
Cited by: Dr. Mario (NES), Piece randomizer
A level holds (level + 1) × 4 viruses; for player 1 levels past 20 count as 20, while player 2's count is uncapped. The count of viruses still to add runs down, and its low two bits pick the color (0 yellow, 1 red, 2 blue, 3 a color from a 16-entry table), so each run of four from a multiple of 4 goes yellow, random, blue, red. Each virus goes at a random height no higher than the level allows and a random column, moving on to the next free cell, and takes another color if one of its own lies two cells away in a straight line. dr-mario/virus-placement
About: Dr. Mario (NES) Piece randomizer
Value
{
"perLevel": 4,
"max": 84
}prg/drmario_prg_level_init.asm#L133-L145lda p1_level ;Then perform some calculations to find how many viruses to add … lda #selectableLvCap ;And use the level cap as basis for virus quantity … clc ;Nb of virus = (lvNb + 1) * 4Dr. Mario (NES) Disassembly · prg/drmario_prg_level_init.asm#L146lda p2_level ;No need to check level cap for player 2Dr. Mario (NES) Disassembly · prg/drmario_prg_game_logic.asm#L3080-L3085and #lastRow ;Maxout at 16 … lda addVirus_maxHeight_basedOnLvl,X … bcc @getValidHeight ;New random number if height is over the maxDr. Mario (NES) Disassembly · prg/drmario_prg_game_logic.asm#L3099-L3102lda currentP_virusToAdd ;This here is to ensure for evey 4 viruses, there are guaranteed 1 for each color. The 4th virus is random. … and #virusRndMask … sta virusColor … cmp #virusRndColorDr. Mario (NES) Disassembly · prg/drmario_prg_game_logic.asm#L3290dec currentP_virusToAddDr. Mario (NES) Disassembly · defines/drmario_constants.asm#L230-L232yellow = $00 … red = $01 … blue = $02Dr. Mario (NES) Disassembly · defines/drmario_constants.asm#L49-L51rndColorQty = $01 … virusRndMask = $02 + rndColorQty … virusRndColor = $03Dr. Mario (NES) Disassembly · prg/drmario_prg_game_logic.asm#L3224-L3234cmp #%00000111 … jmp @tryNextPos ;If all 3 virus colors were detected two apart, then position is assuredly not viable … and virusColorVerif ;If virus color is not present at 2 of distance in any direction, we have a valid virus to add … dec virusColor ;Otherwise, cycle through other colorsDr. Mario (NES) Disassembly · defines/drmario_constants.asm#L11selectableLvCap = $14Checked by claude, 2026-10-21 — read initData_level's virus count and addVirus at the pinned commitCited by: Dr. Mario (NES)
After a pill lands the game scans the bottle row by row for 4 or more cells of one color in a row, then column by column for 4 or more in a column, and clears every run it finds. dr-mario/match-four
About: Dr. Mario (NES) Clearing
Value: 4
CodeDr. Mario (NES) Disassembly ·defines/drmario_constants.asm#L15match_length = $04 ;Length of color chain required for a matchDr. Mario (NES) Disassembly · prg/drmario_prg_game_logic.asm#L1141-L1170 @noMatchInMemory:
lda #$00
sta fieldPos ;Will check field pos from top left to bottom right, row after row
…
@checkHorColorChain_loop:
inc fieldPos_tmp ;Checks next horizontal
lda fieldPos_tmp
and #lastColumn ;Check if reached right end of bottle
beq @horColorChainBroken
ldy fieldPos_tmp ;Get next horizontal
lda (currentP_fieldPointer),Y
and #mask_fieldobject_color
…Dr. Mario (NES) Disassembly · prg/drmario_prg_game_logic.asm#L1171-L1176@horColorChainBroken: … cmp #match_length-1 ;Checks if enough for a match (does not include the starting color, which explains the "-1") … inc currentP_comboCounter ;Increase combo counter and store color chain lengthDr. Mario (NES) Disassembly · prg/drmario_prg_game_logic.asm#L26-L31.word checkDrop … .word resetMatchFlag … .word checkHorMatch … .word checkVerMatch … .word updateFieldChecked by claude, 2026-10-25 — read checkHorMatch from L1131: fieldPos starts at 0, each cell's color is compared with the cells to its right until the color changes or the row ends, and a chain of match_length - 1 more cells or longer runs @clearHorChain_loop over it; the pill-placed jump table runs checkHorMatch, then checkVerMatch, then updateFieldCited by: Clearing, Dr. Mario (NES)
When a clear happens, updateField sends the placed pill's steps back to checkDrop, which lets unsupported halves fall, and the match checks run again, so one pill can set off a chain of clears. dr-mario/cascade
About: Dr. Mario (NES) Chain
CodeDr. Mario (NES) Disassembly ·prg/drmario_prg_game_logic.asm#L1478-L1486lda currentP_matchFlag ;Check if there was a match (and thus if we need to process drops and further field update) … lda #pillPlaced_nextStep1 ;If there was a match, we need to update the field again to process the impacts of this match (ex: pill drops) … sta currentP_pillPlacedStepDr. Mario (NES) Disassembly · prg/drmario_prg_game_logic.asm#L71-L149checkDrop:
…
ldy #lastFieldPos
sty fieldPointerOffset ;Starts at the end and goes backward
…
lda (currentP_fieldPointer),Y
cmp #fieldPosJustEmptied ;If not empty, then no drop possible
…
sbc #rowSize ;Substract 1 row to check what's on top
…
@canDrop:
ldy fieldPointerOffset_top ;Get what was on top
…Checked by claude, 2026-10-25 — read updateField's match branch (L1478-L1486), which sets the step back to pillPlaced_nextStep1, and checkDrop (L71-L149): from the last cell backward, an empty cell takes the pill half above it (a horizontal pill only when the cells under both halves are empty) and the half's old cell is emptiedCited by: Chain, Clearing, Dr. Mario (NES)
In a one-player game each virus cleared scores 100, 200, or 300 points at Low, Med, or Hi, times 1, 2, 4, 8, 16, then 32 for the 6th to 11th virus cleared by the same pill. The multiplier isn't capped (the clamp is one of the disassembler's bugfix options, not in the original build), so from the 12th virus on it indexes bytes past the end of the 11-entry table. dr-mario/virus-score
About: Dr. Mario (NES) Chain
Value
[ 1, 2, 4, 8, 16, 32 ]
prg/drmario_prg_game_logic.asm#L691-L716bne @exit_scoreIncrease ;No score increase if 2 players … ldx currentP_scoreMultiplier ;Problem here is that the score combo multiplier is not capped, and so it can overflow … if bugfix … lda scoreMultiplier_table,X … lda currentP_speedSetting ;Score is impacted by speed setting (Low = 100, Med = 200, Hi = 300) … inc currentP_scoreMultiplierDr. Mario (NES) Disassembly · data/drmario_data_game.asm#L266-L268scoreMultiplier_table:
.db $01,$02,$04,$08,$10,$20,$20,$20
.db $20,$20,$20Dr. Mario (NES) Disassembly · prg/drmario_prg_game_logic.asm#L39-L44resetCombo: … sta currentP_scoreMultiplierChecked by claude, 2026-10-21 — read scoreIncrease, its table, and resetCombo, the first step after a pill landsThe multiplier isn't capped at the table's end, which the disassembler blames for glitches after very long combos.
Cited by: Chain, Dr. Mario (NES)
In a two-player game, 2 or more matches from one pill send that many half-pills, at most 4, in the colors of the matches, to the other player's bottle, where they land at its top row in a frame-dependent column. dr-mario/attack
About: Dr. Mario (NES) Garbage
Value
{
"min": 2,
"max": 4
}prg/drmario_prg_game_logic.asm#L2874-L2879lda currentP_comboCounter … cmp #attackSize_min ;Threshold for an attack … adc currentP_attackSize ;Otherwise, add combo counter value to current attack sizeDr. Mario (NES) Disassembly · prg/drmario_prg_game_logic.asm#L1550-L1555cmp #attackSize_max+1 ;Any combo that goes over 4 does not register any more attacks … lda startingColor ;Latest match color is used to send opponent … sta currentP_attackColors,XDr. Mario (NES) Disassembly · prg/drmario_prg_game_logic.asm#L2902-L2908lda p1_attackSize,X … cmp #attackSize_min … bcc @noAttack ;If attack size below minimum, no attack … lda frameCounter … and #attackSize_2_pos ;Position of attack is based on frameChecked by claude, 2026-10-21 — read updateAttackColor, checkComboCounterForAttack, and checkReleaseAttack at the pinned commitCited by: Dr. Mario (NES), Garbage
In a one-player game each new pill waits for Mario's throw: action_sendPill steps the pill along a table of 21 positions, once a frame at Med and Hi and on every other frame at Low, and puts it in the bottle when the table ends. In a two-player game the pill goes straight to the bottle. dr-mario/throw
About: Dr. Mario (NES) Entry delay
Value
{
"positions": 21,
"framesPerStepLow": 2,
"framesPerStepMedHi": 1
}prg/drmario_prg_game_logic.asm#L3546-L3562lda nbPlayers … cmp #$01 … beq @checkFrame_pillThrown … jmp @pillThrown_toField … lda currentP_speedSetting … lda frameCounter … and #spr_mario_throw_speed_low ;On Low speed setting, pill rotates only every other frame … beq @exit_action_sendPillDr. Mario (NES) Disassembly · prg/drmario_prg_game_logic.asm#L3564-L3576inc pillThrownFrame … lda pillThrownAnim_XPos,X … cmp #$FF ;This value ends the anim … beq @pillThrown_toField … and #$F0 ;These values mean we update Mario's sprite anim, not just the pill … jmp @incFrame_pillThrownDr. Mario (NES) Disassembly · data/drmario_data_game.asm#L482-L487pillThrownAnim_XPos:
.db $BE,$F1,$BE,$BC,$B8,$B4,$F2,$B0
.db $AC,$A8,$A4,$A0,$9E,$98,$94,$90
.db $8C,$88,$84,$80,$7C,$7A,$78,$F0
.db $78
.db $FF ;End of dataChecked by claude, 2026-10-21 — read action_sendPill and pillThrownAnim_XPos; the frame index starts at 1, and the three $Fx entries change Mario's sprite within the same frame, leaving 21 positions before $FFThe full lock-to-spawn time also counts the frames the landing checks take; it hasn't been measured.
Cited by: Dr. Mario (NES), Entry delay