This page contains copyright code which was written by Matthew Smith for the long-since dissolved companies Bug-Byte and Software Projects. In a private email of 31st August 1999, he gave me his permission to post disassemblies of MM and JSW, provided that they include the following line at the top and bottom of the file:
(C) 1983,1984,1999 Matthew Smith - all rights reserved
There are several annotated disassemblies of Manic Miner and Jet Set Willy in existence:
This page presents Carl Woffenden's annotated disassemblies of various code-fragments in MM/JSW - thanks to him for sending me the last revisions and for permission to host them:
B8068: DEFB 0 ; Willy's y * 2 B8069: DEFB 0 ; Willy's anim frame 0 - 3 B806A: DEFB 0 ; Willy's walking/facing flag: ; bit-0 = off - right, on - left ; bit-1 = off - still, on - walk B806B: DEFB 0 ; Willy's action: ; -1: dead ; 0: walking/standing ; 1: jumping ; 2: falling ; >2: fall height W806C: DEFW 0 ; Willy's position in attribute buffer B806E: DEFB 0 ; Willy's jump phase counter (0x00 - 0x12) ; movement lookup table: T8408: DEFB 0,1,0,1,1,3,1,3,2,0,2,0,0,1,2,3 ; *************************** start of movement code ************************* C8ABB: LD A,(B806B) ; action states CP 1 JR NZ,R8B10 ; branch (+50) if not currently JUMPING LD A,(B806E) ; JUMP phase counter RES 0,A SUB 8 LD HL,B8068 ; address of Willy's y * 2 ADD A,(HL) LD (HL),A ; jump height algorithm is (y * 2 & 0xFE) - 8 CALL C8B82 ; update Willy's attribute buffer position LD A,(B803B) ; wall attr CP (HL) ; HL now holding attribute buffer position JP Z,L8BA2 ; branch if Willy's head hits wall INC HL ; move one col right CP (HL) JP Z,L8BA2 ; branch if Willy's head hits wall LD A,(B806E) ; JUMP phase counter INC A LD (B806E),A ; store incremented JUMP phase SUB 8 ; **** beeper starts here **** JP P,L8AEB ; branch if SUB 8 goes below 0 NEG ; else phase = 0 - phase L8AEB: INC A RLCA RLCA RLCA ; multiply height by 16 LD D,A LD C,20h LD A,(BORDER) ; maintain border colour R8AF5: OUT (0FEh),A XOR 18h ; toggle ear/mic bits LD B,D R8AFA: DJNZ R8AFA ; wait/pitch based on height DEC C JR NZ,R8AF5 ; **** beeper ends here (after 32 cycles) **** LD A,(B806E) ; JUMP phase counter CP 12h ; 18 steps in a JUMP JP Z,L8B96 ; branch if at end of JUMP phase CP 10h ; [dunno yet why 16?] JR Z,R8B10 ; [+07] CP 0Dh ; [dunno yet why 12?] JP NZ,L8C83 ; branch if not 12 (do horizontal movement) ; entry for manual control R8B10: LD A,(B8068) ; Willy's y * 2 AND 0Fh ; **** JSW is 0x0E **** JR NZ,R8B51 ; branch (+3C) if y isn't row aligned LD HL,(W806C) ; Willy's position in attribute buffer LD DE,64 ADD HL,DE ; move two rows down LD A,(B8032) ; crumble attr CP (HL) CALL Z,C8BBA ; matched crumble LD A,(B804D) ; nasty (1) attr CP (HL) JR Z,R8B51 ; branch (+28) if matched nasty LD A,(B8056) ; nasty (2) attr CP (HL) JR Z,R8B51 ; branch (+22) if matched nasty INC HL ; move one col right (and redo the matches) LD A,(B8032) ; crumble attr CP (HL) CALL Z,C8BBA ; branch if matched crumble LD A,(B804D) ; nasty (1) attr CP (HL) JR Z,R8B51 ; branch (+14) if matched nasty LD A,(B8056) ; nasty (2) attr CP (HL) JR Z,R8B51 ; branch (+0E) if matched nasty LD A,(B8020) ; bkgnd attr CP (HL) DEC HL ; move one col left JP NZ,L8BDD ; not matched bkgnd (from earlier CP before DEC) CP (HL) JP NZ,L8BDD ; branch if not matched bkgnd R8B51: LD A,(B806B) ; Willy's action CP 1 JP Z,L8C83 ; branch if JUMPING (do horizontal movement) LD HL,B806A ; walking/facing flags RES 1,(HL) ; reset walking bit OR A JP Z,L8B9C ; branch if STANDING (this sets FALLING flag) INC A ; else falling so increment fall height LD (B806B),A ; then store it RLCA ; **** beeper starts here **** RLCA RLCA RLCA ; multiply height by 16 LD D,A LD C,20h LD A,(BORDER) ; maintain border colour R8B70: OUT (0FEh),A ; make a noise XOR 18h ; toggle ear/mic bits LD B,D R8B75: DJNZ R8B75 ; wait/pitch based on height DEC C JR NZ,R8B70 ;$-08 ; **** beeper ends here (after 32 cycles) **** LD A,(B8068) ; Willy's y * 2 ADD A,8 ; fall 4 pixels down LD (B8068),A ; then store value C8B82: ; arrive here with A holding Willy's y * 2 AND 0F0h ; align to nearest row (0, 16, 32, etc.) LD L,A XOR A ; clear A RL L ; double (y * 2) using carry for next ADC ADC A,5Ch ; 0x5C00 being start of attribute buffer LD H,A LD A,(W806C) ; Willy's position in attribute buffer AND 1Fh ; col mask OR L ; current row (minus its MSB) LD L,A LD (W806C),HL ; Willy's position updated RET L8B96: ; change from JUMPING to FALLING LD A,6 LD (B806B),A ; sets action/fall distance to 6? RET L8B9C: LD A,2 LD (B806B),A ; sets action flag to FALLING RET ; when Willy's head hits a wall while JUMPING L8BA2: LD A,(B8068) ; Willy's y * 2 ADD A,10h ; 8 pixels (one block) down AND 0F0h ; rounded to nearest block LD (B8068),A ; then store it CALL C8B82 ; set Willy's attribute buffer position LD A,2 LD (B806B),A ; sets action flag to FALLING LD HL,B806A ; walking/facing flag RES 1,(HL) ; reset WALKING bit RET ; Sent here because a crumble block matched. HL contains the block's address ; in the attribute buffer. Basically it handles the crumbling blocks until ; they finally become bkgnd blocks. C8BBA: LD C,L LD A,H ADD A,1Bh OR 7 LD B,A R8BC1: DEC B LD A,(BC) INC B LD (BC),A DEC B LD A,B AND 7 JR NZ,R8BC1 ;$-08 XOR A LD (BC),A LD A,B ADD A,7 LD B,A LD A,(BC) OR A RET NZ LD A,(B8020) ; bkgnd attr INC H INC H LD (HL),A ; set the block to bkgnd DEC H DEC H RET L8BDD: ; HL is currently attributes under Willy's feet LD A,(B806B) ; Willy's action/fall distance CP 0Ch JP NC,L8D06 ; branch if fallen beyond 12 (dead) LD E,0FFh ; equivalent to nothing pressed (active low) XOR A LD (B806B),A ; Willy's action set to STANDING LD A,(B8044) ; conveyor attr CP (HL) JR Z,R8BF5 ; branch (+06) if matched conveyor INC HL ; move one col right CP (HL) JR NZ,R8BFB ; branch (+08) if not matched conveyor R8BF5: LD A,(B806F) ; conveyor direction SUB 3 ; left = 253 (LSBs 01), right 254 (LSBs 10) LD E,A R8BFB: ; the input routines LD BC,0DFFEh IN A,(C) ; read Y, U, I, O, P AND 1Fh ; mask key bits (0-4) OR 20h ; set bit-5 (used for LEFT presses later) AND E LD E,A LD BC,0FBFEh IN A,(C) ; read Q, W, E, R, T AND 1Fh ; mask key bits (0-4) RLC A ; changes key sequence to L-R not R-L OR 1 ; 'unpresses' a RIGHT key AND E LD E,A LD B,0F7h IN A,(C) ; read 1, 2, 3, 4, 5 RRCA ; only interested in key 5 (now at bit-3) OR 0F7h ; so mask (active low) AND E LD E,A LD B,0EFh IN A,(C) ; read 6, 7, 8, 9, 0 OR 0FBh ; mask key 8 (bit-2, active low) AND E LD E,A LD A,(KEMP) OR A JR Z,R8C34 ; branch (+0C) if no joystick connected LD BC,1Fh IN A,(C) ; else read joystick port AND 3 ; left and right mask (bits are xxxFUDLR) CPL ; because Kempston is active high AND E LD E,A R8C34: ; reach here with E holding key/joystick data LD C,0 LD A,E AND 2Ah ; 0x2A = 101010 - mask all LEFT keys CP 2Ah JR Z,R8C3F ; branch if no LEFT keys pressed inc. conveyor LD C,4 ; else set LEFT flag (bit-2) R8C3F: LD A,E AND 15h ; 0x15 = 010101 - mask all RIGHT keys CP 15h JR Z,R8C48 ; branch if no RIGHT keys pressed inc. conveyor SET 3,C ; else set RIGHT flag (bit-3) R8C48: LD A,(B806A) ; flag bits (bit-0 direction, bit-1 walking) ADD A,C ; combined with current key presses LD C,A LD B,0 LD HL,T8408 ; movement lookup table ADD HL,BC ; offset into table LD A,(HL) LD (B806A),A ; flag bits are now set from the table LD BC,07EFEh IN A,(C); ; read bottom row CAPS to SPACE AND 1Fh ; mask key bits (0-4) CP 1Fh JR NZ,R8C7B ; branch (+1B) if any key at all is pressed LD B,0EFh IN A,(C) ; read 6, 7, 8, 9, 0 AND 9 ; mask keys 7 and 0 CP 9 JR NZ,R8C7B ; branch (+11) if any key at all is pressed LD A,(KEMP) ; no jump key pressed so we check the joystick OR A JR Z,L8C83 ; none connected so do horizontal movement (+13) LD BC,1Fh IN A,(C) ; read Kempston joystick BIT 4,A ; fire bit JR Z,L8C83 ; fire not pressed so do horizontal movement R8C7B: XOR A LD (B806E),A ; set the jump counter to 0 INC A LD (B806B),A ; set the action flag to 1 (for jumping) ; horizontal movement L8C83: LD A,(B806A) ; walking/facing flags AND 2 ; walking bit RET Z ; not currently moving so return LD A,(B806A) AND 1 ; facing flag JP Z,L8CCA ; flag = 0 so go right ; else go left LD A,(B8069) ; Willy's anim frame OR A JR Z,R8C9C ; branch (+07) if frame 0 (far left of 16x16) DEC A ; else decrement it LD (B8069),A RET ; nothing else to check R8C9C: LD HL,(W806C) ; Willy's position on attribute buffer DEC HL ; move one col left LD DE,32 ADD HL,DE ; move one row down LD A,(B803B) ; wall attr CP (HL) RET Z ; return if we hit a wall (Willy's feet block) LD A,(B8068) ; Willy's y * 2 AND 0Fh JR Z,R8CB9 ; branch (+0B) if y is block aligned LD A,(B803B) ; wall attr ADD HL,DE ; move one row down again CP (HL) RET Z ; return if we hit a wall (below Willy's feet) OR A ; [this must be to reset the carry flag?] SBC HL,DE ; move one row up R8CB9: LD A,(B803B) ; wall attr OR A ; [this must be to reset the carry flag?] SBC HL,DE ; move one row up again CP (HL) RET Z ; return if we hit a wall (Willy's head block) LD (W806C),HL ; update Willy's position LD A,3 ; frame 3 (far right if 16x16) LD (B8069),A ; update Willy's anim frame RET ; moving right L8CCA: LD A,(B8069) ; Willy's anim frame CP 3 JR Z,R8CD6 ; branch (+07) if frame 3 (far right of 16x16) INC A ; else increment it LD (B8069),A RET ; nothing else to check R8CD6: LD HL,(W806C) ; Willy's position on attribute buffer INC HL INC HL ; move 2 cols right (block to right of Willy) LD DE,32 LD A,(B803B) ; wall attr ADD HL,DE ; move one row down CP (HL) RET Z ; return if we hit a wall (Willy's feet block) LD A,(B8068) ; Willy's y * 2 AND 0Fh JR Z,R8CF4 ; branch (+0B) if y is block aligned LD A,(B803B) ; wall attr ADD HL,DE ; move one row down again CP (HL) RET Z ; return if we hit a wall (below Willy's feet) OR A ; [this must be to reset the carry flag?] SBC HL,DE ; move one row back up R8CF4: LD A,(B803B) ; wall attr OR A ; [this must be to reset the carry flag?] SBC HL,DE ; move one row up again CP (HL) RET Z ; return if we hit a wall (Willy's head block) DEC HL ; all was ok so move back left by one col LD (W806C),HL ; and update Willy's position XOR A ; sets frame to zero (far left of 16x16) LD (B8069),A ; update Willy's anim frame RET L8D05: POP HL L8D06: POP HL L8D07: LD A,0FFh ; Willy has been killed (#806B = 0xFF) LD (B806B),A JP L87A2 ; *************************** end of movement code *************************** ; *********************** Some extra collision checking ********************** C923A: LD HL,(W806C) ; Willy's position in attribute buffer LD DE,31 LD C,0Fh CALL C925F INC HL ; move one col right CALL C925F ADD HL,DE ; move one row down and one col left CALL C925F INC HL ; move one col right CALL C925F LD A,(B8068) ; Willy's y * 2 LD C,A ADD HL,DE ; move one row down and one col left CALL C925F INC HL ; move one col right CALL C925F JR R927F C925F: LD A,(B8020) ; bkgnd attr CP (HL) JR NZ,R9270 ; branch (+0D) if not bkgnd LD A,C AND 0Fh JR Z,R9270 ; branch (+08) if y is block aligned LD A,(B8020) ; bkgnd attr OR 7 LD (HL),A R9270: LD A,(B804D) ; nasty (1) attr CP (HL) JP Z,L8D05 ; killed LD A,(B8056) ; nasty (2) attr CP (HL) JP Z,L8D05 ; killed RET ; draw Willy (run out of steam here but the result is obvious enough) R927F: LD A,(B8068) ; Willy's y * 2 LD IXH,83h LD IXL,A LD A,(B806A) ; Willy's walking/facing flags AND 1 ; facing mask RRCA LD E,A LD A,(B8069) ; Willy's anim frame AND 3 ; frames mask RRCA RRCA RRCA ; frame multiplied by 8 OR E LD E,A LD D,82h ; as in 0x8200, start address for Willy's frames LD B,10h ; 16 lines LD A,(W806C) ; Willy's position in attribute buffer AND 1Fh ; just the col LD C,A R92A2: LD A,(IX+0) LD H,(IX+1) OR C LD L,A LD A,(DE) OR (HL) LD (HL),A INC HL INC DE LD A,(DE) OR (HL) LD (HL),A INC IX INC IX INC DE DJNZ R92A2 ; loop (-15) until all lines are drawn RET ; ************************** End of collision checking ***********************
Jet Set Willy Manic Miner (Bug Byte) 900A: 8C9C: LD HL, (#85D3) LD HL,(#806C) ; Willy's attr buffer position LD A, L AND #1F JP Z, #948A ; branch if exit right of room ADD HL, BC DEC HL DEC HL ; one col left LD DE, 32 LD DE, 32 ADD HL, DE ADD HL, DE ; one row down LD A, (#80B2) LD A, (#803B) ; wall attr from working room CP (HL) CP (HL) RET Z RET Z ; return if we hit a wall LD A, (#85CF) LD A, (#8068) ; Willy's y (really y * 2) SRA C ; BC contains ramp offset ADD C LD B, A AND #0F AND #0F JR Z, #9032 JR Z, #8CB9 ; branch if y is block aligned LD A, (#80B2) LD A, (#803B) ; wall attr from working room ADD HL, DE ADD HL, DE ; one row down CP (HL) CP (HL) RET Z RET Z ; return if we hit a wall OR A OR A SBC HL, DE SBC HL, DE ; one row back up 9032: 8CB9: LD A, (#803B) ; wall attr from working room OR A OR A SBC HL, DE SBC HL,DE ; one row up again CP (HL) RET Z ; return if we hit a wall LD (#85D3), HL LD (#806C), HL ; update Willy's position LD A, B LD (#85CF), A ; store updated y LD A, 3 LD A, 3 ; frame 3 (far right of 16x16) LD (#85D2), A LD (#8069),A ; update Willy's anim frame RET RET
; Original disassembly taken from Geoff Eddy's website. 8000 DEFS #0100 ; data for current room 8100 DEFS #0048 ; guardians in current room 8148 DEFS #00B8 ; blank 8200 DEFS #0100 ; screen coord lookup table ; (#8200 + 2y) contains address of first ; byte in line y (of 128). 8300 DEFS #0080 ; x-offsets between successive dots in a rope. ; All bytes are 0-6, thus: ; 00000000000000000000000000000000 ; 11111111111122222222222222222222 ; 22122112112232323333330000000000 ; 00000000000000000000000000000000 8380 DEFS #0080 ; y-offsets, similarly ; 66666666666666666666666666666666 ; 66666666666666664664646464446444 ; 44444444444444444444440000000000 ; 00000000000000000000000000000000 8400 DEFS #0020 ; attributes of the "Press Enter" message ; on the title screen. @@@ 8420 21 DEFB #21 ; current room number 8421 00010001 DEFS 4 ; Willy state transition table 8425 01030103 DEFS 4 8429 02000200 DEFS 4 842D 00010203 DEFS 4 8431 DEFS #20 ; UDGs for title screen 8451 FF DEFB #FF ; total number of items @@@ (was at #A3FF) 8452 6F6F DEFM "oo" ; spare bytes 8454 DEFS #0100 ; scrolling message on title screen 8554 DEFS #20 ; "Items collected" "time left" string 8574 DEFM "Game Over00099999999999999" 858D DEFS #3E ; zeros (used to be security messages @@@) 85CB DEFS #1A ; timer; just counts from 0 to ff 85CC 10 DEFB #10 ; number of lives @@@ (was 7) 85CD 00 DEFB #00 ; counter 85CE 00 DEFB #00 ; Kempston flag ; These variables are set up when a room is entered and copied to the ; set at 85D7-DD. They are copied back when a life is lost. 85CF D0 DEFB #D0 ; Willy's y * 2 (used for buffer table offset) 85D0 00 DEFB #00 ; Willy's walking/facing flag: ; bit-0 = off - right, on - left ; bit-1 = off - still, on - walk 85D1 00 DEFB #00 ; Willy's action: ; -1: dead ; 0: walking/standing ; 1: jumping ; 2: falling ; >2: fall height 85D2 00 DEFB #00 ; Willy's anim frame 0-3 85D3 B45D DEFW #5DB4 ; Willy's position 0101|110Y|YYYX|XXXX ; actually an address in the attribute buffer 85D5 00 DEFB #00 ; Willy's jump phase counter (0 - 18) 85D6 00 DEFB #00 ; Willy's rope dot position or rope grab delay 85D7 DEFS 7 ; copies of #85CF-#85D5 used after dying 85DE 00 DEFB #00 ; number of items collected 85DF 00 DEFB #00 ; game/item status: ; 0: normal 1: all collected 2: running from bedroom 3: in toilet 85E0 00 DEFB #00 ; pause counter ; *************************** start of movement code ************************* 8DD3 3AD685 LD A, (#85D6) ; Willy's dot when on a rope 8DD6 3D DEC A ; not on a rope = -1 8DD7 CB7F BIT 7, A ; not on rope or rope delay signified by bit-7 8DD9 CAD48E JP Z, #8ED4 ; branch if on rope 8DDC 3AD185 LD A, (#85D1) ; action states 8DDF FE01 CP #01 8DE1 2053 JR NZ, #8E36 ; branch if not currently JUMPING 8DE3 3AD585 LD A, (#85D5) ; JUMP phase counter 8DE6 E6FE AND #FE 8DE8 D608 SUB #08 8DEA 21CF85 LD HL, #85CF ; address of Willy's y * 2 8DED 86 ADD (HL) 8DEE 77 LD (HL), A ; jump height is (y * 2 & 0xFE) - 8 8DEF FEF0 CP #F0 8DF1 D2B094 JP NC, #94B0 ; jumped into room above 8DF4 CD9C8E CALL #8E9C ; update Willy's attribute buffer position 8DF7 3AB280 LD A, (#80B2) ; wall attr 8DFA BE CP (HL) 8DFB CABC8E JP Z, #8EBC ; branch if Willy's head hits wall 8DFE 23 INC HL ; move one col right 8DFF BE CP (HL) 8E00 CABC8E JP Z, #8EBC ; branch if Willy's head hits wall 8E03 3AD585 LD A, (#85D5) ; JUMP phase counter 8E06 3C INC A 8E07 32D585 LD (#85D5), A ; store incremented JUMP phase 8E0A D608 SUB #08 ; **** beeper starts here **** 8E0C F2118E JP P, #8E11 ; branch if SUB 8 goes below 0 8E0F ED44 NEG ; else phase = 0 - phase 8E11 3C INC A 8E12 07 RLCA 8E13 07 RLCA 8E14 07 RLCA ; multiply height by 16 8E15 57 LD D, A 8E16 0E20 LD C, #20 8E18 3ADE80 LD A, (#80DE) ; maintain border colour 8E1B D3FE OUT (#FE), A 8E1D EE18 XOR #18 ; toggle ear/mic bits 8E1F 42 LD B, D 8E20 10FE DJNZ #8E20 ; wait/pitch based on height 8E22 0D DEC C 8E23 20F6 JR NZ, #8E1B ; **** beeper ends here (after 32 cycles) **** 8E25 3AD585 LD A, (#85D5) ; JUMP phase counter 8E28 FE12 CP #12 ; 0x12 being 18 steps in a JUMP 8E2A CAB08E JP Z, #8EB0 ; branch if at end of JUMP phase 8E2D FE10 CP #10 8E2F 2805 JR Z, #8E36 8E31 FE0D CP #0D 8E33 C2BC8F JP NZ, #8FBC ; branch if not 12 (do horizontal movement) 8E36 3ACF85 LD A, (#85CF) ; Willy's y * 2 8E39 E60E AND #0E ; *** note: this is 0x0E in MM *** 8E3B 2025 JR NZ, #8E62 ; branch if y isn't row aligned 8E3D 2AD385 LD HL, (#85D3) ; Willy's position in attribute buffer 8E40 114000 LD DE, 64 8E43 19 ADD HL, DE 8E44 CB4C BIT 1, H 8E46 C2D294 JP NZ, #94D2 ; branch if we're in the room below 8E49 3ABB80 LD A, (#80BB) ; nasty attr 8E4C BE CP (HL) 8E4D 2813 JR Z, #8E62 ; branch if matched nasty 8E4F 23 INC HL ; move one col right 8E50 3ABB80 LD A, (#80BB) ; nasty attr 8E53 BE CP (HL) 8E54 280C JR Z, #8E62 ; branch if matched nasty 8E56 3AA080 LD A, (#80A0) ; bkgnd attr 8E59 BE CP (HL) 8E5A 2B DEC HL ; move one col left (resets HL to left foot) 8E5B C2D48E JP NZ, #8ED4 ; branch if not matched bkgnd 8E5E BE CP (HL) 8E5F C2D48E JP NZ, #8ED4 ; branch if not matched bkgnd ; There is no ground below Willy; why? 8E62 3AD185 LD A, (#85D1) ; Willy's action (standing/jumping/falling) 8E65 FE01 CP #01 8E67 CABC8F JP Z, #8FBC ; branch if JUMPING (do horizontal movement) 8E6A 21D085 LD HL, #85D0 ; walking/facing flags 8E6D CB8E RES 1, (HL) ; reset walking bit 8E6F 3AD185 LD A, (#85D1) ; Willy's action (dunno why it's LDed again?) 8E72 B7 OR A 8E73 CAB68E JP Z, #8EB6 ; branch if STANDING (this sets FALLING flag) 8E76 3C INC A ; else falling so increment fall height 8E77 FE10 CP #10 ; *** MM differences *** 8E79 2002 JR NZ, #8E7D ; *** need to investigate!!! *** 8E7B 3E0C LD A, #0C 8E7D 32D185 LD (#85D1), A ; then store it 8E80 07 RLCA ; **** beeper starts here **** 8E81 07 RLCA 8E82 07 RLCA 8E83 07 RLCA ; multiply height by 16 8E84 57 LD D, A 8E85 0E20 LD C, #20 8E87 3ADE80 LD A, (#80DE) ; maintain border colour 8E8A D3FE OUT (#FE), A ; make a noise 8E8C EE18 XOR #18 ; toggle ear/mic bits 8E8E 42 LD B, D 8E8F 10FE DJNZ #8E8F 8E91 0D DEC C 8E92 20F6 JR NZ, #8E8A ; **** beeper ends here (after 32 cycles) **** 8E94 3ACF85 LD A, (#85CF) ; Willy's y * 2 8E97 C608 ADD #08 ; 4 pixels down 8E99 32CF85 LD (#85CF), A ; then store it ; arrive here with A holding Willy's y * 2 8E9C E6F0 AND #F0 ; align to nearest row (0, 16, 32, etc.) 8E9E 6F LD L, A 8E9F AF XOR A 8EA0 CB15 RL L 8EA2 CE5C ADC #5C ; 0x5C00 being start of attribute buffer 8EA4 67 LD H, A 8EA5 3AD385 LD A, (#85D3) ; Willy's attribute buffer position 8EA8 E61F AND #1F ; col mask 8EAA B5 OR L 8EAB 6F LD L, A 8EAC 22D385 LD (#85D3), HL ; Willy's position updated 8EAF C9 RET ; ; change from JUMPING to FALLING 8EB0 3E06 LD A, #06 8EB2 32D185 LD (#85D1), A ; sets action/fall distance to 6? 8EB5 C9 RET ; 8EB6 3E02 LD A, #02 8EB8 32D185 LD (#85D1), A ; sets action flag to FALLING 8EBB C9 RET ; Willy has hit something while jumping. 8EBC 3ACF85 LD A, (#85CF) ; Willy's y * 2 8EBF C610 ADD #10 ; 8 pixels (one block) down 8EC1 E6F0 AND #F0 ; rounded to nearest block 8EC3 32CF85 LD (#85CF), A ; then store it 8EC6 CD9C8E CALL #8E9C ; set Willy's attribute buffer position 8EC9 3E02 LD A, #02 8ECB 32D185 LD (#85D1), A ; sets action flag to FALLING 8ECE 21D085 LD HL, #85D0 ; walking/facing flag 8ED1 CB8E RES 1, (HL) ; reset WALKING bit 8ED3 C9 RET ; HL is currently attributes under Willy's feet 8ED4 1EFF LD E, #FF ; equivalent to nothing pressed (active low) 8ED6 3AD685 LD A, (#85D6) ; Willy's y when on a rope 8ED9 3D DEC A 8EDA CB7F BIT 7, A 8EDC 281C JR Z, #8EFA ; branch if on a rope 8EDE 3AD185 LD A, (#85D1) ; Willy's action/fall distance 8EE1 FE0C CP #0C 8EE3 D2B790 JP NC, #90B7 ; branch if fallen beyond 12 (dead) 8EE6 AF XOR A 8EE7 32D185 LD (#85D1), A ; Willy's action set to STANDING (0) 8EEA 3ACD80 LD A, (#80CD) ; conveyor attr 8EED BE CP (HL) 8EEE 2804 JR Z, #8EF4 ; branch if matched conveyor 8EF0 23 INC HL ; move one col right 8EF1 BE CP (HL) 8EF2 2006 JR NZ, #8EFA ; branch if not matched conveyor 8EF4 3AD680 LD A, (#80D6) ; conveyor direction 8EF7 D603 SUB #03 ; left = 253 (LSBs 01), right 254 (LSBs 10) 8EF9 5F LD E, A ; the input routines 8EFA 01FEDF LD BC, #DFFE 8EFD ED78 IN A, (C) ; read Y, U, I, O, P 8EFF E61F AND #1F ; mask only key bits (0-4) 8F01 F620 OR #20 ; set bit-5 (used for LEFT presses later) 8F03 A3 AND E 8F04 5F LD E, A 8F05 3ADF85 LD A, (#85DF) ; All items collected? *** Not MM *** 8F08 E602 AND #02 8F0A 0F RRCA 8F0B AB XOR E 8F0C 5F LD E, A ; *** End of not MM section *** 8F0D 01FEFB LD BC, #FBFE 8F10 ED78 IN A, (C) ; read Q, W, E, R, T 8F12 E61F AND #1F ; mask key bits (0-4) 8F14 CB07 RLC A ; changes key sequence to L-R not R-L 8F16 F601 OR #01 ; 'unpresses' a RIGHT key 8F18 A3 AND E 8F19 5F LD E, A 8F1A 06EF LD B, #EF 8F1C ED78 IN A, (C) ; read 6, 7, 8, 9, 0 8F1E 0F RRCA ; only interested in key 6 (now at bit-3) 8F1F F6F7 OR #F7 ; so mask (active low) 8F21 A3 AND E 8F22 5F LD E, A 8F23 06EF LD B, #EF 8F25 ED78 IN A, (C) ; read 6, 7, 8, 9, 0 8F27 F6FB OR #FB ; mask key 8 (bit-2, active low) 8F29 A3 AND E 8F2A 5F LD E, A 8F2B ED78 IN A, (C) ; read 6, 7, 8, 9, 0 8F2D 0F RRCA ; only interested in key 7 (now at bit-2) 8F2E F6FB OR #FB ; so mask (active low) 8F30 A3 AND E 8F31 5F LD E, A 8F32 3ACE85 LD A, (#85CE) 8F35 B7 OR A 8F36 280A JR Z, #8F42 ; branch if no joystick connected 8F38 011F00 LD BC, #001F 8F3B ED78 IN A, (C) ; else read joystick port 8F3D E603 AND #03 ; left and right mask (bits are xxxFUDLR) 8F3F 2F CPL ; because Kempston is active high 8F40 A3 AND E ; reach here with E holding key/joystick data 8F41 5F LD E, A 8F42 0E00 LD C, #00 8F44 7B LD A, E 8F45 E62A AND #2A 8F47 FE2A CP #2A 8F49 2806 JR Z, #8F51 8F4B 0E04 LD C, #04 8F4D AF XOR A 8F4E 32E085 LD (#85E0), A 8F51 7B LD A, E 8F52 E615 AND #15 8F54 FE15 CP #15 8F56 2806 JR Z, #8F5E 8F58 CBD9 SET 3, C 8F5A 8F ADC A 8F5B 32E085 LD (#85E0), A 8F5E 3AD085 LD A, (#85D0) 8F61 81 ADD C 8F62 4F LD C, A 8F63 0600 LD B, #00 8F65 212184 LD HL, #8421 8F68 09 ADD HL, BC 8F69 7E LD A, (HL) 8F6A 32D085 LD (#85D0), A 8F6D 01FE7E LD BC, #7EFE 8F70 ED78 IN A, (C) ; read bottom row CAPS to SPACE 8F72 E61F AND #1F ; mask key bits (0-4) 8F74 FE1F CP #1F 8F76 2017 JR NZ, #8F8F ; branch if any key at all is pressed 8F78 06EF LD B, #EF 8F7A ED78 IN A, (C) ; read 6, 7, 8, 9, 0 8F7C CB47 BIT 0, A 8F7E 280F JR Z, #8F8F ; branch if 0 (bit-0) is pressed 8F80 3ACE85 LD A, (#85CE) ; no jump key pressed so we check the joystick 8F83 B7 OR A 8F84 2836 JR Z, #8FBC ; none connected so do horizontal movement 8F86 011F00 LD BC, #001F 8F89 ED78 IN A, (C) ; read Kempston joystick 8F8B CB67 BIT 4, A ; fire bit 8F8D 282D JR Z, #8FBC ; fire not pressed so do horizontal movement 8F8F 3ADF85 LD A, (#85DF) ; *** Item to collect? *** 8F92 CB4F BIT 1, A 8F94 2026 JR NZ, #8FBC 8F96 AF XOR A 8F97 32D585 LD (#85D5), A ; set JUMP phase counter to 0 8F9A 32E085 LD (#85E0), A ; set PAUSE counter to 0 8F9D 3C INC A 8F9E 32D185 LD (#85D1), A ; set the action flag to 1 (for jumping) 8FA1 3AD685 LD A, (#85D6) ; Willy's y when on a rope 8FA4 3D DEC A 8FA5 CB7F BIT 7, A 8FA7 2013 JR NZ, #8FBC ; branch if not on a rope 8FA9 3EF0 LD A, #F0 8FAB 32D685 LD (#85D6), A 8FAE 3ACF85 LD A, (#85CF) 8FB1 E6F0 AND #F0 8FB3 32CF85 LD (#85CF), A 8FB6 21D085 LD HL, #85D0 8FB9 CBCE SET 1, (HL) 8FBB C9 RET ; could be move decision code? 8FBC 3AD085 LD A, (#85D0) ; move state 8FBF E602 AND #02 8FC1 C8 RET Z 8FC2 3AD685 LD A, (#85D6) ; Willy's y when on a rope 8FC5 3D DEC A 8FC6 CB7F BIT 7, A 8FC8 C8 RET Z ; return if on rope 8FC9 3AD085 LD A, (#85D0) 8FCC E601 AND #01 8FCE CA4290 JP Z, #9042 ; move left 8FD1 3AD285 LD A, (#85D2) ; Willy's phase 8FD4 B7 OR A 8FD5 2805 JR Z, #8FDC 8FD7 3D DEC A 8FD8 32D285 LD (#85D2), A 8FDB C9 RET ; move Willy left 8FDC 3AD185 LD A, (#85D1) ; Willy's action states 8FDF 010000 LD BC, #0000 8FE2 FE00 CP #00 8FE4 2024 JR NZ, #900A 8FE6 2AD385 LD HL, (#85D3) 8FE9 010000 LD BC, #0000 8FEC 3ADA80 LD A, (#80DA) ; ramp direction (0 = L, 1 = R) 8FEF 3D DEC A 8FF0 F6A1 OR #A1 8FF2 EEE0 XOR #E0 ; ramp direction is now #1F = L, #41 = R 8FF4 5F LD E, A 8FF5 1600 LD D, #00 8FF7 19 ADD HL, DE 8FF8 3AC480 LD A, (#80C4) ; ramp attr 8FFB BE CP (HL) 8FFC 200C JR NZ, #900A 8FFE 012000 LD BC, #0020 9001 3ADA80 LD A, (#80DA) 9004 B7 OR A 9005 2003 JR NZ, #900A 9007 01E0FF LD BC, #FFE0 900A 2AD385 LD HL, (#85D3) ; lots of stuff jumps to here... 900D 7D LD A, L 900E E61F AND #1F 9010 CA8A94 JP Z, #948A 9013 09 ADD HL, BC 9014 2B DEC HL 9015 112000 LD DE, 32 9018 19 ADD HL, DE ; move one row down 9019 3AB280 LD A, (#80B2) ; wall attr 901C BE CP (HL) 901D C8 RET Z ; return if we hit a wall (Willy's feet block) 901E 3ACF85 LD A, (#85CF) 9021 CB29 SRA C 9023 81 ADD C 9024 47 LD B, A 9025 E60F AND #0F 9027 2809 JR Z, #9032 ; branch if y is block aligned 9029 3AB280 LD A, (#80B2) ; wall attr 902C 19 ADD HL, DE 902D BE CP (HL) 902E C8 RET Z 902F B7 OR A 9030 ED52 SBC HL, DE ; move one row up 9032 B7 OR A 9033 ED52 SBC HL, DE ; move one row up again **MM tests this block** 9035 22D385 LD (#85D3), HL ; update Willy's position 9038 78 LD A, B 9039 32CF85 LD (#85CF), A 903C 3E03 LD A, #03 ; frame 3 (far right if 16x16) 903E 32D285 LD (#85D2), A ; update Willy's anim frame 9041 C9 RET ; moving right 9042 3AD285 LD A, (#85D2) ; Willy's anim frame 9045 FE03 CP #03 9047 2805 JR Z, #904E ; branch if frame 3 (far right of 16x16) 9049 3C INC A ; else increment it 904A 32D285 LD (#85D2), A 904D C9 RET ; nothing else to check 904E 3AD185 LD A, (#85D1) ; Willy's action states 9051 010000 LD BC, #0000 9054 B7 OR A 9055 2021 JR NZ, #9078 ; if fall/move isn't 0 (ie not standing) 9057 2AD385 LD HL, (#85D3) ; Willy's position on attribute buffer 905A 3ADA80 LD A, (#80DA) ; ramp direction (0 = L, 1 = R) 905D 3D DEC A 905E F69D OR #9D 9060 EEBF XOR #BF ; ramp direction is now #40 = L, #22 = R 9062 5F LD E, A 9063 1600 LD D, #00 ; attribute we're looking at is now either 9065 19 ADD HL, DE ; two rows or one row and two cols below 9066 3AC480 LD A, (#80C4) ; ramp attr 9069 BE CP (HL) 906A 200C JR NZ, #9078 ; branch if we're not on a ramp 906C 012000 LD BC, #0020 906F 3ADA80 LD A, (#80DA) ; ramp direction 9072 B7 OR A 9073 2803 JR Z, #9078 ; ramp is left 9075 01E0FF LD BC, #FFE0 ; either #0020 (left) or #FFE0 (right) or 0 9078 2AD385 LD HL, (#85D3) ; Willy's position on attribute buffer 907B 09 ADD HL, BC ; now we're either one row below or one up... 907C 23 INC HL ; ...if on a ramp, or none otherwise 907D 23 INC HL ; and two cols right (block to right of Willy) 907E 7D LD A, L 907F E61F AND #1F 9081 CA9E94 JP Z, #949E ; off the left of the screen 9084 112000 LD DE, 32 9087 3AB280 LD A, (#80B2) ; wall attr 908A 19 ADD HL, DE ; move one row down 908B BE CP (HL) 908C C8 RET Z ; return if we hit a wall (Willy's feet block) 908D 3ACF85 LD A, (#85CF) ; Willy's y 9090 CB29 SRA C 9092 81 ADD C 9093 47 LD B, A ; store y * 2 for later 9094 E60F AND #0F 9096 2809 JR Z, #90A1 ; branch if y is block aligned 9098 3AB280 LD A, (#80B2) ; wall attr 909B 19 ADD HL, DE ; move one row down again 909C BE CP (HL) 909D C8 RET Z ; return if we hit a wall (below Willy's feet) 909E B7 OR A ; [this must be to reset the carry flag?] 909F ED52 SBC HL, DE ; move one row back up 90A1 3AB280 LD A, (#80B2) ; wall attr 90A4 B7 OR A ; [this must be to reset the carry flag?] 90A5 ED52 SBC HL, DE ; move one row up again 90A7 BE CP (HL) 90A8 C8 RET Z ; return if we hit a wall (Willy's head block) 90A9 2B DEC HL ; all was ok so move back left by one col 90AA 22D385 LD (#85D3), HL ; and update Willy's position 90AD AF XOR A ; sets frame to zero (far left of 16x16) 90AE 32D285 LD (#85D2), A ; update Willy's anim frame 90B1 78 LD A, B 90B2 32CF85 LD (#85CF), A ; updates Willy's y * 2 90B5 C9 RET 90B6 E1 POP HL 90B7 E1 POP HL 90B8 3EFF LD A, #FF ; Willy has been killed (#85D1 = 0xFF) 90BA 32D185 LD (#85D1), A 90BD C3F589 JP #89F5 ; *************************** end of movement code *************************** ; *********************** Some extra collision checking ********************** 95C8 2AD385 LD HL, (#85D3) ; Willy's position on attribute buffer 95CB 0600 LD B, #00 95CD 3ADA80 LD A, (#80DA) ; ramp direction (0 = L, 1 = R) 95D0 E601 AND #01 95D2 C640 ADD #40 ; down 2 rows 95D4 5F LD E, A 95D5 1600 LD D, #00 95D7 19 ADD HL, DE ; L ramps move 2 rows; R moves 1 col & 2 rows 95D8 3AC480 LD A, (#80C4) ; ramp attr 95DB BE CP (HL) 95DC 201A JR NZ, #95F8 ; branch if we're not on a ramp 95DE 3AD185 LD A, (#85D1) ; Willy's action/fall distance 95E1 B7 OR A 95E2 2014 JR NZ, #95F8 ; branch if we're not walking or standing 95E4 3AD285 LD A, (#85D2) ; Willy's anim frame 95E7 E603 AND #03 ; frames mask 95E9 07 RLCA 95EA 07 RLCA ; frame multiplied by 4 95EB 47 LD B, A 95EC 3ADA80 LD A, (#80DA) ; ramp direction (0 = L, 1 = R) 95EF E601 AND #01 95F1 3D DEC A ; gives L = 0xFF or R = 0x00 95F2 EE0C XOR #0C ; gives L = 0xF3 or R = 0x0C 95F4 A8 XOR B ; basically L ramps give an offset of FRAME * 2 95F5 E60C AND #0C ; whereas R ramps offset by (3 - FRAME) * 2 95F7 47 LD B, A ; (given that Willy's y is multiplied by 2) ; Normal MM-style code starts here. 95F8 2AD385 LD HL, (#85D3) ; Willy's position in attribute buffer 95FB 111F00 LD DE, #001F 95FE 0E0F LD C, #0F 9600 CD1E96 CALL #961E ; test for nasty (head left) 9603 23 INC HL ; move one col right 9604 CD1E96 CALL #961E ; test for nasty (head right) 9607 19 ADD HL, DE ; move one row down and one col left 9608 CD1E96 CALL #961E ; test for nasty (legs left) 960B 23 INC HL ; move one col right 960C CD1E96 CALL #961E ; test for nasty (legs right) 960F 3ACF85 LD A, (#85CF) ; Willy's y * 2 9612 80 ADD B ; compensate for ramp (see #95C8) 9613 4F LD C, A 9614 19 ADD HL, DE ; move one row down and one col left 9615 CD1E96 CALL #961E ; test for nasty (under left foot) 9618 23 INC HL ; move one col right 9619 CD1E96 CALL #961E ; test for nasty (under right foot) 961C 1819 JR #9637 ; no nasties so draw Willy ; code to test for nasty blocks (also sets Willy's colour attributes) 961E 3AA080 LD A, (#80A0) ; bkgnd attr 9621 BE CP (HL) 9622 200B JR NZ, #962F ; branch if not bkgnd 9624 79 LD A, C ; either contains 0x0F or y * 2 + ramp offset 9625 E60F AND #0F ; block mask (given that y is multiplied by 2) 9627 2806 JR Z, #962F ; branch if block aligned (no need to colour) 9629 3AA080 LD A, (#80A0) ; bkgnd attr 962C F607 OR #07 ; set the ink to white 962E 77 LD (HL), A ; then put this colour in the attribute buffer 962F 3ABB80 LD A, (#80BB) ; nasty attr 9632 BE CP (HL) 9633 CAB690 JP Z, #90B6 ; branch if killed 9636 C9 RET ; code to draw Willy 9637 3ACF85 LD A, (#85CF) ; Willy's y * 2 963A 80 ADD B ; compensate for ramp (see #95C8) ; the remaining draw code doesn't need commenting ; ****************************************************************************
IX+0 -- 3 MSBs are continuous frame count (HGs use MSB as direction) ; Horizontal guardian ; ------------------- L9133: BIT 7,(IX+&00) ; direction JR NZ,L915C ; branch if moving right (bit-7 == 1) ; Move horizontal guardian left ; ----------------------------- LD A,(IX+&00) SUB &20 ; decrement 'frame' counter by 1 AND &7F ; set MSB to 0 (moving left flag) LD (IX+&00),A ; update it CP &60 JR C,L91B6 ; branch if frame != 3 LD A,(IX+&02) ; frame and col whatnot AND &1F ; mask just the col CP (IX+&06) ; compare with min (left) boundary JR Z,L9156 ; branch if reached boundary (flip direction) DEC (IX+&02) ; else decrement the current col JR L91B6 ; do next guardian L9156: LD (IX+&00),&81 ; set to moving right and zero frame count JR L91B6 ; do next guardian ; Move horizontal guardian right ; ------------------------------ L915C: LD A,(IX+&00) ADD A,&20 ; increment 'frame' counter by 1 OR &80 ; set MSB to 1 (moving right flag) LD (IX+&00),A ; update it CP &A0 JR NC,L91B6 LD A,(IX+&02) ; frame and col whatnot AND &1F ; mask just the col CP (IX+&07) ; compare with max (right) boundary JR Z,L9179 ; branch if reached boundary (flip direction) INC (IX+&02) ; else increment the current col JR L91B6 ; do next guardian L9179: LD (IX+&00),&61 ; set to moving left and on last frame JR L91B6 ; do next guardian ; Vertical guardian ; ----------------- L917F: LD A,(IX+&00) XOR &08 ; flip bit-3 LD (IX+&00),A AND &18 ; bit-4 and bit-3 (anim speed and cycling thing) JR Z,L9193 ; branch to skip every other frame (anim slow) LD A,(IX+&00) ADD A,&20 ; else increment the frame LD (IX+&00),A L9193: LD A,(IX+&03) ; y (x2) ADD A,(IX+&04) ; add the step (x2) LD (IX+&03),A ; update y (x2) CP (IX+&07) ; compare with max (bottom) boundary JR NC,L91AE ; branch if >= max CP (IX+&06) ; compare with min (top) boundary JR Z,L91A8 ; branch if == min JR NC,L91B6 ; branch if >= min (do next guard) L91A8: LD A,(IX+&06) LD (IX+&03),A ; set the y (x2) to min (top) boundary L91AE: LD A,(IX+&04) NEG ; negate velocity LD (IX+&04),A L91B6: LD DE,&0008 ; 8 bytes per record ADD IX,DE JP L90C4 ; do next guardian
IX+0 bit-7 direction IX+2 IX+4 start col, later used for actual working col L9237: BIT 7,(IX+&00) ; arrow direction (0 = L, 1 = R) JR NZ,L9244 ; branch if moving right DEC (IX+&04) ; move left one col LD C,&2C ; 44 JR L9249 L9244: INC (IX+&04) ; move right one col LD C,&F4 ; 244 L9249: LD A,(IX+&04) ; arrow col/timer CP C JR NZ,L9262 ; branch if not equal to 44 (L) or 244 (R) LD BC,&0280 LD A,(BORDER) L9255: OUT (&FE),A ; else do beep XOR &18 L9259: DJNZ L9259 LD B,C DEC C JR NZ,L9255 JP L93B3 ; after beeping move on to next guardian L9262: AND &E0 JP NZ,L93B3 ; branch if the current col is off-screen LD E,(IX+&02) ; y * 2 [need to look at - block aligned?] LD D,&82 ; 0x8200 buffer row lookup table LD A,(DE) ADD A,(IX+&04) ; current col LD L,A ; L holds low-byte of attribute buffer LD A,E AND &80 RLCA OR &5C LD H,A ; HL now points to arrow's attr buffer position LD (IX+&05),&00 ; (for later testing *no* pixels for collision) LD A,(HL) ; get the attr where the arrow would be AND &07 ; ink mask CP &07 JR NZ,L9286 ; branch if not white (white ink is Willy) DEC (IX+&05) ; else IX+5 = 255 (test for collision later) L9286: LD A,(HL) ; get the attr where the arrow would be OR &07 ; set the ink to white LD (HL),A ; then put it back in the buffer INC DE ; down one row? [arrows appear not to start @ 0] LD A,(DE) LD H,A DEC H ; [too tired right now! Anyway HL is pixel addr] LD A,(IX+&06) ; top/bottom pixel pattern LD (HL),A ; draw the top of the arrow INC H ; down one row LD A,(HL) ; get the pixels where the arrow middle wil be AND (IX+&05) ; holds 255 if the ink is white or 0 otherwise JP NZ,DIED1 ; branch if anything is there (and on white) LD (HL),&FF ; draw the middle of the arrow (an 8px line) INC H ; down one row LD A,(IX+&06) ; top/bottom pixel pattern LD (HL),A ; draw the bottom of the arrow JP L93B3
0 guardian type (with bit-7 for swing direction) 1 [moving] swing table index offset 2 [init] start col 3 [drawing] dot col (currently being drawn into) 4 rope length 5 [drawing] dot bitmap pattern 6 *not used* (I'm guessing it was pointing to the swing table) 7 maximum rope swing 8 9 [drawing] dot y * 2 (offset into lookup table) A B [drawing] Willy is on THIS rope C #85CF: Willy's current rope dot T8100: DEFS #0048 ; guardian records T8200: DEFS #0100 ; screen buffer y lookup table ; Rope swing table T8300: DEFB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ; x offsets DEFB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 DEFB 1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2 DEFB 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2 DEFB 2,2,1,2,2,1,1,2,1,1,2,2,3,2,3,2 DEFB 3,3,3,3,3,3,0,0,0,0,0,0,0,0,0,0 DEFB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 DEFB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 DEFB 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6 ; y offsets DEFB 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6 DEFB 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6 DEFB 4,6,6,4,6,4,6,4,6,4,4,4,6,4,4,4 DEFB 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4 DEFB 4,4,4,4,4,4,0,0,0,0,0,0,0,0,0,0 DEFB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 DEFB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ; ******************************** Move rope ********************************* BIT 7,(IX+&00) ; rope direction (0 = left, 1 = right) JR Z,L90FF ; branch if moving left else moving right LD A,(IX+&01) ; rope swing table index offset BIT 7,A JR Z,L90F5 ; branch if not negative SUB &02 ; subract 2 (drawing LHS) CP &94 JR NC,L911D SUB &02 ; subract another 2 if less than -108 CP &80 JR NZ,L911D XOR A ; set the swing to 0 if equal to -128 JR L911D L90F5: ADD A,&02 ; add 2 (drawing RHS) CP &12 JR NC,L911D ADD A,&02 ; add another 2 if less than 18 JR L911D ; right rope swing code L90FF: LD A,(IX+&01) BIT 7,A JR NZ,L9115 ; branch if negative SUB &02 ; subract 2 (drawing RHS) CP &14 JR NC,L911D SUB &02 ; subract another 2 if less than 20 OR A JR NZ,L911D LD A,&80 ; set the swing to -128 if equal to 0 JR L911D L9115: ADD A,&02 ; add 2 (drawing LHS) CP &92 JR NC,L911D ADD A,&02 ; add another 2 if less than -112 L911D: LD (IX+&01),A ; update the current rope swing AND &7F CP (IX+&07) ; maximum rope swing JP NZ,L91B6 ; branch if rope can continue swinging LD A,(IX+&00) XOR &80 ; else reverse the rope's direction LD (IX+&00),A JP L91B6 L91B6: ; continue for the other guardians ; ***************************** Draw guardians ******************************* L91BE: LD IX,&8100 ; current room's guardian records L91C2: LD A,(IX+&00) ; guardian type CP &FF RET Z ; return to main loop if at end of records AND &07 ; guardian type mask JP Z,L93B3 ; branch if an empty record CP &03 JP Z,L92A4 ; branch if type 3 (rope) CP &04 JR Z,L9237 ; branch if type 4 (arrow) ; [code continues for H and V guardians] ; rope entry point ; [initialise this rope] L92A4: LD IY,&8200 ; screen buffer y lookup table LD (IX+&09),&00 ; current dot y * 2 (offset into lookup table) LD A,(IX+&02) ; rope start col LD (IX+&03),A ; current dot col (reset to start col) LD (IX+&05),&80 ; dot bitmap pattern (LHS pixel to start with) ; [start of the loop to draw the dots] L92B6: LD A,(IY+&00) ; low-byte of buffer y table ADD A,(IX+&03) ; add current dot col to get screen low-byte LD L,A LD H,(IY+&01) ; HL at screen address of current dot col LD A,(#85D6) ; rope dot Willy is on (0 when not on a rope) OR A JR NZ,L92D6 ; branch if Willy is already on a rope ; [find if Willy is touching a rope] LD A,(IX+&05) ; bitmap pattern of previous dot AND (HL) ; compare the dot pattern with screen buffer JR Z,L930E ; branch if nothing is where the rope should be LD A,(IX+&09) ; else Willy is touching so take current dot y LD (#85D6),A ; set Willy's rope dot to current dot SET 0,(IX+&0B) ; set the flag to show Willy is on this rope ; [set Willy's frame and position] L92D6: CP (IX+&09) ; compare Willy's dot with this rope dot JR NZ,L930E ; branch if Willy is not at this dot BIT 0,(IX+&0B) JR Z,L930E ; branch if Willy is not on this rope LD B,(IX+&03) ; used later for setting Willy's col to dot col LD A,(IX+&05) ; dot bitmap pattern LD C,&01 ; used later for setting Willy's frame to 1 CP &04 JR C,L92FC ; branch if dot pattern fits ......XX LD C,&00 ; used later for setting Willy's frame to 0 CP &10 JR C,L92FC ; branch if dot pattern fits ....XX.. DEC B ; used later for moving Willy one col left LD C,&03 ; used later for setting Willy's frame to 3 CP &40 JR C,L92FC ; branch if dot pattern fits ..XX.... LD C,&02 ; else Willy's frame is 2 (pattern XX......) L92FC: LD (#85D2),BC ; Willy's anim frame (and col) LD A,IYL ; row taken from lookup index low-byte SUB &10 ; up 8 pixels LD (#85CF),A ; update Willy's y * 2 PUSH HL CALL L8E9C ; update Willy's attribute buffer position POP HL JR L930E ; [draw the current dot/create the next dot] L930E: LD A,(IX+&05) ; bitmap pattern for drawing the dot OR (HL) ; combine with the existing screen pixels LD (HL),A ; draw it back to screen LD A,(IX+&09) ; current dot's y * 2 ADD A,(IX+&01) ; add the rope swing table index offset LD L,A ; put it into low-byte of lookup address SET 7,L ; using y offsets in rope table LD H,&83 ; as in 0x8300, the rope table LD E,(HL) ; y offset LD D,&00 ADD IY,DE ; move down the screen by the offset rows RES 7,L ; using x offsets in rope table LD A,(HL) ; x offset OR A JR Z,L9350 ; branch if 0 (bit pattern remains the same) ; [create the dot pattern] LD B,A BIT 7,(IX+&01) ; rope swing table index offset sign JR Z,L9341 ; branch if a positive number L9330: RLC (IX+&05) ; else move the dot pattern to the left BIT 0,(IX+&05) JR Z,L933D ; branch if the dot is not in a new col DEC (IX+&03) ; else move current dot col left L933D: DJNZ L9330 ; looping until the dot pattern is finished JR L9350 ; [skipping over code for moving right] L9341: RRC (IX+&05) ; move the dot pattern to the right BIT 7,(IX+&05) JR Z,L934E ; branch if the dot is not in a new col INC (IX+&03) ; else move current dot col right L934E: DJNZ L9341 ; looping until the dot pattern is finished ; [repeat to draw the remaining rope sections] L9350: LD A,(IX+&09) ; current dot row CP (IX+&04) ; rope length JR Z,L935E ; branch if reached end of rope INC (IX+&09) ; else move down to the next dot row JP L92B6 ; and repeat for the next dot ; [test whether Willy is still on this rope] L935E: LD A,(85D6) ; Willy's rope dot position BIT 7,A JR Z,L936F ; branch if is still on the rope (bit-7 = 0) INC A ; else he's off but there's a delay before... LD (85D6),A ; ...he can get back on (16 ticks) RES 0,(IX+&0B) ; flag him as not being on this rope JR L93B3 ; no need to perform next section so done ; [allow Willy to climb up or down this rope] L936F: BIT 0,(IX+&0B) JR Z,L93B3 ; branch if Willy is not on this rope LD A,(#85D0) ; Willy's walking/facing flags BIT 1,A JR Z,L93B3 ; branch if Willy is standing still RRCA ; facing flag now at bit-7 (walking at bit-0) XOR (IX+&00) ; XOR with rope swing direction - left rope... RLCA ; ...is normal Willy L/R, right rope reverses RLCA ; facing result in bit-1 AND &02 ; mask just bit-1 DEC A ; result is now 1 or -1 LD HL,#85D6 ; Willy's rope dot address ADD A,(HL) ; move either up one dot or down one dot LD (HL),A LD A,(#80EB) ; room above this room LD C,A LD A,(#8420) ; current room CP C JR NZ,L939B ; branch if going up leads to a different room LD A,(HL) ; Willy's rope dot CP &0C JR NC,L939B ; branch if Willy's rope dot > 12 LD (HL),&0C ; else set Willy's rope dot to 12 (can't go up) L939B: LD A,(HL) ; Willy's rope dot CP (IX+&04) ; rope length JR C,L93B3 ; branch if Willy's rope dot < the rope length JR Z,L93B3 ; branch if Willy's rope dot = the rope length LD (HL),&F0 ; else set bit-7 (not attached) and prep delay LD A,(#85CF) ; Willy's y * 2 AND &F8 ; align it to half a block LD (#85CF),A ; then update it XOR A LD (#85D1),A ; change Willy's action to standing JR L93B3 L93B3: LD DE,&0008 ADD IX,DE ; move to next guardian record JP L91C2
(C) 1983,1984,1999 Matthew Smith - all rights reserved