Wizadore disassembly ==================== Wizadore was written by Chris Roberts and published by Imagine Software for the BBC Micro in 1985. It is a side-scrolling platform game where the player must collect pieces of a sword, jumping gaps and avoiding or destroying enemies. 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 =============== The game and its custom tape loader are 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. A relocation routine taken from a cracked disc version is included. Code copied from the OS ROM is used to change into MODE 2 without clearing the screen. The flashing colours are disabled to leave two sets of eight static colours. Ladders and cliffs are plotted in colour 15, which is redefined, so that player and enemy sprites can be EORed on top without apparent change. Each ladder has a single red (colour 1) pixel which is used to mark its base. Sprites are stored in columns using run-length encoding. Marker bytes allow the sprites to be plotted from left to right or right to left. When scrolling the screen, a single column of scenery and objects is plotted into a buffer. When entering a level, the screen is drawn by scrolling a column at a time. Each level can have five enemies. The first four are always either archers or birdmen. The fifth enemy is updated in two parts, for its feet and its head. It is the only enemy that can be killed by the player. Interesting Pokes ================= &2087 = &00 infinite lives &2b79 = &a9 archers don't fire arrows &2ea5 = &60 birdmen don't drop swords &2dfc = &92 arrows don't kill player &2e17 = &92 swords don't kill player &2f03 = &ea enemies don't kill player &2069 = &ff falling doesn't kill player &2602 = &04 wider jump &21d3 = &ae view level being plotted Loader Disassembly ================== ; wizadore ; 001900 0020e3 000840 ; sprite_0 (castle) &1900 50 3f 00 09 00 0e 04 81 d7 c1 00 0a 30 15 10 2a &1910 00 88 0e 0c 04 03 6b 83 42 00 2d 30 04 10 14 00 &1920 54 07 3c 06 28 05 00 c2 00 37 30 41 0a 00 94 07 &1930 3c a8 1e 00 04 01 00 04 30 05 34 22 3c 0c 34 43 &1940 04 0c 0d 2c 1f 04 c3 06 17 c1 00 37 3c 43 30 0c &1950 09 03 6b 83 42 00 10 30 09 38 1e 3c 43 58 48 1a &1960 00 06 28 0a 3c 40 82 04 03 c2 00 09 30 0b 24 09 &1970 30 04 38 16 3c 43 06 30 0a 10 06 14 81 83 d7 41 &1980 0b 00 68 05 3c 00 e4 16 0c 64 06 30 43 69 12 3c &1990 43 70 04 34 10 3c 05 03 6b 42 0c 00 fc 00 4c 05 &19a0 08 08 00 07 08 0a 0c 07 03 69 0e 3c 43 7c 04 28 &19b0 11 00 04 02 10 00 7c a8 00 18 00 48 07 0c 0a 03 &19c0 69 0a 3c 43 4c 07 04 1d 00 04 14 fc 18 00 81 c3 &19d0 04 01 00 1a 00 c8 05 0c 6a bf 97 09 03 a9 07 3c &19e0 43 3f 0c 06 0c c3 05 2b d7 41 00 19 00 55 7f 05 &19f0 0c c0 aa bf 0a 03 06 3c 43 09 0c 2d 08 0d 1c 48 &1a00 08 03 c2 00 1d 00 55 cc c0 95 bf 05 0f 47 04 03 &1a10 05 3c 43 48 38 00 68 07 3c c0 c2 00 1c 00 ea cc &1a20 55 bf af 0a 0f 87 43 04 3c 43 f0 d0 29 00 81 c3 &1a30 04 01 08 00 a8 fc 00 1f 00 cc 10 0f 83 a9 fc 43 &1a40 1c 34 11 3c 04 03 05 2b 57 c1 80 d4 04 3c 00 1c &1a50 00 d5 cc 6a bf 9f 0e 0f fc 43 ec fc 27 28 42 08 &1a60 03 56 0a 3c 0a 00 81 c3 c1 00 06 30 06 10 11 00 &1a70 6a cc c0 aa bf 0d 0f fc 43 3f 0c 0e 0c c3 05 2b &1a80 57 41 00 19 30 04 3a 05 18 04 10 ba 09 1a cf 04 &1a90 3c 43 cc 3f 08 0b 08 08 03 42 00 34 30 f8 92 87 &1aa0 85 44 3a 00 c1 0e 00 c2 00 07 30 05 34 2c 30 4f &1ab0 05 0c 35 04 81 43 05 17 41 00 04 34 16 3c 11 34 &1ac0 a0 0c 30 4f 3a 0c 08 03 6b 42 00 2a 3c c0 0b 3c &1ad0 4f 05 08 36 00 82 c3 c2 00 1f 3c 12 00 07 3c 4f &1ae0 4c c4 21 00 81 c3 c1 00 2a 3c c0 0b 3c 4f 25 0c &1af0 c3 05 2b 57 41 00 2b 3c 94 0c 3c 4f 05 0c 20 08 &1b00 82 08 03 42 00 34 3c 04 28 4a 48 25 00 c2 00 19 &1b10 3c 16 28 00 06 3c 06 28 00 00 ; sprite_1 (wizadore) &1b1a 15 00 c4 00 c4 0c 00 c4 8c cd 8f 8c 00 8c 8e 8f &1b2a cd 8c 05 04 8c cd ce 48 8e 8f 8c 00 40 88 8e 06 &1b3a 0f ce 8c c8 05 00 48 00 44 8d 06 0f 4c 08 00 44 &1b4a 8c 8d 8c 00 8c 4e 07 0f 4d 8c c4 8c cd cf 8c 00 &1b5a 40 c8 8c 04 0e cf 05 0e 8c 05 08 00 80 94 7c 94 &1b6a 04 00 05 08 c0 a8 7c 78 bc 94 00 bc b8 b0 b4 bc &1b7a a8 0c 00 94 bc f0 bc 00 bc f0 0f 38 04 30 bc 00 &1b8a bc 70 b4 bc 0d 28 bc 04 30 bc 00 a8 bc 74 bc a8 &1b9a 0a 00 94 7c f4 bc a8 00 c3 41 0b 00 41 83 93 83 &1baa 41 00 43 73 53 83 41 07 00 82 83 a3 f3 93 83 00 &1bba 43 f3 e3 53 83 41 05 00 82 83 a3 73 83 00 43 73 &1bca 43 40 42 63 53 83 41 80 81 83 93 73 83 00 86 43 &1bda b3 93 83 4b 81 c5 42 63 d3 04 33 83 00 4d 87 83 &1bea e3 87 cc 04 0e c7 04 23 83 82 00 45 05 00 8a 8f &1bfa 4c 04 0d 4c ce 8f 85 00 8f 8e 8f 05 00 8f 4c 8f &1c0a 45 4f 8e 04 0c 8e 8f 85 00 8f 8c 07 0e 04 0c 07 &1c1a 0d cc 8f 00 8a 8f 07 0d 8f 04 0a 05 00 4a 8f 8d &1c2a 8f 00 91 b3 63 73 0a 00 a2 73 63 b3 91 00 b3 43 &1c3a 73 0d 11 b3 a3 43 a3 b3 00 73 04 03 0d 13 c3 73 &1c4a 00 62 b3 53 43 63 b3 06 11 b3 a3 c3 93 b3 a2 00 &1c5a 04 00 04 22 b3 08 13 b3 04 22 00 07 00 0b 15 00 &1c6a 40 55 bf fe 09 3c 7e bf 55 00 95 bf be 04 3c 7d &1c7a bf 04 2a bf 7d 04 3c be bf 95 00 7f 04 3c be bf &1c8a 55 04 00 55 bf be 04 3c 7f 00 80 aa bf 7d 04 3c &1c9a 06 3e 04 3c 7d bf aa 00 04 00 ea bf 09 3d bf 6a &1caa 00 45 0e 00 45 8f 8e 8f 45 00 4f 45 0b 00 8a 8f &1cba 8d 04 0c 4f 00 8f 4c 04 0e 8f 09 05 8f 8e cc 4f &1cca 00 8f 8c 06 0d 04 0c 08 0d 4c 4f 00 ca 80 45 8f &1cda 8e 04 0c 8e 8f 85 40 85 8f 8e 8c 8d 8f 8a 00 80 &1cea 85 8f 4e 8c 8d 8f 4a 8f 8d 4c 04 0e 8c 4d 8f 8a &1cfa 00 4f 8d 8c 8d 8f 8a 04 00 4a 8f 04 0d 8f 4a 00 &1d0a 40 8a 05 0b 0c 01 00 81 83 53 73 07 23 73 e3 b3 &1d1a d3 83 81 00 83 04 33 83 82 04 00 81 83 73 83 80 &1d2a 42 83 a3 73 83 00 82 83 a3 73 93 83 41 40 83 63 &1d3a 83 82 c0 81 83 73 83 00 40 42 83 e3 43 08 00 43 &1d4a 63 83 82 00 00 ; sprite_2 (imagine) &1d4f 16 00 05 03 0e 02 83 c2 83 00 c0 85 8f 4a 8f 85 &1d5f 05 00 4a 06 00 c3 82 80 94 0b 3e bf 95 80 94 be &1d6f bf 95 00 c0 8a 8f 45 8f 8a 05 00 4a 06 00 c3 81 &1d7f 80 a8 0c 3c aa 80 a8 7c aa 00 c0 06 05 05 00 45 &1d8f 4f 45 40 04 03 82 80 0c 15 80 82 c1 83 00 05 00 &1d9f 4f 80 4f 06 00 4f 04 00 c3 40 0c 3c be bf 40 c3 &1daf 00 07 00 4a 05 00 07 05 80 04 03 81 80 0a 28 7c &1dbf a8 80 81 c3 00 06 00 45 08 00 4f 04 00 c3 82 80 &1dcf 94 0a 3e bc a8 80 81 04 03 20 00 07 14 00 c0 ca &1ddf 4f 4a 04 00 ca 05 00 04 03 81 80 0a 28 7c 40 04 &1def 03 20 00 7c 00 06 00 4a 06 00 85 8f 8a 8f 85 c0 &1dff c3 82 80 94 0a 3e fc 40 c3 20 00 68 00 c0 4a 4f &1e0f ca 04 00 8f 8a 85 8f 8a c0 c3 81 80 a8 0c 3c a8 &1e1f 80 81 c3 20 00 94 bc e8 bc 94 00 c0 45 8f 8a 0f &1e2f 00 05 03 81 40 08 15 40 81 05 03 20 00 a8 bc d4 &1e3f bc a8 00 04 00 c5 07 00 ca 8f 85 c0 c3 82 80 94 &1e4f fe 06 3c 7e bf 95 80 82 c3 20 00 06 14 00 c0 4f &1e5f 80 4f 06 00 c5 8f 8a c0 c3 40 7c 68 05 01 68 fc &1e6f 40 c3 22 00 7c 80 7c 00 c0 8a 80 4a 08 00 c5 04 &1e7f 00 c3 81 80 a8 7c 07 15 be 7c a8 80 81 c3 20 00 &1e8f 06 28 00 80 45 80 c5 07 00 4f 80 4f c0 c3 40 0c &1e9f 3c bf bd 40 c3 20 00 7c e8 7c 00 4f 80 4f 80 4f &1eaf 06 00 04 0a 04 00 04 03 81 80 0c 28 80 81 04 03 &1ebf 20 00 a8 bc d4 bc a8 00 80 06 0a 07 00 ca 8f 85 &1ecf c0 82 80 d4 40 55 bf 05 3e bf 55 80 82 04 03 20 &1edf 00 54 c0 54 00 c0 85 8f 8a 8f 85 08 00 8a 8f 85 &1eef 04 00 fc a8 80 bf be 7c 05 28 7c be bf 40 c3 20 &1eff 00 7c e8 7c 00 c0 4f 85 8f 8a 06 00 04 0a 05 00 &1f0f fc 40 a8 7c 94 80 c2 80 94 7c a8 80 81 c3 20 00 &1f1f 07 14 00 c0 04 05 07 00 85 8f 8a 8f 85 04 00 a8 &1f2f 08 3c 05 3e fc bf 40 c3 24 00 7c 94 00 05 00 85 &1f3f 8f 8a 06 00 8f 8a 85 8f 8a c0 43 81 80 0e 28 80 &1f4f 81 04 02 20 00 06 28 00 c0 c5 8f 8a 0e 00 43 82 &1f5f 80 94 0c 3e bf 95 80 94 be bf 95 20 00 94 bc e8 &1f6f bc 94 00 04 00 c5 0f 00 43 81 80 a8 0d 3c a8 80 &1f7f a8 7c a8 20 00 a8 bc 94 bc 80 bc a8 00 c0 4f 80 &1f8f 4f 0e 00 c3 40 0d 15 80 82 04 01 00 c0 8a 80 4a &1f9f 0f 00 43 40 0d 3c 7e 40 c3 20 00 68 00 16 00 c3 &1faf 81 80 0a 28 7c bd 40 81 c3 20 00 68 00 16 00 43 &1fbf 82 80 94 0a 3e 7c 7e 40 c3 20 00 68 00 16 00 43 &1fcf 81 80 a8 0c 3c a8 80 81 04 03 00 16 00 04 03 41 &1fdf 40 07 15 c0 06 03 00 16 00 c3 82 80 94 bc 7e 05 &1fef 3c 7e bf 95 80 82 04 03 00 16 00 43 40 fc a8 40 &1fff fc 40 a8 bc be bf 40 c3 00 16 00 43 40 fc 94 40 &200f fc 55 fc a8 80 81 c3 00 16 00 c3 81 80 a8 7c a8 &201f 80 a8 04 3c 68 41 05 03 00 16 00 05 03 0b 01 08 &202f 03 00 00 ; run_string &2032 52 55 4e 20 57 49 5a 41 44 4f 52 45 0d # "RUN WIZADORE" ; unused &203f 00 00 00 ; sprite_address_high_table &2042 19 1b 1d ; sprite_address_low_table &2045 00 1a 4f ; plot_sprite &2048 8e 95 20 STX &2095 ; screen_address_high # Bottom left of sprite &204b 8d 94 20 STA &2094 ; screen_address_low &204e 86 71 STX &71 ; column_screen_address_high &2050 85 70 STA &70 ; column_screen_address_low &2052 b9 42 20 LDA &2042,Y ; sprite_address_high_table &2055 85 73 STA &73 ; sprite_address_high &2057 b9 45 20 LDA &2045,Y ; sprite_address_low_table &205a 85 72 STA &72 ; sprite_address_low &205c a0 00 LDY #&00 ; plot_sprite_column_loop &205e b1 72 LDA (&72),Y ; sprite_address # Get a byte of sprite data &2060 f0 5f BEQ &20c1 ; end_of_column &2062 aa TAX &2063 10 12 BPL &2077 ; double_or_long_run &2065 29 40 AND #&40 &2067 d0 07 BNE &2070 ; triple_run ; single_run &2069 8a TXA # If top two bits are &80, &206a 29 3f AND #&3f # bottom five bits are pixel_values, run length 1 &206c a2 01 LDX #&01 &206e d0 19 BNE &2089 ; store_pixel_values_and_plot_run # Always branches ; triple_run &2070 8a TXA # If top two bits are &c0, &2071 29 3f AND #&3f # bottom five bits are pixel_values, run length 3 &2073 a2 03 LDX #&03 &2075 d0 12 BNE &2089 ; store_pixel_values_and_plot_run # Always branches ; double_or_long_run &2077 29 40 AND #&40 # If top two bits are &00, bottom five bits are run &2079 f0 07 BEQ &2082 ; move_to_next_byte_of_sprite_data # length, next byte is pixel_values ; double_run &207b 8a TXA # If top two bits are &40 &207c 29 3f AND #&3f # bottom five bits are pixel_values, run length 2 &207e a2 02 LDX #&02 &2080 d0 07 BNE &2089 ; store_pixel_values_and_plot_run # Always branches ; move_to_next_byte_of_sprite_data &2082 c8 INY &2083 d0 02 BNE &2087 ; skip_page &2085 e6 73 INC &73 ; sprite_address_high ; skip_page &2087 b1 72 LDA (&72),Y ; sprite_address ; store_pixel_values_and_plot_run &2089 8d 92 20 STA &2092 ; pixel_values &208c c8 INY &208d d0 02 BNE &2091 ; skip_page &208f e6 73 INC &73 ; sprite_address_high ; skip_page ; plot_run_loop # Plot X copies of pixel values to screen &2091 a9 ff LDA #&ff # actually LDA pixel_values &2093 8d ee ee STA &eeee # actually STA screen_address &2096 ad 94 20 LDA &2094 ; screen_address_low &2099 29 07 AND #&07 &209b f0 08 BEQ &20a5 ; next_group &209d ce 94 20 DEC &2094 ; screen_address_low # Move one pixel up ; next_row &20a0 ca DEX &20a1 d0 ee BNE &2091 ; plot_run_loop &20a3 f0 b9 BEQ &205e ; plot_sprite_column_loop # Get next run at end of run ; next_group &20a5 ce 95 20 DEC &2095 ; screen_address_high &20a8 ce 95 20 DEC &2095 ; screen_address_high &20ab ad 94 20 LDA &2094 ; screen_address_low &20ae 38 SEC &20af e9 79 SBC #&79 &20b1 8d 94 20 STA &2094 ; screen_address_low &20b4 b0 03 BCS &20b9 ; skip_page &20b6 ce 95 20 DEC &2095 ; screen_address_high ; skip_page &20b9 ad 95 20 LDA &2095 ; screen_address_high &20bc c9 32 CMP #&32 # Stop before top of screen &20be b0 e0 BCS &20a0 ; next_row &20c0 60 RTS ; end_of_column &20c1 c8 INY &20c2 d0 02 BNE &20c6 ; skip_page &20c4 e6 73 INC &73 ; sprite_address_high ; skip_page &20c6 b1 72 LDA (&72),Y ; sprite_address # Get next byte of sprite data &20c8 d0 01 BNE &20cb ; not_end_of_sprite # Second &00 byte marks end of sprite &20ca 60 RTS ; not_end_of_sprite &20cb a5 70 LDA &70 ; column_screen_address_low &20cd 18 CLC &20ce 69 08 ADC #&08 # Move two pixels right &20d0 85 70 STA &70 ; column_screen_address_low &20d2 90 02 BCC &20d6 ; skip_page &20d4 e6 71 INC &71 ; column_screen_address_high ; skip_page &20d6 a5 71 LDA &71 ; column_screen_address_high &20d8 8d 95 20 STA &2095 ; screen_address_high &20db a5 70 LDA &70 ; column_screen_address_low &20dd 8d 94 20 STA &2094 ; screen_address_low &20e0 4c 5e 20 JMP &205e ; plot_sprite_column_loop ; entry_point &20e3 a9 16 LDA #&16 # Change to MODE 2 &20e5 20 ee ff JSR &ffee ; OSWRCH &20e8 a9 02 LDA #&02 &20ea 20 ee ff JSR &ffee ; OSWRCH &20ed a9 06 LDA #&06 # R6: Vertical displayed register &20ef 8d 00 fe STA &fe00 ; video register number &20f2 a9 17 LDA #&17 # Set screen to be 22 characters (184 pixels) high &20f4 8d 01 fe STA &fe01 ; video register value &20f7 a9 07 LDA #&07 # R7: Vertical sync position &20f9 8d 00 fe STA &fe00 ; video register number &20fc a9 1f LDA #&1f &20fe 8d 01 fe STA &fe01 ; video register value &2101 a9 0c LDA #&0c # R12: Displayed screen start address register (high) &2103 8d 00 fe STA &fe00 ; video register number &2106 a9 08 LDA #&08 &2108 8d 01 fe STA &fe01 ; video register value &210b a9 0d LDA #&0d # R13: Displayed screen start address register (low) &210d 8d 00 fe STA &fe00 ; video register number &2110 a9 d0 LDA #&d0 # Set screen start address to &4680 &2112 8d 01 fe STA &fe01 ; video register value &2115 a9 80 LDA #&80 ; sprite 0 at &7d80 # Plot castle &2117 a2 7d LDX #&7d &2119 a0 00 LDY #&00 &211b 20 48 20 JSR &2048 ; plot_sprite &211e a9 80 LDA #&80 ; sprite 2 at &7e80 # Plot "LOADING...", "imagine ..the name of the game" &2120 a2 7e LDX #&7e &2122 a0 02 LDY #&02 &2124 20 48 20 JSR &2048 ; plot_sprite &2127 a2 53 LDX #&53 ; sprite 1 at &53a0 # Plot WIZADORE &2129 a9 a0 LDA #&a0 &212b a0 01 LDY #&01 &212d 20 48 20 JSR &2048 ; plot_sprite &2130 a2 01 LDX #&01 # Turn off filing system messages &2132 a0 00 LDY #&00 &2134 a9 8b LDA #&8b ; Set filing system attributes &2136 20 f4 ff JSR &fff4 ; OSBYTE &2139 a2 32 LDX #&32 ; &2032 = run_string # Run second binary &213b a0 20 LDY #&20 &213d 4c f7 ff JMP &fff7 ; OSCLI Tape Protection Disassembly =========================== ; WIZADORE ; 000bea 000bea 000317 ; entry_point &0bea a9 0f LDA #&0f ; Flushes all buffers &0bec a2 00 LDX #&00 &0bee a0 00 LDY #&00 &0bf0 20 f4 ff JSR &fff4 ; OSBYTE &0bf3 4c ea 0c JMP &0cea ; via_decryption &0bf6 20 20 20 20 54 61 70 65 20 70 72 6f 74 65 63 74 ; " Tape protect" &0c06 69 6f 6e 20 62 79 20 4b 65 76 69 6e 45 64 77 61 ; "ion by KevinEdwa" &0c16 72 64 73 20 28 63 29 20 31 39 38 35 20 20 20 20 ; "rds (c) 1985 " &0c26 20 20 20 20 20 20 20 20 20 20 20 20 54 68 69 73 ; " This" &0c36 20 70 72 6f 67 72 61 6d 20 63 61 6e 6e 6f 74 20 ; " program cannot " &0c46 62 65 20 74 72 61 6e 73 66 65 72 65 64 20 74 6f ; "be transfered to" &0c56 20 64 69 73 63 2e 20 55 6e 61 75 74 68 6f 72 69 ; " disc. Unauthori" &0c66 73 65 64 20 64 69 73 63 20 63 6f 70 69 65 73 20 ; "sed disc copies " &0c76 61 72 65 20 69 6c 6c 65 67 61 6c 20 61 6e 64 20 ; "are illegal and " &0c86 69 6d 70 6f 73 73 69 62 6c 65 20 74 6f 20 63 72 ; "impossible to cr" &0c96 65 61 74 65 2e 20 41 6e 79 6f 6e 65 20 77 68 6f ; "eate. Anyone who" &0ca6 20 74 72 61 6e 73 66 65 72 73 20 74 68 69 73 20 ; " transfers this " &0cb6 70 72 6f 67 72 61 6d 20 74 6f 20 64 69 73 63 20 ; "program to disc " &0cc6 69 73 20 76 65 72 79 20 76 65 72 79 20 63 6c 65 ; "is very very cle" &0cd6 76 65 72 2e 20 47 6f 6f 64 20 6c 75 63 6b 2e 2e ; "ver. Good luck.." &0ce6 4b 65 76 2e ; "Kev." ; via_decryption &0cea 78 SEI &0ceb a9 df LDA #&df # Set User VIA timer 2 to timed interrupt &0ced 2d 6b fe AND &fe6b ; User VIA auxiliary control register &0cf0 8d 6b fe STA &fe6b ; User VIA auxiliary control register &0cf3 a9 a0 LDA #&a0 # Enable interrupts for User VIA timer 2 &0cf5 8d 6e fe STA &fe6e ; User VIA interrupt enable register &0cf8 a9 ff LDA #&ff &0cfa 8d 68 fe STA &fe68 ; User VIA timer 2 counter LSB &0cfd 8d 69 fe STA &fe69 ; User VIA timer 2 counter MSB &0d00 a2 00 LDX #&00 ; via_decryption_loop &0d02 ad 00 0d LDA &0d00 # Runs from &0d00 to &0dff, # actually LDA &0d00 + via_decryption_offset # EORs all of &0e00 - &0eff on every loop &0d05 ee 1d 0d INC &0d1d + via_decryption_eor &0d08 18 CLC &0d09 4d 68 fe EOR &fe68 ; User VIA timer 2 counter LSB &0d0c a8 TAY &0d0d ad 1d 0d LDA &0d1d ; via_decryption_eor &0d10 4d fc ff EOR &fffc ; os_reset_address_low # Ensure 6502 reset vector hasn't been changed &0d13 4d 68 fe EOR &fe68 ; User VIA timer 2 counter LSB &0d16 8d 1b 0d STA &0d1b ; via_decryption_add &0d19 98 TYA &0d1a 69 ff ADC #&ff # actually ADC via_decryption_add &0d1c 49 00 EOR #&00 # actually EOR via_decryption_eor &0d1e 4d 68 fe EOR &fe68 ; User VIA timer 2 counter LSB &0d21 4d 40 d9 EOR &d940 ; os_default_vector_table # Ensure OS default vector table hasn't been changed # actually EOR &d900 + via_decryption_rom_offset_one &0d24 ee 1d 0d INC &0d1d ; via_decryption_eor &0d27 4d 69 fe EOR &fe69 ; User VIA timer 2 counter MSB &0d2a 4d cd d9 EOR &d9cd ; os_reset_handler # Ensure OS reset handler hasn't been changed # actually EOR &d900 + via_decryption_rom_offset_two &0d2d 5d 02 0d EOR &0d02,X ; via_decryption + 2 &0d30 4d 1c dc EOR &dc1c ; os_irq_handler # Ensure OS main IRQ handler hasn't been changed # actually EOR &dc00 + via_decryption_rom_offset_three &0d33 5d 00 0e EOR &0e00,X ; payload &0d36 4d 68 fe EOR &fe68 ; User VIA timer 2 counter LSB &0d39 4d d9 ea EOR &ead9 ; os_break_intercept_handler # Ensure OS break intercept handler hasn't been changed # actually EOR &ea00 + via_decryption_rom_offset_four # (OSBYTE 247 (&f7), calls &0287 after BREAK) &0d3c 38 SEC &0d3d 6d 03 0d ADC &0d03 ; via_decryption_offset &0d40 4d fd ff EOR &fffd ; os_reset_address_high &0d43 4d 68 fe EOR &fe68 ; User VIA timer 2 counter LSB &0d46 18 CLC &0d47 7d 01 0e ADC &0e01,X ; payload + 1 # Runs from &0e01 to &0f00 &0d4a 4d 93 dc EOR &dc93 ; os_irq1v_handler # Ensure OS IRQ1 handler hasn't been changed # actually EOR &dc00 + via_decryption_rom_offset_five &0d4d ee 1b 0d INC &0d1b ; via_decryption_add &0d50 a8 TAY &0d51 ad 1b 0d LDA &0d1b ; via_decryption_add &0d54 4d 68 fe EOR &fe68 ; User VIA timer 2 counter LSB &0d57 8d 1b 0d STA &0d1b ; via_decryption_add &0d5a 98 TYA &0d5b 4d b0 da EOR &dab0 ; ? # Runs over &da00 - &daff # actually EOR &da00 + via_decryption_rom_offset_six # (System VIA setup, OS sideways ROM checking) &0d5e 4d 69 fe EOR &fe69 ; User VIA timer 2 counter MSB &0d61 4d 68 fe EOR &fe68 ; User VIA timer 2 counter LSB &0d64 9d 00 0e STA &0e00,X ; payload &0d67 e8 INX &0d68 d0 98 BNE &0d02 ; via_decryption_loop &0d6a a9 03 LDA #&03 &0d6c 8d 58 02 STA &0258 ; ESCAPE/BREAK effect &0d6f a9 4c LDA #&4c ; JMP # Set BREAK intercept code to JMP &0287, endless loop &0d71 8d 87 02 STA &0287 ; BREAK intercept code &0d74 a9 87 LDA #&87 &0d76 8d 88 02 STA &0288 ; BREAK intercept code + 1 &0d79 a9 02 LDA #&02 &0d7b 8d 89 02 STA &0289 ; BREAK intercept code + 2 &0d7e ee 31 0d INC &0d31 ; via_decryption_rom_offset_three &0d81 ee 2b 0d INC &0d2b ; via_decryption_rom_offset_two &0d84 ee 3a 0d INC &0d3a ; via_decryption_rom_offset_four &0d87 a0 35 LDY #&35 # Reset all vectors to OS defaults ; reset_vector_table_loop &0d89 b9 40 d9 LDA &d940,Y ; os_default_vector_table &0d8c 99 00 02 STA &0200,Y ; os_vector_table &0d8f 88 DEY &0d90 10 f7 BPL &0d89 ; reset_vector_table_loop &0d92 ee 22 0d INC &0d22 ; via_decryption_rom_offset_one &0d95 ee 4b 0d INC &0d4b ; via_decryption_rom_offset_five &0d98 ee 5c 0d INC &0d5c ; via_decryption_rom_offset_six &0d9b ad 1d 0d LDA &0d1d ; via_decryption_eor &0d9e 4d 68 fe EOR &fe68 ; User VIA timer 2 counter LSB &0da1 8d 1d 0d STA &0d1d ; via_decryption_eor &0da4 ee 1d 0d INC &0d1d ; via_decryption_eor &0da7 ee 03 0d INC &0d03 ; via_decryption_offset &0daa ad 03 0d LDA &0d03 ; via_decryption_offset &0dad c9 00 CMP #&00 &0daf f0 03 BEQ &0db4 ; calculate_checksum &0db1 4c 02 0d JMP &0d02 ; via_decryption_loop ; calculate_checksum &0db4 a9 00 LDA #&00 # Checksum &0e00 - &0efd &0db6 85 70 STA &70 ; calculated_checksum_one &0db8 85 71 STA &71 ; calculated_checksum_two &0dba a8 TAY ; calculate_checksum_loop &0dbb a5 71 LDA &71 ; calculated_checksum_two &0dbd 59 00 0e EOR &0e00,Y ; payload &0dc0 85 71 STA &71 ; calculated_checksum_two &0dc2 a2 08 LDX #&08 ; calculate_checksum_inner_loop &0dc4 a5 71 LDA &71 ; calculated_checksum_two &0dc6 2a ROL A &0dc7 90 0c BCC &0dd5 ; clear_set &0dc9 a5 71 LDA &71 ; calculated_checksum_two &0dcb 49 08 EOR #&08 &0dcd 85 71 STA &71 ; calculated_checksum_two &0dcf a5 70 LDA &70 ; calculated_checksum_one &0dd1 49 10 EOR #&10 &0dd3 85 70 STA &70 ; calculated_checksum_one ; clear_set &0dd5 26 70 ROL &70 ; calculated_checksum_one &0dd7 26 71 ROL &71 ; calculated_checksum_two &0dd9 ca DEX &0dda d0 e8 BNE &0dc4 ; calculate_checksum_inner_loop &0ddc c8 INY &0ddd c0 fe CPY #&fe &0ddf d0 da BNE &0dbb ; calculate_checksum_loop &0de1 a5 70 LDA &70 ; calculated_checksum_one &0de3 cd fe 0e CMP &0efe ; valid_checksum_one &0de6 d0 07 BNE &0def ; invalid_checksum &0de8 a5 71 LDA &71 ; calculated_checksum_two &0dea cd ff 0e CMP &0eff ; valid_checksum_two &0ded f0 11 BEQ &0e00 ; payload # If the checksum matches, run the decrypted code ; invalid_checksum &0def a9 c8 LDA #&c8 ; Read/Write BREAK/ESCAPE effect # This is handled by the OS OSBYTE handler at &e99c, &0df1 a2 03 LDX #&03 ; Clear memory on next RESET # which isn't checked in the decryption routine, &0df3 a0 00 LDY #&00 # so could be intercepted with a custom ROM &0df5 20 f4 ff JSR &fff4 ; OSBYTE ; endless_wiping_loop # Otherwise, if the checksum doesn't match, &0df8 99 00 0e STA &0e00,Y ; payload # Wipe &0e00 - &0eff (failed decryption) with &c8 &0dfb c8 INY &0dfc d0 fa BNE &0df8 ; endless_wiping_loop &0dfe f0 f8 BEQ &0df8 ; endless_wiping_loop ; payload &0e00 20 0c 0e JSR &0e0c ; move_tape_loader_to_zero_page # Leaves with X = &ff, A = &d9 ; wipe_unrelocated_tape_loader_loop &0e03 9d 0c 0e STA &0e0c,X ; move_tape_loader_to_zero_page # Wipe &0e0d - &0f0b with &d9 &0e06 ca DEX # i.e. remove unrelocated tape loader from main memory &0e07 d0 fa BNE &0e03 ; wipe_unrelocated_tape_loader_loop &0e09 4c 00 00 JMP &0000 ; tape_loader ; move_tape_loader_to_zero_page &0e0c a9 00 LDA #&00 &0e0e a2 0f LDX #&0f ; remove_roms_loop &0e10 9d a1 02 STA &02a1,X ; os_paged_rom_type_table # Remove paged ROMs from ROM information table &0e13 ca DEX &0e14 10 fa BPL &0e10 ; remove_roms_loop &0e16 e8 INX ; move_tape_loader_loop &0e17 bd 39 0e LDA &0e39,X ; unrelocated_tape_loader # Move &0e39 - &0ebc to &0000 - &0083 &0e1a 95 00 STA &00,X ; tape_loader &0e1c e8 INX &0e1d e0 84 CPX #&84 &0e1f d0 f6 BNE &0e17 ; move_tape_loader_loop &0e21 a2 41 LDX #&41 ; move_load_error_loop &0e23 bd bd 0e LDA &0ebd,X ; unrelocated_load_error # Move &0ebd - &0efe to &0120 - &0161 (one byte extra) &0e26 9d 20 01 STA &0120,X ; load_error &0e29 ca DEX &0e2a 10 f7 BPL &0e23 ; move_load_error_loop &0e2c a9 cd LDA #&cd ; &d9cd = os_reset_handler # Interrupts were disabled at &0cea &0e2e 8d 04 02 STA &0204 ; irq1_vector_low # Reset the system if an interrupt somehow occurs &0e31 a9 d9 LDA #&d9 &0e33 8d 05 02 STA &0205 ; irq1_vector_high &0e36 85 fc STA &fc ; irq_accumulator # Next binary checks for this value &0e38 60 RTS # to ensure no interrupts have occurred while loading # &0e39 - &0ebc copied to &0000 - &0083 at &0e17 ; tape_loader &0000 a9 03 LDA #&03 &0002 85 f8 STA &f8 ; waiting_for_start_of_data # Top bit clear to indicate waiting for start of data &0004 8d 08 fe STA &fe08 ; Cassette ACIA control register # Disable transmit and receiver interrupts &0007 a9 05 LDA #&05 # Switch off cassette motor &0009 8d 10 fe STA &fe10 ; Serial ULA control register &000c a2 ff LDX #&ff ; delay_loop &000e ca DEX &000f d0 fd BNE &000e ; delay_loop &0011 a9 85 LDA #&85 # Set to 2400 baud, switch on cassette motor &0013 8d 10 fe STA &fe10 ; Serial ULA control register &0016 a9 d5 LDA #&d5 # 1200 baud, odd parity, 8 bit words, &0018 8d 08 fe STA &fe08 ; Cassette ACIA control register # disable transmit interrupts ; get_data_from_tape # enable all receiver interrupts &001b ad 08 fe LDA &fe08 ; Cassette ACIA status register &001e 10 fb BPL &001b ; get_data_from_tape # Wait for interrupt from the cassette system &0020 a8 TAY &0021 29 01 AND #&01 &0023 f0 f6 BEQ &001b ; get_data_from_tape # Is it a receiver interrupt? If so, &0025 98 TYA &0026 29 70 AND #&70 # Is there a framing, receiver overrun or parity error? &0028 f0 07 BEQ &0031 ; received_data_from_tape # If not, it's data &002a 24 f8 BIT &f8 ; waiting_for_start_of_data &002c 10 ed BPL &001b ; get_data_from_tape # Top bit clear if still waiting for start of data &002e 4c 20 01 JMP &0120 ; load_error # Otherwise, abort the load ; received_data_from_tape &0031 ad 09 fe LDA &fe09 ; Cassette ACIA data register &0034 49 b5 EOR #&b5 # Data is obfuscated on tape &0036 24 f8 BIT &f8 ; waiting_for_start_of_data &0038 30 08 BMI &0042 ; leave # Top bit set if already reading data &003a c9 cd CMP #&cd &003c d0 dd BNE &001b ; get_data_from_tape # Otherwise, wait for &cd byte &003e 85 f8 STA &f8 ; waiting_for_start_of_data # Set top bit to indicate data is being read &0040 f0 01 BEQ &0043 ; read_addresses_from_tape ; leave &0042 60 RTS ; read_addresses_from_tape &0043 a2 00 LDX #&00 ; decrypt_addresses_loop # Read six bytes of addresses from tape &0045 20 1b 00 JSR &001b ; get_data_from_tape # for load address, length and run address &0048 38 SEC &0049 f5 7e SBC &7e,X ; addresses_sub # and decrypt them &004b 55 78 EOR &78,X ; addresses_eor &004d 95 72 STA &72,X ; addresses &004f e8 INX &0050 e0 06 CPX #&06 &0052 d0 f1 BNE &0045 ; decrypt_addresses_loop &0054 a2 00 LDX #&00 ; read_data_from_tape_loop &0056 20 1b 00 JSR &001b ; get_data_from_tape # Get a byte of data from the tape &0059 81 72 STA (&72,X) ; write_address # Write it to memory &005b e6 72 INC &72 ; write_address_low &005d d0 02 BNE &0061 ; not_new_page &005f e6 73 INC &73 ; write_address_high ; not_new_page &0061 a5 74 LDA &74 ; length_low # Reduce the bytes still needing to be read by one &0063 d0 02 BNE &0067 ; not_end_of_page &0065 c6 75 DEC &75 ; length_high ; not_end_of_page &0067 c6 74 DEC &74 ; length_low &0069 d0 eb BNE &0056 ; read_data_from_tape_loop &006b a5 75 LDA &75 ; length_high &006d d0 e7 BNE &0056 ; read_data_from_tape_loop # When all the data is loaded from tape to memory, &006f 6c 76 00 JMP (&0076) ; run_address # call the run address to start the loaded binary ; addresses &0072 00 00 00 00 00 00 ; addresses_eor &0078 2d 9b 63 7a 46 67 ; addresses_sub &007e 6e f2 39 cd b3 e9 # &0ebd - &0efe copied to &0120 - &0161 at &0e23 ; load_error &0120 a2 00 LDX #&00 ; wipe_memory_loop &0122 9d 00 04 STA &0400,X # Wipe &0400 - &7fff (main memory, i.e. loaded data) # actually STA wipe_address &0125 e8 INX &0126 d0 fa BNE &0122 ; wipe_memory_loop &0128 ee 24 01 INC &0124 ; wipe_address_high &012b 10 f5 BPL &0122 ; wipe_memory_loop ; wipe_zero_page_loop # Wipe &0000 - &00ff (zero page, i.e. loader) &012d 95 00 STA &00,X ; tape_loader &012f e8 INX &0130 d0 fb BNE &012d ; wipe_zero_page_loop &0132 a9 3f LDA #&3f ; &013f = write_load_error # Set system to call write_load_error on reset &0134 8d 88 02 STA &0288 ; BREAK intercept code + 1 &0137 a9 01 LDA #&01 &0139 8d 89 02 STA &0289 ; BREAK intercept code + 2 &013c 6c fc ff JMP (&fffc) ; os_reset_handler # and reset system ; write_load_error &013f 90 10 BCC &0151 ; leave &0141 a2 00 LDX #&00 ; BRK # Reset the BREAK handler to system default &0143 8e 87 02 STX &0287 ; BREAK intercept code ; write_load_error_loop &0146 bd 52 01 LDA &0152,X ; loader_error_string # Write "Load Error" &0149 f0 06 BEQ &0151 ; leave &014b 20 ee ff JSR &ffee ; OSWRCH &014e e8 INX &014f d0 f5 BNE &0146 ; write_load_error_loop ; leave &0151 60 RTS ; load_error_string &0152 07 4c 6f 61 64 20 45 72 72 6f 72 0d 0a 0a 00 ; BELL, "Load Error\r\n\n" ; valid_checksum_one &0efe f9 ; valid_checksum_two &0eff 23 &0f00 00 # Used at &0d47 in final round of via_decryption Game Disassembly ================ ; (no filename) # Tape version ; 0004d0 0042ea 004031 ; $.WIZADORE # Cracked disc version ; 001100 005130 004062 &00 player_materialisation, platform &01 rows_written, left_or_right &02 amount_to_scroll, jump_timer, copy_of_player_direction_and_velocity &03 (unused) &04 - &11 scrolled_screen_addresses (high, low) &04 - &05 top left of screen &06 - &07 bottom left of top scenery &08 - &09 bottom left of middle scenery &0a - &0b bottom left of bottom scenery &0c - &0d top left of lives &0e - &0f right of top left of lives (unused, possibly for score) &10 - &11 bottom left of pockets &12 player_screen_address_high &13 player_screen_address_low &14 - &16 pockets &17 object_being_dropped &18 player_x &19 player_y &1a player_feet_sprite &1b player_head_sprite &1c player_direction_and_velocity # &80 set when moving right, &40 set when moving jump &1d fall_distance &1e player_is_climbing &1f column_x &20 - &24 enemies_x &25 - &29 enemies_bottom_sprite &2a - &2e enemies_screen_address_low &2f - &33 enemies_screen_address_high &34 sprite_column_address_low &35 sprite_column_address_high &36 enemy_to_consider &37 other_enemy_to_consider &38 - &39 projectiles_y &3a - &3d projectiles_sprite # &80 set if exploding, plus &40 if shrinking &3e - &41 projectiles_screen_address_low &42 - &45 projectiles_screen_address_high &46 - &49 projectiles_x &4a - &4d projectiles_direction_and_age # &80 set if moving to right, clear if moving to left &4e jump_stage_one &4f jump_stage_two &50 - &a8 plot_column_of_sprite &bb jump_stage_three &0300 - &03c7 column_buffer &0400 - &0413 objects_level # &80 set if sprite cropped to right, &40 if to left &0414 - &0419 enemies_level # &80 set if sprite cropped to right, &40 if to left &041a - &042d objects_sprite &042e - &0433 enemies_sprite # &80 set if materialising, plus &40 if shrinking &0434 - &0447 objects_y &0448 - &044d enemies_head_y (initialised, but unused) &044e - &0461 objects_x &0462 - &0467 enemies_start_x &0468 - &047b objects_end_x &047c - &0481 enemies_end_x &0482 - &0495 objects_sprite_address_low # Object and enemy sprite address store the address &0496 - &049b enemies_sprite_address_low # of the start of the next column to plot when the &049c - &04af objects_sprite_address_high # sprite is cropped to the right, and the address of &04b0 - &04b6 enemies_sprite_address_high # the first visible column when cropped to the left &04b7 - &04bb enemies_minimum_x &04bc - &04c0 enemies_maximum_x &04c1 - &04c5 enemies_type &04c6 - &04ca enemies_y &04cb - &04cf enemies_direction # &00 if moving to right, &80 if moving to left &4000 - &7fff screen memory # Initial objects # =============== # lv xs xe y sp # &00: 0e 13 28 20 0a ; level 14, &13-&28, bottom, DRAGON_BODY # &01: 01 6d 6f 90 28 ; level 1, &6d-&6f, top, SCROLL_GREEN # &02: 03 be c0 20 29 ; level 3, &be-&c0, bottom, SCROLL_CYAN # &03: 06 86 88 58 2a ; level 6, &86-&88, middle, SCROLL_MAGENTA # &04: 07 be c0 20 21 ; level 7, &be-&c0, bottom, SWORD_LEFT # &05: 0a 2a 2c 90 20 ; level 10, &2a-&2c, top, SWORD_MIDDLE # &06: 0f be c0 20 1f ; level 15, &be-&c0, bottom, SWORD_RIGHT # &07: 0e 96 98 58 27 ; level 14, &96-&98, middle, POTION (red herring) # &08: 08 7e 80 58 2f ; level 8, &7e-&80, middle, LIFE # &09: 0b 30 32 58 2f ; level 11, &30-&32, middle, LIFE # &0a: 0f 88 8a 90 2f ; level 15, &88-&8a, top, LIFE # &0b: 06 d2 d4 20 2f ; level 6, &d2-&d4, bottom, LIFE # &0c: 04 2f 31 20 2f ; level 4, &2f-&31, bottom, LIFE # &0d: 00 2b 2d 34 20 ; &2b-&2d, &34 SWORD_MIDDLE in dragon after killing dragon # &0e: 00 2f 31 34 1f ; &2f-&31, &34 SWORD_RIGHT in dragon after killing dragon # &0f: 00 c5 d1 1c 2d ; &c5-&d1, &1c BRIDGE by castle after killing dragon # &10: 0f 6e 7a 8c 2d ; level 15, &6e-&7a, &8c BRIDGE # &11: 0c 7a 86 54 2d ; level 12, &7a-&86, &54 BRIDGE # &12: 03 90 9c 54 2d ; level 3, &90-&9c, &54 BRIDGE # &13: 01 2c 38 54 2d ; level 1, &2c-&38, &54 BRIDGE ; initial_objects_data ; initial_objects_level &04d0 0e 01 03 06 07 0a 0f 0e 08 0b 0f 06 04 00 00 00 &04e0 0f 0c 03 01 ; initial_objects_sprite &04e4 0a 28 29 2a 21 20 1f 27 2f 2f 2f 2f 2f 20 1f 2d &04f4 2d 2d 2d 2d ; initial_objects_y &04f8 20 90 20 58 20 90 20 58 58 58 90 20 20 34 34 1c &0508 8c 54 54 54 ; initial_objects_x &050c 13 6d be 86 be 2a be 96 7e 30 88 d2 2f 2b 2f c5 &051c 6e 7a 90 2c ; initial_objects_end_x &0520 28 6f c0 88 c0 2c c0 98 80 32 8a d4 31 2d 31 d1 &0530 7a 86 9c 38 # Scenery sprites # =============== # &01 = CASTLE # &02 = CLOUD # &03 = STAIRS_RIGHT # &04 = STAIRS_LEFT # &05 = LADDER # &06 = TREE # &07 = DRAGON_HEAD # &08 = DRAGON_HEAD_2 # &09 = DRAGON_HEAD_3 # &0a = DRAGON_BODY # &0b = SHIELD # &0c = TORCH # &0d = SKELETON # &0e = SWORDSMAN_HEAD_RIGHT # &0f = SWORDSMAN_HEAD_LEFT # &10 = ENEMY_FEET_RIGHT # &11 = ENEMY_FEET_RIGHT_2 # &12 = ENEMY_FEET_RIGHT_3 # &13 = ENEMY_FEET_LEFT # &14 = ENEMY_FEET_LEFT_2 # &15 = ENEMY_FEET_LEFT_3 # &16 = AXEMAN_HEAD_RIGHT # &17 = AXEMAN_HEAD_LEFT # &18 = BIRDMAN_RIGHT # &19 = BIRDMAN_RIGHT_2 # &1a = BIRDMAN_LEFT # &1b = BIRDMAN_LEFT_2 # &1c = ARCHER_LEFT # &1d = ARCHER_LEFT_2 # &1e = ARCHER_LEFT_3 # &1f = SWORD_RIGHT # &20 = SWORD_MIDDLE # &21 = SWORD_LEFT # &22 = BARBARIAN_HEAD_RIGHT # &23 = BARBARIAN_HEAD_LEFT # &24 = ARCHER_RIGHT # &25 = ARCHER_RIGHT_2 # &26 = ARCHER_RIGHT_3 # &27 = POTION # &28 = SCROLL_GREEN # &29 = SCROLL_CYAN # &2a = SCROLL_MAGENTA # &2b = CAGE # &2c = CLIFF_LEFT # &2d = BRIDGE # &2e = TOWER # &2f = LIFE # &30 = CLIFF # &31 = CLIFF_RIGHT # &32 = BARRIER ; scenery_sprites_last_column_address_low_table &0534 24 a4 38 94 1d d7 57 c5 34 48 f4 87 22 5a 0a 7b &0544 60 9c d8 c1 f8 c9 67 61 f3 84 13 aa 0c 74 ae 87 &0554 5c 4d f8 a8 bf 38 0f e9 bc 8f e4 23 7c 08 34 32 &0564 7a 96 ; scenery_sprites_last_column_address_high_table &0566 0b 0b 0c 0c 0d 0d 0e 0e 0f 11 11 11 13 36 36 3f &0576 3f 3f 3f 3f 3f 35 35 3b 3a 3a 3a 38 39 39 32 32 &0586 32 38 37 37 36 37 3c 3b 3b 3b 13 14 14 35 32 12 &0596 12 12 ; scenery_sprites_first_column_address_low_table &0598 00 32 be 47 9a 23 e1 5f cd 3c 98 5f a6 19 d3 69 &05a8 44 84 c7 a2 e2 7b 23 fb 8e 20 b3 5a bb 1e 93 66 &05b8 3e 0a ba 4b 5f d2 f0 c3 96 69 2c e8 2b fc 0f fe &05c8 3a 87 ; scenery_sprites_first_column_address_high_table &05ca 09 0b 0b 0c 0c 0d 0d 0e 0e 0f 11 11 12 36 35 3f &05da 3f 3f 3f 3f 3f 35 35 3a 3a 3a 39 38 38 39 32 32 &05ea 32 38 37 37 36 36 3b 3b 3b 3b 13 13 14 33 32 11 &05fa 12 12 # Enemy types # =========== # f ts bs h w top sprite bottom sprite # &01: 00 0e 10 20 03 ; SWORDSMAN SWORDSMAN_HEAD_RIGHT, ENEMY_FEET_RIGHT # &02: 00 16 10 20 03 ; AXEMAN AXEMAN_HEAD_RIGHT, ENEMY_FEET_RIGHT # &03: 00 22 10 20 03 ; BARBARIAN BARBARIAN_HEAD_RIGHT, ENEMY_FEET_RIGHT # &04: 01 17 18 1a 05 ; BIRDMAN (AXEMAN_HEAD_LEFT), BIRDMAN_RIGHT # &05: 80 0e 1c 1c 03 ; ARCHER_LEFT (SWORDSMAN_HEAD_RIGHT), ARCHER_LEFT # &06: 80 8a 24 1e 03 ; ARCHER_RIGHT (DRAGON_BODY), ARCHER_RIGHT # &07: 80 9c 07 3b 07 ; DRAGON (ARCHER_LEFT), DRAGON_HEAD ; SM AM BB BM LA RA DG ; enemy_firing_table &05fc 00 00 00 01 80 80 80 ; enemy_top_sprite_table &0603 0e 16 22 17 0e 8a 9c # &80 set if facing right ; enemy_bottom_sprite_table &060a 10 10 10 18 1c 24 07 ; enemy_height_table &0611 20 20 20 1a 1c 1e 3b ; enemy_width_table &0618 03 03 03 05 03 03 07 ; unused &061f 00 ; level_background_data_address_high_table &0620 14 14 15 15 15 16 16 16 17 17 17 17 18 18 18 ; level_background_data_address_low_table &062f 82 f2 3f 96 e9 40 91 db 1f 68 a3 df 1a 5c a2 # Other sprites # ============= # &00 = PLAYER_HEAD_RIGHT # &01 = PLAYER_HEAD_RIGHT_2 # &02 = PLAYER_HEAD_LEFT # &03 = PLAYER_HEAD_LEFT_2 # &04 = PLAYER_FEET_RIGHT # &05 = PLAYER_FEET_RIGHT_2 # &06 = PLAYER_FEET_RIGHT_3 # &07 = PLAYER_FEET_LEFT # &08 = PLAYER_FEET_LEFT_2 # &09 = PLAYER_FEET_LEFT_3 # &0a = ARROW_RIGHT # &0b = EMPTY_POCKET # &0c = PLAYER_CLIMBING # &0d = PLAYER_CLIMBING_2 # &0e = ARROW_LEFT # &0f = EXPLOSION # &10 = EXPLOSION_2 # &11 = EXPLOSION_3 # &12 = EXPLOSION_4 # &13 = MATERIALISATION # &14 = MATERIALISATION_2 # &15 = MATERIALISATION_3 # &16 = MATERIALISATION_4 # &17 = SWORD # &18 = SPELL_CYAN_RIGHT # &19 = SPELL_CYAN_LEFT # &1a = SPELL_GREEN_RIGHT # &1b = SPELL_GREEN_LEFT # &1c = SPELL_MAGENTA_RIGHT # &1d = SPELL_MAGENTA_LEFT # &1e = PLAYER_HEAD_CASTING_RIGHT # &1f = PLAYER_HEAD_CASTING_LEFT ; other_sprites_address_high_table &063e 3e 3e 3e 3f 3f 3f 3f 3f 3f 3f 39 0b 3d 3c 39 3c &064e 3c 3c 3c 32 32 33 33 39 31 31 31 31 31 31 31 31 ; other_sprites_address_low_table &065e 69 a0 d8 0d 45 85 6a a3 e3 c8 97 b2 29 ce 87 13 &066e 29 58 93 b8 d5 1e 87 a7 e0 f9 c8 b0 a1 92 23 5b ; starting_positions_table ; px py sc lv &067e 28 58 02 01 ; starting position &00 &0682 ae 18 88 01 ; starting position &01 &0686 f2 b0 cc 04 ; starting position &02 &068a 0a b0 1d 02 ; starting position &03 &068e 36 18 10 03 ; starting position &04 &0692 f2 b0 cc 02 ; starting position &05 &0696 7c 18 56 01 ; starting position &06 &069a f2 b0 cc 05 ; starting position &07 &069e 36 18 10 06 ; starting position &08 &06a2 18 18 0f 04 ; starting position &09 &06a6 0a b0 1d 04 ; starting position &0a &06aa d6 18 b0 05 ; starting position &0b &06ae f2 b0 cc 07 ; starting position &0c &06b2 c2 18 9c 02 ; starting position &0d &06b6 0a b0 1d 08 ; starting position &0e &06ba d6 18 b0 0a ; starting position &0f &06be 18 18 0b 08 ; starting position &10 &06c2 0a b0 1d 0c ; starting position &11 &06c6 f2 b0 cc 09 ; starting position &12 &06ca 0a b0 1d 09 ; starting position &13 &06ce 2c 18 06 0f ; starting position &14 &06d2 0a b0 1d 0e ; starting position &15 &06d6 d6 18 b0 09 ; starting position &16 &06da 18 18 0f 0d ; starting position &17 &06de e0 18 ba 0e ; starting position &18 &06e2 f2 b0 cc 0c ; starting position &19 &06e6 e0 18 ba 0b ; starting position &1a &06ea f2 b0 cc 0d ; starting position &1b &06ee 0a b0 1d 0b ; starting position &1c ; level_enemy_data ; 0 1 2 3 4 ; x yt x yt x yt x yt x yt &06f2 d0 05 93 44 50 86 00 00 4b 42 ; level 1 &06fc 14 46 3c 84 e1 45 00 00 c8 02 ; level 2 &0706 3c 44 a0 05 a0 84 a6 06 78 42 ; level 3 &0710 4b 45 eb 45 82 84 55 46 1e 03 ; level 4 &071a cf 45 46 44 82 84 23 86 c8 81 ; level 5 &0724 28 44 6f 46 b4 84 88 84 78 02 ; level 6 &072e 37 45 00 00 a0 84 5f 46 05 02 ; level 7 &0738 91 45 a0 44 d7 85 0a 44 14 81 ; level 8 &0742 69 85 78 84 b4 86 00 00 8c 03 ; level 9 &074c 14 86 dc 45 64 84 00 00 28 81 ; level 10 &0756 14 46 73 45 31 84 be 44 b4 03 ; level 11 &0760 14 46 32 84 64 84 96 84 e6 45 ; level 12 &076a 32 46 e6 45 96 84 00 00 28 01 ; level 13 &0774 78 85 b9 45 3c 44 be 46 2a 07 ; level 14 &077e 32 84 90 84 90 45 00 00 66 81 ; level 15 ; start_screen_text &0788 d8 45 0f ; &45d8, Y &078b b6 62 c8 32 44 86 98 4a ; "WIZADORE" &0793 fe &0794 28 57 0c ; &5728, G &0797 00 d4 9e a4 32 98 a4 d4 56 32 7a 4a ; "0 START GAME" &07a3 fe &07a4 60 68 33 ; &6860, M &07a7 56 98 32 8c 5c 62 3e 9e d4 32 80 44 d4 44 4a 9e ; "GRAPHICS AND DESIGN" &07b7 62 56 80 &07ba fe &07bb 98 72 3c ; &7298, C &07be da d4 62 7a 32 56 62 80 4a d4 05 2d 28 19 ; "c IMAGINE 1985" &07cc ff ; well_done_text &07cd c8 4a 0f ; &4ac8, Y &07d0 b6 4a 74 74 d4 44 86 80 4a ; "WELL DONE" &07d9 fe &07da 10 4f 0c ; &4f10, G &07dd c2 86 aa d4 5c 32 b0 4a d4 74 62 50 a4 4a 44 d4 ; "YOU HAVE LIFTED THE CURSE" &07ed a4 5c 4a d4 3e aa 98 9e 4a &07f6 fe &07f7 00 5f 3c ; &5f00, C &07fa 4a 5c 86 14 c8 ; "EHO4Z" &07ff ff ; OS sound workspace &0800 ff 00 00 00 00 00 00 00 c0 c0 c0 c0 04 04 04 04 # Initial values unused, overwritten by OS &0810 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 &0820 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 &0830 00 00 00 00 00 00 00 00 ff 00 00 00 00 f0 00 0e ; OS channel buffers &0840 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 # Initial values unused, overwritten by OS &0850 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 &0860 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 &0870 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; chan vol pitch dur &0880 11 00 01 00 c8 00 05 00 ; sound_0 # Explosion &0888 10 00 f1 ff 07 00 05 00 ; sound_1 # Explosion &0890 12 00 02 00 0a 00 05 00 ; sound_2 # Player jumping &0898 11 00 03 00 14 00 0f 00 ; sound_3 # Materialisation &08a0 10 00 f1 ff 07 00 0f 00 ; sound_4 # Materialisation &08a8 13 00 f1 ff 64 00 01 00 ; sound_5 # Extra life &08b0 12 00 02 00 0a 00 01 00 ; sound_6 # Player landing &08b8 13 00 f1 ff 50 00 01 00 ; sound_7 # Dropped object ; OS envelope storage area &08c0 01 fb 00 00 64 00 00 00 00 00 00 00 00 00 00 00 ; envelope 1 &08d0 01 01 00 00 64 00 00 7e fe fd fb 7e 64 00 00 00 ; envelope 2 &08e0 02 01 00 00 64 00 00 00 00 00 00 00 00 00 00 00 ; envelope 3 &08f0 00 00 00 00 00 00 00 64 ec ff ff 7e 64 00 00 00 ; envelope 4 (tune) ; scenery_sprite_01 CASTLE &0900 ff 0f 05 3c 05 02 04 8d 8c 09 0f 05 01 4d 19 0f &0910 05 1f 30 0f 8c 06 0f 0d 03 05 01 4e 19 0f bf 03 &0920 0f bf 2d 0f 8e 02 0d 8c 09 0f 14 03 05 01 53 19 &0930 0f bf 03 1f bf 03 2f bf 1a 0f 08 00 0a 0f 8c 06 &0940 0f 1f 03 55 19 0f bf 03 0f bf 03 0f bf 29 0f 8d &0950 02 0e 8c 09 0f 14 03 05 02 56 0f 0f 3f 0f 8c 06 &0960 0f 0d 03 05 02 4c 3f 2f bf 0b 0a 02 08 8e 8c 09 &0970 0f 05 02 4e 2d 0f 05 05 0a 0f 04 2f 8f 03 0f 8c &0980 02 0f 02 07 04 03 0b 01 83 04 01 58 3c 0f 03 2f &0990 bf 8f 02 0d 8d 8c 02 0f 02 0b 0c 03 04 02 04 01 &09a0 55 3c 0f 04 2a 8a 88 02 0e 8c 02 0f 02 07 04 03 &09b0 04 02 04 05 03 0b 0a 03 05 01 5a 2d 0f 05 05 0a &09c0 0f 03 2f bf 0d 05 08 0f 03 07 14 03 05 01 05 11 &09d0 56 3c 0f 04 2f 15 0f 03 0b 0f 03 05 02 05 00 a2 &09e0 03 33 a2 53 3c 0f 03 2f bf 10 0a 05 0f 03 07 05 &09f0 03 05 02 0f 00 91 b3 a2 55 2d 0f 05 05 0a 0f 04 &0a00 2a 12 00 06 0a 4d 3c 0f 03 2f bf 46 3c 0f 04 2a &0a10 45 2d 0f 05 05 0a 0f 03 2f bf 17 05 03 04 02 0d &0a20 8c 08 0f 06 01 55 0d 0f bf 2e 0f 04 2f 1c 0f 8c &0a30 05 0f 0f 03 06 01 51 09 0f bf 03 2f bf 2e 0f 03 &0a40 2f bf 17 0f 03 0e 02 0d 8c 08 0f 18 03 06 01 59 &0a50 05 0f bf 03 2f bf 03 0f bf 1f 0f 05 05 0a 0f 04 &0a60 2f 0a 0f 08 00 0a 0f 8c 05 0f 27 03 06 33 5f 05 &0a70 0f bf 03 0f bf 04 2f 2e 0f 03 2f bf 17 0f 03 0d &0a80 02 0e 8c 08 0f 18 03 06 02 06 00 91 03 33 a2 61 &0a90 05 0f 04 2f bf 32 0f 04 2f 1c 0f 8c 05 0f 0f 03 &0aa0 06 02 0f 00 04 22 57 2d 0f 05 05 0a 0f 03 2f bf &0ab0 17 0a 03 08 02 0e 8c 08 0f 06 02 55 3f 2f af 0b &0ac0 05 02 04 8d 8c 09 0f 05 01 4e 23 0f 05 1f 03 0f &0ad0 bf 22 0f 8c 06 0f 0d 03 05 01 51 23 0f bf 03 0f &0ae0 bf 03 1f bf 1f 0f 8e 02 0d 8c 09 0f 14 03 05 01 &0af0 56 23 0f bf 03 1f bf 03 0f bf 10 0f 08 00 0a 0f &0b00 8c 06 0f 1f 03 55 23 0f bf 03 0f bf 23 0f 8d 02 &0b10 0e 8c 09 0f 14 03 05 02 53 0f 0f 3f 0f 8c 06 0f &0b20 0d 03 05 02 4c 0f 0a 3c 0a 02 08 8e 8c 09 0f 05 &0b30 02 cd ; scenery_sprite_02 CLOUD &0b32 ff 07 00 04 10 06 35 03 10 49 04 00 90 02 35 0d &0b42 3f 02 35 90 4b 04 00 a0 ba 06 3f ba 03 35 02 3a &0b52 05 3f b0 4f 02 00 90 02 35 0d 3f b5 bf 02 3a a0 &0b62 4d 80 b0 14 3f 02 35 90 48 b0 18 3f b0 45 a0 ba &0b72 07 3f 02 3a 0c 3f 02 3a a0 4c 80 a0 02 3a 07 3f &0b82 03 35 03 3a 02 35 03 3f b5 90 51 04 00 a0 ba 12 &0b92 3f b0 48 05 00 a0 02 3a 07 3f 02 3a 03 3f 02 3a &0ba2 02 20 50 08 00 02 20 04 3a a0 02 00 03 20 cc &0bb1 ff ; other_sprite_0b EMPTY_POCKET &0bb2 10 00 43 10 00 43 10 00 43 10 00 c3 ; scenery_sprite_03 STAIRS_RIGHT &0bbe ff 06 ad 02 fc 45 06 0f 02 fc 45 06 0f 08 ad 02 &0bce fc 47 0e 0f 02 fc 45 0e 0f 08 ad 02 fc 47 0a 0f &0bde 80 03 05 80 03 0f 8a 03 0f 02 fc 4e 0a 0f 80 03 &0bee 0f 80 03 05 80 03 0f 08 ad 02 fc 50 0a 0f 04 05 &0bfe 80 03 0f 80 0b 0f 02 fc 4d 0e 0f 80 04 05 0b 0f &0c0e 08 ad 02 fc 4c 26 0f 02 fc 45 26 0f 08 ad 02 fc &0c1e 47 14 0f 04 0a 80 15 0f 02 fc 4a 14 0f 80 03 0f &0c2e 80 03 0a 80 11 0f 08 ad 02 fc 50 14 0f 80 03 0a &0c3e 80 03 0f 80 19 0f 02 fc ce ; scenery_sprite_04 STAIRS_LEFT &0c47 ff 36 0f 02 fc 45 2e 0f 08 5e 02 fc 47 2e 0f 02 &0c57 fc 45 26 0f 08 5e 02 fc 47 26 0f 02 fc 45 1e 0f &0c67 08 5e 02 fc 47 1e 0f 02 fc 45 16 0f 08 5e 02 fc &0c77 47 16 0f 02 fc 45 0e 0f 08 5e 02 fc 47 0e 0f 02 &0c87 fc 45 06 0f 08 5e 02 fc 47 06 0f 02 fc 45 06 5e &0c97 02 fc c5 ; scenery_sprite_05 LADDER &0c9a ff 08 55 81 2d 55 02 fc 48 02 00 02 ff 04 00 02 &0caa ff 04 00 02 ff 04 00 02 ff 04 00 02 ff 04 00 02 &0cba ff 04 00 02 ff 04 00 02 ff 04 00 02 ff 02 00 02 &0cca fc 69 02 00 02 ff 04 00 02 ff 04 00 02 ff 04 00 &0cda 02 ff 04 00 02 ff 04 00 02 ff 04 00 02 ff 04 00 &0cea 02 ff 04 00 02 ff 02 00 02 fc 69 02 00 02 ff 04 &0cfa 00 02 ff 04 00 02 ff 04 00 02 ff 04 00 02 ff 04 &0d0a 00 02 ff 04 00 02 ff 04 00 02 ff 04 00 02 ff 02 &0d1a 00 02 fc 69 36 aa 02 fc c5 ; scenery_sprite_06 TREE &0d23 ff 37 00 05 04 0c 0c 06 04 49 31 00 03 04 1e 0c &0d33 03 04 49 2f 00 84 26 0c 84 47 2e 00 2a 0c 45 2f &0d43 00 88 28 0c 46 32 00 88 02 5d 24 0c 48 02 55 2e &0d53 00 02 55 04 ff 01 aa 80 02 08 20 0c 50 05 ff 06 &0d63 55 1f 00 03 55 06 ff 02 aa 04 00 84 21 0c 84 53 &0d73 03 ff 03 55 06 aa 0a ff 05 aa 0f ff 04 aa 02 55 &0d83 02 ff 01 aa 05 00 25 0c 84 5a 03 ff 05 aa 07 ff &0d93 04 aa 0b ff 06 aa 0d ff 02 55 05 00 88 25 0c 56 &0da3 0b ff 23 aa 06 ff 01 55 05 00 23 0c 4d 02 ff 03 &0db3 aa 2d 00 02 aa 03 ff 02 55 01 55 22 0c 51 35 00 &0dc3 84 02 ae 22 0c 48 31 00 02 04 25 0c 47 30 00 88 &0dd3 24 0c 02 08 48 33 00 04 08 15 0c 05 08 49 ; scenery_sprite_07 DRAGON_HEAD &0de1 ff 12 00 04 0a 07 0f 0b 0a 09 0f 87 05 03 03 0c &0df1 50 2e 00 8a 03 0f 05 03 03 0e 8a 4b 2e 00 85 02 &0e01 0f 8b 04 03 02 0c 88 4c 2d 00 85 02 0f 8b 03 03 &0e11 86 02 0e 8d 85 4e 24 00 06 01 85 03 0f 8b 04 03 &0e21 86 02 0c 88 4f 20 00 81 10 03 86 02 0e 02 0d 4b &0e31 1c 00 02 01 02 03 03 02 02 01 03 03 02 17 93 82 &0e41 02 06 8e 8d 02 0c 02 08 59 20 00 81 03 03 02 02 &0e51 06 22 80 03 08 8a 4e 1f 00 83 81 02 03 c7 ; scenery_sprite_08 DRAGON_HEAD_2 &0e5f ff 12 00 04 0a 07 0f 0d 0a 06 0f 87 05 03 03 0c &0e6f 50 23 00 09 05 03 0f 8b 04 03 86 03 0e 8a 4e 1a &0e7f 00 02 01 04 03 0d 0b 03 03 02 07 02 0c 02 08 51 &0e8f 18 00 09 03 93 82 03 06 87 03 06 02 07 03 06 02 &0e9f 0c 88 02 0a 55 16 00 81 03 03 82 04 03 02 3b 02 &0eaf 22 80 02 08 8f 05 08 02 0a 88 56 14 00 81 02 03 &0ebf 82 80 81 03 03 82 4c 18 00 83 81 02 03 c7 ; scenery_sprite_09 DRAGON_HEAD_3 &0ecd ff 12 00 04 0a 07 0f 0c 0a 06 0f 02 0b 04 03 86 &0edd 02 0c 88 53 19 00 05 01 03 05 0a 0f 02 0b 04 03 &0eed 02 06 02 0e 02 0d 53 15 00 02 01 17 03 86 02 0e &0efd 02 0d 02 08 4e 13 00 81 09 03 93 82 03 06 02 0c &0f0d 8f 05 0c 8e 8d 8c 03 08 54 12 00 81 02 03 02 02 &0f1d 02 00 02 03 ab bb 02 03 80 88 03 00 8a 55 12 00 &0f2d 02 03 04 00 03 03 a2 4a 18 00 83 81 02 03 c7 ; scenery_sprite_0a DRAGON_BODY &0f3c ff 0d 00 09 01 45 06 00 03 01 11 03 03 01 49 03 &0f4c 00 81 1b 03 81 07 00 04 04 4b 02 00 05 03 03 02 &0f5c 0b 01 03 02 08 03 8c 84 07 00 8a 04 0f 02 05 56 &0f6c 80 05 03 80 19 03 02 0d 85 08 00 8f 9b b3 9b 02 &0f7c 0f 85 53 04 03 82 81 19 03 03 0c 07 00 85 8f a7 &0f8c 04 33 9b 02 0f 53 04 03 80 0d 03 82 0c 03 03 0d &0f9c 85 04 00 85 02 0f 9b 02 0f a7 04 33 02 0f 59 04 &0fac 03 80 04 03 82 08 03 80 0c 03 03 0c 80 02 05 04 &0fbc 0f 03 33 9b 02 0f a7 03 33 02 0f 5d 04 03 80 04 &0fcc 03 8f 85 82 04 03 82 81 06 03 8b 03 0f 02 07 02 &0fdc 0d 05 0f 9b b3 03 0f a7 03 33 02 0f a7 03 33 02 &0fec 0f 66 04 03 80 03 03 03 0f 83 04 01 0a 03 02 0f &0ffc 03 1b 05 0f 9b 03 33 9b 03 0f 03 33 02 0f a7 02 &100c 33 9b 02 0f 63 04 03 80 02 03 87 03 0f 0c 03 02 &101c 07 03 0f a7 03 33 02 1b 04 0f a7 02 33 9b 03 0f &102c 03 33 02 0f 03 33 02 0f 64 04 03 80 02 03 04 0f &103c 87 0d 03 8b 05 0f 02 27 03 33 02 1b 02 0f a7 b3 &104c 9b 03 0f 02 33 9b 8f a7 03 33 02 0f 64 80 03 03 &105c 80 87 06 0f 0d 03 87 0a 0f 02 27 b3 9b 8f a7 02 &106c 33 02 0f a7 02 33 02 0f 03 33 02 0f 60 80 03 03 &107c 80 07 0f 0b 03 02 0b 8f 9b 8f 9b 03 33 05 1b 05 &108c 0f a7 b3 03 0f a7 b3 02 0f 02 33 02 0f 61 02 00 &109c 02 03 02 00 06 0f 87 0d 03 8f 04 27 03 33 04 27 &10ac 05 0a 04 0f a7 02 0f b3 a7 8f 8a 5e 02 00 83 03 &10bc 00 8a 06 0f 0c 03 87 02 0b 83 02 0c 02 0e 03 0a &10cc 0c 00 03 0a 03 0f 5b 02 00 83 04 00 06 0f 87 0f &10dc 03 8b 03 0e 8a 11 00 02 0c 53 08 00 07 0f 0f 03 &10ec 03 0c 84 10 00 02 08 4e 06 00 82 05 03 02 0b 02 &10fc 0f 0f 03 04 0e 8a 4f 02 04 02 00 81 08 03 87 02 &110c 0f 10 03 89 02 0c 02 0d 02 0e 54 02 00 89 02 03 &111c 02 02 02 00 08 0f 12 03 03 09 02 0c 02 04 8f 05 &112c 04 8f 04 04 5a 02 08 8c 82 06 00 07 0f 02 07 17 &113c 03 8b 05 09 8b 03 09 8d 8e 02 0c 84 58 02 08 0a &114c 00 03 0a 07 0f 05 07 07 0f 07 07 0c 03 89 02 0d &115c 8e 8a d6 ; scenery_sprite_0b SHIELD &115f ff 12 00 02 23 02 11 02 00 02 01 02 02 0c 00 02 &116f 11 51 14 00 02 02 02 23 02 11 80 02 14 80 03 3c &117f 80 02 07 02 01 02 27 b3 57 18 00 02 02 80 02 2a &118f 80 03 3d 80 04 0b 02 22 d0 ; scenery_sprite_0c TORCH &1198 ff 14 00 82 83 81 0a 00 94 bc a8 4b 16 00 02 07 &11a8 02 0a 02 00 0c 15 4b 15 00 03 15 04 2e 02 0c 88 &11b8 91 05 33 bf aa 4f 12 00 95 bf aa 09 08 80 06 22 &11c8 aa bf 95 4e 13 00 02 2a 03 37 06 33 80 06 03 bf &11d8 aa 4e 16 00 02 05 04 2a 03 37 95 05 17 02 3f 95 &11e8 4f 15 00 81 83 82 02 0a 07 00 02 14 4c 14 00 02 &11f8 02 0c 00 02 28 c9 ; scenery_sprite_30 CLIFF &11fe ff 31 ff 82 84 05 fc 47 0d ff 06 55 11 ff 07 55 &120e 05 ff 81 89 88 05 fc 50 07 ff 05 aa 26 ff 82 84 &121e 04 fc 4b 31 ff 81 88 05 fc 47 20 ff 06 55 0c ff &122e 82 84 04 fc 4b 31 ff 81 88 05 fc c7 ; scenery_sprite_31 CLIFF_RIGHT &123a ff 30 ff 82 84 06 fc 47 09 ff 07 55 18 ff 06 aa &124a 03 ff 81 88 05 fc 4f 1d ff 04 55 12 ff 80 04 fc &125a 4a 0a ff 05 aa 03 55 16 ff 04 aa 05 ff 82 84 05 &126a fc 51 13 ff 11 aa 08 ff 03 55 03 ff 81 88 04 fc &127a 4f 04 aa 28 00 06 aa 84 04 fc 01 a8 cc ; scenery_sprite_32 BARRIER &1287 ff 01 54 07 b9 01 54 08 b9 01 54 05 b9 01 54 4f &1297 01 a8 07 76 01 a8 08 76 01 a8 05 76 01 a8 cf ; scenery_sprite_0d SKELETON &12a6 ff 02 00 aa bf 95 02 00 03 15 80 03 15 03 00 02 &12b6 14 02 28 53 02 15 bf 03 2a 02 00 02 2a 04 00 aa &12c6 a8 bd 95 50 02 00 02 2a bf 80 94 a8 80 95 80 bf &12d6 80 bf 80 bf aa 95 80 95 bf aa bf 95 59 04 00 95 &12e6 80 bc 80 aa bf aa bf aa bf aa bf 80 bf 80 02 3f &12f6 aa 02 3f 57 02 15 bf 02 2a 02 00 a8 03 00 aa 80 &1306 aa 80 aa bf 95 02 00 03 2a 56 02 00 aa 02 3f aa &1316 80 95 02 3f 80 03 15 aa 02 28 02 14 53 02 00 02 &1326 2a 0f 00 02 28 c9 ; scenery_sprite_2b CAGE &132c ff 0b ff 07 55 45 0b 00 07 aa 06 ff 04 55 49 12 &133c aa 06 00 04 aa 04 ff 03 55 4b 20 55 03 aa 03 ff &134c 02 55 49 25 00 02 aa 03 ff 94 48 02 ff 1d aa 02 &135c ff 80 05 aa 02 00 a8 02 ff 94 50 02 ff 1d 55 02 &136c ff 80 08 55 80 03 ff 4d 02 ff 1d 00 02 ff 0b 00 &137c 03 ff 4b 02 ff 0c aa 04 ff 02 aa bc 0a aa 02 ff &138c 80 0a aa 80 03 ff 54 02 ff 0c 55 02 ff 04 55 bc &139c 0a 55 02 ff 80 09 55 80 94 02 ff a8 56 2b 00 94 &13ac 02 ff a8 47 2a aa 94 02 ff a8 47 25 55 02 00 02 &13bc 55 02 ff a8 4a 23 00 02 55 03 ff 02 aa 49 1c aa &13cc 04 55 03 ff 03 aa 49 0b 55 07 00 06 55 04 ff 04 &13dc aa 4b 0b 55 07 ff 06 aa 47 0b aa c3 ; scenery_sprite_2c CLIFF_LEFT &13e8 ff 02 ff 07 55 24 00 05 55 88 04 fc 01 54 ff 04 &13f8 aa 0a ff 11 55 08 ff 04 aa 02 ff 82 84 04 fc 53 &1408 09 ff 07 55 16 ff 06 55 05 ff 81 88 05 fc 4f 06 &1418 aa 0c ff 82 84 04 fc 4b 32 ff 82 84 04 fc c7 ; scenery_sprite_2d BRIDGE &142b ff 04 fc 82 81 45 04 fc 02 00 82 81 47 04 fc 04 &143b 11 93 81 47 04 fc 05 00 83 46 04 fc 04 00 83 46 &144b 04 fc 03 00 83 46 04 fc 03 00 83 46 04 fc 03 00 &145b 83 46 04 fc 03 00 83 46 04 fc 04 00 83 46 04 fc &146b 05 00 83 46 04 fc 04 22 a3 82 47 04 fc 02 00 81 &147b 82 47 04 fc 81 82 c5 ; level1_background_data &1482 91 14 ; &1491 = level1_platform_data &1484 9a 14 ; &149a = level1_scenery_data &1486 00 08 08 08 # Platform data is at &1491, &1499, &1499 and &1499 &148a 00 36 4b # Scenery data is at &149a, &14d0 and &14e5 &148d e5 f6 ; G R # Green platforms, red ladders &148f eb 14 ; &14eb = level1_exit_data ; level1_platform_data ; + - + - + - + - &1491 00 2a 3a 76 80 aa b4 ff # Bottom platforms &1499 ff # No middle, top or ceiling platforms ; level1_scenery_data ; x- x+ sp &149a 0a 16 2e ; &0a-&16, TOWER # Bottom scenery &149d 19 1e 2c ; &19-&1e, CLIFF_LEFT &14a0 1e 24 30 ; &1e-&24, CLIFF &14a3 24 2a 30 ; &24-&2a, CLIFF &14a6 3a 40 30 ; &3a-&40, CLIFF &14a9 40 46 30 ; &40-&46, CLIFF &14ac 46 4c 30 ; &46-&4c, CLIFF &14af 4c 52 30 ; &4c-&52, CLIFF &14b2 52 58 30 ; &52-&58, CLIFF &14b5 58 5d 05 ; &58-&5d, LADDER &14b8 5d 63 30 ; &5d-&63, CLIFF &14bb 63 69 30 ; &63-&69, CLIFF &14be 69 6f 30 ; &69-&6f, CLIFF &14c1 6f 75 31 ; &6f-&75, CLIFF_RIGHT &14c4 80 90 06 ; &80-&90, TREE &14c7 b9 c9 06 ; &b9-&c9, TREE &14ca d6 d8 32 ; &d6-&d8, BARRIER &14cd db eb 06 ; &db-&eb, TREE &14d0 22 24 32 ; &22-&24, BARRIER # Middle scenery &14d3 4e 53 2c ; &4e-&53, CLIFF_LEFT &14d6 53 59 30 ; &53-&59, CLIFF &14d9 59 5f 30 ; &59-&5f, CLIFF &14dc 5f 64 05 ; &5f-&64, LADDER &14df 64 6a 30 ; &64-&6a, CLIFF &14e2 6a 70 31 ; &6a-&70, CLIFF_RIGHT &14e5 16 21 02 ; &16-&21, CLOUD # Top scenery &14e8 a0 ab 02 ; &a0-&ab, CLOUD ; level1_exit_data &14eb 76 80 02 ; &76-&80, bottom, starting position &02 (level 4) &14ee aa b4 03 ; &aa-&b4, bottom, starting position &03 (level 2) &14f1 ff ; level2_background_data &14f2 01 15 ; &1501 = level2_platform_data &14f4 16 15 ; &1516 = level2_scenery_data - 3 &14f6 01 05 11 15 # Platform data is at &1502, &1506, &1512 and &1516 &14fa 03 09 15 # Scenery data is at &1519, &151f, &152b &14fd e6 f2 ; R M # Red platforms, magenta ladders &14ff 35 15 ; &1535 = level2_exit_data ; level2_platform_data ; + - + - + - + - + - + - &1501 00 b4 be c8 ff # Bottom platforms &1506 00 19 28 46 52 5a 66 96 b9 d2 e1 ff # Middle platforms &1512 00 32 96 ff # Top platforms &1516 11 ee ff # Ceiling platforms ; level2_second_data &1519 b5 bd 0b ; &b5-&bd, SHIELD # Bottom scenery &151c cd d2 05 ; &cd-&d2, LADDER &151f 2a 2f 05 ; &2a-&2f, LADDER # Middle scenery &1522 88 96 03 ; &88-&96, STAIRS_RIGHT &1525 b9 be 05 ; &b9-&be, LADDER &1528 f0 f7 0d ; &f0-&f7, SKELETON &152b 00 0e 04 ; &00-&0e, STAIRS_LEFT # Top scenery &152e a0 a3 0c ; &a0-&a3, TORCH &1531 ef fd 03 ; &ef-&fd, STAIRS_RIGHT &1534 00 ; level2_exit_data &1535 00 11 81 ; &00-&11, ceiling, starting position &01 (level 1) &153. be c8 0e ; &be-&c8, bottom, starting position &0e (level 8) &153. ee fe 84 ; &ee-&fe, ceiling, starting position &04 (level 3) &153e ff ; level3_background_data &153f 4e 15 ; &154e = level3_platform_data &1541 53 15 ; &1553 = level3_scenery_data &1543 00 06 06 06 # Platform data is at &154e, &1554, &1554 and &1554 &1547 02 35 38 # Scenery data is at &1555, &1588, and &158b &154a e5 f6 ; G R # Green platforms, red ladders &154c 92 15 ; &1592 = level3_exit_data ; level3_platform_data ; + - + - + &154e 00 3c 8e 9e ff # Bottom platforms &1554 ff # No middle, top, ceiling or platforms ; level3_scenery_data &1555 0f 1f 06 ; &0f-&1f : TREE # Bottom scenery &1558 22 24 32 ; &22-&24 ; BARRIER &155b 6c 71 2c ; &6c-&71 ; CLIFF_LEFT &155e 71 77 30 ; &71-&77 ; CLIFF &1561 77 7d 30 ; &77-&7d ; CLIFF &1564 7d 83 30 ; &7d-&83 ; CLIFF &1567 83 88 05 ; &83-&88 ; LADDER &156a 88 8e 30 ; &88-&8e ; CLIFF &156d 9e a4 30 ; &9e-&a4 ; CLIFF &1570 a4 aa 30 ; &a4-&aa ; CLIFF &1573 aa b0 30 ; &aa-&b0 ; CLIFF &1576 b0 b6 30 ; &b0-&b6 ; CLIFF &1579 b6 bb 05 ; &b6-&bb : LADDER &157c bb c1 30 ; &bb-&c1 ; CLIFF &157f c1 c7 31 ; &c1-&c7 ; CLIFF_RIGHT &1582 d6 d8 32 ; &d6-&d8 ; BARRIER &1585 dc ec 06 ; &dc-&ec ; TREE &1588 78 88 06 ; &78-&88 ; TREE # Middle scenery &158b 32 3d 02 ; &32-&3d ; CLOUD # Top scenery &158e c8 d3 02 ; &c8-&d3 ; CLOUD &1591 00 ; level3_exit_data &1592 32 3c 05 ; &32-&3c, bottom, starting position &05 (level 2) &1593 ff ; level4_background_data &1596 a5 15 ; &15a5 = level4_platform_data &1598 bf 15 ; &15bf = level4_scenery_data &159a 00 04 14 18 # Platform data is at &15a5, &15a9, &15b9 and &15bd &159e 00 07 10 # Scenery data is at &15bf, &15c6 and &15cf &15a1 e6 f2 ; R M # Red platforms, magenta ladders &15a3 df 15 ; &15df = level4_exit_data ; level4_platform_data ; + - + - + - + - + - + - + - + - &15a5 00 14 1e 3c # Bottom platforms &15a9 23 3c 4b 5a 69 78 84 8e 9a a0 ac b6 c2 dc eb ff # Middle platforms &15b9 00 76 c8 ff # Top platforms &15bd 11 ee # Ceiling platforms ; level4_scenery_data &15bf 0a 10 0b ; &0a-&10, SHIELD # Bottom scenery &15c2 28 2d 05 ; &28-&2d, LADDER &15c5 00 &15c6 36 3b 05 ; &36-&3b, LADDER # Middle scenery &15c9 6e 73 05 ; &6e-&73, LADDER &15cc d2 d7 05 ; &d2-&d7, LADDER &15cf 00 0e 04 ; &00-&0e, STAIRS_LEFT # Top scenery &15d2 14 17 0c ; &14-&17, TORCH &15d5 32 3a 0b ; &32-&3a, SHIELD &15d8 50 53 0c ; &50-&53, TORCH &15db ef fd 03 ; &ef-&fd, STAIRS_RIGHT &15de 00 ; level4_exit_data &15df 00 11 88 ; &00-&11, ceiling, starting position &08 (level 6) &15e2 14 1e 07 ; &14-&1e, bottom, starting position &07 (level 5) &15e5 ee fe 86 ; &ee-&fe, ceiling, starting position &06 (level 1) &15e8 ff ; level5_background_data &15e9 f8 15 ; &15f8 = level5_platform_data &15eb 11 16 ; &1611 = level5_scenery_data - 2 &15ed 00 04 0e 18 # Platform data is at &15f8, &15fc, &1606 and &1610 &14f1 02 17 21 # Scenery data is at &1613, &1628 and &1632 &15f4 e2 f6 ; M R # Magenta platforms, red ladders &15f6 39 16 ; &1639 = level5_exit_data ; level5_platform_data ; + - + - + - + - + - &15f8 00 d2 dc ff # Bottom platforms &15fc 1e 3c 6e 82 8e 98 a4 be cd d7 # Middle platforms &1606 1e 28 37 46 52 5a 66 78 af ff # Top platforms &1610 00 ee # Ceiling platforms &1612 00 ; level5_scenery_data &1613 0a 12 0b ; &0a-&12, SHIELD # Bottom scenery &1616 20 25 05 ; &20-&25, LADDER &1619 32 35 0c ; &32-&35, TORCH &161c 6e 75 0d ; &6e-&75, SKELETON &161f a0 a3 0c ; &a0-&a3, TORCH &1622 be c6 0b ; &be-&c6, SHIELD &1625 e6 e9 0c ; &e6-&e9, TORCH &1628 34 39 05 ; &34-&39, LADDER # Middle scenery &162b 70 75 05 ; &70-&75, LADDER &162e b9 be 05 ; &b9-&be, LADDER &1631 00 &1632 d2 d5 0c ; &d2-&d5, TORCH # Top scenery &1635 ef fd 03 ; &ef-&fd, STAIRS_RIGHT &1638 00 ; level5_exit_data &1639 ee fe 89 ; &ee-fe, ceiling, starting position &09 (level 4) &163c d2 dc 0c ; &d2-dc, bottom, starting position &0c (level 7) &163f ff ; level6_background_data &1640 4f 16 ; &164f = level6_platform_data &1642 54 16 ; &1654 = level6_scenery_data - 2 &1644 00 04 04 04 # Platform data is at &164f, &1653, &1653 and &1653 &1648 02 2c 2f # Scenery data is at &1656, &1680 and &1683 &164b e5 f6 ; G R # Green platforms, red ladders &164d 8d 16 ; &168d = level6_exit_data ; level6_platform_data ; + - + - &164f 00 32 3c ff # Bottom platforms &1653 ff # No middle platforms &1654 ff # No top platforms &1655 ff # No ceiling platforms ; level6_scenery_data &1656 0f 1f 06 ; &0f-&1f, TREE # Bottom scenery &1659 22 24 32 ; &22-&24, BARRIER &165c 6e 73 2c ; &6e-&73, CLIFF_LEFT &165f 73 79 30 ; &73-&79, CLIFF &1662 79 7e 05 ; &79-&7e, LADDER &1665 7e 84 30 ; &7e-&84, CLIFF &1668 84 8a 30 ; &84-&8a, CLIFF &166b 8a 90 31 ; &8a-&90, CLIFF_RIGHT &166e aa ba 06 ; &aa-&ba, TREE &1671 bb cb 06 ; &bb-&cb, TREE &1674 d6 d8 32 ; &d6-&d8, BARRIER &1677 e2 ee 2e ; &e2-&ee, TOWER &167a f2 f7 2c ; &f2-&f7, CLIFF_LEFT &167d f7 fd 30 ; &f7-&fd, CLIFF &1680 78 88 06 ; &78-&88, TREE # Middle scenery &1683 32 3d 02 ; &32-&3d, CLOUD # Top scenery &1686 64 6f 02 ; &64-&6f, CLOUD &1689 ee f9 02 ; &ee-&f9, CLOUD &168c 00 ; level6_exit_data &168d 32 3c 0a ; &32-3c, bottom, starting position &0a (level 4) &1690 ff ; level7_background_data &1691 a0 16 ; &16a0 = level7_platform_data &1693 b8 16 ; &16b8 = level7_scenery_data &1695 00 02 10 16 # Platform data is at &16a0, &16a2, &16b0 and &16b6 &1699 00 12 1c # Scenery data is at &16b8, &16ca and &16d4 &169c e2 f1 ; M C # Magenta platforms, cyan ladders &169e d7 16 ; &16d7 = level7_exit_data ; level7_platform_data ; + - + - + - + - + - + - + - &16a0 00 ff # Bottom platforms &16a2 14 28 37 46 5a 64 73 82 8e 98 a4 ae ba c8 # Middle platforms &16b0 00 14 21 8c c8 ff # Top platforms &16b6 00 ee # Ceiling platforms ; level7_scenery_data &16b8 16 1b 05 ; &16-&1b, LADDER # Bottom scenery &16bb a0 a7 0d ; &a0-&a7, SKELETON &16be aa b1 0d ; &aa-&b1, SKELETON &16c1 c8 da 2b ; &c8-&da, CAGE &16c4 dc e3 0d ; &dc-&e3, SKELETON &16c7 e5 f7 2b ; &e5-&f7, CAGE &16ca 23 28 05 ; &23-&28, LADDER # Middle scenery &16cd 73 78 05 ; &73-&78, LADDER &16d0 c3 c8 05 ; &c3-&c8, LADDER &16d3 00 &16d4 ef fd 03 # Top scenery ; level7_exit_data &16d7 ee fe 8b ; &ee-fe, ceiling, starting position &0b (level 5) &16da ff ; level8_background_data &16db ea 16 ; &16ea = level8_platform_data &16dd fe 16 : &16fe = level8_scenery_data - 2 &16df 00 04 0e 14 # Platform data is at &16ea, &16ee, &16f8 and &16fe &1de3 02 0e 17 # Scenery data is at &1700, &170c and &1715 &16e6 e6 f1 ; R C # Red platforms, cyan ladders &16e8 18 17 ; &1718 = level8_exit_data ; level8_platform_data ; + - + - + - + - + - &16ea 00 14 1e ff # Bottom platforms &16ee 46 55 61 6e 7a 82 91 9b c8 e6 # Middle platforms &16f8 00 4c 7a c8 d7 e1 # Top platforms &16fe 11 ff # Ceiling platforms ; level8_scenery_data &1700 02 09 0d ; &02-&09, SKELETON # Bottom scenery &1703 9b ad 2b ; &9b-&ad, CAGE &1706 af c1 2b ; &af-&c1, CAGE &1709 e1 e6 05 ; &e1-&e6, LADDER &170c 46 4b 05 ; &46-&4b, LADDER # Middle scenery &170f 7a 7f 05 ; &7a-&7f, LADDER &1712 c8 cd 05 ; &c8-&cd, LADDER &1715 00 0e 04 ; &00-&0e, STAIRS_LEFT # Top scenery ; level8_exit_data &1718 00 11 8d ; &00-11, ceiling, starting position &0d (level 2) &171b 14 1e 12 ; &14-1e, bottom, starting position &12 (level 9) &171e ff ; level9_background_data &171f 2e 17 ; &172e = level9_platform_data - 1 &1721 43 17 ; &1743 = level9_scenery_data - 3 &1723 01 05 0b 15 # Platform data is at &172f, &1733, &1739 and &1743 &1727 03 09 0f # Scenery data is at &1746, &174c and &1752 &172a e2 f6 ; M R # Magenta platforms, red ladders &172c 5e 17 ; &175e = level9_exit_data &172e 00 ; level9_platform_data ; + - + - + - + - + - &172f 64 d2 dc ff # Bottom platforms &1733 50 82 8e a0 ac d2 # Middle platforms &1739 00 32 3e 5a 69 6e b4 b9 c8 ff # Top platforms &1743 11 ee # Ceiling platforms &1745 00 ; level9_scenery_data &1746 73 78 05 ; &73-&78, LADDER # Bottom scenery &1749 b4 bc 0b ; &b4-&bc, SHIELD &174c 52 57 05 ; &52-&57, LADDER # Middle scenery &174f ca cf 05 ; &ca-&cf, LADDER &1752 00 0e 04 ; &00-&0e, STAIRS_LEFT # Top scenery &1755 1e 21 0c ; &1e-&21, TORCH &1758 46 49 0c ; &46-&49, TORCH &175b ef fd 03 ; &ef-&fd, STAIRS_RIGHT ; level9_exit_data &175e 00 11 8f ; &00-11, ceiling, starting position &0f (level 10) &1761 ee fe 90 ; &ee-fe, ceiling, starting position &10 (level 8) &1764 d2 dc 11 ; &d2-dc, bottom, starting position &11 (level 12) &1767 ff ; level10_background_data &1768 77 17 ; &1777 = level10_platform_data - 1 &176a 8c 17 ; &178c = level10_scenery_data - 3 &176c 01 05 0f 15 # Platform data is at &1778, &177c, &1786 and &178c &1770 03 06 0f # Scenery data is at &178f, &1792 and &179b &1773 e6 f1 ; R C # Red platforms, cyan ladders &1775 9f 17 ; &179f = level10_exit_data &1777 00 ; level10_platform_data ; + - + - + - + - + - &1778 b4 d2 dc ff # Bottom platforms &177c 50 64 70 78 84 96 a2 b4 c3 ff # Middle platforms &1786 00 19 28 50 aa dc # Top platforms &178c 00 ff # Ceiling platforms &178e 00 ; level10_scenery_data &178f b4 c2 04 ; &b4-&c2, STAIRS_LEFT # Bottom scenery &1792 50 5e 04 ; &50-&5e, STAIRS_LEFT # Middle scenery &1795 c8 cd 05 ; &c8-&cd, LADDER &1798 e6 f8 2b ; &e6-&f8, CAGE &179b b4 bb 0d ; &b4-&bb, SKELETON # Top scenery &179e 00 ; level10_exit_data &179f d2 dc 13 ; &d2-dc, ceiling, starting position &13 (level 9) &17a2 ff ; level11_background_data &17a3 b2 17 ; &17b2 = level11_platform_data - 1 &17a5 c5 17 ; &17c5 = level11_scenery_data - 1 &17a7 01 05 0d 11 # Platform data is at &17b3, &17b7, &17bf and &17c3 &17ab 01 04 0d # Scenery data is at &17c6, &17c9 and &17d2 &17ae e6 f2 ; R M # Red platforms, magenta ladders &17b0 d8 17 ; &17d8 = level11_exit_data &17b2 00 ; level11_platform_data ; + - + - + - + - &17b3 a5 dc e6 ff # Bottom platforms &17b7 00 19 28 64 73 78 8c b4 # Middle platforms &17bf 00 2f 64 8c # Top platforms &17c3 11 ff # Ceiling platforms &17c5 00 ; level11_scenery_data &17c6 af b4 05 ; &af-&b4, LADDER # Bottom scenery &17c9 28 2d 05 ; &28-&2d, LADDER # Middle scenery &17cc 5f 64 05 ; &5f-&64, LADDER &17cf 8c 9a 04 ; &8c-&9a, STAIRS_LEFT &17d2 00 0e 04 ; &00-&0e, STAIRS_LEFT # Top scenery &17d5 1e 21 0c ; &1e-&21, TORCH ; level11_exit_data &17d8 00 11 94 ; &00-11, bottom, starting position &14 (level 15) &17db dc e6 15 ; &dc-e6, ceiling, starting position &15 (level 14) &17de ff ; level12_background_data &17df ee 17 ; &17ee = level12_platform_data - 1 &17e1 04 18 ; &1804 = level12_scenery_data - 1 &17e3 01 02 10 14 # Platform data is at &17ef, &17f0, &17fe and &1802 &17e7 02 03 09 # Scenery data is at &1806, &1807 and &180d &17ea e3 f6 ; B R # Blue platforms, red ladders &17ec 13 18 ; &1813 = level12_exit_data &17ee 00 ; level12_platform_data ; + - + - + - + - + - + - + - &17ef ff # No bottom platforms &17f0 00 19 28 78 88 96 a2 aa b6 c3 cf d7 e6 ff # Middle platforms &17fe 00 2f d0 ff # Top platforms &1802 11 ee ff # Ceiling platforms ; level12_scenery_data &1805 ff ff # No bottom scenery &1807 28 2d 05 ; &28-&2d, LADDER # Middle scenery &180a d2 d7 05 ; &d2-&d7, LADDER &180d 00 0e 04 ; &00-&0e, STAIRS_LEFT # Top scenery &1810 ef fe 03 ; &ef-&fe, STAIRS_RIGHT ; level12_exit_data &1813 00 11 96 ; &00-11, ceiling, starting position &16 (level 9) &1816 ee fe 97 ; &ee-fe, ceiling, starting position &17 (level 13) &1819 ff ; level13_background_data &181a 29 18 ; &1829 = level13_platform_data &181c 41 18 ; &1841 = level13_scenery_data - 1 &181e 00 04 12 16 # Platform data is at &1829, &182d, &183b and &183f &1822 01 05 0e # Scenery data is at &1842, &1846 and &184f &1825 e6 f2 ; R M # Red platforms, magenta ladders &1827 55 18 ; &1855 = level13_exit_data ; level13_platform_data ; + - + - + - + - + - + - + - &1829 00 14 1e 50 # Bottom platforms &182d 1e 37 4a 64 87 96 a2 ac b8 c3 cf d7 e6 ff # Middle platforms &183b 5e 89 d0 ff # Top platforms &183f 00 ee # Ceiling platforms &1841 00 ; level13_scenery_data &1842 4b 50 05 ; &4b-&50, LADDER # Bottom scenery &1845 00 &1846 5f 64 05 ; &5f-&64, LADDER # Middle scenery &1849 87 8c 05 ; &87-&8c, LADDER &184c d2 d7 05 ; &d2-&d7, LADDER &184f d2 d5 0c ; &d2-&d5, TORCH # Top scenery &1852 ef fe 03 ; &ef-&fe, STAIRS_RIGHT ; level13_exit_data &1855 14 1e 19 ; &14-1e, bottom, starting position &19 (level 12) &1858 ee fe 98 ; &ee-fe, ceiling, starting position &18 (level 14) &1859 ff ; level14_background_data &185c 6b 18 ; &186b = level14_platform_data &185e 86 18 ; &1886 = level14_scenery_data &1860 00 04 0e 18 # Platform data is at &186b, &186f, &1879 and &1883 &1854 00 06 0f # Scenery data is at &1886, &188c and &1895 &1867 e2 f6 ; M R # Magenta platforms, red ladders &1869 9b 18 ; &189b = level14_exit_data ; level14_platform_data ; + - + - + - + - + - &186b 00 dc e6 ff # Bottom platforms &186f 64 73 7f 89 95 af b9 c3 cd dc # Middle platforms &1879 00 28 34 50 5c 69 78 7d aa ce # Top platforms &1883 11 ff # Ceiling platforms &1885 00 ; level14_scenery_data &1886 78 80 0b ; &78-&80, SHIELD # Bottom scenery &1889 d7 dc 05 ; &d7-&dc, LADDER &188c 64 69 05 ; &64-&69, LADDER # Middle scenery &188f aa af 05 ; &aa-&af, LADDER &1892 cd d2 05 ; &cd-&d2, LADDER &1895 00 0e 04 ; &00-&0e, STAIRS_LEFT # Top scenery &1898 1e 26 0b ; &1e-&26, SHIELD ; level14_exit_data &189b 00 11 9a ; &00-11, ceiling, starting position &1a (level 11) &18ae dc e6 1b ; &dc-e6, bottom, starting position &1b (level 13) &18a1 ff ; level15_background_data &18a2 b1 18 ; &18b1 = level15_platform_data &18a4 ba 18 ; &18ba = level15_scenery_data &18a6 00 08 08 08 # Platform data is at &18b1, &18b9, &18b9 and &18b9 &18aa 00 2d 3f # Scenery data is at &18ba, &18e7 and &18f9 &18ad e5 f6 ; G R # Green platforms, red ladders &18af fc 18 ; &18fc = level15_exit_data ; level15_platform_data ; + - + - + - + - &18b1 00 28 32 6c 7c c3 d3 ff # Bottom platforms &18b9 ff # No middle, top or ceiling platforms ; level15_scenery_data &18ba 00 06 31 ; &00-&06, CLIFF_RIGHT # Bottom scenery &18bd 22 24 32 ; &22-&24, BARRIER &18c0 3c 4c 06 ; &3c-&4c, TREE &18c3 50 55 2c ; &50-&55, CLIFF_LEFT &18c6 55 5b 30 ; &55-&5b, CLIFF &18c9 5b 60 05 ; &5b-&60, LADDER &18cc 60 66 30 ; &60-&66, CLIFF &18cf 66 6c 30 ; &66-&6c, CLIFF &18d2 7c 82 30 ; &7c-&82, CLIFF &18d5 82 88 30 ; &82-&88, CLIFF &18d8 88 8d 05 ; &88-&8d, LADDER &18db 8d 93 30 ; &8d-&93, CLIFF &18de 93 99 31 ; &93-&99, CLIFF_RIGHT &18e1 a0 b0 06 ; &a0-&b0, TREE &18e4 d3 e7 01 ; &d3-&e7, CASTLE &18e7 5c 61 2c ; &5c-&61, CLIFF_LEFT # Middle scenery &18ea 61 66 05 ; &61-&66, LADDER &18ed 66 6c 30 ; &66-&6c, CLIFF &18f0 7c 82 30 ; &7c-&82, CLIFF &18f3 82 87 05 ; &82-&87, LADDER &18f6 87 8d 31 ; &87-&8d, CLIFF_RIGHT &18f9 28 33 02 ; &28-&33, CLOUD # Top scenery ; level15_exit_data &18fc 28 32 1c ; &28-32, bottom, starting position &1c (level 11) &18ff ff ; platform_ends_right # Initial values unused for &1900 - &193d &1900 ff 00 0a 0e ; platform_starts_right &1904 2a 46 58 32 ; right_side_columns_right &1908 34 30 2c 32 ; platform_data_offsets_right &190c 32 32 0d 00 ; platform_ends_left &1910 14 0c 2a 46 ; platform_starts_left &1914 58 32 30 30 ; right_side_columns_left &1918 2c 32 0d 00 ; platform_data_offsets_left &191c 1e 16 4c 4f ; edges_of_level_visible # &80 if left edge of level is visible on screen &1920 4f # &01 if right edge of level is visible on screen ; section_to_plot &1921 50 ; length_of_next_rle_column ; height_of_platform &1922 3d ; scenery_sprites_right &1923 26 35 30 ; scenery_data_offsets_right &1926 3a 4c 4f ; scenery_sprites_address_low_right &1929 4f 50 31 ; scenery_sprites_address_high_right &192c 3d 26 36 ; scenery_sprites_left &192f 45 0d 00 ; scenery_data_offsets_left &1932 28 11 70 ; scenery_sprites_address_low_left &1935 6c 61 79 ; scenery_sprites_address_high_left &1938 74 75 6e ; scrolling_on_entry_to_level &193b 65 ; offset_in_column &193c 3d ; screen_edge_column &193d 26 ; platform_and_scenery_variables_addresses_left &193e 10 ; (&c0) = &1910 ; platform_ends_address = platform_ends_left &193f 14 ; (&c2) = &1914 ; platform_starts_address = platform_starts_left &1940 1c ; (&c4) = &191c ; platform_data_offsets_address = platform_data_offsets_left &1941 2f ; (&c6) = &192f ; scenery_sprites_address = scenery_sprites_left &1942 32 ; (&c8) = &1932 ; scenery_data_offsets_address = scenery_data_offsets_left &1943 35 ; (&ca) = &1935 ; scenery_sprites_addresses_low_address = scenery_sprites_address_low_left &1944 38 ; (&cc) = &1938 ; scenery_sprites_addresses_high_address = scenery_sprites_address_high_left ; platform_and_scenery_variables_addresses_right &1945 00 ; (&c0) = &1900 ; platform_ends_address = platform_ends_right &1946 04 ; (&c2) = &1904 ; platform_starts_address = platform_starts_right &1947 0c ; (&c4) = &190c ; platform_data_offsets_address = platform_data_offsets_right &1948 23 ; (&c6) = &1923 ; scenery_sprites_address = scenery_sprites_right &1949 26 ; (&c8) = &1926 ; scenery_data_offsets_address = scenery_data_offsets_right &194a 29 ; (&ca) = &1929 ; scenery_sprites_addresses_low_address = scenery_sprites_address_low_right &194b 2c ; (&cc) = &192c ; scenery_sprites_addresses_high_address = scenery_sprites_address_high_right ; level_data_address_addresses_table &194c 58 1a ; &1a58 = update_platform_addresses_for_scrolling_left_get_second_byte + 1 &194e 63 1a ; &1a63 = update_platform_addresses_for_scrolling_left_get_first_byte + 1 &1950 76 1b ; &1b76 = update_platform_addresses_for_scrolling_right_get_second_byte + 1 &1952 81 1b ; &1b81 = update_platform_addresses_for_scrolling_right_get_first_byte + 1 &1954 a9 1a ; &1aa9 = update_scenery_sprite_addresses_for_scrolling_left_get_second_byte + 1 &1956 b2 1a ; &1ab2 = update_scenery_sprite_addresses_for_scrolling_left_get_third_byte + 1 &1958 a3 1b ; &1ba3 = update_scenery_sprite_addresses_for_scrolling_right_get_first_byte + 1 &195a ad 1b ; &1bad = update_scenery_sprite_addresses_for_scrolling_right_get_third_byte + 1 ; initial_scrolled_screen_addresses &195c 40 00 ; &4000 # Top left of screen &195e 4f 07 ; &4f07 # Bottom left of top scenery &1960 60 87 ; &6087 # Bottom left of middle scenery &1962 72 07 ; &7207 # Bottom left of bottom scenery &1964 7c 00 ; &7c00 # Top left of lives &1966 7d c0 ; &7dc0 # Right of top left of lives (unused) &1968 7e 27 ; &7e27 # Bottom left of pockets ; unused &196a 00 &196b 00 ; score &196c 00 00 00 00 00 ; unused &1971 00 ; lives_times_five # Initial value unused &1972 0f ; initialise_platform_and_scenery_variable_addresses &1973 d0 0c BNE &1981 ; use_right_addresses ; use_left_addresses &1975 a5 b2 LDA &b2 ; screen_left_x &1977 8d 3d 19 STA &193d ; screen_edge_column &197a a9 3e LDA #&3e ; &193e = platform_and_scenery_variables_addresses_left &197c 85 ce STA &ce ; addresses_address_low &197e 4c 8a 19 JMP &198a ; use_addresses ; use_right_addresses &1981 a9 45 LDA #&45 ; &1945 = platform_and_scenery_variables_addresses_right &1983 85 ce STA &ce ; zero_page_values_address_low &1985 a5 b3 LDA &b3 ; screen_right_x &1987 8d 3d 19 STA &193d ; screen_edge_column ; use_addresses &198a a9 19 LDA #&19 ; &1945 = platform_and_scenery_variables_addresses_right &198c 85 cf STA &cf ; addresses_address_high &198e a2 00 LDX #&00 &1990 a0 00 LDY #&00 ; initialise_platform_and_scenery_variable_addresses_loop &1992 b1 ce LDA (&ce),Y ; addresses_address_low &1994 95 c0 STA &c0,X ; platform_and_scenery_variable_addresses &1996 e8 INX &1997 a9 19 LDA #&19 &1999 95 c0 STA &c0,X ; platform_and_scenery_variable_addresses &199b e8 INX &199c c8 INY &199d e0 0e CPX #&0e &199f d0 f1 BNE &1992 ; initialise_platform_and_scenery_variable_addresses_loop &19a1 60 RTS ; add_length_of_rle_column_to_scenery_sprite_address &19a2 b1 ca LDA (&ca),Y ; scenery_sprites_addresses_low_address &19a4 85 ce STA &ce ; sprite_address_low &19a6 b1 cc LDA (&cc),Y ; scenery_sprites_addresses_high_address &19a8 85 cf STA &cf ; sprite_address_high &19aa 84 00 STY &00 ; section &19ac a0 00 LDY #&00 ; find_end_of_rle_column_loop &19ae c8 INY &19af b1 ce LDA (&ce),Y ; sprite_address &19b1 29 40 AND #&40 &19b3 d0 08 BNE &19bd ; found_end_of_rle_column &19b5 b1 ce LDA (&ce),Y ; sprite_address &19b7 30 f5 BMI &19ae ; find_end_of_rle_column_loop &19b9 c8 INY &19ba 4c ae 19 JMP &19ae ; find_end_of_rle_column_loop ; found_end_of_rle_column &19bd 8c 22 19 STY &1922 ; length_of_next_rle_column &19c0 b1 ce LDA (&ce),Y ; sprite_address &19c2 10 06 BPL &19ca ; not_at_right_edge_of_scenery_sprite &19c4 a4 00 LDY &00 ; section &19c6 a9 00 LDA #&00 # &00 to indicate section has no sprite &19c8 91 c6 STA (&c6),Y ; scenery_sprites_address ; not_at_right_edge_of_scenery_sprite &19ca a4 00 LDY &00 ; section # Move to start of next column &19cc b1 ca LDA (&ca),Y ; scenery_sprites_addresses_low_address &19ce 18 CLC &19cf 6d 22 19 ADC &1922 ; length_of_next_rle_column &19d2 91 ca STA (&ca),Y ; scenery_sprites_addresses_low_address &19d4 90 06 BCC &19dc ; leave &19d6 e6 cf INC &cf ; sprite_address_high &19d8 a5 cf LDA &cf ; sprite_address_high &19da 91 cc STA (&cc),Y ; scenery_sprites_addresses_high_address ; leave &19dc 60 RTS ; scroll_screen_left &19dd a9 80 LDA #&80 # &80 to indicate scrolling left &19df 48 PHA &19e0 a5 b2 LDA &b2 ; screen_left_x &19e2 d0 05 BNE &19e9 ; not_at_left_edge_of_level &19e4 a9 80 LDA #&80 # Set &80 to indicate left edge of level is visible &19e6 8d 20 19 STA &1920 ; edges_of_level_visible ; not_at_left_edge_of_level &19e9 ad 20 19 LDA &1920 ; edges_of_level_visible &19ec f0 26 BEQ &1a14 ; within_level # &00 if neither edge of level is visible &19ee 10 13 BPL &1a03 ; right_edge_of_level_visible # &01 if right edge of level is visible &19f0 a5 b2 LDA &b2 ; screen_left_x # If the left edge of the level is visible, &19f2 c9 dc CMP #&dc &19f4 f0 0b BEQ &1a01 ; leave_after_pla &19f6 20 2a 1a JSR &1a2a ; update_platform_and_scenery_addresses_for_scrolling_left_with_right_variables &19f9 a9 00 LDA #&00 # Use left set of variables &19fb 20 73 19 JSR &1973 ; initialise_platform_and_scenery_variable_addresses &19fe 4c 1a 1a JMP &1a1a ; decrease_right_side_columns # Left variables haven't been updated ; leave_after_pla &1a01 68 PLA &1a02 60 RTS ; right_edge_of_level_visible &1a03 a5 b3 LDA &b3 ; screen_right_x &1a05 c9 fe CMP #&fe &1a07 f0 06 BEQ &1a0f ; returning_to_level &1a09 20 2f 1a JSR &1a2f ; update_platform_and_scenery_addresses_for_scrolling_left_with_left_variables &1a0c 4c 1a 1a JMP &1a1a ; decrease_right_side_columns # Right variables haven't been updated ; returning_to_level &1a0f a9 00 LDA #&00 # &00 to indicate right edge of level no longer visible &1a11 8d 20 19 STA &1920 ; edges_of_level_visible ; within_level &1a14 20 2a 1a JSR &1a2a ; update_platform_and_scenery_addresses_for_scrolling_left_with_right_variables &1a17 20 2f 1a JSR &1a2f ; update_platform_and_scenery_addresses_for_scrolling_left_with_left_variables ; decrease_right_side_columns &1a1a a2 00 LDX #&00 ; decrease_right_side_columns_loop &1a1c de 08 19 DEC &1908,X ; right_side_columns_right &1a1f de 18 19 DEC &1918,X ; right_side_columns_left &1a22 e8 INX &1a23 e0 04 CPX #&04 &1a25 d0 f5 BNE &1a1c ; decrease_right_side_columns_loop &1a27 4c c7 1a JMP &1ac7 ; plot_left_column ; update_platform_and_scenery_addresses_for_scrolling_left_with_right_variables &1a2a a9 01 LDA #&01 # Use right set of variables &1a2c 4c 31 1a JMP &1a31 ; update_platform_and_scenery_addresses_for_scrolling_left ; update_platform_and_scenery_addresses_for_scrolling_left_with_left_variables &1a2f a9 00 LDA #&00 # Use left set of variables ; update_platform_and_scenery_addresses_for_scrolling_left &1a31 20 73 19 JSR &1973 ; initialise_platform_and_scenery_variable_addresses &1a34 20 6d 1a JSR &1a6d ; update_scenery_sprite_addresses_for_scrolling_left &1a37 20 3b 1a JSR &1a3b ; update_platform_addresses_for_scrolling_left &1a3a 60 RTS ; update_platform_addresses_for_scrolling_left &1a3b a0 00 LDY #&00 ; section_loop &1a3d b1 c0 LDA (&c0),Y ; platform_ends_address &1a3f f0 12 BEQ &1a53 ; no_platform_at_this_section # Is a platform being plotted at this section? &1a41 b1 c2 LDA (&c2),Y ; platform_starts_address &1a43 cd 3d 19 CMP &193d ; screen_edge_column &1a46 90 1f BCC &1a67 ; consider_next_section # Does the platform include this column? &1a48 b1 c4 LDA (&c4),Y platform_data_offsets_address &1a4a 38 SEC &1a4b e9 02 SBC #&02 &1a4d 91 c4 STA (&c4),Y ; platform_data_offsets_address # Update the data offset to point at previous platform &1a4f a9 00 LDA #&00 &1a51 91 c0 STA (&c0),Y ; no_platform_at_this_section &1a53 b1 c4 LDA (&c4),Y ; platform_data_offsets_address &1a55 aa TAX &1a56 ca DEX ; update_platform_addresses_for_scrolling_left_get_second_byte &1a57 bd 00 0d LDA &0d00,X # Second byte of platform data is platform end x # actually LDA level_platform_data,X &1a5a cd 3d 19 CMP &193d ; screen_edge_column &1a5d d0 08 BNE &1a67 ; consider_next_section &1a5f 91 c0 STA (&c0),Y ; platform_ends_address &1a61 ca DEX ; update_platform_addresses_for_scrolling_left_get_first_byte &1a62 bd 00 0d LDA &0d00,X # First byte of platform data is platform start x # actually LDA level_platform_data,X &1a65 91 c2 STA (&c2),Y ; platform_starts_address ; consider_next_section &1a67 c8 INY &1a68 c0 04 CPY #&04 &1a6a d0 d1 BNE &1a3d ; section_loop &1a6c 60 RTS ; update_scenery_sprite_addresses_for_scrolling_left &1a6d a0 00 LDY #&00 ; platform_loop &1a6f b1 c6 LDA (&c6),Y ; scenery_sprites_address &1a71 f0 30 BEQ &1aa3 ; no_sprite_on_this_platform # Is a scenery sprite being plotted on this platform? &1a73 b1 ca LDA (&ca),Y ; scenery_sprites_addresses_low_address &1a75 85 ce STA &ce ; sprite_address_low &1a77 b1 cc LDA (&cc),Y ; scenery_sprites_addresses_high_address &1a79 85 cf STA &cf ; sprite_address_high &1a7b a2 00 LDX #&00 # Get a byte of sprite data for the scenery sprite &1a7d a1 ce LDA (&ce,X) ; sprite_address &1a7f c9 ff CMP #&ff # &ff indicates the start (left edge) of sprite &1a81 f0 15 BEQ &1a98 ; at_left_edge_of_scenery_sprite &1a83 29 3f AND #&3f # Otherwise, byte is length of a single RLE column &1a85 85 ce STA &ce ; length_of_previous_rle_column &1a87 b1 ca LDA (&ca),Y ; scenery_sprites_addresses_low_address # Move back to start of previous column &1a89 38 SEC &1a8a e5 ce SBC &ce ; length_of_previous_rle_column &1a8c 91 ca STA (&ca),Y ; scenery_sprites_addresses_low_address &1a8e b0 31 BCS &1ac1 ; consider_next_platform &1a90 a6 cf LDX &cf ; scenery_sprites_addresses_high_address &1a92 ca DEX &1a93 8a TXA &1a94 91 cc STA (&cc),Y ; scenery_sprites_addresses_high_address &1a96 90 29 BCC &1ac1 ; consider_next_platform # Always branches ; at_left_edge_of_scenery_sprite &1a98 a9 00 LDA #&00 # Mark platform as having no sprite &1a9a 91 c6 STA (&c6),Y ; scenery_sprites_address &1a9c b1 c8 LDA (&c8),Y ; scenery_data_offsets_address # Move back to previous sprite in scenery data &1a9e 38 SEC &1a9f e9 03 SBC #&03 &1aa1 91 c8 STA (&c8),Y ; scenery_data_offsets_address ; no_sprite_on_this_platform &1aa3 b1 c8 LDA (&c8),Y ; scenery_data_offsets_address &1aa5 aa TAX &1aa6 ca DEX &1aa7 ca DEX ; update_scenery_sprite_addresses_for_scrolling_left_get_second_byte &1aa8 bd ff ff LDA &ffff,X # Second byte of scenery data is sprite end x # actually LDA level_scenery_data, X &1aab cd 3d 19 CMP &193d ; screen_edge_column &1aae d0 11 BNE &1ac1 ; consider_next_platform # Does the scenery sprite end in this column? &1ab0 e8 INX ; update_scenery_sprite_addresses_for_scrolling_left_get_third_byte &1ab1 bd ff ff LDA &ffff,X # Third byte of scenery data is sprite type # actually LDA level_scenery_data, X &1ab4 91 c6 STA (&c6),Y ; scenery_sprites_address &1ab6 aa TAX &1ab7 bd 33 05 LDA &0533,X ; scenery_sprites_last_column_address_low_table - 1 &1aba 91 ca STA (&ca),Y ; scenery_sprites_addresses_low_address &1abc bd 65 05 LDA &0565,X ; scenery_sprites_last_column_address_high_table - 1 &1abf 91 cc STA (&cc),Y ; scenery_sprites_addresses_high_address ; consider_next_platform &1ac1 c8 INY &1ac2 c0 03 CPY #&03 &1ac4 d0 a9 BNE &1a6f ; platform_loop &1ac6 60 RTS ; plot_left_column &1ac7 a9 18 LDA #&18 ; &1918 = right_side_columns_left &1ac9 85 c2 STA &c2 ; platform_starts_address_low &1acb c6 b2 DEC &b2 ; screen_left_x &1acd c6 b3 DEC &b3 ; screen_right_x ; subtract_0008_from_scrolled_screen_addresses # Move two pixels left &1acf a9 00 LDA #&00 &1ad1 8d 22 19 STA &1922 ; address ; subtract_0008_from_scrolled_screen_addresses_loop &1ad4 ae 22 19 LDX &1922 ; address &1ad7 b4 05 LDY &05,X ; scrolled_screen_addresses_low &1ad9 b5 04 LDA &04,X ; scrolled_screen_addresses_high &1adb aa TAX &1adc 20 7b 24 JSR &247b ; subtract_0008_from_screen_address_in_Y_X &1adf 8a TXA &1ae0 ae 22 19 LDX &1922 ; address &1ae3 95 04 STA &04,X ; scrolled_screen_addresses_high &1ae5 94 05 STY &05,X ; scrolled_screen_addresses_low &1ae7 e8 INX &1ae8 e8 INX &1ae9 8e 22 19 STX &1922 ; address &1aec e0 0e CPX #&0e &1aee d0 e4 BNE &1ad4 ; subtract_0008_from_scrolled_screen_addresses_loop &1af0 a6 b0 LDX &b0 ; crtc_start_address_high &1af2 a4 b1 LDY &b1 ; crtc_start_address_low &1af4 88 DEY &1af5 c0 ff CPY #&ff &1af7 d0 01 BNE &1afa ; skip_page &1af9 ca DEX ; skip_page &1afa e0 05 CPX #&05 &1afc d0 02 BNE &1b00 ; skip_wraparound &1afe a2 0f LDX #&0f ; skip_wraparound &1b00 4c 02 1c JMP &1c02 ; set_crtc_start_address_and_plot_column_of_level ; scroll_screen_right &1b03 a9 01 LDA #&01 # &01 to indicate scrolling right &1b05 48 PHA &1b06 a5 b3 LDA &b3 ; screen_right_x &1b08 c9 fd CMP #&fd &1b0a d0 05 BNE &1b11 ; not_at_right_edge_of_level &1b0c a9 01 LDA #&01 # Set &01 to indicate right edge of level is visible &1b0e 8d 20 19 STA &1920 ; edges_of_level_visible ; not_at_right_edge_of_level &1b11 ad 20 19 LDA &1920 ; edges_of_level_visible &1b14 f0 24 BEQ &1b3a ; within_level # &00 if neither edge of level is visible &1b16 30 13 BMI &1b2b ; left_edge_of_level_visible # &80 if left edge of level is visible &1b18 a5 b3 LDA &b3 ; screen_right_x # If the right edge of the level is visible, &1b1a c9 24 CMP #&24 &1b1c f0 0b BEQ &1b29 ; leave_after_pla &1b1e 20 55 1b JSR &1b55 ; update_platform_and_scenery_addresses_for_scrolling_right_with_left_variables &1b21 a9 01 LDA #&01 # Use right set of variables &1b23 20 73 19 JSR &1973 ; initialise_platform_and_scenery_variable_addresses &1b26 4c 40 1b JMP &1b40 ; increase_right_side_columns # Right variables haven't been updated ; leave_after_pla &1b29 68 PLA &1b2a 60 RTS ; left_edge_of_level_visible &1b2b a5 b2 LDA &b2 ; screen_left_x &1b2d f0 06 BEQ &1b35 ; returning_to_level &1b2f 20 50 1b JSR &1b50 ; update_platform_and_scenery_addresses_for_scrolling_right_with_right_variables &1b32 4c 40 1b JMP &1b40 ; increase_right_side_columns # Left variables haven't been updated ; returning_to_level &1b35 a9 00 LDA #&00 # &00 to indicate left edge of level no longer visible &1b37 8d 20 19 STA &1920 ; edges_of_level_visible ; within_level &1b3a 20 55 1b JSR &1b55 ; update_platform_and_scenery_addresses_for_scrolling_right_with_left_variables &1b3d 20 50 1b JSR &1b50 ; update_platform_and_scenery_addresses_for_scrolling_right_with_right_variables ; increase_right_side_columns &1b40 a2 00 LDX #&00 ; increase_right_side_columns_loop &1b42 fe 08 19 INC &1908,X ; right_side_columns_right &1b45 fe 18 19 INC &1918,X ; right_side_columns_left &1b48 e8 INX &1b49 e0 04 CPX #&04 &1b4b d0 f5 BNE &1b42 ; increase_right_side_columns_loop &1b4d 4c cb 1b JMP &1bcb ; plot_right_column ; update_platform_and_scenery_addresses_for_scrolling_right_with_right_variables &1b50 a9 01 LDA #&01 # Use right set of variables &1b52 4c 57 1b JMP &1b57 ; update_platform_and_scenery_addresses_for_scrolling_right ; update_platform_and_scenery_addresses_for_scrolling_right_with_left_variables &1b55 a9 00 LDA #&00 # Use left set of variables ; update_platform_and_scenery_addresses_for_scrolling_right &1b57 20 73 19 JSR &1973 ; initialise_platform_and_scenery_variable_addresses &1b5a 20 8f 1b JSR &1b8f ; update_scenery_sprite_addresses_for_scrolling_right &1b5d 20 61 1b JSR &1b61 ; update_platform_addresses_for_scrolling_right &1b60 60 RTS ; update_platform_adddresses_for_scrolling_right &1b61 a0 00 LDY #&00 ; section_loop &1b63 b1 c0 LDA (&c0),Y ; platform_ends_address &1b65 f0 0b BEQ &1b72 ; no_platform_at_this_section # Is a platform being plotted at this section? &1b67 ad 3d 19 LDA &193d ; screen_edge_column &1b6a d1 c0 CMP (&c0),Y ; platform_ends_address &1b6c 90 1b BCC &1b89 ; consider_next_section # Does the platform include this column? &1b6e a9 00 LDA #&00 &1b70 91 c0 STA (&c0),Y ; platform_ends_address ; no_platform_at_this_section &1b72 b1 c4 LDA (&c4),Y ; platform_data_offsets_address &1b74 aa TAX ; update_platform_addresses_for_scrolling_right_get_second_byte &1b75 bd 00 0d LDA &0d00,X # First byte of platform data is platform start x # actually LDA level_platform_data, X &1b78 cd 3d 19 CMP &193d ; screen_edge_column &1b7b d0 0c BNE &1b89 ; consider_next_section # Does a platform start in this column? &1b7d 91 c2 STA (&c2),Y ; platform_starts_address &1b7f e8 INX ; update_platform_addresses_for_scrolling_right_get_first_byte &1b80 bd 00 0d LDA &0d00,X # Second byte of platform data is platform end x # actually LDA level_platform_data, X &1b83 91 c0 STA (&c0),Y ; platform_ends_address &1b85 e8 INX &1b86 8a TXA # Update the data offset to point at next platform &1b87 91 c4 STA (&c4),Y ; platform_data_offsets_address ; consider_next_section &1b89 c8 INY &1b8a c0 04 CPY #&04 &1b8c d0 d5 BNE &1b63 ; section_loop &1b8e 60 RTS ; update_scenery_sprite_addresses_for_scrolling_right &1b8f a0 00 LDY #&00 ; section_loop &1b91 b1 c6 LDA (&c6),Y ; scenery_sprites_address &1b93 f0 0a BEQ &1b9f ; no_sprite_at_this_section # Is a scenery sprite being plotted at this section? ; consider_plotting_column_of_scenery_sprite &1b95 a5 c0 LDA &c0 ; platform_ends_address_low # &00 for right variables, &10 for left variables &1b97 f0 2c BEQ &1bc5 ; consider_next_section &1b99 20 a2 19 JSR &19a2 ; add_length_of_rle_column_to_scenery_sprite_address &1b9c 4c c5 1b JMP &1bc5 ; consider_next_section ; no_sprite_at_this_section &1b9f b1 c8 LDA (&c8),Y ; scenery_data_offsets_address &1ba1 aa TAX ; update_scenery_sprite_addresses_for_scrolling_right_get_first_byte &1ba2 bd ff ff LDA &ffff,X # First byte of scenery data is sprite start x # actually LDA level_scenery_data, X &1ba5 cd 3d 19 CMP &193d ; screen_edge_column &1ba8 d0 1b BNE &1bc5 ; consider_next_section # Does the scenery sprite start in this column? &1baa e8 INX &1bab e8 INX ; update_scenery_sprite_addresses_for_scrolling_right_get_third_byte &1bac bd ff ff LDA &ffff,X # Third byte of scenery data is sprite type # actually LDA level_scenery_data, X &1baf 91 c6 STA (&c6),Y ; scenery_sprites_address &1bb1 e8 INX &1bb2 8a TXA &1bb3 91 c8 STA (&c8),Y ; scenery_data_offsets_address # Update the data offset to point at next scenery &1bb5 b1 c6 LDA (&c6),Y ; scenery_sprites_address &1bb7 aa TAX &1bb8 bd 97 05 LDA &0597,X ; scenery_sprites_first_column_address_low_table - 1 &1bbb 91 ca STA (&ca),Y ; scenery_sprites_addresses_low_address &1bbd bd c9 05 LDA &05c9,X ; scenery_sprites_first_column_address_high_table - 1 &1bc0 91 cc STA (&cc),Y ; scenery_sprites_addresses_high_address &1bc2 4c 95 1b JMP &1b95 ; consider_plotting_column_of_scenery_sprite ; consider_next_section &1bc5 c8 INY &1bc6 c0 03 CPY #&03 &1bc8 d0 c7 BNE &1b91 ; section_loop &1bca 60 RTS ; plot_right_column &1bcb a9 08 LDA #&08 ; &1908 = right_side_columns_right &1bcd 85 c2 STA &c2 ; platform_starts_address_low &1bcf e6 b2 INC &b2 ; screen_left_x &1bd1 e6 b3 INC &b3 ; screen_right_x ; add_0008_to_scrolled_screen_addresses &1bd3 a9 00 LDA #&00 &1bd5 8d 22 19 STA &1922 ; address ; add_0008_to_scrolled_screen_addresses_loop &1bd8 ae 22 19 LDX &1922 ; address &1bdb b4 05 LDY &05,X ; scrolled_screen_addresses_low &1bdd b5 04 LDA &04,X ; scrolled_screen_addresses_high &1bdf aa TAX &1be0 20 49 24 JSR &2449 ; add_0008_to_screen_address_in_Y_X &1be3 8a TXA &1be4 ae 22 19 LDX &1922 ; address &1be7 95 04 STA &04,X ; scrolled_screen_addresses_high &1be9 94 05 STY &05,X ; scrolled_screen_addresses_low &1beb e8 INX &1bec e8 INX &1bed 8e 22 19 STX &1922 ; address &1bf0 e0 0e CPX #&0e &1bf2 d0 e4 BNE &1bd8 ; add_0008_to_scrolled_screen_addresses_loop &1bf4 a6 b0 LDX &b0 ; crtc_start_address_high &1bf6 a4 b1 LDY &b1 ; crtc_start_address_low &1bf8 c8 INY &1bf9 d0 01 BNE &1bfc ; skip_page &1bfb e8 INX &1bfc e0 10 CPX #&10 ; skip_page &1bfe d0 02 BNE &1c02 ; skip_wraparound &1c00 a2 06 LDX #&06 ; skip_wraparound ; set_crtc_start_address_and_plot_column_of_level &1c02 86 b0 STX &b0 ; crtc_start_address_high &1c04 84 b1 STY &b1 ; crtc_start_address_low &1c06 a6 04 LDX &04 ; scrolled_screen_addresses_low # Top left of scrolled screen &1c08 a4 05 LDY &05 ; scrolled_screen_addresses_high &1c0a 68 PLA # &01 if scrolling right, &80 if scrolling left &1c0b 48 PHA &1c0c 30 11 BMI &1c1f ; scrolling_left &1c0e e8 INX # Add &0278 to screen address if scrolling right &1c0f e8 INX # i.e. use top right of scrolled screen &1c10 98 TYA &1c11 18 CLC &1c12 69 78 ADC #&78 &1c14 a8 TAY &1c15 90 01 BCC &1c18 ; skip_page &1c17 e8 INX ; skip_page &1c18 8a TXA &1c19 10 04 BPL &1c1f ; skip_wraparound &1c1b 38 SEC &1c1c e9 40 SBC #&40 &1c1e aa TAX ; skip_wraparound ; scrolling_left &1c1f 86 c9 STX &c9 ; screen_address_high &1c21 84 c8 STY &c8 ; screen_address_low &1c23 a9 00 LDA #&00 &1c25 8d 3c 19 STA &193c ; offset_in_column &1c28 68 PLA # &01 if scrolling right, &80 if scrolling left &1c29 2d 20 19 AND &1920 ; edges_of_level_visible # &80 if left edge visible, &01 set if right &1c2c f0 11 BEQ &1c3f ; plot_sections # Is this column past the edge of the level? ; beyond_edges_of_level &1c2e a2 14 LDX #&14 # Write 20 black pixel pairs &1c30 a9 00 LDA #&00 &1c32 20 dc 1e JSR &1edc ; write_X_copies_of_A_to_column_buffer &1c35 a2 b4 LDX #&b4 # Write 180 colour pixel pairs &1c37 a9 fc LDA #&fc &1c39 20 dc 1e JSR &1edc ; write_X_copies_of_A_to_column_buffer &1c3c 4c 40 1e JMP &1e40 ; plot_objects_into_column_buffer ; plot_sections # If this column is within the level, &1c3f a0 00 LDY #&00 &1c41 8c 21 19 STY &1921 ; section_to_plot &1c44 a2 14 LDX #&14 # Write 20 black pixel pairs at bottom of screen &1c46 a9 00 LDA #&00 &1c48 20 dc 1e JSR &1edc ; write_X_copies_of_A_to_column_buffer &1c4b 20 5f 1c JSR &1c5f ; plot_platform # Plot bottom platform ; sections_loop &1c4e 20 cb 1c JSR &1ccb ; plot_section # Plot scenery, then platform above it &1c51 ac 21 19 LDY &1921 ; section_to_plot &1c54 c8 INY &1c55 8c 21 19 STY &1921 ; section_to_plot &1c58 c0 03 CPY #&03 &1c5a d0 f2 BNE &1c4e ; sections_loop &1c5c 4c 40 1e JMP &1e40 ; plot_objects_into_column_buffer ; plot_platform &1c5f ac 21 19 LDY &1921 ; section_to_plot &1c62 b1 c2 LDA (&c2),Y ; platform_starts_address &1c64 a8 TAY &1c65 b9 00 80 LDA &8000,Y # Use content of paged ROM as pseudo-random source &1c68 29 03 AND #&03 &1c6a 18 CLC &1c6b 69 07 ADC #&07 &1c6d 8d 22 19 STA &1922 ; height_of_platform # for the height of the top, colour part of platform &1c70 ac 21 19 LDY &1921 ; section_to_plot &1c73 b1 c0 LDA (&c0),Y ; platform_ends_address &1c75 d0 06 BNE &1c7d ; is_platform ; is_gap &1c77 a2 0c LDX #&0c # Write 12 black pixel pairs instead of platform &1c79 20 dc 1e JSR &1edc ; write_X_copies_of_A_to_column_buffer &1c7c 60 RTS ; is_platform &1c7d a9 0c LDA #&0c &1c7f 38 SEC &1c80 ed 22 19 SBC &1922 ; height_of_platform &1c83 aa TAX &1c84 a9 00 LDA #&00 # Write (12 - height_of_platform) black pixel pairs &1c86 20 dc 1e JSR &1edc ; write_X_copies_of_A_to_column_buffer &1c89 ae 22 19 LDX &1922 ; height_of_platform &1c8c a9 fc LDA #&fc # Write height_of_platform colour pixel pairs &1c8e 20 dc 1e JSR &1edc ; write_X_copies_of_A_to_column_buffer &1c91 60 RTS ; write_column_of_scenery_sprite_to_column_buffer &1c92 a9 00 LDA #&00 &1c94 85 01 STA &01 ; rows_written &1c96 b1 cc LDA (&cc),Y ; scenery_sprites_addresses_high_address &1c98 aa TAX &1c99 b1 ca LDA (&ca),Y ; scenery_sprites_addresses_low_address &1c9b a8 TAY ; write_column_of_sprite_to_column_buffer &1c9c c8 INY &1c9d d0 01 BNE &1ca0 ; skip_page &1c9f e8 INX ; skip_page &1ca0 84 ce STY &ce ; scenery_sprite_address_low &1ca2 86 cf STX &cf ; scenery_sprite_address_high &1ca4 a0 00 LDY #&00 ; write_column_of_scenery_sprite_to_column_buffer_loop &1ca6 b1 ce LDA (&ce),Y ; scenery_sprite # Get a byte of sprite data, consider top two bits &1ca8 aa TAX &1ca9 29 40 AND #&40 # If &40 set, this is the end of the column &1cab d0 1d BNE &1cca ; leave &1cad 8a TXA &1cae 30 0c BMI &1cbc ; single_row # If &c0 unset, bottom five bits are run length &1cb0 8a TXA &1cb1 18 CLC &1cb2 65 01 ADC &01 ; rows_written &1cb4 85 01 STA &01 ; rows_written &1cb6 c8 INY &1cb7 b1 ce LDA (&ce),Y ; scenery_sprite # Get second byte of sprite data for pixel values &1cb9 4c c3 1c JMP &1cc3 ; write_rows ; single_row # If &80 set, bottom five bits are pixel values &1cbc 8a TXA &1cbd 29 7f AND #&7f &1cbf a2 01 LDX #&01 &1cc1 e6 01 INC &01 ; rows_written ; write_rows &1cc3 20 dc 1e JSR &1edc ; write_X_copies_of_A_to_column_buffer # Write rows when plotting scenery, # or JSR &1ef3 ; eor_X_copies_of_A_to_column_buffer # EOR rows when plotting object &1cc6 c8 INY &1cc7 4c a6 1c JMP &1ca6 ; write_column_of_scenery_sprite_to_column_buffer ; leave &1cca 60 RTS ; plot_section &1ccb ac 21 19 LDY &1921 ; section_to_plot &1cce b1 c6 LDA (&c6),Y ; scenery_sprites_address &1cd0 d0 0a BNE &1cdc ; section_has_scenery # If there is no scenery sprite in this section, &1cd2 a2 2c LDX #&2c # Write 44 black pixel pairs &1cd4 a9 00 LDA #&00 &1cd6 20 dc 1e JSR &1edc ; write_X_copies_of_A_to_column_buffer &1cd9 4c f8 1c JMP &1cf8 ; plot_platform_above_section ; section_has_scenery &1cdc 20 92 1c JSR &1c92 ; write_column_of_scenery_sprite_to_column_buffer &1cdf ac 21 19 LDY &1921 ; section_to_plot &1ce2 a5 c0 LDA &c0 ; platform_ends_address # &00 for right variables, &10 for left variables &1ce4 d0 03 BNE &1ce9 ; scrolling_left &1ce6 20 a2 19 JSR &19a2 ; add_length_of_rle_column_to_scenery_sprite_address ; scrolling_left &1ce9 a9 2c LDA #&2c # Did the scenery sprite occupy all 44 rows of the &1ceb 38 SEC # section? &1cec e5 01 SBC &01 ; rows_written &1cee f0 08 BEQ &1cf8 ; plot_platform_above_section &1cf0 90 10 BCC &1d02 ; scenery_sprite_bigger_than_this_section &1cf2 aa TAX # If scenery sprite is smaller, &1cf3 a9 00 LDA #&00 # write black pixel pairs to fill remainder &1cf5 20 dc 1e JSR &1edc ; write_X_copies_of_A_to_column_buffer ; plot_platform_above_section &1cf8 ee 21 19 INC &1921 ; section_to_plot &1cfb 20 5f 1c JSR &1c5f ; plot_platform &1cfe ce 21 19 DEC &1921 ; section_to_plot &1d01 60 RTS ; scenery_sprite_bigger_than_this_section &1d02 a9 38 LDA #&38 ; &2c + &c # Did the scenery sprite occupy all 56 rows of the &1d04 38 SEC # section and the platform above it? &1d05 e5 01 SBC &01 ; rows_written &1d07 90 08 BCC &1d11 ; scenery_sprite_bigger_than_next_platform &1d09 f0 1a BEQ &1d25 ; leave &1d0b aa TAX # If scenery sprite is smaller, &1d0c a9 00 LDA #&00 # write black pixel pairs to fill remainder &1d0e 4c dc 1e JMP &1edc ; write_X_copies_of_A_to_column_buffer ; scenery_sprite_bigger_than_next_platform &1d11 a9 64 LDA #&64 ; &2c * 2 + &c # Did the scenery sprite occupy all 100 rows of the &1d13 38 SEC # section, the platform, and the section above it? &1d14 e5 01 SBC &01 ; rows_written &1d16 90 0e BCC &1d26 ; scenery_sprite_bigger_than_next_section &1d18 f0 06 BEQ &1d20 ; skip_next_section &1d1a aa TAX # If scenery sprite is smaller, &1d1b a9 00 LDA #&00 # write black pixel pairs to fill remainder &1d1d 20 dc 1e JSR &1edc ; write_X_copies_of_A_to_column_buffer ; skip_next_section &1d20 ee 21 19 INC &1921 ; section_to_plot # Don't plot next section &1d23 d0 d3 BNE &1cf8 ; plot_platform_above_section # Always branches ; leave &1d25 60 RTS ; scenery_sprite_bigger_than_next_section &1d26 a9 a8 LDA #&a8 ; &2c * 3 + &c * 3 # Write black pixels to fill all but ceiling platform &1d28 38 SEC &1d29 e5 01 SBC &01 ; rows_written &1d2b aa TAX &1d2c a9 00 LDA #&00 &1d2e 20 dc 1e JSR &1edc ; write_X_copies_of_A_to_column_buffer &1d31 ee 21 19 INC &1921 ; section_to_plot # Don't plot next two sections &1d34 ee 21 19 INC &1921 ; section_to_plot &1d37 60 RTS ; plot_column_of_object_scrolling_left &1d38 bd 82 04 LDA &0482,X ; objects_sprite_address_low &1d3b 85 ce STA &ce ; sprite_address_low &1d3d bd 9c 04 LDA &049c,X ; objects_sprite_address_high &1d40 85 cf STA &cf ; sprite_address_high &1d42 a0 00 LDY #&00 &1d44 b1 ce LDA (&ce),Y ; sprite_address &1d46 c9 ff CMP #&ff &1d48 d0 08 BNE &1d52 ; not_end_of_sprite &1d4a a5 ba LDA &ba ; player_level &1d4c 9d 00 04 STA &0400,X ; objects_level # Clear &80 and &40 to indicate no cropping ; to_consider_next_object &1d4f 4c 6e 1e JMP &1e6e ; consider_next_object ; not_end_of_sprite &1d52 29 3f AND #&3f &1d54 85 cb STA &cb ; rle_data_length &1d56 a5 ce LDA &ce ; sprite_address_low # Move left a column in the sprite &1d58 38 SEC &1d59 e5 cb SBC &cb ; rle_data_length &1d5b 85 ce STA &ce ; sprite_address_low &1d5d b0 02 BCS &1d61 ; skip_page &1d5f c6 cf DEC &cf ; sprite_address_high ; skip_page &1d61 9d 82 04 STA &0482,X ; objects_sprite_address_low &1d64 a8 TAY &1d65 a5 cf LDA &cf ; sprite_address_high &1d67 9d 9c 04 STA &049c,X ; objects_sprite_address_high &1d6a bd 00 04 LDA &0400,X ; objects_level # &80 set if cropped to right &1d6d 30 e0 BMI &1d4f ; to_consider_next_object ; plot_column_of_object_and_consider_next_object &1d6f ad 20 19 LDA &1920 ; edges_of_level_visible &1d72 30 db BMI &1d4f ; to_consider_next_object # &80 if left edge of level visible &1d74 bd 34 04 LDA &0434,X ; objects_y &1d77 8d 3c 19 STA &193c ; offset_in_column &1d7a a6 cf LDX &cf ; sprite_address_high &1d7c 20 9c 1c JSR &1c9c ; write_column_of_sprite_to_column_buffer &1d7f 4c 6e 1e JMP &1e6e ; consider_next_object ; plot_column_of_object_scrolling_right &1d82 bd 82 04 LDA &0482,X ; objects_sprite_address_low &1d85 85 ce STA &ce ; sprite_address_low &1d87 bd 9c 04 LDA &049c,X ; objects_sprite_address_high &1d8a 85 cf STA &cf ; sprite_address_high &1d8c bd 00 04 LDA &0400,X ; objects_level &1d8f 10 14 BPL &1da5 ; not_cropped_to_right &1d91 ad 20 19 LDA &1920 ; edges_of_level_visible &1d94 c9 01 CMP #&01 # &01 if right edge of level visible &1d96 f0 0d BEQ &1da5 ; not_cropped_to_right &1d98 bd 34 04 LDA &0434,X ; objects_y &1d9b 8d 3c 19 STA &193c ; offset_in_column &1d9e a4 ce LDY &ce ; sprite_address_low &1da0 a6 cf LDX &cf ; sprite_address_high &1da2 20 9c 1c JSR &1c9c ; write_column_of_sprite_to_column_buffer ; not_cropped_to_right &1da5 a6 cd LDX &cd &1da7 4c ad 1d JMP &1dad ; find_start_of_next_rle_column ; to_consider_next_object &1daa 4c 6e 1e JMP &1e6e ; consider_next_object # Unused ; find_start_of_next_rle_column &1dad a0 00 LDY #&00 ; find_start_of_next_rle_column_loop &1daf e6 ce INC &ce ; sprite_address_low &1db1 d0 02 BNE &1db5 ; skip_page &1db3 e6 cf INC &cf ; sprite_address_high ; skip_page &1db5 b1 ce LDA (&ce),Y ; sprite_address &1db7 c9 fc CMP #&fc # Keep searching if this is a pixel value &1db9 b0 f4 BCS &1daf ; find_start_of_next_rle_column_loop &1dbb 29 40 AND #&40 &1dbd f0 f0 BEQ &1daf ; find_start_of_next_rle_column_loop &1dbf b1 ce LDA (&ce),Y ; sprite_address &1dc1 10 05 BPL &1dc8 ; not_end_of_sprite &1dc3 a5 ba LDA &ba ; player_level &1dc5 9d 00 04 STA &0400,X ; objects_level # Clear &80 and &40 to indicate no cropping ; not_end_of_sprite &1dc8 a5 ce LDA &ce ; sprite_address_low &1dca 9d 82 04 STA &0482,X ; objects_sprite_address_low &1dcd a5 cf LDA &cf ; sprite_address_high &1dcf 9d 9c 04 STA &049c,X ; objects_sprite_address_high &1dd2 4c 6e 1e JMP &1e6e ; consider_next_object ; mark_object_as_cropped_or_not &1dd5 a5 c0 LDA &c0 ; platform_ends_address # &00 for right variables, &10 for left variables &1dd7 f0 1d BEQ &1df6 ; right_variables ; left_variables &1dd9 bd 68 04 LDA &0468,X ; objects_end_x &1ddc c5 b3 CMP &b3 ; screen_right_x &1dde d0 09 BNE &1de9 ; not_right_edge_of_object_left_variables &1de0 98 TYA &1de1 49 80 EOR #&80 # Unset &80 to indicate not cropped to right &1de3 20 13 1e JSR &1e13 ; store_cropped_state_and_use_last_column_of_sprite ; not_left_edge_of_object_left_variables &1de6 4c 6e 1e JMP &1e6e ; consider_next_object ; not_right_edge_of_object_left_variables &1de9 c5 b2 CMP &b2 ; screen_left_x &1deb d0 f9 BNE &1de6 ; not_left_edge_of_object_left_variables &1ded 98 TYA &1dee 49 40 EOR #&40 # Unset &40 to indicate not cropped to left &1df0 20 13 1e JSR &1e13 ; store_cropped_state_and_use_last_column_of_sprite &1df3 4c 6f 1d JMP &1d6f ; plot_column_of_object_and_consider_next_object ; right_variables &1df6 bd 4e 04 LDA &044e,X ; objects_x &1df9 c5 b2 CMP &b2 ; screen_left_x &1dfb d0 09 BNE &1e06 ; not_left_edge_of_object_right_variables &1dfd 98 TYA &1dfe 49 40 EOR #&40 # Unset &40 to indicate not cropped to left &1e00 20 29 1e JSR &1e29 ; store_cropped_state_and_use_first_column_of_sprite &1e03 4c ad 1d JMP &1dad ; find_start_of_next_rle_column ; not_left_edge_of_object_right_variables &1e06 c5 b3 CMP &b3 ; screen_right_x &1e08 d0 64 BNE &1e6e ; consider_next_object &1e0a 98 TYA &1e0b 49 80 EOR #&80 # Unset &80 to indicate not cropped to right &1e0d 20 29 1e JSR &1e29 ; store_cropped_state_and_use_first_column_of_sprite &1e10 4c 82 1d JMP &1d82 ; plot_column_of_object_scrolling_right ; store_cropped_state_and_use_last_column_of_sprite &1e13 9d 00 04 STA &0400,X ; objects_level &1e16 bc 1a 04 LDY &041a,X ; objects_sprite &1e19 b9 65 05 LDA &0565,Y ; scenery_sprites_last_column_address_high_table - 1 &1e1c 9d 9c 04 STA &049c,X ; objects_sprite_address_high &1e1f 85 cf STA &cf ; sprite_address_high &1e21 b9 33 05 LDA &0533,Y ; scenery_sprites_last_column_address_low_table - 1 &1e24 9d 82 04 STA &0482,X ; objects_sprite_address_low &1e27 a8 TAY &1e28 60 RTS ; store_cropped_state_and_use_first_column_of_sprite &1e29 9d 00 04 STA &0400,X ; objects_level &1e2c bc 1a 04 LDY &041a,X ; objects_sprite &1e2f b9 c9 05 LDA &05c9,Y ; scenery_sprites_first_column_address_high_table - 1 &1e32 9d 9c 04 STA &049c,X ; objects_sprite_address_high &1e35 85 cf STA &cf ; sprite_address_high &1e37 b9 97 05 LDA &0597,Y ; scenery_sprites_first_column_address_low_table - 1 &1e3a 9d 82 04 STA &0482,X ; objects_sprite_address_low &1e3d 85 ce STA &ce ; sprite_address_low &1e3f 60 RTS ; plot_objects_into_column_buffer &1e40 a9 f3 LDA #&f3 ; &1ef3 = eor_X_copies_of_A_to_column_buffer &1e42 8d c4 1c STA &1cc4 ; write_rows + 1 &1e45 a9 1e LDA #&1e # EOR, not write, object sprites to column buffer &1e47 8d c5 1c STA &1cc5 ; write_rows + 2 &1e4a a9 00 LDA #&00 &1e4c 85 cd STA &cd ; object_to_consider ; plot_objects_into_column_buffer_loop &1e4e a6 cd LDX &cd ; object_to_consider &1e50 bd 00 04 LDA &0400,X ; objects_level &1e53 a8 TAY &1e54 f0 18 BEQ &1e6e ; consider_next_object &1e56 29 3f AND #&3f &1e58 c5 ba CMP &ba ; player_level &1e5a d0 12 BNE &1e6e ; consider_next_object &1e5c 98 TYA &1e5d 29 c0 AND #&c0 # &80 set when cropped on right, &40 left &1e5f d0 03 BNE &1e64 ; object_is_cropped_by_edge_of_screen &1e61 4c d5 1d JMP &1dd5 ; mark_object_as_cropped_or_not ; object_is_cropped_by_edge_of_screen &1e64 a5 c0 LDA &c0 ; platform_ends_address # &00 for right variables, &10 for left variables &1e66 d0 03 BNE &1e6b ; to_plot_column_of_object_scrolling_left &1e68 4c 82 1d JMP &1d82 ; plot_column_of_object_scrolling_right ; to_plot_column_of_object_scrolling_left &1e6b 4c 38 1d JMP &1d38 ; plot_column_of_object_scrolling_left ; consider_next_object &1e6e a6 cd LDX &cd ; object_to_consider &1e70 e8 INX &1e71 86 cd STX &cd ; object_to_consider &1e73 e0 1a CPX #&1a &1e75 d0 d7 BNE &1e4e ; plot_objects_into_column_buffer_loop ; finished_plotting_objects_into_column_buffer &1e77 a9 dc LDA #&dc ; &1edc = write_X_copies_of_A_to_column_buffer &1e79 8d c4 1c STA &1cc4 ; write_rows + 1 &1e7c a9 1e LDA #&1e &1e7e 8d c5 1c STA &1cc5 ; write_rows + 2 &1e81 ad 3b 19 LDA &193b ; scrolling_on_entry_to_level &1e84 d0 06 BNE &1e8c ; skip_plotting_player &1e86 20 95 26 JSR &2695 ; plot_player_facing_left_or_right &1e89 20 cc 1e JSR &1ecc ; wait_for_vsync ; skip_plotting_player &1e8c a2 0c LDX #&0c # R12: Displayed screen start address register (high) &1e8e 8e 00 fe STX &fe00 ; video register number &1e91 a5 b0 LDA &b0 ; crtc_start_address_high &1e93 8d 01 fe STA &fe01 ; video register value &1e96 e8 INX # R13: Displayed screen start address register (low) &1e97 8e 00 fe STX &fe00 ; video register number &1e9a a5 b1 LDA &b1 ; crtc_start_address_low &1e9c 8d 01 fe STA &fe01 ; video register value # Update screen scroll ; plot_column_buffer_to_screen &1e9f a0 00 LDY #&00 &1ea1 a2 c8 LDX #&c8 # Copy 200 rows of pixel pairs ; plot_column_buffer_to_screen_loop &1ea3 bd ff 02 LDA &02ff,X ; column_buffer - 1 # from the column buffer &1ea6 91 c8 STA (&c8),Y ; screen_address # to the screen &1ea8 c8 INY &1ea9 c0 08 CPY #&08 &1eab f0 04 BEQ &1eb1 ; next_group ; next_row &1ead ca DEX &1eae d0 f3 BNE &1ea3 ; plot_column_buffer_to_screen_loop ; leave &1eb0 60 RTS ; next_group &1eb1 a5 c8 LDA &c8 ; screen_address_low &1eb3 18 CLC &1eb4 69 80 ADC #&80 &1eb6 85 c8 STA &c8 ; screen_address_low &1eb8 90 02 BCC &1ebc ; skip_page &1eba e6 c9 INC &c9 ; screen_address_high ; skip_page &1ebc a5 c9 LDA &c9 ; screen_address_high &1ebe 18 CLC &1ebf 69 02 ADC #&02 &1ec1 10 03 BPL &1ec6 ; skip_wraparound &1ec3 38 SEC &1ec4 e9 40 SBC #&40 &1ec6 85 c9 STA &c9 ; screen_address_high ; skip_wraparound &1ec8 a0 00 LDY #&00 &1eca f0 e1 BEQ &1ead ; next_row # Always branches ; wait_for_vsync &1ecc a9 02 LDA #&02 # Disable CA1 interrupt (v-sync) &1ece 8d 4e fe STA &fe4e ; System VIA interrupt enable register ; wait_for_vsync_loop &1ed1 2c 4d fe BIT &fe4d ; System VIA interrupt flag register # &02 is set when System VIA CA1 (v-sync) occurs &1ed4 f0 fb BEQ &1ed1 ; wait_for_vsync_loop &1ed6 a9 82 LDA #&82 # Enable CA1 interrupt (v-sync) &1ed8 8d 4e fe STA &fe4e ; System VIA interrupt enable register &1edb 60 RTS ; write_X_copies_of_A_to_column_buffer &1edc 48 PHA &1edd 8a TXA &1ede ae 3c 19 LDX &193c ; offset_in_column &1ee1 18 CLC &1ee2 6d 3c 19 ADC &193c ; offset_in_column &1ee5 8d 3c 19 STA &193c ; offset_in_column &1ee8 68 PLA ; write_X_copies_of_A_to_column_buffer_loop &1ee9 9d 00 03 STA &0300,X ; column_buffer &1eec e8 INX &1eed ec 3c 19 CPX &193c ; offset_in_column &1ef0 d0 f7 BNE &1ee9 ; write_X_copies_of_A_to_column_buffer_loop &1ef2 60 RTS ; eor_X_copies_of_A_to_column_buffer &1ef3 8d 02 1f STA &1f02 ; eor_value &1ef6 8a TXA &1ef7 ae 3c 19 LDX &193c ; offset_in_column &1efa 18 CLC &1efb 6d 3c 19 ADC &193c ; offset_in_column &1efe 8d 3c 19 STA &193c ; offset_in_column ; eor_X_copies_of_A_to_column_buffer_loop &1f01 a9 ff LDA #&ff # actually LDA eor_value &1f03 5d 00 03 EOR &0300,X ; column_buffer &1f06 9d 00 03 STA &0300,X ; column_buffer &1f09 e8 INX &1f0a ec 3c 19 CPX &193c ; offset_in_column &1f0d d0 f2 BNE &1f01 ; eor_X_copies_of_A_to_column_buffer_loop &1f0f 60 RTS ; scroll_left_and_update_player_and_enemy_addresses &1f10 20 dd 19 JSR &19dd ; scroll_screen_left &1f13 a6 12 LDX &12 ; player_screen_address_high &1f15 a4 13 LDY &13 ; player_screen_address_low &1f17 20 7b 24 JSR &247b ; subtract_0008_from_screen_address_in_Y_X # Move two pixels left &1f1a 86 12 STX &12 ; player_screen_address_high &1f1c 84 13 STY &13 ; player_screen_address_low &1f1e 4c 5d 29 JMP &295d ; update_enemy_screen_addresses_for_left_scroll ; scroll_right_and_update_player_and_enemy_addresses &1f21 20 03 1b JSR &1b03 ; scroll_screen_right &1f24 a6 12 LDX &12 ; player_screen_address_high &1f26 a4 13 LDY &13 ; player_screen_address_low &1f28 20 49 24 JSR &2449 ; add_0008_to_screen_address_in_Y_X # Move two pixels right &1f2b 86 12 STX &12 ; player_screen_address_high &1f2d 84 13 STY &13 ; player_screen_address_low &1f2f 4c 89 29 JMP &2989 ; update_enemy_screen_addresses_for_right_scroll ; game_over_screen &1f32 a2 04 LDX #&04 &1f34 a0 00 LDY #&00 ; copy_score_loop &1f36 bd 6c 19 LDA &196c,X ; score &1f39 99 d9 03 STA &03d9,Y ; game_over_text + &10 # Put score into game over text &1f3c a9 00 LDA #&00 &1f3e 9d 6c 19 STA &196c,X ; score &1f41 c8 INY &1f42 ca DEX &1f43 10 f1 BPL &1f36 ; copy_score_loop &1f45 a2 03 LDX #&03 ; &03c9 = game_over_text &1f47 a0 c9 LDY #&c9 &1f49 20 a9 30 JSR &30a9 ; plot_screen_of_text &1f4c 20 62 01 JSR &0162 ; play_tune ; start_screen &1f4f a9 02 LDA #&02 &1f51 85 36 STA &36 ; enemy_to_consider &1f53 a2 07 LDX #&07 ; &0788 = start_screen_text &1f55 a0 88 LDY #&88 &1f57 20 a9 30 JSR &30a9 ; plot_screen_of_text &1f5a 20 c0 21 JSR &21c0 ; wait_for_0_keypress &1f5d 20 62 01 JSR &0162 ; play_tune &1f60 a2 04 LDX #&04 &1f62 86 c1 STX &c1 ; source_address_high &1f64 86 c3 STX &c3 ; target_address_high &1f66 a9 d0 LDA #&d0 ; &04d0 = initial_objects_data &1f68 85 c0 STA &c0 ; source_address_low &1f6a a9 00 LDA #&00 ; &0400 = objects_level &1f6c 85 c2 STA &c2 ; target_address_low &1f6e a2 0a LDX #&0a ; wipe_pockets_loop &1f70 95 14 STA &14,X ; pockets # Wipe &14 - &1e, pockets and player variables &1f72 ca DEX &1f73 10 fb BPL &1f70 ; wipe_pockets_loop &1f75 a2 06 LDX #&06 &1f77 86 1a STX &1a ; player_feet_sprite &1f79 ca DEX ; initialise_data_loop &1f7a a0 13 LDY #&13 # Copy &04d0 - &04e3 to &0400 - &0413 (objects_level) ; initialise_data_inner_loop # &04e4 - &04f7 to &041a - &042d (objects_sprite) &1f7c b1 c0 LDA (&c0),Y ; source_address # &04f8 - &050b to &0434 - &0447 (objects_y) &1f7e 91 c2 STA (&c2),Y ; target_address # &050c - &051f to &044e - &0461 (objects_x) &1f80 88 DEY # &0520 - &0533 to &0468 - &047b (objects_end_x) &1f81 10 f9 BPL &1f7c ; initialise_data_inner_loop # i.e. copy initial_objects_* into objects_* &1f83 a5 c2 LDA &c2 ; target_address_low &1f85 18 CLC &1f86 69 1a ADC #&1a &1f88 85 c2 STA &c2 ; target_address_low &1f8a a5 c0 LDA &c0 ; source_address_low &1f8c 18 CLC &1f8d 69 14 ADC #&14 &1f8f 85 c0 STA &c0 ; target_address_low &1f91 90 02 BCC &1f95 ; skip_page &1f93 e6 c1 INC &c1 ; target_address_high ; skip_page &1f95 ca DEX &1f96 d0 e2 BNE &1f7a ; initialise_data_loop ; initialise_lives_and_starting_position &1f98 a9 14 LDA #&14 ; 25 # Start with 5 lives &1f9a 8d 72 19 STA &1972 ; lives_times_five &1f9d a2 06 LDX #&06 ; &067e = starting_positions_table # Use starting position 0 for start of game &1f9f 86 b5 STX &b5 ; starting_position_address_high &1fa1 a2 7e LDX #&7e &1fa3 86 b4 STX &b4 ; starting_position_address_low ; start_level &1fa5 20 c8 21 JSR &21c8 ; initialise_level &1fa8 20 6b 21 JSR &216b ; materialise_player &1fab 20 4e 20 JSR &204e ; plot_player_standing_still &1fae a9 00 LDA #&00 &1fb0 85 1d STA &1d ; fall_distance ; main_game_loop &1fb2 a2 c8 LDX #&c8 ; P &1fb4 20 93 20 JSR &2093 ; check_for_keypress &1fb7 d0 06 BNE &1fbf ; p_not_pressed &1fb9 20 cc 1e JSR &1ecc ; wait_for_vsync &1fbc 20 c0 21 JSR &21c0 ; wait_for_0_keypress ; p_not_pressed &1fbf a5 1e LDA &1e ; player_is_climbing &1fc1 d0 2d BNE &1ff0 ; consider_player_movements_and_continue &1fc3 a9 02 LDA #&02 &1fc5 85 c0 STA &c0 ; distance_to_fall ; make_player_fall &1fc7 20 e2 26 JSR &26e2 ; check_for_platform_beneath_player &1fca f0 18 BEQ &1fe4 ; player_is_on_platform &1fcc 20 95 26 JSR &2695 ; plot_player_facing_left_or_right &1fcf 20 cf 26 JSR &26cf ; move_player_down_two_pixels_and_update_screen_address &1fd2 20 4e 20 JSR &204e ; plot_player_standing_still &1fd5 c6 c0 DEC &c0 ; distance_to_fall &1fd7 d0 ee BNE &1fc7 ; make_player_fall &1fd9 e6 1d INC &1d ; fall_distance &1fdb a5 19 LDA &19 ; player_y &1fdd c9 15 CMP #&15 &1fdf b0 1c BCS &1ffd ; continue_after_moving_player &1fe1 4c 1b 21 JMP &211b ; move_down_out_of_level ; player_is_on_platform &1fe4 a5 1d LDA &1d ; fall_distance &1fe6 f0 08 BEQ &1ff0 ; consider_player_movements_and_continue # Did the player fall? &1fe8 a9 30 LDA #&30 ; sound_6 &1fea 20 10 31 JSR &3110 ; play_sound # If so, play sound for player landing &1fed 4c 62 20 JMP &2062 ; check_for_death_by_falling ; consider_player_movements_and_continue &1ff0 a5 1c LDA &1c ; player_direction_and_velocity &1ff2 29 bf AND #&bf &1ff4 85 1c STA &1c ; player_direction_and_velocity &1ff6 a9 00 LDA #&00 &1ff8 85 01 STA &01 ; left_or_right &1ffa 20 9d 20 JSR &209d ; consider_player_movements ; continue_after_moving_player &1ffd 20 26 2a JSR &2a26 ; update_enemies_and_projectiles # Returns top bit set if projectile has hit player &2000 30 6c BMI &206e ; unplot_and_dematerialise &2002 20 e9 2e JSR &2ee9 ; check_for_enemy_hitting_player # Returns top bit set if enemy has hit player &2005 30 67 BMI &206e ; unplot_and_dematerialise &2007 a5 1b LDA &1b ; player_head_sprite &2009 c9 1e CMP #&1e ; PLAYER_HEAD_CASTING_RIGHT &200b d0 0a BNE &2017 ; player_wasn't_casting_spell &200d 20 95 26 JSR &2695 ; plot_player_facing_left_or_right # Unplot the player casting &2010 a9 00 LDA #&00 ; PLAYER_HEAD_RIGHT &2012 85 1b STA &1b ; player_head_sprite &2014 20 4e 20 JSR &204e ; plot_player_standing_still # Replot the player standing still ; player_wasn't_casting_spell &2017 a5 ba LDA &ba ; player_level &2019 c9 0f CMP #&0f # Is the player on level 15? &201b d0 0b BNE &2028 ; game_not_completed &201d ad 0f 04 LDA &040f ; objects_level + 15 # Is the bridge by the castle present? &2020 f0 06 BEQ &2028 ; game_not_completed &2022 a5 18 LDA &18 ; player_x &2024 c9 ce CMP #&ce # Has the player crossed the bridge? &2026 f0 2d BEQ &2055 ; well_done_screen # If so, display well done screen ; game_not_completed &2028 a2 08 LDX #&08 ; check_extra_lives_loop # Automatically collect extra lives (objects &8 - &c) &202a 20 76 28 JSR &2876 ; check_if_object_X_is_at_player &202d d0 14 BNE &2043 ; consider_next_extra_life &202f 20 64 28 JSR &2864 ; plot_or_unplot_object &2032 a9 28 LDA #&28 ; sound_5 &2034 20 10 31 JSR &3110 ; play_sound &2037 ad 72 19 LDA &1972 ; lives_times_five &203a 18 CLC &203b 69 05 ADC #&05 &203d 8d 72 19 STA &1972 ; lives_times_five &2040 20 67 25 JSR &2567 ; plot_lives_and_pockets ; consider_next_extra_life &2043 e8 INX &2044 e0 0d CPX #&0d &2046 90 e2 BCC &202a ; check_extra_lives_loop &2048 4c b2 1f JMP &1fb2 ; main_game_loop ; unplot_player_and_replot_standing_still &204b 20 95 26 JSR &2695 ; plot_player_facing_left_or_right # Unplot player ; plot_player_standing_still &204e a9 06 LDA #&06 ; PLAYER_FEET_RIGHT_3 # Feet together &2050 85 1a STA &1a ; player_feet_sprite &2052 4c 95 26 JMP &2695 ; plot_player_facing_left_or_right # Replot player ; well_done_screen &2055 a2 07 LDX #&07 ; &07cd = well_done_text &2057 a0 cd LDY #&cd &2059 20 a9 30 JSR &30a9 ; plot_screen_of_text &205c 20 62 01 JSR &0162 ; play_tune &205f 4c 4f 1f JMP &1f4f ; start_screen ; check_for_death_by_falling &2062 a5 1d LDA &1d ; fall_distance &2064 a2 00 LDX #&00 &2066 86 1d STX &1d ; fall_distance &2068 c9 0c CMP #&0c &206a b0 02 BCS &206e ; unplot_and_dematerialise &206c 90 82 BCC &1ff0 ; consider_player_movements_and_continue ; unplot_and_dematerialise &206e a5 1e LDA &1e ; player_is_climbing &2070 f0 0a BEQ &207c ; unplot_player_and_dematerialise &2072 a9 00 LDA #&00 &2074 85 1e STA &1e ; player_is_climbing &2076 20 95 25 JSR &2595 ; plot_player_climbing &2079 4c 7f 20 JMP &207f ; dematerialise_player_without_unplot ; unplot_player_and_dematerialise &207c 20 95 26 JSR &2695 ; plot_player_facing_left_or_right ; dematerialise_player_without_unplot &207f 20 6b 21 JSR &216b ; materialise_player &2082 ad 72 19 LDA &1972 ; lives_times_five &2085 38 SEC &2086 e9 05 SBC #&05 # Lose a life &2088 10 03 BPL &208d ; continue_game &208a 4c 32 1f JMP &1f32 ; game_over_screen ; continue_game &208d 8d 72 19 STA &1972 ; lives_times_five &2090 4c a5 1f JMP &1fa5 ; start_level ; check_for_keypress &2093 a0 ff LDY #&ff &2095 a9 81 LDA #&81 ; Scan for a particular key &2097 20 f4 ff JSR &fff4 ; OSBYTE &209a e0 ff CPX #&ff # Leave with equal set if key pressed &209c 60 RTS ; consider_player_movements &209d a5 1e LDA &1e ; player_is_climbing &209f d0 57 BNE &20f8 ; consider_player_vertical_movements # Can't move left or right if player climbing &20a1 a2 86 LDX #&86 ; RIGHT &20a3 20 93 20 JSR &2093 ; check_for_keypress &20a6 d0 02 BNE &20aa ; not_right &20a8 e6 01 INC &01 ; left_or_right # Pressing both left and right cancels out ; not_right &20aa a2 e6 LDX #&e6 ; LEFT &20ac 20 93 20 JSR &2093 ; check_for_keypress &20af d0 04 BNE &20b5 ; not_left &20b1 e6 01 INC &01 ; left_or_right &20b3 e6 01 INC &01 ; left_or_right ; not_left &20b5 a6 01 LDX &01 ; left_or_right &20b7 e0 01 CPX #&01 &20b9 d0 06 BNE &20c1 ; not_moving_right &20bb 20 2d 25 JSR &252d ; turn_and_consider_moving_player_right &20be 4c c8 20 JMP &20c8 ; moving_left_or_right ; not_moving_right &20c1 e0 02 CPX #&02 &20c3 d0 0b BNE &20d0 ; not_moving_left &20c5 20 6d 25 JSR &256d ; turn_and_consider_moving_player_left ; moving_left_or_right &20c8 a5 1c LDA &1c ; player_direction_and_velocity &20ca 49 40 EOR #&40 # Set &40 to indicate moving if player then jumps &20cc 85 1c STA &1c ; player_direction_and_velocity &20ce 85 02 STA &02 ; copy_of_player_direction_and_velocity ; not_moving_left &20d0 a2 a6 LDX #&a6 ; DELETE &20d2 20 93 20 JSR &2093 ; check_for_keypress &20d5 d0 0e BNE &20e5 ; delete_not_pressed &20d7 a5 03 LDA &03 ; delete_previously_pressed # DELETE has to pressed each time, not held down &20d9 d0 0e BNE &20e9 ; skip_picking_up &20db a9 01 LDA #&01 &20dd 85 03 STA &03 ; delete_previously_pressed &20df 20 1c 28 JSR &281c ; shuffle_pockets &20e2 4c e9 20 JMP &20e9 ; skip_picking_up ; delete_not_pressed &20e5 a9 00 LDA #&00 &20e7 85 03 STA &03 ; delete_previously_pressed ; skip_picking_up &20e9 a5 02 LDA &02 ; copy_of_player_direction_and_velocity &20eb f0 0b BEQ &20f8 ; consider_player_vertical_movements # Is the player already standing still? &20ed a5 1c LDA &1c ; player_direction_and_velocity &20ef 29 40 AND #&40 &20f1 d0 05 BNE &20f8 ; consider_player_vertical_movements # Is the player moving? &20f3 85 02 STA &02 ; copy_of_player_direction_and_velocity &20f5 20 4b 20 JSR &204b ; unplot_player_and_replot_standing_still # Replot the player standing still ; consider_player_vertical_movements &20f8 a2 be LDX #&be ; A &20fa 20 93 20 JSR &2093 ; check_for_keypress &20fd d0 03 BNE &2102 ; a_not_pressed &20ff 4c a1 25 JMP &25a1 ; consider_moving_player_up_or_jumping ; a_not_pressed &2102 a2 9e LDX #&9e ; Z &2104 20 93 20 JSR &2093 ; check_for_keypress &2107 d0 03 BNE &210c ; z_not_pressed &2109 4c 9f 26 JMP &269f ; consider_moving_player_down ; z_not_pressed &210c a5 1e LDA &1e ; player_is_climbing &210e d0 0a BNE &211a &2110 a2 ff LDX #&ff ; SHIFT &2112 20 93 20 JSR &2093 ; check_for_keypress &2115 d0 03 BNE &211a ; shift_not_pressed &2117 20 95 2f JSR &2f95 ; cast_spell ; shift_not_pressed &211a 60 RTS ; move_down_out_of_level &211b 20 2e 21 JSR &212e ; check_for_exit # Is the player leaving the level through a exit? &211e c9 ff CMP #&ff &2120 f0 09 BEQ &212b ; not_an_exit &2122 20 c8 21 JSR &21c8 ; initialise_level &2125 20 95 26 JSR &2695 ; plot_player_facing_left_or_right &2128 4c 62 20 JMP &2062 ; check_for_death_by_falling ; not_an_exit # If not, kill them &212b 4c 6e 20 JMP &206e ; unplot_and_dematerialise ; check_for_exit &212e a2 00 LDX #&00 ; check_for_exit_loop &2130 8a TXA &2131 a8 TAY &2132 b1 b6 LDA (&b6),Y ; level_exit_list_address # &ff marks end of list &2134 c9 ff CMP #&ff &2136 f0 29 BEQ &2161 ; leave &2138 a5 18 LDA &18 ; player_x &213a d1 b6 CMP (&b6),Y ; level_exit_list_address # First byte of exit data is exit start x &213c 90 28 BCC &2166 ; consider_next_exit &213e c8 INY &213f d1 b6 CMP (&b6),Y ; level_exit_list_address # Second byte of exit data is exit end x &2141 b0 23 BCS &2166 ; consider_next_exit &2143 c8 INY &2144 a5 19 LDA &19 ; player_y &2146 30 1a BMI &2162 ; player_is_at_top_of_level ; player_is_at_bottom_of_level &2148 b1 b6 LDA (&b6),Y ; level_exit_list_address # Third byte of exit data is exit y and number &214a 30 1a BMI &2166 ; consider_next_exit # Top bit set for ceiling exit, clear for bottom exit ; use_this_exit &214c 29 7f AND #&7f # Bottom seven bits are exit number &214e aa TAX &214f a9 06 LDA #&06 ; &067e = starting_positions_table &2151 85 b5 STA &b5 ; starting_position_address_high &2153 a9 7e LDA #&7e ; calculate_starting_position_address_loop &2155 18 CLC &2156 69 04 ADC #&04 &2158 90 02 BCC &215c ; skip_page &215a e6 b5 INC &b5 ; starting_position_address_high ; skip_page &215c ca DEX &215d d0 f6 BNE &2155 ; calculate_starting_position_address_loop &215f 85 b4 STA &b4 ; starting_position_address_low ; leave &2161 60 RTS ; player_is_at_top_of_level &2162 b1 b6 LDA (&b6),Y ; level_exit_list_address &2164 30 e6 BMI &214c ; use_this_exit ; consider_next_exit &2166 e8 INX &2167 e8 INX &2168 e8 INX &2169 d0 c5 BNE &2130 ; check_for_exit_loop # Always branches ; materialise_player &216b 20 09 31 JSR &3109 ; play_materialisation_sound &216e a9 13 LDA #&13 ; MATERIALISATION &2170 85 00 STA &00 ; player_materialisation ; materialise_player_loop &2172 20 95 21 JSR &2195 ; plot_player_materialisation &2175 20 26 2a JSR &2a26 ; update_enemies_and_projectiles &2178 20 26 2a JSR &2a26 ; update_enemies_and_projectiles &217b 20 95 21 JSR &2195 ; plot_player_materialisation &217e a6 00 LDX &00 ; player_materialisation &2180 30 0b BMI &218d ; materialisation_is_shrinking &2182 e8 INX &2183 e0 16 CPX #&16 ; MATERIALISATION_4 &2185 d0 02 BNE &2189 ; materialisation_isn't_full &2187 a2 96 LDX #&96 ; MATERIALISATION_4 | &80 ; materialisation_isn't_full &2189 86 00 STX &00 ; player_materialisation &218b d0 e5 BNE &2172 ; materialise_player_loop ; materialisation_is_shrinking &218d ca DEX &218e 86 00 STX &00 ; player_materialisation &2190 e0 92 CPX #&92 ; MATERIALISATION - 1 | &80 &2192 d0 de BNE &2172 ; materialise_player_loop &2194 60 RTS ; plot_player_materialisation &2195 a5 12 LDA &12 ; player_screen_address_high &2197 85 c0 STA &c0 ; screen_address_high &2199 a5 13 LDA &13 ; player_screen_address_low &219b 85 c1 STA &c1 ; screen_address_low &219d a5 00 LDA &00 ; player_materialisation ; plot_materialisation &219f 29 3f AND #&3f &21a1 85 c2 STA &c2 ; sprite &21a3 a6 c0 LDX &c0 ; screen_address_low &21a5 a4 c1 LDY &c1 ; screen_address_high &21a7 20 85 24 JSR &2485 ; subtract_0010_from_screen_address_in_Y_X # Move four pixels left &21aa 98 TYA &21ab a4 c2 LDY &c2 ; sprite &21ad 20 6d 23 JSR &236d ; plot_other_sprite # Plot sprite &21b0 a6 c0 LDX &c0 ; screen_address_low &21b2 a4 c1 LDY &c1 ; screen_address_high &21b4 20 53 24 JSR &2453 ; add_0280_to_screen_address_in_Y_X # Move eight pixels down &21b7 20 85 24 JSR &2485 ; subtract_0010_from_screen_address_in_Y_X # Move four pixels left &21ba 98 TYA &21bb a4 c2 LDY &c2 ; sprite &21bd 4c 6d 23 JMP &236d ; plot_other_sprite # Plot sprite again ; wait_for_0_keypress &21c0 a2 d8 LDX #&d8 ; 0 &21c2 20 93 20 JSR &2093 ; check_for_keypress &21c5 d0 f9 BNE &21c0 ; wait_for_0_keypress &21c7 60 RTS ; initialise_level &21c8 20 05 23 JSR &2305 ; reset_screen_scroll &21cb a0 00 LDY #&00 &21cd a2 01 LDX #&01 &21cf 8e 00 fe STX &fe00 ; video register number # R1: Number of characters per line &21d2 ca DEX &21d3 8e 01 fe STX &fe01 ; video register value # Hide screen &21d6 b1 b4 LDA (&b4),Y ; starting_position_address # First byte of starting position data is player x &21d8 85 18 STA &18 ; player_x &21da c8 INY &21db b1 b4 LDA (&b4),Y ; starting_position_address # Second byte of starting position data is player y &21dd 85 19 STA &19 ; player_y &21df aa TAX &21e0 c9 b0 CMP #&b0 &21e2 d0 0a BNE &21ee ; player_enters_from_bottom_of_level ; player_enters_from_top_of_level &21e4 a9 af LDA #&af &21e6 85 13 STA &13 ; player_screen_address_low &21e8 a9 43 LDA #&43 &21ea 85 12 STA &12 ; player_screen_address_high &21ec d0 08 BNE &21f6 ; check_for_middle_entry # Always branches ; player_enters_from_bottom_of_level &21ee a9 2f LDA #&2f &21f0 85 13 STA &13 ; player_screen_address_low &21f2 a9 73 LDA #&73 &21f4 85 12 STA &12 ; player_screen_address_high ; check_for_middle_entry &21f6 e0 58 CPX #&58 &21f8 d0 04 BNE &21fe ; not_middle_entry ; player_starts_in_middle_of_level &21fa a9 5f LDA #&5f &21fc 85 12 STA &12 ; player_screen_address_high ; not_middle_entry &21fe c8 INY &21ff c8 INY &2200 b1 b4 LDA (&b4),Y ; starting_position_address # Fourth byte of starting position data is level &2202 85 ba STA &ba ; player_level &2204 a8 TAY &2205 b9 2e 06 LDA &062e,Y ; level_background_data_address_low_table - 1 &2208 85 b8 STA &b8 ; level_background_data_address_low &220a b9 1f 06 LDA &061f,Y ; level_background_data_address_high_table - 1 &220d 85 b9 STA &b9 ; level_background_data_address_high &220f 20 91 28 JSR &2891 ; initialise_enemies ; poke_platform_data_address_low &2212 a0 00 LDY #&00 &2214 b1 b8 LDA (&b8),Y ; level_background_data_address &2216 85 cb STA &cb ; byte_to_poke &2218 a2 00 LDX #&00 # Push first byte of level data ; poke_platform_data_address_low_loop &221a 20 f5 22 JSR &22f5 ; poke_platform_and_scenery_data_addresses # into &1a58, &1a63, &1b76, &1b81 &221d e8 INX # i.e. poke low byte of level platform data address &221e e0 08 CPX #&08 # into update_platform_addresses_for_scrolling_left &2220 d0 f8 BNE &221a ; poke_platform_data_address_low_loop # and update_platform_addresses_for_scrolling_right ; poke_platform_data_address_high &2222 c8 INY &2223 b1 b8 LDA (&b8),Y ; level_background_data_address &2225 85 cb STA &cb ; byte_to_poke &2227 a2 00 LDX #&00 # Push second byte of level data ; poke_platform_data_address_high_loop &2229 20 f5 22 JSR &22f5 ; poke_platform_and_scenery_data_addresses # into &1a59, &1a64, &1b77, &1b82 &222c e8 INX # i.e. poke high byte of level platform data address &222d e0 08 CPX #&08 # into update_platform_addresses_for_scrolling_left &222f d0 f8 BNE &2229 ; poke_platform_data_address_high_loop # and update_platform_addresses_for_scrolling_right ; poke_scenery_data_address_low &2231 c8 INY &2232 b1 b8 LDA (&b8),Y ; level_background_data_address &2234 85 cb STA &cb ; byte_to_poke &2236 a0 00 LDY #&00 &2238 a2 08 LDX #&08 # Push third byte of level data ; poke_scenery_data_address_low_loop &223a 20 f5 22 JSR &22f5 ; poke_platform_and_scenery_data_addresses # into &1aa9, &1ab2, &1ba3, &1bad &223d e8 INX # i.e. poke low byte of level scenery data address &223e e0 10 CPX #&10 # into update_scenery_addresses_for_scrolling_left &2240 d0 f8 BNE &223a ; poke_scenery_data_address_low_loop # and update_scenery_addresses_for_scrolling_right ; poke_scenery_data_address_high &2242 a0 03 LDY #&03 &2244 b1 b8 LDA (&b8),Y ; level_background_data_address &2246 85 cb STA &cb ; byte_to_poke &2248 a0 01 LDY #&01 &224a a2 08 LDX #&08 # Push fourth byte of level data ; poke_scenery_data_address_high_loop &224c 20 f5 22 JSR &22f5 ; poke_platform_and_scenery_data_addresses # into &1aaa, &1ab3, &1ba4, &1bae &224f e8 INX # i.e. poke high byte of level scenery data address &2250 e0 10 CPX #&10 # into update_scenery_addresses_for_scrolling_left &2252 d0 f8 BNE &224c ; poke_scenery_data_address_high_loop # and update_scenery_addresses_for_scrolling_right ; wipe_variables &2254 a2 00 LDX #&00 &2256 a9 00 LDA #&00 ; wipe_variables_loop &2258 9d 00 19 STA &1900,X # Wipe &1900 - &1939 &225b e8 INX # i.e. platform and scenery variables &225c e0 3a CPX #&3a # Bug: should be &3b &225e d0 f8 BNE &2258 ; wipe_variables_loop &2260 a9 19 LDA #&19 ; &1908 = platform_data_offsets_right - 4 &2262 85 c9 STA &c9 ; platform_offsets_address_high &2264 a9 08 LDA #&08 &2266 85 c8 STA &c8 ; platform_offsets_address_low &2268 a9 19 LDA #&19 ; &191e = scenery_data_offsets_right - 8 &226a 85 c7 STA &c7 ; scenery_offsets_address_high &226c a9 1e LDA #&1e &226e 85 c6 STA &c6 ; scenery_offsets_address_low &2270 20 e0 22 JSR &22e0 ; copy_platform_and_scenery_data_offsets # Initialise right platform and scenery data offsets &2273 a9 01 LDA #&01 # Don't plot player or wait for v-sync when scrolling &2275 8d 3b 19 STA &193b ; scrolling_on_entry_to_level &2278 a9 50 LDA #&50 &227a 85 02 STA &02 ; amount_to_scroll # Scroll 160 pixels into level from left side ; scroll_loop &227c 20 21 1f JSR &1f21 ; scroll_right_and_update_player_and_enemy_addresses &227f c6 02 DEC &02 ; amount_to_scroll &2281 d0 f9 BNE &227c ; scroll_loop &2283 a9 19 LDA #&19 &2285 85 c9 STA &c9 ; platform_offsets_address_high &2287 85 c7 STA &c7 ; scenery_offsets_address_high &2289 a9 18 LDA #&18 ; &1918 = platform_data_offsets_left - 4 &228b 85 c8 STA &c8 ; platform_offsets_address_low &228d a9 2a LDA #&2a ; &192a = scenery_data_offsets_left - 8 &228f 85 c6 STA &c6 ; scenery_offsets_address_low &2291 a0 0b LDY #&0b &2293 b1 b8 LDA (&b8),Y ; level_background_data_address # One byte for colour of grass &2295 8d 21 fe STA &fe21 ; video ULA palette register # Write to video ULA palette register &2298 c8 INY &2299 b1 b8 LDA (&b8),Y ; level_background_data_address # One byte for colour of cliffs &229b 8d 21 fe STA &fe21 ; video ULA palette register # Write to video ULA palette register &229e c8 INY &229f b1 b8 LDA (&b8),Y ; level_background_data_address &22a1 85 b6 STA &b6 ; level_exit_list_address_low &22a3 c8 INY &22a4 b1 b8 LDA (&b8),Y ; level_background_data_address &22a6 85 b7 STA &b7 ; level_exit_list_address_high &22a8 20 e0 22 JSR &22e0 ; copy_platform_and_scenery_data_offsets # Initialise left platform and scenery data offsets &22ab a0 02 LDY #&02 &22ad b1 b4 LDA (&b4),Y ; starting_position_address # Third byte of starting position data determines scroll &22af f0 1a BEQ &22cb ; no_scrolling_needed &22b1 29 fe AND #&fe &22b3 85 02 STA &02 ; amount_to_scroll # Top seven bits are amount to scroll &22b5 b1 b4 LDA (&b4),Y ; starting_position_address &22b7 29 01 AND #&01 # Bottom bit is direction to scroll from &22b9 f0 09 BEQ &22c4 ; scroll_into_level_from_left # (0 left, 1 right) ; scroll_into_level_from_right &22bb 20 10 1f JSR &1f10 ; scroll_left_and_update_player_and_enemy_addresses &22be c6 02 DEC &02 ; amount_to_scroll &22c0 d0 f9 BNE &22bb ; scroll_into_level_from_right &22c2 f0 07 BEQ &22cb ; no_scrolling_needed ; scroll_into_level_from_left &22c4 20 21 1f JSR &1f21 ; scroll_right_and_update_player_and_enemy_addresses &22c7 c6 02 DEC &02 ; amount_to_scroll &22c9 d0 f9 BNE &22c4 ; scroll_into_level_from_left ; no_scrolling_needed &22cb a9 00 LDA #&00 # Plot player and wait for v-sync when scrolling &22cd 8d 3b 19 STA &193b ; scrolling_on_entry_to_level &22d0 20 cc 1e JSR &1ecc ; wait_for_vsync &22d3 a9 01 LDA #&01 # R1: Number of characters per line &22d5 8d 00 fe STA &fe00 ; video register number &22d8 a9 50 LDA #&50 # Restore screen &22da 8d 01 fe STA &fe01 ; video register value &22dd 4c 67 25 JMP &2567 ; plot_lives_and_pockets ; copy_platform_and_scenery_data_offsets &22e0 a0 04 LDY #&04 ; copy_platform_offsets_loop &22e2 b1 b8 LDA (&b8),Y ; level_background_data_address &22e4 91 c8 STA (&c8),Y ; platform_offsets_address &22e6 c8 INY &22e7 c0 08 CPY #&08 &22e9 d0 f7 BNE &22e2 ; copy_platform_offsets_loop ; copy_scenery_offsets_loop &22eb b1 b8 LDA (&b8),Y ; level_background_data_address &22ed 91 c6 STA (&c6),Y ; scenery_offsets_address &22ef c8 INY &22f0 c0 0b CPY #&0b &22f2 d0 f7 BNE &22eb ; copy_scenery_offsets_loop &22f4 60 RTS ; poke_platform_and_scenery_data_addresses &22f5 bd 4c 19 LDA &194c,X ; level_data_address_addresses_table &22f8 85 ce STA &ce ; address_address_low &22fa e8 INX &22fb bd 4c 19 LDA &194c,X ; level_data_address_addresses_table &22fe 85 cf STA &cf ; address_address_high &2300 a5 cb LDA &cb ; byte_to_poke &2302 91 ce STA (&ce),Y ; address_address &2304 60 RTS ; reset_screen_scroll &2305 a9 0d LDA #&0d # R13: Displayed screen start address register (low) &2307 8d 00 fe STA &fe00 ; video register number &230a a9 00 LDA #&00 &230c 85 b1 STA &b1 ; crtc_start_address_low &230e 85 b3 STA &b3 ; screen_right_x &2310 8d 01 fe STA &fe01 ; video register value &2313 a9 0c LDA #&0c # R12: Displayed screen start address register (high) &2315 8d 00 fe STA &fe00 ; video register number &2318 a9 08 LDA #&08 # Set screen scroll position to &4000 &231a 85 b0 STA &b0 ; crtc_start_address_high &231c 8d 01 fe STA &fe01 ; video register value &231f a9 b0 LDA #&b0 &2321 85 b2 STA &b2 ; screen_left_x ; initialise_scrolled_screen_addresses &2323 a2 0d LDX #&0d ; initialise_scrolled_screen_addresses_loop &2325 bd 5c 19 LDA &195c,X ; initial_scrolled_screen_addresses &2328 95 04 STA &04,X ; scrolled_screen_addresses &232a ca DEX &232b 10 f8 BPL &2325 ; initialise_scrolled_screen_addresses_loop &232d 60 RTS ; plot_next_column_of_sprite &232e 84 cd STY &cd ; sprite_data_offset &2330 a4 ce LDY &ce ; screen_address_low &2332 a6 cf LDX &cf ; screen_address_high &2334 20 49 24 JSR &2449 ; add_0008_to_screen_address_in_Y_X # Move two pixels right &2337 84 ce STY &ce ; screen_address_low &2339 86 cf STX &cf ; screen_address_high &233b 86 72 STX &72 ; column_screen_address_high &233d 84 71 STY &71 ; column_screen_address_low &233f a6 1f LDX &1f ; column_x # &00 if sprite is being plotted without cropping &2341 f0 15 BEQ &2358 ; next_column &2343 e8 INX # Is the next column off the right of the screen? &2344 e4 b3 CPX &b3 ; screen_right_x &2346 d0 10 BNE &2358 ; next_column &2348 a9 80 LDA #&80 &234a 85 35 STA &35 ; sprite_column_address_high # &80 to indicate sprite was cropped to right &234c a5 51 LDA &51 ; sprite_address_low &234e 18 CLC &234f 65 cd ADC &cd ; sprite_data_offset &2351 85 51 STA &51 ; sprite_address_low &2353 90 02 BCC &2357 ; leave &2355 e6 52 INC &52 ; sprite_address_high ; leave &2357 60 RTS ; next_column &2358 86 1f STX &1f ; column_x &235a a4 cd LDY &cd ; sprite_data_offset &235c c8 INY &235d 4c 50 00 JMP &0050 ; plot_column_of_sprite # Returns to &232e ; plot_next_column_of_sprite ; set_screen_addresses_and_eor_plotting_mode &2360 86 72 STX &72 ; column_screen_address_high &2362 85 71 STA &71 ; column_screen_address_low &2364 86 cf STX &cf ; other_screen_address_high &2366 85 ce STA &ce ; other_screen_address_low &2368 a9 49 LDA #&49 ; EOR &236a 85 6e STA &6e ; plotting_mode &236c 60 RTS ; plot_other_sprite &236d 20 60 23 JSR &2360 ; set_screen_addresses_and_eor_plotting_mode ; plot_other_sprite_without_setting_screen_addresses &2370 b9 3e 06 LDA &063e,Y ; other_sprites_address_high_table &2373 85 52 STA &52 ; sprite_address_high &2375 b9 5e 06 LDA &065e,Y ; other_sprites_address_high_low &2378 85 51 STA &51 ; sprite_address_low ; plot_sprite &237a a0 00 LDY #&00 # Don't crop sprite &237c 84 1f STY &1f ; column_x &237e 4c 50 00 JMP &0050 ; plot_column_of_sprite # Returns at &232e ; plot_next_column_of_sprite ; use_scenery_sprite &2381 be c9 05 LDX &05c9,Y ; scenery_sprites_first_column_address_high_table - 1 &2384 b9 97 05 LDA &0597,Y ; scenery_sprites_first_column_address_low_table - 1 &2387 a8 TAY # Put address of scenery sprite in Y,X &2388 c8 INY # adding a byte to move past the &ff start marker &2389 d0 01 BNE &238c ; not_page &238b e8 INX ; not_page &238c 84 51 STY &51 ; sprite_address_low &238e 84 34 STY &34 ; sprite_column_address_low &2390 86 52 STX &52 ; sprite_address_high &2392 86 35 STX &35 ; sprite_column_address_high &2394 60 RTS ; plot_scenery_sprite_with_eor &2395 20 60 23 JSR &2360 ; set_screen_addresses_and_eor_plotting_mode &2398 20 81 23 JSR &2381 ; use_scenery_sprite &239b d0 dd BNE &237a ; plot_sprite # Always branches ; plot_scenery_sprite_with_write &239d 20 60 23 JSR &2360 ; set_screen_addresses_and_eor_plotting_mode &23a0 a9 a9 LDA #&a9 ; LDA # Write, not EOR, sprite to screen &23a2 85 6e STA &6e ; plotting_mode &23a4 c0 0b CPY #&0b &23a6 f0 c8 BEQ &2370 ; plot_other_sprite_without_setting_screen_addresses &23a8 20 81 23 JSR &2381 ; use_scenery_sprite &23ab d0 cd BNE &237a ; plot_sprite # Always branches ; plot_sprite_with_cropping &23ad 20 60 23 JSR &2360 ; set_screen_addresses_and_eor_plotting_mode &23b0 20 81 23 JSR &2381 ; use_scenery_sprite &23b3 a0 ff LDY #&ff &23b5 a6 1f LDX &1f ; column_x &23b7 ca DEX &23b8 ad 20 19 LDA &1920 ; edges_of_level_visible &23bb c9 01 CMP #&01 # &01 if right edge of level visible &23bd f0 09 BEQ &23c8 ; right_edge_of_level_on_screen &23bf e4 b3 CPX &b3 ; screen_right_x &23c1 b0 27 BCS &23ea ; leave_after_setting_sprite_column_address_high &23c3 ad 20 19 LDA &1920 ; edges_of_level_visible # &80 if left edge of level visible &23c6 30 2b BMI &23f3 ; column_is_on_screen # If so, start of sprite must be visible ; right_edge_of_level_on_screen &23c8 e4 b2 CPX &b2 ; screen_left_x # Is the start of the sprite on screen? &23ca b0 27 BCS &23f3 ; column_is_on_screen ; find_start_of_next_rle_column # If not, skip columns that aren't on screen &23cc c8 INY &23cd b1 51 LDA (&51),Y ; sprite_address &23cf 29 40 AND #&40 # &40 set at end of column &23d1 f0 f9 BEQ &23cc ; find_start_of_next_rle_column &23d3 a5 ce LDA &ce ; screen_address_low &23d5 18 CLC &23d6 69 08 ADC #&08 &23d8 85 ce STA &ce ; screen_address_low &23da 90 08 BCC &23e4 ; skip_page &23dc e6 cf INC &cf ; screen_address_high &23de 10 04 BPL &23e4 ; skip_wraparound &23e0 a9 40 LDA #&40 &23e2 85 cf STA &cf ; screen_address_high ; skip_page ; skip_wraparound &23e4 b1 51 LDA (&51),Y ; sprite_address &23e6 10 06 BPL &23ee ; plot_next_column # &80 set at end of sprite &23e8 a0 ff LDY #&ff # Sprite completely unplotted ; leave_after_setting_sprite_column_address_high &23ea c8 INY &23eb 84 35 STY &35 ; sprite_column_address_high # &00 if sprite wasn't cropped to the left &23ed 60 RTS ; plot_next_column &23ee e8 INX &23ef e4 b2 CPX &b2 ; screen_left_x &23f1 90 d9 BCC &23cc ; find_start_of_next_rle_column # Don't plot column if left of left of screen ; column_is_on_screen &23f3 98 TYA &23f4 18 CLC &23f5 65 34 ADC &34 ; sprite_column_address_low &23f7 85 34 STA &34 ; sprite_column_address_low &23f9 90 02 BCC &23fd ; skip_page &23fb e6 35 INC &35 ; sprite_column_address_high ; skip_page &23fd c8 INY &23fe d0 02 BNE &2402 ; skip_mark_as_uncropped &2400 84 35 STY &35 ; sprite_column_address_high ; skip_mark_as_uncropped &2402 a5 ce LDA &ce ; screen_address_low &2404 85 71 STA &71 ; column_screen_address_low &2406 a5 cf LDA &cf ; screen_address_high &2408 85 72 STA &72 ; column_screen_address_high &240a 86 1f STX &1f ; column_x &240c e8 INX &240d 4c 50 00 JMP &0050 ; plot_column_of_sprite # Plot column of sprite, returns to &232e ; move_player_down_two_pixels &2410 c6 19 DEC &19 ; player_y &2412 c6 19 DEC &19 ; player_y &2414 98 TYA &2415 29 07 AND #&07 &2417 c9 06 CMP #&06 &2419 90 0c BCC &2427 ; not_group_down_two &241b e8 INX &241c e8 INX &241d 98 TYA &241e 18 CLC &241f 69 7a ADC #&7a &2421 a8 TAY &2422 90 39 BCC &245d ; wrap_at_end_of_screen_memory &2424 e8 INX &2425 d0 36 BNE &245d ; wrap_at_end_of_screen_memory ; not_group_down_two &2427 c8 INY &2428 c8 INY &2429 60 RTS ; move_player_down_four_pixels &242a a5 19 LDA &19 ; player_y &242c 38 SEC &242d e9 04 SBC #&04 &242f 85 19 STA &19 ; player_y ; move_screen_address_in_Y_X_down_four_pixels &2431 98 TYA &2432 29 07 AND #&07 &2434 c9 05 CMP #&05 &2436 90 0c BCC &2444 ; not_group_down_four &2438 e8 INX &2439 e8 INX &243a 98 TYA &243b 18 CLC &243c 69 7c ADC #&7c &243e a8 TAY &243f 90 1c BCC &245d ; wrap_at_end_of_screen_memory &2441 e8 INX &2442 d0 19 BNE &245d ; wrap_at_end_of_screen_memory ; not_group_down_four &2444 98 TYA &2445 69 04 ADC #&04 &2447 a8 TAY &2448 60 RTS ; add_0008_to_screen_address_in_Y_X &2449 98 TYA &244a 18 CLC &244b 69 08 ADC #&08 &244d a8 TAY &244e 90 0d BCC &245d ; wrap_at_end_of_screen_memory &2450 e8 INX &2451 d0 0a BNE &245d ; wrap_at_end_of_screen_memory ; add_0280_to_screen_address_in_Y_X &2453 e8 INX &2454 e8 INX &2455 98 TYA &2456 18 CLC &2457 69 80 ADC #&80 &2459 a8 TAY &245a 90 01 BCC &245d ; wrap_at_end_of_screen_memory &245c e8 INX ; wrap_at_end_of_screen_memory &245d 8a TXA &245e 10 04 BPL &2464 ; leave &2460 38 SEC &2461 e9 40 SBC #&40 &2463 aa TAX ; leave &2464 60 RTS ; add_0279_to_screen_address_in_Y_X &2465 e8 INX &2466 e8 INX &2467 98 TYA &2468 18 CLC &2469 69 79 ADC #&79 &246b a8 TAY &246c 90 ef BCC &245d ; wrap_at_end_of_screen_memory &246e e8 INX &246f d0 ec BNE &245d ; wrap_at_end_of_screen_memory ; add_0020_to_screen_address_in_Y_X &2471 98 TYA &2472 18 CLC &2473 69 20 ADC #&20 &2475 a8 TAY &2476 90 e5 BCC &245d ; wrap_at_end_of_screen_memory &2478 e8 INX &2479 d0 e2 BNE &245d ; wrap_at_end_of_screen_memory ; subtract_0008_from_screen_address_in_Y_X &247b 98 TYA &247c 38 SEC &247d e9 08 SBC #&08 &247f a8 TAY &2480 b0 2e BCS &24b0 ; wrap_at_start_of_screen_memory &2482 ca DEX &2483 d0 2b BNE &24b0 ; wrap_at_start_of_screen_memory ; subtract_0010_from_screen_address_in_Y_X &2485 98 TYA &2486 38 SEC &2487 e9 10 SBC #&10 &2489 a8 TAY &248a b0 24 BCS &24b0 ; wrap_at_start_of_screen_memory &248c ca DEX &248d d0 21 BNE &24b0 ; wrap_at_start_of_screen_memory ; subtract_0280_from_screen_address_in_Y_X &248f ca DEX &2490 ca DEX &2491 98 TYA &2492 38 SEC &2493 e9 80 SBC #&80 &2495 a8 TAY &2496 b0 18 BCS &24b0 ; wrap_at_start_of_screen_memory &2498 ca DEX &2499 d0 15 BNE &24b0 ; wrap_at_start_of_screen_memory ; move_player_up_two_pixels &249b e6 19 INC &19 ; player_y &249d e6 19 INC &19 ; player_y &249f 98 TYA &24a0 29 07 AND #&07 &24a2 c9 02 CMP #&02 &24a4 b0 32 BCS &24d8 ; not_group_up_two &24a6 ca DEX &24a7 ca DEX &24a8 98 TYA &24a9 38 SEC &24aa e9 7a SBC #&7a &24ac a8 TAY &24ad b0 01 BCS &24b0 ; wrap_at_start_of_screen_memory &24af ca DEX ; wrap_at_start_of_screen_memory &24b0 e0 40 CPX #&40 &24b2 b0 04 BCS &24b8 ; leave &24b4 8a TXA &24b5 69 40 ADC #&40 &24b7 aa TAX ; leave &24b8 60 RTS ; move_player_up_four_pxiels &24b9 a5 19 LDA &19 ; player_y &24bb 18 CLC &24bc 69 04 ADC #&04 &24be 85 19 STA &19 ; player_y &24c0 98 TYA &24c1 29 07 AND #&07 &24c3 c9 04 CMP #&04 &24c5 b0 0c BCS &24d3 ; not_group_up_four &24c7 ca DEX &24c8 ca DEX &24c9 98 TYA &24ca 38 SEC &24cb e9 7c SBC #&7c &24cd a8 TAY &24ce b0 e0 BCS &24b0 ; wrap_at_start_of_screen_memory &24d0 ca DEX &24d1 d0 dd BNE &24b0 ; wrap_at_start_of_screen_memory ; not_group_up_four &24d3 98 TYA &24d4 e9 04 SBC #&04 &24d6 a8 TAY &24d7 60 RTS ; not_group_up_two &24d8 88 DEY &24d9 88 DEY &24da 60 RTS ; plot_player_facing_right &24db 20 ed 24 JSR &24ed ; add_width_of_players_feet_to_screen_address_and_put_in_Y_X &24de 98 TYA &24df a4 1a LDY &1a ; player_feet_sprite &24e1 20 6d 23 JSR &236d ; plot_other_sprite # Plot the player's feet &24e4 a6 12 LDX &12 ; player_screen_address_high &24e6 a5 13 LDA &13 ; player_screen_address_low &24e8 a4 1b LDY &1b ; player_head_sprite &24ea 4c 6d 23 JMP &236d ; plot_other_sprite # Plot the player's head ; add_width_of_players_feet_to_screen_address_and_put_in_Y_X &24ed 20 fa 24 JSR &24fa ; add_0280_to_player_screen_address_into_Y_X # Move eight pixels down &24f0 a5 1a LDA &1a ; player_feet_sprite &24f2 c9 06 CMP #&06 ; PLAYER_FEET_RIGHT_3 &24f4 f0 03 BEQ &24f9 ; leave &24f6 20 7b 24 JSR &247b ; subtract_0008_from_screen_address_in_Y_X # Move two pixels left ; leave &24f9 60 RTS ; add_0280_to_player_screen_address_into_Y_X &24fa a6 12 LDX &12 ; player_screen_address_high &24fc a4 13 LDY &13 ; player_screen_address_low &24fe 4c 53 24 JMP &2453 ; add_0280_to_screen_address_in_Y_X ; plot_player_facing_left &2501 20 20 25 JSR &2520 ; subtract_fraction_of_players_feet_from_screen_address_and_put_in_Y_X &2504 98 TYA &2505 a4 1a LDY &1a ; player_feet_sprite &2507 c8 INY # Add 3 (PLAYER_FEET_LEFT - PLAYER_FEET_RIGHT) &2508 c8 INY &2509 c8 INY &250a 20 6d 23 JSR &236d ; plot_other_sprite # Plot the player's feet &250d a6 12 LDX &12 ; player_screen_address_high &250f a4 13 LDY &13 ; player_screen_address_low &2511 20 7b 24 JSR &247b ; subtract_0008_from_screen_address_in_Y_X # Move two pixels left &2514 98 TYA &2515 a4 1b LDY &1b ; player_head_sprite &2517 c0 1e CPY #&1e ; PLAYER_HEAD_CASTING_RIGHT &2519 f0 01 BEQ &251c ; player_is_casting &251b c8 INY # Add 2 (PLAYER_HEAD_LEFT - PLAYER_HEAD_RIGHT) ; player_is_casting # or 1 &251c c8 INY # (PLAYER_HEAD_CASTING_LEFT - PLAYER_HEAD_CASTING_RIGHT) &251d 4c 6d 23 JMP &236d ; plot_other_sprite ; subtract_fraction_of_players_feet_from_screen_address_and_put_in_Y_X &2520 20 fa 24 JSR &24fa ; add_0280_to_player_screen_address_into_Y_X # Move eight pixels down &2523 a5 1a LDA &1a ; player_feet_sprite &2525 c9 04 CMP #&04 ; PLAYER_FEET_RIGHT &2527 d0 03 BNE &252c ; leave &2529 20 7b 24 JSR &247b ; subtract_0008_from_screen_address_in_Y_X # Move two pixels left ; leave &252c 60 RTS ; turn_and_consider_moving_player_right &252d a5 1c LDA &1c ; player_direction_and_velocity &252f 10 0b BPL &253c ; player_already_facing_right # Is the player already facing right? &2531 49 80 EOR #&80 # If not, set &80 to make the player face right &2533 85 1c STA &1c ; player_direction_and_velocity &2535 20 01 25 JSR &2501 ; plot_player_facing_left # Unplot &2538 20 db 24 JSR &24db ; plot_player_facing_right # and replot player &253b 60 RTS ; player_already_facing_right &253c 20 4a 25 JSR &254a ; scroll_right_if_no_obstacles # Is there an obstacle to the right? &253f f0 13 BEQ &2554 ; leave # If so, leave &2541 20 55 25 JSR &2555 ; animate_player_walking &2544 20 db 24 JSR &24db ; plot_player_facing_right &2547 4c 67 25 JMP &2567 ; plot_lives_and_pockets ; scroll_right_if_no_obstacles &254a 20 40 27 JSR &2740 ; check_for_obstacles_before_moving_right &254d f0 05 BEQ &2554 ; leave &254f 20 21 1f JSR &1f21 ; scroll_right_and_update_player_and_enemy_addresses &2552 e6 18 INC &18 ; player_x ; leave &2554 60 RTS ; animate_player_walking &2555 a4 1a LDY &1a ; player_feet_sprite # Animate player's feet &2557 c8 INY &2558 c0 07 CPY #&07 ; PLAYER_FEET_RIGHT_3 + 1 &255a d0 08 BNE &2564 ; store_and_leave &255c a0 04 LDY #&04 ; PLAYER_FEET_RIGHT &255e a5 1b LDA &1b ; player_head_sprite # Animate player's head &2560 49 01 EOR #&01 &2562 85 1b STA &1b ; player_head_sprite ; store_and_leave &2564 84 1a STY &1a ; player_feet_sprite &2566 60 RTS ; plot_lives_and_pockets &2567 20 bc 27 JSR &27bc ; plot_pockets &256a 4c 74 30 JMP &3074 ; plot_lives ; turn_and_consider_moving_player_left &256d a5 1c LDA &1c ; player_direction_and_velocity &256f 30 0b BMI &257c ; player_already_facing_left # Is the player already facing left? &2571 49 80 EOR #&80 # If not, clear &80 to make the player face left &2573 85 1c STA &1c ; player_direction_and_velocity &2575 20 db 24 JSR &24db ; plot_player_facing_right # Unplot &2578 20 01 25 JSR &2501 ; plot_player_facing_left # and replot player &257b 60 RTS ; player_already_facing_left &257c 20 8a 25 JSR &258a ; scroll_left_if_no_obstacles # Is there an obstacle to the left? &257f f0 13 BEQ &2594 ; leave # If so, leave &2581 20 55 25 JSR &2555 ; animate_player_walking &2584 20 01 25 JSR &2501 ; plot_player_facing_left &2587 4c 67 25 JMP &2567 ; plot_lives_and_pockets ; scroll_left_if_no_obstacles &258a 20 4a 27 JSR &274a ; check_for_obstacles_before_moving_left &258d f0 05 BEQ &2594 ; leave &258f 20 10 1f JSR &1f10 ; scroll_left_and_update_player_and_enemy_addresses &2592 c6 18 DEC &18 ; player_x ; leave &2594 60 RTS ; plot_player_climbing &2595 20 fa 24 JSR &24fa ; add_0280_to_player_screen_address_into_Y_X # Move eight pixels down &2598 20 7b 24 JSR &247b ; subtract_0008_from_screen_address_in_Y_X # Move two pixels left &259b 98 TYA &259c a4 1a LDY &1a ; player_feet_sprite &259e 4c 6d 23 JMP &236d ; plot_other_sprite ; consider_moving_player_up_or_jumping &25a1 a5 1e LDA &1e ; player_is_climbing &25a3 d0 1a BNE &25bf ; already_climbing # If the player isn't already climbing, &25a5 20 95 26 JSR &2695 ; plot_player_facing_left_or_right # Unplot player before checking for ladder &25a8 20 db 26 JSR &26db ; get_player_screen_address_subtract_0008 &25ab 86 cf STX &cf ; screen_address_high &25ad 84 ce STY &ce ; screen_address_low &25af a0 00 LDY #&00 &25b1 b1 ce LDA (&ce),Y ; screen_address &25b3 c9 01 CMP #&01 ; KR # If not bottom of ladder, &25b5 d0 2b BNE &25e2 ; start_jump # then start player jumping ; at_bottom_of_ladder &25b7 85 1e STA &1e ; player_is_climbing &25b9 a9 0c LDA #&0c ; PLAYER_CLIMBING &25bb 85 1a STA &1a ; player_feet_sprite &25bd d0 03 BNE &25c2 ; skip_unplotting_player # Always branches ; already_climbing &25bf 20 95 25 JSR &2595 ; plot_player_climbing # Unplot player ; skip_unplotting_player &25c2 a6 12 LDX &12 ; player_screen_address_high &25c4 a4 13 LDY &13 ; player_screen_address_low &25c6 20 9b 24 JSR &249b ; move_player_up_two_pixels # Move player up &25c9 86 12 STX &12 ; player_screen_address_high &25cb 84 13 STY &13 ; player_screen_address_low ; animate_climbing_player_and_check_for_platform &25cd a5 1a LDA &1a ; player_feet_sprite &25cf 49 01 EOR #&01 # Animate climbing player &25d1 85 1a STA &1a ; player_feet_sprite &25d3 20 e2 26 JSR &26e2 ; check_for_platform_beneath_player &25d6 d0 07 BNE &25df ; to_plot_player_climbing # Is the player at the top or bottom of the ladder? &25d8 a9 00 LDA #&00 # If so, set the player as finished climbing &25da 85 1e STA &1e ; player_is_climbing &25dc 4c 4e 20 JMP &204e ; plot_player_standing_still # Replot player ; to_plot_player_climbing &25df 4c 95 25 JMP &2595 ; plot_player_climbing # Replot player ; start_jump &25e2 a9 04 LDA #&04 ; PLAYER_FEET_RIGHT &25e4 85 1a STA &1a ; player_feet_sprite &25e6 20 95 26 JSR &2695 ; plot_player_facing_left_or_right # Unplot player &25e9 a9 10 LDA #&10 ; sound_2 &25eb 20 10 31 JSR &3110 ; play_sound # Play sound for jump &25ee a5 19 LDA &19 ; player_y &25f0 c9 b0 CMP #&b0 &25f2 d0 09 BNE &25fd ; not_exiting_through_top_of_level ; jumped_out_of_level &25f4 20 2e 21 JSR &212e ; check_for_exit &25f7 20 c8 21 JSR &21c8 ; initialise_level &25fa 20 95 26 JSR &2695 ; plot_player_facing_left_or_right ; not_exiting_through_top_of_level &25fd a9 00 LDA #&00 &25ff 85 02 STA &02 ; jump_timer ; jump_loop &2601 a2 02 LDX #&02 &2603 a5 1c LDA &1c ; player_direction_and_velocity &2605 29 40 AND #&40 &2607 d0 02 BNE &260b ; moving_jump &2609 a2 04 LDX #&04 ; moving_jump &260b 86 4e STX &4e ; jump_stage_one # Up at four pixels per frame &260d e8 INX &260e e8 INX &260f e8 INX &2610 86 4f STX &4f ; jump_stage_two # Up at two pixels per frame &2612 e8 INX &2613 e8 INX &2614 e8 INX &2615 86 bb STX &bb ; jump_stage_three # Down at two pixels per frame &2617 20 26 2a JSR &2a26 ; update_enemies_and_projectiles &261a 30 5b BMI &2677 ; to_leave &261c a6 1c LDX &1c ; player_direction_and_velocity &261e 8a TXA &261f 29 40 AND #&40 # &40 set if player moving horizontally, clear if not &2621 f0 0f BEQ &2632 ; vertical_jump &2623 8a TXA &2624 10 07 BPL &262d ; right_jump &2626 20 8a 25 JSR &258a ; scroll_left_if_no_obstacles # Returns equal set if obstacle &2629 f0 07 BEQ &2632 ; vertical_jump &262b d0 08 BNE &2635 ; skip_unplot # Always branches ; right_jump &262d 20 4a 25 JSR &254a ; scroll_right_if_no_obstacles # Returns equal set if obstacle &2630 d0 03 BNE &2635 ; skip_unplot # Always branches ; vertical_jump &2632 20 95 26 JSR &2695 ; plot_player_facing_left_or_right ; skip_unplot &2635 a6 12 LDX &12 ; player_screen_address_high &2637 a4 13 LDY &13 ; player_screen_address_low &2639 a5 02 LDA &02 ; jump_timer &263b c5 4e CMP &4e ; jump_stage_one &263d b0 05 BCS &2644 ; not_stage_one &263f 20 b9 24 JSR &24b9 ; move_player_up_four_pxiels # Move up four pixels in stage one of jump &2642 d0 15 BNE &2659 ; replot_player_after_part_of_jump ; not_stage_one &2644 c5 4f CMP &4f ; jump_stage_two &2646 b0 05 BCS &264d ; not_stage_two &2648 20 9b 24 JSR &249b ; move_player_up_two_pixels # Move up two pixels in stage two of jump &264b d0 0c BNE &2659 ; replot_player_after_part_of_jump ; not_stage_two &264d c5 bb CMP &bb ; jump_stage_three &264f b0 05 BCS &2656 ; not_stage_three &2651 20 10 24 JSR &2410 ; move_player_down_two_pixels # Move down two pixels in stage three of jump &2654 d0 03 BNE &2659 ; replot_player_after_part_of_jump ; not_stage_three &2656 20 2a 24 JSR &242a ; move_player_down_four_pixels # Move down four pixels in stage four of jump ; replot_player_after_part_of_jump &2659 86 12 STX &12 ; player_screen_address_high &265b 84 13 STY &13 ; player_screen_address_low &265d 20 95 26 JSR &2695 ; plot_player_facing_left_or_right # Replot player &2660 20 67 25 JSR &2567 ; plot_lives_and_pockets &2663 a5 19 LDA &19 ; player_y &2665 c9 b4 CMP #&b4 &2667 b0 8b BCS &25f4 ; jumped_out_of_level &2669 a5 02 LDA &02 ; jump_timer &266b c5 4f CMP &4f ; jump_stage_two &266d 90 05 BCC &2674 ; not_falling &266f 20 e2 26 JSR &26e2 ; check_for_platform_beneath_player # Returns equal set if platform &2672 f0 18 BEQ &268c ; end_of_jump ; not_falling &2674 20 e9 2e JSR &2ee9 ; check_for_enemy_hitting_player # Top bit set if enemy has hit player ; to_leave &2677 30 1b BMI &2694 ; leave # Leave if enemy has hit player &2679 a6 02 LDX &02 ; jump_timer &267b e8 INX &267c 86 02 STX &02 ; jump_timer &267e a5 bb LDA &bb ; jump_stage_three &2680 18 CLC &2681 65 4e ADC &4e ; jump_stage_one &2683 85 cf STA &cf ; jump_end &2685 e4 cf CPX &cf ; jump_end &2687 f0 03 BEQ &268c ; end_of_jump &2689 4c 01 26 JMP &2601 ; jump_loop ; end_of_jump &268c a9 30 LDA #&30 ; sound_6 &268e 20 10 31 JSR &3110 ; play_sound # Play sound for player landing &2691 4c 4b 20 JMP &204b ; unplot_player_and_replot_standing_still ; leave &2694 60 RTS ; plot_player_facing_left_or_right &2695 a5 1c LDA &1c ; player_direction_and_velocity &2697 30 03 BMI &269c ; player_is_facing_left # &80 set if player facing left &2699 4c db 24 JMP &24db ; plot_player_facing_right ; player_is_facing_left &269c 4c 01 25 JMP &2501 ; plot_player_facing_left ; consider_moving_player_down &269f a5 1e LDA &1e ; player_is_climbing &26a1 d0 23 BNE &26c6 ; already_climbing &26a3 20 db 26 JSR &26db ; get_player_screen_address_subtract_0008 # Move two pixels left and seventeen pixels down &26a6 20 53 24 JSR &2453 ; add_0280_to_screen_address_in_Y_X &26a9 20 65 24 JSR &2465 ; add_0279_to_screen_address_in_Y_X &26ac c8 INY &26ad c8 INY &26ae 86 cf STX &cf ; screen_address_low &26b0 84 ce STY &ce ; screen_address_high &26b2 a0 00 LDY #&00 &26b4 b1 ce LDA (&ce),Y ; screen_address &26b6 c9 55 CMP #&55 ; (both pixels colour 15) # Is this the left side of a ladder? &26b8 d0 0b BNE &26c5 ; leave &26ba 20 95 26 JSR &2695 ; plot_player_facing_left_or_right # If so, unplot player &26bd 85 1e STA &1e ; player_is_climbing &26bf a9 0c LDA #&0c ; PLAYER_CLIMBING # and set climbing &26c1 85 1a STA &1a ; player_feet_sprite &26c3 d0 04 BNE &26c9 ; player_is_already_on_ladder # Always branches ; leave &26c5 60 RTS ; already_climbing &26c6 20 95 25 JSR &2595 ; plot_player_climbing # Unplot player &26c9 20 cf 26 JSR &26cf ; move_player_down_two_pixels_and_update_screen_address &26cc 4c cd 25 JMP &25cd ; animate_climbing_player_and_check_for_platform ; move_player_down_two_pixels_and_update_screen_address &26cf a6 12 LDX &12 ; player_screen_address_high &26d1 a4 13 LDY &13 ; player_screen_address_low &26d3 20 10 24 JSR &2410 ; move_player_down_two_pixels &26d6 86 12 STX &12 ; player_screen_address_high &26d8 84 13 STY &13 ; player_screen_address_low &26da 60 RTS ; get_player_screen_address_subtract_0008 &26db a6 12 LDX &12 ; player_screen_address_high &26dd a4 13 LDY &13 ; player_screen_address_low &26df 4c 7b 24 JMP &247b ; subtract_0008_from_screen_address_in_Y_X # Move two pixels left ; check_for_platform_beneath_player &26e2 20 fa 24 JSR &24fa ; add_0280_to_player_screen_address_into_Y_X # Move eight pixels down &26e5 20 2b 27 JSR &272b ; add_row_to_screen_address_in_Y_X_and_store_in_ce_cf &26e8 a5 1c LDA &1c ; player_direction_and_velocity # &80 set if player facing left &26ea 30 1a BMI &2706 ; player_facing_left ; player_facing_right &26ec a0 18 LDY #&18 &26ee a5 1a LDA &1a ; player_feet_sprite &26f0 c9 04 CMP #&04 ; PLAYER_FEET_RIGHT &26f2 f0 02 BEQ &26f6 ; wider_feet_right &26f4 a0 10 LDY #&10 ; wider_feet_right &26f6 b1 ce LDA (&ce),Y ; screen_address # Check player's bottom right &26f8 20 97 27 JSR &2797 ; check_pixel_values_for_platform_colour &26fb f0 2d BEQ &272a ; leave # Leave with equal set if platform &26fd 20 ed 24 JSR &24ed ; add_width_of_players_feet_to_screen_address_and_put_in_Y_X &2700 20 2b 27 JSR &272b ; add_row_to_screen_address_in_Y_X_and_store_in_ce_cf &2703 4c 23 27 JMP &2723 ; check_left ; player_facing_left &2706 20 fa 24 JSR &24fa ; add_0280_to_player_screen_address_into_Y_X # Move eight pixels down &2709 20 2b 27 JSR &272b ; add_row_to_screen_address_in_Y_X_and_store_in_ce_cf &270c a0 18 LDY #&18 &270e a5 1a LDA &1a ; player_feet_sprite &2710 c9 06 CMP #&06 ; PLAYER_FEET_RIGHT_3 &2712 d0 02 BNE &2716 ; wider_feet_left &2714 a0 10 LDY #&10 ; wider_feet_left &2716 b1 ce LDA (&ce),Y ; screen_address # Check player's bottom right &2718 20 97 27 JSR &2797 ; check_pixel_values_for_platform_colour &271b f0 0d BEQ &272a ; leave # Leave with equal set if platform &271d 20 20 25 JSR &2520 ; subtract_fraction_of_players_feet_from_screen_address_and_put_in_Y_X &2720 20 2b 27 JSR &272b ; add_row_to_screen_address_in_Y_X_and_store_in_ce_cf ; check_left &2723 a0 00 LDY #&00 &2725 b1 ce LDA (&ce),Y ; screen_address # Check player's bottom left &2727 20 97 27 JSR &2797 ; check_pixel_values_for_platform_colour ; leave &272a 60 RTS ; add_row_to_screen_address_in_Y_X_and_store_in_ce_cf &272b 98 TYA &272c 29 07 AND #&07 &272e c9 07 CMP #&07 &2730 f0 06 BEQ &2738 ; next_group &2732 c8 INY &2733 d0 06 BNE &273b ; set_address &2735 e8 INX &2736 d0 03 BNE &273b ; set_address ; next_group &2738 20 65 24 JSR &2465 ; add_0279_to_screen_address_in_Y_X ; set_address &273b 86 cf STX &cf ; screen_address_high &273d 84 ce STY &ce ; screen_address_low &273f 60 RTS ; check_for_obstacles_before_moving_right &2740 a6 12 LDX &12 ; player_screen_address_high &2742 a4 13 LDY &13 ; player_screen_address_low &2744 20 71 24 JSR &2471 ; add_0020_to_screen_address_in_Y_X # Move eight pixels right &2747 4c 51 27 JMP &2751 ; check_for_obstacles_before_moving ; check_for_obstacles_before_moving_left &274a a6 12 LDX &12 ; player_screen_address_high &274c a4 13 LDY &13 ; player_screen_address_low &274e 20 85 24 JSR &2485 ; subtract_0010_from_screen_address_in_Y_X # Move four pixels left ; check_for_obstacles_before_moving &2751 20 8f 24 JSR &248f ; subtract_0280_from_screen_address_in_Y_X # Move eight pixels up &2754 20 8f 24 JSR &248f ; subtract_0280_from_screen_address_in_Y_X # Move eight pixels up, i.e. start at player's nose &2757 86 cf STX &cf ; screen_address_high &2759 84 ce STY &ce ; screen_address_low &275b a0 00 LDY #&00 &275d a9 03 LDA #&03 &275f 85 cd STA &cd ; count ; check_for_obstacles_before_moving_loop &2761 b1 ce LDA (&ce),Y ; screen_address &2763 20 97 27 JSR &2797 ; check_pixel_values_for_platform_colour &2766 f0 2e BEQ &2796 ; leave # Leave with equal set if platform &2768 c6 cd DEC &cd ; count &276a f0 05 BEQ &2771 ; check_for_obstacles_at_players_feet &276c 20 a4 27 JSR &27a4 ; add_0280_to_screen_address_in_ce_cf # Move down eight pixels &276f 10 f0 BPL &2761 ; check_for_obstacles_before_moving_loop # Always branches ; check_for_obstacles_at_players_feet &2771 a6 1c LDX &1c ; player_direction_and_velocity &2773 30 04 BMI &2779 ; player_facing_left &2775 a9 78 LDA #&78 &2777 10 02 BPL &277b ; player_facing_right ; player_facing_left &2779 a9 80 LDA #&80 ; player_facing_right &277b 18 CLC &277c 65 ce ADC &ce ; screen_address_low &277e 85 ce STA &ce ; screen_address_low &2780 90 02 BCC &2784 ; skip_page &2782 e6 cf INC &cf ; screen-address_high ; skip_page &2784 e6 cf INC &cf ; screen-address_high &2786 e6 cf INC &cf ; screen-address_high &2788 b1 ce LDA (&ce),Y ; screen_address &278a 20 97 27 JSR &2797 ; check_pixel_values_for_platform_colour &278d f0 07 BEQ &2796 ; leave # Leave with equal set if platform &278f a0 08 LDY #&08 &2791 b1 ce LDA (&ce),Y ; screen_address &2793 4c 97 27 JMP &2797 ; check_pixel_values_for_platform_colour ; leave &2796 60 RTS ; check_pixel_values_for_platform_colour &2797 aa TAX &2798 29 aa AND #&aa &279a c9 a8 CMP #&a8 ; (left pixel colour 14) # Is the left pixel the platform colour? &279c f0 05 BEQ &27a3 ; leave &279e 8a TXA &279f 29 55 AND #&55 &27a1 c9 54 CMP #&54 ; (right pixel colour 14) # Is the right pixel the platform colour? ; leave &27a3 60 RTS ; add_0280_to_screen_address_in_ce_cf &27a4 a6 cf LDX &cf ; screen_address_high &27a6 a5 ce LDA &ce ; screen_address_low &27a8 18 CLC &27a9 69 80 ADC #&80 &27ab 85 ce STA &c ; screen_address_low &27ad 90 01 BCC &27b0 ; skip_page &27af e8 INX ; skip_page &27b0 e8 INX &27b1 e8 INX &27b2 8a TXA &27b3 10 04 BPL &27b9 ; skip_wraparound &27b5 38 SEC &27b6 e9 40 SBC #&40 &27b8 aa TAX ; skip_wraparound &27b9 86 cf STX &cf ; screen_address_high &27bb 60 RTS ; plot_pockets &27bc a6 10 LDX &10 ; scrolled_screen_addresses + 12 &27be 86 c1 STX &c1 ; pocket_screen_address_high &27c0 a4 11 LDY &11 ; scrolled_screen_addresses + 13 &27c2 84 c0 STY &c0 ; pocket_screen_address_low &27c4 20 7b 24 JSR &247b ; subtract_0008_from_screen_address_in_Y_X # Move two pixels left &27c7 20 8f 24 JSR &248f ; subtract_0280_from_screen_address_in_Y_X # Move eight pixels up &27ca 98 TYA &27cb 38 SEC &27cc e9 07 SBC #&07 &27ce 86 cf STX &cf ; screen_address_high &27d0 85 ce STA &ce ; screen_address_low &27d2 20 87 30 JSR &3087 ; wipe_column_of_pixels # Wipe column to left of pockets &27d5 20 a4 27 JSR &27a4 ; add_0280_to_screen_address_in_ce_cf # Move eight pixels down &27d8 20 87 30 JSR &3087 ; wipe_column_of_pixels &27db a0 0b LDY #&0b ; EMPTY_POCKET # Wipe the pocket using a black sprite if empty &27dd a6 14 LDX &14 ; pockets &27df f0 03 BEQ &27e4 ; first_pocket_is_empty &27e1 bc 1a 04 LDY &041a,X ; objects_sprite ; first_pocket_is_empty &27e4 a6 c1 LDX &c1 ; pocket_screen_address_high &27e6 a5 c0 LDA &c0 ; pocket_screen_address_low &27e8 20 9d 23 JSR &239d ; plot_scenery_sprite_with_write &27eb a0 0b LDY #&0b &27ed a6 15 LDX &15 ; pockets + 1 &27ef f0 03 BEQ &27f4 ; second_pocket_is_empty &27f1 bc 1a 04 LDY &041a,X ; objects_sprite ; second_pocket_is_empty &27f4 20 09 28 JSR &2809 ; add_0020_to_screen_address_in_c0_c1 # Move eight pixels right &27f7 20 9d 23 JSR &239d ; plot_scenery_sprite_with_write &27fa a0 0b LDY #&0b &27fc a6 16 LDX &16 ; pockets + 2 &27fe f0 03 BEQ &2803 ; third_pocket_is_empty &2800 bc 1a 04 LDY &041a,X ; objects_sprite ; third_pocket_is_empty &2803 20 09 28 JSR &2809 ; add_0020_to_screen_address_in_c0_c1 # Move eight pixels right &2806 4c 9d 23 JMP &239d ; plot_scenery_sprite_with_write ; add_0020_to_screen_address_in_c0_c1 &2809 a6 c1 LDX &c1 ; pocket_screen_address_high &280b a5 c0 LDA &c0 ; pocket_screen_address_low &280d 18 CLC &280e 69 20 ADC #&20 &2810 90 05 BCC &2817 ; skip_page &2812 e8 INX &2813 10 02 BPL &2817 ; skip_wraparound &2815 a2 40 LDX #&40 ; skip_page ; skip_wraparound &2817 86 c1 STX &c1 ; pocket_screen_address_high &2819 85 c0 STA &c0 ; pocket_screen_address_low &281b 60 RTS ; shuffle_pockets &281c a5 16 LDA &16 ; pockets + 2 &281e 85 17 STA &17 ; object_being_dropped &2820 a5 15 LDA &15 ; pockets + 1 &2822 85 16 STA &16 ; pockets + 2 &2824 a5 14 LDA &14 ; pockets &2826 85 15 STA &15 ; pockets + 1 &2828 a9 00 LDA #&00 &282a 85 14 STA &14 ; pockets &282c a2 01 LDX #&01 # Don't consider DRAGON_BODY ; check_objects_loop &282e 20 76 28 JSR &2876 ; check_if_object_X_is_at_player # Returns equal set if player can pick up the object &2831 d0 08 BNE &283b ; consider_next_object &2833 86 14 STX &14 ; pockets &2835 20 64 28 JSR &2864 ; plot_or_unplot_object &2838 4c 40 28 JMP &2840 ; drop_object ; consider_next_object &283b e8 INX &283c e0 08 CPX #&08 # Don't consider extra lives or end game objects &283e d0 ee BNE &282e ; check_objects_loop ; drop_object &2840 a6 17 LDX &17 ; object_being_dropped &2842 f0 18 BEQ &285c ; no_object_dropped &2844 a5 ba LDA &ba ; player_level &2846 9d 00 04 STA &0400,X ; objects_level &2849 a5 18 LDA &18 ; player_x &284b 9d 4e 04 STA &044e,X ; objects_x &284e 18 CLC &284f 69 02 ADC #&02 &2851 9d 68 04 STA &0468,X ; objects_end_x &2854 a5 19 LDA &19 ; player_y &2856 9d 34 04 STA &0434,X ; objects_y &2859 20 64 28 JSR &2864 ; plot_or_unplot_object ; object_being_dropped &285c a9 38 LDA #&38 ; sound_7 &285e 20 10 31 JSR &3110 ; play_sound &2861 4c bc 27 JMP &27bc ; plot_pockets ; plot_or_unplot_object &2864 bd 1a 04 LDA &041a,X ; objects_sprite &2867 85 cf STA &cf ; sprite &2869 a6 12 LDX &12 ; player_screen_address_high &286b a4 13 LDY &13 ; player_screen_address_low &286d 20 53 24 JSR &2453 ; add_0280_to_screen_address_in_Y_X # Move eight pixels down &2870 98 TYA &2871 a4 cf LDY &cf ; sprite &2873 4c 95 23 JMP &2395 ; plot_scenery_sprite_with_eor ; check_if_object_X_is_at_player &2876 bc 00 04 LDY &0400,X ; objects_level &2879 c4 ba CPY &ba ; player_level &287b d0 13 BNE &2890 ; leave &287d bc 34 04 LDY &0434,X ; objects_y &2880 c4 19 CPY &19 ; player_y &2882 d0 0c BNE &2890 ; leave &2884 bc 4e 04 LDY &044e,X ; objects_x &2887 c4 18 CPY &18 ; player_x &2889 d0 05 BNE &2890 ; leave &288b a9 00 LDA #&00 # Set object as not being on level &288d 9d 00 04 STA &0400,X ; objects_level ; leave &2890 60 RTS ; initialise_enemies &2891 a2 05 LDX #&05 &2893 a9 00 LDA #&00 ; wipe_enemies_level_loop &2895 9d 14 04 STA &0414,X ; enemies_level # Set enemies_level to 0, i.e. no enemy present &2898 ca DEX &2899 10 fa BPL &2895 ; wipe_enemies_level_loop &289b a2 04 LDX #&04 ; wipe_enemies_direction_and_type_loop &289d 9d cb 04 STA &04cb,X ; enemies_direction &28a0 9d c1 04 STA &04c1,X ; enemies_type &28a3 ca DEX &28a4 10 f7 BPL &289d ; wipe_enemies_direction_and_type_loop &28a6 a2 03 LDX #&03 ; wipe_projectiles_sprite_and_direction_loop &28a8 95 3a STA &3a,X ; projectiles_sprite &28aa 95 4a STA &4a,X ; projectiles_direction_and_age &28ac ca DEX &28ad 10 f9 BPL &28a8 ; wipe_projectiles_sprite_and_direction_loop ; calculate_level_enemy_data_address &28af a9 e8 LDA #&e8 &28b1 a2 06 LDX #&06 ; &06e8 = level_enemy_data - &0a &28b3 a4 ba LDY &ba ; player_level ; calculate_level_enemy_data_address_loop &28b5 18 CLC &28b6 69 0a ADC #&0a # &0a of data per level, 2 bytes each for five enemies &28b8 90 01 BCC &28bb ; not_page &28ba e8 INX ; not_page &28bb 88 DEY &28bc d0 f7 BNE &28b5 ; calculate_level_enemy_data_address_loop &28be 85 ce STA &ce ; level_enemy_data_address_low &28c0 86 cf STX &cf ; level_enemy_data_address_high &28c2 84 cd STY &cd ; enemy ; initialise_enemies_loop &28c4 84 cb STY &cb ; level_enemy_data_offset &28c6 b1 ce LDA (&ce),Y ; level_enemy_data_address # First byte of enemy data is enemy x position &28c8 a6 cd LDX &cd ; enemy &28ca 95 20 STA &20,X ; enemies_x &28cc 9d b7 04 STA &04b7,X ; enemies_minimum_x &28cf 18 CLC &28d0 69 1e ADC #&1e &28d2 9d bc 04 STA &04bc,X ; enemies_maximum_x &28d5 c8 INY &28d6 b1 ce LDA (&ce),Y ; level_enemy_data_address # Second byte of enemy data &28d8 29 3f AND #&3f &28da 9d c1 04 STA &04c1,X ; enemies_type &28dd f0 70 BEQ &294f &28df b1 ce LDA (&ce),Y ; level_enemy_data_address # Top two bits are enemy y position (&20, &58, &90) &28e1 29 c0 AND #&c0 &28e3 30 06 BMI &28eb ; enemy_on_top_platform &28e5 f0 08 BEQ &28ef ; enemy_on_bottom_platform ; enemy_on_middle_platform &28e7 a9 58 LDA #&58 &28e9 d0 06 BNE &28f1 ; set_enemy_y ; enemy_on_top_platform &28eb a9 90 LDA #&90 &28ed d0 02 BNE &28f1 ; set_enemy_y ; enemy_on_bottom_platform &28ef a9 20 LDA #&20 ; set_enemy_y &28f1 9d c6 04 STA &04c6,X ; enemies_y &28f4 bc c1 04 LDY &04c1,X ; enemies_type &28f7 b9 09 06 LDA &0609,Y ; enemy_bottom_sprite_table - 1 &28fa 95 25 STA &25,X ; enemies_bottom_sprite &28fc 9d 2e 04 STA &042e,X ; enemies_sprite &28ff a5 ba LDA &ba ; player_level &2901 9d 14 04 STA &0414,X ; enemies_level &2904 bd c6 04 LDA &04c6,X ; enemies_y &2907 9d 48 04 STA &0448,X ; enemies_head_y &290a b5 20 LDA &20,X ; enemies_x &290c 9d 62 04 STA &0462,X ; enemies_start_x &290f b9 fb 05 LDA &05fb,Y ; enemy_firing_table - 1 &2912 d0 23 BNE &2937 ; enemy_uses_single_sprite # Does the enemy have separate feet and head sprites? &2914 a9 01 LDA #&01 &2916 18 CLC &2917 7d 62 04 ADC &0462,X ; enemies_start_x &291a 9d 7c 04 STA &047c,X ; enemies_end_x &291d b5 20 LDA &20,X ; enemies_x &291f e8 INX # Use next slot for head &2920 9d 62 04 STA &0462,X ; enemies_start_x # (only occurs for last enemy) &2923 bd c5 04 LDA &04c5,X ; enemies_y - 1 &2926 18 CLC &2927 69 08 ADC #&08 &2929 9d 48 04 STA &0448,X ; enemies_head_y &292c b9 02 06 LDA &0602,Y ; enemy_top_sprite_table - 1 &292f 9d 2e 04 STA &042e,X ; enemies_sprite &2932 a5 ba LDA &ba ; player_level &2934 9d 14 04 STA &0414,X ; enemies_level ; enemy_uses_single_sprite &2937 b9 17 06 LDA &0617,Y ; enemy_width_table - 1 &293a 18 CLC &293b 7d 62 04 ADC &0462,X ; enemies_start_x &293e 9d 7c 04 STA &047c,X ; enemies_end_x &2941 c0 07 CPY #&07 &2943 d0 0a BNE &294f ; isn't_dragon &2945 ad 0e 04 LDA &040e ; objects_level + 14 &2948 f0 05 BEQ &294f ; dragon_isn't_dead &294a a9 00 LDA #&00 # Remove DRAGON_HEAD if dragon has been killed &294c 9d c1 04 STA &04c1,X ; enemies_type ; dragon_isn't_dead ; isn't_dragon &294f e6 cd INC &cd ; enemy &2951 a4 cb LDY &cb ; level_enemy_data_offset &2953 c8 INY &2954 c8 INY &2955 c0 0a CPY #&0a &2957 b0 03 BCS &295c ; leave &2959 4c c4 28 JMP &28c4 ; initialise_enemies_loop ; leave &295c 60 RTS ; update_enemy_screen_addresses_for_left_scroll # Affects enemies overlapping left edge of screen &295d a2 04 LDX #&04 ; update_enemy_screen_addresses_for_left_scroll_loop &295f bc c1 04 LDY &04c1,X ; enemies_type &2962 f0 21 BEQ &2985 ; update_next_enemy_left # Don't update if no enemy &2964 30 1f BMI &2985 ; update_next_enemy_left # Don't update if enemy materialising &2966 b9 17 06 LDA &0617,Y ; enemy_width_table - 1 &2969 18 CLC &296a 69 01 ADC #&01 &296c 85 cf STA &cf ; width &296e 75 20 ADC &20,X ; enemies_x &2970 c5 b2 CMP &b2 ; screen_left_x &2972 d0 11 BNE &2985 ; update_next_enemy_left # Don't update if enemy not at edge of screen &2974 20 aa 29 JSR &29aa ; get_scrolled_section_screen_address # Get the screen address for the start of the platform ; reduce_address_loop &2977 20 7b 24 JSR &247b ; subtract_0008_from_screen_address_in_Y_X # Move left two pixels &297a c6 cf DEC &cf ; width &297c 10 f9 BPL &2977 ; reduced_address_loop &297e 8a TXA &297f a6 ce LDX &ce ; enemy &2981 95 2f STA &2f,X ; enemies_screen_address_high &2983 94 2a STY &2a,X ; enemies_screen_address_low ; update_next_enemy_left &2985 ca DEX &2986 10 d7 BPL &295f ; update_enemy_screen_addresses_for_left_scroll_loop &2988 60 RTS ; update_enemy_screen_addresses_for_right_scroll # Affects enemies overlapping right edge of screen &2989 a2 04 LDX #&04 ; update_enemy_screen_addresses_for_right_scroll_loop &298b bd c1 04 LDA &04c1,X ; enemies_type &298e f0 16 BEQ &29a6 ; update_next_enemy_right # Don't update if no enemy &2990 30 14 BMI &29a6 ; update_next_enemy_right # Don't update if enemy materialising &2992 b4 20 LDY &20,X ; enemies_x &2994 88 DEY &2995 c4 b3 CPY &b3 ; screen_right_x &2997 d0 0d BNE &29a6 ; update_next_enemy_right # Don't update if enemy not at edge of screen &2999 20 aa 29 JSR &29aa ; get_scrolled_section_screen_address # Get the screen address for the start of the platform &299c 20 53 24 JSR &2453 ; add_0280_to_screen_address_in_Y_X # Move to end of that row &299f 8a TXA &29a0 a6 ce LDX &ce ; enemy &29a2 95 2f STA &2f,X ; enemies_screen_address_high &29a4 94 2a STY &2a,X ; enemies_screen_address_low ; update_next_enemy_right &29a6 ca DEX &29a7 10 e2 BPL &298b ; update_enemy_screen_addresses_for_right_scroll_loop &29a9 60 RTS ; get_scrolled_section_screen_address &29aa 86 ce STX &ce ; enemy &29ac bd c6 04 LDA &04c6,X ; enemies_y &29af 30 0c BMI &29bd ; top_section &29b1 29 40 AND #&40 &29b3 f0 04 BEQ &29b9 ; bottom_section ; middle_section &29b5 a2 02 LDX #&02 # Use &08, &09, bottom left of middle scenery &29b7 d0 06 BNE &29bf ; leave_with_addresses ; bottom_section &29b9 a2 04 LDX #&04 # Use &0a, &0b, bottom left of bottom scenery &29bb d0 02 BNE &29bf ; leave_with_addresses ; top_section &29bd a2 00 LDX #&00 # Use &06, &07, bottom left of top scenery ; leave_with_addresses &29bf b5 06 LDA &06,X ; scrolled_screen_addresses + 2 &29c1 b4 07 LDY &07,X ; scrolled_screen_addresses + 3 &29c3 aa TAX &29c4 60 RTS ; plot_enemy_materialisation &29c5 b5 2f LDA &2f,X ; enemies_screen_address_high &29c7 b4 2a LDY &2a,X ; enemies_screen_address_low &29c9 aa TAX &29ca 20 8f 24 JSR &248f ; subtract_0280_from_screen_address_in_Y_X # Move eight pixels up &29cd 86 c0 STX &c0 ; screen_address_low &29cf 84 c1 STY &c1 ; screen_address_high &29d1 a6 36 LDX &36 ; enemy_to_consider &29d3 bd c1 04 LDA &04c1,X ; enemies_type # Materialisation sprite &29d6 4c 9f 21 JMP &219f ; plot_materialisation ; enemy_is_materialising &29d9 20 c5 29 JSR &29c5 ; plot_enemy_materialisation &29dc a6 36 LDX &36 ; enemy_to_consider &29de bc c1 04 LDY &04c1,X ; enemies_type &29e1 88 DEY &29e2 c0 92 CPY #&92 ; MATERIALISATION - 1 | &80 &29e4 d0 02 BNE &29e8 ; materialisation_still_in_progress &29e6 a0 00 LDY #&00 # Remove enemy at end of materialisation ; materialisation_still_in_progress &29e8 98 TYA &29e9 9d c1 04 STA &04c1,X ; enemies_type &29ec f0 03 BEQ &29f1 ; consider_next_enemy &29ee 20 c5 29 JSR &29c5 ; plot_enemy_materialisation ; consider_next_enemy &29f1 e6 37 INC &37 ; other_enemy_to_consider &29f3 e6 36 INC &36 ; enemy_to_consider &29f5 a6 36 LDX &36 ; enemy_to_consider &29f7 e0 05 CPX #&05 &29f9 d0 0a BNE &2a05 ; skip_spell_collision_check &29fb a2 02 LDX #&02 &29fd 86 36 STX &36 ; enemy_to_consider &29ff 20 21 2e JSR &2e21 ; check_spell_for_collision_with_enemy &2a02 4c 13 2d JMP &2d13 ; update_projectiles ; skip_spell_collision_check &2a05 e0 02 CPX #&02 &2a07 d0 06 BNE &2a0f ; skip_updating_projectiles &2a09 20 13 2d JSR &2d13 ; update_projectiles # Top bit set if player was hit by projectile &2a0c 10 23 BPL &2a31 ; consider_enemy_firing &2a0e 60 RTS ; skip_updating_projectiles &2a0f 20 cc 1e JSR &1ecc ; wait_for_vsync &2a12 4c 31 2a JMP &2a31 ; consider_enemy_firing ; plot_enemy &2a15 bd cb 04 LDA &04cb,X ; enemies_direction # &80 if moving to left &2a18 30 06 BMI &2a20 ; enemy_moving_left &2a1a 20 69 2c JSR &2c69 ; plot_enemy_bottom_right &2a1d 4c 23 2a JMP &2a23 ; to_plot_enemy_top ; enemy_moving_left &2a20 20 b6 2c JSR &2cb6 ; plot_enemy_bottom_left ; to_plot_enemy_top &2a23 4c 96 2c JMP &2c96 ; plot_enemy_top ; update_enemies_and_projectiles &2a26 c6 36 DEC &36 ; enemy_to_consider # Used as a counter to update enemies every few frames &2a28 f0 03 BEQ &2a2d ; update_enemies &2a2a 4c 5a 2c JMP &2c5a ; update_projectiles_twice_in_between_vsyncs ; update_enemies &2a2d a9 00 LDA #&00 &2a2f 85 37 STA &37 ; other_enemy_to_consider ; consider_enemy_firing &2a31 a6 36 LDX &36 ; enemy_to_consider &2a33 bc c1 04 LDY &04c1,X ; enemies_type &2a36 f0 b9 BEQ &29f1 ; consider_next_enemy &2a38 30 9f BMI &29d9 ; enemy_is_materialising &2a3a b9 fb 05 LDA &05fb,Y ; enemy_firing_table - 1 &2a3d f0 03 BEQ &2a42 ; enemy_doesn't_fire &2a3f 4c 0c 2b JMP &2b0c ; enemy_can_fire ; enemy_doesn't_fire &2a42 20 15 2a JSR &2a15 ; plot_enemy # Plot two sprites for SWORDSMAN, AXEMAN, BARBARIAN &2a45 a4 36 LDY &36 ; enemy_to_consider &2a47 a6 37 LDX &37 ; other_enemy_to_consider &2a49 b9 cb 04 LDA &04cb,Y ; enemies_direction # &80 if moving to left &2a4c 30 13 BMI &2a61 ; enemy_was_moving_left ; enemy_was_moving_right # If the enemy is moving right, &2a4e b9 20 00 LDA &0020,Y ; enemies_x &2a51 d9 bc 04 CMP &04bc,Y ; enemies_maximum_x &2a54 d0 1c BNE &2a72 ; enemy_moving_right # If it hasn't hit its right limit, keep it moving right &2a56 e8 INX &2a57 fe 2e 04 INC &042e,X ; enemies_sprite &2a5a a9 80 LDA #&80 # Otherwise, set it moving left &2a5c 99 cb 04 STA &04cb,Y ; enemies_direction &2a5f 30 50 BMI &2ab1 ; enemy_moving_left ; enemy_was_moving_left # If the enemy is moving left, &2a61 b9 20 00 LDA &0020,Y ; enemies_x &2a64 d9 b7 04 CMP &04b7,Y ; enemies_minimum_x &2a67 d0 48 BNE &2ab1 ; enemy_moving_left # If it hasn't hit its left limit, keep it moving left &2a69 e8 INX &2a6a de 2e 04 DEC &042e,X ; enemies_sprite &2a6d a9 00 LDA #&00 # Otherwise, set it moving right &2a6f 99 cb 04 STA &04cb,Y ; enemies_direction ; enemy_moving_right &2a72 20 db 2c JSR &2cdb ; move_enemy_right &2a75 e8 INX &2a76 20 e8 2c JSR &2ce8 ; increase_enemy_start_and_end_x &2a79 20 fa 2a JSR &2afa ; update_enemy_feet_sprite # Returns with X = enemy foot sprite &2a7c b9 20 00 LDA &0020,Y ; enemies_x &2a7f 85 cf STA &cf ; enemy_x &2a81 e0 10 CPX #&10 ; ENEMY_FEET_RIGHT &2a83 f0 03 BEQ &2a88 ; not_feet_one_right &2a85 38 SEC &2a86 e9 01 SBC #&01 ; not_feet_one_right &2a88 a4 37 LDY &37 ; other_enemy_to_consider &2a8a 99 62 04 STA &0462,Y ; enemies_start_x &2a8d 8a TXA &2a8e 99 2e 04 STA &042e,Y ; enemies_sprite &2a91 a5 cf LDA &cf ; enemy_x &2a93 18 CLC &2a94 69 01 ADC #&01 &2a96 e0 11 CPX #&11 ; ENEMY_FEET_RIGHT_2 &2a98 d0 03 BNE &2a9d ; not_feet_two_right &2a9a 18 CLC &2a9b 69 01 ADC #&01 ; not_feet_two_right &2a9d 99 7c 04 STA &047c,Y ; enemies_end_x &2aa0 20 5d 29 JSR &295d ; update_enemy_screen_addresses_for_left_scroll &2aa3 20 23 2c JSR &2c23 ; plot_enemy_bottom_right_and_store_sprite_cropping ; plot_enemy_top_then_move_on &2aa6 20 96 2c JSR &2c96 ; plot_enemy_top &2aa9 e6 37 INC &37 ; other_enemy_to_consider &2aab 20 26 2c JSR &2c26 ; store_sprite_cropping &2aae 4c f1 29 JMP &29f1 ; consider_next_enemy ; enemy_moving_left &2ab1 20 ef 2c JSR &2cef ; move_enemy_left &2ab4 e8 INX &2ab5 20 fc 2c JSR &2cfc ; decrease_enemy_start_and_end_x &2ab8 20 fa 2a JSR &2afa ; update_enemy_feet_sprite &2abb be c1 04 LDX &04c1,Y ; enemies_type &2abe bd 17 06 LDA &0617,X ; enemy_width_table - 1 &2ac1 18 CLC &2ac2 79 20 00 ADC &0020,Y ; enemies_x &2ac5 38 SEC &2ac6 e9 01 SBC #&01 &2ac8 85 cf STA &cf ; enemy_end_x &2aca b6 25 LDX &25,Y ; enemies_bottom_sprite &2acc e0 11 CPX #&11 ; ENEMY_FEET_RIGHT_2 &2ace d0 03 BNE &2ad3 ; not_feet_two_left &2ad0 38 SEC &2ad1 e9 01 SBC #&01 ; not_feet_two_left &2ad3 a4 37 LDY &37 ; other_enemy_to_consider &2ad5 99 62 04 STA &0462,Y ; enemies_start_x &2ad8 8a TXA &2ad9 18 CLC &2ada 69 03 ADC #&03 &2adc 99 2e 04 STA &042e,Y ; enemies_sprite &2adf a5 cf LDA &cf ; enemy_end_x &2ae1 18 CLC &2ae2 69 01 ADC #&01 &2ae4 e0 10 CPX #&10 ; ENEMY_FEET_RIGHT &2ae6 f0 03 BEQ &2aeb ; not_feet_left &2ae8 18 CLC &2ae9 69 01 ADC #&01 ; not_feet_left &2aeb 99 7c 04 STA &047c,Y ; enemies_end_x &2aee 20 89 29 JSR &2989 ; update_enemy_screen_addresses_for_right_scroll &2af1 20 b6 2c JSR &2cb6 ; plot_enemy_bottom_left &2af4 20 26 2c JSR &2c26 ; store_sprite_cropping &2af7 4c a6 2a JMP &2aa6 ; plot_enemy_top_then_move_on ; update_enemy_feet_sprite &2afa a4 36 LDY &36 ; enemy_to_consider &2afc b6 25 LDX &25,Y ; enemies_bottom_sprite &2afe e0 11 CPX #&11 ; ENEMY_FEET_RIGHT_2 &2b00 f0 02 BEQ &2b04 feet_one_or_two &2b02 b0 03 BCS &2b07 ; feet_three ; feet_one_or_two &2b04 e8 INX &2b05 d0 02 BNE &2b09 ; set_enemies_bottom_sprite ; feet_three &2b07 a2 10 LDX #&10 ; ENEMY_FEET_RIGHT ; set_enemies_bottom_sprite &2b09 96 25 STX &25,Y ; enemies_bottom_sprite &2b0b 60 RTS ; enemy_can_fire &2b0c 30 5c BMI &2b6a ; enemy_fires_horizontally ; enemy_fires_vertically &2b0e 20 69 2c JSR &2c69 ; plot_enemy_bottom_right # Plot only one sprite for BIRDMAN, ARCHERs, DRAGON_HEAD &2b11 a6 36 LDX &36 ; enemy_to_consider &2b13 a4 37 LDY &37 ; other_enemy_to_consider &2b15 b5 25 LDA &25,X ; enemies_bottom_sprite &2b17 49 01 EOR #&01 # Animate the sprite &2b19 95 25 STA &25,X ; enemies_bottom_sprite &2b1b bd cb 04 LDA &04cb,X ; enemies_direction # &80 if moving to left &2b1e 30 1f BMI &2b3f ; enemy_moving_left ; enemy_moving_right &2b20 b5 20 LDA &20,X ; enemies_x &2b22 dd bc 04 CMP &04bc,X ; enemies_maximum_x &2b25 d0 0c BNE &2b33 ; enemy_still_moving_right &2b27 a9 80 LDA #&80 # Set &80 to make enemy move left &2b29 9d cb 04 STA &04cb,X ; enemies_direction &2b2c b5 25 LDA &25,X ; enemies_bottom_sprite &2b2e 18 CLC &2b2f 69 02 ADC #&02 # Use left sprites &2b31 d0 29 BNE &2b5c ; update_enemy_sprite # Always branches ; enemy_still_moving_right &2b33 20 db 2c JSR &2cdb ; move_enemy_right &2b36 20 5d 29 JSR &295d ; update_enemy_screen_addresses_for_left_scroll &2b39 a6 36 LDX &36 ; enemy_to_consider &2b3b b5 25 LDA &25,X ; enemies_bottom_sprite &2b3d d0 1d BNE &2b5c ; update_enemy_sprite # Always branches ; enemy_moving_left &2b3f b5 20 LDA &20,X ; enemies_x &2b41 dd b7 04 CMP &04b7,X ; enemies_minimum_x &2b44 d0 09 BNE &2b4f ; enemy_still_moving_left &2b46 a9 00 LDA #&00 # Clear &80 to make the enemy move right &2b48 9d cb 04 STA &04cb,X ; enemies_direction &2b4b b5 25 LDA &25,X ; enemies_bottom_sprite # Use right sprites &2b4d d0 0d BNE &2b5c ; update_enemy_sprite # Always branches ; enemy_still_moving_left &2b4f 20 ef 2c JSR &2cef ; move_enemy_left &2b52 20 89 29 JSR &2989 ; update_enemy_screen_addresses_for_right_scroll &2b55 a6 36 LDX &36 ; enemy_to_consider &2b57 b5 25 LDA &25,X ; enemies_bottom_sprite &2b59 18 CLC &2b5a 69 02 ADC #&02 ; update_enemy_sprite &2b5c a4 37 LDY &37 ; other_enemy_to_consider &2b5e 99 2e 04 STA &042e,Y ; enemies_sprite &2b61 20 23 2c JSR &2c23 ; plot_enemy_bottom_right_and_store_sprite_cropping &2b64 20 a5 2e JSR &2ea5 ; consider_dropping_sword &2b67 4c f1 29 JMP &29f1 ; consider_next_enemy ; enemy_fires_horizontally &2b6a a6 36 LDX &36 ; enemy_to_consider &2b6c bc c1 04 LDY &04c1,X ; enemies_type &2b6f b9 09 06 LDA &0609,Y ; enemy_bottom_sprite_table - 1 &2b72 85 c0 STA &c0 ; bottom_sprite &2b74 18 CLC &2b75 69 03 ADC #&03 &2b77 85 c1 STA &c1 ; bottom_sprite_facing_left &2b79 a5 3b LDA &3b ; projectiles_sprite + 1 # Don't fire if there is already an arrow firing &2b7b d0 18 BNE &2b95 ; skip_firing &2b7d b5 25 LDA &25,X ; enemies_bottom_sprite &2b7f c5 c0 CMP &c0 ; bottom_sprite &2b81 d0 21 BNE &2ba4 ; update_archer &2b83 b9 02 06 LDA &0602,Y ; enemy_top_sprite_table - 1 &2b86 30 10 BMI &2b98 ; enemy_facing_left ; enemy_facing_right &2b88 a4 37 LDY &37 ; other_enemy_to_consider &2b8a b9 7c 04 LDA &047c,Y ; enemies_end_x &2b8d c5 b3 CMP &b3 ; screen_right_x &2b8f b0 04 BCS &2b95 ; skip_firing # Don't fire if right of enemy is off screen &2b91 c5 18 CMP &18 ; player_x &2b93 b0 0f BCS &2ba4 ; update_archer # Don't fire if player is left of archer ; skip_firing &2b95 4c f1 29 JMP &29f1 ; consider_next_enemy ; enemy_facing_left &2b98 a5 b2 LDA &b2 ; screen_left_x &2b9a d5 20 CMP &20,X ; enemies_x &2b9c b0 f7 BCS &2b95 ; skip_firing # Don't fire if left of enemy is off screen &2b9e b5 20 LDA &20,X ; enemies_x &2ba0 c5 18 CMP &18 ; player_x &2ba2 b0 f1 BCS &2b95 ; skip_firing # Don't fire if player is right of archer ; update_archer &2ba4 20 69 2c JSR &2c69 ; plot_enemy_bottom_right # Unplot archer &2ba7 a6 36 LDX &36 ; enemy_to_consider &2ba9 b4 25 LDY &25,X ; enemies_bottom_sprite &2bab c8 INY &2bac c4 c1 CPY &c1 ; bottom_sprite_facing_left &2bae d0 5a BNE &2c0a ; set_archer_sprite_and_continue # Don't fire until archer has pulled back bow &2bb0 bd c6 04 LDA &04c6,X ; enemies_y &2bb3 18 CLC &2bb4 69 10 ADC #&10 &2bb6 85 39 STA &39 ; projectiles_y + 1 &2bb8 bc c1 04 LDY &04c1,X ; enemies_type &2bbb b9 02 06 LDA &0602,Y ; enemy_top_sprite_table - 1 &2bbe 30 1d BMI &2bdd ; archer_facing_right &2bc0 85 3b STA &3b ; projectiles_sprite + 1 &2bc2 a9 00 LDA #&00 # Clear &80 to indicate projectile moving left &2bc4 85 4b STA &4b ; projectiles_direction_and_age + 1 &2bc6 a9 05 LDA #&05 &2bc8 85 cf STA &cf ; projectile_width &2bca b5 20 LDA &20,X ; enemies_x &2bcc 38 SEC &2bcd e5 cf SBC &cf ; projectile_width &2bcf 85 47 STA &47 ; projectiles_x + 1 &2bd1 20 18 2c JSR &2c18 ; subtract_0500_from_enemies_screen_address_into_Y_X # Move sixteen pixels up ; allow_space_for_projectile_loop &2bd4 20 7b 24 JSR &247b ; subtract_0008_from_screen_address_in_Y_X # Move two pixels left &2bd7 c6 cf DEC &cf ; projectile_width &2bd9 d0 f9 BNE &2bd4 ; allow_space_for_projectile_loop &2bdb f0 20 BEQ &2bfd ; set_arrow_screen_address # Always branches ; archer_facing_right &2bdd 29 7f AND #&7f &2bdf 85 3b STA &3b ; projectiles_sprite + 1 &2be1 a9 80 LDA #&80 # Set &80 to indicate projectile moving right &2be3 85 4b STA &4b ; projectiles_direction_and_age + 1 &2be5 b9 17 06 LDA &0617,Y ; enemy_width_table - 1 &2be8 18 CLC &2be9 69 02 ADC #&02 &2beb 85 cf STA &cf ; offset &2bed b5 20 LDA &20,X ; enemies_x &2bef 65 cf ADC &cf ; offset &2bf1 85 47 STA &47 ; projectiles_x + 1 &2bf3 20 18 2c JSR &2c18 ; subtract_0500_from_enemies_screen_address_into_Y_X # Move sixteen pixels up ; shift_loop &2bf6 20 49 24 JSR &2449 ; add_0008_to_screen_address_in_Y_X # Move two pixels right &2bf9 c6 cf DEC &cf ; offset &2bfb d0 f9 BNE &2bf6 ; shift_loop ; set_arrow_screen_address &2bfd 86 43 STX &43 ; projectiles_screen_address_high + 1 &2bff 84 3f STY &3f ; projectiles_screen_address_low + 1 &2c01 a0 01 LDY #&01 &2c03 20 94 2e JSR &2e94 ; plot_or_unplot_projectile_Y # Plot new arrow &2c06 a6 36 LDX &36 ; enemy_to_consider &2c08 a4 c0 LDY &c0 ; bottom_sprite ; set_archer_sprite_and_continue &2c0a 94 25 STY &25,X ; enemies_bottom_sprite &2c0c 98 TYA &2c0d a4 37 LDY &37 ; other_enemy_to_consider &2c0f 99 2e 04 STA &042e,Y ; enemies_sprite &2c12 20 23 2c JSR &2c23 ; plot_enemy_bottom_right_and_store_sprite_cropping &2c15 4c f1 29 JMP &29f1 ; consider_next_enemy ; subtract_0500_from_enemies_screen_address_into_Y_X &2c18 b4 2a LDY &2a,X ; enemies_screen_address_low &2c1a b5 2f LDA &2f,X ; enemies_screen_address_high &2c1c aa TAX &2c1d 20 8f 24 JSR &248f ; subtract_0280_from_screen_address_in_Y_X # Move eight pixels up &2c20 4c 8f 24 JMP &248f ; subtract_0280_from_screen_address_in_Y_X # Move eight pixels up ; plot_enemy_bottom_right_and_store_sprite_cropping &2c23 20 69 2c JSR &2c69 ; plot_enemy_bottom_right ; store_sprite_cropping &2c26 a4 37 LDY &37 ; other_enemy_to_consider &2c28 a5 35 LDA &35 ; sprite_column_address_high &2c2a 30 09 BMI &2c35 ; enemy_was_cropped_on_right_side # &80 if sprite was cropped on right side &2c2c d0 1a BNE &2c48 ; enemy_was_cropped_on_left_side # &00 if sprite was completely unplotted &2c2e a5 ba LDA &ba ; player_level &2c30 99 14 04 STA &0414,Y ; enemies_level &2c33 d0 24 BNE &2c59 ; leave # Always branches ; enemy_was_cropped_on_right_side &2c35 a5 ba LDA &ba ; player_level &2c37 49 80 EOR #&80 &2c39 99 14 04 STA &0414,Y ; enemies_level # &80 set if enemy cropped on right side &2c3c a5 51 LDA &51 ; sprite_address_low &2c3e 99 96 04 STA &0496,Y enemies_sprite_address_low &2c41 a5 52 LDA &52 ; sprite_address_high &2c43 99 b0 04 STA &04b0,Y ; enemies_sprite_address_high &2c46 d0 11 BNE &2c59 ; leave # Always branches ; enemy_was_cropped_on_left_side &2c48 a5 ba LDA &ba ; player_level &2c4a 49 40 EOR #&40 &2c4c 99 14 04 STA &0414,Y ; enemies_level # &40 set if enemy cropped on left side &2c4f a5 34 LDA &34 ; sprite_column_address_low &2c51 99 96 04 STA &0496,Y enemies_sprite_address_low &2c54 a5 35 LDA &35 ; sprite_column_address_high &2c56 99 b0 04 STA &04b0,Y ; enemies_sprite_address_high ; leave &2c59 60 RTS ; update_projectiles_twice_in_between_vsyncs &2c5a 20 cc 1e JSR &1ecc ; wait_for_vsync &2c5d 20 13 2d JSR &2d13 ; update_projectiles &2c60 20 cc 1e JSR &1ecc ; wait_for_vsync &2c63 20 cc 1e JSR &1ecc ; wait_for_vsync &2c66 4c 13 2d JMP &2d13 ; update_projectiles ; plot_enemy_bottom_right &2c69 a6 36 LDX &36 ; enemy_to_consider &2c6b b4 25 LDY &25,X ; enemies_bottom_sprite &2c6d bd cb 04 LDA &04cb,X ; enemies_direction # &80 if moving to left, &00 if moving to right &2c70 10 02 BPL &2c74 ; enemy_moving_right &2c72 c8 INY &2c73 c8 INY ; enemy_moving_right &2c74 84 cf STY &cf ; sprite &2c76 a4 37 LDY &37 ; other_enemy_to_consider &2c78 b9 62 04 LDA &0462,Y ; enemies_start_x &2c7b 85 1f STA &1f ; column_x &2c7d d5 20 CMP &20,X ; enemies_x &2c7f f0 0a BEQ &2c8b ; get_enemy_screen_address_and_plot_sprite_with_cropping &2c81 b4 2a LDY &2a,X ; enemies_screen_address_low &2c83 b5 2f LDA &2f,X ; enemies_screen_address_high &2c85 aa TAX &2c86 20 7b 24 JSR &247b ; subtract_0008_from_screen_address_in_Y_X # Move two pixels left &2c89 d0 05 BNE &2c90 ; to_plot_sprite_with_cropping ; get_enemy_screen_address_and_plot_sprite_with_cropping &2c8b b4 2a LDY &2a,X ; enemies_screen_address_low &2c8d b5 2f LDA &2f,X ; enemies_screen_address_high &2c8f aa TAX ; to_plot_sprite_with_cropping &2c90 98 TYA &2c91 a4 cf LDY &cf ; sprite &2c93 4c ad 23 JMP &23ad ; plot_sprite_with_cropping ; plot_enemy_top &2c96 a6 36 LDX &36 ; enemy_to_consider &2c98 bc c1 04 LDY &04c1,X ; enemies_type &2c9b b9 02 06 LDA &0602,Y ; enemy_top_sprite_table - 1 &2c9e a8 TAY &2c9f bd cb 04 LDA &04cb,X ; enemies_direction # &80 if moving to left, &00 if moving to right &2ca2 10 01 BPL &2ca5 ; enemy_moving_right &2ca4 c8 INY ; enemy_moving_right &2ca5 84 cf STY &cf ; sprite &2ca7 b5 20 LDA &20,X ; enemies_x &2ca9 85 1f STA &1f ; column_x &2cab b4 2a LDY &2a,X ; enemies_screen_address_low &2cad b5 2f LDA &2f,X ; enemies_screen_address_high &2caf aa TAX &2cb0 20 8f 24 JSR &248f ; subtract_0280_from_screen_address_in_Y_X # Move eight pixels up &2cb3 4c 90 2c JMP &2c90 ; to_plot_sprite_with_cropping ; plot_enemy_bottom_left &2cb6 a6 36 LDX &36 ; enemy_to_consider &2cb8 b5 25 LDA &25,X ; enemies_bottom_sprite &2cba 18 CLC &2cbb 69 03 ADC #&03 ; (ENEMY_FEET_LEFT - ENEMY_FEET_RIGHT) &2cbd 85 cf STA &cf ; sprite &2cbf a4 37 LDY &37 ; other_enemy_to_consider &2cc1 b9 62 04 LDA &0462,Y ; enemies_start_x &2cc4 85 1f STA &1f ; column_x &2cc6 38 SEC &2cc7 f5 20 SBC &20,X ; enemies_x &2cc9 f0 c0 BEQ &2c8b ; get_enemy_screen_address_and_plot_sprite_with_cropping &2ccb 85 ce STA &ce ; columns_to_add &2ccd b4 2a LDY &2a,X ; enemies_screen_address_low &2ccf b5 2f LDA &2f,X ; enemies_screen_address_high &2cd1 aa TAX ; add_columns_loop &2cd2 20 49 24 JSR &2449 ; add_0008_to_screen_address_in_Y_X # Move two pixels right &2cd5 c6 ce DEC &ce ; columns_to_add &2cd7 d0 f9 BNE &2cd2 ; add_columns_loop &2cd9 f0 b5 BEQ &2c90 ; to_plot_sprite_with_cropping # Always branches ; move_enemy_right &2cdb 20 03 2d JSR &2d03 ; get_enemy_screen_address &2cde 20 49 24 JSR &2449 ; add_0008_to_screen_address_in_Y_X # Move two pixels right &2ce1 20 0b 2d JSR &2d0b ; set_enemy_screen_address &2ce4 f6 20 INC &20,X ; enemies_x &2ce6 a6 37 LDX &37 ; other_enemy_to_consider ; increase_enemy_start_and_end_x &2ce8 fe 62 04 INC &0462,X ; enemies_start_x &2ceb fe 7c 04 INC &047c,X ; enemies_end_x &2cee 60 RTS ; move_enemy_left &2cef 20 03 2d JSR &2d03 ; get_enemy_screen_address &2cf2 20 7b 24 JSR &247b ; subtract_0008_from_screen_address_in_Y_X # Move two pixels left &2cf5 20 0b 2d JSR &2d0b ; set_enemy_screen_address &2cf8 d6 20 DEC &20,X ; enemies_x &2cfa a6 37 LDX &37 ; other_enemy_to_consider ; decrease_enemy_start_and_end_x &2cfc de 62 04 DEC &0462,X ; enemies_start_x &2cff de 7c 04 DEC &047c,X ; enemies_end_x &2d02 60 RTS ; get_enemy_screen_address &2d03 a6 36 LDX &36 ; enemy_to_consider &2d05 b4 2a LDY &2a,X ; enemies_screen_address_low &2d07 b5 2f LDA &2f,X ; enemies_screen_address_high &2d09 aa TAX &2d0a 60 RTS ; set_enemy_screen_address &2d0b 8a TXA &2d0c a6 36 LDX &36 ; enemy_to_consider &2d0e 95 2f STA &2f,X ; enemies_screen_address_high &2d10 94 2a STY &2a,X ; enemies_screen_address_low &2d12 60 RTS ; update_projectiles &2d13 a9 00 LDA #&00 &2d15 85 c2 STA &c2 ; projectile_to_consider ; update_horizontal_projectiles_loop # For projectiles 0 and 1, &2d17 a6 c2 LDX &c2 ; projectile_to_consider # i.e. player's spell and archer's arrow &2d19 b5 3a LDA &3a,X ; projectiles_sprite &2d1b f0 6a BEQ &2d87 ; consider_next_horizontal_projectile &2d1d 10 06 BPL &2d25 ; horizontal_projectile_is_not_exploding # &80 set if projectile is exploding &2d1f 20 6c 2e JSR &2e6c ; update_projectile_explosion # If so, update explosion animation &2d22 4c 87 2d JMP &2d87 consider_next_horizontal_projectile ; horizontal_projectile_is_not_exploding &2d25 20 92 2e JSR &2e92 ; plot_or_unplot_projectile &2d28 a6 c2 LDX &c2 ; projectile_to_consider &2d2a b5 4a LDA &4a,X ; projectiles_direction_and_age # &80 set if projectile is moving right &2d2c 30 1f BMI &2d4d ; projectile_moving_right ; projectile_moving_left &2d2e d6 46 DEC &46,X ; projectiles_x &2d30 ad 20 19 LDA &1920 ; edges_of_level_visible &2d33 10 04 BPL &2d39 ; level_occupies_part_of_screen # &80 if left edge of level visible &2d35 a9 00 LDA #&00 &2d37 f0 02 BEQ &2d3b ; level_occupies_all_of_screen # Always branches ; level_occupies_part_of_screen &2d39 a5 b2 LDA &b2 ; screen_left_x ; level_occupies_all_of_screen &2d3b 18 CLC &2d3c 69 08 ADC #&08 &2d3e d5 46 CMP &46,X ; projectiles_x # Is the projectile too close to left of screen? &2d40 b0 42 BCS &2d84 ; explode_horizontal_projectile # If so, explode it &2d42 b5 42 LDA &42,X ; projectiles_screen_address_high &2d44 b4 3e LDY &3e,X ; projectiles_screen_address_low &2d46 aa TAX &2d47 20 7b 24 JSR &247b ; subtract_0008_from_screen_address_in_Y_X # Otherwise, move it left two pixels &2d4a 4c 6b 2d JMP &2d6b ; store_updated_position ; projectile_moving_right &2d4d f6 46 INC &46,X ; projectiles_x &2d4f ad 20 19 LDA &1920 ; edges_of_level_visible &2d52 c9 01 CMP #&01 # &01 if right edge of level visible &2d54 d0 04 BNE &2d5a ; level_occupies_part_of_screen &2d56 a9 ff LDA #&ff &2d58 d0 02 BNE &2d5c ; level_occupies_all_of_screen # Always branches ; level_occupies_part_of_screen &2d5a a5 b3 LDA &b3 ; screen_right_x ; level_occupies_all_of_screen &2d5c 38 SEC &2d5d e9 0d SBC #&0d &2d5f d5 46 CMP &46,X ; projectiles_x # Has the projectile too close to right of the screen? &2d61 90 21 BCC &2d84 ; explode_horizontal_projectile # If so, explode it &2d63 b5 42 LDA &42,X ; projectiles_screen_address_high &2d65 b4 3e LDY &3e,X ; projectiles_screen_address_low &2d67 aa TAX &2d68 20 49 24 JSR &2449 ; add_0008_to_screen_address_in_Y_X # Otherwise, move it right two pixels ; store_updated_position &2d6b 8a TXA &2d6c a6 c2 LDX &c2 ; projectile_to_consider &2d6e 95 42 STA &42,X ; projectiles_screen_address_high &2d70 94 3e STY &3e,X ; projectiles_screen_address_low &2d72 b4 4a LDY &4a,X ; projectiles_direction_and_age &2d74 c8 INY &2d75 98 TYA &2d76 29 7f AND #&7f &2d78 c9 32 CMP #&32 &2d7a f0 08 BEQ &2d84 ; explode_horizontal_projectile # Explode the projectile after 50 frames &2d7c 94 4a STY &4a,X ; projectiles_direction_and_age &2d7e 20 92 2e JSR &2e92 ; plot_or_unplot_projectile &2d81 4c 87 2d JMP &2d87 ; consider_next_horizontal_projectile ; explode_horizontal_projectile &2d84 20 12 30 JSR &3012 ; explode_projectile ; consider_next_horizontal_projectile &2d87 e6 c2 INC &c2 ; projectile_to_consider &2d89 a5 c2 LDA &c2 ; projectile_to_consider &2d8b c9 02 CMP #&02 &2d8d d0 88 BNE &2d17 ; update_horizontal_projectiles_loop ; update_vertical_projectiles_loop # For projectiles 2 and 3, &2d8f a4 c2 LDY &c2 ; projectile_to_consider # i.e. birdman's swords &2d91 b9 3a 00 LDA &003a,Y ; projectiles_sprite &2d94 f0 44 BEQ &2dda ; consider_next_vertical_projectile &2d96 10 06 BPL &2d9e ; vertical_projectile_is_not_exploding # Top bit set if projectile is exploding &2d98 20 6c 2e JSR &2e6c ; update_projectile_explosion # If so, update explosion animation &2d9b 4c da 2d JMP &2dda ; consider_next_vertical_projectile ; vertical_projectile_is_not_exploding &2d9e 20 94 2e JSR &2e94 ; plot_or_unplot_projectile_Y &2da1 a4 c2 LDY &c2 ; projectile_to_consider &2da3 b6 42 LDX &42,Y ; projectiles_screen_address_high &2da5 b9 3e 00 LDA &003e,Y ; projectiles_screen_address_low &2da8 a8 TAY &2da9 20 31 24 JSR &2431 ; move_screen_address_in_Y_X_down_four_pixels &2dac 84 cc STY &cc ; screen_address_low &2dae 86 cd STX &cd ; screen_address_high &2db0 a0 00 LDY #&00 &2db2 b1 cc LDA (&cc),Y ; screen_address &2db4 c9 fc CMP #&fc ; (both pixels colour 14) # Has the projectile hit a platform? &2db6 f0 1f BEQ &2dd7 ; explode_vertical_projectile # If so, explode it &2db8 a4 c2 LDY &c2 ; projectile_to_consider &2dba a5 cc LDA &cc ; screen_address_low # Otherwise, move it down four pixels &2dbc 99 3e 00 STA &003e,Y ; projectiles_screen_address_low &2dbf a5 cd LDA &cd ; screen_address_high &2dc1 99 42 00 STA &0042,Y ; projectiles_screen_address_high &2dc4 b9 4a 00 LDA &004a,Y ; projectiles_direction_and_age &2dc7 38 SEC &2dc8 e9 04 SBC #&04 &2dca 99 4a 00 STA &004a,Y ; projectiles_direction_and_age &2dcd c9 14 CMP #&14 &2dcf 90 06 BCC &2dd7 ; explode_vertical_projectile # Explode the projectile just above platform &2dd1 20 94 2e JSR &2e94 ; plot_or_unplot_projectile_Y &2dd4 4c da 2d JMP &2dda ; consider_next_vertical_projectile ; explode_vertical_projectile &2dd7 20 12 30 JSR &3012 ; explode_projectile ; consider_next_vertical_projectile &2dda e6 c2 INC &c2 ; projectile_to_consider &2ddc a5 c2 LDA &c2 ; projectile_to_consider &2dde c9 04 CMP #&04 &2de0 90 ad BCC &2d8f ; update_vertical_projectiles_loop ; check_horizontal_projectile_for_collision_with_player &2de2 a5 3b LDA &3b ; projectiles_sprite + 1 # For projectile 1, archer's arrow &2de4 f0 1a BEQ &2e00 ; check_vertical_projectiles_for_collision_with_player &2de6 29 c0 AND #&c0 # Is the projectile exploding? &2de8 d0 16 BNE &2e00 ; check_vertical_projectiles_for_collision_with_player &2dea a6 39 LDX &39 ; projectiles_y + 1 &2dec 86 c0 STX &c0 ; y_min &2dee e8 INX &2def e8 INX &2df0 86 c1 STX &c1 ; y_max &2df2 a5 47 LDA &47 ; projectiles_x + 1 &2df4 85 c2 STA &c2 ; x_min &2df6 18 CLC &2df7 69 04 ADC #&04 &2df9 85 c3 STA &c3 ; x_max &2dfb 20 75 2f JSR &2f75 ; check_for_overlap_with_player &2dfe 30 20 BMI &2e20 ; leave # Don't check any more if projectile has hit player ; check_vertical_projectiles_for_collision_with_player &2e00 a2 02 LDX #&02 # For projectiles 2 and 3, birdman's swords ; check_vertical_projectiles_for_collision_with_player_loop &2e02 b5 3a LDA &3a,X ; projectiles_sprite &2e04 f0 15 BEQ &2e1b ; check_next_projectile &2e06 b5 4a LDA &4a,X ; projectiles_direction_and_age &2e08 85 c0 STA &c0 ; y_min &2e0a 18 CLC &2e0b 69 10 ADC #&10 &2e0d 85 c1 STA &c1 ; y_max &2e0f b4 46 LDY &46,X ; projectiles_x &2e11 84 c2 STY &c2 ; x_min &2e13 c8 INY &2e14 84 c3 STY &c3 ; x_max &2e16 20 75 2f JSR &2f75 ; check_for_overlap_with_player &2e19 30 05 BMI &2e20 ; leave # Don't check any more if projectile has hit player ; check_next_projectile &2e1b e8 INX &2e1c e0 04 CPX #&04 ; check_vertical_projectiles_for_collision_with_player &2e1e d0 e2 BNE &2e02 ; loop ; leave &2e20 60 RTS ; check_spell_for_collision_with_enemy &2e21 a5 3a LDA &3a ; projectiles_sprite # &18-&19 = CYAN, &1a-&1b = GREEN, &1c-&1d = MAGENTA &2e23 29 3e AND #&3e &2e25 38 SEC # &1 = CYAN, kills SWORDSMAN &2e26 e9 16 SBC #&16 # &2 = GREEN, kills AXEMAN &2e28 4a LSR A # &3 = MAGENTA, kills BARBARIAN &2e29 a2 04 LDX #&04 # Only consider enemy 4 &2e2b dd c1 04 CMP &04c1,X ; enemies_type &2e2e d0 39 BNE &2e69 ; leave_with_zero &2e30 86 36 STX &36 ; enemy_to_consider &2e32 86 37 STX &37 ; other_enemy_to_consider &2e34 20 5a 2f JSR &2f5a ; calculate_enemy_bounding_box &2e37 a5 38 LDA &38 ; projectiles_y &2e39 c5 c1 CMP &c1 ; y_max &2e3b b0 2c BCS &2e69 ; leave_with_zero &2e3d 18 CLC &2e3e 69 05 ADC #&05 &2e40 c5 c0 CMP &c0 ; y_min &2e42 90 25 BCC &2e69 ; leave_with_zero &2e44 a5 46 LDA &46 ; projectiles_x &2e46 c5 c3 CMP &c3 ; x_max &2e48 b0 1f BCS &2e69 ; leave_with_zero &2e4a 18 CLC &2e4b 69 04 ADC #&04 &2e4d c5 c2 CMP &c2 ; x_min &2e4f 90 18 BCC &2e69 ; leave_with_zero &2e51 20 15 2a JSR &2a15 ; plot_enemy &2e54 a9 96 LDA #&96 ; MATERIALISATION_4 | &80 # Dematerialise enemy &2e56 a2 04 LDX #&04 &2e58 9d c1 04 STA &04c1,X ; enemies_type &2e5b a9 00 LDA #&00 &2e5d 8d 18 04 STA &0418 ; enemies_level + 4 # Remove feet &2e60 8d 19 04 STA &0419 ; enemies_level + 5 # and head of enemy from level &2e63 20 c5 29 JSR &29c5 ; plot_enemy_materialisation &2e66 20 e1 30 JSR &30e1 ; increase_score ; leave_with_zero &2e69 a9 00 LDA #&00 &2e6b 60 RTS ; update_projectile_explosion &2e6c a4 c2 LDY &c2 ; projectile_to_consider &2e6e 20 94 2e JSR &2e94 ; plot_or_unplot_projectile_Y &2e71 a4 c2 LDY &c2 ; projectile_to_consider &2e73 b6 3a LDX &3a,Y ; projectiles_sprite &2e75 8a TXA &2e76 29 40 AND #&40 &2e78 d0 09 BNE &2e83 ; explosion_is_shrinking # &40 set if explosion is shrinking &2e7a e8 INX &2e7b e0 93 CPX #&93 ; EXPLOSION_4 + 1 | &80 &2e7d d0 0b BNE &2e8a ; set_sprite &2e7f a2 d2 LDX #&d2 ; EXPLOSION_4 | &c0 # Set explosion shrinking after four frames of growing &2e81 d0 07 BNE &2e8a ; set_sprite ; explosion_is_shrinking &2e83 ca DEX &2e84 e0 ce CPX #&ce ; EXPLOSION - 1 | &c0 &2e86 d0 02 BNE &2e8a ; set_sprite &2e88 a2 00 LDX #&00 # Remove explosion after four frames of shrinking ; set_sprite &2e8a 96 3a STX &3a,Y ; projectiles_sprite &2e8c f0 03 BEQ &2e91 ; leave &2e8e 4c 94 2e JMP &2e94 ; plot_or_unplot_projectile_Y &2e91 60 RTS ; plot_or_unplot_projectile &2e92 a4 c2 LDY &c2 ; projectile_to_consider ; plot_or_unplot_projectile_Y &2e94 b6 42 LDX &42,Y ; projectiles_screen_address_high &2e96 b9 3a 00 LDA &003a,Y ; projectiles_sprite &2e99 29 3f AND #&3f &2e9b 85 cf STA &cf ; sprite &2e9d b9 3e 00 LDA &003e,Y ; projectiles_screen_address_low &2ea0 a4 cf LDY &cf ; sprite &2ea2 4c 6d 23 JMP &236d ; plot_other_sprite ; consider_dropping_sword &2ea5 a0 02 LDY #&02 ; find_vertical_projectile_slot_loop # Consider projectiles 2 and 3 for new sword &2ea7 b9 3a 00 LDA &003a,Y ; projectiles_sprite &2eaa f0 06 BEQ &2eb2 ; found_a_free_slot &2eac c8 INY &2ead c0 04 CPY #&04 &2eaf 90 f6 BCC &2ea7 ; find_vertical_projectile_slot_loop ; leave &2eb1 60 RTS ; found_a_free_slot &2eb2 84 c2 STY &c2 ; slot &2eb4 a6 36 LDX &36 ; enemy_to_consider &2eb6 b5 20 LDA &20,X ; enemies_x &2eb8 c5 18 CMP &18 ; player_x &2eba d0 f5 BNE &2eb1 ; leave &2ebc 99 46 00 STA &0046,Y ; projectiles_x &2ebf bd c6 04 LDA &04c6,X ; enemies_y # Set projectile to explode just above platform &2ec2 38 SEC &2ec3 e9 10 SBC #&10 &2ec5 99 4a 00 STA &004a,Y ; projectiles_direction_and_age &2ec8 bc c1 04 LDY &04c1,X ; enemies_type &2ecb b9 02 06 LDA &0602,Y ; enemy_top_sprite_table - 1 &2ece a4 c2 LDY &c2 ; slot &2ed0 99 3a 00 STA &003a,Y ; projectiles_sprite &2ed3 b4 2a LDY &2a,X ; enemies_screen_address_low &2ed5 b5 2f LDA &2f,X ; enemies_screen_address_high &2ed7 aa TAX &2ed8 20 53 24 JSR &2453 ; add_0280_to_screen_address_in_Y_X # Move eight pixels down &2edb 20 53 24 JSR &2453 ; add_0280_to_screen_address_in_Y_X # Move eight pixels down &2ede 98 TYA &2edf a4 c2 LDY &c2 ; slot &2ee1 99 3e 00 STA &003e,Y ; projectiles_screen_address_low &2ee4 96 42 STX &42,Y ; projectiles_screen_address_high &2ee6 4c 94 2e JMP &2e94 ; plot_or_unplot_projectile_Y # Plot new sword ; check_for_enemy_hitting_player &2ee9 a9 00 LDA #&00 &2eeb 85 37 STA &37 ; other_enemy_to_consider ; check_for_enemy_hitting_player_loop &2eed a6 37 LDX &37 ; other_enemy_to_consider &2eef bc c1 04 LDY &04c1,X ; enemies_type &2ef2 f0 10 BEQ &2f04 ; no_collision # No collision if no enemy &2ef4 30 0e BMI &2f04 ; no_collision # No collision if enemy is materialising &2ef6 20 5a 2f JSR &2f5a ; calculate_enemy_bounding_box &2ef9 20 75 2f JSR &2f75 ; check_for_overlap_with_player # Top bit set if enemy overlaps with player &2efc f0 06 BEQ &2f04 ; no_collision &2efe c0 07 CPY #&07 &2f00 f0 0c BEQ &2f0e ; is_dragon &2f02 aa TAX &2f03 60 RTS ; no_collision &2f04 a6 37 LDX &37 ; other_enemy_to_consider &2f06 e8 INX &2f07 86 37 STX &37 ; other_enemy_to_consider &2f09 e0 05 CPX #&05 &2f0b d0 e0 BNE &2eed ; check_for_enemy_hitting_player_loop &2f0d 60 RTS ; is_dragon &2f0e a2 04 LDX #&04 &2f10 86 36 STX &36 ; enemy_to_consider &2f12 86 37 STX &37 ; other_enemy_to_consider ; check_for_sword_loop &2f14 8a TXA &2f15 d5 10 CMP &10,X ; pocket - 4 &2f17 d0 76 BNE &2f8f ; leave_with_top_bit_set # Kill player if pocket doesn't contain sword part &2f19 e8 INX &2f1a e0 07 CPX #&07 &2f1c d0 f6 BNE &2f14 ; check_for_sword_loop &2f1e 20 69 2c JSR &2c69 ; plot_enemy_bottom_right &2f21 a9 07 LDA #&07 ; DRAGON_HEAD # Reset to first frame of animation &2f23 85 29 STA &29 ; enemies_bottom_sprite + 4 &2f25 8d 32 04 STA &0432 ; enemies_sprite + 4 &2f28 20 69 2c JSR &2c69 ; plot_enemy_bottom_right &2f2b a2 70 LDX #&70 &2f2d a0 20 LDY #&20 ; SWORD_MIDDLE &2f2f a9 d3 LDA #&d3 &2f31 20 95 23 JSR &2395 ; plot_scenery_sprite_with_eor # Plot SWORD_MIDDLE at &70d3 &2f34 a2 70 LDX #&70 &2f36 a0 1f LDY #&1f ; SWORD_RIGHT &2f38 a9 f3 LDA #&f3 &2f3a 20 95 23 JSR &2395 ; plot_scenery_sprite_with_eor # Plot SWORD_RIGHT at &70f3 &2f3d a2 0e LDX #&0e &2f3f 8e 0d 04 STX &040d ; objects_level + 13 # Add SWORD_MIDDLE object in dragon &2f42 8e 0e 04 STX &040e ; objects_level + 14 # Add SWORD_RIGHT object in dragon &2f45 e8 INX &2f46 8e 0f 04 STX &040f ; objects_level + 15 # Add BRIDGE to level 15 &2f49 a9 00 LDA #&00 &2f4b 8d c5 04 STA &04c5 ; enemies_type + 4 # Stop DRAGON_HEAD from touching player &2f4e 85 14 STA &14 ; pockets # Empty pockets &2f50 85 15 STA &15 ; pockets + 1 &2f52 85 16 STA &16 ; pockets + 2 &2f54 20 bc 27 JSR &27bc ; plot_pockets &2f57 4c 62 01 JMP &0162 ; play_tune ; calculate_enemy_bounding_box &2f5a bc c1 04 LDY &04c1,X ; enemies_type &2f5d bd c6 04 LDA &04c6,X ; enemies_y &2f60 85 c0 STA &c0 ; y_min &2f62 18 CLC &2f63 79 10 06 ADC &0610,Y ; enemy_height_table - 1 &2f66 85 c1 STA &c1 ; y_max &2f68 b5 20 LDA &20,X ; enemies_x &2f6a 85 c2 STA &c2 ; x_min &2f6c 18 CLC &2f6d 79 17 06 ADC &0617,Y ; enemy_width_table - 1 &2f70 69 03 ADC #&03 &2f72 85 c3 STA &c3 ; x_max &2f74 60 RTS ; check_for_overlap_with_player &2f75 a5 19 LDA &19 ; player_y &2f77 c5 c1 CMP &c1 ; y_max &2f79 b0 17 BCS &2f92 ; no_overlap &2f7b 18 CLC &2f7c 69 1b ADC #&1b &2f7e c5 c0 CMP &c0 ; y_min &2f80 90 10 BCC &2f92 ; no_overlap &2f82 a5 18 LDA &18 ; player_x &2f84 c5 c3 CMP &c3 ; x_max &2f86 b0 0a BCS &2f92 ; no_overlap &2f88 18 CLC &2f89 69 04 ADC #&04 &2f8b c5 c2 CMP &c2 ; x_min &2f8d 90 03 BCC &2f92 ; no_overlap ; leave_with_top_bit_set &2f8f a9 80 LDA #&80 # &80 for overlap &2f91 60 RTS ; no_overlap &2f92 a9 00 LDA #&00 # &00 for no overlap &2f94 60 RTS ; cast_spell &2f95 a5 18 LDA &18 ; player_x &2f97 c9 f1 CMP #&f1 &2f99 b0 76 BCS &3011 ; leave # Can't fire spell if too close to right of level edge &2f9b c9 09 CMP #&09 &2f9d 90 72 BCC &3011 ; leave # Can't fire spell if too close to left of level edge &2f9f a5 3a LDA &3a ; projectiles_sprite &2fa1 d0 6e BNE &3011 ; leave # Can't fire spell if spell already being fired &2fa3 a5 14 LDA &14 ; pockets &2fa5 c9 01 CMP #&01 ; SPELL_GREEN &2fa7 d0 04 BNE &2fad ; not_green_spell &2fa9 a0 1a LDY #&1a ; SPELL_GREEN_RIGHT &2fab d0 0e BNE &2fbb ; fire_spell ; not_green_spell &2fad c9 02 CMP #&02 ; SPELL_CYAN &2faf d0 04 BNE &2fb5 ; not_cyan_spell &2fb1 a0 18 LDY #&18 ; SPELL_CYAN_RIGHT &2fb3 d0 06 BNE &2fbb ; fire_spell ; not_cyan_spell &2fb5 c9 03 CMP #&03 ; SPELL_MAGENTA &2fb7 d0 58 BNE &3011 ; leave &2fb9 a0 1c LDY #&1c ; SPELL_MAGENTA_RIGHT ; fire_spell &2fbb a5 19 LDA &19 ; player_y &2fbd 18 CLC &2fbe 69 10 ADC #&10 &2fc0 85 38 STA &38 ; projectiles_y &2fc2 a5 1c LDA &1c ; player_direction_and_velocity &2fc4 30 16 BMI &2fdc ; player_firing_left ; player_firing_right &2fc6 a9 80 LDA #&80 &2fc8 85 4a STA &4a ; projectiles_direction_and_age &2fca 84 3a STY &3a ; projectiles_sprite &2fcc a5 18 LDA &18 ; player_x &2fce 18 CLC &2fcf 69 04 ADC #&04 &2fd1 85 46 STA &46 ; projectiles_x &2fd3 a6 12 LDX &12 ; player_screen_address_high &2fd5 a4 13 LDY &13 ; player_screen_address_low &2fd7 20 71 24 JSR &2471 ; add_0020_to_screen_address_in_Y_X # Move eight pixels right &2fda d0 18 BNE &2ff4 ; set_spell_screen_address ; player_firing_left &2fdc c8 INY &2fdd 84 3a STY &3a ; projectiles_sprite &2fdf a5 18 LDA &18 ; player_x &2fe1 38 SEC &2fe2 e9 04 SBC #&04 &2fe4 85 46 STA &46 ; projectiles_x &2fe6 a9 00 LDA #&00 &2fe8 85 4a STA &4a ; projectiles_direction_and_age &2fea a6 12 LDX &12 ; player_screen_address_high &2fec a4 13 LDY &13 ; player_screen_address_low &2fee 20 85 24 JSR &2485 ; subtract_0010_from_screen_address_in_Y_X # Move two pixels left &2ff1 20 85 24 JSR &2485 ; subtract_0010_from_screen_address_in_Y_X # Move two pixels left ; set_spell_screen_address &2ff4 98 TYA &2ff5 38 SEC &2ff6 e9 04 SBC #&04 &2ff8 86 42 STX &42 ; projectiles_screen_address_high &2ffa 85 3e STA &3e ; projectiles_screen_address_low &2ffc 20 95 26 JSR &2695 ; plot_player_facing_left_or_right &2fff a9 1e LDA #&1e ; PLAYER_HEAD_CASTING_RIGHT &3001 85 1b STA &1b ; player_head_sprite &3003 20 95 26 JSR &2695 ; plot_player_facing_left_or_right &3006 a0 00 LDY #&00 &3008 20 94 2e JSR &2e94 ; plot_or_unplot_projectile_Y &300b 20 1b 30 JSR &301b ; play_explosion_sound &300e 20 26 2a JSR &2a26 ; update_enemies_and_projectiles ; leave &3011 60 RTS ; explode_projectile &3012 a6 c2 LDX &c2 ; projectile_to_consider &3014 a9 8f LDA #&8f ; EXPLOSION | &80 # &80 set to indicate projectile exploding &3016 95 3a STA &3a,X ; projectiles_sprite &3018 20 92 2e JSR &2e92 ; plot_or_unplot_projectile ; play_explosion_sound &301b a9 00 LDA #&00 ; sound_0 &301d 20 10 31 JSR &3110 ; play_sound &3020 a9 08 LDA #&08 ; sound_1 &3022 4c 10 31 JMP &3110 ; play_sound ; plot_character # Called with X = offset to character &3025 85 cd STA &cd ; text_mask # Used to determine which pixel of pair to plot &3027 8a TXA &3028 18 CLC &3029 69 05 ADC #&05 &302b c9 37 CMP #&37 # Numbers are five pixels wide, letters are six &302d 90 02 BCC &3031 ; is_number &302f 69 00 ADC #&00 ; is_number &3031 85 c7 STA &c7 ; character_end_offset ; plot_character_row_loop # Plot from left to right &3033 bd 83 3d LDA &3d83,X ; font_data # One byte of font data per eight pixel column &3036 85 cb STA &cb ; character_data &3038 a0 07 LDY #&07 ; plot_character_column_loop # Plot from top to bottom &303a a9 00 LDA #&00 &303c 26 cb ROL &cb ; character_data # Get bit of character data &303e 90 04 BCC &3044 ; pixel_unset &3040 a9 03 LDA #&03 # actually LDA text_colour &3042 25 cd AND &cd ; text_mask ; pixel_unset &3044 85 ca STA &ca ; pixel_values &3046 a5 cd LDA &cd ; text_mask # Plot pixel to screen &3048 49 ff EOR #&ff &304a 31 ce AND (&ce),Y ; character_screen_address &304c 45 ca EOR &ca ; pixel_values &304e 91 ce STA (&ce),Y ; character_screen_address &3050 88 DEY &3051 10 e7 BPL &303a ; plot_character_column_loop &3053 a5 cd LDA &cd ; text_mask &3055 49 ff EOR #&ff # Use other pixel &3057 85 cd STA &cd ; text_mask &3059 10 13 BPL &306e ; skip_group &305b a5 ce LDA &ce ; character_screen_address_low # If right pixel, move to next pair of pixels &305d 18 CLC &305e 69 08 ADC #&08 &3060 85 ce STA &ce ; character_screen_address_low &3062 90 02 BCC &3066 ; skip_page &3064 e6 cf INC &cf ; character_screen_address_high ; skip_page &3066 a5 cf LDA &cf ; character_screen_address_high &3068 10 04 BPL &306e ; skip_wraparound &306a a9 40 LDA #&40 &306c 85 cf STA &cf ; character_screen_address_high ; skip_wraparound ; skip_group &306e e8 INX &306f e4 c7 CPX &c7 ; character_end_offset &3071 d0 c0 BNE &3033 ; plot_character_row_loop &3073 60 RTS ; plot_lives &3074 a5 0c LDA &0c ; scrolled_screen_addresses + 8 &3076 85 cf STA &cf ; character_screen_address_high &3078 a5 0d LDA &0d ; scrolled_screen_addresses + 9 &307a 85 ce STA &ce ; character_screen_address_low &307c a9 aa LDA #&aa # Start with left pixel &307e ae 72 19 LDX &1972 ; lives_times_five &3081 20 25 30 JSR &3025 ; plot_character &3084 4c 87 30 JMP &3087 ; plot_lives_wipe_pixels # Unnecessary code ; wipe_column_of_pixels &3087 a0 07 LDY #&07 &3089 a9 00 LDA #&00 ; wipe_column_of_pixels_loop &308b 91 ce STA (&ce),Y ; character_screen_address # Wipe column of pixels to right of life counter &308d 88 DEY &308e 10 fb BPL &308b ; wipe_column_of_pixels &3090 60 RTS ; wipe_screen &3091 20 cc 1e JSR &1ecc ; wait_for_vsync &3094 a9 40 LDA #&40 &3096 8d 9f 30 STA &309f ; wipe_screen_address_high &3099 a0 00 LDY #&00 &309b a9 00 LDA #&00 ; wipe_screen_loop &309d 99 00 40 STA &4000,Y # Wipe &4000 - &7fff # actually STA wipe_screen_address,Y &30a0 c8 INY &30a1 d0 fa BNE &309d &30a3 ee 9f 30 INC &309f ; wipe_screen_address_high &30a6 10 f5 BPL &309d ; wipe_screen_loop &30a8 60 RTS ; plot_screen_of_text &30a9 86 c3 STX &c3 ; text_address_high &30ab 84 c2 STY &c2 ; text_address_low &30ad 20 91 30 JSR &3091 ; wipe_screen &30b0 20 05 23 JSR &2305 ; reset_screen_scroll &30b3 a0 00 LDY #&00 ; plot_screen_of_text_loop &30b5 b1 c2 LDA (&c2),Y ; text_address &30b7 85 ce STA &ce ; character_screen_address_low &30b9 c8 INY &30ba b1 c2 LDA (&c2),Y ; text_address &30bc 85 cf STA &cf ; character_screen_address_high &30be c8 INY &30bf b1 c2 LDA (&c2),Y ; text_address &30c1 8d 41 30 STA &3041 ; text_colour &30c4 c8 INY &30c5 a9 aa LDA #&aa # Start with left pixel &30c7 85 cd STA &cd ; text_mask ; plot_screen_of_text_line_loop &30c9 b1 c2 LDA (&c2),Y ; text_address &30cb c8 INY &30cc c9 fe CMP #&fe # &fe marks end of line &30ce f0 e5 BEQ &30b5 ; plot_screen_of_text_loop &30d0 c9 ff CMP #&ff # &ff marks end of text &30d2 d0 01 BNE &30d5 ; not_end_of_text &30d4 60 RTS ; not_end_of_text &30d5 84 c1 STY &c1 ; text_offset &30d7 aa TAX &30d8 a5 cd LDA &cd ; text_mask &30da 20 25 30 JSR &3025 ; plot_character &30dd a4 c1 LDY &c1 ; text_offset &30df d0 e8 BNE &30c9 ; plot_screen_of_text_line_loop ; increase_score &30e1 ad 6c 19 LDA &196c ; score &30e4 18 CLC &30e5 69 19 ADC #&19 ; 5 &30e7 8d 6c 19 STA &196c ; score &30ea a2 00 LDX #&00 &30ec a0 00 LDY #&00 ; increase_score_loop &30ee 98 TYA &30ef a0 00 LDY #&00 &30f1 18 CLC &30f2 7d 6c 19 ADC &196c,X ; score &30f5 c9 32 CMP #&32 &30f7 90 05 BCC &30fe ; not_nine &30f9 38 SEC &30fa e9 32 SBC #&32 &30fc a0 05 LDY #&05 ; not_nine &30fe 9d 6c 19 STA &196c,X ; score &3101 e8 INX &3102 e0 06 CPX #&06 &3104 90 e8 BCC &30ee ; increase_score_loop &3106 20 74 30 JSR &3074 ; plot_lives # Suggests that plot_lives once plotted score too ; play_materialisation_sound &3109 a9 18 LDA #&18 ; sound_3 &310b 20 10 31 JSR &3110 ; play_sound &310e a9 20 LDA #&20 ; sound_4 ; play_sound &3110 18 CLC &3111 69 80 ADC #&80 &3113 aa TAX &3114 a0 08 LDY #&08 ; &0880 = sound_0 &3116 a9 07 LDA #&07 ; Generate a sound (SOUND) &3118 6c 0c 02 JMP (&020c) ; OSWORD ; unused &311b 00 00 00 00 00 00 00 00 ; other_sprite_1e PLAYER_HEAD_CASTING_RIGHT &3123 bc 02 00 04 30 02 10 80 88 8c 05 04 84 8c 84 40 &3133 bc 02 00 b0 b1 b3 b0 80 03 15 80 88 04 0c 02 08 &3143 40 a8 02 00 a0 02 33 a0 02 01 88 aa 03 00 88 8c &3153 40 04 00 8a 8f 80 8f c0 ; other_sprite_1f PLAYER_HEAD_CASTING_LEFT &315b 04 00 85 8f 80 8f 40 94 02 00 90 02 33 90 02 02 &316b 84 95 03 00 84 8c 40 bc 02 00 b0 b2 b3 b0 80 03 &317b 2a 80 84 04 0c 02 04 40 bc 02 00 04 30 02 20 80 &318b 84 8c 06 08 8c 88 c0 ; other_sprite_1d SPELL_MAGENTA_LEFT &3192 81 83 81 40 83 b3 83 40 83 b3 83 40 82 8f c0 ; other_sprite_1c SPELL_MAGENTA_RIGHT &31a1 81 8f 40 83 b3 83 40 83 b3 83 40 82 83 82 c0 ; other_sprite_1b SPELL_GREEN_LEFT &31b0 85 8f 02 00 85 40 02 0f 85 02 0f 40 02 0f 8a 02 &31c0 0f 40 8a 02 00 02 0f c0 ; other_sprite_1a SPELL_GREEN_RIGHT &31c8 85 02 00 02 0f 40 02 0f 85 02 0f 40 02 0f 8a 02 &31d8 0f 40 8a 8f 02 00 8a c0 ; other_sprite_18 SPELL_CYAN_RIGHT &31e0 02 00 94 bc 94 40 94 04 3c bd 94 40 a8 02 3c 02 &31f0 3d be a8 40 02 00 03 28 c0 ; other_sprite_19 SPELL_CYAN_LEFT &31f9 80 94 bc 02 3d 94 40 05 3c bf bc 40 80 a8 03 3c &3209 a8 40 03 00 a8 c0 ; scenery_sprite_2f LIFE &320f ff 02 0f 80 03 05 8a 80 8a 02 0f 85 4c 04 00 8a &321f 05 0f 8a 85 03 0f 95 4b 02 05 80 95 02 1f 03 2a &322f 02 0f 95 03 2a 4e 02 2a 04 00 aa 80 03 2a c9 ; scenery_sprite_21 SWORD_LEFT &323e ff 03 00 85 8f af 95 09 00 49 02 00 85 03 0f af &324e 95 08 00 4a 02 00 8f 85 80 85 80 bf 08 00 4b 02 &325e 00 8f 04 05 bf 08 00 c9 ; scenery_sprite_20 SWORD_MIDDLE &3266 ff 02 00 8f 80 02 05 80 bf 08 00 4b 02 00 8f 85 &3276 02 0f 85 bf 08 00 4b 02 00 8f 80 02 05 80 bf 08 &3287 00 4b 02 00 8f 02 05 8f 85 bf 08 00 cb ; scenery_sprite_1f SWORD_LEFT &3293 ff 02 05 05 0a aa 85 95 06 00 4a 80 02 0a 04 1b &32a3 8a aa 07 00 4a 03 00 04 33 09 00 47 02 00 85 04 &32b3 27 95 08 00 c9 ; other_sprite_13 MATERIALISATION &32b8 0d 00 81 40 06 00 85 40 0a 00 81 0b 00 88 40 0f &32c8 00 85 8f 85 40 10 00 8a 40 0c 00 82 c0 ; other_sprite_14 MATERIALISATION_2 &32d5 0d 00 81 40 04 00 84 8c 84 05 00 82 83 82 40 03 &32e5 00 84 80 88 04 00 81 08 00 84 8c 84 40 80 84 03 &32f5 0c 84 80 85 06 00 85 8f 85 03 00 88 40 02 00 88 &3305 8c 88 80 8a 8f 8a 04 00 8a 03 0f 8a 40 0b 00 81 &3315 83 81 80 8a 40 0c 00 82 c0 ; other_sprite_15 MATERIALISATION_3 &331e 0c 00 81 83 81 40 05 00 84 05 00 82 03 03 82 06 &332e 00 82 40 03 00 84 02 00 81 02 00 81 83 81 80 82 &333e 80 85 03 00 84 8c 84 40 80 84 03 0c 84 04 00 82 &334e 02 00 85 03 0f 85 02 00 88 40 02 00 88 8c 88 80 &335e 85 8f 85 03 00 8a 05 0f 8a 02 00 81 40 03 00 81 &336e 80 8a 03 0f 8a 84 8c 84 80 8a 8f 8a 03 00 82 83 &337e 82 40 07 00 8a 03 00 88 c0 ; other_sprite_16 MATERIALISATION_4 &3387 04 00 84 8c 84 05 00 81 83 81 40 03 00 88 03 0c &3397 88 03 00 82 03 03 82 02 00 84 8c 84 40 03 00 84 &33a7 80 88 03 00 81 83 81 80 82 80 85 80 88 03 0c 88 &33b7 40 80 84 03 0c 84 80 85 02 00 82 02 00 85 03 0f &33c7 85 80 88 02 00 82 40 02 00 88 8c 88 85 03 0f 85 &33d7 02 00 8a 05 0f 8a 81 83 81 40 03 00 81 8a 05 0f &33e7 8a 03 00 8a 8f 8a 80 82 03 03 82 40 06 00 8a 8f &33f7 8a 0b 00 82 c0 ; scenery_sprite_2e TOWER &33fc ff 04 03 0b 01 36 00 06 01 02 03 03 01 04 00 02 &340c 01 83 03 02 80 81 03 03 03 01 5a 05 13 2d 03 10 &341c 01 03 03 06 13 02 22 03 13 07 03 03 02 80 0a 03 &342c 03 01 58 31 33 11 13 03 22 06 11 02 33 03 11 0a &343c 22 80 10 03 03 01 54 07 03 03 07 05 03 03 07 04 &344c 23 2b 33 04 22 05 00 a2 0f 33 80 16 03 03 01 59 &345c 07 03 03 0f 05 03 03 0f 07 03 02 23 21 33 02 22 &346c 0b 00 95 02 3f 05 33 02 11 b3 80 05 33 80 1c 03 &347c 03 01 63 06 03 8b 03 0f 8b 03 03 8b 03 0f 8b 09 &348c 03 a3 1d 33 a2 12 00 06 33 91 06 33 80 22 03 81 &349c 5e 08 03 8b 07 03 8b 0b 03 93 1d 33 91 12 00 06 &34ac 33 a2 06 33 80 22 03 82 58 19 03 02 13 21 33 02 &34bc 11 0b 00 aa 02 3f 05 33 02 22 b3 80 05 33 80 1c &34cc 03 03 02 5b 12 03 04 13 2b 33 04 11 05 00 91 0f &34dc 33 80 16 03 03 02 53 3f 33 03 33 03 11 06 22 02 &34ec 33 03 22 0a 11 80 10 03 03 02 54 32 33 10 22 09 &34fc 33 02 11 0a 33 03 11 80 0a 03 03 02 52 04 33 0b &350c 22 36 00 06 22 02 33 03 22 04 00 02 22 b3 03 11 &351c 80 82 03 03 03 02 da ; scenery_sprite_17 AXEMAN_HEAD_LEFT &3523 ff 0f 00 02 2a 04 3e 02 28 49 03 22 80 02 08 8c &3533 80 88 8c 80 07 22 a8 bc 80 03 28 52 94 80 91 80 &3543 02 0f 80 91 8f 80 8c 80 84 02 0c 84 85 84 02 14 &3553 55 bc 80 b3 91 8a 02 0f 85 a2 91 88 03 0c 03 0e &3563 9c 03 3c 95 54 bc 80 03 33 03 11 a2 02 00 88 02 &3573 3d 9d 84 8c 03 3d aa d3 ; scenery_sprite_16 AXEMAN_HEAD_RIGHT &357b ff bc 80 03 33 03 22 91 02 00 84 02 3e ae 88 8c &358b 03 3e 95 53 bc 80 b3 a2 85 02 0f 8a 91 a2 84 03 &359b 0c 03 0d ac 03 3c aa 54 a8 80 a2 80 02 0f 80 a2 &35ab 8f 80 8c 80 88 02 0c 88 8a 88 02 28 55 03 11 80 &35bb 02 04 8c 80 84 8c 80 07 11 94 bc 80 03 14 52 0f &35cb 00 02 15 04 3d 02 15 c9 ; scenery_sprite_0f SWORDSMAN_HEAD_LEFT &35d3 ff 09 00 94 44 02 00 a2 80 02 0a 8f 80 a8 bc 80 &35e3 0d 28 4e 94 80 81 80 02 0c 80 81 03 00 02 02 80 &35f3 81 80 02 14 52 bc 80 83 81 88 02 0c 84 82 81 02 &3603 00 03 02 94 03 3c 95 53 bc 80 03 03 03 01 82 02 &3613 00 06 3d 02 2a ce ; scenery_sprite_0e SWORDSMAN_HEAD_RIGHT &3619 ff bc 80 03 03 03 02 81 02 00 06 3e 02 15 4e bc &3629 80 83 82 84 02 0c 88 81 82 02 00 03 01 a8 03 3c &3639 aa 53 a8 80 82 80 02 0c 80 82 03 00 02 01 80 82 &3649 80 02 28 52 02 00 91 80 02 05 8f 80 94 bc 80 0d &3659 14 4e 09 00 a8 c4 ; scenery_sprite_25 ARCHER_RIGHT_2 &365f ff 03 05 80 03 01 80 81 02 00 04 01 80 02 04 02 &366f 0c 03 00 88 03 0c 80 02 0c 59 8f 8a 80 03 02 80 &367f 02 03 02 00 05 03 80 02 0d 8f 02 00 03 15 88 8c &368f 84 88 59 85 8f 8a 81 02 03 81 82 83 02 00 06 03 &369f 81 80 b3 80 02 01 80 aa 02 00 88 59 8a 05 00 91 &36af b3 91 b9 05 28 02 2c 02 28 b3 06 28 b9 91 b3 91 &36bf 55 09 00 03 22 b3 91 80 02 05 8f 80 be 03 11 b3 &36cf 03 22 d2 ; scenery_sprite_26 ARCHER_RIGHT_3 &36d2 ff 03 05 80 03 01 80 81 02 00 03 01 80 02 04 02 &36e2 0c 8d 03 00 88 03 0c 80 02 0c 5a 8f 8a 80 03 02 &36f2 80 02 03 02 00 03 03 02 16 80 02 0a 9b 80 94 03 &3702 15 88 8c 84 88 5b 85 8f 8a 81 02 03 81 82 83 80 &3712 94 96 02 29 03 03 81 80 b3 80 81 a9 a8 be 94 80 &3722 88 5c 8a 05 00 91 b3 02 39 05 00 02 0c 02 00 b3 &3732 06 00 02 39 b3 91 55 09 00 03 22 b3 91 80 02 05 &3742 8f 80 be 03 11 b3 03 22 d2 ; scenery_sprite_24 ARCHER_RIGHT &374b ff 03 05 80 03 01 80 81 02 00 05 01 80 03 04 03 &375b 00 88 03 0c 80 02 0c 57 8f 8a 80 03 02 80 02 03 &376b 02 00 03 03 81 89 88 02 0c 8d 02 00 03 15 88 8c &377b 84 88 5b 85 8f 8a 81 02 03 81 82 83 02 00 05 03 &378b 81 03 0a 80 02 01 80 aa 02 00 88 59 8a 05 00 91 &379b b3 91 b9 05 28 02 2c 09 28 b9 91 b3 91 52 09 00 &37ab 03 22 b3 91 80 02 05 8f 80 04 11 b3 03 22 d1 ; scenery_sprite_23 BARBARIAN_HEAD_LEFT &37ba ff 03 00 95 80 05 11 94 bc 80 0f 05 4c 05 00 02 &37ca 11 a2 91 a2 80 a8 4a 94 02 00 91 80 02 33 80 b3 &37da 03 00 02 33 80 91 02 33 95 02 01 55 bc 02 00 b3 &37ea 91 a2 02 33 91 a2 91 a2 05 33 02 2b 03 03 53 bc &37fa 02 00 03 33 03 11 b3 a2 81 02 23 06 03 02 02 d1 ; scenery_sprite_22 BARBARIAN_HEAD_RIGHT &380a ff bc 02 00 03 33 03 22 b3 91 82 02 13 06 03 02 &381a 01 51 bc 02 00 b3 a2 91 02 33 a2 91 a2 91 05 33 &382a 02 17 03 03 53 a8 02 00 a2 80 02 33 80 b3 03 00 &383a 02 33 80 a2 02 33 aa 02 02 55 05 00 02 22 91 a2 &384a 91 80 94 4a 03 00 aa 80 05 22 a8 bc 80 0f 0a cc ; scenery_sprite_1c ARCHER_LEFT &385a ff 0b 00 03 11 02 0a 8f 80 03 22 03 11 4d 85 08 &386a 00 02 22 80 02 28 02 39 02 28 02 29 03 28 80 02 &387a 22 54 8a 8f 8d 03 0c 88 84 8c 80 06 0c 84 02 00 &388a 02 15 bf 80 03 3c 02 14 57 8f 85 04 04 80 02 0c &389a 80 03 0c 88 91 02 1b 8f 80 03 15 04 3d 02 3e a8 &38aa 58 03 0a 04 08 80 88 80 04 08 80 03 22 80 07 28 &38ba d0 ; scenery_sprite_1d ARCHER_LEFT_2 &38bb ff 0b 00 03 11 02 0a 8f 80 bd 02 22 03 11 4e 85 &38cb 08 00 02 22 80 02 28 02 39 02 28 b3 a9 03 28 80 &38db 02 22 54 8a 8f 8d 03 0c 88 84 8c 80 05 0c 88 02 &38eb 05 a7 80 95 bf 80 03 3c 02 14 58 8f 85 04 04 80 &38fb 02 0c 80 03 0c 88 91 03 33 8a 03 15 04 3d 02 3e &390b a8 57 03 0a 04 08 80 88 80 04 08 80 02 22 02 00 &391b 07 28 d1 ; scenery_sprite_1e ARCHER_LEFT_3 &391e ff 0b 00 03 11 02 0a 8f 80 bd 02 22 03 11 4e 85 &392e 08 00 02 22 94 02 00 02 33 02 00 b3 81 03 00 94 &393e 02 22 54 8a 8f 8d 03 0c 88 84 8c 80 02 0c ac 9c &394e 02 0c 84 80 b3 02 15 be a8 94 02 3c 02 14 5c 8f &395e 85 04 04 80 02 0c 80 04 0c ac 88 8d 85 a7 94 a8 &396e 95 04 3d 02 3e a8 58 03 0a 04 08 80 88 80 04 08 &397e 80 a2 02 33 9b 80 06 28 d2 ; other_sprite_0e ARROW_LEFT &3987 80 bd 40 80 b3 40 80 b3 40 80 b3 40 8c 80 8c c0 ; other_sprite_0a ARROW_RIGHT &3997 8f 80 8f 40 80 b3 40 80 b3 40 80 b3 40 80 be c0 ; other_sprite_17 SWORD &39a7 0a 14 80 8f 80 03 11 40 0b 00 8a c0 ; scenery_sprite_1b BIRDMAN_LEFT_2 &39b3 ff 0a 00 8a 02 0f 85 47 0a 00 84 03 0c 88 9d 84 &39c3 49 05 00 03 04 05 19 02 2f bb 99 07 11 95 94 4f &39d3 8a 85 80 83 89 05 19 02 08 80 02 33 80 8c 95 9d &39e3 84 81 95 94 55 8f 02 00 02 06 a7 03 0e a7 80 02 &39f3 30 02 33 b0 8c 9c 8c 88 ae be bc bd 58 8a 85 8a &3a03 88 8e 8c 8d 05 0c 03 24 85 80 02 2a 88 8c 02 2a &3a13 54 05 00 02 08 80 8a 88 8d 02 0c 8d cc ; scenery_sprite_1a BIRDMAN_LEFT &3a20 ff 0b 00 8a 02 0f 85 47 0b 00 84 03 0c 88 9d 84 &3a30 49 06 00 84 02 11 03 19 02 0d 03 3b 99 05 11 95 &3a40 94 51 8a 85 80 83 89 05 19 02 08 02 33 02 00 8c &3a50 95 9d 84 81 95 94 55 8f 02 00 02 06 a7 03 0e a7 &3a60 80 b0 b2 02 33 b0 8c 9c 8c 88 ae be bc bd 58 8a &3a70 85 8a 88 8e 8c 8d 8c 8e 02 0c 04 20 02 00 02 2a &3a80 88 8c 02 2a 56 05 00 8a 88 8d 8c 8d 88 c9 ; scenery_sprite_19 BIRDMAN_RIGHT_2 &3a8e ff 05 00 02 04 80 85 84 8e 02 0c 8e 4c 85 8a 85 &3a9e 84 8d 8c 8e 05 0c 03 18 8a 80 02 15 84 8c 02 15 &3aae 54 8f 02 00 02 09 9b 03 0d 9b 80 02 30 02 33 b0 &3abe 8c ac 8c 84 9d bd bc be 58 85 8a 80 83 86 05 26 &3ace 02 04 80 02 33 80 8c aa ae 88 82 aa a8 55 05 00 &3ade 03 08 05 26 02 1f b7 a6 07 22 aa a8 4f 0a 00 88 &3aee 03 0c 84 ae 88 49 0a 00 85 02 0f 8a c7 ; scenery_sprite_18 BIRDMAN_RIGHT &3afb ff 05 00 85 84 8e 8c 8e 84 49 85 8a 85 84 8d 8c &3b0b 8e 8c 8d 02 0c 04 10 02 00 02 15 84 8c 02 15 56 &3b1b 8f 02 00 02 09 9b 03 0d 9b 80 b0 b1 02 33 b0 8c &3b2b ac 8c 84 9d bd bc be 58 85 8a 80 83 86 05 26 02 &3b3b 04 02 33 02 00 8c aa ae 88 82 aa a8 55 06 00 88 &3b4b 02 22 03 26 02 0e 03 37 a6 05 22 aa a8 51 0b 00 &3b5b 88 03 0c 84 ae 88 49 0b 00 85 02 0f 8a c7 ; scenery_sprite_2a SCROLL_MAGENTA &3b69 ff 91 02 27 a2 08 00 03 11 80 4a 8f 02 1b 91 a2 &3b79 a7 06 11 80 02 0f a7 4d a2 80 03 11 9b 80 8f 8a &3b89 8f 80 8f 03 22 9b 4f 06 00 09 22 80 c6 ; scenery_sprite_29 SCROLL_CYAN &3b96 ff 94 02 3d a8 08 00 03 14 80 4a bf 02 3e 94 a8 &3ba6 be 06 14 80 02 3f 95 4d a8 80 03 14 be 80 bf be &3bb6 bf 80 bf 03 28 be 4f 06 00 09 28 80 c6 ; scenery_sprite_28 SCROLL_GREEN &3bc3 ff 84 02 0d 88 08 00 03 04 80 4a 8f 02 0e 84 88 &3bd3 8e 06 04 80 02 0f 8d 4d 88 80 03 04 8e 80 8f 8a &3be3 8f 80 8f 03 08 8e 4f 06 00 09 08 80 c6 ; scenery_sprite_27 POTION &3bf0 ff 0b 04 05 00 45 8c 03 0e 04 30 02 0e 8d 8c 80 &3c00 94 02 3c 4e 04 0c 04 24 03 0c 88 02 00 02 28 4c &3c10 10 00 c3 ; other_sprite_0f EXPLOSION &3c13 40 07 00 02 04 40 05 00 84 8d 02 0f 8d 84 40 06 &3c23 00 88 02 0e 88 c0 ; other_sprite_10 EXPLOSION_2 &3c29 40 02 00 84 04 0d 02 04 02 0d 02 04 40 02 00 88 &3c39 8e 02 0f 03 0e 03 0f 8e 88 40 02 00 8c 03 0f 02 &3c49 0e 03 0f 8d 84 40 03 00 03 08 02 00 04 08 c0 ; other_sprite_11 EXPLOSION_3 &3c58 04 00 03 04 02 00 03 04 40 80 84 02 0d 03 0f 02 &3c68 0d 03 0f 8d 84 40 02 00 88 8e 8f 8e 04 0d 8e 02 &3c78 0f 8e 88 40 80 84 8d 04 0f 02 0d 03 0f 8d 84 40 &3c88 02 00 88 03 0e 02 08 04 0e 88 c0 ; other_sprite_12 EXPLOSION_4 &3c93 02 00 03 04 05 0d 03 04 40 84 8d 8f 02 0e 05 0d &3ca3 02 0e 8f 8d 84 40 80 88 8e 0b 0f 8e 88 40 84 8d &3cb3 03 0f 8d 04 0e 8d 02 0f 8d 84 40 80 88 03 0e 04 &3cc3 0f 03 0e 02 08 40 05 00 04 08 c0 ; other_sprite_0d PLAYER_CLIMBING_2 &3cce 02 00 84 8c 98 90 09 00 02 11 9b 8a 02 00 84 40 &3cde 02 00 02 08 a0 80 94 03 3c 02 00 03 30 02 32 b0 &3cee 80 84 02 0c 02 04 40 05 00 04 3c 02 00 06 30 02 &3cfe 00 07 0c 02 04 40 02 0c 02 30 90 80 a8 03 3c 02 &3d0e 00 03 30 02 31 b0 80 02 0c 88 80 84 8c 88 40 80 &3d1e 02 08 0b 00 02 27 a2 03 00 88 c0 ; other_sprite_0c PLAYER_CLIMBING &3d29 80 02 04 0b 00 02 1b 91 04 00 84 40 02 0c 02 30 &3d39 a0 80 94 03 3c 02 00 03 30 02 32 b0 80 84 02 0c &3d49 02 04 40 05 00 04 3c 02 00 06 30 02 00 07 0c 02 &3d59 04 40 02 00 02 04 90 80 a8 03 3c 02 00 03 30 02 &3d69 31 b0 80 02 0c 88 80 84 8c 88 40 02 00 88 8c a4 &3d79 a0 09 00 02 22 a7 85 80 88 c0 ; font_data &3d83 7e c3 c3 7e 00 ; "0" &3d88 00 c6 ff c0 00 ; "1" &3d8d e6 f3 db ce 00 ; "2" &3d92 66 c3 db 7e 00 ; "3" &3d97 3e 33 f8 30 00 ; "4" &3d9c 6f cb db 73 00 ; "5" &3da1 7e db d3 76 00 ; "6" &3da6 03 e3 3b 0f 00 ; "7" &3dab 76 cb cb 76 00 ; "8" &3db0 1e 33 33 fe 00 ; "9" &3db5 fe 33 33 33 fe 00 ; "A" &3dbb 7e cb cb cb 76 00 ; "B" &3dc1 7e c3 c3 c3 66 00 ; "C" &3dc7 ff c3 c3 c3 7e 00 ; "D" &3dcd 7e db db c3 66 00 ; "E" &3dd3 fe 33 33 33 06 00 ; "F" &3dd9 7e c3 d3 d3 76 00 ; "G" &3ddf ff 18 18 18 ff 00 ; "H" &3de5 c3 c3 ff c3 c3 00 ; "I" &3deb 63 c3 c3 7f 03 00 ; "J" &3df1 ff 18 3c 66 c3 00 ; "K" &3df7 ff c0 c0 c0 c0 00 ; "L" &3dfd fe 07 1c 07 fe 00 ; "M" &3d03 ff 03 03 03 fe 00 ; "N" &3d09 7e c3 c3 c3 7e 00 ; "O" &3d0f fe 33 33 33 1e 00 ; "P" &3d15 7e c3 a3 43 be 00 ; "Q" &3d1b fe 13 13 33 ce 00 ; "R" &3d21 66 cb cb d3 76 00 ; "S" &3d27 03 03 ff 03 03 00 ; "T" &3d2d 7f c0 c0 c0 7f 00 ; "U" &3d33 07 3c e0 3c 07 00 ; "V" &3d39 7f e0 38 e0 7f 00 ; "W" &3d3f c3 24 18 24 c3 00 ; "X" &3d45 67 cc cc cc 7f 00 ; "Y" &3d4b e3 f3 db cf c7 00 ; "Z" &3d51 66 66 66 66 66 66 ; "=" &3d57 00 00 00 00 00 00 ; " " &3d5d 7e c3 bd a5 c3 7e ; "c" &3d63 00 00 e0 e0 00 00 ; "." ; other_sprite_00 PLAYER_HEAD_RIGHT &3e69 bc 02 00 03 30 02 10 02 00 88 8c 05 04 84 8c 84 &3e79 40 bc 02 00 b1 02 33 02 32 a0 03 00 88 05 0c 88 &3e89 40 a8 02 00 02 27 03 20 80 aa ae bf 02 00 88 8c &3e99 40 06 00 80 02 02 c0 ; other_sprite_01 PLAYER_HEAD_RIGHT_2 &3ea0 bc 02 00 b0 b1 02 33 91 90 80 88 8c 05 04 84 8c &3eb0 84 40 bc 02 00 02 1a 02 30 b2 a2 03 00 88 05 0c &3ec0 88 40 a8 02 00 05 20 80 aa ae bf 02 00 88 8c 40 &3ed0 04 00 02 0a 80 02 02 c0 ; other_sprite_02 PLAYER_HEAD_LEFT &3ed8 07 00 02 01 40 94 02 00 02 1b 03 10 80 95 9d bf &3ee8 02 00 84 8c 40 bc 02 00 b2 02 33 02 31 90 03 00 &3ef8 84 05 0c 84 40 bc 02 00 03 30 02 20 02 00 84 8c &3f08 06 08 8c 88 c0 ; other_sprite_03 PLAYER_HEAD_LEFT_2 &3f0d 04 00 02 05 80 02 01 40 94 02 00 05 10 80 95 9d &3f1d bf 02 00 84 8c 40 bc 02 00 02 25 02 30 b1 91 03 &3f2d 00 84 05 0c 84 40 bc 02 00 b0 b2 02 33 a2 a0 80 &3f3d 84 8c 06 08 8c 88 c0 ; scenery_sprite_11 ENEMY_FEET_RIGHT_2 &3f44 ff ; other_sprite_04 PLAYER_FEET_RIGHT &3f45 84 8c 02 18 45 88 80 a0 b0 a0 80 94 bc 49 05 00 &3f55 a8 02 3c 46 03 00 90 b0 90 80 a8 48 02 00 88 8c &3f65 a4 02 04 c8 ; scenery_sprite_10 ENEMY_FEET_RIGHT &3f69 ff ; other_sprite_06 PLAYER_FEET_RIGHT_3 &3f6a 02 0c 02 30 a0 80 94 bc 49 88 84 02 10 80 a8 02 &3f7a 3c 49 8c 88 03 20 02 00 a8 c8 ; scenery_sprite_12 ENEMY_FEET_RIGHT_3 &3f84 ff ; other_sprite_05 PLAYER_FEET_RIGHT_2 &3f85 80 84 8c 02 18 88 47 02 00 03 20 80 94 bc 48 02 &3f95 0c 02 30 90 a8 02 3c 49 88 06 00 a8 c5 ; scenery_sprite_14 ENEMY_FEET_LEFT_2 &3fa2 ff ; other_sprite_07 PLAYER_FEET_LEFT &3fa3 02 00 84 8c 98 02 08 48 03 00 a0 b0 a0 80 94 48 &3fb3 05 00 94 02 3c 46 84 80 90 b0 90 80 a8 bc 49 88 &3fc3 8c 02 24 c5 ; scenery_sprite_13 ENEMY_FEET_LEFT &3fc7 ff ; other_sprite_09 PLAYER_FEET_LEFT_3 &3fc8 8c 84 03 10 02 00 94 48 84 88 02 20 80 94 02 3c &3fd8 49 02 0c 02 30 90 80 a8 bc c9 ; scenery_sprite_15 ENEMY_FEET_LEFT_3 &3fe2 ff ; other_sprite_08 PLAYER_FEET_LEFT_2 &3fe3 84 06 00 94 45 02 0c 02 30 a0 94 02 3c 49 02 00 &3ff3 03 10 80 a8 bc 48 80 88 8c 02 24 84 c7 ; original_entry_point # Presumably original entry point before protection &4000 a9 8c LDA #&8c ; Select Tape FS &4002 20 f4 ff JSR &fff4 ; OSBYTE &4005 a2 ff LDX #&ff &4007 9a TXS &4008 a2 15 LDX #&15 ; move_game_over_text_loop &400a bd 47 42 LDA &4247,X ; unrelocated_game_over_text # Move &4247 - &425c to &03c9 - &03de &400d 9d c9 03 STA &03c9,X ; game_over_text &4010 ca DEX &4011 10 f7 BPL &400a ; move_game_over_text_loop &4013 a2 58 LDX #&58 ; move_plot_column_of_sprite_loop &4015 bd 3d 41 LDA &413d,X ; unrelocated_plot_column_of_sprite # Move &413d - &4195 to &0050 - &00a8 &4018 95 50 STA &50,X ; plot_column_of_sprite &401a ca DEX &401b 10 f8 BPL &4015 ; move_plot_column_of_sprite_loop &401d a2 00 LDX #&00 ; move_tune_data_and_code_loop &401f bd 96 41 LDA &4196,X ; unrelocated_tune_data_and_code # Move &4196 - &4246 to &0100 - &01b0 &4022 9d 00 01 STA &0100,X ; tune_data_and_code &4025 e8 INX &4026 e0 b1 CPX #&b1 &4028 d0 f5 BNE &401f ; move_tune_data_and_code_loop ; initialise_mode # Change to MODE 2 without clearing screen memory &402a a9 02 LDA #&02 ; MODE 2 &402c 48 PHA # The code at &402c - &40fd is identical to &402d a2 7f LDX #&7f # the code at &cb2d - &cb3f in the OS 1.20 ROM &402f a9 00 LDA #&00 &4031 85 d0 STA &d0 ; os_vdu_status # Clear VDU status byte ; wipe_os_vdu_workspace &4033 9d ff 02 STA &02ff,X ; os_vdu_workspace - 1 # Wipe &0300 - &037e, OS VDU workspace &4036 ca DEX &4037 d0 fa BNE &4033 ; wipe_os_vdu_workspace &4039 20 07 cd JSR &cd07 ; os_osbyte_20 (&14) # Set characters &80 to &9f as redefineable &403c 68 PLA &403d a2 7f LDX #&7f &403f 8e 66 03 STX &0366 ; Teletext output cursor character &4042 2c 8e 02 BIT &028e ; Available RAM &4045 30 02 BMI &4049 ; use_all_modes # Always branches on a 32k machine &4047 09 04 ORA #&04 ; use_all_modes &4049 29 07 AND #&07 &404b aa TAX &404c 8e 55 03 STX &0355 ; os_mode &404f bd 14 c4 LDA &c414,X ; os_rom_colours_per_mode_table &4052 8d 60 03 STA &0360 ; os_colours_available &4055 bd ff c3 LDA &c3ff,X ; os_rom_bytes_per_mode_table &4058 8d 4f 03 STA &034f ; os_bytes_per_character &405b bd 3a c4 LDA &c43a,X ; os_rom_pixels_per_bute_per_mode_table &405e 8d 61 03 STA &0361 ; os_pixels_per_byte &4061 d0 02 BNE &4065 ; not_mode_7 # Always branches &4063 a9 07 LDA #&07 ; not_mode_7 &4065 0a ASL A &4066 a8 TAY &4067 b9 06 c4 LDA &c406,Y ; os_rom_mask_table &406a 8d 63 03 STA &0363 ; os_right_colour_mask ; shift_loop &406d 0a ASL A &406e 10 fd BPL &406d ; shift_loop &4070 8d 62 03 STA &0362 ; os_left_colour_mask &4073 bc 40 c4 LDY &c440,X ; os_rom_screen_memory_type_per_mode_table &4076 8c 56 03 STY &0356 ; os_screen_memory_type &4079 b9 4f c4 LDA &c44f,Y ; os_rom_via_scroll_per_mode_table &407c 20 f8 e9 JSR &e9f8 ; os_rom_write_to_via_register_B # Writes A to &fe40, system VIA port B input/ouput register &407f b9 4b c4 LDA &c44b,Y ; os_rom_crtc_setup_parameters_1_table &4082 20 f8 e9 JSR &e9f8 ; os_rom_write_to_via_register_B &4085 b9 59 c4 LDA &c459,Y ; os_rom_screen_memory_size_per_mode_table &4088 8d 54 03 STA &0354 ; os_screen_memory_size &408b b9 5e c4 LDA &c45e,Y ; os_rom_screen_memory_high_byte_per_mode_table &408e 8d 4e 03 STA &034e ; os_screen_memory_high_byte &4091 98 TYA &4092 69 02 ADC #&02 &4094 49 07 EOR #&07 &4096 4a LSR A &4097 aa TAX &4098 bd 66 c4 LDA &c466,X ; os_rom_row_multiplication_table &409b 85 e0 STA &e0 ; os_row_multiplication_table_low &409d a9 c3 LDA #&c3 &409f 85 e1 STA &e1 ; os_row_multiplication_table_high &40a1 bd 63 c4 LDA &c463,X ; os_rom_bytes_per_row_table &40a4 8d 52 03 STA &0352 ; os_bytes_per_line &40a7 8e 53 03 STX &0353 ; os_other_bytes_per_line &40aa a9 43 LDA #&43 &40ac 20 a8 c5 JSR &c5a8 ; os_write_to_os_vdu_status # Writes A to &d0, os_vdu_status &40af ae 55 03 LDX &0355 ; os_mode &40b2 bd f7 c3 LDA &c3f7,X ; os_rom_video_ula_control_register_table &40b5 20 00 ea JSR &ea00 ; os_write_to_video_ula # Writes A to &0248 and &fe20, video ULA control register &40b8 08 PHP &40b9 78 SEI &40ba be 69 c4 LDX &c469,Y ; os_rom_crtc_cursor_end_table &40bd a0 0b LDY #&0b ; write_video_registers_loop &40bf bd 6e c4 LDA &c46e,X ; os_rom_video_registers_table &40c2 20 5e c9 JSR &c95e ; os_write_to_video_register # Write Y to &fe00, A to &fe01, video registers &40c5 ca DEX &40c6 88 DEY &40c7 10 f6 BPL &40bf ; write_video_registers_loop &40c9 28 PLP &40ca 20 39 c8 JSR &c839 ; os_vdu_20 # Restore default colours &40cd 20 bd c9 JSR &c9bd ; os_vdu_26 # Set default windows &40d0 a2 00 LDX #&00 &40d2 ad 4e 03 LDA &034e ; os_screen_memory_high_byte &40d5 8e 50 03 STX &0350 ; os_screen_start_address_low &40d8 8d 51 03 STA &0351 ; os_screen_start_address_high &40db 20 f6 c9 JSR &c9f6 ; os_set_text_cursor_address # Writes X to &034a, A to &034b, os_text_cursor_address &40de a0 0c LDY #&0c &40e0 20 2b ca JSR &ca2b ; os_write_to_video_registers_14_and_15 # Write A, X to registers 14, 15, text cursor address &40e3 ad 58 03 LDA &0358 ; os_background_text_colour &40e6 ae 56 03 LDX &0356 ; os_screen_memory_type &40e9 bc 54 c4 LDY &c454,X ; os_rom_vdu_section_control_numbers &40ec 8c 5d 03 STY &035d ; vdu_vector_low &40ef a0 cc LDY #&cc &40f1 8c 5e 03 STY &035e ; vdu_vector_high &40f4 a2 00 LDX #&00 &40f6 8e 69 02 STX &0269 ; os_lines_since_last_page &40f9 8e 18 03 STX &0318 ; os_text_cursor_x &40fc 8e 19 03 STX &0319 ; os_text_cursor_y # The OS ROM code jumps to (&035d) to clear screen here ; customise_mode &40ff a9 06 LDA #&06 # R6: Vertical displayed register &4101 8d 00 fe STA &fe00 ; video register number &4104 a9 19 LDA #&19 # Set screen to be 25 characters (200 pixels) high &4106 8d 01 fe STA &fe01 ; video register value &4109 a9 07 LDA #&07 # R7: Vertical sync position &410b 8d 00 fe STA &fe00 ; video register number &410e a9 20 LDA #&20 &4110 8d 01 fe STA &fe01 ; video register value &4113 a9 0f LDA #&0f # Set PB0-3 as outputs, PB4-7 as input (OS defaults) &4115 8d 42 fe STA &fe42 ; System VIA data direction register B &4118 a9 04 LDA #&04 # B4 = 0 &411a 8d 40 fe STA &fe40 ; System VIA port B input/ouput register &411d a9 05 LDA #&05 # B5 = 0; set size of screen to be &4000 for scrolling &411f 8d 40 fe STA &fe40 ; System VIA port B input/ouput register &4122 a9 0a LDA #&0a ; Set duration of second flash colour &4124 a2 00 LDX #&00 ; hold flash still # Disable flashing colours &4126 20 f4 ff JSR &fff4 ; OSBYTE &4129 a9 0c LDA #&0c # R12: Displayed screen start address register (high) &412b 8d 00 fe STA &fe00 ; video register number &412e a9 08 LDA #&08 # Set screen scroll position to &4000 &4130 8d 01 fe STA &fe01 ; video register value &4133 4c 4f 1f JMP &1f4f ; start_screen ; unused &4136 00 00 00 00 00 00 00 # &413d - &4195 copied to &0050 - &00a8 at &4448 or &4015 ; plot_column_of_sprite &0050 b9 ff ff LDA &ffff,Y # Get byte of sprite data, consider top two bits # actually LDA sprite_address,Y &0053 aa TAX &0054 29 40 AND #&40 &0056 d0 4a BNE &00a2 ; end_of_column # If &40 set, this is the end of a column &0058 8a TXA &0059 10 06 BPL &0061 ; repeated_run &005b 29 7f AND #&7f # If &80 set, bottom five bits are pixel values, &005d a2 01 LDX #&01 # run length 1 &005f d0 04 BNE &0067 ; plot_run ; repeated_run &0061 aa TAX # If &c0 unset, bottom five bits are run length &0062 c8 INY &0063 b1 51 LDA (&51),Y ; sprite_address # Get second byte of sprite data for pixel values &0065 85 6f STA &6f ; pixel_values ; plot_run &0067 c8 INY &0068 84 cd STY &cd ; rle_data_length &006a a0 00 LDY #&00 ; plot_run_loop # X is the length of the run &006c b1 71 LDA (&71),Y ; column_screen_address ; plotting_mode &006e 49 ff EOR #&ff # actually EOR pixel_values # EOR pixel values onto screen # or LDA pixel_values # or write pixels when plotting pockets &0070 8d ee ee STA &eeee # actually STA column_screen_address &0073 a5 71 LDA &71 ; column_screen_address_low &0075 29 07 AND #&07 &0077 f0 09 BEQ &0082 ; move_up_a_group &0079 c6 71 DEC &71 ; column_screen_address_low ; consider_next_row &007b ca DEX &007c d0 ee BNE &006c ; plot_run_loop # Is this the end of this run? &007e a4 cd LDY &cd ; rle_data_length &0080 d0 ce BNE &0050 ; plot_column_of_sprite # Always branches ; move_up_a_group &0082 c6 72 DEC &72 ; column_screen_address_high # Move up eight pixels on screen &0084 c6 72 DEC &72 ; column_screen_address_high &0086 a5 71 LDA &71 ; column_screen_address_low &0088 38 SEC &0089 e9 79 SBC #&79 &008b 85 71 STA &71 ; column_screen_address_low &008d b0 02 BCS &0091 ; not_page &008f c6 72 DEC &72 ; column_screen_address_high ; not_page &0091 a5 72 LDA &72 ; column_screen_address_high &0093 38 SEC &0094 c9 40 CMP #&40 # Wrap back to end of screen memory if necessary &0096 b0 e3 BCS &007b ; consider_next_row &0098 18 CLC &0099 a5 72 LDA &72 ; column_screen_address_high &009b 69 40 ADC #&40 &009d 85 72 STA &72 ; column_screen_address_high &009f 4c 7b 00 JMP &007b ; consider_next_row ; end_of_column &00a2 8a TXA &00a3 30 03 BMI &00a8 ; leave # Leave if top two bits of sprite data are &c0 &00a5 4c 2e 23 JMP &232e ; plot_next_column_of_sprite ; leave &00a8 60 RTS # &4196 - &4246 copied to &0100 - &01b0 at &4452 or &401f ; tune_data_and_code ; tune_channel1_data &0100 51 59 00 51 65 00 65 61 00 65 75 00 75 71 00 75 &0110 79 00 79 75 00 79 7d 00 7d 79 00 7d 81 00 89 81 &0120 00 79 75 00 65 6d 00 61 65 5d 55 4d 45 3d 35 00 &0130 00 ; tune_channel2_data &0131 00 00 00 00 35 00 00 45 00 00 45 00 00 51 00 00 &0141 49 00 00 59 00 00 4e 00 00 59 00 00 51 00 59 51 &0151 00 49 51 00 59 61 00 51 65 00 00 51 00 00 35 00 &0161 00 ; play_tune &0162 a9 00 LDA #&00 &0164 85 c0 STA &c0 ; tune_position &0166 a2 07 LDX #&07 ; zero_tune_sound_block_loop &0168 95 c1 STA &c1,X ; tune_sound_block &016a ca DEX &016b 10 fb BPL &0168 ; zero_tune_sound_block_loop &016d a9 04 LDA #&04 # Use envelope 4 &016f 85 c3 STA &c3 ; tune_sound_block + 2 # Volume ; play_tune_loop &0171 a6 c0 LDX &c0 ; tune_position &0173 bd 00 01 LDA &0100,X ; tune_channel1_data &0176 f0 15 BEQ &018d ; skip_note &0178 a0 11 LDY #&11 ; channel &017a a2 08 LDX #&08 ; duration &017c 20 a2 01 JSR &01a2 ; play_note &017f a6 c0 LDX &c0 ; tune_position &0181 bd 31 01 LDA &0131,X ; tune_channel2_data &0184 f0 07 BEQ &018d ; skip_note &0186 a0 12 LDY #&12 ; channel &0188 a2 02 LDX #&02 ; duration &018a 20 a2 01 JSR &01a2 ; play_note ; skip_note &018d a9 07 LDA #&07 &018f 85 cf STA &cf ; delay ; play_tune_delay_loop &0191 20 cc 1e JSR &1ecc ; wait_for_vsync &0194 c6 cf DEC &cf delay &0196 d0 f9 BNE &0191 ; play_tune_delay_loop &0198 a6 c0 LDX &c0 ; tune_position &019a e8 INX &019b 86 c0 STX &c0 ; tune_position &019d e0 31 CPX #&31 &019f 90 d0 BCC &0171 ; play_tune_loop &01a1 60 RTS ; play_note &01a2 85 c5 STA &c5 ; tune_sound_block + 4 # Pitch &01a4 84 c1 STY &c1 ; tune_sound_block # Channel &01a6 86 c7 STX &c7 ; tune_sound_block + 6 # Duration &01a8 a0 00 LDY #&00 ; &00c1 = tune_sound_block &01aa a2 c1 LDX #&c1 &01ac a9 07 LDA #&07 ; Generate a sound (SOUND) &01ae 6c 0c 02 JMP (&020c) ; OSWORD # &4247 - &425c copied to &03c9 - &03de at &443d or &400a ; game_over_text &03c9 58 57 0c ; &5758, G &03cc 56 32 7a 4a d4 86 b0 4a 98 ; "GAME OVER" &03d5 fe &03d6 10 5f 0f ; &5f10, Y &03d9 00 00 00 00 00 ; "00000" &03de ff ; unused &425d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 &426d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 &427d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 &428d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 &429d 00 00 00 00 00 00 00 00 00 00 00 ae 00 00 00 00 &42ad 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 &42bd 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 &42cd 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 &42dd 00 00 00 00 00 00 00 00 00 00 00 00 00 ; protected_entry_point ; via_decryption # VIA decryption method identical to previous binary &42ea 78 SEI &42eb a9 df LDA #&df # Set User VIA timer 2 to timed interrupt &42ed 2d 6b fe AND &fe6b ; User VIA auxiliary control register &42f0 8d 6b fe STA &fe6b ; User VIA auxiliary control register &42f3 a9 a0 LDA #&a0 # Enable interrupts for User VIA timer 2 &42f5 8d 6e fe STA &fe6e ; User VIA interrupt enable register &42f8 a9 ff LDA #&ff &42fa 8d 68 fe STA &fe68 ; User VIA timer 2 counter LSB &42fd 8d 69 fe STA &fe69 ; User VIA timer 2 counter MSB &4300 a2 00 LDX #&00 ; via_decryption_loop &4302 ad 00 43 LDA &4300 # Runs from &4300 to &43ff, # actually LDA &4300 + via_decryption_offset # EORs all of &4400 - &44ff on every loop &4305 ee 1d 43 INC &431d ; via_decryption_eor &4308 18 CLC &4309 4d 68 fe EOR &fe68 ; User VIA timer 2 counter LSB &430c a8 TAY &430d ad 1d 43 LDA &431d ; via_decryption_eor &4310 4d fc ff EOR &fffc ; os_reset_address_low # Ensure 6502 reset vector hasn't been changed &4313 4d 68 fe EOR &fe68 ; User VIA timer 2 counter LSB &4316 8d 1b 43 STA &431b ; via_decryption_add &4319 98 TYA &431a 69 6d ADC #&6d # actually ADC via_decryption_add &431c 49 00 EOR #&00 # actually EOR via_decryption_eor &431e 4d 68 fe EOR &fe68 ; User VIA timer 2 counter LSB &4321 4d 40 d9 EOR &d940 ; os_default_vector_table # Ensure OS default vector table hasn't been changed # actually EOR &d900 + via_decryption_rom_offset_one &4324 ee 1d 43 INC &431d ; via_decryption_eor &4327 4d 69 fe EOR &fe69 ; User VIA timer 2 counter MSB &432a 4d cd d9 EOR &d9cd ; os_reset_handler # Ensure OS reset handler hasn't been changed # actually EOR &d900 + via_decryption_rom_offset_two &432d 5d 02 43 EOR &4302,X ; via_decryption_loop &4330 4d 1c dc EOR &dc1c ; os_irq_handler # Ensure OS main IRQ handler hasn't been changed # actually EOR &dc00 + via_decryption_rom_offset_three &4333 5d 00 44 EOR &4400,X ; payload &4336 4d 68 fe EOR &fe68 ; User VIA timer 2 counter LSB &4339 4d d9 ea EOR &ead9 ; os_break_intercept_handler # Ensure OS break intercept handler hasn't been changed # actually EOR &ea00 + via_decryption_rom_offset_four # (OSBYTE 247 (&f7), calls &0287 after BREAK) &433c 38 SEC &433d 6d 03 43 ADC &4303 ; via_decryption_offset &4340 4d fd ff EOR &fffd ; os_reset_address_high &4343 4d 68 fe EOR &fe68 ; User VIA timer 2 counter LSB &4346 18 CLC &4347 7d 01 44 ADC &4401,X ; payload + 1 # Runs from &4401 to &4500 &434a 4d 93 dc EOR &dc93 ; os_irq1v_handler # Ensure OS IRQ1 handler hasn't been changed # actually EOR &dc00 + via_decryption_rom_offset_five &434d ee 1b 43 INC &431b ; via_decryption_add &4350 a8 TAY &4351 ad 1b 43 LDA &431b ; via_decryption_add &4354 4d 68 fe EOR &fe68 ; User VIA timer 2 counter LSB &4357 8d 1b 43 STA &431b ; via_decryption_add &435a 98 TYA &435b 4d b0 da EOR &dab0 ; ? # Runs over &da00 - &daff # actually EOR &da00 + via_decryption_rom_offset_six # (System VIA setup, OS sideways ROM checking) &435e 4d 69 fe EOR &fe69 ; User VIA timer 2 counter MSB &4361 4d 68 fe EOR &fe68 ; User VIA timer 2 counter LSB &4364 9d 00 44 STA &4400,X ; payload &4367 e8 INX &4368 d0 98 BNE &4302 ; via_decryption_loop &436a a9 03 LDA #&03 &436c 8d 58 02 STA &0258 ; ESCAPE/BREAK effect &436f a9 4c LDA #&4c ; JMP # Set BREAK intercept code to JMP &0287, endless loop &4371 8d 87 02 STA &0287 ; BREAK intercept code &4374 a9 87 LDA #&87 &4376 8d 88 02 STA &0288 ; BREAK intercept code + 1 &4379 a9 02 LDA #&02 &437b 8d 89 02 STA &0289 ; BREAK intercept code + 2 &437e ee 31 43 INC &4331 ; via_decryption_rom_offset_three &4381 ee 2b 43 INC &432b ; via_decryption_rom_offset_two &4384 ee 3a 43 INC &433a ; via_decryption_rom_offset_four &4387 a0 35 LDY #&35 ; reset_vector_table_loop &4389 b9 40 d9 LDA &d940,Y ; os_default_vector_table &438c 99 00 02 STA &0200,Y ; os_vector_table # Reset all vectors to OS default &438f 88 DEY &4390 10 f7 BPL &4389 ; reset_vector_table_loop &4392 ee 22 43 INC &4322 ; via_decryption_rom_offset_one &4395 ee 4b 43 INC &434b ; via_decryption_rom_offset_five &4398 ee 5c 43 INC &435c ; via_decryption_rom_offset_six &439b ad 1d 43 LDA &431d ; via_decryption_eor &439e 4d 68 fe EOR &fe68 ; User VIA timer 2 counter LSB &43a1 8d 1d 43 STA &431d ; via_decryption_eor &43a4 ee 1d 43 INC &431d ; via_decryption_eor &43a7 ee 03 43 INC &4303 ; via_decryption_offset &43aa ad 03 43 LDA &4303 ; via_decryption_offset &43ad c9 00 CMP #&00 &43af f0 03 BEQ &43b4 ; calculate_checksum &43b1 4c 02 43 JMP &4302 ; via_decryption_loop ; calculate_checksum &43b4 a9 00 LDA #&00 # Checksum &4400 - &44fd &43b6 85 70 STA &70 ; calculated_checksum_one &43b8 85 71 STA &71 ; calculated_checksum_two &43ba a8 TAY ; calculate_checksum_loop &43bb a5 71 LDA &71 ; calculated_checksum_two &43bd 59 00 44 EOR &4400,Y ; payload &43c0 85 71 STA &71 ; calculated_checksum_two &43c2 a2 08 LDX #&08 ; calculate_checksum_inner_loop &43c4 a5 71 LDA &71 ; calculated_checksum_two &43c6 2a ROL A &43c7 90 0c BCC &43d5 ; clear_set &43c9 a5 71 LDA &71 ; calculated_checksum_two &43cb 49 08 EOR #&08 &43cd 85 71 STA &71 ; calculated_checksum_two &43cf a5 70 LDA &70 ; calculated_checksum_one &43d1 49 10 EOR #&10 &43d3 85 70 STA &70 ; calculated_checksum_one ; clear_set &43d5 26 70 ROL &70 ; calculated_checksum_one &43d7 26 71 ROL &71 ; calculated_checksum_two &43d9 ca DEX &43da d0 e8 BNE &43c4 ; calculate_checksum_inner_loop &43dc c8 INY &43dd c0 fe CPY #&fe &43df d0 da BNE &43bb ; calculate_checksum_loop &43e1 a5 70 LDA &70 ; calculated_checksum_one &43e3 cd fe 44 CMP &44fe ; valid_checksum_one &43e6 d0 07 BNE &43ef ; invalid_checksum &43e8 a5 71 LDA &71 ; calculated_checksum_two &43ea cd ff 44 CMP &44ff ; valid_checksum_two &43ed f0 11 BEQ &4400 ; payload # If the checksum matches, run the decrypted code ; invalid_checksum &43ef a9 c8 LDA #&c8 ; Read/Write BREAK/ESCAPE effect # This is handled by the OS OSBYTE handler at &e99c, &43f1 a2 03 LDX #&03 ; Clear memory on next RESET # which isn't checked in the decryption routine, &43f3 a0 00 LDY #&00 # so could be intercepted with a custom ROM &43f5 20 f4 ff JSR &fff4 ; OSBYTE ; endless_wiping_loop # Otherwise, if the checksum doesn't match, &43f8 99 00 44 STA &4400,Y ; payload # Wipe &4400 - &44ff (failed decryption) with &c8 &43fb c8 INY &43fc d0 fa BNE &43f8 ; endless_wiping_loop &43fe f0 f8 BEQ &43f8 ; endless_wiping_loop ; payload &4400 a9 03 LDA #&03 # Disable transmit and receiver interrupts &4402 8d 08 fe STA &fe08 ; Cassette ACIA control register &4405 a9 64 LDA #&64 &4407 8d 10 fe STA &fe10 ; Serial ULA control register # Switch off cassette motor &440a a5 fc LDA &fc ; irq_accumulator ; irq_trap &440c c9 d9 CMP #&d9 # Set to &d9 by previous binary, would be changed if &440e d0 fa BNE &440a ; irq_trap # any interrupt had occurred, causing an infinite loop &4410 a9 20 LDA #&20 &4412 8d 6e fe STA &fe6e ; User VIA interrupt enable register # Disable User VIA timer 2 interrupts &4415 a9 03 LDA #&03 # Enable ESCAPE, clear memory on BREAK &4417 8d 58 02 STA &0258 ; ESCAPE/BREAK effect ; decrypt_main_code &441a a2 ff LDX #&ff &441c 9a TXS &441d a9 00 LDA #&00 &441f 85 70 STA &70 ; address_low &4421 a9 04 LDA #&04 &4423 85 71 STA &71 ; address_high &4425 a0 00 LDY #&00 ; decrypt_main_code_loop &4427 b1 70 LDA (&70),Y ; address # Decrypt &0400 - &42ff &4429 38 SEC &442a e9 6e SBC #&6e &442c 49 ad EOR #&ad &442e 91 70 STA (&70),Y ; address &4430 c8 INY &4431 d0 f4 BNE &4427 ; decrypt_main_code_loop &4433 e6 71 INC &71 ; address_low &4435 a5 71 LDA &71 ; address_high &4437 c9 43 CMP #&43 &4439 90 ec BCC &4427 ; decrypt_main_code_loop ; skip_decryption # The code at &443b - &445c is identical to &443b a2 15 LDX #&15 # the code at &4008 - &4029. Used to pad the payload? ; move_game_over_text_loop &443d bd 47 42 LDA &4247,X ; unrelocated_game_over_text # Move &4247 - &425c to &03c9 - &03de &4440 9d c9 03 STA &03c9,X ; game_over_text &4443 ca DEX &4444 10 f7 BPL &443d ; move_game_over_text_loop &4446 a2 58 LDX #&58 ; move_plot_column_of_sprite_loop &4448 bd 3d 41 LDA &413d,X ; unrelocated_plot_column_of_sprite # Move &413d - &4195 to &0050 - &00a8 &444b 95 50 STA &50,X ; plot_column_of_sprite &444d ca DEX &444e 10 f8 BPL &4448 ; move_plot_column_of_sprite_loop &4450 a2 00 LDX #&00 ; move_tune_data_and_code_loop &4452 bd 96 41 LDA &4196,X ; unrelocated_tune_data_and_code # Move &4196 - &4246 to &0100 - &01b0 &4455 9d 00 01 STA &0100,X ; tune_data_and_code &4458 e8 INX &4459 e0 b1 CPX #&b1 &445b d0 f5 BNE &4452 ; move_tune_data_and_code_loop &445d a2 5d LDX #&5d ; wipe_decryption_code_loop &445f 9d 00 44 STA &4400,X ; second_stage_decryption_code # Wipe &4401 - &445d &4462 ca DEX &4463 d0 fa BNE &445f ; wipe_decryption_code_loop &4465 58 CLI &4466 4c 2a 40 JMP &402a ; initialise_mode # Continue in unprotected binary &4469 59 6f 75 20 74 6f 6f 6b 20 79 6f 75 72 20 74 69 ; "You took your ti" &4479 6d 65 20 21 20 50 72 6f 74 65 63 74 69 6f 6e 20 ; "me ! Protection " &4489 28 63 29 20 4b 65 76 69 6e 20 45 64 77 61 72 64 ; "(c) Kevin Edward" &4499 73 54 68 69 73 20 70 72 6f 74 65 63 74 69 6f 6e ; "sThis protection" &44a9 20 73 79 73 74 65 6d 20 77 61 73 20 64 65 73 69 ; " system was desi" &44b9 67 6e 65 64 20 61 6e 64 20 69 6d 70 6c 65 6d 65 ; "gned and impleme" &44c9 6e 74 65 64 20 62 79 20 4b 65 76 69 6e 20 45 64 ; "nted by Kevin Ed" &44d9 77 61 72 64 73 20 28 63 29 20 31 39 38 35 50 72 ; "wards (c) 1985Pr" &44e9 6f 74 65 63 74 69 6f 6e 20 63 6f 64 65 20 20 4d ; "otection code M" &44f9 4f 43 53 41 4e ; "OCSAN" ; valid_checksum_one &44fe dd ; valid_checksum_two &44ff 8e &4500 00 # Used at &4347 in final round of via_decryption A cracked disc version replaces the final &00 byte with relocation code: ; cracked_entry_point &5130 a9 8c LDA #&8c ; Select Tape FS &5132 20 f4 ff JSR &fff4 ; OSBYTE &5135 a9 c8 LDA #&c8 ; Read/Write BREAK/ESCAPE effect &5137 a2 02 LDX #&02 ; Escape disabled, Memory cleared on next reset &5139 20 f4 ff JSR &fff4 ; OSBYTE &513c 78 SEI &513d a9 00 LDA #&00 &513f 85 70 STA &70 ; source_address_low &5141 a9 11 LDA #&11 &5143 85 71 STA &71 ; source_addess_high &5145 a9 d0 LDA #&d0 &5147 85 72 STA &72 ; target_address_low &5149 a9 04 LDA #&04 &514b 85 73 STA &73 ; target_address_high &514d a2 41 LDX #&41 &514f a0 00 LDY #&00 ; move_memory_loop # Move &1100 - &51ff to &04d0 - &45cf &5151 b1 70 LDA (&70),Y ; source_address &5153 91 72 STA (&72),Y ; target_address &5155 88 DEY &5156 d0 f9 BNE &5151 ; move_memory_loop &5158 e6 71 INC &71 ; source_addess_high &515a e6 73 INC &73 ; target_address_high &515c ca DEX &515d d0 f2 BNE &5151 ; move_memory_loop &515f 4c 3b 44 JMP &443b ; skip_decryption # or JMP &4000 ; original_entry_point # to run original version