Difference between revisions of "Disassembly Notes (NES)"
| Line 2: | Line 2: | ||
If you sit idle on the title screen for a while, a demo plays. It's triggered by the frame counter rolling over to <code>00</code> 8 times in a row. The frame counter cycles through from <code>00</code>-<code>FF</code>. So this means it takes anywhere from ~29-34 seconds to start ((256 frames * 7 + [1,256] frames) / 60 frames per second). It can be disabled a number of ways, but the simplest way is editing the jump offset (to <code>0</code>) when it decides to load the demo code (at <code>$9905</code>), accomplishable through the Game Genie code <code>AAAPSP</code>. Next, while the demo board is a generatable one (seed <code>03BE</code>), it's stored directly in the ROM (<code>$CF00</code>-<code>$CF7F</code>) and loaded into memory. The capsules generated do not match this seed, but they're stored right after the board (<code>$CF80</code>-<code>$CFFF</code>). The controls are stored in pairs of bytes, the first byte being the buttons pressed (bitmask - A, B, Select, Start, Up, Down, Left, Right) and the second being the number of frames to hold down those buttons. These are stored right after the board/capsules at <code>$D000</code>-<code>$D1FF</code>. | If you sit idle on the title screen for a while, a demo plays. It's triggered by the frame counter rolling over to <code>00</code> 8 times in a row. The frame counter cycles through from <code>00</code>-<code>FF</code>. So this means it takes anywhere from ~29-34 seconds to start ((256 frames * 7 + [1,256] frames) / 60 frames per second). It can be disabled a number of ways, but the simplest way is editing the jump offset (to <code>0</code>) when it decides to load the demo code (at <code>$9905</code>), accomplishable through the Game Genie code <code>AAAPSP</code>. Next, while the demo board is a generatable one (seed <code>03BE</code>), it's stored directly in the ROM (<code>$CF00</code>-<code>$CF7F</code>) and loaded into memory. The capsules generated do not match this seed, but they're stored right after the board (<code>$CF80</code>-<code>$CFFF</code>). The controls are stored in pairs of bytes, the first byte being the buttons pressed (bitmask - A, B, Select, Start, Up, Down, Left, Right) and the second being the number of frames to hold down those buttons. These are stored right after the board/capsules at <code>$D000</code>-<code>$D1FF</code>. | ||
| + | |||
| + | == Pill movement == | ||
| + | |||
| + | This is all the code responsible for moving the pill each frame. The disassembly and function descriptions are from [https://github.com/brianhuffman/drmario Brian Huffman's disassembly]; this version has added detailed English descriptions of the code. I also did a cursory look through the code for what $06f1 does, but I couldn't find anything obvious that read from that address. So either it's dead code, or it's read via indirect addressing. | ||
| + | |||
| + | jsr R8D70_DROP_PILL ; may go to state 1 ; 8D66 20 70 8D | ||
| + | jsr R8DBF_PILL_MOVE ; 8D69 20 BF 8D | ||
| + | jsr R8E2B_PILL_ROTATE ; 8D6C 20 2B 8E | ||
| + | |||
| + | ; -------------------------------------- | ||
| + | ; Called once, in L8D56. | ||
| + | R8D70_DROP_PILL: | ||
| + | begin | ||
| + | lda L43_CLOCK ; 8D70 A5 43 | ||
| + | and #$01 ; 8D72 29 01 | ||
| + | beq L8D7E ; 8D74 F0 08 Every other frame, | ||
| + | lda L5C_INPUT_OLD ; 8D76 A5 5C | ||
| + | and #$0F ; 8D78 29 0F | ||
| + | cmp #$04 ; "down" ; 8D7A C9 04 if the user is pressing down but not left, right, or up, | ||
| + | beq L8D94 ; 8D7C F0 16 skip ahead to L8D94. | ||
| + | L8D7E: | ||
| + | inc L92_DROP_TIMER ; 8D7E E6 92 Increase the drop counter. | ||
| + | lda L8A_EXTRA_SPEED ; 8D80 A5 8A | ||
| + | sta LA0_TEMP ; redundant copy ; 8D82 85 A0 | ||
| + | ldx L8B_SPEED ; 8D84 A6 8B | ||
| + | lda LA38D,x ; $0F,$19,$1F ; 8D86 BD 8D A3 Load the base speed offset for the player-selected speed (low, med, hi), | ||
| + | add LA0_TEMP ; 8D89 18 65 A0 then add in the offset for having played a long time. | ||
| + | tax ; 8D8C AA | ||
| + | lda LA795,x ; drop timer threshold ; 8D8D BD 95 A7 Load the gravity value. | ||
| + | cmp L92_DROP_TIMER ; 8D90 C5 92 If the drop counter is <= the gravity value, | ||
| + | bcs break ; 8D92 B0 2A return from this function. | ||
| + | L8D94: | ||
| + | dec L86_PILL_ROW ; 8D94 C6 86 Move down. | ||
| + | lda #$00 ; 8D96 A9 00 | ||
| + | sta L92_DROP_TIMER ; 8D98 85 92 Reset the drop counter to 0. | ||
| + | jsr R90D3_COLLISION ; 8D9A 20 D3 90 | ||
| + | if_eq ; 8D9D D0 06 If we are over in-bounds empty space, | ||
| + | lda L86_PILL_ROW ; 8D9F A5 86 | ||
| + | cmp #$FF ; 8DA1 C9 FF and not below the board, | ||
| + | bne break ; 8DA3 D0 19 return from this function. | ||
| + | end_if | ||
| + | inc L86_PILL_ROW ; 8DA5 E6 86 Move up. | ||
| + | lda #$07 ; 8DA7 A9 07 | ||
| + | sta L06F1_ ; 8DA9 8D F1 06 Set $06F1 to 7. | ||
| + | jsr R8F52_PLACE_PILL ; 8DAC 20 52 8F Lock the pill in place. | ||
| + | ; make the program crash if L0740_CHECKSUM_FAIL is nonzero | ||
| + | lda L0740_CHECKSUM_FAIL ; 8DAF AD 40 07 | ||
| + | if_ne ; 8DB2 F0 05 | ||
| + | lda L53_SPRITE_NUM ; 8DB4 A5 53 | ||
| + | pha ; 8DB6 48 | ||
| + | pha ; 8DB7 48 | ||
| + | pha ; 8DB8 48 | ||
| + | end_if | ||
| + | inc L97_GAME_STATE ; 8DB9 E6 97 | ||
| + | jmp break ; 8DBB 4C BE 8D | ||
| + | end | ||
| + | rts ; 8DBE 60 | ||
| + | |||
| + | ; -------------------------------------- | ||
| + | ; Increment or decrement pill column based on controller input. | ||
| + | ; Repeat every 6 frames after holding for 16. | ||
| + | R8DBF_PILL_MOVE: | ||
| + | begin | ||
| + | lda L5B_INPUT_NEW ; 8DBF A5 5B | ||
| + | and #$03 ; left or right ; 8DC1 29 03 | ||
| + | if_eq ; 8DC3 D0 15 If the user did not start pressing left or right, | ||
| + | lda L5C_INPUT_OLD ; 8DC5 A5 5C | ||
| + | and #$03 ; left or right ; 8DC7 29 03 | ||
| + | beq break ; 8DC9 F0 5F and neither left nor right is currently pressed, return from this function. Otherwise, | ||
| + | inc L93_REPEAT_TIMER ; 8DCB E6 93 increase the DAS counter. | ||
| + | lda L93_REPEAT_TIMER ; 8DCD A5 93 | ||
| + | cmp #$10 ; 8DCF C9 10 | ||
| + | bmi break ; 8DD1 30 57 If the DAS counter is under 16, return from this function. Otherwise, | ||
| + | lda #$0A ; 8DD3 A9 0A | ||
| + | sta L93_REPEAT_TIMER ; 8DD5 85 93 set the DAS counter to 10. | ||
| + | else ; 8DD7 4C E3 8D If the user started pressing left or right, | ||
| + | lda #$00 ; 8DDA A9 00 | ||
| + | sta L93_REPEAT_TIMER ; 8DDC 85 93 set the DAS counter to 0, | ||
| + | lda #$03 ; 8DDE A9 03 | ||
| + | sta L06F1_ ; 8DE0 8D F1 06 and set $06F1 to 3. | ||
| + | end_if | ||
| + | lda L5C_INPUT_OLD ; 8DE3 A5 5C | ||
| + | and #$01 ; "right" ; 8DE5 29 01 | ||
| + | if_ne ; 8DE7 F0 20 If the user is pressing right, | ||
| + | lda LA5_PILL_DIR ; 8DE9 A5 A5 | ||
| + | and #$01 ; 1 = U/D, 0 = L/R ; 8DEB 29 01 | ||
| + | add #$06 ; 8DED 18 69 06 | ||
| + | cmp L85_PILL_COLUMN ; 8DF0 C5 85 | ||
| + | if_ne ; 8DF2 F0 15 and the pill is not in the rightmost column for its orientation, | ||
| + | inc L85_PILL_COLUMN ; 8DF4 E6 85 move right. | ||
| + | jsr R90D3_COLLISION ; 8DF6 20 D3 90 | ||
| + | if_eq ; 8DF9 D0 08 If that would put us over in-bounds empty space, | ||
| + | lda #$03 ; 8DFB A9 03 | ||
| + | sta L06F1_ ; 8DFD 8D F1 06 set $06F1 to 3. | ||
| + | else ; 8E00 4C 09 8E If that would put us out of bounds or over a non-empty space, | ||
| + | dec L85_PILL_COLUMN ; 8E03 C6 85 move left | ||
| + | lda #$0F ; 8E05 A9 0F | ||
| + | sta L93_REPEAT_TIMER ; 8E07 85 93 and set the DAS counter to 16. | ||
| + | end_if | ||
| + | end_if | ||
| + | end_if | ||
| + | lda L5C_INPUT_OLD ; 8E09 A5 5C | ||
| + | and #$02 ; "left" ; 8E0B 29 02 | ||
| + | if_ne ; 8E0D F0 1B If the user is pressing left, | ||
| + | lda L85_PILL_COLUMN ; 8E0F A5 85 | ||
| + | cmp #$00 ; 8E11 C9 00 | ||
| + | if_ne ; 8E13 F0 15 and we're not in the left-most column, | ||
| + | dec L85_PILL_COLUMN ; 8E15 C6 85 move left. | ||
| + | jsr R90D3_COLLISION ; 8E17 20 D3 90 | ||
| + | if_eq ; 8E1A D0 08 If that would put us over in-bounds empty space, | ||
| + | lda #$03 ; 8E1C A9 03 | ||
| + | sta L06F1_ ; 8E1E 8D F1 06 set $06F1 to 3. | ||
| + | else ; 8E21 4C 2A 8E If that would put us out of bounds or over a non-empty space, | ||
| + | inc L85_PILL_COLUMN ; 8E24 E6 85 move right, | ||
| + | lda #$0F ; 8E26 A9 0F | ||
| + | sta L93_REPEAT_TIMER ; 8E28 85 93 and set the DAS counter to 16. | ||
| + | end_if | ||
| + | end_if | ||
| + | end_if | ||
| + | end | ||
| + | rts ; 8E2A 60 | ||
| + | |||
| + | ; ---------------------------------------------------------------------------- | ||
| + | ; Pill collision detection. | ||
| + | ; Returns A = 0, Z set for no collision. | ||
| + | ; Returns A = FF, Z clear for collision. | ||
| + | R90D3_COLLISION: | ||
| + | .scope | ||
| + | ldx LA6_PILL_SIZE ; 90D3 A6 A6 | ||
| + | dex ; 90D5 CA | ||
| + | dex ; 90D6 CA | ||
| + | lda LA5_PILL_DIR ; 90D7 A5 A5 | ||
| + | and #$01 ; 1 = U/D, 0 = L/R ; 90D9 29 01 | ||
| + | if_eq ; 90DB D0 13 If the current pill is horizontal, | ||
| + | lda LA455,x ; $00,$FF,$FF ; 90DD BD 55 A4 | ||
| + | add L85_PILL_COLUMN ; 90E0 18 65 85 and the pill's column is negative, | ||
| + | bmi collision ; 90E3 30 4C it's a collision. | ||
| + | lda LA458,x ; $F9,$F9,$FA ; 90E5 BD 58 A4 | ||
| + | add L85_PILL_COLUMN ; 90E8 18 65 85 and the pill's column - 7 is nonnegative, | ||
| + | bpl collision ; 90EB 10 44 it's a collision. | ||
| + | else ; 90ED 4C F8 90 If the current pill is vertical, | ||
| + | lda LA45B,x ; $00,$FF,$FF,... ; 90F0 BD 5B A4 | ||
| + | add L86_PILL_ROW ; 90F3 18 65 86 and the pill's row is negative, | ||
| + | bmi collision ; 90F6 30 39 it's a collision. | ||
| + | end_if | ||
| + | lda #$00 ; 90F8 A9 00 | ||
| + | sta L57_ ; 90FA 85 57 $57 = 0 | ||
| + | ldx L86_PILL_ROW ; 90FC A6 86 | ||
| + | lda LA474,x ; 120 - x*8 ; 90FE BD 74 A4 | ||
| + | add L85_PILL_COLUMN ; 9101 18 65 85 | ||
| + | sta L47_TEMP ; 9104 85 47 $47 = pill's current position | ||
| + | lda LA6_PILL_SIZE ; 9106 A5 A6 | ||
| + | sub #$02 ; 9108 38 E9 02 | ||
| + | asl a ; 910B 0A | ||
| + | sta L49_TEMP ; 910C 85 49 $49 = 0 | ||
| + | ; L49_TEMP = LA6_PILL_SIZE - 2 | ||
| + | lda LA5_PILL_DIR ; 910E A5 A5 | ||
| + | and #$01 ; 1 = U/D, 0 = L/R ; 9110 29 01 | ||
| + | add L49_TEMP ; 9112 18 65 49 | ||
| + | asl a ; 9115 0A | ||
| + | asl a ; 9116 0A | ||
| + | tax ; 9117 AA x = 0 for horizontal pill, 4 for vertical pill | ||
| + | ; x = ((LA5_PILL_DIR & #1) + L49_TEMP) << 2 | ||
| + | lda #$04 ; 9118 A9 04 | ||
| + | sta L48_TEMP ; 911A 85 48 for(i=0; i<4; i++) | ||
| + | loop | ||
| + | lda LA4C4,x ; 0,1,0,0, f8,0,0,0 ; 911C BD C4 A4 | ||
| + | add L47_TEMP ; 911F 18 65 47 | ||
| + | tay ; 9122 A8 y = pill's position + { horizontal pill -> 0 or 1; vertical pill -> 0 or -8 } | ||
| + | lda ($57),y ; 9123 B1 57 | ||
| + | cmp #$FF ; 9125 C9 FF If the board at index y is not empty, | ||
| + | bne collision ; 9127 D0 08 it's a collision. | ||
| + | inx ; 9129 E8 | ||
| + | dec L48_TEMP ; 912A C6 48 | ||
| + | while_ne ; 912C D0 EE | ||
| + | lda #$00 ; 912E A9 00 It's not a collision. | ||
| + | rts ; 9130 60 | ||
| + | |||
| + | collision: | ||
| + | lda #$FF ; 9131 A9 FF | ||
| + | rts ; 9133 60 | ||
| + | .endscope | ||
| + | |||
| + | |||
| + | ; -------------------------------------- | ||
| + | ; Increment or decrement LA5_PILL_DIR (mod 4) depending on controller input. | ||
| + | R8E2B_PILL_ROTATE: | ||
| + | lda LA5_PILL_DIR ; 8E2B A5 A5 | ||
| + | sta L4A_TEMP ; 8E2D 85 4A | ||
| + | lda L85_PILL_COLUMN ; 8E2F A5 85 | ||
| + | sta L4B_TEMP ; 8E31 85 4B | ||
| + | lda L5B_INPUT_NEW ; 8E33 A5 5B | ||
| + | and #$80 ; "A" ; 8E35 29 80 | ||
| + | if_ne ; 8E37 F0 10 If the user started pressing A, | ||
| + | lda #$05 ; 8E39 A9 05 | ||
| + | sta L06F1_ ; 8E3B 8D F1 06 set $06f1 to 5, | ||
| + | dec LA5_PILL_DIR ; 8E3E C6 A5 | ||
| + | lda LA5_PILL_DIR ; 8E40 A5 A5 | ||
| + | and #$03 ; 8E42 29 03 | ||
| + | sta LA5_PILL_DIR ; 8E44 85 A5 subtract one (mod 4) from the current rotation count, | ||
| + | jsr R8E60_CHECK_ROTATE ; 8E46 20 60 8E and then roll back the change if there's a problem. | ||
| + | end_if | ||
| + | lda L5B_INPUT_NEW ; 8E49 A5 5B | ||
| + | and #$40 ; "B" ; 8E4B 29 40 If the user started pressing B, | ||
| + | if_ne ; 8E4D F0 10 | ||
| + | lda #$05 ; 8E4F A9 05 | ||
| + | sta L06F1_ ; 8E51 8D F1 06 set $06f1 to 5, | ||
| + | inc LA5_PILL_DIR ; 8E54 E6 A5 | ||
| + | lda LA5_PILL_DIR ; 8E56 A5 A5 | ||
| + | and #$03 ; 8E58 29 03 | ||
| + | sta LA5_PILL_DIR ; 8E5A 85 A5 add one (mod 4) to the current rotation count, | ||
| + | jsr R8E60_CHECK_ROTATE ; 8E5C 20 60 8E and then roll back the change if there's a problem. | ||
| + | end_if | ||
| + | rts ; 8E5F 60 | ||
| + | |||
| + | |||
| + | ; -------------------------------------- | ||
| + | ; Adjust or undo pill rotation if there are collisions. | ||
| + | ; Previous DIR and COLUMN values are passed in L4A_TEMP/L4B_TEMP. | ||
| + | R8E60_CHECK_ROTATE: | ||
| + | begin | ||
| + | lda LA5_PILL_DIR ; 8E60 A5 A5 | ||
| + | and #$01 ; 1 = U/D, 0 = L/R ; 8E62 29 01 | ||
| + | if_eq ; 8E64 D0 19 If the current pill is horizontal, | ||
| + | jsr R90D3_COLLISION ; 8E66 20 D3 90 | ||
| + | if_eq ; 8E69 D0 12 and over in-bounds empty space, | ||
| + | lda L5C_INPUT_OLD ; 8E6B A5 5C | ||
| + | and #$02 ; "left" ; 8E6D 29 02 | ||
| + | beq break ; 8E6F F0 1B and the user is not pressing left, return from this function. | ||
| + | dec L85_PILL_COLUMN ; 8E71 C6 85 Move left. | ||
| + | jsr R90D3_COLLISION ; 8E73 20 D3 90 | ||
| + | beq break ; 8E76 F0 14 If the pill is over in-bounds empty space, return from this function. | ||
| + | inc L85_PILL_COLUMN ; 8E78 E6 85 Move right. | ||
| + | jmp break ; 8E7A 4C 8C 8E Return from this function. | ||
| + | end_if | ||
| + | dec L85_PILL_COLUMN ; 8E7D C6 85 Move left. | ||
| + | end_if | ||
| + | jsr R90D3_COLLISION ; 8E7F 20 D3 90 If the current pill is out of bounds or over non-empty space, | ||
| + | beq break ; 8E82 F0 08 | ||
| + | |||
| + | lda L4A_TEMP ; 8E84 A5 4A | ||
| + | sta LA5_PILL_DIR ; 8E86 85 A5 | ||
| + | lda L4B_TEMP ; 8E88 A5 4B | ||
| + | sta L85_PILL_COLUMN ; 8E8A 85 85 roll back to the position and rotation we were at before we started the rotation. | ||
| + | end | ||
| + | rts ; 8E8C 60 | ||
| + | |||
| + | == External resources == | ||
[https://github.com/brianhuffman/drmario Brian Huffman's disassembly notes] | [https://github.com/brianhuffman/drmario Brian Huffman's disassembly notes] | ||
Revision as of 01:41, 13 February 2023
Demo
If you sit idle on the title screen for a while, a demo plays. It's triggered by the frame counter rolling over to 00 8 times in a row. The frame counter cycles through from 00-FF. So this means it takes anywhere from ~29-34 seconds to start ((256 frames * 7 + [1,256] frames) / 60 frames per second). It can be disabled a number of ways, but the simplest way is editing the jump offset (to 0) when it decides to load the demo code (at $9905), accomplishable through the Game Genie code AAAPSP. Next, while the demo board is a generatable one (seed 03BE), it's stored directly in the ROM ($CF00-$CF7F) and loaded into memory. The capsules generated do not match this seed, but they're stored right after the board ($CF80-$CFFF). The controls are stored in pairs of bytes, the first byte being the buttons pressed (bitmask - A, B, Select, Start, Up, Down, Left, Right) and the second being the number of frames to hold down those buttons. These are stored right after the board/capsules at $D000-$D1FF.
Pill movement
This is all the code responsible for moving the pill each frame. The disassembly and function descriptions are from Brian Huffman's disassembly; this version has added detailed English descriptions of the code. I also did a cursory look through the code for what $06f1 does, but I couldn't find anything obvious that read from that address. So either it's dead code, or it's read via indirect addressing.
jsr R8D70_DROP_PILL ; may go to state 1 ; 8D66 20 70 8D
jsr R8DBF_PILL_MOVE ; 8D69 20 BF 8D
jsr R8E2B_PILL_ROTATE ; 8D6C 20 2B 8E
; --------------------------------------
; Called once, in L8D56.
R8D70_DROP_PILL:
begin
lda L43_CLOCK ; 8D70 A5 43
and #$01 ; 8D72 29 01
beq L8D7E ; 8D74 F0 08 Every other frame,
lda L5C_INPUT_OLD ; 8D76 A5 5C
and #$0F ; 8D78 29 0F
cmp #$04 ; "down" ; 8D7A C9 04 if the user is pressing down but not left, right, or up,
beq L8D94 ; 8D7C F0 16 skip ahead to L8D94.
L8D7E:
inc L92_DROP_TIMER ; 8D7E E6 92 Increase the drop counter.
lda L8A_EXTRA_SPEED ; 8D80 A5 8A
sta LA0_TEMP ; redundant copy ; 8D82 85 A0
ldx L8B_SPEED ; 8D84 A6 8B
lda LA38D,x ; $0F,$19,$1F ; 8D86 BD 8D A3 Load the base speed offset for the player-selected speed (low, med, hi),
add LA0_TEMP ; 8D89 18 65 A0 then add in the offset for having played a long time.
tax ; 8D8C AA
lda LA795,x ; drop timer threshold ; 8D8D BD 95 A7 Load the gravity value.
cmp L92_DROP_TIMER ; 8D90 C5 92 If the drop counter is <= the gravity value,
bcs break ; 8D92 B0 2A return from this function.
L8D94:
dec L86_PILL_ROW ; 8D94 C6 86 Move down.
lda #$00 ; 8D96 A9 00
sta L92_DROP_TIMER ; 8D98 85 92 Reset the drop counter to 0.
jsr R90D3_COLLISION ; 8D9A 20 D3 90
if_eq ; 8D9D D0 06 If we are over in-bounds empty space,
lda L86_PILL_ROW ; 8D9F A5 86
cmp #$FF ; 8DA1 C9 FF and not below the board,
bne break ; 8DA3 D0 19 return from this function.
end_if
inc L86_PILL_ROW ; 8DA5 E6 86 Move up.
lda #$07 ; 8DA7 A9 07
sta L06F1_ ; 8DA9 8D F1 06 Set $06F1 to 7.
jsr R8F52_PLACE_PILL ; 8DAC 20 52 8F Lock the pill in place.
; make the program crash if L0740_CHECKSUM_FAIL is nonzero
lda L0740_CHECKSUM_FAIL ; 8DAF AD 40 07
if_ne ; 8DB2 F0 05
lda L53_SPRITE_NUM ; 8DB4 A5 53
pha ; 8DB6 48
pha ; 8DB7 48
pha ; 8DB8 48
end_if
inc L97_GAME_STATE ; 8DB9 E6 97
jmp break ; 8DBB 4C BE 8D
end
rts ; 8DBE 60
; --------------------------------------
; Increment or decrement pill column based on controller input.
; Repeat every 6 frames after holding for 16.
R8DBF_PILL_MOVE:
begin
lda L5B_INPUT_NEW ; 8DBF A5 5B
and #$03 ; left or right ; 8DC1 29 03
if_eq ; 8DC3 D0 15 If the user did not start pressing left or right,
lda L5C_INPUT_OLD ; 8DC5 A5 5C
and #$03 ; left or right ; 8DC7 29 03
beq break ; 8DC9 F0 5F and neither left nor right is currently pressed, return from this function. Otherwise,
inc L93_REPEAT_TIMER ; 8DCB E6 93 increase the DAS counter.
lda L93_REPEAT_TIMER ; 8DCD A5 93
cmp #$10 ; 8DCF C9 10
bmi break ; 8DD1 30 57 If the DAS counter is under 16, return from this function. Otherwise,
lda #$0A ; 8DD3 A9 0A
sta L93_REPEAT_TIMER ; 8DD5 85 93 set the DAS counter to 10.
else ; 8DD7 4C E3 8D If the user started pressing left or right,
lda #$00 ; 8DDA A9 00
sta L93_REPEAT_TIMER ; 8DDC 85 93 set the DAS counter to 0,
lda #$03 ; 8DDE A9 03
sta L06F1_ ; 8DE0 8D F1 06 and set $06F1 to 3.
end_if
lda L5C_INPUT_OLD ; 8DE3 A5 5C
and #$01 ; "right" ; 8DE5 29 01
if_ne ; 8DE7 F0 20 If the user is pressing right,
lda LA5_PILL_DIR ; 8DE9 A5 A5
and #$01 ; 1 = U/D, 0 = L/R ; 8DEB 29 01
add #$06 ; 8DED 18 69 06
cmp L85_PILL_COLUMN ; 8DF0 C5 85
if_ne ; 8DF2 F0 15 and the pill is not in the rightmost column for its orientation,
inc L85_PILL_COLUMN ; 8DF4 E6 85 move right.
jsr R90D3_COLLISION ; 8DF6 20 D3 90
if_eq ; 8DF9 D0 08 If that would put us over in-bounds empty space,
lda #$03 ; 8DFB A9 03
sta L06F1_ ; 8DFD 8D F1 06 set $06F1 to 3.
else ; 8E00 4C 09 8E If that would put us out of bounds or over a non-empty space,
dec L85_PILL_COLUMN ; 8E03 C6 85 move left
lda #$0F ; 8E05 A9 0F
sta L93_REPEAT_TIMER ; 8E07 85 93 and set the DAS counter to 16.
end_if
end_if
end_if
lda L5C_INPUT_OLD ; 8E09 A5 5C
and #$02 ; "left" ; 8E0B 29 02
if_ne ; 8E0D F0 1B If the user is pressing left,
lda L85_PILL_COLUMN ; 8E0F A5 85
cmp #$00 ; 8E11 C9 00
if_ne ; 8E13 F0 15 and we're not in the left-most column,
dec L85_PILL_COLUMN ; 8E15 C6 85 move left.
jsr R90D3_COLLISION ; 8E17 20 D3 90
if_eq ; 8E1A D0 08 If that would put us over in-bounds empty space,
lda #$03 ; 8E1C A9 03
sta L06F1_ ; 8E1E 8D F1 06 set $06F1 to 3.
else ; 8E21 4C 2A 8E If that would put us out of bounds or over a non-empty space,
inc L85_PILL_COLUMN ; 8E24 E6 85 move right,
lda #$0F ; 8E26 A9 0F
sta L93_REPEAT_TIMER ; 8E28 85 93 and set the DAS counter to 16.
end_if
end_if
end_if
end
rts ; 8E2A 60
; ----------------------------------------------------------------------------
; Pill collision detection.
; Returns A = 0, Z set for no collision.
; Returns A = FF, Z clear for collision.
R90D3_COLLISION:
.scope
ldx LA6_PILL_SIZE ; 90D3 A6 A6
dex ; 90D5 CA
dex ; 90D6 CA
lda LA5_PILL_DIR ; 90D7 A5 A5
and #$01 ; 1 = U/D, 0 = L/R ; 90D9 29 01
if_eq ; 90DB D0 13 If the current pill is horizontal,
lda LA455,x ; $00,$FF,$FF ; 90DD BD 55 A4
add L85_PILL_COLUMN ; 90E0 18 65 85 and the pill's column is negative,
bmi collision ; 90E3 30 4C it's a collision.
lda LA458,x ; $F9,$F9,$FA ; 90E5 BD 58 A4
add L85_PILL_COLUMN ; 90E8 18 65 85 and the pill's column - 7 is nonnegative,
bpl collision ; 90EB 10 44 it's a collision.
else ; 90ED 4C F8 90 If the current pill is vertical,
lda LA45B,x ; $00,$FF,$FF,... ; 90F0 BD 5B A4
add L86_PILL_ROW ; 90F3 18 65 86 and the pill's row is negative,
bmi collision ; 90F6 30 39 it's a collision.
end_if
lda #$00 ; 90F8 A9 00
sta L57_ ; 90FA 85 57 $57 = 0
ldx L86_PILL_ROW ; 90FC A6 86
lda LA474,x ; 120 - x*8 ; 90FE BD 74 A4
add L85_PILL_COLUMN ; 9101 18 65 85
sta L47_TEMP ; 9104 85 47 $47 = pill's current position
lda LA6_PILL_SIZE ; 9106 A5 A6
sub #$02 ; 9108 38 E9 02
asl a ; 910B 0A
sta L49_TEMP ; 910C 85 49 $49 = 0
; L49_TEMP = LA6_PILL_SIZE - 2
lda LA5_PILL_DIR ; 910E A5 A5
and #$01 ; 1 = U/D, 0 = L/R ; 9110 29 01
add L49_TEMP ; 9112 18 65 49
asl a ; 9115 0A
asl a ; 9116 0A
tax ; 9117 AA x = 0 for horizontal pill, 4 for vertical pill
; x = ((LA5_PILL_DIR & #1) + L49_TEMP) << 2
lda #$04 ; 9118 A9 04
sta L48_TEMP ; 911A 85 48 for(i=0; i<4; i++)
loop
lda LA4C4,x ; 0,1,0,0, f8,0,0,0 ; 911C BD C4 A4
add L47_TEMP ; 911F 18 65 47
tay ; 9122 A8 y = pill's position + { horizontal pill -> 0 or 1; vertical pill -> 0 or -8 }
lda ($57),y ; 9123 B1 57
cmp #$FF ; 9125 C9 FF If the board at index y is not empty,
bne collision ; 9127 D0 08 it's a collision.
inx ; 9129 E8
dec L48_TEMP ; 912A C6 48
while_ne ; 912C D0 EE
lda #$00 ; 912E A9 00 It's not a collision.
rts ; 9130 60
collision:
lda #$FF ; 9131 A9 FF
rts ; 9133 60
.endscope
; --------------------------------------
; Increment or decrement LA5_PILL_DIR (mod 4) depending on controller input.
R8E2B_PILL_ROTATE:
lda LA5_PILL_DIR ; 8E2B A5 A5
sta L4A_TEMP ; 8E2D 85 4A
lda L85_PILL_COLUMN ; 8E2F A5 85
sta L4B_TEMP ; 8E31 85 4B
lda L5B_INPUT_NEW ; 8E33 A5 5B
and #$80 ; "A" ; 8E35 29 80
if_ne ; 8E37 F0 10 If the user started pressing A,
lda #$05 ; 8E39 A9 05
sta L06F1_ ; 8E3B 8D F1 06 set $06f1 to 5,
dec LA5_PILL_DIR ; 8E3E C6 A5
lda LA5_PILL_DIR ; 8E40 A5 A5
and #$03 ; 8E42 29 03
sta LA5_PILL_DIR ; 8E44 85 A5 subtract one (mod 4) from the current rotation count,
jsr R8E60_CHECK_ROTATE ; 8E46 20 60 8E and then roll back the change if there's a problem.
end_if
lda L5B_INPUT_NEW ; 8E49 A5 5B
and #$40 ; "B" ; 8E4B 29 40 If the user started pressing B,
if_ne ; 8E4D F0 10
lda #$05 ; 8E4F A9 05
sta L06F1_ ; 8E51 8D F1 06 set $06f1 to 5,
inc LA5_PILL_DIR ; 8E54 E6 A5
lda LA5_PILL_DIR ; 8E56 A5 A5
and #$03 ; 8E58 29 03
sta LA5_PILL_DIR ; 8E5A 85 A5 add one (mod 4) to the current rotation count,
jsr R8E60_CHECK_ROTATE ; 8E5C 20 60 8E and then roll back the change if there's a problem.
end_if
rts ; 8E5F 60
; --------------------------------------
; Adjust or undo pill rotation if there are collisions.
; Previous DIR and COLUMN values are passed in L4A_TEMP/L4B_TEMP.
R8E60_CHECK_ROTATE:
begin
lda LA5_PILL_DIR ; 8E60 A5 A5
and #$01 ; 1 = U/D, 0 = L/R ; 8E62 29 01
if_eq ; 8E64 D0 19 If the current pill is horizontal,
jsr R90D3_COLLISION ; 8E66 20 D3 90
if_eq ; 8E69 D0 12 and over in-bounds empty space,
lda L5C_INPUT_OLD ; 8E6B A5 5C
and #$02 ; "left" ; 8E6D 29 02
beq break ; 8E6F F0 1B and the user is not pressing left, return from this function.
dec L85_PILL_COLUMN ; 8E71 C6 85 Move left.
jsr R90D3_COLLISION ; 8E73 20 D3 90
beq break ; 8E76 F0 14 If the pill is over in-bounds empty space, return from this function.
inc L85_PILL_COLUMN ; 8E78 E6 85 Move right.
jmp break ; 8E7A 4C 8C 8E Return from this function.
end_if
dec L85_PILL_COLUMN ; 8E7D C6 85 Move left.
end_if
jsr R90D3_COLLISION ; 8E7F 20 D3 90 If the current pill is out of bounds or over non-empty space,
beq break ; 8E82 F0 08
lda L4A_TEMP ; 8E84 A5 4A
sta LA5_PILL_DIR ; 8E86 85 A5
lda L4B_TEMP ; 8E88 A5 4B
sta L85_PILL_COLUMN ; 8E8A 85 85 roll back to the position and rotation we were at before we started the rotation.
end
rts ; 8E8C 60