XOR disassembly =============== XOR was written by Paul Carruthers and Ian Downend for Astral Software, and published by Logotron for the BBC Micro in 1987. It is a puzzle game in which the player must use two shields to manipulate pieces including fish, chickens and bombs in order to collect masks. The following disassembly was created by reverse engineering binary images, without access to any source code. It is nevertheless reasonably complete, allowing the technical approaches used to be understood. The author of this disassembly imposes no additional copyright restrictions beyond those already present on the game itself. It is provided for educational purposes only, and it is hoped that the original authors will accept it in the good faith it was intended - as a tribute to their skills. Technical notes =============== Two versions of the game are analysed here. The tape version is protected by a VIA-based decryption routine written by Kevin Edwards. The disassembly analyses each stage after decryption has taken place. Once decrypted, the game binary can be run without any loader. The February 1987 edition of A & B Computing magazine included a cover disk containing a "free review copy", which could be run three times, but was restricted to the first five levels of the game. When run for a fourth time, the disk required an unlock code to be entered. Two of the three stages of the loader and the main game binary are stored in deleted data on the disk. A custom formatted track is used to check if the disk has been copied. A sector of seemingly random bytes stores how many times the disk has been run, and whether it has been unlocked. The number of times the disk has been run is stored in an obfuscated format in twenty-seven different bytes. Both versions prompt to save replay data after level nine ("THE CHALLENGE") has been completed. On a screenshot on the cover of the magazine, level nine is titled "COMPETITION", suggesting a purpose for this. The screenshots also have other differences from the released game, including a level resembling level fourteen ("PENULTIMATE") but numbered twelve and titled "DANGEROUS DOORSTEP", and a level seven that does not match any of the released levels. Interesting pokes ================= &2582 = &ad, &25c1 = &ad access all levels from title screen &28dd = &22 save replay data after completing any level Tape protection disassembly =========================== ; XOR ; ffff0e00 ffff8023 00000099 &0e00 0d # Start of BASIC program &0e01 00 00 15 f4 20 58 4f 52 20 54 61 70 65 20 4c 6f ; 0REM XOR Tape Loader &0e11 61 64 65 72 0d &0e16 00 0a 16 f4 20 42 79 20 4b 65 76 69 6e 20 45 64 ; 10REM By Kevin Edwards &0e26 77 61 72 64 73 0d &0e2c 00 14 06 eb 37 0d ; 20MODE7 &0e32 00 1e 13 ef 32 33 3b 38 32 30 32 3b 30 3b 30 3b ; 30VDU23;8202;0;0;0; # Disable cursor &0e42 30 3b 0d &0e45 00 28 15 2a 4c 4f 41 44 22 58 4f 52 53 43 52 22 ; 40*LOAD"XORSCR"4000 # Load loading screen &0e55 34 30 30 30 0d &0e5a 00 32 22 e3 4c 25 3d 30 b8 26 33 46 46 3a 4c 25 ; 50FORL%=0TO&3FF: # Copy into screen memory &0e6a 3f 26 37 43 30 30 3d 4c 25 3f 26 34 30 30 30 3a ; L%?&7C00=L%?&4000: &0e7a ed 0d ; NEXT &0e7c 00 3c 16 ef 32 38 2c 31 33 2c 31 35 2c 33 32 2c ; 60VDU28,13,15,32,13, # Define text window &0e8c 31 33 2c 31 32 0d ; 12 # CLS &0e92 00 46 06 2a 2f 0d ; 70*/ # *RUN XOR2 &0e98 ff # End of BASIC program ; XORSCR ; ffff7c00 ffff7c00 00000400 &7c00 94 9a ab ff ff f7 a3 a3 a3 a3 a3 a3 a3 a3 a3 a3 ; "....................... " &7c10 a3 a3 e3 ff ff bf a1 20 20 20 20 20 20 20 20 20 ; ".. ..... .... " &7c20 20 20 20 20 20 20 20 20 94 9a 20 a2 ef ff fd b0 ; ".. .... ..... ...... ....... " &7c30 20 20 20 20 20 20 20 20 20 f8 ff ff a7 20 20 20 ; ".. ..... .... .. .. .. .. " &7c40 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 ; ".. ......... .. .. .. .. " &7c50 94 9a 20 20 20 ab ff ff f4 20 20 20 20 20 20 e0 ; ".. ...... .. .. .. ... " &7c60 fe ff bf a1 20 f8 ae a3 a3 ad f4 20 20 20 ff ff ; ".. ...... .. .. ...... " &7c70 a3 a3 a3 ad f4 20 20 20 94 9a 20 20 20 20 a2 ef ; ".. ......... .. .. ...... " &7c80 ff fd b0 20 20 20 f8 ff ff a7 20 20 fa ff 20 20 ; ".. ..... .... .. .. .. .... " &7c90 20 20 ff f5 20 20 ff ff 20 20 20 20 ff f5 20 20 ; ".. .... ..... ...... .. .... " &7ca0 94 9a 20 20 20 20 20 20 ab ff ff f4 e0 fe ff bf ; ".. ..... .... " &7cb0 a1 20 20 20 ff ff 20 20 20 20 ff ff 20 20 ff ff ; "....................... " &7cc0 20 20 20 20 ff bf 20 20 94 9a 20 20 20 20 20 20 ; " " &7cd0 20 a2 ef ff ff ff a7 20 20 20 20 20 ff ff 20 20 ; " " &7ce0 20 20 ff ff 20 20 ff ff 20 20 20 f0 bf a1 20 20 ; ". " &7cf0 94 9a 20 20 20 20 20 20 20 e0 fe ff ff ff f4 20 ; ". " &7d00 20 20 20 20 ff ff 20 20 20 20 ff ff 20 20 ff ff ; ". " &7d10 ff f7 a3 a1 20 20 20 20 94 9a 20 20 20 20 20 20 ; ". Xor must be revealed. " &7d20 f8 ff ff a7 a2 ef ff fd b0 20 20 20 ff ff 20 20 ; ". His many faces are scattered through" &7d30 20 20 ff ff 20 20 ff ff ab ff fd b0 20 20 20 20 ; ".15 levels. Acquiring all the faces on " &7d40 94 9a 20 20 20 20 e0 fe ff bf a1 20 20 20 ab ff ; ".any level will enhance your knowledge " &7d50 ff f4 20 20 eb ff 20 20 20 20 ff bf 20 20 ff ff ; ".of Xor. " &7d60 20 a2 ef ff f4 20 20 20 94 9a 20 20 20 f8 ff ff ; ". Beware Xor controls his world and " &7d70 a7 20 20 20 20 20 20 a2 ef ff fd b0 20 ab ec f0 ; ".doesn't give up his personality easily." &7d80 f0 bc a7 20 20 20 ff ff 20 20 20 ab ff fd b0 20 ; ". (c) 1987 Astral Software Ltd. " &7d90 94 9a 20 e0 fe ff bf a1 20 20 20 20 20 20 20 20 ; " " &7da0 20 ab ff ff f4 20 20 20 20 20 20 20 20 20 20 20 &7db0 20 20 20 20 20 20 20 20 94 9a f8 ff ff f7 f0 f0 &7dc0 f0 f0 f0 f0 f0 f0 f0 f0 f0 f0 f2 ff ff fd b0 20 &7dd0 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 &7de0 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 &7df0 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 &7e00 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 &7e10 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 &7e20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 &7e30 83 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 &7e40 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 &7e50 20 20 20 20 20 20 20 20 83 20 20 20 20 20 20 20 &7e60 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 &7e70 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 &7e80 83 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 &7e90 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 &7ea0 20 20 20 20 20 20 20 20 83 20 20 20 20 20 20 20 &7eb0 20 20 58 6f 72 20 6d 75 73 74 20 62 65 20 72 65 &7ec0 76 65 61 6c 65 64 2e 20 20 20 20 20 20 20 20 20 &7ed0 83 20 20 20 48 69 73 20 6d 61 6e 79 20 66 61 63 &7ee0 65 73 20 61 72 65 20 73 63 61 74 74 65 72 65 64 &7ef0 20 74 68 72 6f 75 67 68 83 31 35 20 6c 65 76 65 &7f00 6c 73 2e 20 41 63 71 75 69 72 69 6e 67 20 61 6c &7f10 6c 20 74 68 65 20 66 61 63 65 73 20 6f 6e 20 20 &7f20 83 61 6e 79 20 6c 65 76 65 6c 20 77 69 6c 6c 20 &7f30 65 6e 68 61 6e 63 65 20 79 6f 75 72 20 6b 6e 6f &7f40 77 6c 65 64 67 65 20 20 83 6f 66 20 58 6f 72 2e &7f50 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 &7f60 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 &7f70 83 20 20 20 42 65 77 61 72 65 20 58 6f 72 20 63 &7f80 6f 6e 74 72 6f 6c 73 20 68 69 73 20 77 6f 72 6c &7f90 64 20 61 6e 64 20 20 20 83 64 6f 65 73 6e 27 74 &7fa0 20 67 69 76 65 20 75 70 20 68 69 73 20 70 65 72 &7fb0 73 6f 6e 61 6c 69 74 79 20 65 61 73 69 6c 79 2e &7fc0 86 20 20 20 20 28 63 29 20 31 39 38 37 20 41 73 &7fd0 74 72 61 6c 20 53 6f 66 74 77 61 72 65 20 4c 74 &7fe0 64 2e 20 20 20 20 20 20 20 20 20 20 20 20 20 20 &7ff0 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 ; XOR2 ; ffff0e00 ffff0e00 00000301 ; entry_point &0e00 a2 00 LDX #&00 ; write_please_wait_loop &0e02 bd 17 0e LDA &0e17,X ; end_of_string &0e05 f0 06 BEQ &0e0d ; end_of_string &0e07 20 e3 ff JSR &ffe3 ; OSASCI &0e0a e8 INX &0e0b d0 f5 BNE &0e02 ; write_please_wait_loop ; end_of_string &0e0d a9 0f LDA #&0f &0e0f a2 00 LDX #&00 &0e11 20 f4 ff JSR &fff4 ; OSBYTE &0e14 4c d3 0e JMP &0ed3 ; via_decryption ; please_wait-string &0e17 0c ; CLS &0e18 0d ; CR &0e19 50 6c 65 61 73 65 20 77 61 69 74 ; "Please wait" &0e24 0d ; CR &0e25 00 ; unused &0e26 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a &0e36 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a &0e46 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a &0e56 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a &0e66 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a &0e76 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a &0e86 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a &0e96 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a &0ea6 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a &0eb6 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a &0ec6 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a ; via_decryption &0ed3 78 SEI &0ed4 a2 ff LDX #&ff &0ed6 9a TXS &0ed7 e8 INX ; 0 &0ed8 a9 40 LDA #&40 # Set User VIA timer 1 to continuous interrupts &0eda 8d 6b fe STA &fe6b ; User VIA auxiliary control register &0edd a9 7f LDA #&7f # Disable all User VIA interrupts &0edf 8d 6e fe STA &fe6e ; User VIA interrupt enable register &0ee2 a9 e0 LDA #&e0 # Enable interrupts for User VIA timers 1 and 2 &0ee4 8d 6e fe STA &fe6e ; User VIA interrupt enable register &0ee7 a9 41 LDA #&41 &0ee9 8d 68 fe STA &fe68 ; User VIA timer 2 counter LSB &0eec a9 42 LDA #&42 &0eee 8d 69 fe STA &fe69 ; User VIA timer 2 counter MSB &0ef1 a9 43 LDA #&43 &0ef3 8d 64 fe STA &fe64 ; User VIA timer 1 counter LSB &0ef6 a9 44 LDA #&44 &0ef8 8d 65 fe STA &fe65 ; User VIA timer 1 counter MSB &0efb a9 03 LDA #&03 &0efd 8d 58 02 STA &0258 ; ESCAPE/BREAK effect ; via_decryption_code ; via_decryption_loop &0f00 ad 00 0f LDA &0f00 # Runs from &0f00 to &0fff # actually LDA &0f00 + via_decryption_offset &0f03 4d 69 fe EOR &fe69 ; User VIA timer 2 counter MSB &0f06 ce 65 fe DEC &fe65 ; User VIA timer 1 counter MSB &0f09 5d 00 10 EOR &1000,X ; payload &0f0c 9d 00 01 STA &0100,X ; stack # Possibly intended to be confused with &1000 (payload) &0f0f ac 64 fe LDY &fe64 ; User VIA timer 1 counter LSB &0f12 8c 17 0f STY &0f17 ; via_decryption_add &0f15 18 CLC &0f16 69 ed ADC #&ed # actually ADC via_decryption_add &0f18 4d 64 fe EOR &fe64 ; User VIA timer 1 counter LSB &0f1b ac 65 fe LDY &fe65 ; User VIA timer 1 counter MSB &0f1e cc 69 fe CPY &fe69 ; User VIA timer 2 counter MSB &0f21 6d 68 fe ADC &fe68 ; User VIA timer 2 counter LSB &0f24 ac 69 fe LDY &fe69 ; User VIA timer 2 counter MSB &0f27 8c 2b 0f STY &0f2b ; via_decryption_eor_one &0f2a 49 ee EOR #&ee # actually EOR via_decryption_eor_one &0f2c 4d 17 0f EOR &0f17 ; via_decryption_add &0f2f 4d 64 fe EOR &fe64 ; User VIA timer 1 counter LSB &0f32 4e 69 fe LSR &fe69 ; User VIA timer 2 counter MSB &0f35 ce 65 fe DEC &fe65 ; User VIA timer 1 counter MSB &0f38 4d 69 fe EOR &fe69 ; User VIA timer 2 counter MSB &0f3b ac 65 fe LDY &fe65 ; User VIA timer 1 counter MSB &0f3e 59 00 0f EOR &0f00,Y ; via_decryption_code &0f41 ee 45 0f INC &0f45 ; via_decryption_eor_two &0f44 49 78 EOR #&78 # actually EOR via_decryption_eor_two &0f46 4d 66 fe EOR &fe66 ; User VIA timer 1 latch LSB &0f49 ce 67 fe DEC &fe67 ; User VIA timer 1 latch MSB &0f4c 5d 01 10 EOR &1001,X ; payload + 1 # Runs over &1001 to &1101 &0f4f ce 69 fe DEC &fe69 ; User VIA timer 2 counter MSB &0f52 18 CLC &0f53 6e 68 fe ROR &fe68 ; User VIA timer 2 counter LSB &0f56 ac 69 fe LDY &fe69 ; User VIA timer 2 counter MSB &0f59 8c 64 fe STY &fe64 ; User VIA timer 1 counter LSB &0f5c 9d 00 10 STA &1000,X ; payload &0f5f e8 INX &0f60 d0 9e BNE &0f00 ; via_decryption_loop &0f62 a0 03 LDY #&03 # Clear memory on break &0f64 8c 58 02 STY &0258 ; ESCAPE/BREAK effect &0f67 a9 4c LDA #&4c ; JMP # Set BREAK intercept code to JMP &0287, endless loop &0f69 8d 87 02 STA &0287 ; BREAK intercept code &0f6c a9 87 LDA #&87 &0f6e 8d 88 02 STA &0288 ; BREAK intercept code + 1 &0f71 88 DEY ; 2 &0f72 8c 89 02 STY &0289 ; BREAK intercept code + 2 &0f75 a9 40 LDA #&40 ; RTI # Reset NMI handler &0f77 8d 00 0d STA &0d00 ; nmi_handler &0f7a ad fa ff LDA &fffa ; os_nmi_handler_address_low # Ensure NMI handler address hasn't been changed &0f7d d0 5e BNE &0fdd ; endless_wiping_loop &0f7f ad fb ff LDA &fffb ; os_nmi_handler_address_high &0f82 c9 0d CMP #&0d ; &0d00 = nmi_handler &0f84 d0 57 BNE &0fdd ; endless_wiping_loop &0f86 ee 01 0f INC &0f01 ; via_decryption_offset &0f89 f0 03 BEQ &0f8e ; calculate_checksum &0f8b 4c 00 0f JMP &0f00 ; via_decryption_loop ; calculate_checksum &0f8e a9 00 LDA #&00 # Checksum &1000 to &1013 &0f90 85 70 STA &70 ; calculated_checksum_one &0f92 85 71 STA &71 ; calculated_checksum_two &0f94 a8 TAY ; calculate_checksum_loop &0f95 a5 71 LDA &71 ; calculated_checksum_two &0f97 59 00 10 EOR &1000,Y ; payload &0f9a 85 71 STA &71 ; calculated_checksum_two &0f9c a2 08 LDX #&08 ; calculate_checksum_inner_loop &0f9e a5 71 LDA &71 ; calculated_checksum_two &0fa0 2a ROL A &0fa1 90 0c BCC &0faf ; clear_set &0fa3 a5 71 LDA &71 ; calculated_checksum_two &0fa5 49 08 EOR #&08 &0fa7 85 71 STA &71 ; calculated_checksum_two &0fa9 a5 70 LDA &70 ; calculated_checksum_one &0fab 49 10 EOR #&10 &0fad 85 70 STA &70 ; calculated_checksum_one ; clear_set &0faf 26 70 ROL &70 ; calculated_checksum_one &0fb1 26 71 ROL &71 ; calculated_checksum_two &0fb3 ca DEX &0fb4 d0 e8 BNE &0f9e ; calculate_checksum_inner_loop &0fb6 c8 INY &0fb7 c0 14 CPY #&14 &0fb9 d0 da BNE &0f95 ; calculate_checksum_loop &0fbb a5 70 LDA &70 ; calculated_checksum_one &0fbd cd fe 10 CMP &10fe ; valid_checksum_one &0fc0 d0 14 BNE &0fd6 ; invalid_checksum &0fc2 a5 71 LDA &71 ; calculated_checksum_two &0fc4 cd ff 10 CMP &10ff ; valid_checksum_two &0fc7 f0 37 BEQ &1000 ; payload # If the checksum matches, run the decrypted code &0fc9 d0 0b BNE &0fd6 ; invalid_checksum # Always branches ; unused &0fcb 48 69 20 42 54 57 20 2e 2e 2e 2e ; "Hi BTW ...." ; invalid_checksum &0fd6 a9 c8 LDA #&c8 ; Read/Write BREAK/ESCAPE effect # This is handled by the OS OSBYTE handler at &e99c, &0fd8 a2 03 LDX #&03 ; Clear memory on next RESET # which isn't checked in the decryption routine &0fda 20 f4 ff JSR &fff4 ; OSBYTE # so could be intercepted with a custom ROM ; endless_wiping_loop # Otherwise, if the checksum doesn't match, &0fdd 99 00 10 STA &1000,Y ; payload # Wipe &1000 - &10ff (failed decryption) with &c8 &0fe0 c8 INY &0fe1 4c dd 0f JMP &0fdd ; endless_wiping_loop ; unused &0fe4 20 28 63 29 20 4b 65 76 69 6e 20 45 64 77 61 72 ; " (c) Kevin Edwar" &0ff4 64 73 20 31 39 38 37 20 20 20 20 20 ; "ds 1987 " ; payload &1000 a2 f8 LDX #&f8 &1002 9a TXS &1003 a9 03 LDA #&03 &1005 8d 58 02 STA &0258 ; ESCAPE/BREAK effect &1008 a9 28 LDA #&28 ; &28ff = main_binary_entry_point - 1 &100a 48 PHA &100b a9 ff LDA #&ff &100d 48 PHA &100e a9 56 LDA #&56 # Used to decrypt main binary &1010 48 PHA &1011 a9 de LDA #&de # Used to decrypt main binary &1013 48 PHA &1014 a2 35 LDX #&35 ; check_vector_table_loop &1016 bd 00 02 LDA &0200,X ; os_vector_table # Check all vectors are in ROM &1019 10 c2 BPL &0fdd ; endless_wiping_loop # Wipe payload if any are in RAM &101b ca DEX &101c ca DEX &101d 10 f7 BPL &1016 ; check_vector_table_loop &101f a9 7f LDA #&7f # Disable all User VIA interrupts &1021 8d 6e fe STA &fe6e ; User VIA interrupt enable register &1024 58 CLI &1025 a0 00 LDY #&00 ; wipe_1000_to_1026_loop # Wipe &1000 - &1026 &1027 99 00 10 STA &1000,Y ; payload &102a c8 INY &102b c0 27 CPY #&27 &102d d0 f8 BNE &1027 ; wipe_1000_to_1026_loop &102f a9 8c LDA #&8c ; Select Tape FS &1031 a2 0c LDX #&0c ; 1200 baud &1033 20 f4 ff JSR &fff4 ; OSBYTE &1036 a2 ed LDX #&ed ; &10ed = load_game_string &1038 a0 10 LDY #&10 &103a 20 f7 ff JSR &fff7 ; OSCLI # *LOAD GAME.. 1100 &103d 78 SEI &103e a9 40 LDA #&40 # Set User VIA timer 1 to continuous interrupts &1040 8d 6b fe STA &fe6b ; User VIA auxiliary control register &1043 68 PLA &1044 8d 68 fe STA &fe68 ; User VIA timer 2 counter LSB &1047 68 PLA &1048 8d 69 fe STA &fe69 ; User VIA timer 2 counter MSB &104b a0 00 LDY #&00 &104d a2 4c LDX #&4c ; decrypt_main_binary_loop # Decrypt &1100 - &5bff &104f b9 00 11 LDA &1100,Y # actually LDA source_address,Y &1052 4d 68 fe EOR &fe68 ; User VIA timer 2 counter LSB &1055 ee 68 fe INC &fe68 ; User VIA timer 2 counter LSB &1058 4d 69 fe EOR &fe69 ; User VIA timer 2 counter MSB &105b 99 00 11 STA &1100,Y # actually LDA target_address,Y &105e c8 INY &105f d0 ee BNE &104f ; decrypt_main_binary_loop &1061 ee 51 10 INC &1051 ; source_address_high &1064 ee 5d 10 INC &105d ; target_address_high &1067 ca DEX &1068 d0 e5 BNE &104f ; decrypt_main_binary_loop &106a 58 CLI &106b a2 6c LDX #&6c ; wipe_1000_to_106c_loop # Wipe &1000 - &106c &106d 9d 00 10 STA &1000,X ; payload &1070 ca DEX &1071 d0 fa BNE &106d ; wipe_1000_to_106c_loop &1073 60 RTS # Return via main_binary_entry_point ; unused &1074 50 72 6f 74 65 63 74 69 6f 6e 20 28 63 29 20 4b ; "Protection (c) K" &1084 65 76 69 6e 20 45 64 77 61 72 64 73 20 31 39 38 ; "evin Edwards 198" &1094 37 20 48 69 20 74 6f 20 61 6c 6c 20 68 61 63 6b ; "7 Hi to all hack" &10a4 65 72 73 20 72 65 61 64 69 6e 67 20 74 68 69 73 ; "ers reading this" &10b4 20 6d 65 73 73 61 67 65 2c 20 79 6f 75 20 73 68 ; " message, you sh" &10c4 6f 75 6c 64 20 62 65 20 64 6f 69 6e 67 20 73 6f ; "ould be doing so" &10d4 6d 65 74 68 69 6e 67 20 65 6c 73 65 20 6d 6f 72 ; "mething else mor" &10e4 65 20 75 73 65 66 75 6c 21 ; "e useful!" ; load_game_string # Filename contains embedded &7f and &82 byte &10ed 4c 4f 41 44 20 47 41 4d 45 7f 82 20 31 31 30 30 ; "LOAD GAME.. 1100" &10fd 0d ; valid_checksum_one &10fe f4 ; valid_checksum_two &10ff 83 &1100 00 # Used at &0f4c in final round of via_decryption Disk protection disassembly =========================== ; $.BOOT ; 001200 001200 0005f6 ; entry_point &1200 a9 06 LDA #&06 &1202 85 77 STA &77 ; key &1204 a9 0e LDA #&0e &1206 85 78 STA &78 ; key + 1 &1208 a9 3b LDA #&3b &120a 85 79 STA &79 ; key + 2 &120c a9 00 LDA #&00 &120e 85 75 STA &75 ; decryption_address_low &1210 a9 12 LDA #&12 &1212 85 76 STA &76 ; decryption_address_high ; decryption_page_loop # Decrypt &123a - &1fff &1214 a0 3a LDY #&3a # skipping bytes &00 to &39 of each page ; decryption_byte_loop &1216 a5 77 LDA &77 ; key # Use a prnd as stream for decryption &1218 38 SEC &1219 69 38 ADC #&38 &121b 29 48 AND #&48 &121d 0a ASL A &121e 2a ROL A &121f 66 77 ROR &77 ; key &1221 46 78 LSR &78 ; key + 1 &1223 65 79 ADC &79 ; key + 2 &1225 85 79 STA &79 ; key + 2 &1227 51 75 EOR (&75),Y ; decryption_address &1229 91 75 STA (&75),Y ; decryption_address &122b c8 INY &122c d0 e8 BNE &1216 ; decryption_byte_loop &122e e6 76 INC &76 ; decryption_address_high &1230 a5 76 LDA &76 ; decryption_address_high &1232 c9 20 CMP #&20 &1234 b0 04 BCS &123a ; decrypted_code &1236 4c 14 12 JMP &1214 ; decryption_page_loop ; disk_has_been_unlocked &1239 00 # &ba if disk has been unlocked ; decrypted_code &123a 20 db 14 JSR &14db ; flush_keyboard # Returns X = 0 &123d 86 73 STX &73 ; double_track_numbers # Set to zero to not double track numbers by default &123f 86 7b STX &7b ; valid_disk # Set to zero to indicate disk is valid by default &1241 a9 c8 LDA #&c8 ; Read/Write BREAK/ESCAPE effect &1243 a2 03 LDX #&03 ; Clear memory on next RESET &1245 20 f4 ff JSR &fff4 ; OSBYTE &1248 a9 7e LDA #&7e ; Acknowledge ESCAPE condition &124a 20 f4 ff JSR &fff4 ; OSBYTE &124d a9 e5 LDA #&e5 ; Read/Write ESCAPE key status &124f a2 01 LDX #&01 ; ESCAPE inserts ASCII value &1251 20 f4 ff JSR &fff4 ; OSBYTE &1254 20 e3 14 JSR &14e3 ; seek_track_0 &1257 a9 7f LDA #&7f ; Floppy disk operation &1259 a2 9c LDX #&9c ; &159c = read_ids_block &125b a0 15 LDY #&15 &125d 20 f1 ff JSR &fff1 ; OSWORD # Read IDs to &2000 (id_data) &1260 ad 00 20 LDA &2000 ; id_data &1263 c9 04 CMP #&04 # Did a request for track 4 return track 4? &1265 f0 04 BEQ &126b ; skip_doubling &1267 a9 01 LDA #&01 # If not, set to non-zero to double track numbers &1269 85 73 STA &73 ; double_track_numbers ; skip_doubling &126b a9 80 LDA #&80 ; &2080 = special_sector_data + &80 &126d 85 75 STA &75 ; check_address_low &126f a9 20 LDA #&20 &1271 85 76 STA &76 ; check_address_high &1273 a0 0a LDY #&0a ; initialise_check_data_loop &1275 a9 ab LDA #&ab # Initialise memory with known value &1277 91 75 STA (&75),Y ; check_address &1279 88 DEY &127a 10 f9 BPL &1275 ; initialise_check_data_loop &127c a9 04 LDA #&04 &127e 85 7a STA &7a ; attempts &1280 ad af 15 LDA &15af ; set_track_register_block + 8 (value) # Use track 2 &1283 8d 3b 15 STA &153b ; track_to_use ; check_for_special_sector_loop &1286 20 e3 14 JSR &14e3 ; seek_track_0 &1289 20 ed 14 JSR &14ed ; seek_track &128c 20 04 15 JSR &1504 ; set_track_register &128f a9 7f LDA #&7f ; Floppy disk operation &1291 a2 b1 LDX #&b1 ; &15b1 = read_special_sector_block &1293 a0 15 LDY #&15 &1295 20 f1 ff JSR &fff1 ; OSWORD # Read track 2, sector 0 to &2000 (special_sector_data) ; check_if_data_was_as_expected &1298 a0 0a LDY #&0a ; check_if_data_was_as_expected_loop &129a b1 75 LDA (&75),Y ; check_address &129c d9 53 15 CMP &1553,Y ; expected_special_sector_data - 1 # Do bytes 129 - 138 match the expected values? &129f d0 05 BNE &12a6 ; read_data_failed_check &12a1 88 DEY &12a2 f0 17 BEQ &12bb ; disk_passed_check # If so, disk is valid &12a4 d0 f4 BNE &129a ; check_if_data_was_as_expected_loop # Always branches ; read_data_failed_check &12a6 c6 7a DEC &7a ; attempts # Otherwise, repeat read &12a8 10 dc BPL &1286 ; check_for_special_sector_loop ; check_if_any_data_was_read # If four attempts have failed, &12aa a0 0a LDY #&0a ; check_if_any_data_was_read_loop &12ac b1 75 LDA (&75),Y ; check_address &12ae c9 ab CMP #&ab # Has the previously initialised memory changed? &12b0 d0 05 BNE &12b7 ; disk_failed_check # If so, disk is invalid &12b2 88 DEY &12b3 f0 06 BEQ &12bb ; disk_passed_check # Otherwise, disk is valid &12b5 d0 f5 BNE &12ac ; check_if_any_data_was_read_loop # Always branches ; disk_failed_check &12b7 a9 01 LDA #&01 &12b9 85 7b STA &7b ; valid_disk # Set to non-zero to indicate disk is invalid ; disk_passed_check &12bb 20 e3 14 JSR &14e3 ; seek_track_0 &12be ad 88 15 LDA &1588 ; read_sectors_block + 7 (track) # Use track 3 &12c1 8d 3b 15 STA &153b ; track_to_use &12c4 20 e3 14 JSR &14e3 ; seek_track_0 &12c7 ad 88 15 LDA &1588 ; read_sectors_block + 7 (track) &12ca 8d 3b 15 STA &153b ; track_to_use &12cd a0 00 LDY #&00 # Read second stage from deleted sectors ; copy_read_sectors_block_loop # Copy &1581 - &1590 to &152b - &153a &12cf b9 81 15 LDA &1581,Y ; read_sectors_block &12d2 99 2b 15 STA &152b,Y ; read_block &12d5 e8 INX &12d6 c8 INY &12d7 c0 10 CPY #&10 &12d9 d0 f4 BNE &12cf ; copy_read_sectors_block_loop &12db ad 33 15 LDA &1533 ; read_block + 8 (sector) # Does the data start partway through a track? &12de f0 1d BEQ &12fd ; skip_reading_partial_first_track # Always branches &12e0 a9 00 LDA #&00 &12e2 8d 35 15 STA &1535 ; read_block + 10 (result) &12e5 a9 7f LDA #&7f ; Floppy disk operation &12e7 a2 2b LDX #&2b ; &152b = read_block &12e9 a0 15 LDY #&15 &12eb 20 f1 ff JSR &fff1 ; OSWORD # Read sectors from partial first track &12ee a9 0a LDA #&0a &12f0 38 SEC &12f1 ed 33 15 SBC &1533 ; read_block + 8 (sector) # Reduce size of subsequent read &12f4 18 CLC &12f5 69 20 ADC #&20 ; use 256 byte sectors &12f7 8d 34 15 STA &1534 ; read_block + 9 (size and count) &12fa ee 38 15 INC &1538 ; whole_tracks_to_read # Reread partial first track again ; skip_reading_partial_first_track ; read_whole_tracks_loop &12fd 20 ed 14 JSR &14ed ; seek_track &1300 20 04 15 JSR &1504 ; set_track_register &1303 ad 3b 15 LDA &153b ; track_to_use &1306 8d 32 15 STA &1532 ; read_block + 7 (track) &1309 a9 7f LDA #&7f ; Floppy disk operation &130b a2 2b LDX #&2b ; &152b = read_block &130d a0 15 LDY #&15 &130f 20 f1 ff JSR &fff1 ; OSWORD # Read whole track &1312 ad 34 15 LDA &1534 ; read_block + 9 (size and count) &1315 29 0f AND #&0f &1317 18 CLC &1318 6d 2d 15 ADC &152d ; read_block + 2 (address high) # Add size of track to address for next read &131b 8d 2d 15 STA &152d ; read_block + 2 (address high) &131e a9 2a LDA #&2a ; ten 256 byte sectors &1320 8d 34 15 STA &1534 ; read_block + 9 (size and count) # Read full track of ten sectors &1323 a9 00 LDA #&00 &1325 8d 33 15 STA &1533 ; read_block + 8 (sector) # Start reading from start of track &1328 20 14 15 JSR &1514 ; set_track_register_with_doubling &132b ee 3b 15 INC &153b ; track_to_use # Use next track &132e ce 38 15 DEC &1538 ; whole_tracks_to_read &1331 d0 ca BNE &12fd ; read_whole_tracks_loop &1333 ad 39 15 LDA &1539 ; remaining_sectors_to_read &1336 f0 1b BEQ &1353 ; skip_reading_partial_final_track &1338 18 CLC &1339 69 20 ADC #&20 ; use 256 byte sectors &133b 8d 34 15 STA &1534 ; read_block + 9 (size and count) &133e 20 ed 14 JSR &14ed ; seek_track &1341 20 04 15 JSR &1504 ; set_track_register &1344 ad 3b 15 LDA &153b ; track_to_use &1347 8d 32 15 STA &1532 ; read_block + 7 (track) &134a a9 7f LDA #&7f ; Floppy disk operation &134c a2 2b LDX #&2b ; &152b = read_block &134e a0 15 LDY #&15 &1350 20 f1 ff JSR &fff1 ; OSWORD # Read sectors from partial final track ; skip_reading_partial_final_track ; infinite_loop_if_unexpected_code_sector &1353 a5 7b LDA &7b ; valid_disk &1355 f0 29 BEQ &1380 ; load_code_sector ; this_is_a_copy &1357 a9 16 LDA #&16 # MODE 7 &1359 20 ee ff JSR &ffee ; OSWRCH &135c a9 07 LDA #&07 &135e 20 ee ff JSR &ffee ; OSWRCH &1361 a9 1f LDA #&1f # TAB(&0a, &0a) &1363 20 ee ff JSR &ffee ; OSWRCH &1366 a9 0a LDA #&0a &1368 20 ee ff JSR &ffee ; OSWRCH &136b a9 0a LDA #&0a &136d 20 ee ff JSR &ffee ; OSWRCH &1370 a0 00 LDY #&00 ; write_this_is_a_copy_loop &1372 b9 63 15 LDA &1563,Y ; this_is_a_copy_string &1375 20 ee ff JSR &ffee ; OSWRCH &1378 c8 INY &1379 c9 0d CMP #&0d ; CR &137b d0 f5 BNE &1372 ; write_this_is_a_copy_loop ; infinite_loop &137d 4c 7d 13 JMP &137d ; infinite_loop ; load_code_sector &1380 20 e3 14 JSR &14e3 ; seek_track_0 &1383 a9 26 LDA #&26 &1385 8d 3b 15 STA &153b ; track_to_use &1388 20 ed 14 JSR &14ed ; seek_track &138b 20 04 15 JSR &1504 ; set_track_register &138e a9 11 LDA #&11 ; &1100 = code_data &1390 8d be 15 STA &15be ; read_code_sector_block + 2 (address high) &1393 a9 00 LDA #&00 &1395 8d bd 15 STA &15bd ; read_code_sector_block + 1 (address low) &1398 a9 7f LDA #&7f ; Floppy disk operation &139a a2 bc LDX #&bc ; &15bc = read_code_sector_block &139c a0 15 LDY #&15 &139e 20 f1 ff JSR &fff1 ; OSWORD # Read code sector from track 26, sector 7 &13a1 ad fd 11 LDA &11fd ; code_data + &fd &13a4 85 70 STA &70 ; unique_bytes &13a6 ad fe 11 LDA &11fe ; code_data + &fe &13a9 85 71 STA &71 ; unique_bytes + 1 &13ab ad ff 11 LDA &11ff ; code_data + &ff # Unique values are stored in last three bytes &13ae 85 72 STA &72 ; unique_bytes + 2 &13b0 ad 96 11 LDA &1196 ; code_data + &96 &13b3 8d 39 12 STA &1239 ; disk_has_been_unlocked # If disk has been unlocked, byte &96 of sector is &ba &13b6 a2 00 LDX #&00 ; check_code_sector_contents_loop # For each byte in the "Peter Lee" string, &13b8 bd d7 15 LDA &15d7,X ; peter_lee_string &13bb a8 TAY &13bc 18 CLC &13bd 69 01 ADC #&01 # Add one, and use that as an offset into the sector &13bf 38 SEC &13c0 f9 00 11 SBC &1100,Y ; code_data &13c3 e0 00 CPX #&00 # First byte to check (X = 0) is "P" (ASCII &50), so &13c5 f0 05 BEQ &13cc ; skip_check # byte &50 of sector sets times run; (&51 - times run) &13c7 cd 94 14 CMP &1494 ; times_run # For each offset corresponding to the other bytes, &13ca d0 87 BNE &1353 ; infinite_loop_if_unexpected_code_sector # check that it matches; if not cause an infinite loop ; skip_check &13cc 85 74 STA &74 ; unobfuscated_times_run &13ce 8d 94 14 STA &1494 ; times_run &13d1 e8 INX &13d2 c0 0d CPY #&0d ; CR &13d4 d0 e2 BNE &13b8 ; check_code_sector_contents_loop &13d6 a2 ff LDX #&ff # For each byte in the code sector, ; randomise_non_peter_lee_bytes_loop &13d8 b5 00 LDA &00,X ; zero_page &13da 6d a0 02 ADC &02a0 ; os_countdown_timer + 4 &13dd 4d 93 02 EOR &0293 ; os_system_clock + 1 &13e0 85 80 STA &80 ; random_value &13e2 a0 00 LDY #&00 ; check_if_byte_is_in_peter_lee_string_loop &13e4 b9 d7 15 LDA &15d7,Y ; peter_lee_string &13e7 85 81 STA &81 ; expected_peter_lee &13e9 e4 81 CPX &81 ; expected_peter_lee &13eb f0 0a BEQ &13f7 ; skip_randomising_byte # Is it in the "Peter Lee" string? &13ed c8 INY &13ee c9 0d CMP #&0d ; CR &13f0 d0 f2 BNE &13e4 ; check_if_byte_is_in_peter_lee_string_loop &13f2 a5 80 LDA &80 ; random_value # If not, replace it with a random value &13f4 9d 00 11 STA &1100,X ; code_data # Bug: 1 in 256 chance of unlocking disk! ; skip_randomising_byte &13f7 ca DEX &13f8 d0 de BNE &13d8 ; randomise_non_peter_lee_bytes_loop &13fa a0 00 LDY #&00 ; increase_times_run_loop # For each byte in the "Peter Lee" string, &13fc b9 d7 15 LDA &15d7,Y ; peter_lee_string &13ff aa TAX &1400 d9 d7 15 CMP &15d7,Y ; peter_lee_string &1403 d0 0d BNE &1412 ; skip_increasing_times_run # Never branches &1405 fe 4a 16 INC &164a,X ; count_table &1408 bd 4a 16 LDA &164a,X ; count_table &140b c9 02 CMP #&02 &140d 10 03 BPL &1412 ; skip_increasing_times_run # Has the corresponding byte in the sector been changed? &140f de 00 11 DEC &1100,X ; code_data # If not, reduce by one (i.e. increase times run) ; skip_increasing_times_run &1412 c8 INY &1413 e0 0d CPX #&0d ; CR &1415 d0 e5 BNE &13fc ; increase_times_run_loop &1417 a5 74 LDA &74 ; unobfuscated_times_run &1419 c9 04 CMP #&04 # If the disk hasn't already been run four times, &141b b0 03 BCS &1420 ; skip_writing &141d 20 95 14 JSR &1495 ; write_code_sector_with_random_code # Write the code sector with the increased number ; skip_writing &1420 a5 74 LDA &74 ; unobfuscated_times_run # Obfuscate the number of times run &1422 18 CLC &1423 0a ASL A &1424 65 74 ADC &74 ; unobfuscated_times_run &1426 09 50 ORA #&50 &1428 49 ff EOR #&ff &142a 85 74 STA &74 ; obfuscated_times_run # Obfuscated value = ((unobfuscated * 3) | &50) ^ &ff &142c ad 39 12 LDA &1239 ; disk_has_been_unlocked &142f c9 ba CMP #&ba ; UNLOCKED &1431 d0 02 BNE &1435 ; not_unlocked &1433 85 74 STA &74 ; obfuscated_times_run ; not_unlocked &1435 20 00 20 JSR &2000 ; second_stage_entry_point # Returns if game is allowed to run &1438 ad 94 14 LDA &1494 ; times_run &143b c9 04 CMP #&04 # If the disk has been run four times, then the correct &143d d0 2d BNE &146c ; skip_writing_unlocked_code_sector # unlock code has been entered; unlock the disk. Bug: &143f 20 e3 14 JSR &14e3 ; seek_track_0 # the disk is written to every time it is run afterwards &1442 a9 26 LDA #&26 &1444 8d 3b 15 STA &153b ; track_to_use &1447 20 ed 14 JSR &14ed ; seek_track &144a 20 04 15 JSR &1504 ; set_track_register &144d a9 11 LDA #&11 ; &1100 = code_data &144f 8d be 15 STA &15be ; read_code_sector_block + 2 (address high) &1452 a9 00 LDA #&00 &1454 8d bd 15 STA &15bd ; read_code_sector_block + 1 (address low) &1457 a9 7f LDA #&7f ; Floppy disk operation &1459 a2 bc LDX #&bc ; &15bc = read_code_sector_block &145b a0 15 LDY #&15 &145d 20 f1 ff JSR &fff1 ; OSWORD # Reread code sector from track 26, sector 7 &1460 a9 ba LDA #&ba ; UNLOCKED &1462 8d 96 11 STA &1196 ; code_data + &96 # Set byte &96 to &ba to indicate disk is unlocked &1465 20 aa 14 JSR &14aa ; write_code_sector # Write code sector to track 26, sector 7 &1468 a9 10 LDA #&10 # Unlocked disk allows access to all 15 levels &146a 85 3f STA &3f ; maximum_level_plus_one ; skip_writing_unlocked_code_sector &146c a9 04 LDA #&04 ; &0400 = third_stage &146e 8d 8d 15 STA &158d ; run_address_high &1471 8d 3b 15 STA &153b ; track_to_use # Read third stage from deleted data on track 4 &1474 8d 88 15 STA &1588 ; read_sectors_block + 7 (track) &1477 a9 02 LDA #&02 &1479 8d 89 15 STA &1589 ; read_sectors_block + 8 (sector) # sectors 2 onwards (only first two are meaningful) &147c 20 e3 14 JSR &14e3 ; seek_track_0 &147f 20 ed 14 JSR &14ed ; seek_track &1482 20 04 15 JSR &1504 ; set_track_register &1485 a9 7f LDA #&7f ; Floppy disk operation &1487 a2 81 LDX #&81 ; &1581 = read_sectors_block &1489 a0 15 LDY #&15 &148b 20 f1 ff JSR &fff1 ; OSWORD # Read third stage &148e 20 c3 17 JSR &17c3 ; relocate_third_stage &1491 6c 8c 15 JMP (&158c) ; run_address # Call third_stage_entry_point ; times_run &1494 00 ; write_code_sector_with_random_code &1495 20 61 17 JSR &1761 ; initialise_prnd_state &1498 20 4d 17 JSR &174d ; generate_unique_bytes &149b a5 70 LDA &70 ; unique_bytes &149d 8d fd 11 STA &11fd ; code_data + &fd &14a0 a5 71 LDA &71 ; unique_bytes + 1 &14a2 8d fe 11 STA &11fe ; code_data + &fe &14a5 a5 72 LDA &72 ; unique_bytes + 2 &14a7 8d ff 11 STA &11ff ; code_data + &ff ; write_code_sector &14aa 20 e3 14 JSR &14e3 ; seek_track_0 &14ad a9 26 LDA #&26 &14af 8d 3b 15 STA &153b ; track_to_use &14b2 20 ed 14 JSR &14ed ; seek_track &14b5 20 04 15 JSR &1504 ; set_track_register &14b8 a9 11 LDA #&11 ; &1100 = code_data &14ba 8d c9 15 STA &15c9 ; write_code_sector_block + 2 (address high) &14bd a9 00 LDA #&00 &14bf 8d c8 15 STA &15c8 ; write_code_sector_block + 1 (address low) &14c2 a9 11 LDA #&11 &14c4 8d cb 15 STA &15cb ; write_code_sector_block + 4 (address high + 2) &14c7 a9 00 LDA #&00 &14c9 8d ca 15 STA &15ca ; write_code_sector_block + 3 (address low + 2) &14cc a9 7f LDA #&7f ; Floppy disk operation &14ce a2 c7 LDX #&c7 ; &15c7 = write_code_sector_block &14d0 a0 15 LDY #&15 &14d2 20 f1 ff JSR &fff1 ; OSWORD # Write code sector to track 26, sector 7 &14d5 ad d1 15 LDA &15d1 ; write_code_sector_block + 10 (result) &14d8 d0 bb BNE &1495 ; write_code_sector_with_random_code # Repeat until success &14da 60 RTS ; flush_keyboard &14db a9 15 LDA #&15 ; Flush selected buffer &14dd a2 00 LDX #&00 ; keyboard &14df 20 f4 ff JSR &fff4 ; OSBYTE &14e2 60 RTS ; seek_track_0 &14e3 a9 7f LDA #&7f ; Floppy disk operation &14e5 a2 76 LDX #&76 ; &1576 = seek_track_0_block &14e7 a0 15 LDY #&15 &14e9 20 f1 ff JSR &fff1 ; OSWORD # Seek to track 0 &14ec 60 RTS ; seek_track &14ed ad 3b 15 LDA &153b ; track_to_use &14f0 8d 98 15 STA &1598 ; seek_track_block + 7 (track number) &14f3 a5 73 LDA &73 ; double_track_numbers &14f5 f0 03 BEQ &14fa ; skip_doubling &14f7 0e 98 15 ASL &1598 ; seek_track_block + 7 (track number) ; skip_doubling &14fa a9 7f LDA #&7f ; Floppy disk operation &14fc a2 91 LDX #&91 ; &1591 = seek_track_block &14fe a0 15 LDY #&15 &1500 20 f1 ff JSR &fff1 ; OSWORD # Seek to specified track &1503 60 RTS ; set_track_register &1504 ad 3b 15 LDA &153b ; track_to_use &1507 8d af 15 STA &15af ; set_track_register_block + 8 (value) &150a a9 7f LDA #&7f ; Floppy disk operation &150c a2 a7 LDX #&a7 ; &15a7 = set_track_register_block &150e a0 15 LDY #&15 &1510 20 f1 ff JSR &fff1 ; OSWORD # Set track register &1513 60 RTS ; set_track_register_with_doubling &1514 ad 3b 15 LDA &153b ; track_to_use &1517 8d af 15 STA &15af ; set_track_register_block + 8 (value) &151a a5 73 LDA &73 ; double_track_numbers &151c f0 03 BEQ &1521 ; skip_doubling &151e 0e af 15 ASL &15af ; set_track_register_block + 8 (value) ; skip_doubling &1521 a9 7f LDA #&7f ; Floppy disk operation &1523 a2 a7 LDX #&a7 ; &15a7 = set_track_register_block &1525 a0 15 LDY #&15 &1527 20 f1 ff JSR &fff1 ; OSWORD # Set track register &152a 60 RTS ; read_block # &152b - &153a is overwritten at &12d2 &152b 00 ; drive 0 &152c 00 00 00 00 ; address &1530 00 ; parameters &1531 00 ; command &1532 00 ; track &1533 00 ; sector &1534 00 ; size and count &1535 00 ; result ; unused_copy_of_run_address &1536 00 00 ; whole_tracks_to_read &1538 00 ; remaining_sectors_to_read &1539 00 ; unused &153a 00 ; track_to_use &153b 00 ; unused &153c 00 ; unused_disable_cursor_string # Unused &153d 17 01 00 00 00 00 00 00 00 00 0d ; Turn off cursor ; unused_enable_cursor_string # Unused &1548 17 01 01 00 00 00 00 00 00 00 0d ; Turn on cursor ; unused &1553 5d ; expected_special_sector_data &1554 30 ff ff ff ff ff ff ff ff ff ; unused &155e 00 00 00 00 00 ; this_is_a_copy_string &1563 0c ; CLS &1564 1f 03 0e ; TAB(&03, &0e) &1567 54 68 69 73 20 69 73 20 61 20 63 6f 70 79 0d ; "This is a copy" ; seek_track_0_block # Seek to track 0 &1576 00 ; drive 0 &1577 00 19 00 00 ; address (unused) &157b 03 ; parameters (should be 1) &157c 69 ; command: seek &157d 00 ; track 0 &157e 00 ; unused parameter &157f 2a ; unused parameter &1580 00 ; result ; read_sectors_block # Read second and third stages &1581 00 ; drive 0 &1582 00 20 00 00 ; address : &2000 = second_stage_entry_point, unrelocated_third_state_entry_point &1586 03 ; parameters &1587 57 ; command : read data and deleted data &1588 03 ; track 3 &1589 00 ; sector 0 &158a 2a ; size and count : ten 256 byte sectors &158b 00 ; ; result ; run_address &158c 00 20 ; &2000 = second_stage_entry_point # Overwritten with third_state_entry_point ; initial_whole_tracks_to_read &158e 01 ; initial_remaining_sectors_to_read &158f 02 ; unused &1590 00 ; seek_track_block # Seek to specified track &1591 00 ; drive 0 &1592 00 20 00 00 ; address (unused) &1596 03 ; parameters (should be 1) &1597 69 ; command : seek &1598 04 ; track (value is overwritten) &1599 00 ; unused parameter &159a 2a ; unused parameter &159b 00 ; result ; read_ids_block # Read IDs &159c 00 ; drive 0 &159d 00 20 00 00 ; address : &2000 = id_data &15a1 03 ; parameters &15a2 5b ; command : read IDs &15a3 04 ; track 4 &15a4 00 ; zero parameter &15a5 0a ; count &15a6 00 ; result ; set_track_register_block # Set track register &15a7 00 ; drive 0 &15a8 ff ff 00 00 ; address (unused) &15ac 04 ; parameters (should be 2) &15ad 7a ; command : write special register &15ae 12 ; register : track register &15af 02 ; value (value is overwritten) &15b0 ff ; unused parameter ; read_special_sector_block # Read special sector from track 2, sector 0 &15b1 00 ; drive 0 &15b2 00 20 00 00 ; address : &2000 = special_sector_data &15b6 03 ; parameters &15b7 57 ; command : read data and deleted data &15b8 02 ; track 2 &15b9 00 ; sector 0 &15ba 21 ; size and count : one 256 byte sector &15bb 00 ; result ; read_code_sector_block # Read code sector from track 26, sector 7 &15bc 00 ; drive 0 &15bd 00 20 00 00 ; address (value is overwritten) &15c1 03 ; parameters &15c2 57 ; command : read data and deleted data &15c3 26 ; track 26 &15c4 07 ; sector 7 &15c5 21 ; size and count : one 256 byte sector &15c6 00 ; result ; write_code_sector_block &15c7 00 ; drive 0 &15c8 00 20 00 00 ; address (value is overwritten) &15cc 03 ; parameters &15cd 4b ; command : write data &15ce 26 ; track 26 &15cf 07 ; sector 7 &15d0 21 ; size and count : one 256 byte sector &15d1 00 ; result ; unused &15d2 00 00 00 00 00 ; peter_lee_string &15d7 50 65 74 65 72 20 4c 65 65 20 49 73 20 54 68 65 ; "Peter Lee Is The" # Peter Lee Is The Place To Be &15e7 20 50 6c 61 63 65 20 54 6f 20 42 65 50 65 74 65 ; " Place To BePete" # Peter Peter Where Art Thou &15f7 72 20 50 65 74 65 72 20 57 68 65 72 65 20 41 72 ; "r Peter Where Ar" # My Humble Master And The One &1607 74 20 54 68 6f 75 4d 79 20 48 75 6d 62 6c 65 20 ; "t ThouMy Humble " # I Adore Where Art Thou Great One &1617 4d 61 73 74 65 72 20 41 6e 64 20 54 68 65 20 4f ; "Master And The O" &1627 6e 65 49 20 41 64 6f 72 65 20 57 68 65 72 65 20 ; "neI Adore Where " &1637 41 72 74 20 54 68 6f 75 20 47 72 65 61 74 20 4f ; "Art Thou Great O" &1647 6e 65 0d ; "ne" ; count_table # Only bytes corresponding to characters in "Peter Lee" &164a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 # string are used ( ABGHILMOPTWabcdehlmnorstuy) &165a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 &166a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 &167a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 &168a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 &169a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 &16aa 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 &16ba 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 &16ca 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 &16da 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 &16ea 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 &16fa 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 &170a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 &171a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 &172a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 &173a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; prnd_state &1749 00 00 00 00 ; generate_unique_bytes &174d 20 7d 17 JSR &177d ; prnd &1750 85 71 STA &71 ; unique_bytes + 1 &1752 20 af 17 JSR &17af ; rotate_two_bits_into_first_byte_of_unique_bytes &1755 ad 96 02 LDA &0296 ; os_system_clock + 4 &1758 8d 49 17 STA &1749 ; prnd_state &175b 85 72 STA &72 ; unique_bytes + 2 &175d 20 b7 17 JSR &17b7 ; or_bits_into_first_byte_of_unique_bytes &1760 60 RTS ; initialise_prnd_state &1761 ad a0 02 LDA &02a0 ; os_countdown_timer + 4 &1764 4d 49 17 EOR &1749 ; prnd_state &1767 8d 49 17 STA &1749 ; prnd_state &176a 4d 4a 17 EOR &174a ; prnd_state + 1 &176d 8d 4a 17 STA &174a ; prnd_state + 1 &1770 4d 4b 17 EOR &174b ; prnd_state + 2 &1773 8d 4b 17 STA &174b ; prnd_state + 2 &1776 4d 4c 17 EOR &174c ; prnd_state + 3 &1779 8d 4c 17 STA &174c ; prnd_state + 3 &177c 60 RTS ; prnd &177d 8a TXA &177e 48 PHA &177f 98 TYA &1780 48 PHA &1781 a2 08 LDX #&08 ; prnd_loop &1783 a0 00 LDY #&00 &1785 8c 4c 17 STY &174c ; prnd_state + 3 &1788 a0 08 LDY #&08 &178a ad 4b 17 LDA &174b ; prnd_state + 2 &178d 29 e1 AND #&e1 ; prnd_bit_loop &178f 0a ASL A &1790 90 03 BCC &1795 ; bit_not_set &1792 ee 4c 17 INC &174c ; prnd_state + 3 ; bit_not_set &1795 88 DEY &1796 d0 f7 BNE &178f ; prnd_bit_loop &1798 4e 4c 17 LSR &174c ; prnd_state + 3 &179b 2e 49 17 ROL &1749 ; prnd_state &179e 2e 4a 17 ROL &174a ; prnd_state + 1 &17a1 2e 4b 17 ROL &174b ; prnd_state + 2 &17a4 ca DEX &17a5 d0 dc BNE &1783 ; prnd_loop &17a7 68 PLA &17a8 a8 TAY &17a9 68 PLA &17aa aa TAX &17ab ad 49 17 LDA &1749 ; prnd_state &17ae 60 RTS ; rotate_two_bits_into_first_byte_of_unique_bytes &17af 18 CLC &17b0 2a ROL A &17b1 66 70 ROR &70 ; unique_bytes &17b3 2a ROL A &17b4 66 70 ROR &70 ; unique_bytes &17b6 60 RTS ; or_bits_into_first_byte_of_unique_bytes &17b7 18 CLC &17b8 6a ROR A &17b9 26 84 ROL &84 ; sink &17bb 6a ROR A &17bc 26 84 ROL &84 ; sink &17be 05 70 ORA &70 ; unique_bytes &17c0 85 70 STA &70 ; unique_bytes &17c2 60 RTS ; relocate_third_stage &17c3 a9 20 LDA #&20 ; &2000 = unrelocated_third_stage # Move &2000 - &24ff to &0400 - &08ff &17c5 85 76 STA &76 ; source_address_high &17c7 a9 00 LDA #&00 &17c9 85 75 STA &75 ; source_address_low &17cb a9 04 LDA #&04 ; &0400 = third_stage_entry_point &17cd 85 83 STA &83 ; target_address_high &17cf a9 00 LDA #&00 &17d1 85 82 STA &82 ; target_address_low ; relocate_third_stage_page_loop &17d3 a0 00 LDY #&00 ; relocate_third_stage_byte_loop &17d5 b1 75 LDA (&75),Y ; source_address &17d7 91 82 STA (&82),Y ; target_address &17d9 c8 INY &17da d0 f9 BNE &17d5 ; relocate_third_stage_bute_loop &17dc e6 76 INC &76 ; source_address_high &17de e6 83 INC &83 ; target_address_high &17e0 a5 83 LDA &83 ; target_address_high &17e2 c9 08 CMP #&08 &17e4 d0 ed BNE &17d3 ; relocate_third_stage_page_loop &17e6 a0 00 LDY #&00 ; relocate_third_stage_last_loop &17e8 b1 75 LDA (&75),Y ; source_address &17ea 91 82 STA (&82),Y ; target_address &17ec c8 INY &17ed d0 f9 BNE &17e8 ; relocate_third_stage_last_loop &17ef 60 RTS ; unused &17f0 00 fe 1e 3e 5e 7e 9e be de fe 1e 3e 5e 7e 9e be # Second stage # &2000 - &2bff is loaded from deleted data on track 3 and first two sectors of track 4 ; second_stage_entry_point &2000 a5 74 LDA &74 ; obfuscated_times_run &2002 c9 bb CMP #&bb ; UNLOCKED + 1 &2004 90 1b BCC &2021 ; skip_pointless_checksum # Always branches &2006 a9 27 LDA #&27 ; &27f6 = title_screen_data # Unnecessary code &2008 85 7e STA &7e ; address_high &200a a9 f6 LDA #&f6 &200c 85 7d STA &7d ; address_low ; pointless_checksum_page_loop &200e a0 ff LDY #&ff ; pointless_checksum_byte_loop &2010 b9 00 00 LDA &0000,Y &2013 4d a0 02 EOR &02a0 ; os_countdown_timer + 4 &2016 88 DEY &2017 d0 f7 BNE &2010 ; pointless_checksum_byte_loop &2019 c6 7e DEC &7e ; address_high &201b a5 7e LDA &7e ; address_high &201d c9 20 CMP #&20 &201f d0 ed BNE &200e ; pointless_checksum_page_loop ; skip_pointless_checksum &2021 a5 74 LDA &74 ; obfuscated_times_run &2023 c9 ba CMP #&ba ; UNLOCKED &2025 d0 03 BNE &202a ; instructions_screen &2027 4c d8 21 JMP &21d8 ; copy_title_screen_and_disable_cursor ; instructions_screen &202a a9 16 LDA #&16 # Change to MODE 3 &202c 20 ee ff JSR &ffee ; OSWRCH &202f a9 03 LDA #&03 &2031 20 ee ff JSR &ffee ; OSWRCH &2034 a2 00 LDX #&00 # TAB(&00, &00) &2036 a0 00 LDY #&00 &2038 20 56 22 JSR &2256 ; tab_to_x_y &203b a0 22 LDY #&22 ; &226e = instructions_line_1_string &203d a2 6e LDX #&6e &203f 20 0b 22 JSR &220b ; write_string &2042 a2 00 LDX #&00 # TAB(&00, &02) &2044 a0 02 LDY #&02 &2046 20 56 22 JSR &2256 ; tab_to_x_y &2049 a0 22 LDY #&22 ; &22ab = instructions_line_2_string &204b a2 ab LDX #&ab &204d 20 0b 22 JSR &220b ; write_string &2050 a2 00 LDX #&00 # TAB(&00, &03) &2052 a0 03 LDY #&03 &2054 20 56 22 JSR &2256 ; tab_to_x_y &2057 a0 22 LDY #&22 ; &22fa = instructions_line_3_string &2059 a2 fa LDX #&fa &205b 20 0b 22 JSR &220b ; write_string &205e a2 00 LDX #&00 # TAB(&00, &04) &2060 a0 04 LDY #&04 &2062 20 56 22 JSR &2256 ; tab_to_x_y &2065 a0 23 LDY #&23 ; &233e = instructions_line_4_string &2067 a2 3e LDX #&3e &2069 20 0b 22 JSR &220b ; write_string &206c a2 00 LDX #&00 # TAB(&00, &05) &206e a0 05 LDY #&05 &2070 20 56 22 JSR &2256 ; tab_to_x_y &2073 a0 23 LDY #&23 ; &2369 = instructions_line_5_string &2075 a2 69 LDX #&69 &2077 20 0b 22 JSR &220b ; write_string &207a a2 14 LDX #&14 # TAB(&14, &02) &207c a0 02 LDY #&02 &207e 20 56 22 JSR &2256 ; tab_to_x_y &2081 20 ab 27 JSR &27ab ; get_number_of_times_run &2084 20 44 26 JSR &2644 ; write_three_digit_number # Write number of times disk has been run &2087 a2 00 LDX #&00 # TAB(&00, &07) &2089 a0 07 LDY #&07 &208b 20 56 22 JSR &2256 ; tab_to_x_y &208e a0 23 LDY #&23 ; &238b = instructions_line_6_string &2090 a2 8b LDX #&8b &2092 20 0b 22 JSR &220b ; write_string &2095 a2 00 LDX #&00 # TAB(&00, &08) &2097 a0 08 LDY #&08 &2099 20 56 22 JSR &2256 ; tab_to_x_y &209c a0 23 LDY #&23 ; &23d9 = instructions_line_7_string &209e a2 d9 LDX #&d9 &20a0 20 0b 22 JSR &220b ; write_string &20a3 a2 00 LDX #&00 # TAB(&00, &09) &20a5 a0 09 LDY #&09 &20a7 20 56 22 JSR &2256 ; tab_to_x_y &20aa a0 24 LDY #&24 ; &242a = instructions_line_8_string &20ac a2 2a LDX #&2a &20ae 20 0b 22 JSR &220b ; write_string &20b1 a2 00 LDX #&00 # TAB(&00, &0b) &20b3 a0 0b LDY #&0b &20b5 20 56 22 JSR &2256 ; tab_to_x_y &20b8 a0 24 LDY #&24 ; &244f = instructions_line_9_string &20ba a2 4f LDX #&4f &20bc 20 0b 22 JSR &220b ; write_string &20bf a2 00 LDX #&00 # TAB(&00, &0c) &20c1 a0 0c LDY #&0c &20c3 20 56 22 JSR &2256 ; tab_to_x_y &20c6 a0 24 LDY #&24 ; &245c = instructions_line_10_string &20c8 a2 5c LDX #&5c &20ca 20 0b 22 JSR &220b ; write_string &20cd a2 00 LDX #&00 # TAB(&00, &0d) &20cf a0 0d LDY #&0d &20d1 20 56 22 JSR &2256 ; tab_to_x_y &20d4 a0 24 LDY #&24 ; &246a = instructions_line_11_string &20d6 a2 6a LDX #&6a &20d8 20 0b 22 JSR &220b ; write_string &20db a2 00 LDX #&00 # TAB(&00, &0e) &20dd a0 0e LDY #&0e &20df 20 56 22 JSR &2256 ; tab_to_x_y &20e2 a0 24 LDY #&24 ; &24b3 = instructions_line_12_string &20e4 a2 b3 LDX #&b3 &20e6 20 0b 22 JSR &220b ; write_string &20e9 a2 00 LDX #&00 # TAB(&00, &0f) &20eb a0 0f LDY #&0f &20ed 20 56 22 JSR &2256 ; tab_to_x_y &20f0 a0 24 LDY #&24 ; &24bd = instructions_line_13_string &20f2 a2 bd LDX #&bd &20f4 20 0b 22 JSR &220b ; write_string &20f7 a2 00 LDX #&00 # TAB(&00, &11) &20f9 a0 11 LDY #&11 &20fb 20 56 22 JSR &2256 ; tab_to_x_y &20fe a0 24 LDY #&24 ; &24c5 = instructions_line_14_string &2100 a2 c5 LDX #&c5 &2102 20 0b 22 JSR &220b ; write_string &2105 a2 00 LDX #&00 # TAB(&00, &12) &2107 a0 12 LDY #&12 &2109 20 56 22 JSR &2256 ; tab_to_x_y &210c a0 25 LDY #&25 ; &2515 = instructions_line_15_string &210e a2 15 LDX #&15 &2110 20 0b 22 JSR &220b ; write_string &2113 a9 06 LDA #&06 # Locked version only allows access to levels 1 - 5 &2115 85 3f STA &3f ; maximum_level_plus_one &2117 20 ab 27 JSR &27ab ; get_number_of_times_run &211a c0 04 CPY #&04 &211c b0 03 BCS &2121 ; request_unlock_code # On the fourth run, request unlock code &211e 4c c7 21 JMP &21c7 ; wait_for_space_then_copy_title_screen # Otherwise, continue to loading game ; request_unlock_code &2121 a9 10 LDA #&10 # Unlocked disk allows access to all 15 levels &2123 85 3f STA &3f ; maximum_level_plus_one &2125 a2 00 LDX #&00 # TAB(&00, &14) &2127 a0 14 LDY #&14 &2129 20 56 22 JSR &2256 ; tab_to_x_y &212c a0 25 LDY #&25 ; &255f = enter_your_code_converted_number &212e a2 5f LDX #&5f &2130 20 0b 22 JSR &220b ; write_string &2133 a5 72 LDA &72 ; unique_bytes + 2 # Permute unique bytes on disk to create unique number &2135 49 ab EOR #&ab &2137 85 72 STA &72 ; unique_bytes + 2 &2139 a5 70 LDA &70 ; unique_bytes &213b 29 7f AND #&7f &213d 85 70 STA &70 ; unique_bytes &213f a5 70 LDA &70 ; unique_bytes &2141 85 80 STA &80 ; unique_number + 1 &2143 a5 71 LDA &71 ; unique_bytes + 1 &2145 85 7f STA &7f ; unique_number &2147 a5 72 LDA &72 ; unique_bytes + 2 &2149 85 81 STA &81 ; unique_number + 2 &214b a2 18 LDX #&18 # TAB(&18, &05) &214d a0 05 LDY #&05 &214f 20 56 22 JSR &2256 ; tab_to_x_y &2152 a0 00 LDY #&00 ; write_unique_number_loop # Write unique number &2154 b9 7f 00 LDA &007f,Y ; unique_number &2157 20 e7 26 JSR &26e7 ; convert_number_to_string &215a ad e3 26 LDA &26e3 ; converted_number &215d 20 ee ff JSR &ffee ; OSWRCH &2160 ad e4 26 LDA &26e4 ; converted_number + 1 &2163 20 ee ff JSR &ffee ; OSWRCH &2166 ad e5 26 LDA &26e5 ; converted_number + 2 &2169 20 ee ff JSR &ffee ; OSWRCH &216c c8 INY &216d c0 03 CPY #&03 &216f d0 e3 BNE &2154 ; write_unique_number_loop &2171 a5 70 LDA &70 ; unique_bytes &2173 85 78 STA &78 ; expected_result &2175 a5 71 LDA &71 ; unique_bytes + 1 &2177 85 79 STA &79 ; expected_result + 1 &2179 a5 72 LDA &72 ; unique_bytes + 2 &217b 85 7a STA &7a ; expected_result + 2 ; wait_for_valid_code_number &217d 20 1e 22 JSR &221e ; read_number # Request nine digit number &2180 a2 00 LDX #&00 &2182 a0 00 LDY #&00 ; process_entered_number_loop # For three sets of three digits, &2184 b9 65 22 LDA &2265,Y ; entered_number &2187 8d b5 26 STA &26b5 ; three_digits_string &218a b9 66 22 LDA &2266,Y ; entered_number + 1 &218d 8d b6 26 STA &26b6 ; three_digits_string + 1 &2190 b9 67 22 LDA &2267,Y ; entered_number + 2 &2193 8d b7 26 STA &26b7 ; three_digits_string + 2 &2196 98 TYA &2197 48 PHA &2198 8a TXA &2199 48 PHA &219a 20 bb 26 JSR &26bb ; convert_three_digits_into_byte # convert the digits into a byte &219d 68 PLA &219e aa TAX &219f 68 PLA &21a0 a8 TAY &21a1 ad b9 26 LDA &26b9 ; digits_as_byte &21a4 95 75 STA &75,X ; entered_result &21a6 e8 INX &21a7 c8 INY &21a8 c8 INY &21a9 c8 INY &21aa c0 09 CPY #&09 &21ac d0 d6 BNE &2184 ; process_entered_number_loop &21ae a2 38 LDX #&38 # TAB(&38, &14) &21b0 a0 14 LDY #&14 &21b2 20 56 22 JSR &2256 ; tab_to_x_y &21b5 20 95 27 JSR &2795 ; transform_entered_result &21b8 a2 00 LDX #&00 ; check_loop &21ba b5 75 LDA &75,X ; entered_result &21bc d5 78 CMP &78,X ; expected_result # Is the entered number correct? &21be d0 26 BNE &21e6 ; code_number_is_wrong &21c0 e8 INX &21c1 e0 03 CPX #&03 &21c3 d0 f5 BNE &21ba ; check_loop &21c5 f0 11 BEQ &21d8 ; copy_title_screen_and_disable_cursor # Always branches ; wait_for_space_then_copy_title_screen &21c7 a2 18 LDX #&18 # TAB(&18, &14) &21c9 a0 14 LDY #&14 &21cb 20 56 22 JSR &2256 ; tab_to_x_y &21ce a0 25 LDY #&25 ; &25b9 = press_space_to_continue_string &21d0 a2 b9 LDX #&b9 &21d2 20 0b 22 JSR &220b ; write_string &21d5 20 e0 ff JSR &ffe0 ; OSRDCH ; copy_title_screen_and_disable_cursor &21d8 20 c7 27 JSR &27c7 ; copy_title_screen &21db a0 26 LDY #&26 ; &269f = disable_cursor_string &21dd a2 9f LDX #&9f &21df 20 0b 22 JSR &220b ; write_string &21e2 20 e0 ff JSR &ffe0 ; OSRDCH &21e5 60 RTS ; code_number_is_wrong &21e6 a2 00 LDX #&00 # TAB(&00, &17) &21e8 a0 17 LDY #&17 &21ea 20 56 22 JSR &2256 ; tab_to_x_y &21ed a0 25 LDY #&25 ; &2596 = code_number_is_wrong_string &21ef a2 96 LDX #&96 &21f1 20 0b 22 JSR &220b ; write_string &21f4 20 4b 22 JSR &224b ; delay &21f7 20 e0 ff JSR &ffe0 ; OSRDCH &21fa a2 00 LDX #&00 # TAB(&00, &17) &21fc a0 17 LDY #&17 &21fe 20 56 22 JSR &2256 ; tab_to_x_y &2201 a0 25 LDY #&25 ; &25d8 = spaces_string &2203 a2 d8 LDX #&d8 &2205 20 0b 22 JSR &220b ; write_string &2208 4c 7d 21 JMP &217d ; wait_for_valid_code_number ; write_string &220b 86 7d STX &7d ; text_address_low &220d 84 7e STY &7e ; text_address_high &220f a0 00 LDY #&00 ; write_string_loop &2211 b1 7d LDA (&7d),Y ; text_address &2213 c9 0d CMP #&0d ; CR &2215 f0 06 BEQ &221d ; leave &2217 20 ee ff JSR &ffee ; OSWRCH &221a c8 INY &221b d0 f4 BNE &2211 ; write_string_loop &221d 60 RTS ; read_number &221e a2 38 LDX #&38 # TAB(&38, &14) &2220 a0 14 LDY #&14 &2222 20 56 22 JSR &2256 ; tab_to_x_y &2225 a2 00 LDX #&00 &2227 a0 09 LDY #&09 # Y is characters remaining ; read_number_loop &2229 20 e0 ff JSR &ffe0 ; OSRDCH &222c c9 0d CMP #&0d ; CR &222e f0 07 BEQ &2237 ; add_character &2230 c9 7f CMP #&7f &2232 f0 0b BEQ &223f ; delete_pressed &2234 20 ee ff JSR &ffee ; OSWRCH ; add_character &2237 9d 65 22 STA &2265,X ; entered_number &223a e8 INX &223b 88 DEY &223c d0 eb BNE &2229 ; read_number_loop # Require nine characters &223e 60 RTS ; delete_pressed &223f c0 09 CPY #&09 &2241 b0 e6 BCS &2229 ; read_number_loop &2243 20 ee ff JSR &ffee ; OSWRCH &2246 ca DEX &2247 c8 INY &2248 4c 29 22 JMP &2229 ; read_number_loop ; delay &224b a0 ff LDY #&ff ; delay_outer_loop &224d a2 ff LDX #&ff ; delay_inner_loop &224f ca DEX &2250 d0 fd BNE &224f ; delay_inner_loop &2252 88 DEY &2253 d0 f8 BNE &224d ; delay_outer_loop &2255 60 RTS ; tab_to_x_y &2256 a9 1f LDA #&1f &2258 20 ee ff JSR &ffee ; OSWRCH &225b 8a TXA &225c 20 ee ff JSR &ffee ; OSWRCH &225f 98 TYA &2260 20 ee ff JSR &ffee ; OSWRCH &2263 60 RTS ; unused &2264 0a ; entered_number &2265 00 00 00 00 00 00 00 00 00 ; instructions_line_1_string &226e 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 ; " WARNING! THIS DISC LOADS ONLY THREE TIMES" &227e 20 20 20 57 41 52 4e 49 4e 47 21 20 54 48 49 53 &228e 20 44 49 53 43 20 4c 4f 41 44 53 20 4f 4e 4c 59 &229e 20 54 48 52 45 45 20 54 49 4d 45 53 0d ; instructions_line_2_string &22ab 54 68 69 73 20 64 69 73 63 20 68 61 73 20 6c 6f ; "This disc has loaded times. To continue playing XOR after the " &22bb 61 64 65 64 20 20 20 20 74 69 6d 65 73 2e 20 54 ; "third time of" &22cb 6f 20 63 6f 6e 74 69 6e 75 65 20 70 6c 61 79 69 &22db 6e 67 20 58 4f 52 20 61 66 74 65 72 20 74 68 65 &22eb 20 74 68 69 72 64 20 74 69 6d 65 20 6f 66 0d ; instructions_line_3_string &22fa 6c 6f 61 64 69 6e 67 20 79 6f 75 20 72 65 71 75 ; "loading you require a CODE number to match with your UNIQUE " &230a 69 72 65 20 61 20 43 4f 44 45 20 6e 75 6d 62 65 ; "number." &231a 72 20 74 6f 20 6d 61 74 63 68 20 77 69 74 68 20 &232a 79 6f 75 72 20 55 4e 49 51 55 45 20 6e 75 6d 62 &233a 65 72 2e 0d ; instructions_line_4_string &233e 57 68 69 63 68 20 77 69 6c 6c 20 61 70 70 65 61 ; "Which will appear below on the fourth load" &234e 72 20 62 65 6c 6f 77 20 6f 6e 20 74 68 65 20 66 &235e 6f 75 72 74 68 20 6c 6f 61 64 0d ; instructions_line_5_string &2369 59 4f 55 52 20 55 4e 49 51 55 45 20 4e 55 4d 42 ; "YOUR UNIQUE NUMBER IS : 000000000" &2379 45 52 20 49 53 20 3a 20 30 30 30 30 30 30 30 30 &2389 30 0d ; instructions_line_6_string &238b 59 6f 75 20 63 61 6e 20 65 6e 61 62 6c 65 20 74 ; "You can enable the disk for indefinite plays and access to " &239b 68 65 20 64 69 73 6b 20 66 6f 72 20 69 6e 64 65 ; "levels 6-15 at the" &23ab 66 69 6e 69 74 65 20 70 6c 61 79 73 20 61 6e 64 &23bb 20 61 63 63 65 73 73 20 74 6f 20 6c 65 76 65 6c &23cb 73 20 36 2d 31 35 20 61 74 20 74 68 65 0d ; instructions_line_7_string &23d9 6f 66 66 65 72 20 70 72 69 63 65 20 6f 66 20 60 ; "offer price of `9.95 (RRP `12.95), by sending a cheque or postal " &23e9 39 2e 39 35 20 28 52 52 50 20 60 31 32 2e 39 35 ; "order for `9.95" &23f9 29 2c 20 62 79 20 73 65 6e 64 69 6e 67 20 61 20 &2409 63 68 65 71 75 65 20 6f 72 20 70 6f 73 74 61 6c &2419 20 6f 72 64 65 72 20 66 6f 72 20 60 39 2e 39 35 &2429 0d ; instructions_line_8_string &242a 54 4f 47 45 54 48 45 52 20 57 49 54 48 20 59 4f ; "TOGETHER WITH YOUR UNIQUE NUMBER to:" &243a 55 52 20 55 4e 49 51 55 45 20 4e 55 4d 42 45 52 &244a 20 74 6f 3a 0d ; instructions_line_9_string &244f 4c 6f 67 6f 74 72 6f 6e 2f 58 4f 52 0d ; "Logotron/XOR" ; instructions_line_10_string &245c 44 61 6c 65 73 20 42 72 65 77 65 72 79 0d ; "Dales Brewery" ; instructions_line_11_string &246a 47 77 79 64 69 72 20 53 74 72 65 65 74 20 20 20 ; "Gwydir Street Every 100th purchaser receives their CODE " &247a 20 20 20 20 20 45 76 65 72 79 20 31 30 30 74 68 ; "No. FREE!" &248a 20 70 75 72 63 68 61 73 65 72 20 72 65 63 65 69 &249a 76 65 73 20 74 68 65 69 72 20 43 4f 44 45 20 4e &24aa 6f 2e 20 46 52 45 45 21 0d ; instructions_line_12_string &24b3 43 61 6d 62 72 69 64 67 65 0d ; "Cambridge" ; instructions_line_13_string &24bd 43 42 31 20 32 4c 46 0d ; "CB1 2LF" ; instructions_line_14_string &24c5 6f 72 20 74 65 6c 65 70 68 6f 6e 65 20 79 6f 75 ; "or telephone your VISA or ACCESS No. to Cambridge (0223) 460201, " &24d5 72 20 56 49 53 41 20 6f 72 20 41 43 43 45 53 53 ; "460207, 460208" &24e5 20 4e 6f 2e 20 74 6f 20 43 61 6d 62 72 69 64 67 &24f5 65 20 28 30 32 32 33 29 20 34 36 30 32 30 31 2c &2505 20 34 36 30 32 30 37 2c 20 34 36 30 32 30 38 0d ; instructions_line_15_string &2515 6f 72 20 34 36 30 32 30 39 2e 20 57 65 20 77 69 ; "or 460209. We will give you the code number you need to ENABLE " &2525 6c 6c 20 67 69 76 65 20 79 6f 75 20 74 68 65 20 ; "your disk." &2535 63 6f 64 65 20 6e 75 6d 62 65 72 20 79 6f 75 20 &2545 6e 65 65 64 20 74 6f 20 45 4e 41 42 4c 45 20 79 &2555 6f 75 72 20 64 69 73 6b 2e 0d ; enter_your_code_converted_number &255f 54 4f 20 43 4f 4e 54 49 4e 55 45 20 57 49 54 48 ; "TO CONTINUE WITH THE GAME PLEASE ENTER YOUR CODE NO. :" &256f 20 54 48 45 20 47 41 4d 45 20 50 4c 45 41 53 45 &257f 20 45 4e 54 45 52 20 59 4f 55 52 20 43 4f 44 45 &258f 20 4e 4f 2e 20 3a 0d ; code_number_is_wrong_string &2596 54 48 45 20 43 4f 44 45 20 4e 4f 2e 20 59 4f 55 ; "THE CODE NO. YOU TYPED IN IS WRONG" &25a6 20 54 59 50 45 44 20 49 4e 20 49 53 20 57 52 4f &25b6 4e 47 0d ; press_space_to_continue_string &25b9 50 6c 65 61 73 65 20 70 72 65 73 73 20 53 50 41 ; "Please press SPACE to continue" &25c9 43 45 20 74 6f 20 63 6f 6e 74 69 6e 75 65 0d ; spaces_string &25d8 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 ; " " &25e8 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 &25f8 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 &2608 20 20 0d ; tonys_protector_screen # Unused code &260b a9 16 LDA #&16 # Change to MODE 7 &260d 20 ee ff JSR &ffee ; OSWRCH &2610 a9 07 LDA #&07 &2612 20 ee ff JSR &ffee ; OSWRCH &2615 a0 05 LDY #&05 ; write_tonys_protector_double_height_loop &2617 a9 1f LDA #&1f # TAB(&08, &05) &2619 20 ee ff JSR &ffee ; OSWRCH &261c a9 08 LDA #&08 &261e 20 ee ff JSR &ffee ; OSWRCH &2621 98 TYA &2622 20 ee ff JSR &ffee ; OSWRCH &2625 a2 00 LDX #&00 ; write_tonys_protector_loop &2627 bd 8d 26 LDA &268d,X ; tonys_protector_string # Write "Tonys Protector" in double height yellow &262a 20 ee ff JSR &ffee ; OSWRCH &262d e8 INX &262e e0 11 CPX #&11 &2630 d0 f5 BNE &2627 ; write_tonys_protector_loop &2632 c8 INY &2633 c0 06 CPY #&06 &2635 f0 e0 BEQ &2617 ; write_tonys_protector_double_height_loop &2637 a2 02 LDX #&02 # TAB(&02, &02) &2639 a0 02 LDY #&02 &263b 20 56 22 JSR &2256 ; tab_to_x_y &263e 20 ab 27 JSR &27ab ; get_number_of_times_run &2641 20 44 26 JSR &2644 ; write_three_digit_number # Write number of times run ; write_three_digit_number &2644 20 72 26 JSR &2672 ; split_number_into_three_digits &2647 f0 09 BEQ &2652 ; write_leading_space &2649 18 CLC &264a 69 30 ADC #&30 ; "0" &264c 20 ee ff JSR &ffee ; OSWRCH &264f 4c 63 26 JMP &2663 ; write_two_digit_number_from_Y_and_X ; write_leading_space &2652 a9 20 LDA #&20 ; " " &2654 20 ee ff JSR &ffee ; OSWRCH &2657 c0 00 CPY #&00 &2659 d0 08 BNE &2663 ; write_two_digit_number_from_Y_and_X &265b a9 20 LDA #&20 ; " " &265d 20 ee ff JSR &ffee ; OSWRCH &2660 4c 6a 26 JMP &266a ; write_one_digit_number_from_X ; write_two_digit_number_from_Y_and_X &2663 98 TYA &2664 18 CLC &2665 69 30 ADC #&30 ; "0" &2667 20 ee ff JSR &ffee ; OSWRCH ; write_one_digit_number_from_X &266a 8a TXA &266b 18 CLC &266c 69 30 ADC #&30 ; "0" &266e 20 ee ff JSR &ffee ; OSWRCH &2671 60 RTS ; split_number_into_three_digits &2672 a0 ff LDY #&ff &2674 38 SEC ; calculate_hundreds_loop &2675 c8 INY &2676 e9 64 SBC #&64 ; 100 &2678 b0 fb BCS &2675 ; calculate_hundreds_loop &267a 69 64 ADC #&64 ; 100 &267c aa TAX &267d 98 TYA &267e 48 PHA &267f 8a TXA &2680 a0 ff LDY #&ff &2682 38 SEC ; calculate_tens_loop &2683 c8 INY &2684 e9 0a SBC #&0a ; 10 &2686 b0 fb BCS &2683 ; calculate_tens_loop &2688 69 0a ADC #&0a ; 10 &268a aa TAX &268b 68 PLA &268c 60 RTS # Leave with A = hundreds, Y = tens, X = ones ; tonys_protector_string &268d 8d 83 ; DOUBLE_HEIGHT YELLOW &268f 54 6f 6e 79 73 20 50 72 6f 74 65 63 74 6f 72 0d ; "Tonys Protector" ; disable_cursor_string &269f 17 01 00 00 00 00 00 00 00 00 0d ; Turn off cursor ; unused_enable_cursor_string # Unused &26ab 17 01 01 00 00 00 00 00 00 00 0d ; Turn on cursor ; three_digits_string &26b5 30 30 30 0d ; "000" ; digits_as_byte &26b9 00 ; tmp &26ba 00 ; convert_three_digits_into_byte &26bb a0 00 LDY #&00 &26bd 8c b9 26 STY &26b9 ; digits_as_byte ; convert_three_digits_into_byte_loop &26c0 b9 b5 26 LDA &26b5,Y ; three_digits_string &26c3 c9 0d CMP #&0d ; CR &26c5 f0 1b BEQ &26e2 ; leave &26c7 29 0f AND #&0f &26c9 8d ba 26 STA &26ba ; tmp &26cc ad b9 26 LDA &26b9 ; digits_as_byte &26cf 0a ASL A # Multiply by ten &26d0 8d b9 26 STA &26b9 ; digits_as_byte &26d3 0a ASL A &26d4 0a ASL A &26d5 18 CLC &26d6 6d b9 26 ADC &26b9 ; digits_as_byte &26d9 6d ba 26 ADC &26ba ; tmp &26dc 8d b9 26 STA &26b9 ; digits_as_byte &26df c8 INY &26e0 d0 de BNE &26c0 ; convert_three_digits_into_byte_loop ; leave &26e2 60 RTS ; converted_number &26e3 32 35 35 0d ; "255" ; convert_number_to_string &26e7 a2 30 LDX #&30 ; "0" ; calculate_hundreds_loop &26e9 c9 64 CMP #&64 ; 100 &26eb 90 05 BCC &26f2 ; skip_hundreds &26ed e9 64 SBC #&64 ; 100 &26ef e8 INX &26f0 d0 f7 BNE &26e9 ; calculate_hundreds_loop ; skip_hundreds &26f2 8e e3 26 STX &26e3 ; converted_number &26f5 a2 30 LDX #&30 ; "0" ; calculate_tens_loop &26f7 c9 0a CMP #&0a ; 10 &26f9 90 05 BCC &2700 ; skip_tens &26fb e9 0a SBC #&0a ; 10 &26fd e8 INX &26fe d0 f7 BNE &26f7 ; calculate_tens_loop ; skip_tens &2700 8e e4 26 STX &26e4 ; converted_number + 1 &2703 18 CLC &2704 69 30 ADC #&30 ; "0" &2706 8d e5 26 STA &26e5 ; converted_number + 2 &2709 60 RTS ; unused_prnd_state # &270a - &2780 is similar to &1749 - &17c2 &270a 00 00 00 00 ; unused_generate_unique_bytes &270e 20 3b 27 JSR &273b ; unused_prnd &2711 85 71 STA &71 ; unique_bytes + 1 &2713 20 6d 27 JSR &276d ; unused_rotate_two_bits_into_first_byte_of_unique_bytes &2716 20 3b 27 JSR &273b ; unused_prnd # &1755 ad 96 02 LDA &0296 ; os_system_clock + 4 # &1758 8d 49 17 STA &1749 ; prnd_state &2719 85 72 STA &72 ; unique_bytes + 2 &271b 20 75 27 JSR &2775 ; unused_or_bits_into_first_byte_of_unique_bytes &271e 60 RTS ; unused_initialise_prnd_state # Identical to initialise_prnd_state except addresses &271f ad a0 02 LDA &02a0 ; os_countdown_timer + 4 &2722 4d 0a 27 EOR &270a ; unused_prnd_state &2725 8d 0a 27 STA &270a ; unused_prnd_state &2728 4d 0b 27 EOR &270b ; unused_prnd_state + 1 &272b 8d 0b 27 STA &270b ; unused_prnd_state + 1 &272e 4d 0c 27 EOR &270c ; unused_prnd_state + 2 &2731 8d 0c 27 STA &270c ; unused_prnd_state + 2 &2734 4d 0d 27 EOR &270d ; unused_prnd_state + 3 &2737 8d 0d 27 STA &270d ; unused_prnd_state + 3 &273a 60 RTS ; unused_prnd # Identical to prnd except addresses &273b 8a TXA &273c 48 PHA &273d 98 TYA &273e 48 PHA &273f a2 08 LDX #&08 ; unused_prnd_loop &2741 a0 00 LDY #&00 &2743 8c 0d 27 STY &270d ; unused_prnd_state + 3 &2746 a0 08 LDY #&08 &2748 ad 0c 27 LDA &270c ; unused_prnd_state + 2 &274b 29 e1 AND #&e1 ; unused_prnd_bit_loop &274d 0a ASL A &274e 90 03 BCC &2753 ; not_set &2750 ee 0d 27 INC &270d ; unused_prnd_state + 3 ; not_set &2753 88 DEY &2754 d0 f7 BNE &274d ; unused_prnd_bit_loop &2756 4e 0d 27 LSR &270d ; unused_prnd_state + 3 &2759 2e 0a 27 ROL &270a ; unused_prnd_state &275c 2e 0b 27 ROL &270b ; unused_prnd_state + 1 &275f 2e 0c 27 ROL &270c ; unused_prnd_state + 2 &2762 ca DEX &2763 d0 dc BNE &2741 ; unused_prnd_loop &2765 68 PLA &2766 a8 TAY &2767 68 PLA &2768 aa TAX &2769 ad 0a 27 LDA &270a ; unused_prnd_state &276c 60 RTS ; unused_rotate_two_bits_into_first_byte_of_unique_bytes # Identical to rotate_two_bits_into_first_byte_of_unique_bytes &276d 18 CLC &276e 2a ROL A &276f 66 70 ROR &70 ; unique_bytes &2771 2a ROL A &2772 66 70 ROR &70 ; unique_bytes &2774 60 RTS ; unused_or_bits_into_first_byte_of_unique_bytes # Identical to or_bits_into_first_byte_of_unique_bytes except addresses &2775 18 CLC &2776 6a ROR A &2777 26 7b ROL &7b ; unused_sink &2779 6a ROR A &277a 26 7b ROL &7b ; unused_sink &277c 05 70 ORA &70 ; unique_bytes &277e 85 70 STA &70 ; unique_bytes &2780 60 RTS ; unused &2781 29 f0 AND #&f0 &2783 18 CLC &2784 6a ROR A &2785 26 76 ROL &76 ; entered_result + 1 &2787 6a ROR A &2788 26 76 ROL &76 ; entered_result + 1 &278a 60 RTS ; unused &278b 29 0f AND #&0f &278d 18 CLC &278e 2a ROL A &278f 66 77 ROR &77 ; entered_result + 2 &2791 2a ROL A &2792 66 77 ROR &77 ; entered_result + 2 &2794 60 RTS ; transform_entered_result &2795 18 CLC &2796 66 75 ROR &75 ; entered_result &2798 66 76 ROR &76 ; entered_result + 1 &279a 66 77 ROR &77 ; entered_result + 2 &279c a5 76 LDA &76 ; entered_result + 1 &279e 18 CLC &279f 69 07 ADC #&07 &27a1 85 76 STA &76 ; entered_result + 1 &27a3 a5 77 LDA &77 ; entered_result + 2 &27a5 18 CLC &27a6 69 d0 ADC #&d0 &27a8 85 77 STA &77 ; entered_result + 2 &27aa 60 RTS ; get_number_of_times_run &27ab a2 04 LDX #&04 &27ad b5 70 LDA &70,X ; obfuscated_times_run - 4 &27af 49 ff EOR #&ff &27b1 49 50 EOR #&50 &27b3 a0 00 LDY #&00 &27b5 84 7c STY &7c ; result ; divide_by_three_loop &27b7 38 SEC &27b8 e9 03 SBC #&03 &27ba 30 05 BMI &27c1 ; leave_with_result &27bc e6 7c INC &7c ; result &27be 4c b7 27 JMP &27b7 ; divide_by_three_loop ; leave_with_result &27c1 18 CLC &27c2 a5 7c LDA &7c ; result # Unobfuscated value = ((obfuscated ^ &ff) ^ &50) / 3 &27c4 a8 TAY &27c5 aa TAX &27c6 60 RTS # Leave with result in A, X and Y ; copy_title_screen &27c7 a9 16 LDA #&16 # Change to MODE 7 &27c9 20 ee ff JSR &ffee ; OSWRCH &27cc a9 07 LDA #&07 &27ce 20 ee ff JSR &ffee ; OSWRCH &27d1 a9 27 LDA #&27 ; &27f6 = title_screen_data &27d3 85 7e STA &7e ; source_address_high &27d5 a9 f6 LDA #&f6 &27d7 85 7d STA &7d ; source_address_low &27d9 a9 7c LDA #&7c ; &7c00 = screen_memory &27db 85 83 STA &83 ; target_address_high &27dd a9 00 LDA #&00 &27df 85 82 STA &82 ; target_address_low &27e1 a2 00 LDX #&00 ; copy_title_screen_page_loop # Copy &27f6 - &2bf5 to &7c00 - &7fff &27e3 a0 00 LDY #&00 ; copy_title_screen_byte_loop &27e5 b1 7d LDA (&7d),Y ; source_address &27e7 91 82 STA (&82),Y ; target_address &27e9 c8 INY &27ea d0 f9 BNE &27e5 ; copy_title_screen_byte_loop &27ec e6 7e INC &7e ; source_address_high &27ee e6 83 INC &83 ; target_address_high &27f0 e8 INX &27f1 e0 04 CPX #&04 &27f3 d0 ee BNE &27e3 ; copy_title_screen_page_loop &27f5 60 RTS ; title_screen_data &27f6 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 ; " " &2806 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 ; "....................... " &2816 20 20 20 20 20 20 20 20 94 9a ab ff ff f7 a3 a3 ; ".. ..... .... " &2826 a3 a3 a3 a3 a3 a3 a3 a3 a3 a3 e3 ff ff bf a1 20 ; ".. .... ..... ...... ....... " &2836 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 ; ".. ..... .... .. .. .. .. " &2846 94 9a 20 a2 ef ff fd b0 20 20 20 20 20 20 20 20 ; ".. ......... .. .. .. .. " &2856 20 f8 ff ff a7 20 20 20 20 20 20 20 20 20 20 20 ; ".. ...... .. .. .. ... " &2866 20 20 20 20 20 20 20 20 94 9a 20 20 20 ab ff ff ; ".. ...... .. .. ...... " &2876 f4 20 20 20 20 20 20 e0 fe ff bf a1 20 f8 ae a3 ; ".. ......... .. .. ...... " &2886 a3 ad f4 20 20 20 ff ff a3 a3 a3 ad f4 20 20 20 ; ".. ..... .... .. .. .. .... " &2896 94 9a 20 20 20 20 a2 ef ff fd b0 20 20 20 f8 ff ; ".. .... ..... ...... .. .... " &28a6 ff a7 20 20 fa ff 20 20 20 20 ff f5 20 20 ff ff ; ".. ..... .... " &28b6 20 20 20 20 ff f5 20 20 94 9a 20 20 20 20 20 20 ; "....................... " &28c6 ab ff ff f4 e0 fe ff bf a1 20 20 20 ff ff 20 20 ; " " &28d6 20 20 ff ff 20 20 ff ff 20 20 20 20 ff bf 20 20 ; ". Xor must be revealed. " &28e6 94 9a 20 20 20 20 20 20 20 a2 ef ff ff ff a7 20 ; ". " &28f6 20 20 20 20 ff ff 20 20 20 20 ff ff 20 20 ff ff ; ". His many faces are scattered through" &2906 20 20 20 f0 bf a1 20 20 94 9a 20 20 20 20 20 20 ; ".15 levels. Acquiring all the faces on " &2916 20 e0 fe ff ff ff f4 20 20 20 20 20 ff ff 20 20 ; ".any level will enhance your knowledge " &2926 20 20 ff ff 20 20 ff ff ff f7 a3 a1 20 20 20 20 ; ".of Xor. " &2936 94 9a 20 20 20 20 20 20 f8 ff ff a7 a2 ef ff fd ; ". Beware Xor controls his world and " &2946 b0 20 20 20 ff ff 20 20 20 20 ff ff 20 20 ff ff ; ".doesn't give up his personality easily." &2956 ab ff fd b0 20 20 20 20 94 9a 20 20 20 20 e0 fe ; ". key..." &2966 ff bf a1 20 20 20 ab ff ff f4 20 20 eb ff 20 20 ; ". " &2976 20 20 ff bf 20 20 ff ff 20 a2 ef ff f4 20 20 20 ; ". (c) 1987 Astral Software Ltd. " &2986 94 9a 20 20 20 f8 ff ff a7 20 20 20 20 20 20 a2 ; " " &2996 ef ff fd b0 20 ab ec f0 f0 bc a7 20 20 20 ff ff &29a6 20 20 20 ab ff fd b0 20 94 9a 20 e0 fe ff bf a1 &29b6 20 20 20 20 20 20 20 20 20 ab ff ff f4 20 20 20 &29c6 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 &29d6 94 9a f8 ff ff f7 f0 f0 f0 f0 f0 f0 f0 f0 f0 f0 &29e6 f0 f0 f2 ff ff fd b0 20 20 20 20 20 20 20 20 20 &29f6 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 &2a06 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 &2a16 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 &2a26 83 20 20 20 20 20 20 20 20 20 58 6f 72 20 6d 75 &2a36 73 74 20 62 65 20 72 65 76 65 61 6c 65 64 2e 20 &2a46 20 20 20 20 20 20 20 20 83 20 20 20 20 20 20 20 &2a56 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 &2a66 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 &2a76 83 20 20 20 48 69 73 20 6d 61 6e 79 20 66 61 63 &2a86 65 73 20 61 72 65 20 73 63 61 74 74 65 72 65 64 &2a96 20 74 68 72 6f 75 67 68 83 31 35 20 6c 65 76 65 &2aa6 6c 73 2e 20 41 63 71 75 69 72 69 6e 67 20 61 6c &2ab6 6c 20 74 68 65 20 66 61 63 65 73 20 6f 6e 20 20 &2ac6 83 61 6e 79 20 6c 65 76 65 6c 20 77 69 6c 6c 20 &2ad6 65 6e 68 61 6e 63 65 20 79 6f 75 72 20 6b 6e 6f &2ae6 77 6c 65 64 67 65 20 20 83 6f 66 20 58 6f 72 2e &2af6 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 &2b06 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 &2b16 83 20 20 20 42 65 77 61 72 65 20 58 6f 72 20 63 &2b26 6f 6e 74 72 6f 6c 73 20 68 69 73 20 77 6f 72 6c &2b36 64 20 61 6e 64 20 20 20 83 64 6f 65 73 6e 27 74 &2b46 20 67 69 76 65 20 75 70 20 68 69 73 20 70 65 72 &2b56 73 6f 6e 61 6c 69 74 79 20 65 61 73 69 6c 79 2e &2b66 86 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 &2b76 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 &2b86 20 20 6b 65 79 2e 2e 2e 86 20 20 20 20 20 20 20 &2b96 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 &2ba6 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 &2bb6 86 20 20 20 20 28 63 29 20 31 39 38 37 20 41 73 &2bc6 74 72 61 6c 20 53 6f 66 74 77 61 72 65 20 4c 74 &2bd6 64 2e 20 20 20 20 20 20 20 20 20 20 20 20 20 20 &2be6 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 &2bf6 00 00 00 00 00 00 00 00 00 00 # Third stage; loads main binary # &0400 - &05ff is loaded from deleted data on track 4, sectors 2 and 3 ; third_stage_entry_point &0400 4c 3c 04 JMP &043c ; skip_decryption ; unused # Unused code &0403 a9 01 LDA #&01 # identical to first stage except key and start offset &0405 85 6b STA &6b ; key &0407 a9 07 LDA #&07 &0409 85 6c STA &6c ; key + 1 &040b a9 41 LDA #&41 &040d 85 6d STA &6d ; key + 2 &040f a9 00 LDA #&00 &0411 85 69 STA &69 ; decryption_address_low &0413 a9 04 LDA #&04 &0415 85 6a STA &6a ; decryption_address_high ; decryption_page_loop # Decrypt &043c - &07ff &0417 a0 3c LDY #&3c # skipping bytes &00 to &3b of each page ; decryption_byte_loop &0419 a5 6b LDA &6b ; key # Use a prnd as stream for decryption &041b 38 SEC &041c 69 38 ADC #&38 &041e 29 48 AND #&48 &0420 0a ASL A &0421 2a ROL A &0422 66 6b ROR &6b ; key &0424 46 6c LSR &6c ; key + 1 &0426 65 6d ADC &6d ; key + 2 &0428 85 6d STA &6d ; key + 2 &042a 51 69 EOR (&69),Y ; decryption_address &042c 91 69 STA (&69),Y ; decryption_address &042e c8 INY &042f d0 e8 BNE &0419 ; ; decryption_byte_loop &0431 e6 6a INC &6a ; decryption_address_high &0433 a5 6a LDA &6a ; decryption_address_high &0435 c9 08 CMP #&08 &0437 b0 03 BCS &043c ; skip_decryption &0439 4c 17 04 JMP &0417 ; decryption_page_loop ; skip_decryption &043c a9 16 LDA #&16 # Change to MODE 5 &043e 20 ee ff JSR &ffee ; OSWRCH &0441 a9 05 LDA #&05 &0443 20 ee ff JSR &ffee ; OSWRCH &0446 a2 00 LDX #&00 ; write_disable_cursor_loop &0448 bd 7c 05 LDA &057c,X ; disable_cursor_string &044b 20 ee ff JSR &ffee ; OSWRCH &044e e8 INX &044f e0 0a CPX #&0a &0451 d0 f5 BNE &0448 ; write_disable_cursor_loop &0453 a2 00 LDX #&00 ; write_change_palette_loop &0455 bd 92 05 LDA &0592,X ; change_palette_string &0458 20 ee ff JSR &ffee ; OSWRCH &045b e8 INX &045c e0 0c CPX #&0c &045e d0 f5 BNE &0455 ; write_change_palette_loop &0460 20 1a 05 JSR &051a ; flush_keyboard &0463 86 68 STX &68 ; double_track_numbers &0465 20 22 05 JSR &0522 ; seek_track_0 &0468 a9 7f LDA #&7f ; Floppy disk operation &046a a2 e7 LDX #&e7 ; &05e7 = read_ids_block &046c a0 05 LDY #&05 &046e 20 f1 ff JSR &fff1 ; OSWORD # Read IDs to &2000 (id_data) &0471 ad 00 20 LDA &2000 ; id_data &0474 c9 04 CMP #&04 # Did a request for track 4 return track 4? &0476 f0 04 BEQ &047c ; skip_doubling &0478 a9 01 LDA #&01 # If not, set to non-zero to double track numbers &047a 85 68 STA &68 ; double_track_numbers ; skip_doubling &047c 4c 7f 04 JMP &047f ; load_main_binary # Unnecessary code ; load_main_binary # Similar to deleted data loading code from first stage &047f 20 22 05 JSR &0522 ; seek_track_0 &0482 ad d3 05 LDA &05d3 ; read_sectors_block + 7 (track) # Use track 5 &0485 8d 7a 05 STA &057a ; track_to_use &0488 20 22 05 JSR &0522 ; seek_track_0 &048b ad d3 05 LDA &05d3 ; read_sectors_block + 7 (track) &048e 8d 7a 05 STA &057a ; track_to_use &0491 a0 00 LDY #&00 # Read main binary from deleted sectors ; copy_read_sectors_block_loop # Copy &05cc - &05db to &056a - &0579 &0493 b9 cc 05 LDA &05cc,Y ; read_sectors_block &0496 99 6a 05 STA &056a,Y ; read_block &0499 e8 INX &049a c8 INY &049b c0 10 CPY #&10 &049d d0 f4 BNE &0493 ; copy_read_sectors_block_loop &049f ad 72 05 LDA &0572 ; read_block + 8 (sector) # Does the data start partway through a track? &04a2 f0 1d BEQ &04c1 ; skip_reading_partial_first_track # Always branches &04a4 a9 00 LDA #&00 &04a6 8d 74 05 STA &0574 ; read_block + 10 (result) &04a9 a9 7f LDA #&7f ; Floppy disk operation &04ab a2 6a LDX #&6a ; &056a = read_block &04ad a0 05 LDY #&05 &04af 20 f1 ff JSR &fff1 ; OSWORD # Read sectors from partial first track &04b2 a9 0a LDA #&0a &04b4 38 SEC &04b5 ed 72 05 SBC &0572 ; read_block + 8 (sector) # Reduce size of subsequent read &04b8 18 CLC &04b9 69 20 ADC #&20 ; use 256 byte sectors &04bb 8d 73 05 STA &0573 ; read_block + 9 &04be ee 77 05 INC &0577 ; whole_tracks_to_read # Reread partial first track again ; skip_reading_partial_first_track ; read_whole_tracks_loop &04c1 20 2c 05 JSR &052c ; seek_track &04c4 20 43 05 JSR &0543 ; set_track_register &04c7 ad 7a 05 LDA &057a ; track_to_use &04ca 8d 71 05 STA &0571 ; read_block + 7 (track) &04cd a9 7f LDA #&7f ; Floppy disk operation &04cf a2 6a LDX #&6a ; &056a = read_block &04d1 a0 05 LDY #&05 &04d3 20 f1 ff JSR &fff1 ; OSWORD # Read whole track &04d6 ad 73 05 LDA &0573 ; read_block + 9 &04d9 29 0f AND #&0f &04db 18 CLC &04dc 6d 6c 05 ADC &056c ; read_block + 2 (address high) # Add size of track to address for next read &04df 8d 6c 05 STA &056c ; read_block + 2 (address high) &04e2 a9 2a LDA #&2a ; ten 256 byte sectors &04e4 8d 73 05 STA &0573 ; read_block + 9 (size and count) # Read full track of ten sectors &04e7 a9 00 LDA #&00 &04e9 8d 72 05 STA &0572 ; read_block + 8 (sector) # Start reading from start of track &04ec 20 53 05 JSR &0553 ; set_track_register_with_doubling &04ef ee 7a 05 INC &057a ; track_to_use # Use next track &04f2 ce 77 05 DEC &0577 ; whole_tracks_to_read &04f5 d0 ca BNE &04c1 ; read_whole_tracks_loop &04f7 ad 78 05 LDA &0578 ; remaining_sectors_to_read &04fa f0 1b BEQ &0517 ; skip_reading_partial_final_track &04fc 18 CLC &04fd 69 20 ADC #&20 ; use 256 byte sectors &04ff 8d 73 05 STA &0573 ; read_block + 9 (size and count) &0502 20 2c 05 JSR &052c ; seek_track &0505 20 43 05 JSR &0543 ; set_track_register &0508 ad 7a 05 LDA &057a ; track_to_use &050b 8d 71 05 STA &0571 ; read_block + 7 (track) &050e a9 7f LDA #&7f ; Floppy disk operation &0510 a2 6a LDX #&6a ; &056a = read_block &0512 a0 05 LDY #&05 &0514 20 f1 ff JSR &fff1 ; OSWORD # Read sectors from partial final track ; skip_reading_partial_final_track &0517 6c d7 05 JMP (&05d7) ; run_address # Run main binary ; flush_keyboard &051a a9 15 LDA #&15 ; Flush selected buffer &051c a2 00 LDX #&00 ; keyboard &051e 20 f4 ff JSR &fff4 ; OSBYTE &0521 60 RTS ; seek_track_0 &0522 a9 7f LDA #&7f ; Floppy disk operation &0524 a2 c1 LDX #&c1 ; &05c1 = seek_track_0_block &0526 a0 05 LDY #&05 &0528 20 f1 ff JSR &fff1 ; OSWORD # Seek to track 0 &052b 60 RTS ; seek_track &052c ad 7a 05 LDA &057a ; track_to_use &052f 8d e3 05 STA &05e3 ; seek_track_block + 7 (track number) &0532 a5 68 LDA &68 ; double_track_numbers &0534 f0 03 BEQ &0539 ; skip_doubling &0536 0e e3 05 ASL &05e3 ; seek_track_block + 7 (track number) ; skip_doubling &0539 a9 7f LDA #&7f ; Floppy disk operation &053b a2 dc LDX #&dc ; &05dc = seek_track_block &053d a0 05 LDY #&05 &053f 20 f1 ff JSR &fff1 ; OSWORD # Seek to specified track &0542 60 RTS ; set_track_register &0543 ad 7a 05 LDA &057a ; track_to_use &0546 8d fa 05 STA &05fa ; set_track_register_block + 8 (value) &0549 a9 7f LDA #&7f ; Floppy disk operation &054b a2 f2 LDX #&f2 ; &05f2 = set_track_register_block &054d a0 05 LDY #&05 &054f 20 f1 ff JSR &fff1 ; OSWORD # Set track register &0552 60 RTS ; set_track_register_with_doubling &0553 ad 7a 05 LDA &057a ; track_to_use &0556 8d fa 05 STA &05fa ; set_track_register_block + 8 (value) &0559 a5 68 LDA &68 ; double_track_numbers &055b f0 03 BEQ &0560 ; skip_doubling &055d 0e fa 05 ASL &05fa ; set_track_register_block + 8 (value) ; skip_doubling &0560 a9 7f LDA #&7f ; Floppy disk operation &0562 a2 f2 LDX #&f2 ; &05f2 = set_track_register_block &0564 a0 05 LDY #&05 &0566 20 f1 ff JSR &fff1 ; OSWORD # Set track register &0569 60 RTS ; read_block # &056a - &0579 is overwritten at &0496 &056a 00 ; drive &056b 00 00 00 00 ; address &056f 00 ; parameters &0570 00 ; command &0571 00 ; track &0572 00 ; sector &0573 00 ; size and count &0574 00 ; result ; unused_copy_of_run_address &0575 00 00 ; whole_tracks_to_read &0577 00 ; remaining_sectors_to_read &0578 00 ; unused &0579 00 ; track_to_use &057a 00 ; unused &057b 00 ; disable_cursor_string &057c 17 01 00 00 00 00 00 00 00 00 0d ; Turn off cursor ; unused_enable_cursor_string # Unused &0587 17 01 01 00 00 00 00 00 00 00 0d ; Turn on cursor ; change_palette_string &0592 13 02 00 00 00 00 ; Set logical colour 2 to black &0598 13 03 00 00 00 00 ; Set logical colour 3 to black &059e 0d ; unused # &059f - &05c0 is a copy of &1553 - &1575 &059f 5d &05a0 30 ff ff ff ff ff ff ff ff ff &05aa 00 00 00 00 00 &05af 0c ; CLS &05b0 1f 03 0e ; TAB(&03, &0e) &05b3 54 68 69 73 20 69 73 20 61 20 63 6f 70 79 0d ; "This is a copy" ; seek_track_0_block # Seek to track 0 &05c1 00 ; drive 0 &05c2 00 19 00 00 ; address (unused) &05c6 03 ; parameters (should be 1) &05c7 69 ; command : seek &05c8 00 ; track 0 &05c9 00 ; unused parameter &05ca 2a ; unused parameter &05cb 00 ; result ; read_sectors_block # Read main binary from tracks 5 to 16, track 17 sector 0 &05cc 00 ; drive 0 &05cd 00 11 00 00 ; address : &1100 # Reads &1100 - &7fff &05d1 03 ; parameters &05d2 57 ; command : read data and deleted data &05d3 05 ; track 5 &05d4 00 ; sector 0 &05d5 2a ; size and count : ten 256 byte sectors &05d6 00 ; result ; run_address &05d7 00 29 ; &2900 = main_binary_entry_point ; initial_whole_tracks_to_read &05d9 0c ; initial_remaining_sectors_to_read &05da 01 ; unused &05db 00 ; seek_track_block # Seek to specified track &05dc 00 ; drive 0 &05dd 00 20 00 00 ; address (unused) &05e1 03 ; parameters (should be 1) &05e2 69 ; command : seek &05e3 04 ; track (value is overwritten) &05e4 00 ; unused parameter &05e5 2a ; unused parameter &05e6 00 ; result ; read_ids_block # Read IDs &05e7 00 ; drive 0 &05e8 00 20 00 00 ; address &2000 = id_data &05ec 03 ; parameters &05ed 5b ; command : read IDs &05ee 04 ; track 4 &05ef 00 ; zero &05f0 0a ; count &05f1 00 ; result ; set_track_register_block # Set track register &05f2 00 ; drive 0 &05f3 ff ff 00 00 ; address (unused) &05f7 04 ; parameters (should be 2) &05f8 7a ; command : write special register &05f9 12 ; register : track register &05fa 02 ; value &05fb ff ; unused parameter ; unused_seek_special_sector_block # Unused &05fc 00 ; drive 0 &05fd 00 20 00 00 ; address (unused) &0601 03 ; parameters (should be 1) &0602 69 ; command : seek &0603 02 ; track 2 &0604 00 ; unused parameter &0605 21 ; unused parameter &0606 00 ; result ; unused_read_special_sector_block # Unused &0607 00 ; drive 0 &0608 00 20 00 00 ; address : &2000 &060c 03 ; parameters &060d 57 ; command : read data and deleted data &060e 02 ; track 2 &060f 00 ; sector 0 &0610 21 ; size and count : one 256 byte sector &0611 00 ; result ; unused_read_drive_status_block # Unused &0612 00 ; drive 0 &0613 00 20 00 00 ; address (unused) &0617 00 ; parameters &0618 6c ; command : read drive status &0619 00 ; result ; unused # &061a - &06ff is a copy of &051a - &05ff &061a a9 15 a2 00 20 f4 ff 60 a9 7f a2 c1 a0 05 20 f1 &062a ff 60 ad 7a 05 8d e3 05 a5 68 f0 03 0e e3 05 a9 &063a 7f a2 dc a0 05 20 f1 ff 60 ad 7a 05 8d fa 05 a9 &064a 7f a2 f2 a0 05 20 f1 ff 60 ad 7a 05 8d fa 05 a5 &065a 68 f0 03 0e fa 05 a9 7f a2 f2 a0 05 20 f1 ff 60 &066a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 &067a 00 00 17 01 00 00 00 00 00 00 00 00 0d 17 01 01 &068a 00 00 00 00 00 00 00 0d 13 02 00 00 00 00 13 03 &069a 00 00 00 00 0d 5d 30 ff ff ff ff ff ff ff ff ff &06aa 00 00 00 00 00 0c 1f 03 0e 54 68 69 73 20 69 73 &06ba 20 61 20 63 6f 70 79 00 00 19 00 00 03 69 00 00 &06ca 2a 00 00 00 11 00 00 03 57 05 00 2a 00 00 29 0c &06da 01 00 00 00 20 00 00 03 69 04 00 2a 00 00 00 20 &06ea 00 00 03 5b 04 00 0a 00 00 ff ff 00 00 04 7a 12 &06fa 02 ff 00 00 20 00 Game disassembly ================ ; GAME?? ; bbc1bbc2 bbc1bbc 00004b1a ; plot_viewpoint &1100 a2 00 LDX #&00 &1102 86 50 STX &50 ; group_offset &1104 a5 77 LDA &77 ; viewpoint_address_high &1106 85 54 STA &54 ; tile_address_high &1108 a5 76 LDA &76 ; viewpoint_address_low &110a 85 53 STA &53 ; tile_address_low &110c a2 00 LDX #&00 ; plot_viewpoint_row_loop &110e a0 00 LDY #&00 ; plot_viewpoint_column_loop &1110 b1 53 LDA (&53),Y ; tile_address &1112 29 0f AND #&0f &1114 85 55 STA &55 ; tile &1116 86 5c STX &5c ; tile_x &1118 84 5d STY &5d ; tile_y &111a a4 50 LDY &50 ; group_offset &111c b1 56 LDA (&56),Y ; screen_addresses &111e c8 INY &111f 85 58 STA &58 ; screen_address_low &1121 b1 56 LDA (&56),Y ; screen_addresses &1123 85 59 STA &59 ; screen_address_high &1125 a5 55 LDA &55 ; tile &1127 20 2d 11 JSR &112d ; plot_sprite &112a 4c 5e 11 JMP &115e ; continue_plotting_viewpoint ; plot_sprite &112d 0a ASL A &112e a8 TAY &112f b1 5a LDA (&5a),Y ; sprite_addresses &1131 8d 3f 11 STA &113f ; sprite_address_low &1134 c8 INY &1135 b1 5a LDA (&5a),Y ; sprite_addresses &1137 8d 40 11 STA &1140 ; sprite_address_high &113a a2 00 LDX #&00 ; plot_sprite_group_loop &113c a0 00 LDY #&00 ; plot_sprite_byte_loop &113e bd 00 80 LDA &8000,X # actually LDA sprite_address,X &1141 91 58 STA (&58),Y ; screen_address &1143 e8 INX &1144 c8 INY &1145 c0 18 CPY #&18 &1147 d0 f5 BNE &113e ; plot_sprite_byte_loop &1149 e0 48 CPX #&48 &114b f0 10 BEQ &115d ; leave &114d a5 58 LDA &58 ; screen_address_low &114f 18 CLC &1150 69 40 ADC #&40 &1152 85 58 STA &58 ; screen_address_low &1154 a5 59 LDA &59 ; screen_address_high &1156 69 01 ADC #&01 &1158 85 59 STA &59 ; screen_address_high &115a 4c 3c 11 JMP &113c ; plot_sprite_group_loop ; leave &115d 60 RTS ; continue_plotting_viewpoint &115e a6 5c LDX &5c ; tile_x &1160 a4 5d LDY &5d ; tile_y &1162 c8 INY &1163 e6 50 INC &50 ; group_offset &1165 e6 50 INC &50 ; group_offset &1167 c0 08 CPY #&08 &1169 d0 a5 BNE &1110 ; plot_viewpoint_column_loop &116b e8 INX &116c 18 CLC &116d a5 53 LDA &53 ; tile_address_low &116f 69 20 ADC #&20 &1171 85 53 STA &53 ; tile_address_low &1173 90 02 BCC &1177 ; skip_page &1175 e6 54 INC &54 ; tile_address_high ; skip_page &1177 e0 08 CPX #&08 &1179 d0 93 BNE &110e ; plot_viewpoint_row_loop &117b 60 RTS ; unused &117c 4c 87 11 JMP &1187 ; get_player_screen_address ; right_pixel_masks &117f ff 11 33 77 ; 3333 0003 0033 0333 ; left_pixel_masks &1183 00 88 cc ee ; 0000 3000 3300 3330 ; get_player_screen_address &1187 a5 73 LDA &73 ; player_y_offset &1189 0a ASL A &118a 0a ASL A &118b 0a ASL A &118c 18 CLC &118d 65 72 ADC &72 ; player_x_offset &118f 0a ASL A &1190 a8 TAY &1191 b1 56 LDA (&56),Y ; screen_addresses &1193 85 6a STA &6a ; player_screen_address_low &1195 c8 INY &1196 b1 56 LDA (&56),Y ; screen_addresses &1198 85 6b STA &6b ; player_screen_address_high &119a 60 RTS ; plot_player &119b a5 6a LDA &6a ; player_screen_address_low &119d 85 5e STA &5e ; row_screen_address_low &119f a5 6b LDA &6b ; player_screen_address_high &11a1 85 5f STA &5f ; row_screen_address_high &11a3 a9 6d LDA #&6d ; &126d = sprite_current_player &11a5 85 61 STA &61 ; player_sprite_address_low &11a7 a9 12 LDA #&12 &11a9 85 62 STA &62 ; player_sprite_address_high &11ab a0 18 LDY #&18 ; plot_player_loop &11ad 98 TYA &11ae 85 6c STA &6c ; count &11b0 20 ba 11 JSR &11ba ; plot_row_of_player &11b3 a5 6c LDA &6c ; count &11b5 a8 TAY &11b6 88 DEY &11b7 d0 f4 BNE &11ad ; plot_player_loop &11b9 60 RTS ; plot_row_of_player &11ba a0 00 LDY #&00 # Use empty pixels to right of sprite &11bc 8c 6d 12 STY &126d ; sprite_row + 3 # (this overlaps first byte of sprite_current_player) ; copy_row_loop # Copy row from sprite into left three bytes &11bf b1 61 LDA (&61),Y ; player_sprite_address &11c1 99 6a 12 STA &126a,Y ; sprite_row &11c4 c8 INY &11c5 c0 03 CPY #&03 &11c7 d0 f6 BNE &11bf ; copy_row_loop &11c9 a4 60 LDY &60 ; shift_steps &11cb c0 00 CPY #&00 &11cd f0 3a BEQ &1209 ; skip_shifting # Does the sprite need to be shifted horizontally? &11cf a9 00 LDA #&00 &11d1 85 66 STA &66 ; left_pixels # Use empty pixels to left of sprite &11d3 b9 7f 11 LDA &117f,Y ; right_pixel_masks &11d6 85 65 STA &65 ; right_mask &11d8 98 TYA &11d9 49 03 EOR #&03 &11db a8 TAY &11dc c8 INY &11dd a2 00 LDX #&00 &11df 84 64 STY &64 ; left_shift_steps ; shift_row_byte_loop # For each byte in the row of the sprite, &11e1 a5 65 LDA &65 ; right_mask &11e3 3d 6a 12 AND &126a,X ; sprite_row # Get pixels from the right of the byte &11e6 85 63 STA &63 ; right_pixels &11e8 a5 65 LDA &65 ; right_mask &11ea 49 ff EOR #&ff &11ec 3d 6a 12 AND &126a,X ; sprite_row # Get pixels from the left of the byte &11ef a4 60 LDY &60 ; shift_steps ; calculate_new_right_pixels_loop &11f1 4a LSR A # Shift right one pixel &11f2 88 DEY &11f3 d0 fc BNE &11f1 ; calculate_new_right_pixels_loop &11f5 05 66 ORA &66 ; left_pixels # Add the pixels shifted from the previous byte &11f7 9d 6a 12 STA &126a,X ; sprite_row &11fa a5 63 LDA &63 ; right_pixels &11fc a4 64 LDY &64 ; left_shift_steps ; calculate_new_left_pixels_loop &11fe 0a ASL A # Shift left one pixel &11ff 88 DEY &1200 d0 fc BNE &11fe ; calculate_new_left_pixels_loop &1202 85 66 STA &66 ; left_pixels # Store for use in next byte &1204 e8 INX &1205 e0 04 CPX #&04 &1207 d0 d8 BNE &11e1 ; shift_row_byte_loop ; skip_shifting &1209 a6 60 LDX &60 ; shift_steps &120b a0 00 LDY #&00 &120d bd 83 11 LDA &1183,X ; left_pixel_masks &1210 31 5e AND (&5e),Y ; row_screen_address # Keep background to left of sprite &1212 0d 6a 12 ORA &126a ; sprite_row &1215 8d 6a 12 STA &126a ; sprite_row &1218 a0 18 LDY #&18 &121a bd 7f 11 LDA &117f,X ; right_pixel_masks &121d 31 5e AND (&5e),Y ; row_screen_address # Keep background to right of sprite &121f 0d 6d 12 ORA &126d ; sprite_row + 3 &1222 8d 6d 12 STA &126d ; sprite_row + 3 &1225 a2 00 LDX #&00 &1227 a0 00 LDY #&00 ; plot_row_loop &1229 bd 6a 12 LDA &126a,X ; sprite_row &122c 91 5e STA (&5e),Y ; row_screen_address &122e a5 5e LDA &5e ; row_screen_address_low &1230 18 CLC &1231 69 08 ADC #&08 # Move right one byte &1233 85 5e STA &5e ; row_screen_address_low &1235 90 02 BCC &1239 ; skip_page &1237 e6 5f INC &5f ; row_screen_address_high ; skip_page &1239 e8 INX &123a e0 04 CPX #&04 &123c d0 eb BNE &1229 ; plot_row_loop &123e a5 5e LDA &5e ; row_screen_address_low &1240 38 SEC &1241 e9 1f SBC #&1f # Move left four bytes, down one row &1243 85 5e STA &5e ; row_screen_address_low &1245 a5 5f LDA &5f ; row_screen_address_high &1247 e9 00 SBC #&00 &1249 85 5f STA &5f ; row_screen_address_high &124b a5 5e LDA &5e ; row_screen_address_low &124d 29 07 AND #&07 &124f d0 0d BNE &125e ; skip_group &1251 a5 5e LDA &5e ; row_screen_address_low &1253 18 CLC &1254 69 38 ADC #&38 # Move to next group &1256 85 5e STA &5e ; row_screen_address_low &1258 a5 5f LDA &5f ; row_screen_address_high &125a 69 01 ADC #&01 &125c 85 5f STA &5f ; row_screen_address_high ; skip_group &125e a5 61 LDA &61 ; player_sprite_address_low &1260 18 CLC &1261 69 03 ADC #&03 # Move to next row of sprite &1263 85 61 STA &61 ; player_sprite_address_low &1265 90 02 BCC &1269 ; skip_page &1267 e6 62 INC &62 ; player_sprite_address_high ; skip_page &1269 60 RTS ; sprite_row &126a 00 00 00 ; sprite_current_player # &126d - &12b3 is a copy of &5521 - &5567 (sprite_magus + 1) &126d 00 00 70 f0 e2 70 f0 e2 70 f4 e2 70 fe e2 71 ff # First byte is also used for sprite_row &127d e2 73 fb ea 77 f1 ee 76 f0 ee 74 f0 e6 70 f0 e2 &128d 70 f4 e2 70 fe e2 71 ff e2 73 fb ea 77 f1 ee 76 &129d f0 ee 74 f0 e6 30 f0 c4 30 f0 c4 10 f0 88 00 f1 &12ad 00 00 62 00 00 00 00 00 ; plot_moving_player &12b5 85 69 STA &69 ; direction &12b7 20 87 11 JSR &1187 ; get_player_screen_address &12ba a9 00 LDA #&00 &12bc 85 60 STA &60 ; shift_steps &12be a5 69 LDA &69 ; direction &12c0 d0 04 BNE &12c6 ; plot_player_moving_in_direction &12c2 20 9b 11 JSR &119b ; plot_player &12c5 60 RTS ; plot_player_moving_in_direction &12c6 c9 01 CMP #&01 ; DIRECTION_DOWN &12c8 d0 03 BNE &12cd ; not_moving_down &12ca 4c 39 13 JMP &1339 ; plot_player_moving_down ; not_moving_down &12cd c9 02 CMP #&02 ; DIRECTION_UP &12cf d0 03 BNE &12d4 ; not_moving_up &12d1 4c 5c 13 JMP &135c ; plot_player_moving_up ; not_moving_up &12d4 c9 04 CMP #&04 ; DIRECTION_RIGHT &12d6 d0 03 BNE &12db ; not_moving_right &12d8 4c e3 12 JMP &12e3 ; plot_player_moving_right ; not_moving_right &12db c9 08 CMP #&08 ; DIRECTION_LEFT &12dd d0 03 BNE &12e2 ; not_moving_left &12df 4c 0d 13 JMP &130d ; plot_player_moving_left ; not_moving_left &12e2 60 RTS ; plot_player_moving_right &12e3 a9 03 LDA #&03 &12e5 85 69 STA &69 ; steps ; plot_player_moving_right_loop &12e7 e6 60 INC &60 ; shift_steps &12e9 20 9b 11 JSR &119b ; plot_player &12ec e6 60 INC &60 ; shift_steps &12ee 20 9b 11 JSR &119b ; plot_player &12f1 e6 60 INC &60 ; shift_steps &12f3 20 9b 11 JSR &119b ; plot_player &12f6 a5 6a LDA &6a ; player_screen_address_low &12f8 18 CLC &12f9 69 08 ADC #&08 &12fb 85 6a STA &6a ; player_screen_address_low &12fd 90 02 BCC &1301 ; skip_page &12ff e6 6b INC &6b ; player_screen_address_high ; skip_page &1301 a9 00 LDA #&00 &1303 85 60 STA &60 ; shift_steps &1305 20 9b 11 JSR &119b ; plot_player &1308 c6 69 DEC &69 ; steps &130a d0 db BNE &12e7 ; plot_player_moving_right_loop &130c 60 RTS ; plot_player_moving_left &130d a9 03 LDA #&03 &130f 85 69 STA &69 ; steps ; plot_player_moving_left_loop &1311 a5 6a LDA &6a ; player_screen_address_low &1313 38 SEC &1314 e9 08 SBC #&08 &1316 85 6a STA &6a ; player_screen_address_low &1318 c9 f8 CMP #&f8 &131a d0 02 BNE &131e ; skip_page &131c c6 6b DEC &6b ; player_screen_address_high ; skip_page &131e a9 03 LDA #&03 &1320 85 60 STA &60 ; shift_steps &1322 20 9b 11 JSR &119b ; plot_player &1325 c6 60 DEC &60 ; shift_steps &1327 20 9b 11 JSR &119b ; plot_player &132a c6 60 DEC &60 ; shift_steps &132c 20 9b 11 JSR &119b ; plot_player &132f c6 60 DEC &60 ; shift_steps &1331 20 9b 11 JSR &119b ; plot_player &1334 c6 69 DEC &69 ; steps &1336 d0 d9 BNE &1311 ; plot_player_moving_left_loop &1338 60 RTS ; plot_player_moving_down &1339 a9 18 LDA #&18 &133b 85 69 STA &69 ; steps ; plot_player_moving_down_loop &133d e6 6a INC &6a ; player_screen_address_low &133f a5 6a LDA &6a ; player_screen_address_low &1341 29 07 AND #&07 &1343 d0 0f BNE &1354 ; skip_group &1345 c6 6a DEC &6a ; player_screen_address_low &1347 18 CLC &1348 a5 6a LDA &6a ; player_screen_address_low &134a 69 39 ADC #&39 &134c 85 6a STA &6a ; player_screen_address_low &134e a5 6b LDA &6b ; player_screen_address_high &1350 69 01 ADC #&01 &1352 85 6b STA &6b ; player_screen_address_high ; skip_group &1354 20 9b 11 JSR &119b ; plot_player &1357 c6 69 DEC &69 ; steps &1359 d0 e2 BNE &133d ; plot_player_moving_down_loop &135b 60 RTS ; plot_player_moving_up &135c a9 18 LDA #&18 &135e 85 69 STA &69 ; steps ; plot_player_moving_up_loop &1360 c6 6a DEC &6a ; player_screen_address_low &1362 a5 6a LDA &6a ; player_screen_address_low &1364 29 07 AND #&07 &1366 c9 07 CMP #&07 &1368 d0 0f BNE &1379 ; skip_group &136a e6 6a INC &6a ; player_screen_address_low &136c 38 SEC &136d a5 6a LDA &6a ; player_screen_address_low &136f e9 39 SBC #&39 &1371 85 6a STA &6a ; player_screen_address_low &1373 a5 6b LDA &6b ; player_screen_address_high &1375 e9 01 SBC #&01 &1377 85 6b STA &6b ; player_screen_address_high ; skip_group &1379 20 9b 11 JSR &119b ; plot_player &137c c6 69 DEC &69 ; steps &137e d0 e0 BNE &1360 ; plot_player_moving_up_loop &1380 60 RTS ; unused # Unused code fragment &1381 d0 cc BNE &134f &1383 c6 61 DEC &61 &1385 d0 c4 BNE &134b &1387 e6 75 INC &75 &1389 c6 60 DEC &60 &138b d0 87 BNE &1314 &138d 60 RTS ; unused &138e 00 00 ; main_game_loop &1390 ad 54 1d LDA &1d54 ; mask_was_collected # Non-zero if mask was collected &1393 f0 03 BEQ &1398 ; skip_updating_map &1395 20 c3 18 JSR &18c3 ; update_map ; skip_updating_map &1398 a0 00 LDY #&00 # Check if first explosion or mover destroyed a player &139a 4c af 1e JMP &1eaf ; check_if_explosion_or_mover_destroyed_player ; check_other_explosion_side &139d a0 01 LDY #&01 # Check if second explosion destroyed a player &139f 4c af 1e JMP &1eaf ; check_if_explosion_or_mover_destroyed_player ; consider_updating_movers &13a2 a5 94 LDA &94 ; mover_count &13a4 f0 03 BEQ &13a9 ; skip_updating_movers &13a6 4c 61 19 JMP &1961 ; update_movers ; skip_updating_movers &13a9 a9 00 LDA #&00 &13ab 85 af STA &af ; mover_is_doll # Set to zero to indicate mover is not doll &13ad 8d 54 1d STA &1d54 ; mask_was_collected # Set to zero to indicate no mask collected &13b0 ea NOP &13b1 ea NOP ; check_for_keys &13b2 20 00 28 JSR &2800 ; check_for_volume_change # Returns A = keycode &13b5 ea NOP &13b6 ea NOP &13b7 ea NOP &13b8 ea NOP &13b9 ea NOP &13ba a6 b1 LDX &b1 ; replaying # Non-zero if replaying level &13bc f0 0e BEQ &13cc ; not_replaying &13be c9 a2 CMP #&a2 ; E # End replay when E is pressed &13c0 f0 0e BEQ &13d0 ; consider_move &13c2 c9 d4 CMP #&d4 ; H # Pause replay while H is pressed &13c4 f0 ec BEQ &13b2 ; check_for_keys &13c6 20 8b 22 JSR &228b ; get_move_from_replay &13c9 4c d0 13 JMP &13d0 ; consider_move ; not_replaying &13cc c9 00 CMP #&00 &13ce f0 c0 BEQ &1390 ; main_game_loop ; consider_move &13d0 c9 e1 CMP #&e1 ; Z &13d2 f0 18 BEQ &13ec ; left_pressed &13d4 c9 c2 CMP #&c2 ; X &13d6 f0 30 BEQ &1408 ; right_pressed &13d8 c9 c8 CMP #&c8 ; * &13da f0 25 BEQ &1401 ; up_pressed &13dc c9 e8 CMP #&e8 ; / &13de f0 13 BEQ &13f3 ; down_pressed &13e0 c9 c9 CMP #&c9 ; RETURN &13e2 f0 16 BEQ &13fa ; swap_pressed &13e4 c9 a2 CMP #&a2 ; E &13e6 f0 27 BEQ &140f ; end_pressed &13e8 4c 90 13 JMP &1390 ; main_game_loop ; unused &13eb 60 RTS ; left_pressed &13ec a2 03 LDX #&03 ; MOVE_LEFT &13ee 86 b6 STX &b6 ; move_direction &13f0 4c 1e 14 JMP &141e ; consider_moving_left ; down_pressed &13f3 a2 01 LDX #&01 ; MOVE_DOWN &13f5 86 b6 STX &b6 ; move_direction &13f7 4c 69 16 JMP &1669 ; consider_moving_down ; swap_pressed &13fa a2 04 LDX #&04 ; MOVE_SWAP &13fc 86 b6 STX &b6 ; move_direction &13fe 4c 5f 17 JMP &175f ; consider_swap ; up_pressed &1401 a2 00 LDX #&00 ; MOVE_UP &1403 86 b6 STX &b6 ; move_direction &1405 4c a5 15 JMP &15a5 ; consider_moving_up ; right_pressed &1408 a2 02 LDX #&02 ; MOVE_RIGHT &140a 86 b6 STX &b6 ; move_direction &140c 4c e8 14 JMP &14e8 ; consider_moving_right ; end_pressed &140f a6 b1 LDX &b1 ; replaying # Non-zero if replaying level &1411 d0 05 BNE &1418 ; skip_storing_end &1413 a2 0f LDX #&0f ; MOVE_END &1415 20 4e 22 JSR &224e ; store_move ; skip_storing_end &1418 a9 00 LDA #&00 # Leave with zero to indicate level not completed &141a 60 RTS ; to_main_game_loop &141b 4c 90 13 JMP &1390 ; main_game_loop ; consider_moving_left &141e a0 1f LDY #&1f # Consider tile to left of player &1420 b1 70 LDA (&70),Y ; player_offset_tile_address &1422 20 f6 18 JSR &18f6 ; check_if_player_can_move # Returns X = &01 if player cannot move &1425 e0 01 CPX #&01 &1427 f0 f2 BEQ &141b ; to_main_game_loop &1429 e0 ff CPX #&ff # X = &ff if level completed &142b d0 03 BNE &1430 ; consider_tile_to_left &142d 4c 3e 1d JMP &1d3e ; level_completed ; consider_tile_to_left &1430 c9 06 CMP #&06 ; PIECE_WAVES &1432 f0 e7 BEQ &141b ; to_main_game_loop # Player can't move left into waves &1434 c9 08 CMP #&08 ; PIECE_CHICKEN &1436 f0 e3 BEQ &141b ; to_main_game_loop # Player can't move left into chicken &1438 c9 0a CMP #&0a ; PIECE_V_BOMB &143a f0 df BEQ &141b ; to_main_game_loop # Player can't move left into v-bomb &143c c9 07 CMP #&07 ; PIECE_FISH &143e d0 06 BNE &1446 ; not_fish &1440 20 55 1d JSR &1d55 ; check_if_player_can_push_left # Returns X zero if player can push &1443 4c 4d 14 JMP &144d ; consider_pushing_horizontal_mover_left ; not_fish &1446 c9 09 CMP #&09 ; PIECE_H_BOMB &1448 d0 0a BNE &1454 ; not_h_bomb &144a 20 55 1d JSR &1d55 ; check_if_player_can_push_left # Returns X zero if player can push ; consider_pushing_horizontal_mover_left &144d e0 01 CPX #&01 &144f f0 ca BEQ &141b ; to_main_game_loop &1451 4c aa 14 JMP &14aa ; move_left # Player can push fish or H-bomb left ; not_h_bomb &1454 c9 0e CMP #&0e ; PIECE_TELEPORT &1456 d0 35 BNE &148d ; not_teleport &1458 20 4e 20 JSR &204e ; check_teleports # Returns X zero if both teleports exist &145b e0 01 CPX #&01 &145d f0 bc BEQ &141b ; to_main_game_loop &145f a9 1f LDA #&1f &1461 85 ac STA &ac ; player_movement_offset # Indicate that player is moving left into teleport &1463 a9 08 LDA #&08 ; DIRECTION_LEFT &1465 20 b5 12 JSR &12b5 ; plot_moving_player &1468 20 39 1f JSR &1f39 ; consider_teleporting_player # Returns X zero if player exited destination teleport &146b e0 00 CPX #&00 &146d d0 ac BNE &141b ; to_main_game_loop &146f 20 05 21 JSR &2105 ; increment_move_counter &1472 a0 20 LDY #&20 &1474 a9 00 LDA #&00 ; PIECE_SPACE &1476 91 60 STA (&60),Y ; previous_player_offset_tile_address # Replace player's old position with space &1478 20 2c 20 JSR &202c ; use_player_offset_for_entering_teleport # Use the player's old position for considering movers &147b 20 bf 1c JSR &1cbf ; consider_space_vacated_by_player_moving_left &147e 20 3d 20 JSR &203d ; use_player_offset_for_leaving_teleport &1481 a5 90 LDA &90 ; current_player &1483 a0 20 LDY #&20 &1485 91 70 STA (&70),Y ; player_offset_tile_address # Replace player's new position with player &1487 20 00 11 JSR &1100 ; plot_viewpoint &148a 4c 90 13 JMP &1390 ; main_game_loop ; not_teleport &148d c9 0f CMP #&0f ; PIECE_SWITCH &148f d0 06 BNE &1497 ; not_switch &1491 20 73 20 JSR &2073 ; toggle_switch &1494 4c aa 14 JMP &14aa ; move_left # Player can move left into switch ; not_switch &1497 c9 0d CMP #&0d ; PIECE_DOLL &1499 d0 0f BNE &14aa ; after_moving_left &149b a9 1f LDA #&1f &149d 85 b0 STA &b0 ; doll_direction_offset # Indicate that doll is moving left &149f a9 01 LDA #&01 &14a1 85 af STA &af ; mover_is_doll # Set to non-zero to indicate mover is doll &14a3 20 55 1d JSR &1d55 ; check_if_player_can_push_left # Returns X zero if player can push &14a6 e0 01 CPX #&01 &14a8 f0 3b BEQ &14e5 ; to_main_game_loop ; move_left &14aa 20 bf 1c JSR &1cbf ; consider_space_vacated_by_player_moving_left &14ad 20 05 21 JSR &2105 ; increment_move_counter &14b0 a9 00 LDA #&00 ; PIECE_SPACE &14b2 a0 20 LDY #&20 &14b4 91 70 STA (&70),Y ; player_offset_tile_address # Replace player's old position with space &14b6 a5 70 LDA &70 ; player_offset_tile_address_low &14b8 38 SEC &14b9 e9 01 SBC #&01 &14bb 85 70 STA &70 ; player_offset_tile_address_low &14bd a5 71 LDA &71 ; player_offset_tile_address_high &14bf e9 00 SBC #&00 &14c1 85 71 STA &71 ; player_offset_tile_address_high &14c3 a5 90 LDA &90 ; current_player &14c5 91 70 STA (&70),Y ; player_offset_tile_address # Replace player's new position with player &14c7 ad f5 18 LDA &18f5 ; map_was_collected # Non-zero if map was collected &14ca f0 03 BEQ &14cf ; skip_removing_map &14cc 20 8a 18 JSR &188a ; collect_map ; skip_removing_map &14cf a5 72 LDA &72 ; player_x_offset &14d1 c9 01 CMP #&01 # If the player is at the left of the viewpoint, &14d3 f0 0a BEQ &14df ; to_scroll_viewpoint_left # scroll the viewpoint left &14d5 a9 08 LDA #&08 ; DIRECTION_LEFT &14d7 20 b5 12 JSR &12b5 ; plot_moving_player &14da c6 72 DEC &72 ; player_x_offset ; to_main_game_loop &14dc 4c 90 13 JMP &1390 ; main_game_loop ; to_scroll_viewpoint_left &14df 4c 2c 17 JMP &172c ; scroll_viewpoint_left ; to_scroll_viewpoint_right &14e2 4c 33 17 JMP &1733 ; scroll_viewpoint_right ; to_main_game_loop &14e5 4c 90 13 JMP &1390 ; main_game_loop ; consider_moving_right &14e8 a0 21 LDY #&21 &14ea b1 70 LDA (&70),Y ; player_offset_tile_address # Consider tile to right of player &14ec 20 f6 18 JSR &18f6 ; check_if_player_can_move # Returns X = &01 if player cannot move &14ef e0 01 CPX #&01 &14f1 f0 e9 BEQ &14dc ; to_main_game_loop &14f3 e0 ff CPX #&ff # X = &ff if level completed &14f5 d0 03 BNE &14fa ; consider_tile_to_right &14f7 4c 3e 1d JMP &1d3e ; level_completed ; consider_tile_to_right &14fa c9 06 CMP #&06 ; PIECE_WAVES &14fc f0 e7 BEQ &14e5 ; to_main_game_loop # Player can't move right into waves &14fe c9 08 CMP #&08 ; PIECE_CHICKEN &1500 f0 e3 BEQ &14e5 ; to_main_game_loop # Player can't move right into chicken &1502 c9 0a CMP #&0a ; PIECE_V_BOMB &1504 f0 df BEQ &14e5 ; to_main_game_loop # Player can't move right into V-bomb &1506 c9 07 CMP #&07 ; PIECE_FISH &1508 d0 06 BNE &1510 ; not_fish &150a 20 a0 1d JSR &1da0 ; check_if_player_can_push_right # Returns X zero if player can push &150d 4c 17 15 JMP &1517 ; consider_pushing_horizontal_mover_right ; not_fish &1510 c9 09 CMP #&09 ; PIECE_H_BOMB &1512 d0 0a BNE &151e ; not_h_bomb &1514 20 a0 1d JSR &1da0 ; check_if_player_can_push_right # Returns X zero if player can push ; consider_pushing_horizontal_mover_right &1517 e0 01 CPX #&01 &1519 f0 ca BEQ &14e5 ; to_main_game_loop &151b 4c 74 15 JMP &1574 ; move_right # Player can push fish or H-bomb right ; not_h_bomb &151e c9 0e CMP #&0e ; PIECE_TELEPORT &1520 d0 35 BNE &1557 ; not_teleport &1522 20 4e 20 JSR &204e ; check_teleports # Returns X zero if both teleports exist &1525 e0 01 CPX #&01 &1527 f0 bc BEQ &14e5 ; to_main_game_loop &1529 a9 21 LDA #&21 &152b 85 ac STA &ac ; player_movement_offset # Indicate that player is moving right into teleport &152d a9 04 LDA #&04 ; DIRECTION_RIGHT &152f 20 b5 12 JSR &12b5 ; plot_moving_player &1532 20 39 1f JSR &1f39 ; consider_teleporting_player # Returns X zero if player exited destination teleport &1535 e0 00 CPX #&00 &1537 d0 ac BNE &14e5 ; to_main_game_loop &1539 20 05 21 JSR &2105 ; increment_move_counter &153c a0 20 LDY #&20 &153e a9 00 LDA #&00 &1540 91 60 STA (&60),Y ; previous_player_offset_tile_address # Replace player's old position with space &1542 20 2c 20 JSR &202c ; use_player_offset_for_entering_teleport # Use the player's old position for considering movers &1545 20 ff 1c JSR &1cff ; consider_space_vacated_by_player_moving_right &1548 20 3d 20 JSR &203d ; use_player_offset_for_leaving_teleport &154b a5 90 LDA &90 ; current_player &154d a0 20 LDY #&20 &154f 91 70 STA (&70),Y ; player_offset_tile_address # Replace player's new position with player &1551 20 00 11 JSR &1100 ; plot_viewpoint &1554 4c 90 13 JMP &1390 ; main_game_loop ; not_teleport &1557 c9 0f CMP #&0f ; PIECE_SWITCH &1559 d0 06 BNE &1561 ; not_switch &155b 20 73 20 JSR &2073 ; toggle_switch &155e 4c 74 15 JMP &1574 ; move_right # Player can move right into switch ; not_switch &1561 c9 0d CMP #&0d ; PIECE_DOLL &1563 d0 0f BNE &1574 ; move_right &1565 a9 21 LDA #&21 &1567 85 b0 STA &b0 ; doll_direction_offset # Indicate that doll is moving right &1569 a9 01 LDA #&01 &156b 85 af STA &af ; mover_is_doll # Set to non-zero to indicate mover is doll &156d 20 a0 1d JSR &1da0 ; check_if_player_can_push_right # Returns X zero if player can push &1570 e0 01 CPX #&01 &1572 f0 2b BEQ &159f ; to_main_game_loop ; move_right &1574 20 ff 1c JSR &1cff ; consider_space_vacated_by_player_moving_right &1577 20 05 21 JSR &2105 ; increment_move_counter &157a a9 00 LDA #&00 ; PIECE_SPACE &157c a0 20 LDY #&20 &157e 91 70 STA (&70),Y ; player_offset_tile_address # Replace player's old position with space &1580 e6 70 INC &70 ; player_offset_tile_address_low &1582 d0 02 BNE &1586 ; skip_page &1584 e6 71 INC &71 ; player_offset_tile_address_high ; skip_page &1586 a5 90 LDA &90 ; current_player &1588 91 70 STA (&70),Y ; player_offset_tile_address # Replace player's new position with player &158a ad f5 18 LDA &18f5 ; map_was_collected # Non-zero if map was collected &158d f0 03 BEQ &1592 ; skip_removing_map &158f 20 8a 18 JSR &188a ; collect_map ; skip_removing_map &1592 a5 72 LDA &72 ; player_x_offset &1594 c9 06 CMP #&06 # If the player is at the right of the viewpoint, &1596 f0 0a BEQ &15a2 ; to_to_scroll_viewpoint_right # scroll the viewpoint right &1598 a9 04 LDA #&04 ; DIRECTION_RIGHT &159a 20 b5 12 JSR &12b5 ; plot_moving_player &159d e6 72 INC &72 ; player_x_offset ; to_main_game_loop &159f 4c 90 13 JMP &1390 ; main_game_loop ; to_to_scroll_viewpoint_right &15a2 4c e2 14 JMP &14e2 ; to_scroll_viewpoint_right ; consider_moving_up &15a5 a0 00 LDY #&00 &15a7 b1 70 LDA (&70),Y ; player_offset_tile_address # Consider tile above player &15a9 20 f6 18 JSR &18f6 ; check_if_player_can_move # Returns X = &01 if player cannot move &15ac e0 01 CPX #&01 &15ae f0 ef BEQ &159f ; to_main_game_loop &15b0 e0 ff CPX #&ff # X = &ff if level completed &15b2 d0 03 BNE &15b7 ; consider_tile_above &15b4 4c 3e 1d JMP &1d3e ; level_completed ; consider_tile_above &15b7 c9 05 CMP #&05 ; PIECE_DOTS &15b9 f0 e4 BEQ &159f ; to_main_game_loop # Player can't move up into dots &15bb c9 07 CMP #&07 ; PIECE_FISH &15bd f0 e0 BEQ &159f ; to_main_game_loop # Player can't move up into fish &15bf c9 09 CMP #&09 ; PIECE_H_BOMB &15c1 f0 dc BEQ &159f ; to_main_game_loop # Player can't move up into H-bomb &15c3 c9 08 CMP #&08 ; PIECE_CHICKEN &15c5 d0 06 BNE &15cd ; not_chicken &15c7 20 eb 1d JSR &1deb ; check_if_player_can_push_up # Returns X zero if player can push &15ca 4c d4 15 JMP &15d4 ; consider_pushing_vertical_mover_up ; not_chicken &15cd c9 0a CMP #&0a ; PIECE_V_BOMB &15cf d0 0a BNE &15db ; not_v_bomb &15d1 20 eb 1d JSR &1deb ; check_if_player_can_push_up # Returns X zero if player can push ; consider_pushing_vertical_mover_up &15d4 e0 01 CPX #&01 &15d6 f0 c7 BEQ &159f ; to_main_game_loop &15d8 4c 31 16 JMP &1631 ; move_up # Player can push chicken or V-bomb up ; not_v_bomb &15db c9 0e CMP #&0e ; PIECE_TELEPORT &15dd d0 35 BNE &1614 ; not_teleport &15df 20 4e 20 JSR &204e ; check_teleports # Returns X zero if both teleports exist &15e2 e0 01 CPX #&01 &15e4 f0 b9 BEQ &159f ; to_main_game_loop &15e6 a9 00 LDA #&00 &15e8 85 ac STA &ac ; player_movement_offset # Indicate that player is moving up into teleport &15ea a9 02 LDA #&02 ; DIRECTION_UP &15ec 20 b5 12 JSR &12b5 ; plot_moving_player &15ef 20 39 1f JSR &1f39 ; consider_teleporting_player # Returns X zero if player exited destination teleport &15f2 e0 00 CPX #&00 &15f4 d0 a9 BNE &159f ; to_main_game_loop &15f6 20 05 21 JSR &2105 ; increment_move_counter &15f9 a0 20 LDY #&20 &15fb a9 00 LDA #&00 ; PIECE_SPACE &15fd 91 60 STA (&60),Y ; previous_player_offset_tile_address # Replace player's old position with space &15ff 20 2c 20 JSR &202c ; use_player_offset_for_entering_teleport # Use the player's old position for considering movers &1602 20 0f 1d JSR &1d0f ; consider_space_vacated_by_player_moving_up &1605 20 3d 20 JSR &203d ; use_player_offset_for_leaving_teleport &1608 a5 90 LDA &90 ; current_player &160a a0 20 LDY #&20 &160c 91 70 STA (&70),Y ; player_offset_tile_address # Replace player's new position with player &160e 20 00 11 JSR &1100 ; plot_viewpoint &1611 4c 90 13 JMP &1390 ; main_game_loop ; not_teleport &1614 c9 0f CMP #&0f ; PIECE_SWITCH &1616 d0 06 BNE &161e ; not_switch &1618 20 73 20 JSR &2073 ; toggle_switch &161b 4c 31 16 JMP &1631 ; move_up # Player can move up into switch ; not_switch &161e c9 0d CMP #&0d ; PIECE_DOLL &1620 d0 0f BNE &1631 ; move_up &1622 a9 00 LDA #&00 &1624 85 b0 STA &b0 ; doll_direction_offset # Indicate that doll is moving up &1626 a9 01 LDA #&01 &1628 85 af STA &af ; mover_is_doll # Set to non-zero to indicate mover is doll &162a 20 eb 1d JSR &1deb ; check_if_player_can_push_up # Returns X zero if player can push &162d e0 01 CPX #&01 &162f f0 32 BEQ &1663 ; to_main_game_loop ; move_up &1631 20 0f 1d JSR &1d0f ; consider_space_vacated_by_player_moving_up &1634 20 05 21 JSR &2105 ; increment_move_counter &1637 a9 00 LDA #&00 &1639 a0 20 LDY #&20 &163b 91 70 STA (&70),Y ; player_offset_tile_address # Replace player's old position with space &163d a5 70 LDA &70 ; player_offset_tile_address_low &163f 38 SEC &1640 e9 20 SBC #&20 &1642 85 70 STA &70 ; player_offset_tile_address_low &1644 a5 71 LDA &71 ; player_offset_tile_address_high &1646 e9 00 SBC #&00 &1648 85 71 STA &71 ; player_offset_tile_address_high &164a a5 90 LDA &90 ; current_player &164c 91 70 STA (&70),Y ; player_offset_tile_address # Replace player's new position with player &164e ad f5 18 LDA &18f5 ; map_was_collected # Non-zero if map was collected &1651 f0 03 BEQ &1656 ; skip_removing_map &1653 20 8a 18 JSR &188a ; collect_map ; skip_removing_map &1656 a5 73 LDA &73 ; player_y_offset &1658 c9 01 CMP #&01 # If the player is at the top of the viewpoint, &165a f0 0a BEQ &1666 ; to_scroll_viewpoint_up # scroll the viewpoint up &165c a9 02 LDA #&02 ; DIRECTION_UP &165e 20 b5 12 JSR &12b5 ; plot_moving_player &1661 c6 73 DEC &73 ; player_y_offset ; to_main_game_loop &1663 4c 90 13 JMP &1390 ; main_game_loop ; to_scroll_viewpoint_up &1666 4c 3a 17 JMP &173a ; scroll_viewpoint_up ; consider_moving_down &1669 a0 40 LDY #&40 &166b b1 70 LDA (&70),Y ; player_offset_tile_address # Consider tile below player &166d 20 f6 18 JSR &18f6 ; check_if_player_can_move # Returns X = &01 if player cannot move &1670 e0 01 CPX #&01 &1672 f0 ef BEQ &1663 ; to_main_game_loop &1674 e0 ff CPX #&ff # X = &ff if level completed &1676 d0 03 BNE &167b ; consider_tile_below &1678 4c 3e 1d JMP &1d3e ; level_completed ; consider_tile_below &167b c9 05 CMP #&05 ; PIECE_DOTS &167d f0 e4 BEQ &1663 ; to_main_game_loop # Player can't move down into dots &167f c9 07 CMP #&07 ; PIECE_FISH &1681 f0 e0 BEQ &1663 ; to_main_game_loop # Player can't move down into fish &1683 c9 09 CMP #&09 ; PIECE_H_BOMB &1685 f0 dc BEQ &1663 ; to_main_game_loop # Player can't move down into H-bomb &1687 c9 08 CMP #&08 ; PIECE_CHICKEN &1689 d0 06 BNE &1691 ; not_chicken &168b 20 55 1e JSR &1e55 ; check_if_player_can_push_down # Returns X zero if player can push &168e 4c 98 16 JMP &1698 ; consider_pushing_vertical_mover_down ; not_chicken &1691 c9 0a CMP #&0a ; PIECE_V_BOMB &1693 d0 0a BNE &169f ; not_v_bomb &1695 20 55 1e JSR &1e55 ; check_if_player_can_push_down # Returns X zero if player can push ; consider_pushing_vertical_mover_down &1698 e0 01 CPX #&01 &169a f0 c7 BEQ &1663 ; to_main_game_loop &169c 4c f5 16 JMP &16f5 ; move_down # Player can push chicken or V-bomb down ; not_v_bomb &169f c9 0e CMP #&0e ; PIECE_TELEPORT &16a1 d0 35 BNE &16d8 ; not_teleport &16a3 20 4e 20 JSR &204e ; check_teleports # Returns X zero if both teleports exist &16a6 e0 01 CPX #&01 &16a8 f0 b9 BEQ &1663 ; to_main_game_loop &16aa a9 40 LDA #&40 &16ac 85 ac STA &ac ; player_movement_offset # Indicate that player is moving down into teleport &16ae a9 01 LDA #&01 ; DIRECTION_DOWN &16b0 20 b5 12 JSR &12b5 ; plot_moving_player &16b3 20 39 1f JSR &1f39 ; consider_teleporting_player # Returns X zero if player exited destination teleport &16b6 e0 00 CPX #&00 &16b8 d0 a9 BNE &1663 ; to_main_game_loop &16ba 20 05 21 JSR &2105 ; increment_move_counter &16bd a0 20 LDY #&20 &16bf a9 00 LDA #&00 ; PIECE_SPACE &16c1 91 60 STA (&60),Y ; previous_player_offset_tile_address # Replace player's old position with space &16c3 20 2c 20 JSR &202c ; use_player_offset_for_entering_teleport # Use the player's old position for considering movers &16c6 20 1f 1d JSR &1d1f ; consider_space_vacated_by_player_moving_down &16c9 20 3d 20 JSR &203d ; use_player_offset_for_leaving_teleport &16cc a5 90 LDA &90 ; current_player &16ce a0 20 LDY #&20 &16d0 91 70 STA (&70),Y ; player_offset_tile_address # Replace player's new position with player &16d2 20 00 11 JSR &1100 ; plot_viewpoint &16d5 4c 90 13 JMP &1390 ; main_game_loop ; not_teleport &16d8 c9 0f CMP #&0f ; PIECE_SWITCH &16da d0 06 BNE &16e2 ; not_switch &16dc 20 73 20 JSR &2073 ; toggle_switch &16df 4c f5 16 JMP &16f5 ; move_down # Player can move down into switch ; not_switch &16e2 c9 0d CMP #&0d ; PIECE_DOLL &16e4 d0 0f BNE &16f5 ; move_down &16e6 a9 40 LDA #&40 &16e8 85 b0 STA &b0 ; doll_direction_offset # Indicate that doll is moving down &16ea a9 01 LDA #&01 &16ec 85 af STA &af ; mover_is_doll # Set to non-zero to indicate mover is doll &16ee 20 55 1e JSR &1e55 ; check_if_player_can_push_down # Returns X zero if player can push &16f1 e0 01 CPX #&01 &16f3 f0 34 BEQ &1729 ; to_main_game_loop ; move_down &16f5 20 1f 1d JSR &1d1f ; consider_space_vacated_by_player_moving_down &16f8 20 05 21 JSR &2105 ; increment_move_counter &16fb a9 00 LDA #&00 ; PIECE_SPACE &16fd a0 20 LDY #&20 &16ff 91 70 STA (&70),Y ; player_offset_tile_address # Replace player's old position with space &1701 18 CLC &1702 a5 70 LDA &70 ; player_offset_tile_address_low &1704 18 CLC &1705 69 20 ADC #&20 &1707 85 70 STA &70 ; player_offset_tile_address_low &1709 90 02 BCC &170d ; skip_page &170b e6 71 INC &71 ; player_offset_tile_address_high ; skip_page &170d a5 90 LDA &90 ; current_player &170f 91 70 STA (&70),Y ; player_offset_tile_address # Replace player's new position with player &1711 ad f5 18 LDA &18f5 ; map_was_collected # Non-zero if map was collected &1714 f0 03 BEQ &1719 ; skip_removing_map &1716 20 8a 18 JSR &188a ; collect_map ; skip_removing_map &1719 a5 73 LDA &73 ; player_y_offset &171b c9 06 CMP #&06 # If the player is at the bottom of the viewpoint, &171d f0 2d BEQ &174c ; scroll_viewpoint_down # scroll the viewpoint down &171f a9 01 LDA #&01 ; DIRECTION_DOWN &1721 20 b5 12 JSR &12b5 ; plot_moving_player &1724 e6 73 INC &73 ; player_y_offset &1726 4c 90 13 JMP &1390 ; main_game_loop ; to_main_game_loop &1729 4c 90 13 JMP &1390 ; main_game_loop ; scroll_viewpoint_left &172c c6 74 DEC &74 ; viewpoint_x &172e c6 76 DEC &76 ; viewpoint_tile_address_low &1730 4c 59 17 JMP &1759 ; replot_viewpoint ; scroll_viewpoint_right &1733 e6 74 INC &74 ; viewpoint_x &1735 e6 76 INC &76 ; viewpoint_tile_address_low &1737 4c 59 17 JMP &1759 ; replot_viewpoint ; scroll_viewpoint_up &173a c6 75 DEC &75 ; viewpoint_y &173c 38 SEC &173d a5 76 LDA &76 ; viewpoint_tile_address_low &173f e9 20 SBC #&20 &1741 85 76 STA &76 ; viewpoint_tile_address_low &1743 a5 77 LDA &77 ; viewpoint_tile_address_high &1745 e9 00 SBC #&00 &1747 85 77 STA &77 ; viewpoint_tile_address_high &1749 4c 59 17 JMP &1759 ; replot_viewpoint ; scroll_viewpoint_down &174c e6 75 INC &75 ; viewpoint_y &174e 18 CLC &174f a5 76 LDA &76 ; viewpoint_tile_address_low &1751 69 20 ADC #&20 &1753 85 76 STA &76 ; viewpoint_tile_address_low &1755 90 02 BCC &1759 ; replot_viewpoint &1757 e6 77 INC &77 ; viewpoint_tile_address_high ; replot_viewpoint &1759 20 00 11 JSR &1100 ; plot_viewpoint &175c 4c 90 13 JMP &1390 ; main_game_loop ; consider_swap &175f a6 91 LDX &91 ; other_player_state # Zero if other player is dead &1761 f0 51 BEQ &17b4 ; to_main_game_loop # Can't swap if other player is dead &1763 20 05 21 JSR &2105 ; increment_move_counter &1766 a5 90 LDA &90 ; current_player &1768 c9 02 CMP #&02 ; PIECE_MAGUS &176a d0 03 BNE &176f ; swap_from_questor &176c 4c b7 17 JMP &17b7 ; swap_from_magus ; swap_from_questor &176f a9 02 LDA #&02 ; PIECE_MAGUS &1771 85 90 STA &90 ; current_player &1773 a0 00 LDY #&00 ; copy_magus_sprite_loop &1775 b9 20 55 LDA &5520,Y ; sprite_magus_source &1778 99 6d 12 STA &126d,Y ; sprite_current_player &177b c8 INY &177c c0 48 CPY #&48 &177e d0 f5 BNE &1775 ; copy_magus_sprite_loop &1780 a0 00 LDY #&00 ; backup_questor_variables_loop &1782 b9 70 00 LDA &0070,Y ; player_address_offsets_and_viewpoint &1785 99 88 00 STA &0088,Y ; questor_address_offsets_and_viewpoint &1788 c8 INY &1789 c0 08 CPY #&08 &178b d0 f5 BNE &1782 ; backup_questor_variables_loop &178d a0 00 LDY #&00 ; restore_magus_variables_loop &178f b9 80 00 LDA &0080,Y ; magus_address_offsets_and_viewpoint &1792 99 70 00 STA &0070,Y ; player_address_offsets_and_viewpoint &1795 c8 INY &1796 c0 08 CPY #&08 &1798 d0 f5 BNE &178f ; restore_magus_variables_loop ; replot_player_and_viewpoint &179a a5 90 LDA &90 ; current_player &179c a2 e8 LDX #&e8 &179e 86 58 STX &58 ; screen_address_low &17a0 a2 71 LDX #&71 &17a2 86 59 STX &59 ; screen_address_high &17a4 20 2d 11 JSR &112d ; plot_sprite # Plot player next to move counter &17a7 20 00 11 JSR &1100 ; plot_viewpoint &17aa a9 00 LDA #&00 ; DIRECTION_NONE &17ac 20 b5 12 JSR &12b5 ; plot_moving_player &17af a9 3c LDA #&3c &17b1 20 a3 1e JSR &1ea3 ; delay ; to_main_game_loop &17b4 4c 90 13 JMP &1390 ; main_game_loop ; swap_from_magus &17b7 a9 03 LDA #&03 ; PIECE_QUESTOR &17b9 85 90 STA &90 ; current_player &17bb a0 00 LDY #&00 ; copy_questor_sprite_loop &17bd b9 68 55 LDA &5568,Y ; sprite_questor_source &17c0 99 6d 12 STA &126d,Y ; sprite_current_player &17c3 c8 INY &17c4 c0 48 CPY #&48 &17c6 d0 f5 BNE &17bd ; copy_questor_sprite_loop &17c8 a0 00 LDY #&00 ; backup_magus_variables_loop &17ca b9 70 00 LDA &0070,Y ; player_address_offsets_and_viewpoint &17cd 99 80 00 STA &0080,Y ; magus_address_offsets_and_viewpoint &17d0 c8 INY &17d1 c0 08 CPY #&08 &17d3 d0 f5 BNE &17ca ; backup_magus_variables_loop &17d5 a0 00 LDY #&00 ; restore_questor_variables_loop &17d7 b9 88 00 LDA &0088,Y ; questor_address_offsets_and_viewpoint &17da 99 70 00 STA &0070,Y ; player_address_offsets_and_viewpoint &17dd c8 INY &17de c0 08 CPY #&08 &17e0 d0 f5 BNE &17d7 ; restore_questor_variables_loop &17e2 4c 9a 17 JMP &179a ; replot_player_and_viewpoint ; unused &17e5 60 RTS ; plot_map_quadrant &17e6 a2 00 LDX #&00 &17e8 86 62 STX &62 ; column &17ea 86 6c STX &6c ; row_in_group &17ec 86 65 STX &65 ; group ; plot_map_quadrant_byte_loop &17ee a9 00 LDA #&00 &17f0 a0 00 LDY #&00 &17f2 91 60 STA (&60),Y ; map_screen_address &17f4 a2 00 LDX #&00 ; plot_map_quadrant_pixel_loop &17f6 a0 00 LDY #&00 &17f8 b1 5e LDA (&5e),Y ; map_tile_address &17fa 29 0f AND #&0f &17fc a0 00 LDY #&00 &17fe c9 01 CMP #&01 ; PIECE_WALL &1800 d0 01 BNE &1803 ; not_wall &1802 c8 INY # Use colour 1 for walls ; not_wall &1803 c9 0b CMP #&0b ; PIECE_MASK &1805 d0 02 BNE &1809 ; not_mask &1807 a0 02 LDY #&02 # Use colour 2 for masks ; not_mask &1809 c9 0c CMP #&0c ; PIECE_DOOR &180b d0 02 BNE &180f ; not_door &180d a0 03 LDY #&03 # Use colour 3 for doors ; not_door &180f bd 82 18 LDA &1882,X ; pixel_values &1812 39 86 18 AND &1886,Y ; colour_masks &1815 a0 00 LDY #&00 &1817 11 60 ORA (&60),Y ; map_screen_address # Plot pixel for tile &1819 91 60 STA (&60),Y ; map_screen_address &181b e6 5e INC &5e ; map_tile_address_low &181d a5 5e LDA &5e ; map_tile_address_low &181f d0 02 BNE &1823 ; skip_page &1821 e6 5f INC &5f ; map_tile_address_high ; skip_page &1823 e8 INX &1824 e0 04 CPX #&04 &1826 d0 ce BNE &17f6 ; plot_map_quadrant_pixel_loop &1828 b1 60 LDA (&60),Y ; map_screen_address # Map pixels are two rows high &182a c8 INY &182b 91 60 STA (&60),Y ; map_screen_address &182d a5 60 LDA &60 ; map_screen_address_low &182f 18 CLC &1830 69 08 ADC #&08 # Move right four pixels &1832 85 60 STA &60 ; map_screen_address_low &1834 90 02 BCC &1838 ; skip_page &1836 e6 61 INC &61 ; map_screen_address_high ; skip_page &1838 e6 62 INC &62 ; column &183a a5 62 LDA &62 ; column &183c c9 04 CMP #&04 # Plot four columns of four pixels (sixteen tiles) &183e d0 ae BNE &17ee ; plot_map_quadrant_byte_loop &1840 a9 00 LDA #&00 &1842 85 62 STA &62 ; column &1844 e6 6c INC &6c ; row_in_group &1846 18 CLC &1847 a5 5e LDA &5e ; map_tile_address_low &1849 69 10 ADC #&10 &184b 85 5e STA &5e ; map_tile_address_low &184d 90 02 BCC &1851 ; skip_page &184f e6 5f INC &5f ; map_tile_address_high ; skip_page &1851 a5 6c LDA &6c ; row_in_group &1853 c9 04 CMP #&04 # Plot four rows of tiles per group &1855 f0 0e BEQ &1865 ; next_group &1857 38 SEC &1858 a5 60 LDA &60 ; map_screen_address_low &185a e9 1e SBC #&1e # Move to start of next row &185c 85 60 STA &60 ; map_screen_address_low &185e b0 8e BCS &17ee ; plot_map_quadrant_byte_loop &1860 c6 61 DEC &61 ; map_screen_address_high &1862 4c ee 17 JMP &17ee ; plot_map_quadrant_byte_loop ; next_group &1865 a2 00 LDX #&00 &1867 86 6c STX &6c ; row_in_group &1869 e6 65 INC &65 ; group &186b e6 61 INC &61 ; map_screen_address_high &186d 18 CLC &186e a5 60 LDA &60 ; map_screen_address_low &1870 69 1a ADC #&1a # Move to start of next row in next group &1872 85 60 STA &60 ; map_screen_address_low &1874 90 02 BCC &1878 ; skip_page &1876 e6 61 INC &61 ; map_screen_address_high ; skip_page &1878 a5 65 LDA &65 ; group &187a c9 04 CMP #&04 # Plot four groups of four rows of tiles (sixteen tiles) &187c f0 03 BEQ &1881 ; leave &187e 4c ee 17 JMP &17ee ; plot_map_quadrant_byte_loop ; leave &1881 60 RTS ; pixel_values &1882 88 44 22 11 ; colour_masks &1886 00 0f ff f0 ; collect_map &188a a0 fe LDY #&fe ; check_for_maps_loop # For each map piece, &188c c8 INY &188d c8 INY &188e a5 70 LDA &70 ; player_offset_tile_address_low &1890 d9 78 00 CMP &0078,Y ; map_addresses # Check if the player has collected it &1893 d0 f7 BNE &188c ; check_for_maps_loop &1895 a5 71 LDA &71 ; player_offset_tile_address_high &1897 c8 INY &1898 d9 78 00 CMP &0078,Y ; map_addresses &189b f0 04 BEQ &18a1 ; found_map &189d 88 DEY &189e 4c 8c 18 JMP &188c ; check_for_maps_loop ; found_map &18a1 a9 00 LDA #&00 # Set to zero to indicate map piece has been collected &18a3 99 78 00 STA &0078,Y ; map_addresses &18a6 88 DEY &18a7 99 78 00 STA &0078,Y ; map_addresses ; plot_map_quadrant_after_setting_addresses &18aa b9 e5 18 LDA &18e5,Y ; map_screen_addresses &18ad 85 60 STA &60 ; map_screen_address_low &18af b9 ed 18 LDA &18ed,Y ; map_tile_addresses &18b2 85 5e STA &5e ; map_tile_address_low &18b4 c8 INY &18b5 b9 e5 18 LDA &18e5,Y ; map_screen_addresses &18b8 85 61 STA &61 ; map_screen_address_high &18ba b9 ed 18 LDA &18ed,Y ; map_tile_addresses &18bd 85 5f STA &5f ; map_tile_address_high &18bf 20 e6 17 JSR &17e6 ; plot_map_quadrant # Plot map quadrant &18c2 60 RTS ; update_map &18c3 a0 fe LDY #&fe ; update_map_loop # For each map quadrant, &18c5 c8 INY &18c6 c8 INY &18c7 b9 78 00 LDA &0078,Y ; map_addresses # Has the map piece been collected? &18ca f0 03 BEQ &18cf ; check_map_address_high &18cc 4c df 18 JMP &18df ; consider_next_quadrant ; check_map_address_high &18cf c8 INY &18d0 b9 78 00 LDA &0078,Y ; map_addresses # Zero if map piece has been collected &18d3 88 DEY &18d4 c9 00 CMP #&00 &18d6 d0 07 BNE &18df ; consider_next_quadrant # If so, replot map quadrant &18d8 98 TYA &18d9 48 PHA &18da 20 aa 18 JSR &18aa ; plot_map_quadrant_after_setting_addresses &18dd 68 PLA &18de a8 TAY ; consider_next_quadrant &18df c0 06 CPY #&06 &18e1 d0 e2 BNE &18c5 ; update_map_loop &18e3 60 RTS ; unused &18e4 60 RTS ; map_screen_addresses &18e5 a8 61 ; &61a8 # Top left quadrant &18e7 c8 61 ; &61c8 # Top right quadrant &18e9 a8 66 ; &66a8 # Bottom left quadrant &18eb c8 66 ; &66c8 # Bottom right quadrant ; map_tile_addresses &18ed 00 09 ; &0900 = tile_data # Top left quadrant &18ef 10 09 ; &0910 = tile_data + 16 # Top right quadrant &18f1 00 0b ; &0b00 = tile_data + &20 * 16 # Bottom left quadrant &18f3 10 0b ; &0b10 = tile_data + &20 * 16 + 16 # Bottom right quadrant ; map_was_collected &18f5 ea ; check_if_player_can_move &18f6 a2 00 LDX #&00 # Set X to &00 to indicate player can move by default &18f8 a0 00 LDY #&00 # Set Y to &00 to indicate map not collected by default &18fa c9 01 CMP #&01 ; PIECE_WALL &18fc f0 26 BEQ &1924 ; player_cannot_move # Player is stopped by wall &18fe c9 02 CMP #&02 ; PIECE_MAGUS &1900 f0 22 BEQ &1924 ; player_cannot_move # Player is stopped by Magus &1902 c9 03 CMP #&03 ; PIECE_QUESTOR &1904 f0 1e BEQ &1924 ; player_cannot_move # Player is stopped by Questor &1906 c9 0b CMP #&0b ; PIECE_MASK &1908 d0 05 BNE &190f ; not_mask &190a e6 93 INC &93 ; masks_collected &190c 20 41 1d JSR &1d41 ; collect_mask ; not_mask &190f c9 0c CMP #&0c ; PIECE_DOOR &1911 d0 0e BNE &1921 ; not_door &1913 a5 92 LDA &92 ; masks_total &1915 c5 93 CMP &93 ; masks_collected &1917 d0 0b BNE &1924 ; player_cannot_move # Player is stopped by door if not all masks collected &1919 a6 b6 LDX &b6 ; move_direction &191b 20 4e 22 JSR &224e ; store_move &191e a2 ff LDX #&ff # Set X to &ff to indicate level completed &1920 60 RTS ; not_door &1921 4c 25 19 JMP &1925 ; player_can_move # Player can move into all other pieces ; player_cannot_move &1924 e8 INX # Set X to &01 to indicate player cannot move ; player_can_move &1925 c9 04 CMP #&04 ; PIECE_MAP &1927 d0 01 BNE &192a ; not_map &1929 c8 INY # Set Y to &01 to indicate map collected ; not_map &192a 8c f5 18 STY &18f5 ; map_was_collected &192d 60 RTS ; add_mover &192e a5 94 LDA &94 ; mover_count &1930 0a ASL A &1931 a8 TAY &1932 ad b7 1c LDA &1cb7 ; new_mover_tile_address_low &1935 99 00 29 STA &2900,Y ; movers # Add mover to end of list &1938 c8 INY &1939 ad b8 1c LDA &1cb8 ; new_mover_tile_address_high &193c 99 00 29 STA &2900,Y ; movers &193f e6 94 INC &94 ; mover_count &1941 60 RTS ; get_mover &1942 ad 00 29 LDA &2900 ; movers # Get first mover from list &1945 85 a8 STA &a8 ; mover_tile_address_low &1947 ad 01 29 LDA &2901 ; movers + 1 &194a 85 a9 STA &a9 ; mover_tile_address_high &194c a0 02 LDY #&02 ; shuffle_movers_loop # Shuffle remaining movers forward a position &194e b9 00 29 LDA &2900,Y ; movers &1951 88 DEY &1952 88 DEY &1953 99 00 29 STA &2900,Y ; movers &1956 c8 INY &1957 c8 INY &1958 c8 INY &1959 d0 f3 BNE &194e ; shuffle_movers_loop &195b c6 94 DEC &94 ; mover_count &195d 60 RTS ; to_update_horizontal_mover &195e 4c b2 1b JMP &1bb2 ; update_horizontal_mover ; update_movers &1961 20 42 19 JSR &1942 ; get_mover &1964 a0 00 LDY #&00 &1966 b1 a8 LDA (&a8),Y ; mover_tile_address &1968 c9 07 CMP #&07 ; PIECE_FISH &196a f0 1c BEQ &1988 ; update_vertical_mover &196c c9 09 CMP #&09 ; PIECE_H_BOMB &196e f0 18 BEQ &1988 ; update_vertical_mover &1970 c9 08 CMP #&08 ; PIECE_CHICKEN &1972 f0 ea BEQ &195e ; to_update_horizontal_mover &1974 c9 0a CMP #&0a ; PIECE_V_BOMB &1976 f0 e6 BEQ &195e ; to_update_horizontal_mover &1978 c9 0d CMP #&0d ; PIECE_DOLL &197a f0 06 BEQ &1982 ; to_update_doll &197c 4c 90 13 JMP &1390 ; main_game_loop ; to_vertical_mover_moving_into_h_bomb &197f 4c e9 1a JMP &1ae9 ; vertical_mover_moving_into_h_bomb ; to_update_doll &1982 4c 9e 20 JMP &209e ; update_doll ; to_vertical_mover_moving_into_v_bomb &1985 4c 57 1b JMP &1b57 ; vertical_mover_moving_into_v_bomb ; update_vertical_mover &1988 a0 20 LDY #&20 # Consider the tile below the mover &198a b1 a8 LDA (&a8),Y ; mover_tile_address &198c f0 1f BEQ &19ad ; vertical_mover_can_move_down # Vertical mover can move into space &198e c9 06 CMP #&06 ; PIECE_WAVES &1990 f0 1b BEQ &19ad ; vertical_mover_can_move_down # Vertical mover can move into waves &1992 c9 02 CMP #&02 ; PIECE_MAGUS &1994 d0 08 BNE &199e ; not_magus # Vertical mover can move into Magus ; vertical_mover_moving_into_player &1996 a0 00 LDY #&00 # Use first explosion slot for mover &1998 99 09 1f STA &1f09,Y ; explosions_or_mover_destroyed # Note that mover destroyed player &199b 4c ad 19 JMP &19ad ; vertical_mover_can_move_down ; not_magus &199e c9 03 CMP #&03 ; PIECE_QUESTOR &19a0 f0 f4 BEQ &1996 ; vertical_mover_moving_into_player # Vertical mover can move into Questor &19a2 c9 09 CMP #&09 ; PIECE_H_BOMB &19a4 f0 d9 BEQ &197f ; to_vertical_mover_moving_into_h_bomb # Vertical mover can move into H-bomb &19a6 c9 0a CMP #&0a ; PIECE_V_BOMB &19a8 f0 db BEQ &1985 ; to_vertical_mover_moving_into_v_bomb # Vertical mover can move into V-bomb &19aa 4c 90 13 JMP &1390 ; main_game_loop # Vertical mover is stopped by all other pieces ; vertical_mover_can_move_down &19ad 20 4f 1a JSR &1a4f ; consider_mover_above # Is there a mover above this mover? &19b0 20 76 1a JSR &1a76 ; consider_mover_right # Is there a mover to the right of this mover? &19b3 a5 a8 LDA &a8 ; mover_tile_address_low &19b5 18 CLC &19b6 69 20 ADC #&20 &19b8 85 aa STA &aa ; mover_destination_tile_address_low &19ba a5 a9 LDA &a9 ; mover_tile_address_high &19bc 69 00 ADC #&00 &19be 85 ab STA &ab ; mover_destination_tile_address_high &19c0 20 f2 19 JSR &19f2 ; move_mover # Move the mover down a tile &19c3 a0 20 LDY #&20 &19c5 b1 aa LDA (&aa),Y ; mover_destination_tile_address # Consider the piece below the destination &19c7 c9 06 CMP #&06 ; PIECE_WAVES &19c9 f0 17 BEQ &19e2 ; continue_moving_mover # Vertical mover can keep moving into waves ; check_if_mover_can_continue_moving &19cb c9 00 CMP #&00 ; PIECE_SPACE &19cd f0 13 BEQ &19e2 ; continue_moving_mover # Mover can keep moving into space &19cf c9 09 CMP #&09 ; PIECE_H_BOMB &19d1 f0 0f BEQ &19e2 ; continue_moving_mover # Mover can keep moving into H-bomb &19d3 c9 02 CMP #&02 ; PIECE_MAGUS &19d5 f0 0b BEQ &19e2 ; continue_moving_mover # Mover can keep moving into Magus &19d7 c9 03 CMP #&03 ; PIECE_QUESTOR &19d9 f0 07 BEQ &19e2 ; continue_moving_mover # Mover can keep moving into Questor &19db c9 0a CMP #&0a ; PIECE_V_BOMB &19dd f0 03 BEQ &19e2 ; continue_moving_mover # Mover can keep moving into V-bomb &19df 4c 90 13 JMP &1390 ; main_game_loop # Mover is stopped by all other pieces ; continue_moving_mover &19e2 a5 aa LDA &aa ; mover_destination_tile_address_low &19e4 8d b7 1c STA &1cb7 ; new_mover_tile_address_low &19e7 a5 ab LDA &ab ; mover_destination_tile_address_high &19e9 8d b8 1c STA &1cb8 ; new_mover_tile_address_high &19ec 20 2e 19 JSR &192e ; add_mover # Add mover in new position to end of mover list &19ef 4c 90 13 JMP &1390 ; main_game_loop ; move_mover &19f2 a5 a8 LDA &a8 ; mover_tile_address_low &19f4 85 5e STA &5e ; check_tile_address_low &19f6 a5 a9 LDA &a9 ; mover_tile_address_high &19f8 85 5f STA &5f ; check_tile_address_high &19fa 20 99 1a JSR &1a99 ; check_if_tile_is_visible &19fd a5 5e LDA &5e ; check_screen_address_low &19ff 8d b9 1c STA &1cb9 ; mover_origin_screen_address_low &1a02 a5 5f LDA &5f ; check_screen_address_high &1a04 8d ba 1c STA &1cba ; mover_origin_screen_address_high &1a07 a5 aa LDA &aa ; mover_destination_tile_address_low &1a09 85 5e STA &5e ; check_tile_address_low &1a0b a5 ab LDA &ab ; mover_destination_tile_address_high &1a0d 85 5f STA &5f ; check_tile_address_high &1a0f 20 99 1a JSR &1a99 ; check_if_tile_is_visible &1a12 a5 5e LDA &5e ; check_screen_address_low &1a14 8d bb 1c STA &1cbb ; mover_destination_screen_address_low &1a17 a5 5f LDA &5f ; check_screen_address_high &1a19 8d bc 1c STA &1cbc ; mover_destination_screen_address_high &1a1c a0 00 LDY #&00 &1a1e b1 a8 LDA (&a8),Y ; mover_tile_address &1a20 91 aa STA (&aa),Y ; mover_destination_tile_address &1a22 98 TYA &1a23 91 a8 STA (&a8),Y ; mover_tile_address &1a25 ad ba 1c LDA &1cba ; mover_origin_screen_address_high &1a28 f0 0c BEQ &1a36 ; skip_unplotting_mover # If the old position of the mover is on screen, &1a2a 85 59 STA &59 ; screen_address_high &1a2c ad b9 1c LDA &1cb9 ; mover_origin_screen_address_low &1a2f 85 58 STA &58 ; screen_address_low &1a31 a9 00 LDA #&00 ; PIECE_SPACE &1a33 20 2d 11 JSR &112d ; plot_sprite # Unplot mover from old position ; skip_unplotting_mover &1a36 ad bc 1c LDA &1cbc ; mover_destination_screen_address_high &1a39 f0 13 BEQ &1a4e ; skip_plotting_mover # If the new position of the mover is on screen, &1a3b 85 59 STA &59 ; screen_address_high &1a3d ad bb 1c LDA &1cbb ; mover_destination_screen_address_low &1a40 85 58 STA &58 ; screen_address_low &1a42 a0 00 LDY #&00 &1a44 b1 aa LDA (&aa),Y ; mover_destination_tile_address &1a46 20 2d 11 JSR &112d ; plot_sprite # Plot mover in new position &1a49 a9 14 LDA #&14 &1a4b 20 a3 1e JSR &1ea3 ; delay ; skip_plotting_mover &1a4e 60 RTS ; consider_mover_above &1a4f a5 a8 LDA &a8 ; mover_tile_address_low &1a51 38 SEC &1a52 e9 20 SBC #&20 &1a54 85 52 STA &52 ; above_tile_address_low &1a56 a5 a9 LDA &a9 ; mover_tile_address_high &1a58 e9 00 SBC #&00 &1a5a 85 53 STA &53 ; above_tile_address_high &1a5c a0 00 LDY #&00 &1a5e b1 52 LDA (&52),Y ; above_tile_address # Consider the tile above the mover &1a60 c9 07 CMP #&07 ; PIECE_FISH &1a62 f0 04 BEQ &1a68 ; piece_above_can_fall # Does it contain a fish? &1a64 c9 09 CMP #&09 ; PIECE_H_BOMB &1a66 d0 0d BNE &1a75 ; leave # Or an H-bomb? ; piece_above_can_fall &1a68 a5 52 LDA &52 ; above_tile_address_low &1a6a 8d b7 1c STA &1cb7 ; new_mover_tile_address_low &1a6d a5 53 LDA &53 ; above_tile_address_high &1a6f 8d b8 1c STA &1cb8 ; new_mover_tile_address_high &1a72 20 2e 19 JSR &192e ; add_mover # If so, add that as a mover ; leave &1a75 60 RTS ; consider_mover_right &1a76 a0 01 LDY #&01 &1a78 b1 a8 LDA (&a8),Y ; mover_tile_address # Consider the tile to the right of the mover &1a7a c9 08 CMP #&08 ; PIECE_CHICKEN &1a7c f0 05 BEQ &1a83 ; piece_right_can_move_left # Does it contain a chicken? &1a7e c9 0a CMP #&0a ; PIECE_V_BOMB &1a80 f0 01 BEQ &1a83 ; piece_right_can_move_left # Or a V-bomb? &1a82 60 RTS ; piece_right_can_move_left &1a83 a6 a8 LDX &a8 ; mover_tile_address_low &1a85 a5 a9 LDA &a9 ; mover_tile_address_high &1a87 e8 INX &1a88 8e b7 1c STX &1cb7 ; new_mover_tile_address_low &1a8b e0 00 CPX #&00 &1a8d d0 03 BNE &1a92 ; skip_page &1a8f aa TAX &1a90 e8 INX &1a91 8a TXA ; skip_page &1a92 8d b8 1c STA &1cb8 ; new_mover_tile_address_high &1a95 20 2e 19 JSR &192e ; add_mover # If so, add that as a mover &1a98 60 RTS ; check_if_tile_is_visible &1a99 a5 5f LDA &5f ; check_tile_address_high # Convert tile address into x and y positions &1a9b 38 SEC &1a9c e9 09 SBC #&09 &1a9e 0a ASL A &1a9f 0a ASL A &1aa0 0a ASL A &1aa1 8d bd 1c STA &1cbd ; tile_y &1aa4 a5 5e LDA &5e ; check_tile_address_low ; calculate_tile_y_loop &1aa6 ee bd 1c INC &1cbd ; tile_y &1aa9 38 SEC &1aaa e9 20 SBC #&20 &1aac b0 f8 BCS &1aa6 ; calculate_tile_y_loop &1aae ce bd 1c DEC &1cbd ; tile_y &1ab1 69 20 ADC #&20 &1ab3 8d be 1c STA &1cbe ; tile_x &1ab6 38 SEC &1ab7 e5 74 SBC &74 ; viewpoint_x &1ab9 8d be 1c STA &1cbe ; tile_x &1abc 30 26 BMI &1ae4 ; not_visible # Tile isn't visible if beyond left of viewpoint &1abe c9 08 CMP #&08 &1ac0 10 22 BPL &1ae4 ; not_visible # Tile isn't visible if beyond right of viewpoint &1ac2 ad bd 1c LDA &1cbd ; tile_y &1ac5 38 SEC &1ac6 e5 75 SBC &75 ; viewpoint_y &1ac8 8d bd 1c STA &1cbd ; tile_y &1acb 30 17 BMI &1ae4 ; not_visible # Tile isn't visible if beyond top of viewpoint &1acd c9 08 CMP #&08 &1acf 10 13 BPL &1ae4 ; not_visible # Tile isn't visible if beyond bottom of viewpoint &1ad1 0a ASL A &1ad2 0a ASL A &1ad3 0a ASL A &1ad4 18 CLC &1ad5 6d be 1c ADC &1cbe ; tile_x &1ad8 0a ASL A &1ad9 a8 TAY &1ada b1 56 LDA (&56),Y ; screen_addresses # Convert relative tile position into screen address &1adc 85 5e STA &5e ; check_screen_address_low &1ade c8 INY &1adf b1 56 LDA (&56),Y ; screen_addresses &1ae1 85 5f STA &5f ; check_screen_address_high &1ae3 60 RTS # Leave with tile screen address ; not_visible &1ae4 a9 00 LDA #&00 # Set to zero to indicate tile is not visible &1ae6 85 5f STA &5f ; check_screen_address_high &1ae8 60 RTS # Leave with zero to indicate tile is not visible ; vertical_mover_moving_into_h_bomb &1ae9 a9 03 LDA #&03 ; Y # H-bomb has yellow explosion &1aeb 8d 46 22 STA &2246 ; flash_colour &1aee 20 4f 1a JSR &1a4f ; consider_mover_above # Is there a mover above the detonator? &1af1 a5 a8 LDA &a8 ; mover_tile_address_low # Bug: doesn't consider mover right of the detonator &1af3 85 aa STA &aa ; bomb_tile_address_low &1af5 a5 a9 LDA &a9 ; mover_tile_address_high &1af7 85 ab STA &ab ; bomb_tile_address_high &1af9 a5 aa LDA &aa ; bomb_tile_address_low &1afb 18 CLC &1afc 69 1f ADC #&1f # Consider the tile to the left of the bomb &1afe 85 a8 STA &a8 ; mover_tile_address_low &1b00 a5 ab LDA &ab ; bomb_tile_address_high &1b02 69 00 ADC #&00 &1b04 85 a9 STA &a9 ; mover_tile_address_high &1b06 20 4f 1a JSR &1a4f ; consider_mover_above # Is there a mover above the left explosion? &1b09 a0 00 LDY #&00 &1b0b 20 0e 1f JSR &1f0e ; flash_explosion_and_check_for_damage # Has the left explosion destroyed a player or switch? &1b0e a5 a8 LDA &a8 ; mover_tile_address_low &1b10 18 CLC &1b11 69 02 ADC #&02 # Consider the tile to the right of the bomb &1b13 85 a8 STA &a8 ; mover_tile_address_low &1b15 a5 a9 LDA &a9 ; mover_tile_address_high &1b17 69 00 ADC #&00 &1b19 85 a9 STA &a9 ; mover_tile_address_high &1b1b 20 4f 1a JSR &1a4f ; consider_mover_above # Is there a mover above the right explosion? &1b1e 20 76 1a JSR &1a76 ; consider_mover_right # Is there a mover right of the right explosion? &1b21 a0 01 LDY #&01 &1b23 20 0e 1f JSR &1f0e ; flash_explosion_and_check_for_damage # Has the right explosion destroyed a player or switch? &1b26 a0 00 LDY #&00 ; PIECE_SPACE &1b28 98 TYA &1b29 91 aa STA (&aa),Y ; bomb_tile_address # Replace detonator with space &1b2b a0 20 LDY #&20 &1b2d 91 aa STA (&aa),Y ; bomb_tile_address # Replace bomb with space &1b2f a5 a8 LDA &a8 ; mover_tile_address_low &1b31 29 1f AND #&1f &1b33 c9 1f CMP #&1f &1b35 f0 06 BEQ &1b3d ; skip_right_side # If right explosion isn't right edge of level, &1b37 a9 00 LDA #&00 ; PIECE_SPACE &1b39 a0 21 LDY #&21 &1b3b 91 aa STA (&aa),Y ; bomb_tile_address # Replace right explosion with space ; skip_right_side &1b3d a5 aa LDA &aa ; bomb_tile_address_low &1b3f 18 CLC &1b40 69 1f ADC #&1f &1b42 29 1f AND #&1f &1b44 c9 00 CMP #&00 &1b46 f0 06 BEQ &1b4e ; skip_left_side # If left explosion isn't left edge of level, &1b48 a9 00 LDA #&00 ; PIECE_SPACE &1b4a a0 1f LDY #&1f &1b4c 91 aa STA (&aa),Y ; bomb_tile_address # Replace left explosion with space ; skip_left_side &1b4e 20 c3 18 JSR &18c3 ; update_map &1b51 20 00 11 JSR &1100 ; plot_viewpoint &1b54 4c 90 13 JMP &1390 ; main_game_loop ; vertical_mover_moving_into_v_bomb &1b57 a9 02 LDA #&02 ; G # V-bomb has green explosion &1b59 8d 46 22 STA &2246 ; flash_colour &1b5c 20 4f 1a JSR &1a4f ; consider_mover_above # Is there a mover above the detonator? &1b5f 20 76 1a JSR &1a76 ; consider_mover_right # Is there a mover right of the detonator? &1b62 a5 a8 LDA &a8 ; mover_tile_address_low &1b64 85 aa STA &aa ; bomb_tile_address_low &1b66 a5 a9 LDA &a9 ; mover_tile_address_high &1b68 85 ab STA &ab ; bomb_tile_address_high &1b6a a9 01 LDA #&01 &1b6c 85 6c STA &6c ; count ; check_for_movers_loop &1b6e a5 a8 LDA &a8 ; mover_tile_address_low &1b70 18 CLC &1b71 69 20 ADC #&20 &1b73 85 a8 STA &a8 ; mover_tile_address_low &1b75 a5 a9 LDA &a9 ; mover_tile_address_high &1b77 69 00 ADC #&00 &1b79 85 a9 STA &a9 ; mover_tile_address_high &1b7b 20 76 1a JSR &1a76 ; consider_mover_right # Is there a mover right of the bomb? &1b7e c6 6c DEC &6c ; count &1b80 a5 6c LDA &6c ; count &1b82 f0 ea BEQ &1b6e ; check_for_movers_loop # Is there a mover right of the bottom explosion? &1b84 a0 00 LDY #&00 &1b86 20 0e 1f JSR &1f0e ; flash_explosion_and_check_for_damage # Has the bottom explosion destroyed a player or switch? &1b89 a0 00 LDY #&00 ; PIECE_SPACE &1b8b 98 TYA &1b8c 91 aa STA (&aa),Y ; bomb_tile_address # Replace detonator / top explosion with space &1b8e a0 20 LDY #&20 &1b90 91 aa STA (&aa),Y ; bomb_tile_address # Replace bomb with space ; consider_bottom_explosion &1b92 a5 a9 LDA &a9 ; mover_tile_address_high &1b94 c9 0c CMP #&0c &1b96 f0 0f BEQ &1ba7 ; consider_skipping_bottom # If bottom explosion isn't bottom edge of level, ; remove_bottom_explosion &1b98 a9 00 LDA #&00 ; PIECE_SPACE &1b9a a0 40 LDY #&40 &1b9c 91 aa STA (&aa),Y ; bomb_tile_address # Replace bottom explosion with space ; skip_bottom &1b9e 20 c3 18 JSR &18c3 ; update_map &1ba1 20 00 11 JSR &1100 ; plot_viewpoint &1ba4 4c 90 13 JMP &1390 ; main_game_loop ; consider_skipping_bottom &1ba7 a5 a8 LDA &a8 ; mover_tile_address_low &1ba9 29 e0 AND #&e0 &1bab c9 e0 CMP #&e0 &1bad d0 e9 BNE &1b98 ; remove_bottom_explosion &1baf 4c 9e 1b JMP &1b9e ; skip_bottom ; update_horizontal_mover &1bb2 a5 a8 LDA &a8 ; mover_tile_address_low &1bb4 38 SEC &1bb5 e9 01 SBC #&01 &1bb7 85 aa STA &aa ; mover_destination_tile_address_low &1bb9 a5 a9 LDA &a9 ; mover_tile_address_high &1bbb e9 00 SBC #&00 &1bbd 85 ab STA &ab ; mover_destination_tile_address_high &1bbf a0 00 LDY #&00 &1bc1 b1 aa LDA (&aa),Y ; mover_destination_tile_address # Consider the piece to the left of the mover &1bc3 f0 22 BEQ &1be7 ; horizontal_mover_can_move_left # Horizontal mover can move into space &1bc5 c9 05 CMP #&05 ; PIECE_DOTS &1bc7 f0 1e BEQ &1be7 ; horizontal_mover_can_move_left # Horizontal mover can move into dots &1bc9 c9 02 CMP #&02 ; PIECE_MAGUS &1bcb d0 08 BNE &1bd5 ; not_magus # Horizontal mover can move into Magus ; horizontal_mover_moving_into_player &1bcd a0 00 LDY #&00 # Use first explosion slot for mover &1bcf 99 09 1f STA &1f09,Y ; explosions_or_mover_destroyed # Note that mover destroyed player &1bd2 4c e7 1b JMP &1be7 ; horizontal_mover_can_move_left ; not_magus &1bd5 c9 03 CMP #&03 ; PIECE_QUESTOR &1bd7 f0 f4 BEQ &1bcd ; horizontal_mover_moving_into_player # Horizontal mover can move into Questor &1bd9 c9 09 CMP #&09 ; PIECE_H_BOMB &1bdb f0 2b BEQ &1c08 ; horizontal_mover_moving_into_h_bomb # Horizontal mover can move into H-bomb &1bdd c9 0a CMP #&0a ; PIECE_V_BOMB &1bdf f0 70 BEQ &1c51 ; horizontal_mover_can_move_left # Horizontal mover can move into V-bomb &1be1 4c 90 13 JMP &1390 ; main_game_loop # Horizontal mover is stopped by all other pieces ; to_continue_moving_mover &1be4 4c e2 19 JMP &19e2 ; continue_moving_mover ; horizontal_mover_can_move_left &1be7 20 76 1a JSR &1a76 ; consider_mover_right # Is there a mover to the right of this mover? &1bea 20 4f 1a JSR &1a4f ; consider_mover_above # Is there a mover above this mover? &1bed 20 f2 19 JSR &19f2 ; move_mover # Move the mover left &1bf0 a5 a8 LDA &a8 ; mover_tile_address_low &1bf2 38 SEC &1bf3 e9 02 SBC #&02 &1bf5 85 a8 STA &a8 ; mover_tile_address_low &1bf7 a5 a9 LDA &a9 ; mover_tile_address_high &1bf9 e9 00 SBC #&00 &1bfb 85 a9 STA &a9 ; mover_tile_address_high &1bfd a0 00 LDY #&00 &1bff b1 a8 LDA (&a8),Y ; mover_tile_address # Consider the piece to the left of the destination &1c01 c9 05 CMP #&05 ; PIECE_DOTS &1c03 f0 df BEQ &1be4 ; to_continue_moving_mover # Horizontal mover can keep moving into dots &1c05 4c cb 19 JMP &19cb ; check_if_mover_can_continue_moving # space, players, and bombs ; horizontal_mover_moving_into_h_bomb &1c08 a9 03 LDA #&03 ; Y # H-bomb has yellow explosion &1c0a 8d 46 22 STA &2246 ; flash_colour &1c0d 20 76 1a JSR &1a76 ; consider_mover_right # Is there a mover right of the detonator? &1c10 20 4f 1a JSR &1a4f ; consider_mover_above # Is there a mover above the detonator? &1c13 a9 01 LDA #&01 &1c15 85 6c STA &6c ; count ; check_for_movers_loop &1c17 38 SEC &1c18 a5 a8 LDA &a8 ; mover_tile_address_low &1c1a e9 01 SBC #&01 &1c1c 85 a8 STA &a8 ; mover_tile_address_low &1c1e a5 a9 LDA &a9 ; mover_tile_address_high &1c20 e9 00 SBC #&00 &1c22 85 a9 STA &a9 ; mover_tile_address_high &1c24 20 4f 1a JSR &1a4f ; consider_mover_above # Is there a mover above of the bomb? &1c27 c6 6c DEC &6c ; count &1c29 a5 6c LDA &6c ; count &1c2b f0 ea BEQ &1c17 ; check_for_movers_loop # Is there a mover above the left explosion? &1c2d a0 00 LDY #&00 &1c2f 20 0e 1f JSR &1f0e ; flash_explosion_and_check_for_damage # Has the left explosion destroyed a player or switch? &1c32 a5 a8 LDA &a8 ; mover_tile_address_low &1c34 29 1f AND #&1f &1c36 c9 00 CMP #&00 &1c38 f0 05 BEQ &1c3f ; skip_left_side # If left explosion isn't left edge of level, &1c3a a9 00 LDA #&00 ; PIECE_SPACE &1c3c a8 TAY &1c3d 91 a8 STA (&a8),Y ; mover_tile_address # Replace left explosion with space ; skip_left_side &1c3f a9 00 LDA #&00 &1c41 a8 TAY &1c42 c8 INY &1c43 91 a8 STA (&a8),Y ; mover_tile_address # Replace bomb with space &1c45 c8 INY &1c46 91 a8 STA (&a8),Y ; mover_tile_address # Replace right explosion with space &1c48 20 c3 18 JSR &18c3 ; update_map &1c4b 20 00 11 JSR &1100 ; plot_viewpoint &1c4e 4c 90 13 JMP &1390 ; main_game_loop ; horizontal_mover_moving_into_v_bomb &1c51 a9 02 LDA #&02 ; G # V-bomb has green explosion &1c53 8d 46 22 STA &2246 ; flash_colour &1c56 20 76 1a JSR &1a76 ; consider_mover_right # Is there a mover right of the detonator? &1c59 20 4f 1a JSR &1a4f ; consider_mover_above # Is there a mover above the detonator? &1c5c a5 a8 LDA &a8 ; mover_tile_address_low &1c5e 18 CLC &1c5f 69 1f ADC #&1f &1c61 85 a8 STA &a8 ; mover_tile_address_low &1c63 a5 a9 LDA &a9 ; mover_tile_address_high &1c65 69 00 ADC #&00 &1c67 85 a9 STA &a9 ; mover_tile_address_high &1c69 20 76 1a JSR &1a76 ; consider_mover_right # Is there a mover right of the bottom explosion? &1c6c a0 00 LDY #&00 &1c6e 20 0e 1f JSR &1f0e ; flash_explosion_and_check_for_damage # Has the bottom explosion destroyed a player or switch? &1c71 a5 a8 LDA &a8 ; mover_tile_address_low &1c73 38 SEC &1c74 e9 40 SBC #&40 &1c76 85 a8 STA &a8 ; mover_tile_address_low &1c78 a5 a9 LDA &a9 ; mover_tile_address_high &1c7a e9 00 SBC #&00 &1c7c 85 a9 STA &a9 ; mover_tile_address_high &1c7e 20 76 1a JSR &1a76 ; consider_mover_right # Is there a mover right of the top explosion? &1c81 20 4f 1a JSR &1a4f ; consider_mover_above # Is there a mover above the top explosion? &1c84 a0 01 LDY #&01 &1c86 20 0e 1f JSR &1f0e ; flash_explosion_and_check_for_damage # Has the top explosion destroyed a player or switch? &1c89 a0 00 LDY #&00 ; PIECE_SPACE &1c8b a5 a9 LDA &a9 ; mover_tile_address_high &1c8d c9 09 CMP #&09 &1c8f d0 06 BNE &1c97 ; remove_top_side &1c91 a5 a8 LDA &a8 ; mover_tile_address_low &1c93 29 e0 AND #&e0 &1c95 f0 03 BEQ &1c9a ; skip_top_side # If top explosion isn't top edge of level, ; remove_top_side &1c97 98 TYA &1c98 91 a8 STA (&a8),Y ; mover_tile_address # Replace top explosion with space ; skip_top_side &1c9a a9 00 LDA #&00 ; PIECE_SPACE &1c9c a0 20 LDY #&20 &1c9e 91 a8 STA (&a8),Y ; mover_tile_address # Replace bomb with space &1ca0 c8 INY &1ca1 91 a8 STA (&a8),Y ; mover_tile_address # Replace detonator with space &1ca3 a5 a8 LDA &a8 ; mover_tile_address_low &1ca5 85 aa STA &aa ; bomb_tile_address_low &1ca7 18 CLC &1ca8 69 40 ADC #&40 &1caa 85 a8 STA &a8 ; mover_tile_address_low &1cac a5 a9 LDA &a9 ; mover_tile_address_high &1cae 85 ab STA &ab ; bomb_tile_address_high &1cb0 69 00 ADC #&00 &1cb2 85 a9 STA &a9 ; mover_tile_address_high &1cb4 4c 92 1b JMP &1b92 ; consider_bottom_explosion # Consider replacing bottom explosion with space ; new_mover_tile_address_low &1cb7 ea ; new_mover_tile_address_high &1cb8 ea ; mover_origin_screen_address_low &1cb9 ea ; mover_origin_screen_address_high &1cba ea ; mover_destination_screen_address_low &1cbb ea ; mover_destination_screen_address_high &1cbc ea ; tile_y &1cbd ea ; tile_x &1cbe ea ; consider_space_vacated_by_player_moving_left &1cbf a0 00 LDY #&00 &1cc1 b1 70 LDA (&70),Y ; player_offset_tile_address # Consider the tile above the player &1cc3 c9 07 CMP #&07 ; PIECE_FISH &1cc5 f0 04 BEQ &1ccb ; add_mover_above # If it contains a fish, &1cc7 c9 09 CMP #&09 ; PIECE_H_BOMB &1cc9 d0 03 BNE &1cce ; skip_adding_mover_above # or an H-bomb, ; add_mover_above &1ccb 20 de 1c JSR &1cde ; add_mover_above_player # then add that as a mover ; skip_adding_mover_above &1cce a0 21 LDY #&21 &1cd0 b1 70 LDA (&70),Y ; player_offset_tile_address # Consider the tile right of the player &1cd2 c9 08 CMP #&08 ; PIECE_CHICKEN &1cd4 f0 04 BEQ &1cda ; add_mover_right # If it contains a chicken &1cd6 c9 0a CMP #&0a ; PIECE_V_BOMB &1cd8 d0 03 BNE &1cdd ; skip_mover_right # or an V-bomb, ; add_mover_right &1cda 20 ec 1c JSR &1cec ; add_mover_right_of_player # then add that as a mover ; skip_mover_right &1cdd 60 RTS ; add_mover_above_player &1cde a5 70 LDA &70 ; player_offset_tile_address_low &1ce0 8d b7 1c STA &1cb7 ; new_mover_tile_address_low &1ce3 a5 71 LDA &71 ; player_offset_tile_address_high &1ce5 8d b8 1c STA &1cb8 ; new_mover_tile_address_high &1ce8 20 2e 19 JSR &192e ; add_mover # Add mover above player &1ceb 60 RTS ; add_mover_right_of_player &1cec a5 70 LDA &70 ; player_offset_tile_address_low &1cee 18 CLC &1cef 69 21 ADC #&21 &1cf1 8d b7 1c STA &1cb7 ; new_mover_tile_address_low &1cf4 a5 71 LDA &71 ; player_offset_tile_address_high &1cf6 69 00 ADC #&00 &1cf8 8d b8 1c STA &1cb8 ; new_mover_tile_address_high &1cfb 20 2e 19 JSR &192e ; add_mover # Add mover right of player &1cfe 60 RTS ; consider_space_vacated_by_player_moving_right &1cff a0 00 LDY #&00 &1d01 b1 70 LDA (&70),Y ; player_offset_tile_address # Consider the tile above the player &1d03 c9 07 CMP #&07 ; PIECE_FISH &1d05 f0 04 BEQ &1d0b ; add_mover_above # If it contains a fish, &1d07 c9 09 CMP #&09 ; PIECE_H_BOMB &1d09 d0 03 BNE &1d0e ; skip_adding_mover_above # or an H-bomb, ; add_mover_above &1d0b 20 de 1c JSR &1cde ; add_mover_above_player # then add that as a mover ; skip_adding_mover_above &1d0e 60 RTS ; consider_space_vacated_by_player_moving_up &1d0f a0 21 LDY #&21 &1d11 b1 70 LDA (&70),Y ; player_offset_tile_address # Consider the tile right of the player &1d13 c9 08 CMP #&08 ; PIECE_CHICKEN &1d15 f0 04 BEQ &1d1b ; add_mover_right # If it contains a chicken &1d17 c9 0a CMP #&0a ; PIECE_V_BOMB &1d19 d0 03 BNE &1d1e ; skip_mover_right # or an V-bomb, ; add_mover_right &1d1b 20 ec 1c JSR &1cec ; add_mover_right_of_player # then add that as a mover ; skip_mover_right &1d1e 60 RTS ; consider_space_vacated_by_player_moving_down &1d1f a0 21 LDY #&21 &1d21 b1 70 LDA (&70),Y ; player_offset_tile_address # Consider the tile right of the player &1d23 c9 08 CMP #&08 ; PIECE_CHICKEN &1d25 f0 04 BEQ &1d2b ; add_mover_right # If it contains a chicken &1d27 c9 0a CMP #&0a ; PIECE_V_BOMB &1d29 d0 03 BNE &1d2e ; skip_mover_right # or an V-bomb, ; add_mover_right &1d2b 20 ec 1c JSR &1cec ; add_mover_right_of_player # then add that as a mover ; skip_mover_right &1d2e a0 00 LDY #&00 &1d30 b1 70 LDA (&70),Y ; player_offset_tile_address # Consider the tile above the player &1d32 c9 07 CMP #&07 ; PIECE_FISH &1d34 f0 04 BEQ &1d3a ; add_mover_above # If it contains a fish, &1d36 c9 09 CMP #&09 ; PIECE_H_BOMB &1d38 d0 03 BNE &1d3d ; skip_adding_mover_above # or an H-bomb, ; add_mover_above &1d3a 20 de 1c JSR &1cde ; add_mover_above_player # then add that as a mover ; skip_adding_mover_above &1d3d 60 RTS ; level_completed &1d3e a9 01 LDA #&01 # Leave with non-zero to indicate level completed &1d40 60 RTS ; collect_mask &1d41 48 PHA &1d42 98 TYA &1d43 48 PHA &1d44 8a TXA &1d45 48 PHA &1d46 20 f3 21 JSR &21f3 ; plot_masks_collected &1d49 a9 01 LDA #&01 &1d4b 8d 54 1d STA &1d54 ; mask_was_collected # Set to non-zero to indicate mask collected &1d4e 68 PLA &1d4f aa TAX &1d50 68 PLA &1d51 a8 TAY &1d52 68 PLA &1d53 60 RTS ; mask_was_collected &1d54 ea ; check_if_player_can_push_left &1d55 a0 1e LDY #&1e &1d57 b1 70 LDA (&70),Y ; player_offset_tile_address # Consider the tile two to the left of player &1d59 f0 0b BEQ &1d66 ; can_push_left # Player can push any piece into space &1d5b a6 af LDX &af ; mover_is_doll &1d5d d0 04 BNE &1d63 ; can't_push_left # Non-zero if mover is doll &1d5f c9 05 CMP #&05 ; PIECE_DOTS &1d61 f0 03 BEQ &1d66 ; can_push_left # Player can push all pieces but dolls into dots ; can't_push_left &1d63 a2 01 LDX #&01 # Leave with X non-zero to indicate player can't push &1d65 60 RTS ; can_push_left &1d66 c8 INY &1d67 b1 70 LDA (&70),Y ; player_offset_tile_address # Copy the pushed piece &1d69 88 DEY &1d6a 91 70 STA (&70),Y ; player_offset_tile_address # into the tile to its left &1d6c a9 00 LDA #&00 ; PIECE_SPACE &1d6e c8 INY &1d6f 91 70 STA (&70),Y ; player_offset_tile_address # Replace the pushed piece with space &1d71 a0 3e LDY #&3e # Consider the tile two left, one below the player &1d73 a5 af LDA &af ; mover_is_doll &1d75 f0 02 BEQ &1d79 ; not_doll # Non-zero if mover is doll &1d77 a0 1d LDY #&1d # Consider the tile three to the left of the player ; not_doll &1d79 b1 70 LDA (&70),Y ; player_offset_tile_address &1d7b f0 0b BEQ &1d88 ; keep_piece_pushed_left_active # All pieces stay active if space &1d7d a4 af LDY &af ; mover_is_doll &1d7f d0 19 BNE &1d9a ; leave_after_plotting_viewpoint # Non-zero if mover is doll &1d81 c9 06 CMP #&06 ; PIECE_WAVES &1d83 f0 03 BEQ &1d88 ; keep_piece_pushed_left_active # All pieces but dolls stay active if waves &1d85 4c 9a 1d JMP &1d9a ; leave_after_plotting_viewpoint ; keep_piece_pushed_left_active &1d88 a5 70 LDA &70 ; player_offset_tile_address_low &1d8a 18 CLC &1d8b 69 1e ADC #&1e &1d8d 8d b7 1c STA &1cb7 ; new_mover_tile_address_low &1d90 a5 71 LDA &71 ; player_offset_tile_address_high &1d92 69 00 ADC #&00 &1d94 8d b8 1c STA &1cb8 ; new_mover_tile_address_high &1d97 20 2e 19 JSR &192e ; add_mover # Add pushed piece as mover ; leave_after_plotting_viewpoint &1d9a 20 00 11 JSR &1100 ; plot_viewpoint &1d9d a2 00 LDX #&00 # Leave with X zero to indicate player can push &1d9f 60 RTS ; check_if_player_can_push_right &1da0 a0 22 LDY #&22 &1da2 b1 70 LDA (&70),Y ; player_offset_tile_address # Consider the tile two to the right of player &1da4 f0 0b BEQ &1db1 ; can_push_right # Player can push any piece into space &1da6 a6 af LDX &af ; mover_is_doll &1da8 d0 04 BNE &1dae ; can't_push_right # Non-zero if mover is doll &1daa c9 05 CMP #&05 ; PIECE_DOTS &1dac f0 03 BEQ &1db1 ; can_push_right # Player can push all pieces but dolls into dots ; can't_push_right &1dae a2 01 LDX #&01 # Leave with X non-zero to indicate player can't push &1db0 60 RTS ; can_push_right &1db1 88 DEY &1db2 b1 70 LDA (&70),Y ; player_offset_tile_address # Copy the pushed piece &1db4 c8 INY &1db5 91 70 STA (&70),Y ; player_offset_tile_address # into the tile to its right &1db7 88 DEY &1db8 a9 00 LDA #&00 ; PIECE_SPACE &1dba 91 70 STA (&70),Y ; player_offset_tile_address # Replace the pushed piece with space &1dbc a0 42 LDY #&42 # Consider the tile two right, one below the player &1dbe a5 af LDA &af ; mover_is_doll &1dc0 f0 02 BEQ &1dc4 ; not_doll # Non-zero if mover is doll &1dc2 a0 23 LDY #&23 # Consider the tile three to the right of the player ; not_doll &1dc4 b1 70 LDA (&70),Y ; player_offset_tile_address &1dc6 f0 0b BEQ &1dd3 ; keep_piece_pushed_right_active # All pieces stay active if space &1dc8 a6 af LDX &af ; mover_is_doll &1dca d0 19 BNE &1de5 ; leave_after_plotting_viewpoint # Non-zero if mover is doll &1dcc c9 06 CMP #&06 ; PIECE_WAVES &1dce f0 03 BEQ &1dd3 ; keep_piece_pushed_right_active # All pieces but dolls stay active if waves &1dd0 4c e5 1d JMP &1de5 ; leave_after_plotting_viewpoint ; keep_piece_pushed_right_active &1dd3 a5 70 LDA &70 ; player_offset_tile_address_low &1dd5 18 CLC &1dd6 69 22 ADC #&22 &1dd8 8d b7 1c STA &1cb7 ; new_mover_tile_address_low &1ddb a5 71 LDA &71 ; player_offset_tile_address_high &1ddd 69 00 ADC #&00 &1ddf 8d b8 1c STA &1cb8 ; new_mover_tile_address_high &1de2 20 2e 19 JSR &192e ; add_mover # Add pushed piece as mover ; leave_after_plotting_viewpoint &1de5 20 00 11 JSR &1100 ; plot_viewpoint &1de8 a2 00 LDX #&00 # Leave with X zero to indicate player can push &1dea 60 RTS ; check_if_player_can_push_up &1deb a5 70 LDA &70 ; player_offset_tile_address_low &1ded 38 SEC &1dee e9 21 SBC #&21 &1df0 85 aa STA &aa ; push_offset_tile_address_low &1df2 a5 71 LDA &71 ; player_offset_tile_address_high &1df4 e9 00 SBC #&00 &1df6 85 ab STA &ab ; push_offset_tile_address_high &1df8 a0 01 LDY #&01 &1dfa b1 aa LDA (&aa),Y ; push_offset_tile_address # Consider the tile two above player &1dfc f0 0b BEQ &1e09 ; can_push_up # Player can push any piece into space &1dfe a6 af LDX &af ; mover_is_doll &1e00 d0 04 BNE &1e06 ; can't_push_up # Non-zero if mover is doll &1e02 c9 06 CMP #&06 ; PIECE_WAVES &1e04 f0 03 BEQ &1e09 ; can_push_up # Player can push all pieces but dolls into dots ; can't_push_up &1e06 a2 01 LDX #&01 # Leave with X non-zero to indicate player can't push &1e08 60 RTS ; can_push_up &1e09 a0 21 LDY #&21 &1e0b b1 aa LDA (&aa),Y ; push_offset_tile_address # Copy the pushed piece &1e0d a0 01 LDY #&01 &1e0f 91 aa STA (&aa),Y ; push_offset_tile_address # into the tile above it &1e11 a0 21 LDY #&21 &1e13 a9 00 LDA #&00 ; PIECE_SPACE &1e15 91 aa STA (&aa),Y ; push_offset_tile_address # Replace the pushed piece with space &1e17 a4 af LDY &af ; mover_is_doll &1e19 f0 16 BEQ &1e31 ; not_doll # Non-zero if mover is doll &1e1b a5 aa LDA &aa ; push_offset_tile_address_low &1e1d 38 SEC &1e1e e9 20 SBC #&20 &1e20 85 a8 STA &a8 ; mover_tile_address_low &1e22 a5 ab LDA &ab ; push_offset_tile_address_high &1e24 e9 00 SBC #&00 &1e26 85 a9 STA &a9 ; mover_tile_address_high &1e28 a0 01 LDY #&01 &1e2a b1 a8 LDA (&a8),Y ; mover_tile_address # Consider the tile three above the player &1e2c d0 21 BNE &1e4f ; leave_after_plotting_viewpoint &1e2e 4c 40 1e JMP &1e40 ; keep_piece_pushed_up_active # Dolls stay active if space ; not_doll &1e31 b1 aa LDA (&aa),Y ; push_offset_tile_address # Consider the tile two above, one left of the player &1e33 f0 0b BEQ &1e40 ; keep_piece_pushed_up_active # All pieces but dolls stay active if space &1e35 a6 af LDX &af ; mover_is_doll &1e37 d0 16 BNE &1e4f ; leave_after_plotting_viewpoint # Unnecessary code; never branches &1e39 c9 05 CMP #&05 ; PIECE_DOTS &1e3b f0 03 BEQ &1e40 ; keep_piece_pushed_up_active # All pieces but dolls stay active if dots &1e3d 4c 4f 1e JMP &1e4f ; leave_after_plotting_viewpoint ; keep_piece_pushed_up_active &1e40 a6 aa LDX &aa ; push_offset_tile_address_low &1e42 e8 INX &1e43 8a TXA &1e44 8d b7 1c STA &1cb7 ; new_mover_tile_address_low &1e47 a5 ab LDA &ab ; push_offset_tile_address_high &1e49 8d b8 1c STA &1cb8 ; new_mover_tile_address_high &1e4c 20 2e 19 JSR &192e ; add_mover # Add pushed piece as mover ; leave_after_plotting_viewpoint &1e4f 20 00 11 JSR &1100 ; plot_viewpoint &1e52 a2 00 LDX #&00 # Leave with X zero to indicate player can push &1e54 60 RTS ; check_if_player_can_push_down &1e55 a0 60 LDY #&60 &1e57 b1 70 LDA (&70),Y ; player_offset_tile_address # Consider the tile two below player &1e59 f0 0b BEQ &1e66 ; can_push_down # Player can push any piece into space &1e5b a6 af LDX &af ; mover_is_doll &1e5d d0 04 BNE &1e63 ; can't_push_down # Non-zero if mover is doll &1e5f c9 06 CMP #&06 ; PIECE_WAVES &1e61 f0 03 BEQ &1e66 ; can_push_down # Player can push all pieces but dolls into dots ; can't_push_down &1e63 a2 01 LDX #&01 # Leave with X non-zero to indicate player can't push &1e65 60 RTS ; can_push_down &1e66 a0 40 LDY #&40 &1e68 b1 70 LDA (&70),Y ; player_offset_tile_address # Copy the pushed piece &1e6a a0 60 LDY #&60 &1e6c 91 70 STA (&70),Y ; player_offset_tile_address # into the tile below it &1e6e a0 40 LDY #&40 &1e70 a9 00 LDA #&00 ; PIECE_SPACE &1e72 91 70 STA (&70),Y ; player_offset_tile_address # Replace the pushed piece with space &1e74 a0 5f LDY #&5f # Consider the tile two below, one left of the player &1e76 a5 af LDA &af ; mover_is_doll &1e78 f0 02 BEQ &1e7c ; not_doll # Non-zero if mover is doll &1e7a a0 80 LDY #&80 # Consider the tile three below the player ; not_doll &1e7c b1 70 LDA (&70),Y ; player_offset_tile_address &1e7e f0 0b BEQ &1e8b ; keep_piece_pushed_down_active # All pieces stay active if space &1e80 a6 af LDX &af ; mover_is_doll &1e82 d0 19 BNE &1e9d ; leave_after_plotting_viewpoint # Non-zero if mover is doll &1e84 c9 05 CMP #&05 ; PIECE_DOTS &1e86 f0 03 BEQ &1e8b ; keep_piece_pushed_down_active # All pieces but dolls stay active if dots &1e88 4c 9d 1e JMP &1e9d ; leave_after_plotting_viewpoint ; keep_piece_pushed_down_active &1e8b a5 70 LDA &70 ; player_offset_tile_address_low &1e8d 18 CLC &1e8e 69 60 ADC #&60 &1e90 8d b7 1c STA &1cb7 ; new_mover_tile_address_low &1e93 a5 71 LDA &71 ; player_offset_tile_address_high &1e95 69 00 ADC #&00 &1e97 8d b8 1c STA &1cb8 ; new_mover_tile_address_high &1e9a 20 2e 19 JSR &192e ; add_mover # Add pushed piece as mover ; leave_after_plotting_viewpoint &1e9d 20 00 11 JSR &1100 ; plot_viewpoint &1ea0 a2 00 LDX #&00 # Leave with X zero to indicate player can push &1ea2 60 RTS ; delay &1ea3 a8 TAY ; delay_outer_loop &1ea4 a2 ff LDX #&ff ; delay_inner_loop &1ea6 ea NOP &1ea7 ea NOP &1ea8 ca DEX &1ea9 d0 fb BNE &1ea6 ; delay_inner_loop &1eab 88 DEY &1eac d0 f6 BNE &1ea4 ; delay_outer_loop &1eae 60 RTS ; check_if_explosion_or_mover_destroyed_player &1eaf 84 95 STY &95 ; explosion_side # Zero for mover or first explosion, one for second &1eb1 b9 09 1f LDA &1f09,Y ; explosions_or_mover_destroyed # Non-zero if explosion destroyed player &1eb4 f0 3e BEQ &1ef4 ; skip_checking_player &1eb6 a6 91 LDX &91 ; other_player_state # Zero if other player is dead &1eb8 d0 06 BNE &1ec0 ; explosion_destroyed_player &1eba 20 a9 24 JSR &24a9 ; plot_gotcha # "GOTCHA" if both players have been destroyed &1ebd 4c 0b 1f JMP &1f0b ; level_failed ; explosion_destroyed_player &1ec0 ca DEX &1ec1 86 91 STX &91 ; other_player_state # Set to zero to indicate player is dead &1ec3 c9 02 CMP #&02 ; PIECE_MAGUS &1ec5 f0 13 BEQ &1eda ; explosion_destroyed_magus ; explosion_destroyed_questor &1ec7 a5 90 LDA &90 ; current_player &1ec9 c9 02 CMP #&02 ; PIECE_MAGUS &1ecb f0 20 BEQ &1eed ; explosion_destroyed_other_player ; explosion_destroyed_active_questor &1ecd a9 00 LDA #&00 &1ecf a4 95 LDY &95 ; explosion_side &1ed1 99 09 1f STA &1f09,Y ; explosions_or_mover_destroyed # Reset to zero &1ed4 20 c6 24 JSR &24c6 ; plot_whoops # "WHOOPS" if one player has been destroyed &1ed7 4c 6f 17 JMP &176f ; swap_from_questor ; explosion_destroyed_magus &1eda a5 90 LDA &90 ; current_player &1edc c9 03 CMP #&03 ; PIECE_QUESTOR &1ede f0 0d BEQ &1eed ; explosion_destroyed_other_player ; explosion_destroyed_active_magus &1ee0 a9 00 LDA #&00 &1ee2 a4 95 LDY &95 ; explosion_side &1ee4 99 09 1f STA &1f09,Y ; explosions_or_mover_destroyed # Reset to zero &1ee7 20 c6 24 JSR &24c6 ; plot_whoops # "WHOOPS" if one player has been destroyed &1eea 4c b7 17 JMP &17b7 ; swap_from_magus ; explosion_destroyed_other_player &1eed a9 00 LDA #&00 &1eef a4 95 LDY &95 ; explosion_side &1ef1 99 09 1f STA &1f09,Y ; explosions_or_mover_destroyed # Reset to zero ; skip_checking_player &1ef4 ad 04 21 LDA &2104 ; too_many_moves &1ef7 f0 06 BEQ &1eff ; not_too_many_moves # Non-zero if too many moves &1ef9 20 8a 24 JSR &248a ; plot_too_many_moves &1efc 4c 0b 1f JMP &1f0b ; level_failed ; not_too_many_moves &1eff a4 95 LDY &95 ; explosion_side &1f01 f0 03 BEQ &1f06 ; to_check_other_explosion_side &1f03 4c a2 13 JMP &13a2 ; consider_updating_movers ; to_check_other_explosion_side &1f06 4c 9d 13 JMP &139d ; check_other_explosion_side ; explosions_or_mover_destroyed &1f09 00 00 ; level_failed &1f0b a9 00 LDA #&00 # Leave with zero to indicate level was not completed &1f0d 60 RTS ; flash_explosion_and_check_for_damage &1f0e 84 95 STY &95 ; explosion_side &1f10 20 1e 22 JSR &221e ; flash_screen # Set colour 0 to explosion colour &1f13 a9 0f LDA #&0f &1f15 20 a3 1e JSR &1ea3 ; delay &1f18 20 1e 22 JSR &221e ; flash_screen # Set colour 0 to black &1f1b a0 00 LDY #&00 &1f1d b1 a8 LDA (&a8),Y ; mover_tile_address # Consider the explosion tile &1f1f c9 02 CMP #&02 ; PIECE_MAGUS &1f21 d0 05 BNE &1f28 ; not_magus &1f23 a4 95 LDY &95 ; explosion_side &1f25 99 09 1f STA &1f09,Y ; explosions_or_mover_destroyed # Note that Magus was destroyed by explosion ; not_magus &1f28 c9 03 CMP #&03 ; PIECE_QUESTOR &1f2a d0 05 BNE &1f31 ; not_questor &1f2c a4 95 LDY &95 ; explosion_side &1f2e 99 09 1f STA &1f09,Y ; explosions_or_mover_destroyed # Note that Questor was destroyed by explosion ; not_questor &1f31 c9 0f CMP #&0f ; PIECE_SWITCH &1f33 d0 03 BNE &1f38 ; not_switch &1f35 20 73 20 JSR &2073 ; toggle_switch # Toggle switch destroyed by explosion ; not_switch &1f38 60 RTS ; consider_teleporting_player &1f39 a5 70 LDA &70 ; player_offset_tile_address_low &1f3b 18 CLC &1f3c 65 ac ADC &ac ; player_movement_offset # Calculate the address of the teleport being entered &1f3e 85 ad STA &ad ; player_new_tile_address_low &1f40 a5 71 LDA &71 ; player_offset_tile_address_high &1f42 69 00 ADC #&00 &1f44 85 ae STA &ae ; player_new_tile_address_high &1f46 a2 00 LDX #&00 &1f48 b5 98 LDA &98,X ; teleports_tile_addresses &1f4a c5 ad CMP &ad ; player_new_tile_address_low # Is the player entering the first teleport? &1f4c d0 0e BNE &1f5c ; entering_second_teleport &1f4e e8 INX &1f4f b5 98 LDA &98,X ; teleports_tile_addresses &1f51 c5 ae CMP &ae ; player_new_tile_address_high &1f53 d0 07 BNE &1f5c ; entering_second_teleport ; entering_first_teleport &1f55 a0 08 LDY #&08 # If so, use the second teleport as the destination &1f57 84 6c STY &6c ; destination_teleport_offset &1f59 4c 60 1f JMP &1f60 ; consider_destination_teleport ; entering_second_teleport &1f5c a0 00 LDY #&00 # Otherwise, use the first teleport as the destination &1f5e 84 6c STY &6c ; destination_teleport_offset ; consider_destination_teleport &1f60 a6 6c LDX &6c ; destination_teleport_offset &1f62 b5 98 LDA &98,X ; teleports_tile_addresses &1f64 38 SEC &1f65 e9 20 SBC #&20 &1f67 85 5e STA &5e ; destination_offset_tile_address_low &1f69 e8 INX &1f6a b5 98 LDA &98,X ; teleports_tile_addresses &1f6c e9 00 SBC #&00 &1f6e 85 5f STA &5f ; destination_offset_tile_address_high &1f70 a0 21 LDY #&21 &1f72 b1 5e LDA (&5e),Y ; destination_offset_tile_address # Consider the tile to the right of the destination &1f74 f0 4d BEQ &1fc3 ; exit_destination_teleport # Player leaves teleport to right if empty &1f76 a0 00 LDY #&00 &1f78 b1 5e LDA (&5e),Y ; destination_offset_tile_address # Consider the tile above the destination &1f7a f0 47 BEQ &1fc3 ; exit_destination_teleport # Player leaves teleport upwards if empty &1f7c a0 1f LDY #&1f &1f7e b1 5e LDA (&5e),Y ; destination_offset_tile_address # Consider the tile to the left of the destination &1f80 f0 41 BEQ &1fc3 ; exit_destination_teleport # Player leaves teleport to left if empty &1f82 a0 40 LDY #&40 &1f84 b1 5e LDA (&5e),Y ; destination_offset_tile_address # Consider the tile below the destination &1f86 f0 3b BEQ &1fc3 ; exit_destination_teleport # Player leaves teleport downwards if empty ; destination_teleport_blocked &1f88 a4 6c LDY &6c ; destination_teleport_offset &1f8a a5 76 LDA &76 ; viewpoint_tile_address_low # Store viewpoint prior to entering teleport &1f8c 8d 46 20 STA &2046 ; previous_viewpoint_tile_address_low &1f8f a5 77 LDA &77 ; viewpoint_tile_address_high &1f91 8d 47 20 STA &2047 ; previous_viewpoint_tile_address_high &1f94 c0 08 CPY #&08 &1f96 f0 0b BEQ &1fa3 ; use_viewpoint_for_second_teleport ; use_viewpoint_for_first_teleport &1f98 a5 9e LDA &9e ; teleport_viewpoints_tile_address_low # Use viewpoint for first teleport &1f9a 85 76 STA &76 ; viewpoint_tile_address_low &1f9c a5 9f LDA &9f ; teleport_viewpoints_tile_address_high &1f9e 85 77 STA &77 ; viewpoint_tile_address_high &1fa0 4c ab 1f JMP &1fab ; use_viewpoint ; use_viewpoint_for_second_teleport &1fa3 a5 a6 LDA &a6 ; teleport_viewpoints_tile_address_low + 8 # Use viewpoint for second teleport &1fa5 85 76 STA &76 ; viewpoint_tile_address_low &1fa7 a5 a7 LDA &a7 ; teleport_viewpoints_tile_address_high + 8 &1fa9 85 77 STA &77 ; viewpoint_tile_address_high ; use_viewpoint &1fab 20 00 11 JSR &1100 ; plot_viewpoint # Plot destination viewpoint &1fae a9 ff LDA #&ff &1fb0 20 a3 1e JSR &1ea3 ; delay &1fb3 ad 46 20 LDA &2046 ; previous_viewpoint_tile_address_low # Restore original viewpoint &1fb6 85 76 STA &76 ; viewpoint_tile_address_low &1fb8 ad 47 20 LDA &2047 ; previous_viewpoint_tile_address_high &1fbb 85 77 STA &77 ; viewpoint_tile_address_high &1fbd 20 00 11 JSR &1100 ; plot_viewpoint # Plot original viewpoint &1fc0 a2 01 LDX #&01 # Leave with X non-zero to indicate unable to move &1fc2 60 RTS ; exit_destination_teleport &1fc3 98 TYA &1fc4 aa TAX &1fc5 a5 70 LDA &70 ; player_offset_tile_address_low &1fc7 85 60 STA &60 ; previous_player_offset_tile_address_low &1fc9 a5 71 LDA &71 ; player_offset_tile_address_high &1fcb 85 61 STA &61 ; previous_player_offset_tile_address_high &1fcd 8e 48 20 STX &2048 ; teleport_exit_movement_offset &1fd0 a5 6c LDA &6c ; destination_teleport_offset &1fd2 f0 0e BEQ &1fe2 ; exiting_first_teleport ; exiting_second_teleport &1fd4 a2 00 LDX #&00 ; copy_second_teleport_data_loop &1fd6 b5 a0 LDA &a0,X ; teleports_address_offsets_and_viewpoint + 8 &1fd8 95 70 STA &70,X ; player_address_offsets_and_viewpoint # Use second teleport address (not offset) and viewpoint &1fda e8 INX &1fdb e0 08 CPX #&08 &1fdd d0 f7 BNE &1fd6 ; copy_second_teleport_data_loop &1fdf 4c ed 1f JMP &1fed ; exiting_teleport ; exiting_first_teleport &1fe2 a2 00 LDX #&00 ; copy_first_teleport_data_loop &1fe4 b5 98 LDA &98,X ; teleports_address_offsets_and_viewpoint &1fe6 95 70 STA &70,X ; player_address_offsets_and_viewpoint # Use first teleport address (not offset) and viewpoint &1fe8 e8 INX &1fe9 e0 08 CPX #&08 &1feb d0 f7 BNE &1fe4 ; copy_first_teleport_data_loop ; exiting_teleport &1fed a5 5e LDA &5e ; destination_offset_tile_address_low &1fef a2 00 LDX #&00 &1ff1 18 CLC &1ff2 6d 48 20 ADC &2048 ; teleport_exit_movement_offset # Move player out of destination teleport &1ff5 95 70 STA &70,X ; player_address_offsets_and_viewpoint &1ff7 e8 INX &1ff8 a5 5f LDA &5f ; destination_offset_tile_address_high &1ffa 69 00 ADC #&00 &1ffc 95 70 STA &70,X ; player_address_offsets_and_viewpoint &1ffe a5 70 LDA &70 ; player_offset_tile_address_low &2000 38 SEC &2001 e9 20 SBC #&20 # Apply offset to player's address &2003 85 70 STA &70 ; player_offset_tile_address_low &2005 a5 71 LDA &71 ; player_offset_tile_address_high &2007 e9 00 SBC #&00 &2009 85 71 STA &71 ; player_offset_tile_address_high &200b ad 48 20 LDA &2048 ; teleport_exit_movement_offset # Consider direction player is leaving teleport &200e d0 04 BNE &2014 ; not_leaving_teleport_up &2010 c6 73 DEC &73 ; player_y_offset &2012 a5 6c LDA &6c ; destination_teleport_offset # Unnecessary code ; not_leaving_teleport_up &2014 c9 21 CMP #&21 &2016 d0 02 BNE &201a ; not_leaving_teleport_right &2018 e6 72 INC &72 ; player_x_offset ; not_leaving_teleport_right &201a c9 1f CMP #&1f &201c d0 05 BNE &2023 ; not_leaving_teleport_left &201e c6 72 DEC &72 ; player_x_offset &2020 4c 29 20 JMP &2029 ; not_leaving_teleport_down # Unnecessary code ; not_leaving_teleport_left &2023 c9 40 CMP #&40 &2025 d0 02 BNE &2029 ; not_leaving_teleport_down &2027 e6 73 INC &73 ; player_y_offset ; not_leaving_teleport_down &2029 a2 00 LDX #&00 # Leave with X zero to indicate player moved &202b 60 RTS ; use_player_offset_for_entering_teleport &202c a5 70 LDA &70 ; player_offset_tile_address_low &202e 85 5e STA &5e ; destination_offset_tile_address_low &2030 a5 71 LDA &71 ; player_offset_tile_address_high &2032 85 5f STA &5f ; destination_offset_tile_address_high &2034 a5 60 LDA &60 ; previous_player_offset_tile_address_low &2036 85 70 STA &70 ; player_offset_tile_address_low &2038 a5 61 LDA &61 ; previous_player_offset_tile_address_high &203a 85 71 STA &71 ; player_offset_tile_address_high &203c 60 RTS ; use_player_offset_for_leaving_teleport &203d a5 5e LDA &5e ; destination_offset_tile_address_low &203f 85 70 STA &70 ; player_offset_tile_address_low &2041 a5 5f LDA &5f ; destination_offset_tile_address_high &2043 85 71 STA &71 ; player_offset_tile_address_high &2045 60 RTS ; previous_viewpoint_tile_address_low &2046 ea ; previous_viewpoint_tile_address_high &2047 ea ; teleport_exit_movement_offset &2048 ea ; unused &2049 ea ea ea ea ea ; check_teleports &204e a0 00 LDY #&00 &2050 b1 98 LDA (&98),Y ; teleports_tile_addresses # Consider the first teleport &2052 c9 0e CMP #&0e ; PIECE_TELEPORT &2054 f0 0a BEQ &2060 ; check_second_teleport # If it has been destroyed, &2056 a9 01 LDA #&01 ; PIECE_WALL &2058 91 a0 STA (&a0),Y ; teleports_tile_addresses + 8 # Replace the second teleport with a wall &205a 20 00 11 JSR &1100 ; plot_viewpoint &205d a2 01 LDX #&01 # Leave with X non-zero to indicate teleport is no good &205f 60 RTS ; check_second_teleport &2060 b1 a0 LDA (&a0),Y ; teleports_tile_addresses + 8 # Consider the second teleport &2062 c9 0e CMP #&0 ; PIECE_TELEPORT &2064 d0 03 BNE &2069 ; replace_first_teleport &2066 a2 00 LDX #&00 # Leave with X zero to indicate both teleports exist &2068 60 RTS ; replace_first_teleport &2069 a9 01 LDA #&01 ; PIECE_WALL &206b 91 98 STA (&98),Y ; teleports_tile_addresses # Replace the first teleport with a wall &206d 20 00 11 JSR &1100 ; plot_viewpoint &2070 a2 01 LDX #&01 # Leave with X non-zero to indicate teleport is no good &2072 60 RTS ; toggle_switch &2073 a4 96 LDY &96 ; switch_state # Non-zero if level is dark &2075 d0 12 BNE &2089 ; switch_on ; switch_off # If the level will be dark, &2077 a0 00 LDY #&00 &2079 98 TYA ; wipe_sprite_wall_loop # Wipe the wall sprite &207a 99 48 50 STA &5048,Y ; sprite_wall &207d c8 INY &207e c0 48 CPY #&48 &2080 d0 f8 BNE &207a ; wipe_sprite_wall_loop &2082 a0 01 LDY #&01 &2084 84 96 STY &96 ; switch_state # Set to non-zero to indicate level is dark &2086 4c 9a 20 JMP &209a ; leave_after_plotting_viewpoint ; switch_on # If the level will be lit, &2089 a0 00 LDY #&00 ; restore_sprite_wall_loop # Restore the wall sprite &208b b9 b0 55 LDA &55b0,Y ; sprite_wall_source &208e 99 48 50 STA &5048,Y ; sprite_wall &2091 c8 INY &2092 c0 48 CPY #&48 &2094 d0 f5 BNE &208b ; restore_sprite_wall_loop &2096 a0 00 LDY #&00 &2098 84 96 STY &96 ; switch_state # Set to zero to indicate level is lit ; leave_after_plotting_viewpoint &209a 20 00 11 JSR &1100 ; plot_viewpoint &209d 60 RTS ; update_doll &209e a5 a8 LDA &a8 ; mover_tile_address_low &20a0 38 SEC &20a1 e9 20 SBC #&20 # Apply offset to mover_tile_address &20a3 85 a8 STA &a8 ; mover_tile_address_low &20a5 a5 a9 LDA &a9 ; mover_tile_address_high &20a7 e9 00 SBC #&00 &20a9 85 a9 STA &a9 ; mover_tile_address_high &20ab a4 b0 LDY &b0 ; doll_direction_offset &20ad b1 a8 LDA (&a8),Y ; mover_tile_address # Consider the tile the doll is moving into &20af f0 03 BEQ &20b4 ; doll_can_move # Doll can move into space &20b1 4c 90 13 JMP &1390 ; main_game_loop # All other pieces stop doll ; doll_can_move &20b4 a5 a8 LDA &a8 ; mover_tile_address_low &20b6 18 CLC &20b7 65 b0 ADC &b0 ; doll_direction_offset &20b9 85 aa STA &aa ; mover_destination_tile_address_low &20bb a5 a9 LDA &a9 ; mover_tile_address_high &20bd 69 00 ADC #&00 &20bf 85 ab STA &ab ; mover_destination_tile_address_high &20c1 a5 a8 LDA &a8 ; mover_tile_address_low &20c3 18 CLC &20c4 69 20 ADC #&20 # Remove offset from mover_tile_address &20c6 85 a8 STA &a8 ; mover_tile_address_low &20c8 a5 a9 LDA &a9 ; doll_offset_tile_address_high &20ca 69 00 ADC #&00 &20cc 85 a9 STA &a9 ; mover_tile_address_high &20ce 20 f2 19 JSR &19f2 ; move_mover # Move doll &20d1 a5 aa LDA &aa ; mover_destination_tile_address_low &20d3 38 SEC &20d4 e9 20 SBC #&20 # Apply offset to mover_destination_tile_address &20d6 85 aa STA &aa ; mover_destination_tile_address_low &20d8 a5 ab LDA &ab ; mover_destination_tile_address_high &20da e9 00 SBC #&00 &20dc 85 ab STA &ab ; mover_destination_tile_address_high &20de a4 b0 LDY &b0 ; doll_direction_offset &20e0 b1 aa LDA (&aa),Y ; mover_destination_tile_address # Consider the tile beyond the destination &20e2 f0 03 BEQ &20e7 ; continue_moving_doll # Doll can keep moving into space &20e4 4c 90 13 JMP &1390 ; main_game_loop # All other pieces stop doll ; continue_moving_doll &20e7 a5 aa LDA &aa ; mover_destination_tile_address_low &20e9 18 CLC &20ea 69 20 ADC #&20 # Remove offset from mover_destination_tile_address &20ec 85 aa STA &aa ; mover_destination_tile_address_low &20ee a5 ab LDA &ab ; mover_destination_tile_address_high &20f0 69 00 ADC #&00 &20f2 85 ab STA &ab ; mover_destination_tile_address_high &20f4 4c e2 19 JMP &19e2 ; continue_moving_mover # Add destination tile to mover list ; unused # Source code fragment corresponding to &53a1 - &53a4 &20f7 43 2c 45 43 2c 45 43 2c 41 ; "C,EC,EC,A ; move_counter # Least significant byte first &2100 ea ea ea ea ; too_many_moves &2104 ea ; increment_move_counter &2105 a6 b1 LDX &b1 ; replaying # Non-zero if replaying level &2107 d0 05 BNE &210e ; skip_storing_move &2109 a6 b6 LDX &b6 ; move_direction &210b 20 4e 22 JSR &224e ; store_move ; skip_storing_move &210e ee 00 21 INC &2100 ; move_counter &2111 ad 00 21 LDA &2100 ; move_counter &2114 c9 0a CMP #&0a ; 10 &2116 d0 33 BNE &214b ; to_plot_move_counter &2118 a9 00 LDA #&00 &211a 8d 00 21 STA &2100 ; move_counter &211d ee 01 21 INC &2101 ; move_counter + 1 &2120 ad 01 21 LDA &2101 ; move_counter + 1 &2123 c9 0a CMP #&0a ; 10 &2125 d0 24 BNE &214b ; to_plot_move_counter &2127 a9 00 LDA #&00 &2129 8d 01 21 STA &2101 ; move_counter + 1 &212c ee 02 21 INC &2102 ; move_counter + 2 &212f ad 02 21 LDA &2102 ; move_counter + 2 &2132 c9 0a CMP #&0a ; 10 &2134 d0 15 BNE &214b ; to_plot_move_counter &2136 a9 00 LDA #&00 &2138 8d 02 21 STA &2102 ; move_counter + 2 &213b ee 03 21 INC &2103 ; move_counter + 3 &213e ad 03 21 LDA &2103 ; move_counter + 3 &2141 c9 02 CMP #&02 &2143 d0 06 BNE &214b ; to_plot_move_counter # If 2000 moves have been made, &2145 a9 01 LDA #&01 &2147 8d 04 21 STA &2104 ; too_many_moves # Set to non-zero to indicate too many moves &214a 60 RTS ; to_plot_move_counter &214b 20 4f 21 JSR &214f ; plot_move_counter &214e 60 RTS ; plot_move_counter &214f a9 73 LDA #&73 &2151 8d 8c 21 STA &218c ; number_screen_address_high &2154 a9 68 LDA #&68 &2156 8d 8b 21 STA &218b ; number_screen_address_low &2159 ad 00 21 LDA &2100 ; move_counter &215c 20 81 21 JSR &2181 ; plot_number # Plot fourth digit of move counter &215f a9 60 LDA #&60 &2161 8d 8b 21 STA &218b ; number_screen_address_low &2164 ad 01 21 LDA &2101 ; move_counter + 1 &2167 20 81 21 JSR &2181 ; plot_number # Plot third digit of move counter &216a a9 58 LDA #&58 &216c 8d 8b 21 STA &218b ; number_screen_address_low &216f ad 02 21 LDA &2102 ; move_counter + 2 &2172 20 81 21 JSR &2181 ; plot_number # Plot second digit of move counter &2175 a9 50 LDA #&50 &2177 8d 8b 21 STA &218b ; number_screen_address_low &217a ad 03 21 LDA &2103 ; move_counter + 3 &217d 20 81 21 JSR &2181 ; plot_number # Plot first digit of move counter &2180 60 RTS ; plot_number &2181 0a ASL A &2182 0a ASL A &2183 0a ASL A &2184 a8 TAY &2185 a2 00 LDX #&00 ; plot_number_loop &2187 b9 f8 55 LDA &55f8,Y ; number_sprites &218a 9d 00 80 STA &8000,X # actually STA number_screen_address,X &218d e8 INX &218e c8 INY &218f e0 08 CPX #&08 &2191 d0 f4 BNE &2187 ; plot_number_loop &2193 60 RTS ; initialise_and_plot_counters &2194 a9 00 LDA #&00 &2196 8d 00 21 STA &2100 ; move_counter &2199 8d 01 21 STA &2101 ; move_counter + 1 &219c 8d 02 21 STA &2102 ; move_counter + 2 &219f 8d 03 21 STA &2103 ; move_counter + 3 &21a2 8d 04 21 STA &2104 ; too_many_moves # Set to zero to indicate not too many moves &21a5 20 4f 21 JSR &214f ; plot_move_counter &21a8 a9 80 LDA #&80 &21aa 85 58 STA &58 ; screen_address_low &21ac a9 79 LDA #&79 &21ae 85 59 STA &59 ; screen_address_high &21b0 a9 0b LDA #&0b ; PIECE_MASK &21b2 20 2d 11 JSR &112d ; plot_sprite # Plot mask next to mask counter &21b5 a5 92 LDA &92 ; masks_total &21b7 a0 00 LDY #&00 &21b9 38 SEC ; calculate_masks_total_tens_loop &21ba c8 INY &21bb e9 0a SBC #&0a ; 10 &21bd b0 fb BCS &21ba ; calculate_masks_total_tens_loop &21bf 69 0a ADC #&0a ; 10 &21c1 8d 1d 22 STA &221d ; digit &21c4 88 DEY &21c5 a9 b0 LDA #&b0 &21c7 8d 8b 21 STA &218b ; number_screen_address_low &21ca a9 7a LDA #&7a &21cc 8d 8c 21 STA &218c ; number_screen_address_high &21cf 98 TYA &21d0 20 81 21 JSR &2181 ; plot_number # Plot first digit of total masks &21d3 a9 b8 LDA #&b8 &21d5 8d 8b 21 STA &218b ; number_screen_address_low &21d8 ad 1d 22 LDA &221d ; digit &21db 20 81 21 JSR &2181 ; plot_number # Plot second digit of total masks &21de a9 e0 LDA #&e0 &21e0 8d 8b 21 STA &218b ; number_screen_address_low &21e3 a9 00 LDA #&00 &21e5 20 81 21 JSR &2181 ; plot_number # Plot first digit of masks collected &21e8 a9 e8 LDA #&e8 &21ea 8d 8b 21 STA &218b ; number_screen_address_low &21ed a9 00 LDA #&00 &21ef 20 81 21 JSR &2181 ; plot_number # Plot second digit of masks collected &21f2 60 RTS ; plot_masks_collected &21f3 a5 93 LDA &93 ; masks_collected &21f5 a0 00 LDY #&00 &21f7 38 SEC ; calculate_masks_collected_tens_loop &21f8 c8 INY &21f9 e9 0a SBC #&0a ; 10 &21fb b0 fb BCS &21f8 ; calculate_masks_collected_tens_loop &21fd 69 0a ADC #&0a ; 10 &21ff 8d 1d 22 STA &221d ; digit &2202 88 DEY &2203 a9 7a LDA #&7a &2205 8d 8c 21 STA &218c ; number_screen_address_high &2208 a9 e0 LDA #&e0 &220a 8d 8b 21 STA &218b ; number_screen_address_low &220d 98 TYA &220e 20 81 21 JSR &2181 ; plot_number # Plot first digit of masks collected &2211 a9 e8 LDA #&e8 &2213 8d 8b 21 STA &218b ; number_screen_address_low &2216 ad 1d 22 LDA &221d ; digit &2219 20 81 21 JSR &2181 ; plot_number # Plot second digit of masks collected &221c 60 RTS ; digit &221d ea ; flash_screen &221e a2 02 LDX #&02 ; flash_screen_loop &2220 ad 4a 22 LDA &224a ; flash_string + 3 # Swap previous and current colour &2223 ac 46 22 LDY &2246 ; flash_colour &2226 8d 46 22 STA &2246 ; flash_colour &2229 8c 4a 22 STY &224a ; flash_string + 3 &222c a0 06 LDY #&06 ; write_flash_loop &222e b9 46 22 LDA &2246,Y ; flash_string - 1 &2231 20 ee ff JSR &ffee ; OSWRCH &2234 88 DEY &2235 d0 f7 BNE &222e ; write_flash_loop &2237 8e 4d 22 STX &224d ; flash_stage &223a a9 0f LDA #&0f &223c 20 a3 1e JSR &1ea3 ; delay &223f ae 4d 22 LDX &224d ; flash_stage &2242 ca DEX &2243 d0 db BNE &2220 ; flash_screen_loop &2245 60 RTS ; flash_colour &2246 ea ; flash_string # Stored backwards &2247 00 00 00 00 00 13 ; Set colour 0 to (flash_string + 3) ; flash_stage &224d ea ; store_move # Called with X = move to store &224e a5 b2 LDA &b2 ; replay_nibble &2250 f0 2c BEQ &227e ; use_low_nibble # Low nibble first ; use_high_nibble &2252 8a TXA &2253 0a ASL A &2254 0a ASL A &2255 0a ASL A &2256 0a ASL A &2257 09 0f ORA #&0f &2259 85 b5 STA &b5 ; replay_byte &225b a9 00 LDA #&00 &225d 85 b2 STA &b2 ; replay_nibble &225f a0 00 LDY #&00 &2261 b1 b3 LDA (&b3),Y ; replay_data_address &2263 09 f0 ORA #&f0 &2265 25 b5 AND &b5 ; replay_byte &2267 91 b3 STA (&b3),Y ; replay_data_address &2269 e6 b3 INC &b3 ; replay_data_address_low # Move to next byte &226b a5 b3 LDA &b3 ; replay_data_address_low &226d d0 1b BNE &228a ; leave &226f e6 b4 INC &b4 ; replay_data_address_high &2271 a5 b4 LDA &b4 ; replay_data_address_high &2273 c9 08 CMP #&08 &2275 d0 13 BNE &228a ; leave # Always branches (unless number of moves > 2047) &2277 a9 4c LDA #&4c ; &4c00 = save_filename # Unnecessary code; would overwrite replay saving code &2279 85 b4 STA &b4 ; replay_data_address_high &227b 4c 8a 22 JMP &228a ; leave ; use_low_nibble &227e 86 b5 STX &b5 ; replay_byte &2280 a9 01 LDA #&01 &2282 85 b2 STA &b2 ; replay_nibble &2284 a5 b5 LDA &b5 ; replay_byte &2286 a0 00 LDY #&00 &2288 91 b3 STA (&b3),Y ; replay_data_address ; leave &228a 60 RTS ; get_move_from_replay # Called with A = keycode &228b c9 a2 CMP #&a2 ; E &228d f0 58 BEQ &22e7 ; leave # Unnecessary code; never branches &228f a5 b2 LDA &b2 ; replay_nibble &2291 f0 23 BEQ &22b6 ; use_low_nibble # Low nibble first ; use_high_nibble &2293 a0 00 LDY #&00 &2295 84 b2 STY &b2 ; replay_nibble &2297 b1 b3 LDA (&b3),Y ; replay_data_address &2299 29 f0 AND #&f0 # Use top nibble &229b 4a LSR A &229c 4a LSR A &229d 4a LSR A &229e 4a LSR A &229f 85 b5 STA &b5 ; replay_direction &22a1 e6 b3 INC &b3 ; replay_data_address_low # Move to next byte of replay data &22a3 a5 b3 LDA &b3 ; replay_data_address_low &22a5 d0 1a BNE &22c1 ; use_replay_direction &22a7 e6 b4 INC &b4 ; replay_data_address_high &22a9 a5 b4 LDA &b4 ; replay_data_address_high &22ab c9 08 CMP #&08 &22ad d0 12 BNE &22c1 ; use_replay_direction # Always branches (unless number of moves > 2047) &22af a9 4c LDA #&4c ; &4c00 = save_filename # Unnecessary code; would overwrite replay saving code &22b1 85 b4 STA &b4 ; replay_data_address_high &22b3 4c c1 22 JMP &22c1 ; use_replay_direction ; use_low_nibble &22b6 a0 01 LDY #&01 &22b8 84 b2 STY &b2 ; replay_nibble &22ba 88 DEY &22bb b1 b3 LDA (&b3),Y ; replay_data_address &22bd 29 0f AND #&0f # Use bottom nibble &22bf 85 b5 STA &b5 ; replay_direction ; use_replay_direction &22c1 a5 b5 LDA &b5 ; replay_direction &22c3 f0 1c BEQ &22e1 ; use_up &22c5 c9 01 CMP #&01 ; MOVE_DOWN &22c7 f0 15 BEQ &22de ; use_down &22c9 c9 02 CMP #&02 ; MOVE_RIGHT &22cb f0 0e BEQ &22db ; use_right &22cd c9 03 CMP #&03 ; MOVE_LEFT &22cf f0 07 BEQ &22d8 ; use_left &22d1 c9 04 CMP #&04 ; MOVE_SWAP &22d3 f0 0f BEQ &22e4 ; use_swap &22d5 a9 a2 LDA #&a2 ; E # Set keycode corresponding to move &22d7 60 RTS ; use_left &22d8 a9 e1 LDA #&e1 ; Z &22da 60 RTS ; use_right &22db a9 c2 LDA #&c2 ; X &22dd 60 RTS ; use_down &22de a9 e8 LDA #&e8 ; / &22e0 60 RTS ; use_up &22e1 a9 c8 LDA #&c8 ; * &22e3 60 RTS ; use_swap &22e4 a9 c9 LDA #&c9 ; RETURN &22e6 60 RTS ; leave &22e7 60 RTS ; unpack_level_data &22e8 a5 60 LDA &60 ; level_data_address_low &22ea 18 CLC &22eb 69 c2 ADC #&c2 &22ed 85 5e STA &5e ; map_data_address_low &22ef a5 61 LDA &61 ; level_data_address_high &22f1 69 01 ADC #&01 &22f3 85 5f STA &5f ; map_data_address_high &22f5 a0 00 LDY #&00 ; copy_mask_player_and_teleport_addresses_loop # Copy level data to &0078 - &00a7 &22f7 b1 5e LDA (&5e),Y ; map_data_address &22f9 99 78 00 STA &0078,Y ; map_addresses &22fc c8 INY &22fd c0 30 CPY #&30 &22ff d0 f6 BNE &22f7 ; copy_mask_player_and_teleport_addresses_loop &2301 a2 00 LDX #&00 ; copy_magus_variables_loop &2303 b5 80 LDA &80,X ; magus_address_offsets_and_viewpoint &2305 95 70 STA &70,X ; player_address_offsets_and_viewpoint &2307 e8 INX &2308 e0 08 CPX #&08 &230a d0 f7 BNE &2303 ; copy_magus_variables_loop &230c a9 00 LDA #&00 &230e 85 62 STA &62 ; level_data_nibble &2310 a9 21 LDA #&21 ; &0921 = tile_data + &20 + 1 # Start at tile (1, 1) &2312 85 5e STA &5e ; tile_address_low &2314 a9 09 LDA #&09 &2316 85 5f STA &5f ; tile_address_high ; unpack_level_data_loop &2318 a0 00 LDY #&00 &231a b1 60 LDA (&60),Y ; level_data_address # Get byte of level data &231c a6 62 LDX &62 ; level_data_nibble &231e e0 01 CPX #&01 &2320 d0 04 BNE &2326 ; use_low_nibble # Low nibble first ; use_high_nibble &2322 4a LSR A &2323 4a LSR A &2324 4a LSR A &2325 4a LSR A ; use_low_nibble &2326 29 0f AND #&0f &2328 91 5e STA (&5e),Y ; tile_address &232a a5 62 LDA &62 ; level_data_nibble &232c 49 01 EOR #&01 &232e 85 62 STA &62 ; level_data_nibble &2330 d0 06 BNE &2338 ; skip_byte &2332 e6 60 INC &60 ; level_data_address_low &2334 d0 02 BNE &2338 ; skip_page &2336 e6 61 INC &61 ; level_data_address_high ; skip_page ; skip_byte &2338 a5 5e LDA &5e ; tile_address_low &233a 29 1f AND #&1f &233c c9 1e CMP #&1e &233e d0 06 BNE &2346 ; not_end_of_row &2340 20 59 23 JSR &2359 ; move_to_next_tile # Skip two tiles for left and right edges at end of row &2343 20 59 23 JSR &2359 ; move_to_next_tile ; not_end_of_row &2346 20 59 23 JSR &2359 ; move_to_next_tile &2349 a5 5f LDA &5f ; tile_address_high &234b c9 0c CMP #&0c ; &0ce1 = tile_data + &20 * 31 + 1 # End at tile (1, 31) &234d d0 06 BNE &2355 ; not_end_of_data &234f a5 5e LDA &5e ; tile_address_low &2351 c9 e1 CMP #&e1 &2353 f0 03 BEQ &2358 ; leave ; not_end_of_data &2355 4c 18 23 JMP &2318 ; unpack_level_data_loop ; leave &2358 60 RTS ; move_to_next_tile &2359 e6 5e INC &5e ; tile_address_low &235b d0 02 BNE &235f ; skip_page &235d e6 5f INC &5f ; tile_address_high ; skip_page &235f 60 RTS ; unused # Source code fragment &2360 3a 68 65 72 6f 3d 32 0d ; ... :hero=2 &2368 00 fa 29 68 65 72 6f 78 3d 26 37 32 3a 68 65 72 ; 250herox=&72: # player_x_offset &2378 6f 79 3d 26 37 33 3a 3f ; heroy=&73: # player_y_offset ; ? ... ; initialise_tile_data &2380 a9 09 LDA #&09 &2382 8d 8e 23 STA &238e ; fill_address_high &2385 a9 01 LDA #&01 ; PIECE_WALL &2387 a0 00 LDY #&00 &2389 8c 8d 23 STY &238d ; fill_address_low ; initialise_tile_data_loop &238c 99 00 09 STA &0900,Y ; tile_data # Wipe &0900 - &0cff with &01 (PIECE_WALL) # actually STA fill_address,Y &238f c8 INY &2390 d0 fa BNE &238c ; initialise_tile_data_loop &2392 ee 8e 23 INC &238e ; fill_address_high &2395 ae 8e 23 LDX &238e ; fill_address_high &2398 e0 0d CPX #&0d &239a d0 f0 BNE &238c ; initialise_tile_data_loop &239c 60 RTS ; initialise_variables &239d a9 80 LDA #&80 ; &5480 = screen_address_table &239f 85 56 STA &56 ; screen_addresses_low &23a1 a9 54 LDA #&54 &23a3 85 57 STA &57 ; screen_addresses_high &23a5 a9 00 LDA #&00 &23a7 8d 09 1f STA &1f09 ; explosions_or_mover_destroyed &23aa 8d 0a 1f STA &1f0a ; explosions_or_mover_destroyed + 1 &23ad 85 5a STA &5a ; sprite_addresses_low &23af 85 6e STA &6e ; unused # Unused variable &23b1 85 b2 STA &b2 ; replay_nibble &23b3 85 b3 STA &b3 ; replay_data_address_low &23b5 a9 55 LDA #&55 ; &5500 = sprite_address_table &23b7 85 5b STA &5b ; sprite_addresses_high &23b9 a9 ed LDA #&ed &23bb 85 6d STA &6d ; unused # Unused variable &23bd a9 04 LDA #&04 ; &0400 = replay_data &23bf 85 b4 STA &b4 ; replay_data_address_high &23c1 60 RTS ; plot_text &23c2 a9 00 LDA #&00 ; &5800 = screen_memory &23c4 85 5e STA &5e ; text_screen_address_low &23c6 a9 58 LDA #&58 &23c8 85 5f STA &5f ; text_screen_address_high &23ca a0 01 LDY #&01 &23cc b1 53 LDA (&53),Y ; text_address # Second byte of text sets y position &23ce aa TAX ; add_groups_to_text_screen_address_loop &23cf e6 5f INC &5f ; text_screen_address_high &23d1 18 CLC &23d2 a5 5e LDA &5e ; text_screen_address_low &23d4 69 40 ADC #&40 # Add &140 per group &23d6 85 5e STA &5e ; text_screen_address_low &23d8 90 02 BCC &23dc ; skip_page &23da e6 5f INC &5f ; text_screen_address_high ; skip_page &23dc ca DEX &23dd d0 f0 BNE &23cf ; add_groups_to_text_screen_address_loop &23df 88 DEY &23e0 b1 53 LDA (&53),Y ; text_address # First byte of text sets x position &23e2 aa TAX ; add_columns_to_text_screen_address_loop &23e3 e0 00 CPX #&00 &23e5 f0 07 BEQ &23ee ; finished_calculating_text_screen_address &23e7 ca DEX &23e8 20 4b 24 JSR &244b ; move_right_a_column &23eb 4c e3 23 JMP &23e3 ; add_columns_to_text_screen_address_loop ; finished_calculating_text_screen_address &23ee a0 02 LDY #&02 &23f0 84 60 STY &60 ; text_offset ; plot_text_loop &23f2 a4 60 LDY &60 ; text_offset &23f4 b1 53 LDA (&53),Y ; text_address &23f6 c9 20 CMP #&20 ; " " # " " is replaced by "[" &23f8 d0 02 BNE &23fc ; not_space &23fa a9 5b LDA #&5b ; "[" ; not_space &23fc c9 3f CMP #&3f ; "?" # "?" is replaced by "\" &23fe d0 02 BNE &2402 ; not_question_mask &2400 a9 5c LDA #&5c ; "\" ; not_question_mask &2402 c9 0d CMP #&0d ; CR # CR ends string &2404 d0 01 BNE &2407 ; plot_character &2406 60 RTS ; plot_character &2407 38 SEC &2408 e9 41 SBC #&41 ; "A" &240a aa TAX &240b c8 INY &240c 84 60 STY &60 ; text_offset &240e a0 00 LDY #&00 &2410 a9 00 LDA #&00 ; calculate_font_offset_loop &2412 e0 00 CPX #&00 &2414 f0 07 BEQ &241d ; finished_calculating_font_offset &2416 ca DEX &2417 18 CLC &2418 69 05 ADC #&05 # Five bytes per character &241a 4c 12 24 JMP &2412 ; calculate_font_offset_loop ; finished_calculating_font_offset &241d aa TAX &241e a0 00 LDY #&00 &2420 98 TYA &2421 91 5e STA (&5e),Y ; text_screen_address # Plot blank row at top of character &2423 8a TXA &2424 a8 TAY &2425 a2 01 LDX #&01 ; plot_character_loop &2427 b9 60 56 LDA &5660,Y ; font_data &242a 84 61 STY &61 ; tmp_y &242c 86 62 STX &62 ; tmp_x &242e a4 62 LDY &62 ; tmp_x &2430 91 5e STA (&5e),Y ; text_screen_address # Plot five rows of character &2432 a4 61 LDY &61 ; tmp_y &2434 a6 62 LDX &62 ; tmp_x &2436 c8 INY &2437 e8 INX &2438 e0 06 CPX #&06 &243a d0 eb BNE &2427 ; plot_character_loop &243c 8a TXA &243d a8 TAY &243e a9 00 LDA #&00 &2440 91 5e STA (&5e),Y ; text_screen_address # Plot two blank rows at bottom of character &2442 c8 INY &2443 91 5e STA (&5e),Y ; text_screen_address &2445 20 4b 24 JSR &244b ; move_right_a_column &2448 4c f2 23 JMP &23f2 ; plot_text_loop ; move_right_a_column &244b a5 5e LDA &5e ; text_screen_address_low &244d 18 CLC &244e 69 08 ADC #&08 &2450 85 5e STA &5e ; text_screen_address_low &2452 90 02 BCC &2456 ; skip_page &2454 e6 5f INC &5f ; text_screen_address_high ; skip_page &2456 60 RTS ; wipe_map &2457 a9 61 LDA #&61 &2459 8d 69 24 STA &2469 ; wipe_screen_address_high &245c a9 a8 LDA #&a8 &245e 8d 68 24 STA &2468 ; wipe_screen_address_low &2461 a9 00 LDA #&00 &2463 aa TAX ; wipe_map_group_loop &2464 a0 00 LDY #&00 &2466 98 TYA ; wipe_map_byte_loop &2467 99 00 80 STA &8000,Y # actually STA wipe_screen_address,Y &246a c8 INY &246b c0 40 CPY #&40 &246d d0 f8 BNE &2467 ; wipe_map_byte_loop &246f e8 INX &2470 e0 08 CPX #&08 &2472 f0 14 BEQ &2488 ; leave &2474 ad 68 24 LDA &2468 ; wipe_screen_address_low &2477 18 CLC &2478 69 40 ADC #&40 &247a 8d 68 24 STA &2468 ; wipe_screen_address_low &247d ad 69 24 LDA &2469 ; wipe_screen_address_high &2480 69 01 ADC #&01 &2482 8d 69 24 STA &2469 ; wipe_screen_address_high &2485 4c 64 24 JMP &2464 ; wipe_map_group_loop ; leave &2488 60 RTS ; replay_state &2489 ea ; plot_too_many_moves &248a a9 96 LDA #&96 ; &2496 = too_many_moves_string &248c 85 53 STA &53 ; text_address_low &248e a9 24 LDA #&24 &2490 85 54 STA &54 ; text_address_high &2492 20 c2 23 JSR &23c2 ; plot_text # Plot " TOO MANY MOVES " &2495 60 RTS ; too_many_moves_string &2496 05 15 &2498 20 54 4f 4f 20 4d 41 4e 59 20 4d 4f 56 45 53 20 ; " TOO MANY MOVES " &24a8 0d ; plot_gotcha &24a9 a9 b5 LDA #&b5 ; &24b5 = gotcha_string &24aa 85 53 STA &53 ; text_address_low &24ad a9 24 LDA #&24 &24af 85 54 STA &54 ; text_address_high &24b1 20 c2 23 JSR &23c2 ; plot_text # Plot " GOTCHA " &24b4 60 RTS ; gotcha_string &24b5 06 15 &24b7 20 20 20 20 47 4f 54 43 48 41 20 20 20 20 0d ; " GOTCHA " ; plot_whoops &24c6 a9 dd LDA #&dd ; &24dd = whoops_string &24c8 85 53 STA &53 ; text_address_low &24ca a9 24 LDA #&24 &24cc 85 54 STA &54 ; text_address_high &24ce 20 c2 23 JSR &23c2 ; plot_text # Plot " WHOOPS " ; long_delay &24d1 a9 fa LDA #&fa &24d3 20 a3 1e JSR &1ea3 ; delay &24d6 20 a3 1e JSR &1ea3 ; delay &24d9 20 a3 1e JSR &1ea3 ; delay &24dc 60 RTS ; whoops_string &24dd 08 15 &24df 20 20 20 57 48 4f 4f 50 53 20 20 20 20 0d ; " WHOOPS " ; level_result &24ed ea ; play_and_replay_level &24ee a9 00 LDA #&00 # Set to zero to indicate not replaying level &24f0 8d 89 24 STA &2489 ; replay_state &24f3 20 2b 25 JSR &252b ; initialise_and_play_level # Returns zero if level failed, one if level completed &24f6 8d ed 24 STA &24ed ; level_result &24f9 c9 01 CMP #&01 &24fb f0 2d BEQ &252a ; leave ; consider_replay &24fd a9 51 LDA #&51 ; &2551 = replay_string &24ff 85 53 STA &53 ; text_address_low &2501 a9 25 LDA #&25 &2503 85 54 STA &54 ; text_address_high &2505 20 c2 23 JSR &23c2 ; plot_text # Plot " REPLAY ? " &2508 a9 15 LDA #&15 ; Flush selected buffer &250a a2 00 LDX #&00 ; keyboard &250c 20 f4 ff JSR &fff4 ; OSBYTE &250f 20 00 28 JSR &2800 ; check_for_volume_change &2512 ea NOP &2513 ea NOP &2514 c9 c4 CMP #&c4 ; Y &2516 f0 07 BEQ &251f ; start_replay &2518 c9 d5 CMP #&d5 ; N &251a f0 0e BEQ &252a ; leave &251c 4c fd 24 JMP &24fd ; consider_replay ; start_replay &251f a9 01 LDA #&01 # Set to non-zero to indicate replaying level &2521 8d 89 24 STA &2489 ; replay_state &2524 20 2b 25 JSR &252b ; initialise_and_play_level &2527 4c fd 24 JMP &24fd ; consider_replay ; leave &252a 60 RTS ; initialise_and_play_level &252b 20 57 24 JSR &2457 ; wipe_map &252e 20 80 23 JSR &2380 ; initialise_tile_data &2531 a9 00 LDA #&00 &2533 85 60 STA &60 ; level_data_address_low &2535 20 60 25 JSR &2560 ; get_level_data_address &2538 20 9d 23 JSR &239d ; initialise_variables &253b ad 89 24 LDA &2489 ; replay_state &253e 85 b1 STA &b1 ; replaying &2540 20 e8 22 JSR &22e8 ; unpack_level_data &2543 a9 01 LDA #&01 # Set to non-zero to indicate other player is alive &2545 85 91 STA &91 ; other_player_state &2547 20 7b 27 JSR &277b ; initialise_wall_sprite &254a 20 94 21 JSR &2194 ; initialise_and_plot_counters &254d 20 b7 17 JSR &17b7 ; swap_from_magus # Start with Questor (leaves via main_game_loop) &2550 60 RTS ; replay_string &2551 08 18 &2553 20 20 52 45 50 4c 41 59 20 20 3f 20 0d ; " REPLAY ? " ; get_level_data_address &2560 ad 6e 25 LDA &256e ; level_number &2563 0a ASL &2564 85 61 STA &61 ; level_data_address_high &2566 a9 4c LDA #&4c ; &4c00 = level_1_data + &200 &2568 38 SEC &2569 e5 61 SBC &61 ; level_data_address_high &256b 85 61 STA &61 ; level_data_address_high &256d 60 RTS ; main &256e ea NOP &256f 20 5e 27 JSR &275e ; initialise_music &2572 a9 01 LDA #&01 &2574 8d 6e 25 STA &256e ; level_number ; title_screen &2577 ad 6e 25 LDA &256e ; level_number &257a c9 0b CMP #&0b &257c 30 07 BMI &2585 ; skip_hiding_level &257e 29 01 AND #&01 # Levels 11, 13 and 15 are hidden on title screen &2580 f0 03 BEQ &2585 ; skip_hiding_level &2582 ce 6e 25 DEC &256e ; level_number ; skip_hiding_level &2585 20 93 26 JSR &2693 ; wipe_main_area &2588 20 1d 26 JSR &261d ; plot_title_screen ; title_screen_loop &258b 20 40 57 JSR &5740 ; set_level_colours_and_wall_sprite &258e 20 00 2c JSR &2c00 ; plot_level_title &2591 a9 15 LDA #&15 ; Flush selected buffer &2593 a2 00 LDX #&00 ; keyboard &2595 20 f4 ff JSR &fff4 ; OSBYTE &2598 20 e0 ff JSR &ffe0 ; OSRDCH &259b 09 20 ORA #&20 # Convert to lowercase &259d c9 66 CMP #&66 ; "f" &259f d0 07 BNE &25a8 ; f_not_pressed &25a1 38 SEC # Set carry to increase volume &25a2 20 15 28 JSR &2815 ; increase_or_decrease_volume &25a5 4c 8b 25 JMP &258b ; title_screen_loop ; f_not_pressed &25a8 c9 70 CMP #&70 ; "p" &25aa d0 07 BNE &25b3 ; p_not_pressed &25ac 18 CLC # Clear carry to decrease volume &25ad 20 15 28 JSR &2815 ; increase_or_decrease_volume &25b0 4c 8b 25 JMP &258b ; title_screen_loop ; p_not_pressed &25b3 c9 6c CMP #&6c ; "l" &25b5 d0 1c BNE &25d3 ; l_not_pressed &25b7 ee 6e 25 INC &256e ; level_number # Move to next level if L pressed &25ba ad 6e 25 LDA &256e ; level_number &25bd c9 0b CMP #&0b &25bf 30 06 BMI &25c7 ; not_later_level &25c1 ee 6e 25 INC &256e ; level_number # Levels 11, 13 and 15 are hidden on title screen &25c4 ad 6e 25 LDA &256e ; level_number ; not_later_level &25c7 c5 3f CMP &3f ; maximum_level_plus_one &25c9 d0 05 BNE &25d0 ; skip_wraparound &25cb a9 01 LDA #&01 &25cd 8d 6e 25 STA &256e ; level_number ; skip_wraparound &25d0 4c 8b 25 JMP &258b ; title_screen_loop ; l_not_pressed &25d3 c9 65 CMP #&65 ; "e" &25d5 d0 01 BNE &25d8 ; e_not_pressed &25d7 ea NOP # Unnecessary code; do nothing if E pressed ; e_not_pressed &25d8 c9 20 CMP #&20 ; " " &25da d0 af BNE &258b ; title_screen_loop &25dc 20 1d 27 JSR &271d ; animate_masks_pattern # Animate masks ; play_next_level &25df 20 ee 24 JSR &24ee ; play_and_replay_level &25e2 ad ed 24 LDA &24ed ; level_result # Zero if level wasn't completed &25e5 f0 90 BEQ &2577 ; title_screen &25e7 ee 6e 25 INC &256e ; level_number # If level was completed, move to next level &25ea ad 6e 25 LDA &256e ; level_number &25ed c9 0a CMP #&0a &25ef 30 04 BMI &25f5 ; not_later_level &25f1 29 01 AND #&01 &25f3 d0 12 BNE &2607 ; plot_random_viewpoint # Display random tiles at end of levels 10, 12 and 14 &25f5 20 a9 28 JSR &28a9 ; show_level_code_letter # Otherwise, show code for completed level &25f8 ad 6e 25 LDA &256e ; level_number &25fb c5 3f CMP &3f ; maximum_level_plus_one &25fd d0 05 BNE &2604 ; skip_wraparound &25ff a9 01 LDA #&01 &2601 8d 6e 25 STA &256e ; level_number ; skip_wraparound &2604 4c 77 25 JMP &2577 ; title_screen ; plot_random_viewpoint &2607 a2 11 LDX #&11 ; &1100 = plot_viewpoint # Use code as source of random tile data ; plot_random_viewpoint_loop &2609 86 77 STX &77 ; viewpoint_address_high &260b 8a TXA &260c 48 PHA &260d 20 00 11 JSR &1100 ; plot_viewpoint &2610 68 PLA &2611 aa TAX &2612 e8 INX &2613 e0 25 CPX #&25 &2615 d0 f2 BNE &2609 ; plot_random_viewpoint_loop &2617 20 00 2c JSR &2c00 ; plot_level_title &261a 4c df 25 JMP &25df ; play_next_level ; plot_title_screen &261d 20 7b 27 JSR &277b ; initialise_wall_sprite &2620 20 57 24 JSR &2457 ; wipe_map &2623 20 94 21 JSR &2194 ; initialise_and_plot_counters &2626 20 43 2c JSR &2c43 ; check_for_alternative_keys &2629 a9 80 LDA #&80 &262b 85 58 STA &58 ; screen_address_low &262d a9 79 LDA #&79 &262f 85 59 STA &59 ; screen_address_high &2631 a9 00 LDA #&00 ; PIECE_SPACE &2633 20 2d 11 JSR &112d ; plot_sprite # Plot space next to mask counter &2636 a9 e8 LDA #&e8 &2638 85 58 STA &58 ; screen_address_low &263a a9 71 LDA #&71 &263c 85 59 STA &59 ; screen_address_high &263e a9 00 LDA #&00 ; PIECE_SPACE &2640 20 2d 11 JSR &112d ; plot_sprite # Plot space next to move counter &2643 a9 68 LDA #&68 &2645 85 58 STA &58 ; screen_address_low &2647 a9 79 LDA #&79 &2649 85 59 STA &59 ; screen_address_high &264b a9 00 LDA #&00 ; PIECE_SPACE &264d 20 2d 11 JSR &112d ; plot_sprite &2650 a0 00 LDY #&00 ; copy_title_screen_masks_pattern_loop &2652 b9 8a 26 LDA &268a,Y ; title_screen_masks_pattern &2655 99 c5 26 STA &26c5,Y ; masks_pattern &2658 c8 INY &2659 c0 08 CPY #&08 &265b d0 f5 BNE &2652 ; copy_title_screen_masks_pattern_loop &265d 20 d2 26 JSR &26d2 ; plot_masks_pattern # Plot masks in main area &2660 a9 f0 LDA #&f0 ; &56f0 = piano_string &2662 85 53 STA &53 ; text_address_low &2664 a9 56 LDA #&56 &2666 85 54 STA &54 ; text_address_high &2668 20 c2 23 JSR &23c2 ; plot_text # Plot "P PIANO " &266b a9 fe LDA #&fe ; &56fe = forte_string &266d 85 53 STA &53 ; text_address_low &266f 20 c2 23 JSR &23c2 ; plot_text # Plot "F FORTE " &2672 a9 0d LDA #&0d ; &570d = blank_string &2674 85 53 STA &53 ; text_address_low &2676 e6 54 INC &54 ; text_address_high &2678 20 c2 23 JSR &23c2 ; plot_text # Plot " " &267b a9 1b LDA #&1b ; &571b = next_level_string &267d 85 53 STA &53 ; text_address_low &267f 20 c2 23 JSR &23c2 ; plot_text # Plot "L NEXT LEVEL" &2682 a9 2b LDA #&2b ; &572b = space_to_play_string &2684 85 53 STA &53 ; text_address_low &2686 20 c2 23 JSR &23c2 ; plot_text # Plot "SPACE TO PLAY" &2689 60 RTS ; title_screen_masks_pattern &268a ff ff 81 81 81 ff 81 ff ; unused &2692 ea ; wipe_main_area &2693 a9 90 LDA #&90 &2695 8d a4 26 STA &26a4 ; wipe_address_low &2698 a9 5f LDA #&5f &269a 8d a5 26 STA &26a5 ; wipe_address_high &269d a9 00 LDA #&00 &269f aa TAX ; wipe_main_area_group_loop &26a0 a0 00 LDY #&00 &26a2 98 TYA ; wipe_main_area_byte_loop &26a3 99 00 80 STA &8000,Y # actually STA wipe_address,Y &26a6 c8 INY &26a7 c0 c0 CPY #&c0 &26a9 d0 f8 BNE &26a3 ; wipe_main_area_byte_loop &26ab e8 INX &26ac e0 18 CPX #&18 &26ae f0 14 BEQ &26c4 ; leave &26b0 ad a4 26 LDA &26a4 ; wipe_address_low &26b3 18 CLC &26b4 69 40 ADC #&40 # Move down a group &26b6 8d a4 26 STA &26a4 ; wipe_address_low &26b9 ad a5 26 LDA &26a5 ; wipe_address_high &26bc 69 01 ADC #&01 &26be 8d a5 26 STA &26a5 ; wipe_address_high &26c1 4c a0 26 JMP &26a0 ; wipe_main_area_group_loop ; leave &26c4 60 RTS ; masks_pattern &26c5 ea ea ea ea ea ea ea ea ; pattern_group_offset &26cd ea ; pattern_column &26ce ea ; pattern_row &26cf ea ; pattern_sprite &26d0 ea ; pattern_byte &26d1 ea ; plot_masks_pattern &26d2 a9 00 LDA #&00 &26d4 a8 TAY &26d5 aa TAX &26d6 8d cd 26 STA &26cd ; pattern_group_offset ; plot_masks_pattern_row_loop &26d9 a2 00 LDX #&00 &26db b9 c5 26 LDA &26c5,Y ; masks_pattern &26de c8 INY &26df 8c cf 26 STY &26cf ; pattern_row ; plot_masks_pattern_column_loop &26e2 a0 0b LDY #&0b ; PIECE_MASK # actually LDY sprite_to_use_for_pattern &26e4 2a ROL A &26e5 b0 02 BCS &26e9 ; use_mask &26e7 a0 00 LDY #&00 ; PIECE_SPACE ; use_mask &26e9 8c d0 26 STY &26d0 ; pattern_sprite &26ec 8d d1 26 STA &26d1 ; pattern_byte &26ef e8 INX &26f0 8e ce 26 STX &26ce ; pattern_column &26f3 ac cd 26 LDY &26cd ; pattern_group_offset &26f6 b9 80 54 LDA &5480,Y ; screen_address_table &26f9 85 58 STA &58 ; screen_address_low &26fb c8 INY &26fc b9 80 54 LDA &5480,Y ; screen_address_table &26ff 85 59 STA &59 ; screen_address_high &2701 c8 INY &2702 8c cd 26 STY &26cd ; pattern_group_offset &2705 ad d0 26 LDA &26d0 ; pattern_sprite &2708 20 2d 11 JSR &112d ; plot_sprite &270b ad d1 26 LDA &26d1 ; pattern_byte &270e ae ce 26 LDX &26ce ; pattern_column &2711 ac cf 26 LDY &26cf ; pattern_row &2714 e0 08 CPX #&08 &2716 d0 ca BNE &26e2 ; plot_masks_pattern_column_loop &2718 c0 08 CPY #&08 &271a d0 bd BNE &26d9 ; plot_masks_pattern_row_loop &271c 60 RTS ; animate_masks_pattern &271d a9 f7 LDA #&f7 ; &27f7 = animated_patterns + 8 * 3 &271f 8d 2c 27 STA &272c ; pattern_address_low &2722 a9 27 LDA #&27 &2724 8d 2d 27 STA &272d ; pattern_address_high &2727 a2 00 LDX #&00 ; animate_masks_pattern_loop &2729 a0 00 LDY #&00 ; copy_masks_pattern_loop &272b b9 40 1f LDA &1f40,Y # actually LDA pattern_address,Y &272e 99 c5 26 STA &26c5,Y ; masks_pattern &2731 c8 INY &2732 c0 08 CPY #&08 &2734 d0 f5 BNE &272b ; copy_masks_pattern_loop &2736 48 PHA &2737 98 TYA &2738 48 PHA &2739 8a TXA &273a 48 PHA &273b 20 d2 26 JSR &26d2 ; plot_masks_pattern &273e 68 PLA &273f aa TAX &2740 68 PLA &2741 a8 TAY &2742 68 PLA &2743 e8 INX &2744 e0 05 CPX #&05 &2746 f0 15 BEQ &275d ; leave &2748 ad 2c 27 LDA &272c ; pattern_address_low &274b 38 SEC &274c e9 08 SBC #&08 &274e 8d 2c 27 STA &272c ; pattern_address_low &2751 8a TXA &2752 48 PHA &2753 a9 7d LDA #&7d &2755 20 a3 1e JSR &1ea3 ; delay &2758 68 PLA &2759 aa TAX &275a 4c 29 27 JMP &2729 ; animate_masks_pattern_loop ; leave &275d 60 RTS ; initialise_music &275e a9 50 LDA #&50 &2760 8d 20 02 STA &0220 ; event_vector_low &2763 a9 4d LDA #&4d ; &4d50 = event_handler &2765 8d 21 02 STA &0221 ; event_vector_high &2768 a9 0e LDA #&0e ; Enable event &276a a2 05 LDX #&05 ; interval timer event &276c 20 f4 ff JSR &fff4 ; OSBYTE &276f a9 00 LDA #&00 ; &4f00 = channel_3_bar_data &2771 85 40 STA &40 ; channel_3_data_address_low &2773 a9 4f LDA #&4f &2775 85 41 STA &41 ; channel_3_data_address_high &2777 20 50 4d JSR &4d50 ; event_handler &277a 60 RTS ; initialise_wall_sprite &277b a0 00 LDY #&00 ; initialise_wall_sprite_loop &277d b9 b0 55 LDA &55b0,Y ; sprite_wall_source &2780 99 48 50 STA &5048,Y ; sprite_wall &2783 c8 INY &2784 c0 48 CPY #&48 &2786 d0 f5 BNE &277d ; initialise_wall_sprite_loop &2788 a0 00 LDY #&00 &278a 84 96 STY &96 ; switch_state # Set to zero to indicate level is lit &278c 60 RTS ; unused # Unused code; similar to &2772 - &277a &278d 40 ... &40 ; channel_3_data_address_low &278e a9 10 LDA #&10 # &2773 a9 4f LDA #&4f &2790 85 41 STA &41 ; channel_3_data_address_high &2792 20 50 4d JSR &4d50 ; event_handler &2795 60 RTS ; unused # Source code fragment &2796 72 6f 78 3d 26 37 32 3a 68 65 72 6f 79 3d 26 37 ; ... rox=&72: # player_x_offset &27a6 33 3a 3f 68 65 72 6f 78 3d 33 3a 3f 68 65 72 6f ; heroy=&73: # player_y_offset &27b6 79 3d 31 0d ; ?herox=3: ; ?heroy=1 &27ba 01 36 15 77 69 6e 78 3d 26 37 34 3a 77 69 6e 79 ; 310winx=&74: # viewpoint_x &27ca 3d 26 37 35 0d ; winy=&75 # viewpoint_y &27cf 01 40 13 3f 77 69 6e 78 ; 320?winx ... ; unused &27d7 00 00 00 00 00 00 00 00 ; animated_patterns &27df ff 81 81 81 81 81 81 ff &27e7 00 7e 42 42 42 42 7e 00 &27ef 00 00 3c 24 24 3c 00 00 &27f7 00 00 00 18 18 00 00 00 ; unused &27ff 3f ; check_for_volume_change &2800 a9 7a LDA #&7a ; Keyboard scan &2802 20 f4 ff JSR &fff4 ; OSBYTE &2805 8a TXA &2806 09 80 ORA #&80 &2808 20 43 2c JSR &2c43 ; check_for_alternative_keys &280b c9 c3 CMP #&c3 ; F &280d f0 05 BEQ &2814 ; increase_volume &280f c9 b7 CMP #&b7 ; P &2811 f0 04 BEQ &2817 ; decrease_volume &2813 60 RTS # Leave with A = keycode ; increase_volume &2814 38 SEC # Set carry to indicate increase volume ; increase_or_decrease_volume &2815 b0 01 BCS &2818 ; change_volume # Always branches ; decrease_volume &2817 18 CLC # Clear carry to indicate decrease volume ; change_volume &2818 ae 5f 28 LDX &285f ; volume &281b 90 02 BCC &281f ; skip_inx &281d e8 INX &281e e8 INX ; skip_inx &281f ca DEX &2820 8a TXA &2821 c9 05 CMP #&05 &2823 d0 02 BNE &2827 ; skip_ceiling &2825 a9 04 LDA #&04 ; skip_ceiling &2827 c9 ff CMP #&ff &2829 d0 02 BNE &282d ; skip_floor &282b a9 00 LDA #&00 ; skip_floor &282d 8d 5f 28 STA &285f ; volume &2830 0a ASL A &2831 aa TAX &2832 bd 60 28 LDA &2860,X ; amplitudes_table &2835 8d 78 28 STA &2878 ; envelope_1 + 13 (ALD, decay amplitude target) &2838 8d 86 28 STA &2886 ; envelope_2 + 13 (ALD, decay amplitude target) &283b e8 INX &283c bd 60 28 LDA &2860,X ; amplitudes_table &283f 8d 75 28 STA &2875 ; envelope_1 + 10 (AS, sustain amplitude change) &2842 8d 83 28 STA &2883 ; envelope_2 + 10 (AS, sustain amplitude change) ; initialise_envelopes &2845 a2 79 LDX #&79 ; &2879 = envelope_2 &2847 a0 28 LDY #&28 &2849 a9 08 LDA #&08 ; Define a sound envelope &284b 20 f1 ff JSR &fff1 ; OSWORD &284e a2 6b LDX #&6b ; &286b = envelope_1 &2850 a0 28 LDY #&28 &2852 a9 08 LDA #&08 ; Define a sound envelope &2854 20 f1 ff JSR &fff1 ; OSWORD &2857 a9 fa LDA #&fa &2859 20 a3 1e JSR &1ea3 ; delay &285c a9 00 LDA #&00 # Leave with zero to indicate key has been processed &285e 60 RTS ; volume &285f 02 ; amplitudes_table &2860 00 00 &2862 1f ff &2864 3f fe &2866 5f fe &2868 7e fe ; unused &286a e5 ; envelope_1 # Music channels 1 and 2 &286b 01 01 00 00 00 01 01 01 3c fc fe ff 00 32 ; envelope_2 # Music channel 3 &2879 02 01 00 00 00 01 01 01 9c 19 fe 01 00 32 ; unused &2887 e5 e5 e5 e5 e5 e5 e5 e5 e5 ; code_letters ; 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 &2890 0a 7b 08 04 7b 12 65 0e 20 69 07 69 20 69 02 ; L ? B F ? T ! H Z - C - Z - D # decrypted_letter = (encrypted_letter -1) ^ &45 ; unused &289f 0d ; character_definition &28a0 46 ; "F" &28a1 7e 60 60 7c 60 60 60 00 # Data consistent with "F" ; show_level_code_letter &28a9 ae 6e 25 LDX &256e ; level_number &28ac ca DEX # level_number was incremented at &25e7 &28ad 8e e3 26 STX &26e3 ; sprite_to_use_for_pattern &28b0 a9 41 LDA #&41 ; "A" &28b2 8d a0 28 STA &28a0 ; character_definition ; show_alphabet_loop &28b5 20 e0 28 JSR &28e0 ; show_letter # Show alphabet letter &28b8 ee a0 28 INC &28a0 ; character_definition &28bb ac a0 28 LDY &28a0 ; character_definition &28be c0 5b CPY #&5b ; "Z" + 1 &28c0 d0 f3 BNE &28b5 ; show_alphabet_loop &28c2 ae 6e 25 LDX &256e ; level_number &28c5 ca DEX &28c6 bd 8f 28 LDA &288f,X ; code_letters - 1 &28c9 aa TAX &28ca ca DEX &28cb 8a TXA &28cc 49 45 EOR #&45 &28ce 8d a0 28 STA &28a0 ; character_definition &28d1 a9 0b LDA #&0b ; PIECE_MASK &28d3 8d e3 26 STA &26e3 ; sprite_to_use_for_pattern &28d6 20 e0 28 JSR &28e0 ; show_letter # Show code letter &28d9 20 d1 24 JSR &24d1 ; long_delay &28dc 20 19 4c JSR &4c19 ; consider_saving_data &28df 60 RTS ; show_letter &28e0 a9 0a LDA #&0a ; Read character definition &28e2 a2 a0 LDX #&a0 ; &28a0 = character_definition &28e4 a0 28 LDY #&28 &28e6 20 f1 ff JSR &fff1 ; OSWORD &28e9 a0 09 LDY #&09 ; copy_letter_pattern_loop &28eb b9 a0 28 LDA &28a0,Y ; character_definition &28ee 99 c4 26 STA &26c4,Y ; masks_pattern - 1 &28f1 88 DEY &28f2 d0 f7 BNE &28eb ; copy_letter_pattern_loop &28f4 20 d2 26 JSR &26d2 ; plot_masks_pattern &28f7 a9 64 LDA #&64 &28f9 20 a3 1e JSR &1ea3 ; delay &28fc 60 RTS ; unused # &28fd - &28ff is a copy of &28fa - &28fc &28fd a3 1e 60 ; entry_point &2900 a9 8b LDA #&8b ; Set filing system attributes # *OPT 1,0 &2902 a2 01 LDX #&01 &2904 a0 00 LDY #&00 &2906 20 f4 ff JSR &fff4 ; OSBYTE &2909 a9 55 LDA #&55 # Maximum level number is stored obfuscated &290b 85 3f STA &3f ; maximum_level_plus_one &290d a9 0e LDA #&0e ; Enable event &290f a2 06 LDX #&06 ; ESCAPE pressed event &2911 20 f4 ff JSR &fff4 ; OSBYTE &2914 a9 04 LDA #&04 ; Define action of cursor editing keys &2916 a2 01 LDX #&01 ; Cursor keys return ASCII values 135-139 &2918 20 f4 ff JSR &fff4 ; OSBYTE &291b a9 c8 LDA #&c8 ; Read/Write BREAK/ESCAPE effect &291d a2 03 LDX #&03 ; Clear memory on next RESET &291f 20 f4 ff JSR &fff4 ; OSBYTE &2922 a9 00 LDA #&00 ; &5500 = sprite_address_table &2924 85 5a STA &5a ; sprite_addresses_low &2926 a9 55 LDA #&55 &2928 85 5b STA &5b ; sprite_addresses_high &292a a9 80 LDA #&80 ; &3680 = ? # Value is overwritten at &239f &292c 85 56 STA &56 ; screen_addresses_low &292e a9 36 LDA #&36 &2930 85 57 STA &57 ; screen_addresses_high &2932 20 45 28 JSR &2845 ; initialise_envelopes &2935 a9 45 LDA #&45 &2937 45 3f EOR &3f ; maximum_level_plus_one &2939 85 3f STA &3f ; maximum_level_plus_one &293b a2 04 LDX #&04 ; move_5800_5bff_page_loop # Move &5800 - &5bff to &0400 - &07ff &293d a0 00 LDY #&00 ; move_5800_5bff_byte_loop &293f b9 00 58 LDA &5800,Y # actually LDA source_address,Y &2942 99 00 04 STA &0400,Y # actually STA target_address,Y &2945 c8 INY &2946 d0 f7 BNE &293f ; move_5800_5bff_byte_loop &2948 ee 41 29 INC &2941 ; source_address_high &294b ee 44 29 INC &2944 ; target_address_high &294e ca DEX &294f d0 ec BNE &293d ; move_5800_5bff_page_loop &2951 20 db 06 JSR &06db ; initialise_screen &2954 20 6e 25 JSR &256e ; main &2957 60 RTS ; unused &2958 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 &2968 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 &2978 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 &2988 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 &2998 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 &29a8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 &29b8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 &29c8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 &29d8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 &29e8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 &29f8 00 00 00 00 00 00 00 00 ; sprite_wall_bricks &2a00 1d 1d dd 00 47 47 77 00 0f 0f ff 00 1d 1d dd 00 &2a10 47 47 77 00 0f 0f ff 00 0e 0e ee 00 2b 2b bb 00 &2a20 8f 8f ff 00 0e 0e ee 00 1d 1d dd 00 8f 8f ff 00 &2a30 8f 8f ff 00 0f 0f ff 00 2b 2b bb 00 47 47 77 00 &2a40 0e 0e ee 00 1d 1d dd 00 ; sprite_wall_hatched &2a48 0f 0f 07 07 0b 0b 0d 0d 0b 0b 0d 0d 0e 0e 0f 0f &2a58 0e 0e 0f 0f 0f 0f 07 07 0a 0a 07 07 0f 0f 0f 0f &2a68 0e 0e 05 05 0b 0b 07 07 0b 0b 0d 0d 0e 0e 0d 0d &2a78 0e 0e 0d 0d 0a 0a 07 07 0f 0f 0f 0f 0e 0e 05 05 &2a88 0b 0b 07 07 0b 0b 0d 0d ; sprite_wall_stones &2a90 00 26 1f 0f 0f 0f 0e 04 0e 04 00 88 08 02 17 07 &2aa0 0e 0e 04 01 03 07 07 02 00 01 03 03 8b 0b 09 00 &2ab0 02 88 4d 0d 0c 0c 09 03 00 08 4c 0d 09 03 89 4d &2ac0 01 03 03 09 4c 0c 08 00 03 8b 0b 01 04 2e 0e 0e &2ad0 0c 0c 0c 08 01 01 04 2e ; set_wall_sprite &2ad8 ae 6e LDX &256e ; level_number &2adb ca DEX &2adc bd f0 2a LDA &2af0,X ; level_wall_types_table &2adf 8d e6 2a STA &2ae6 ; source_address_low &2ae2 a0 48 LDY #&48 ; set_wall_sprite_loop &2ae4 88 DEY &2ae5 b9 00 2a LDA &2a00,Y ; sprite_wall_bricks # actually LDA source_address,Y &2ae8 99 b0 55 STA &55b0,Y ; sprite_wall_source &2aeb c0 00 CPY #&00 &2aed d0 f5 BNE &2ae4 ; set_wall_sprite_loop &2aef 60 RTS ; level_wall_types_table ; 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 &2af0 00 48 90 00 48 90 00 48 90 90 90 48 48 00 00 ; unused &2aff 00 ; unused &2b00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 &2b10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 &2b20 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 &2b30 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 &2b40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 &2b50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 &2b60 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 &2b70 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 &2b80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 &2b90 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 &2ba0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 &2bb0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 &2bc0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 &2bd0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 &2be0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 &2bf0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; plot_level_title &2c00 a9 90 LDA #&90 ; &2c90 = level_titles - &17 &2c02 85 53 STA &53 ; text_address_low &2c04 a9 2c LDA #&2c &2c06 85 54 STA &54 ; text_address_high &2c08 ae 6e 25 LDX &256e ; level_number ; calculate_level_title_address_loop &2c0b a5 53 LDA &53 ; text_address_low &2c0d 18 CLC &2c0e 69 17 ADC #&17 &2c10 85 53 STA &53 ; text_address_low &2c12 90 02 BCC &2c16 ; skip_page &2c14 e6 54 INC &54 ; text_address_high ; skip_page &2c16 ca DEX &2c17 d0 f2 BNE &2c0b ; calculate_level_title_address_loop &2c19 20 c2 23 JSR &23c2 ; plot_text # Plot level title &2c1c a9 5a LDA #&5a &2c1e 8d 8c 21 STA &218c ; number_screen_address_high &2c21 a9 e8 LDA #&e8 &2c23 8d 8b 21 STA &218b ; number_screen_address_low &2c26 ad 6e 25 LDA &256e ; level_number &2c29 0a ASL A &2c2a aa TAX &2c2b bd 87 2c LDA &2c87,X ; level_numbers - 2 &2c2e 20 81 21 JSR &2181 ; plot_number # Plot first digit of level number &2c31 a9 f0 LDA #&f0 &2c33 8d 8b 21 STA &218b ; number_screen_address_low &2c36 ad 6e 25 LDA &256e ; level_number &2c39 0a ASL A &2c3a aa TAX &2c3b e8 INX &2c3c bd 87 2c LDA &2c87,X ; level_numbers - 2 &2c3f 20 81 21 JSR &2181 ; plot_number # Plot second digit of level number &2c42 60 RTS ; check_for_alternative_keys &2c43 c9 99 CMP #&99 ; cursor left &2c45 d0 02 BNE &2c49 ; not_cursor_left &2c47 a9 e1 LDA #&e1 ; Z ; not_cursor_left &2c49 c9 f9 CMP #&f9 ; cursor right &2c4b d0 02 BNE &2c4f ; not_cursor_right &2c4d a9 c2 LDA #&c2 ; X ; not_cursor_right &2c4f c9 b9 CMP #&b9 ; cursor up &2c51 d0 02 BNE &2c55 ; not_cursor_up &2c53 a9 c8 LDA #&c8 ; * ; not_cursor_up &2c55 c9 a9 CMP #&a9 ; cursor down &2c57 d0 02 BNE &2c5b ; not_cursor_down &2c59 a9 e8 LDA #&e8 ; / ; not_cursor_down &2c5b 60 RTS ; unused # Source code fragment; doesn't correspond to binary &2c5c 3a 53 54 41 26 35 31 31 0d ; ... :STA&511 &2c65 3c 8c 21 4c 44 41 23 30 3a 53 54 41 26 34 33 35 ; 15500LDA#0: &2c75 3a 53 54 41 26 35 31 30 3a 53 54 41 26 34 30 45 ; STA&435: &2c85 0d ; STA&510: ; STA&40E &2c86 3c ; ... ; unused &2c87 00 4d ; level_numbers &2c89 00 01 ; "01" &2c8b 00 02 ; "02" &2c8d 00 03 ; "03" &2c8f 00 04 ; "04" &2c91 00 05 ; "05" &2c93 00 06 ; "06" &2c95 00 07 ; "07" &2c97 00 08 ; "08" &2c99 00 09 ; "09" &2c9b 01 00 ; "10" &2c9d 01 01 ; "11" &2c9f 01 02 ; "12" &2ca1 01 03 ; "13" &2ca3 01 04 ; "14" &2ca5 01 05 ; "15" ; level_titles &2ca7 04 04 20 20 20 44 4f 54 53 20 41 4e 44 20 57 41 ; " DOTS AND WAVES " &2cb7 56 45 53 20 20 20 0d &2cbe 04 04 20 20 20 53 4f 4d 45 54 48 49 4e 47 20 46 ; " SOMETHING FISHY " &2cce 49 53 48 59 20 20 0d &2cd5 04 04 20 20 43 48 49 43 4b 45 4e 20 53 55 50 52 ; " CHICKEN SUPREME " &2ce5 45 4d 45 20 20 20 0d &2cec 04 04 20 20 45 58 50 4c 4f 53 49 56 45 20 4d 49 ; " EXPLOSIVE MIXTURE " &2cfc 58 54 55 52 45 20 0d &2d03 04 04 20 20 20 48 45 4e 52 59 53 20 41 4e 47 55 ; " HENRYS ANGUISH " &2d13 49 53 48 20 20 20 0d &2d1a 04 04 20 20 20 54 48 45 20 44 4f 4c 4c 53 20 48 ; " THE DOLLS HOUSE " &2d2a 4f 55 53 45 20 20 0d &2d31 04 04 20 20 20 44 4f 4c 4c 59 53 20 52 45 56 45 ; " DOLLYS REVENGE " &2d41 4e 47 45 20 20 20 0d &2d48 04 04 20 20 20 45 4e 4c 49 47 48 54 45 4e 4d 45 ; " ENLIGHTENMENT " &2d58 4e 54 20 20 20 20 0d &2d5f 04 04 20 20 20 54 48 45 20 43 48 41 4c 4c 45 4e ; " THE CHALLENGE " &2d6f 47 45 20 20 20 20 0d &2d76 04 04 20 20 50 41 54 49 45 4e 43 45 20 50 45 4e ; " PATIENCE PENDING " &2d86 44 49 4e 47 20 20 0d &2d8d 04 04 20 20 20 20 20 52 41 5a 4f 52 20 45 44 47 ; " RAZOR EDGE " &2d9d 45 20 20 20 20 20 0d &2da4 04 04 20 20 20 54 48 45 20 48 41 50 50 59 20 48 ; " THE HAPPY HOUR " &2db4 4f 55 52 20 20 20 0d &2dbb 04 04 20 20 20 20 20 20 44 45 4a 41 20 56 55 20 ; " DEJA VU " &2dcb 20 20 20 20 20 20 0d &2dd2 04 04 20 20 20 20 50 45 4e 55 4c 54 49 4d 41 54 ; " PENULTIMATE " &2de2 45 20 20 20 20 20 0d &2de9 04 04 20 20 20 20 54 48 45 20 44 45 43 4f 44 45 ; " THE DECODER " &2df9 52 20 20 20 20 20 0d ; level_15_data ; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% &2e00 00 00 00 00 00 11 11 01 00 00 01 00 00 00 00 ; % %%%%% % % &2e0f 10 11 10 0a 07 11 11 00 70 07 01 00 00 02 07 ; % %%% %Z v %%%% vv % 1 v % &2e1e 00 07 10 00 15 11 00 00 b0 01 01 00 00 30 0d ; % v % -%%% *% % 2o % &2e2d 11 05 10 08 00 01 00 00 00 00 01 00 00 00 00 ; %%%- %< % % % &2e3c e1 09 00 00 1d 11 19 11 11 01 a1 11 11 11 11 ; %%TX o%%%X%%%%%% %Z%%%%%%%%% &2e4b 11 01 00 01 50 91 01 00 c0 01 15 00 00 00 b0 ; %%%% % -%X% /% -% *% &2e5a 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 ; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% &2e69 11 00 07 01 00 00 00 00 00 00 00 00 00 00 00 ; %%% v % % &2e78 11 0d 05 01 10 11 11 00 00 00 00 10 11 11 00 ; %%%o - % %%%%% %%%%% % &2e87 e0 00 00 01 00 00 11 00 10 11 01 10 01 00 00 ; % T % %% %%%% %% % &2e96 10 10 78 01 00 10 01 00 00 00 00 10 11 01 00 ; % % %