├── xroads2-specimen.prg ├── README.md └── xroads2.asm /xroads2-specimen.prg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyphz/crossroads-2-disassembly/HEAD/xroads2-specimen.prg -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # crossroads-2-disassembly 2 | 3 | This is an attempt at reverse engineering the C64 game **Crossroads 2**, originally by Steve Harter and published as a type-in game in Compute! magazine in 1988. 4 | 5 | Crossroads 2 was (is) an interesting game as it is an early example of a game in which all creatures, players and enemies, have similar rules applied to them and react in similar ways. 6 | 7 | ## Format 8 | 9 | The existing ASM file is built with c64studio by George Rottensteiner, at http://www.georg-rottensteiner.de/en/index.html . 10 | 11 | It reproduces the original PRG file exactly if built with `pristine=1`. There are also a small number of code variations enabled: 12 | * `always_show_credits`, if set will remove the code that hides the credits so they are always displayed. 13 | * `minimum_escalation` sets the minimum escalation level (described below). This will make early levels play faster. 14 | * `remove_dead_code` compiles out a number of apparently unreachable code blocks (see below) 15 | 16 | ## Notes 17 | 18 | Labels are being amended as I work out what they mean, as are local and global variables on the zero page. 19 | 20 | ### Dissassembly 21 | 22 | Some disassemblers and debuggers have trouble with some parts of the code due to the "BIT NOP trick", which is used in several 23 | places. That's this fellow: 24 | 25 | ~~~~ 26 | beq .enable_2_player 27 | ... 28 | !byte $2c ; BIT NOP hack 29 | .enable_2_player 30 | lda #c_player ; Make it a player icon 31 | ~~~~ 32 | 33 | The trick here is that `lda #c_player` is a two byte instruction. `$2c` is the opcode for `bit $xxxx`, a three byte instruction 34 | which alters the flags but doesn't change anything in memory or any registers. So if the `beq` is taken, the CPU jumps to the `lda` 35 | instruction; if it is not, the CPU reads the `$2c` as a `bit` instruction with the two bytes of the `lda` instruction as the 36 | operand (which will be a random address, but it doesn't matter, since `bit` doesn't do anything except changing the flags). Most 37 | disassemblers, including the C64studio built-in one, barf at this and disassemble the code as the `bit` instruction with a jump 38 | into the middle of it, so this has to be manually corrected. 39 | 40 | The game also loads its own ISR for timing. Because the ISR isn't actually called by the code, but just loaded as a jump vector 41 | into the zero page ISR address bytes, some disassemblers - again, including the C64studio one - think it's data rather than code 42 | and don't disassemble it. So it's hand disassembled. 43 | 44 | Also, some routines - mainly those for loading characters and reading and writing the screen - make use of self-modifying 45 | code to work around the 6502's limitations on indirect addressing. Fortunately, the original author was kind enough to put 46 | meaningful placeholder instructions in the locations in memory where the self-modifying code is built. 47 | 48 | ### Dead or confused code 49 | 50 | There are a couple of sections of code which are never reached. It's not clear if these are actual bugs or potential transcription errors (since this was a type-in there are likely to be plenty of opportunities for those). 51 | 52 | * Unreachable `jsr $0f58` at `$0ea4`. This is a call to update the status bar, immediately before the routine that draws the map. It's possible that the author realized this wasn't needed and moved the jump address forward at some point. 53 | 54 | * Unreachable `tax` at `$1268`, immediately before the routine that draws an entity. The drawing entity code takes the entity ID to draw in register X, so it looks like this would have allowed it to be in the accumulator instead, but this variant was never used. 55 | 56 | * Unreachable `bne $1959` at `$1951`. This seems to imply that the `jmp $1959` immediately before was originally a `beq` somewhere else. 57 | 58 | * `lda $4500, x; and #$fb; sta $4500, x` at `$1d7d` is immediately followed by a `jsr $1992` which does the same thing again in code at `$199a`. This is related to flipping which animation frame is shown for an entity. 59 | 60 | * Two consecutive `beq`s at `$1605` and `$1607`, means the second one can never be taken. This is probably the strangest of the lot; it is within the "enemy AI" routine, specifically an enemy's reaction to seeing a bullet within its vision range. Due to the second `beq` the code enters the routine at `$1609` which normally runs if no projectile is seen, and does so with the accumulator still holding the target bullet type, whereas `$1609` normally assumes it to hold the type of the active enemy. If this is changed to `bne` as was possibly intended, the effect on enemy behaviour is not clearly observed. 61 | 62 | ### Hidden credits message 63 | 64 | As mentioned in the interview with Steve Harter at https://kirk.is/2006/04/13/ , the game's author credit is hidden in Crossroads 2, because Compute! magazine removed the credit from Crossroads 1 before publication. The code therefore attempts to hide the credit when normally running the program (as the publishers would before approving it), and display it only if the program is running from the type-in, or from the published disk edition of Compute! 65 | 66 | The author credit appears in the code at `$1e73`, but it is simply obfuscated by adding the value of the corresponding bitmap value from the graphics used for the shield spars (which start at `$1f20`). 67 | 68 | The actual display of the credit is controlled by a zero page variable at `$6d`. During initialization, this is set to 69 | 0, but it is incremented in two circumstances: 70 | 71 | * if the first byte after the end of the program (`$21be` by default) is zero. (According to the interview this is because, when Compute! printed type-in listings, they padded the end of the program with zeroes, meaning these would appear at the end of the program when it was loaded from the type-in) 72 | * if the "VIC extra background color" is `$f6` (this is presumably the method of "detecting the loader from the disk version of Compute!" that was also mentioned in the interview) 73 | 74 | If `$6d` remains 0 then the branch at `$0c09` causes the scrolltext to loop before the credit message appears, meaning the scrolltext reads only "...COPYRIGHT 1988 COMPUTE! MAGAZINE...WELCOME TO PANDEMONIUM...PRESS FIRE BUTTON TO START". If `$6d` has been incremented then a higher character limit is used and the text is deobfuscated as it is displayed, by code at `$0b97` which subtracts the appropriate spar image byte from the character code, adding "...BY STEVE HARTER" at the end of the scrolltext above. 75 | 76 | Whether or not the credit appears on emulators differs based on how the emulator models the C64's initial memory state. 77 | 78 | ### Timing 79 | 80 | The timing of the game loop in Crossroads 2 is remarkably sophisticated. It is based on the C64's "jiffy clock", which ticks every 81 | 1/60 of a second. There are two interacting routines: the main game loop, which starts at `$0cc1` and runs constantly, and the 82 | interrupt service routine at `$1015`, which interrupts the normal code every jiffy. The timing manager only runs during the actual 83 | game; the title screen always runs the game loop at the highest possible speed. 84 | 85 | The enemy update code at `$152d` runs once every game loop, and updates **one** enemy each time around. Which enemy this is is 86 | determined round-robin by the value at `$0d`, which increments to the next active enemy each loop (with enemies that are frozen, 87 | exploding or dead not counted as active). When it reaches the last active enemy (stored in `$48`), it wraps around to the first. 88 | 89 | The sweep count is used by the ISR to determine the "difficulty value", at `$41`. Once the game loop has looped this number of times, 90 | it waits (at `$0d2d`) for the end of the current jiffy before proceeding. (Exactly how long this is could be very variable, of 91 | course.) 92 | 93 | The difficulty starts at 2, but is constantly adjusted during the game. This is done based on the "escalation value", which starts 94 | each level at half the level number, and increases every 1530 jiffies (or every 25 seconds); this is counted using the second byte of 95 | the jiffy clock, at `$0d0b`. 96 | 97 | The interrupt service routine updates the difficulty every 4 jiffies. Every time the active enemy tracker wraps around, it 98 | increments the "sweep count" at `$3c`. At each update, the ISR clears this counter and checks if the sweep count within the 4-jiffy 99 | period matches the escalation value. If more sweeps than escalation were made, the difficulty is lowered and the game loop effectively 100 | slows down; if less sweeps than escalation were made, the difficulty is raised and the game loop effectively speeds up. 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /xroads2.asm: -------------------------------------------------------------------------------- 1 | * = $0801 2 | 3 | !zone constants 4 | 5 | DEFAULT_PLAYER_SHIELDS = 3 6 | DEFAULT_PLAYER_MOVE_COOLDOWN = 2 7 | DEFAULT_PLAYER_FIRE_COOLDOWN = 6 8 | POWEREDUP_PLAYER_MOVE_COOLDOWN = 1 9 | POWEREDUP_PLAYER_FIRE_COOLDOWN = 4 10 | SHIELD_SPAR_COLOR = 1 11 | FIRE_SPAR_COLOR = 2 12 | SPEED_SPAR_COLOR = 6 13 | SPARS_TO_WIN_LEVEL = 5 14 | NO_EXTRA_SPAR_SPAWN_CHANCE = $c8 15 | MAX_EXTRA_SPAWNED_SPARS = 5 16 | MAX_PLAYER_SHIELDS = 9 17 | UNENCRYPTED_SCROLLTEXT_CHARACTERS = 96 18 | TOTAL_SCROLLTEXT_CHARACTERS = UNENCRYPTED_SCROLLTEXT_CHARACTERS + 19 19 | NUMBER_TO_PETSCII_ADJUSTMENT = $30 20 | PLAYER_SCORE_DIGITS = 8 21 | INITIAL_SPAR_COUNT = 5 22 | 23 | !zone mod_flags 24 | 25 | pristine = 1 ; Set to exactly rebuild original crossroads 2.prg . 26 | 27 | !ifndef pristine { 28 | always_show_credits = 1 ; Compile out checks for type-in or compute mag and always show credits. 29 | minimum_escalation = 9 ; Set minimum escalation to make early levels faster. 30 | remove_dead_code = 1 ; Remove several examples of unreachable code. 31 | spawn_keys = 1 32 | ;show_timing_info = 1 33 | } 34 | 35 | 36 | !zone internal_values 37 | 38 | ; Critical character codes. 39 | c_empty = $20 40 | c_spar = $3f 41 | c_player = $40 42 | 43 | ; Facing directions. 44 | dir_down = 0 45 | dir_up = 1 46 | dir_right = 2 47 | dir_left = 3 48 | 49 | ; Enemy types. 50 | et_egghead = 0 51 | et_vacuum = 1 52 | et_tagteam1 = 2 53 | et_tagteam2 = 3 54 | et_mutant = 4 55 | et_lemonshark = 5 56 | et_skull = 6 57 | et_chomper = 7 58 | et_monkey = 8 59 | et_rubberhead1 = 9 60 | et_thrower = 10 61 | et_archer = 11 62 | et_dog = 12 63 | et_rubberhead2 = 13 64 | et_flea = 14 65 | et_lion = 15 66 | et_player = 16 67 | et_bullet = 17 68 | et_worm = 18 69 | et_spear = 19 70 | 71 | ; Special enemy IDs. 72 | eid_last_player = $1 73 | eid_first_enemy = $0c 74 | 75 | ; Offset $7FF for BC4 76 | 77 | 78 | !zone hardware_addresses 79 | 80 | ; C64 Hardware addresses. 81 | ram_rom_mapping = $01 82 | jiffy255_clock = $a1 83 | jiffy_clock = $a2 84 | pressed_key_code = $cb 85 | stack = $0100 86 | screen = $0400 87 | vic_sprite_pointer_array = $07f8 88 | 89 | character_rom_base = $d000 ; When mapped by ram_rom_mapping 90 | vic_sprite_coord_array = $d000 91 | vic_sprite_x_hibits = $d010 92 | vic_sprite_enable = $d015 93 | vic_screen_control_2 = $d016 94 | vic_sprite_double_height = $d017 95 | vic_select_buffers = $d018 96 | vic_sprite_color_array = $d027 97 | vic_sprite_priority_bits = $d01b 98 | vic_sprite_double_width = $d01d 99 | 100 | vic_border_color = $d020 101 | vic_background_color = $d021 102 | vic_extra_bg_col_3 = $d024 103 | sid_voice1_high_freq = $d401 104 | sid_voice1_control = $d404 105 | sid_voice1_att_dec = $d405 106 | 107 | sid_voice3_low_freq = $d40e 108 | sid_voice3_high_freq = $d40f 109 | sid_voice3_control = $d412 110 | sid_volume_filter = $d418 111 | sid_voice3_oscillator_ro = $d41b 112 | colors = $d800 113 | port_2_joystick = $dc00 114 | port_1_joystick = $dc01 115 | cia_timer_control = $dc0e 116 | 117 | ; OS ROUTINE 118 | output_string_at_yyaa_until_zero_or_quote = $ab1e 119 | 120 | 121 | sound_buffer = $1f46 122 | 123 | !zone "Game data" 124 | 125 | copy_of_character_rom = $2800 126 | udgs_base = $2a00 127 | 128 | ; Explosion status bytes; arrays of 8 bytes, one per possible explosion. 129 | explosion_or_implosion = $4020 130 | explosion_status = $4028 131 | explosion_count_up_array = $4030 132 | explosion_base_sprite_pointer = $4040 133 | explosion_sprite_pointer_offset = $4048 134 | exploding_entity_index = $4058 135 | 136 | game_status_flags = $4060 137 | 138 | ; AI/Vision buffers - arrays of 4 bytes, one per facing. 139 | vision_char_seen_indir = $4061 140 | vision_dist_seen_indir = $4065 141 | vision_saw_friendly_flag = $4069 142 | ai_direction_votes = $406d 143 | ai_fire_bullet_in_direction_score= $407f 144 | slot_udg_loaded_into = $4096 145 | vision_entityId_seen_indir = $40ae 146 | 147 | ; Entity maps. Entities 0 and 1 are player, 2-12 are player bullets, 13+ are enemies. 148 | ; Each is an array of 255 values, although it is unlikely 255 entities would be viable. 149 | entity_enemy_type = $4100 ; Index into enemy type lists. 150 | entity_base_charno = $4200 151 | entity_bullet_type = $4300 ; Type of bullet we fire. If MSB set, we _are_ a bullet. 152 | entity_color_and_flags= $4400 ; Four bits color, four bits AI flags. 153 | entity_status_byte = $4500 ; See bitmap below. 154 | entity_shields = $4600 ; Number of shields entity has. 155 | p2_shields = $4601 156 | entity_upd_cooldown = $4700 ; Frequency with which entity is updated. 157 | entity_vision_distance= $4800 ; Number of squares vision routine scans ahead. 158 | entity_data_cdlow = $4900 159 | entity_type_fired_me = $4a00 160 | entity_bullet_speed = $4b00 ; Frequency with which entity's bullets are updated. 161 | entity_score_awarded = $4c00 ; Score value for entity. 162 | entity_upd_countdown = $4d00 ; Used to count down loops until next update. 163 | entity_x_coords = $4e00 ; X coordinate. 164 | entity_y_coords = $4f00 ; Y coordinate. 165 | entity_spars_eaten = $5000 ; How many spars entity has eaten and should drop on death. 166 | entity_facing = $5100 ; Direction being faced 167 | 168 | screen_line_address_lowbytes = $6000 ; Array of screen line addresses built during initialization. 169 | screen_line_address_highbytes = $6019 170 | player_1_score_digits = $6040 ; Player 1, player 2, and high score in BCD. 171 | player_2_score_digits = $6048 172 | high_score_digits = $6050 173 | 174 | ; Entity_id_buffer: 2D array the same size as screen, where each byte holds the entity-id of the 175 | ; entity that was most recently in that cell. Note that they are not cleared when the entity moves 176 | ; on, because this should only be used when a collision is confirmed on the screen. 177 | entity_id_buffer = $c000 178 | 179 | 180 | ; It's a 6502 game. It loves zero page global variables. 181 | temp_entity_x_coord = $03 182 | last_facing_for_joystick_position = $04 183 | processing_entity_number = $05 184 | proposed_entity_x_coord = $07 185 | proposed_entity_y_coord = $08 186 | entity_number_that_hit_player = $09 187 | last_enemy_processed = $0d 188 | p1_lives = $11 189 | p2_lives = $12 190 | p1_shields_copy = $14 191 | p2_shields_copy = $15 192 | last_entity_killed_by_overpopulation = $39 193 | enemy_sweep_count = $3c ; How many times enemy update looped in last 4-jiffy period. 194 | escalation = $3f ; Target number of enemy updates in 4-jiffy period, increases with time. 195 | difficulty = $41 ; Number of times enemy update loop repeats before waiting. 196 | udg_number_to_load = $44 197 | interrupt_counter = $46 ; Number of times ISR has run. 198 | level_units_b = $47 199 | max_enemy_entity = $48 200 | player_move_cooldown_counter = $49 ; 201 | level_number_byte = $4b 202 | oldest_bullet_entity_id = $4c 203 | player_fire_cooldown_counter = $4e 204 | spar_animation_timer = $52 205 | player_sound_flag = $66 206 | spars_spawned_by_0d33 = $6b 207 | fast_updates_count = $6c 208 | show_credits = $6d 209 | enemies_left_to_spawn = $6e 210 | extra_enemies_spawnable = $8e 211 | player_has_ticked = $a8 212 | player_move_cooldown = $aa 213 | level_bcd_tens = $b0 214 | level_bcd_units = $b1 215 | udg_slot_to_load_to = $b9 216 | player_fire_cooldown = $be 217 | current_map_color = $c3 218 | current_wall_character = $c4 219 | last_processed_explosion = $c9 220 | current_spar_frame = $ca 221 | extra_enemy_spawn_chance = $d7 222 | 223 | 224 | ; Entity status byte layout 225 | ; Bit 8/sign = 1 = entity is between squares 226 | ; Bit 6/$20 = 1 = immune to damage 227 | esb_frozen = $40 ; ( If set, $1572 and $185d jump out of entity's loop before processing. ) 228 | esb_invulnerable = $20 ; ( If set, $1c17 and $1c50 skip steps that would reduce entity's shield. ) 229 | esb_brave = $10 ; ( If set, $15fb skips applying direction penalty for sighted entities. ) 230 | esb_randomdirbumps = $08 ; ( If set, $1622 bumps current direction and randoms when critical seen. ) 231 | esb_secondframe = $04 ; ( If set, $1292 offsets character used for entity. ) 232 | esb_bullet_chance_mask = $03 ; ( Masked off at $166d and a random 2-bit value is subtracted; if it goes 233 | ; negative, fire. ) 234 | 235 | 236 | 237 | ; Color flags (high byte) 238 | ; Bit 6 = invisible 239 | csf_aggressive = $40 ; ( If 1, $165b adds proximity bonus when non-vacuum entity seen ) 240 | csf_visible = $20 ; ( If 0, $1273 sets drawing color to 0 ) 241 | csf_collects_spars = $10 ; ( If 1, $15db applies direction votes when spars seen ) 242 | 243 | ;to "xroads2.d64", d64 244 | !to "xroads2.prg", cbm 245 | 246 | 247 | !basic entry 248 | 249 | 250 | 251 | !zone character_graphics 252 | 253 | first_frames: 254 | 255 | ;Egghead 256 | 257 | !byte %##..###. 258 | !byte %.#.#..## 259 | !byte %.#.###.. 260 | !byte %.#.#.... 261 | !byte %..####.. 262 | !byte %...##### 263 | !byte %..##.##. 264 | !byte %..#...## 265 | 266 | ;Vacuum 267 | 268 | !byte %..###... 269 | !byte %.##.##.. 270 | !byte %.####..# 271 | !byte %..##..## 272 | !byte %.####### 273 | !byte %..###.## 274 | !byte %###.##.# 275 | !byte %.#..#... 276 | 277 | ; Tagteam 1 278 | 279 | !byte %#.##.... 280 | !byte %#.#..### 281 | !byte %.#####.# 282 | !byte %..##.### 283 | !byte %######.. 284 | !byte %..###.## 285 | !byte %.##.##.. 286 | !byte %.#...##. 287 | 288 | ; Tagteam 2 289 | 290 | !byte %........ 291 | !byte %##...### 292 | !byte %#....#.# 293 | !byte %#.###### 294 | !byte %######.. 295 | !byte %...##### 296 | !byte %.##.##.. 297 | !byte %.#...##. 298 | 299 | ; Mutant 300 | 301 | !byte %........ 302 | !byte %..##.... 303 | !byte %..#..... 304 | !byte %..##.### 305 | !byte %.#####.. 306 | !byte %..##.... 307 | !byte %###.#... 308 | !byte %.#...##. 309 | 310 | ; Lemonshark 311 | 312 | !byte %.######. 313 | !byte %##..#### 314 | !byte %#####... 315 | !byte %####.... 316 | !byte %#####... 317 | !byte %.####### 318 | !byte %###..##. 319 | !byte %#....### 320 | 321 | ; Skull 322 | 323 | !byte %..####.. 324 | !byte %.###..#. 325 | !byte %######## 326 | !byte %##.#.#.# 327 | !byte %##...... 328 | !byte %##.#.#.# 329 | !byte %.####### 330 | !byte %.##...## 331 | 332 | ; Chomper 333 | 334 | !byte %#####... 335 | !byte %#.#####. 336 | !byte %##.#.#.# 337 | !byte %##...... 338 | !byte %##.#.#.# 339 | !byte %.######. 340 | !byte %####.... 341 | !byte %#..##... 342 | 343 | ; Monkey 344 | 345 | !byte %##...### 346 | !byte %#...##.# 347 | !byte %#.###### 348 | !byte %######.. 349 | !byte %######## 350 | !byte %###.##.. 351 | !byte %##...##. 352 | !byte %##....## 353 | 354 | ; Rubberhead 1 355 | 356 | !byte %######## 357 | !byte %#...#### 358 | !byte %######## 359 | !byte %..####.. 360 | !byte %.######. 361 | !byte %.######. 362 | !byte %###.###. 363 | !byte %#....### 364 | 365 | ; THrower 366 | 367 | !byte %....###. 368 | !byte %.#..#... 369 | !byte %###.###. 370 | !byte %.#..##.. 371 | !byte %.####### 372 | !byte %.#..###. 373 | !byte %.#.####. 374 | !byte %.#.#..## 375 | 376 | ; Archer 377 | 378 | !byte %###...## 379 | !byte %##...#.# 380 | !byte %###.#..# 381 | !byte %######## 382 | !byte %###.#..# 383 | !byte %###..#.# 384 | !byte %##....## 385 | !byte %###..... 386 | 387 | ; Dog 388 | 389 | !byte %........ 390 | !byte %........ 391 | !byte %........ 392 | !byte %#....... 393 | !byte %.#...##. 394 | !byte %.####### 395 | !byte %.#####.. 396 | !byte %.#...##. 397 | 398 | ; Rubberhead 2 399 | 400 | !byte %..####.. 401 | !byte %..#..##. 402 | !byte %..####.. 403 | !byte %..#..... 404 | !byte %..#..... 405 | !byte %..####.. 406 | !byte %.#.####. 407 | !byte %.#...##. 408 | 409 | ; Flea 410 | 411 | !byte %.#...... 412 | !byte %.#...... 413 | !byte %#....... 414 | !byte %#.###... 415 | !byte %#.#.#### 416 | !byte %.####... 417 | !byte %..###### 418 | !byte %..##.##. 419 | 420 | ; Lion 421 | 422 | !byte %###..... 423 | !byte %#...#### 424 | !byte %#...#..# 425 | !byte %######## 426 | !byte %######.. 427 | !byte %######## 428 | !byte %##....#. 429 | !byte %#.....## 430 | 431 | ; Player 432 | 433 | !byte %..###... 434 | !byte %..###... 435 | !byte %..##.... 436 | !byte %.####### 437 | !byte %#.#####. 438 | !byte %.##.#... 439 | !byte %##..###. 440 | !byte %###.##.. 441 | 442 | ; Bullet 443 | 444 | !byte %........ 445 | !byte %........ 446 | !byte %........ 447 | !byte %..####.. 448 | !byte %..####.. 449 | !byte %........ 450 | !byte %........ 451 | !byte %........ 452 | 453 | ; Worm 454 | 455 | !byte %........ 456 | !byte %........ 457 | !byte %.#...#.. 458 | !byte %#.#.#.#. 459 | !byte %#.#.#.#. 460 | !byte %...#...# 461 | !byte %........ 462 | !byte %........ 463 | 464 | ; Spear 465 | 466 | !byte %........ 467 | !byte %........ 468 | !byte %......#. 469 | !byte %######## 470 | !byte %......#. 471 | !byte %........ 472 | !byte %........ 473 | !byte %........ 474 | 475 | 476 | second_frames: 477 | !byte %.#..###. 478 | !byte %.#.#..## 479 | !byte %#..##### 480 | !byte %.#.##... 481 | !byte %..###### 482 | !byte %...####. 483 | !byte %....#... 484 | !byte %....##.. 485 | 486 | !byte %..###... 487 | !byte %.##.##.. 488 | !byte %.#####.# 489 | !byte %..##..## 490 | !byte %######## 491 | !byte %..##..## 492 | !byte %..#....# 493 | !byte %..##.... 494 | 495 | !byte %..##.... 496 | !byte %#.#..### 497 | !byte %.###.#.# 498 | !byte %..##.### 499 | !byte %.#####.. 500 | !byte %#.##.... 501 | !byte %...#.... 502 | !byte %...##... 503 | 504 | !byte %........ 505 | !byte %.....### 506 | !byte %##...#.# 507 | !byte %#.###### 508 | !byte %######.. 509 | !byte %..###.## 510 | !byte %...#.... 511 | !byte %...##... 512 | 513 | !byte %........ 514 | !byte %..##.... 515 | !byte %..#..... 516 | !byte %..#####. 517 | !byte %.####... 518 | !byte %..##.... 519 | !byte %..#..... 520 | !byte %..##.... 521 | 522 | !byte %.######. 523 | !byte %##..#### 524 | !byte %######## 525 | !byte %####.... 526 | !byte %######## 527 | !byte %.####### 528 | !byte %..##.... 529 | !byte %..###... 530 | 531 | !byte %..####.. 532 | !byte %.###..#. 533 | !byte %#######. 534 | !byte %######## 535 | !byte %##.#.#.# 536 | !byte %######## 537 | !byte %.####### 538 | !byte %...###.. 539 | 540 | !byte %#####... 541 | !byte %#.#####. 542 | !byte %######## 543 | !byte %##.#.#.# 544 | !byte %######## 545 | !byte %.######. 546 | !byte %.##..... 547 | !byte %.###.... 548 | 549 | !byte %..#..### 550 | !byte %.##.##.# 551 | !byte %#..##### 552 | !byte %######## 553 | !byte %..###### 554 | !byte %..####.. 555 | !byte %..##.... 556 | !byte %..###... 557 | 558 | !byte %######## 559 | !byte %####...# 560 | !byte %######## 561 | !byte %..####.. 562 | !byte %.######. 563 | !byte %.######. 564 | !byte %..###... 565 | !byte %..####.. 566 | 567 | !byte %.#..###. 568 | !byte %###.#... 569 | !byte %.#..###. 570 | !byte %.#..##.. 571 | !byte %.######. 572 | !byte %.#..###. 573 | !byte %.#..##.. 574 | !byte %....###. 575 | 576 | !byte %###...## 577 | !byte %##...#.# 578 | !byte %###.#..# 579 | !byte %######## 580 | !byte %###.#..# 581 | !byte %###..#.# 582 | !byte %####..## 583 | !byte %#..##... 584 | 585 | !byte %........ 586 | !byte %........ 587 | !byte %........ 588 | !byte %#....... 589 | !byte %#....##. 590 | !byte %######## 591 | !byte %.#####.. 592 | !byte %..###... 593 | 594 | !byte %..####.. 595 | !byte %..#..#.. 596 | !byte %..#####. 597 | !byte %..#.##.. 598 | !byte %..#..... 599 | !byte %..####.. 600 | !byte %...#.... 601 | !byte %...##... 602 | 603 | !byte %........ 604 | !byte %..##.... 605 | !byte %.#...... 606 | !byte %#.###... 607 | !byte %#.#.#### 608 | !byte %.####... 609 | !byte %..###### 610 | !byte %...##... 611 | 612 | !byte %..#..... 613 | !byte %###.#### 614 | !byte %#...#..# 615 | !byte %######## 616 | !byte %#####... 617 | !byte %######## 618 | !byte %.#..##.. 619 | !byte %.##.#... 620 | 621 | !byte %..###... 622 | !byte %..###... 623 | !byte %..##.... 624 | !byte %.####### 625 | !byte %.###.##. 626 | !byte %..##.... 627 | !byte %..##.... 628 | !byte %..###... 629 | 630 | !byte %........ 631 | !byte %........ 632 | !byte %........ 633 | !byte %..####.. 634 | !byte %..####.. 635 | !byte %........ 636 | !byte %........ 637 | !byte %........ 638 | 639 | !byte %........ 640 | !byte %........ 641 | !byte %...#...# 642 | !byte %#.#.#.#. 643 | !byte %#.#.#.#. 644 | !byte %.#...#.. 645 | !byte %........ 646 | !byte %........ 647 | 648 | !byte %........ 649 | !byte %........ 650 | !byte %......#. 651 | !byte %######## 652 | !byte %......#. 653 | !byte %........ 654 | !byte %........ 655 | !byte %........ 656 | 657 | walls: 658 | 659 | !byte %##.##.## 660 | !byte %##....## 661 | !byte %..####.. 662 | !byte %#.####.# 663 | !byte %#.####.# 664 | !byte %..####.. 665 | !byte %##....## 666 | !byte %##.##.## 667 | 668 | !byte %##.##.## 669 | !byte %###..### 670 | !byte %.######. 671 | !byte %#.####.# 672 | !byte %#.####.# 673 | !byte %.######. 674 | !byte %###..### 675 | !byte %##.##.## 676 | 677 | !byte %.######. 678 | !byte %#......# 679 | !byte %#......# 680 | !byte %#......# 681 | !byte %#......# 682 | !byte %#......# 683 | !byte %#......# 684 | !byte %.######. 685 | 686 | !byte %.##..##. 687 | !byte %#.#..#.# 688 | !byte %##....## 689 | !byte %...##... 690 | !byte %...##... 691 | !byte %##....## 692 | !byte %#.#..#.# 693 | !byte %.##..##. 694 | 695 | !byte %.######. 696 | !byte %#......# 697 | !byte %#..##..# 698 | !byte %#.#..#.# 699 | !byte %#.#..#.# 700 | !byte %#..##..# 701 | !byte %#......# 702 | !byte %.######. 703 | 704 | !byte %###..### 705 | !byte %#.#..#.# 706 | !byte %##.##.## 707 | !byte %..#..#.. 708 | !byte %..#..#.. 709 | !byte %##.##.## 710 | !byte %#.#..#.# 711 | !byte %###..### 712 | 713 | !byte %##.##.## 714 | !byte %#..##..# 715 | !byte %..####.. 716 | !byte %######## 717 | !byte %######## 718 | !byte %..####.. 719 | !byte %#..##..# 720 | !byte %##.##.## 721 | 722 | !byte %.######. 723 | !byte %##....## 724 | !byte %#.####.# 725 | !byte %#.####.# 726 | !byte %#.####.# 727 | !byte %#.####.# 728 | !byte %##....## 729 | !byte %.######. 730 | 731 | mod_base = $2fc0 732 | 733 | 734 | * = $098d 735 | 736 | !zone main_program 737 | 738 | entry: 739 | 740 | ; Set up to use the SID as a fake random number generator. 741 | lda #$ff ; Set high frequency on both bytes 742 | sta sid_voice3_low_freq 743 | sta sid_voice3_high_freq 744 | lda #$80 ; Enable noise wave 745 | sta sid_voice3_control 746 | 747 | lda #$01 748 | sta $02 ; Unused position in zero page 749 | lda #$c0 750 | sta self_mod_sta_base_address_lo ; self modifying 751 | lda #$2f 752 | sta self_mod_sta_base_address_hi ; self modifying 753 | lda #$03 754 | sta $06 ; Unused position in zero page 755 | 756 | 757 | 758 | ; Accumulate several arrays in screen space?? 759 | ; $400 array - 10 + rand(3) 760 | ; $480 array - 8 + rand (3) 761 | 762 | label_09ac 763 | ldx #$31 764 | 765 | generate_random_arrays_loop 766 | 767 | ; $400 array - 10 + rand(3) 768 | jsr load_two_low_bits_of_osc3_to_accumulator 769 | clc 770 | adc #$0a 771 | sta screen, x 772 | 773 | ; $480 array - 8 + rand(3) 774 | jsr load_two_low_bits_of_osc3_to_accumulator 775 | adc #$08 776 | sta screen+$80, x 777 | 778 | 779 | ; Generate a random number that is either 0, 1, or $ff. 780 | loop_until_first_array_not_3 781 | jsr load_two_low_bits_of_osc3_to_accumulator 782 | cmp #$03 783 | beq loop_until_first_array_not_3 784 | cmp #$02 785 | bne first_random_not_2 786 | lda #$ff 787 | 788 | ; Put it in $500 array at current position 789 | first_random_not_2 790 | sta screen+$100, x 791 | 792 | ; Generate another random 793 | label_09cf 794 | jsr load_two_low_bits_of_osc3_to_accumulator 795 | bne label_09db 796 | 797 | ; If it's not zero, check that its counterpart in the $500 798 | ; array is also not zero, and regenerate it if it is. 799 | tay 800 | lda screen+$100, x 801 | beq loop_until_first_array_not_3 802 | tya 803 | 804 | label_09db 805 | ; If it's 3, reject it and generate again. 806 | cmp #$03 807 | beq label_09cf 808 | ; If it's 2, make it $ff. 809 | cmp #$02 810 | bne label_09e5 811 | lda #$ff 812 | 813 | label_09e5 814 | sta screen+$180, x 815 | ; Result: $500 and $580 are now sequences of random values that are 816 | ; 0, 1, or ff; and where $500's is non zero if $580's is. 817 | 818 | lda sid_voice3_oscillator_ro 819 | and #$0f ; Random value 0-15.. 820 | adc #$05 ; +5. 821 | sta screen+$200, x ; Identical in $600 and $680 arrays. 822 | sta screen+$280, x 823 | dex 824 | bpl generate_random_arrays_loop 825 | 826 | ; ------------------ Random seeding loop ends here 827 | 828 | lda #$1a 829 | sta $fb 830 | 831 | label_09fc 832 | jsr inc_and_clear_smb_64bytes 833 | 834 | label_09ff 835 | ldx #$31 836 | 837 | label_0a01 838 | dec screen+$280, x 839 | bpl label_0a20 840 | lda screen+$200, x 841 | sta screen+$280, x 842 | 843 | ; Add each value in $500 array to parallel value in $400 array. 844 | 845 | lda screen, x 846 | clc 847 | adc screen+$100, x 848 | sta screen, x 849 | 850 | ; Add each value in $580 array to parallel value in $480 array. 851 | 852 | lda screen+$80, x 853 | clc 854 | adc screen+$180, x 855 | sta screen+$80, x 856 | 857 | label_0a20 858 | lda $06 ; This was set to 3 above. 859 | bne label_0a55 860 | lda screen, x 861 | bmi label_0a55 862 | pha 863 | and #$07 864 | tay 865 | pla 866 | lsr 867 | lsr 868 | lsr 869 | sta $fc 870 | lda onebit_masks_zero_is_msb, y 871 | sta $fd 872 | lda screen+$80, x 873 | bmi label_0a55 874 | asl 875 | clc 876 | adc screen+$80, x 877 | adc $fc 878 | tay 879 | jsr self_modified_lda_plus_y 880 | ora $fd 881 | pha 882 | stx temp_entity_x_coord 883 | tya 884 | tax 885 | pla 886 | jsr self_modified_sta_plus_x 887 | ldx temp_entity_x_coord 888 | 889 | label_0a55 890 | dex 891 | bpl label_0a01 892 | 893 | 894 | dec $06 895 | bpl label_09ff 896 | lda #$03 897 | sta $06 898 | dec $fb 899 | bmi label_0a67 900 | jmp label_09fc 901 | 902 | label_0a67 903 | dec $02 904 | bmi label_0a6e 905 | jmp label_09ac 906 | 907 | label_0a6e 908 | lda #$00 909 | sta cia_timer_control 910 | sta show_credits 911 | 912 | !ifdef always_show_credits { 913 | inc show_credits 914 | } 915 | lda #%01110011 916 | sta ram_rom_mapping ; Make character ROM visible at d000 917 | ldx #$ec 918 | 919 | ; Copy character shapes from ROM to $2800 920 | 921 | copy_character_rom 922 | lda character_rom_base-1, x 923 | sta copy_of_character_rom-1, x 924 | lda character_rom_base+$eb, x ; VICII register image?? 925 | sta copy_of_character_rom+$eb, x 926 | dex 927 | bne copy_character_rom 928 | 929 | 930 | ldx #$3f 931 | .load_walls 932 | lda walls, x 933 | sta copy_of_character_rom+$130, x 934 | dex 935 | bpl .load_walls 936 | 937 | 938 | lda #%01110111 939 | sta ram_rom_mapping ; Make I/O visible at d000 940 | lda #$01 941 | sta cia_timer_control 942 | lda #$1a 943 | sta vic_select_buffers 944 | 945 | !ifndef always_show_credits { 946 | ; Determine if the credits should be shown. Because Compute! magazine removed programmer's names from 947 | ; published programs, the credits are hidden and only displayed if the program is running from Compute!'s 948 | ; consumer disk loader or from a typed in program - not if it's running from a raw image, as the 949 | ; publishers would check. 950 | lda vic_extra_bg_col_3 951 | cmp #$f6 ; Check for BG col $f6 - this is presumably set by the Compute! disk loader. 952 | bne .no_compute_loader 953 | inc show_credits ; If set, credits will be shown. 954 | 955 | .no_compute_loader 956 | lda program_end ; Check for a 0 at the end of the program. This was because Compute! padded 957 | bne .no_type_in ; their listings for type in programs with zeroes at the end. 958 | inc show_credits ; If set, credits will be shown. 959 | 960 | .no_type_in 961 | } 962 | 963 | lda #$01 964 | sta $fc 965 | 966 | label_0ab7 967 | jsr inc_and_clear_smb_64bytes 968 | ldy $fc 969 | lda #$0f 970 | jsr label_0d58 971 | ldy #$00 972 | lda #$10 973 | jsr label_0d58 974 | ldy #$00 975 | lda #$11 976 | jsr label_0d58 977 | inc $fc 978 | lda $fc 979 | cmp #$0a 980 | bcc label_0ab7 981 | lda #$cc 982 | sta vic_screen_control_2 ; Set 40 column screen width 983 | lda #$ff 984 | sta vic_sprite_enable ; Enable all sprites 985 | lda #$00 986 | sta vic_background_color ; Background color 987 | sta vic_border_color ; Border color 988 | sta vic_sprite_priority_bits ; Sprite priority register 989 | sta vic_sprite_double_width ; Sprite double width 990 | sta vic_sprite_double_height ; Sprite double height 991 | sta $d0cd ; Register image?? 992 | ldx #$07 993 | 994 | .clear_explosions_and_highscore 995 | lda #$00 996 | sta explosion_status, x 997 | sta high_score_digits, x 998 | dex 999 | bpl .clear_explosions_and_highscore 1000 | 1001 | sta player_sound_flag 1002 | sta $67 1003 | ldx #$04 1004 | tay 1005 | sta game_status_flags 1006 | stx spar_animation_timer 1007 | 1008 | 1009 | generate_screen_line_address_array: 1010 | sta screen_line_address_lowbytes, y ; a=0 1011 | pha ; pushed a 1012 | txa ; 4 1013 | sta screen_line_address_highbytes, y 1014 | iny 1015 | cpy #$19 ; generate 25 total values 1016 | beq install_isr 1017 | pla ; pulled a (0) 1018 | clc 1019 | adc #$28 ; adding 40 1020 | bcc generate_screen_line_address_array 1021 | inx 1022 | bcs generate_screen_line_address_array 1023 | 1024 | install_isr: 1025 | sei ;disable interrupts 1026 | lda #interrupt_service_routine 1029 | sta $0315 1030 | cli ;and restart interrupts 1031 | 1032 | title_screen_init: 1033 | jsr clear_explosions 1034 | ldx #$07 1035 | stx last_enemy_processed 1036 | stx max_enemy_entity 1037 | stx spar_animation_timer 1038 | sta game_status_flags 1039 | 1040 | .clear_player_scores: 1041 | sta player_1_score_digits, x 1042 | sta player_2_score_digits, x 1043 | dex 1044 | bpl .clear_player_scores 1045 | 1046 | tax 1047 | .clear_entities: 1048 | sta entity_shields, x 1049 | sta entity_spars_eaten, x 1050 | inx 1051 | bne .clear_entities 1052 | 1053 | sta $ae 1054 | sta $af 1055 | sta level_bcd_tens 1056 | dex 1057 | stx extra_enemy_spawn_chance 1058 | lda #$0a 1059 | sta level_number_byte 1060 | sta level_bcd_units 1061 | lda #msg_banner 1063 | jsr output_string_at_yyaa_until_zero_or_quote 1064 | jsr draw_new_map 1065 | 1066 | 1067 | ldx #$0f 1068 | display_start_at_level: 1069 | lda msg_start_at_level, x 1070 | sta screen+$214, x 1071 | lda #$0a 1072 | sta colors+$214, x 1073 | dex 1074 | bpl display_start_at_level 1075 | jsr reset_entity_count_and_udgs 1076 | 1077 | .reset_and_update_scrolltext 1078 | ldx #$00 1079 | 1080 | .scrolltext_position = $53 1081 | .last_scrolltext_color_code = $3a 1082 | 1083 | ; Scroll existing text to the left. Rather than updating the screen, just have the kernel print 1084 | ; routine print a series of characters that perform a backspace delete on the left hand character! 1085 | .update_scrolltext 1086 | stx .scrolltext_position 1087 | lda #scroll_left_control_codes 1089 | jsr output_string_at_yyaa_until_zero_or_quote 1090 | 1091 | .fetch_new_scrolltext_end 1092 | lda #$00 1093 | ldx .scrolltext_position ; Get scrolltext position 1094 | cpx #UNENCRYPTED_SCROLLTEXT_CHARACTERS ; Are we within the unencrypted section? 1095 | bcc .no_credit_decrypt 1096 | txa ; No. Move X, position we're on, to A 1097 | sec 1098 | sbc #UNENCRYPTED_SCROLLTEXT_CHARACTERS ; and subtract to get the encrypted character number 1099 | tay 1100 | lda #$00 1101 | sbc spar_images, y ; Initialize accumulator with the negative value from the 1102 | ; spar images corresponding to the position in the encrypted 1103 | ; text 1104 | .no_credit_decrypt: 1105 | clc 1106 | adc main_scrolltext, x ; Add scrolltext character value to accumulator - it will 1107 | ; be 0 or negative key, as set above 1108 | cmp #$f0 ; Is the "character" actually a color code? 1109 | bcc .scrolltext_not_control_char ; No, display it as normal. 1110 | sta .last_scrolltext_color_code ; Yes, store it as current scrolltext color code. 1111 | inc .scrolltext_position ; And manually advance to next character, since we don't 1112 | bne .fetch_new_scrolltext_end ; scroll on color codes. 1113 | 1114 | .scrolltext_not_control_char 1115 | sta screen+$4e ; Put new character at end of scrolltext line 1116 | lda .last_scrolltext_color_code ; Load last color code and set color of new character 1117 | sta colors+$4e 1118 | lda .scrolltext_position ; Is it an odd numbered character? 1119 | and #$01 1120 | beq .title_screen_done_joysticks ; If so, skip handling keys and joysticks. 1121 | ldx pressed_key_code ; Get pressed key 1122 | cpx #$03 ; Is F7 pressed? 1123 | bne .handle_keyboard_title_screen 1124 | jmp title_screen_init ; If so, reinitialize. 1125 | 1126 | .handle_keyboard_title_screen 1127 | lda $eb81, x ; Use built in table to convert keyboard key to PETSCII. 1128 | cmp #$31 ; Is it less than 1? 1129 | bcc .invalid_key ; If so, don't do anything. 1130 | cmp #$3a ; Is it more than or equal to colon (the character after 9)? 1131 | !ifndef spawn_keys { 1132 | bcs .invalid_key ; If so, don't do anything. 1133 | } 1134 | !ifdef spawn_keys { 1135 | bcs .spawn_key 1136 | } 1137 | sta screen+$223 ; Place it on the screen in the "start at level" slot. 1138 | !ifdef spawn_keys { 1139 | bcc .invalid_key 1140 | 1141 | .spawn_key 1142 | cmp #$41 1143 | bcc .invalid_key 1144 | clc 1145 | sbc #$41 1146 | cmp #et_player 1147 | bcs .invalid_key 1148 | pha 1149 | jsr set_xy_to_random_empty_space_coord 1150 | pla 1151 | jsr spawn_enemy_type_a_at_position_xy 1152 | } 1153 | 1154 | .invalid_key 1155 | lda port_2_joystick 1156 | cmp #%01111111 ; Is joystick idle? 1157 | beq handle_player_2_joystick ; Yes, move on to player 2 joystick. 1158 | and #%00010000 ; Is fire button down? 1159 | beq start_game ; Yes, start game. 1160 | jsr toggle_2_player_indicator ; Other than fire. Toggle 2 player mode. 1161 | 1162 | handle_player_2_joystick 1163 | lda port_1_joystick 1164 | cmp #$ff ; Joystick idle / timer bits?? 1165 | beq .title_screen_done_joysticks 1166 | and #$10 ; Is fire button down? 1167 | bne .player_2_non_fire ; No, but joystick not idle, so joystick move 1168 | lda screen+$26 ; Are we in 2 player mode? 1169 | cmp #c_empty 1170 | beq .title_screen_done_joysticks ; No, ignore fire on 2nd joystick. 1171 | bne start_game ; Yes, 2nd player fire starts game. 1172 | 1173 | .player_2_non_fire 1174 | jsr toggle_2_player_indicator 1175 | 1176 | .title_screen_done_joysticks: 1177 | lda #$08 1178 | sta $61 1179 | lda #$00 1180 | sta jiffy_clock 1181 | 1182 | .title_screen_loop: 1183 | lda jiffy_clock 1184 | cmp $61 1185 | bcc .not_time_for_scrolltext 1186 | ldx .scrolltext_position 1187 | inx 1188 | cpx #UNENCRYPTED_SCROLLTEXT_CHARACTERS 1189 | bcc .dont_reset_scrolltext 1190 | lda show_credits 1191 | beq .reset_scrolltext 1192 | cpx #TOTAL_SCROLLTEXT_CHARACTERS 1193 | bcc .dont_reset_scrolltext 1194 | 1195 | .reset_scrolltext 1196 | jmp .reset_and_update_scrolltext 1197 | 1198 | .dont_reset_scrolltext 1199 | jmp .update_scrolltext 1200 | 1201 | .not_time_for_scrolltext 1202 | jsr game_loop_enemies 1203 | jmp .title_screen_loop 1204 | 1205 | ; -------------------------------------------------------------------- 1206 | 1207 | !zone toggle_2_player_indicator 1208 | 1209 | toggle_2_player_indicator 1210 | lda screen+$26 ; Top left of screen 1211 | cmp #c_empty ; If it's a space.. 1212 | beq .enable_2_player 1213 | lda #c_empty ; Make it a space 1214 | !byte $2c ; BIT NOP hack 1215 | .enable_2_player 1216 | lda #c_player ; Make it a player icon (potentially NOPped) 1217 | sta screen+$26 ; Store back in top left of screen 1218 | rts 1219 | 1220 | ; -------------------------------------------------------------------- 1221 | ; LIKELY GAME SETUP ROUTINE 1222 | 1223 | start_game: 1224 | ldx #$00 1225 | ldy #$04 1226 | sty p1_lives 1227 | jsr init_player_x_shields_and_cooldowns 1228 | lda screen+$26 ; Are we in 2 player mode (second player icon in 1229 | cmp #c_player ; top left of screen?) 1230 | beq .start_2player 1231 | ldy #$00 ; If not, give player 2 zero lives 1232 | 1233 | .start_2player: 1234 | sty p2_lives 1235 | inx 1236 | jsr init_player_x_shields_and_cooldowns 1237 | lda screen+$223 ; Digit of level to start at 1238 | sec 1239 | sbc #$30 ; Subtract PETSCII offset to get actual number 1240 | sta level_bcd_units 1241 | sta level_units_b 1242 | sta level_number_byte 1243 | lda #msg_status_bar_headers 1245 | jsr output_string_at_yyaa_until_zero_or_quote 1246 | ldx #$27 1247 | 1248 | .setup_lower_status_line_loop: 1249 | lda colors, x ; Copy color info from top status line to bottom 1250 | sta colors+$28, x 1251 | lda #c_empty ; Also blank bottom status line 1252 | sta screen+$28, x 1253 | dex 1254 | bpl .setup_lower_status_line_loop 1255 | 1256 | jsr draw_new_map 1257 | jsr update_status_bar 1258 | 1259 | per_level_init: 1260 | 1261 | ; Clear shields to 0 on all entities (this marks them as unused) 1262 | lda #$00 1263 | tax 1264 | .loop_clear_shields 1265 | sta entity_shields, x 1266 | inx 1267 | bne .loop_clear_shields 1268 | 1269 | 1270 | sta last_processed_explosion 1271 | sta spars_spawned_by_0d33 1272 | lda #$02 1273 | sta oldest_bullet_entity_id 1274 | sta difficulty 1275 | sta fast_updates_count 1276 | lda level_number_byte 1277 | asl 1278 | asl 1279 | clc 1280 | adc #$46 1281 | bcs label_0c8c 1282 | sta extra_enemy_spawn_chance 1283 | 1284 | label_0c8c 1285 | ldx #eid_first_enemy ; Initialize enemy processing to start at first enemy 1286 | stx last_enemy_processed 1287 | dex ; Initialize enemy overflow to start at first enemy 1288 | stx last_entity_killed_by_overpopulation 1289 | jsr reset_entity_count_and_udgs 1290 | 1291 | ; Check if player 1 is alive. 1292 | lda p1_lives ; Get player 1 lives 1293 | beq .player_1_dead ; Jump ahead if equal to 0. 1294 | ; Spawn player 1. 1295 | ldx #$00 1296 | jsr spawn_player 1297 | .player_1_dead 1298 | ; Check if player 2 is alive. 1299 | lda p2_lives ; Get player 2 lives 1300 | beq .spawn_initial_spars ; Jump ahead if equal to 0. 1301 | ; Spawn player 2 1302 | ldx #$01 1303 | jsr spawn_player 1304 | 1305 | ; Spawn initial spars. 1306 | .initial_spars_to_spawn = $fe 1307 | .spawn_initial_spars 1308 | lda #INITIAL_SPAR_COUNT ; Set up counter left to spawn. 1309 | sta .initial_spars_to_spawn 1310 | 1311 | .spawn_initial_spars_loop 1312 | jsr set_xy_to_random_empty_space_coord ; Pick a random empty space 1313 | lda #c_spar ; Place a spar there 1314 | jsr write_a_to_screen_position_xy 1315 | lda #SHIELD_SPAR_COLOR ; Initial spars are always shield 1316 | jsr write_a_to_colors_position_xy ; Write shield color to colormap 1317 | dec .initial_spars_to_spawn 1318 | bne .spawn_initial_spars_loop ; Loop until all spars spawned. 1319 | 1320 | lda #$f9 1321 | sta jiffy255_clock 1322 | 1323 | ; Main game loop begins here. This is game loop part 1. 1324 | 1325 | !zone game_loop 1326 | 1327 | game_loop: 1328 | ldy pressed_key_code 1329 | cpy #$06 ; Is F5, Pause, being pressed? 1330 | bne .no_pause ; No, skip ahead. 1331 | lda game_status_flags ; Yes, flip paused bit. 1332 | eor #$01 1333 | sta game_status_flags 1334 | 1335 | ; Wait 16 jiffies after flipping pause bit. This is probably to avoid 1336 | ; pause being constantly switched back and forth if the player holds F5 1337 | ; for more than 1/60 of a second. 1338 | .target_jiffytime = $fc 1339 | wait_16jiffies: 1340 | lda jiffy_clock ; Get jiffy clock value 1341 | clc ; Add 16 1342 | adc #$0f 1343 | sta .target_jiffytime ; Note target time to finish waiting 1344 | 1345 | .wait_16jiffies_loop: 1346 | lda jiffy_clock ; Loop reading jiffy clock 1347 | cmp .target_jiffytime ; Until it reaches target time 1348 | bne .wait_16jiffies_loop ; If it hasn't yet, continue loop. 1349 | 1350 | .no_pause: 1351 | lda game_status_flags 1352 | beq .not_paused 1353 | 1354 | ; While paused, check for f1/f3 being pressed to change player color. 1355 | ; For some bizarre reason we check on alternate jiffies for f1 and f3. 1356 | lda jiffy_clock ; Get jiffy clock 1357 | and #$01 ; Mask off last bit, 1 or 0 1358 | tax 1359 | tya 1360 | cmp player_function_keys, x ; Check for F1 or F3 according to parity of jiffy 1361 | bne game_loop ; If not pressed, restart game loop 1362 | lda p1_lives, x ; Check player x is actually alive 1363 | beq game_loop ; If not, can't change color, restart game loop 1364 | inc player_color, x ; Increment that player's color in stored array 1365 | lda player_color, x ; Load it from that array 1366 | ora #csf_visible ; Turn on visible flag 1367 | sta entity_color_and_flags, x ; Update player in entity list 1368 | jsr draw_entity_x ; Redraw affected player 1369 | jmp wait_16jiffies ; Wait 16 jiffies to avoid bounce 1370 | 1371 | .not_paused: 1372 | lda interrupt_counter 1373 | beq game_loop_reentry_from_players 1374 | jsr update_player_bullets 1375 | jmp game_loop_players ; Go to game loop part 2, players 1376 | 1377 | game_loop_reentry_from_players: ; .. Player handling branches back here 1378 | lda jiffy255_clock ; Check coarse timer 1379 | bmi done_escalation ; If it's not reached zero, don't escalate yet. 1380 | lda #$f9 ; Reset to reach zero again in 7 ticks. 1381 | sta jiffy255_clock 1382 | inc escalation ; Increase escalation meter 1383 | !ifndef show_timing_info { 1384 | bne done_escalation 1385 | } 1386 | !ifdef show_timing_info { 1387 | bne updated_escalation 1388 | } 1389 | 1390 | ; If it overflowed to zero.. 1391 | lda #$ff ; Set it to max 1392 | sta escalation 1393 | 1394 | !ifdef show_timing_info { 1395 | updated_escalation: 1396 | ldx #5 1397 | jsr display_hex_value 1398 | } 1399 | 1400 | 1401 | done_escalation: 1402 | dec fast_updates_count ; Count down "fast updates" for difficulty scaling. 1403 | bne .fast_update ; If fast updates still to do, do one. 1404 | lda difficulty ; Reset fast update counter to difficuly. 1405 | sta fast_updates_count 1406 | 1407 | lda jiffy_clock ; Capture jiffy clock time. 1408 | sta .target_jiffytime 1409 | lda difficulty ; If difficulty is $ff, make all updates fast. 1410 | cmp #$ff 1411 | beq .fast_update 1412 | 1413 | .wait_for_jiffy ; Wait for end of current jiffy. 1414 | lda jiffy_clock 1415 | cmp .target_jiffytime 1416 | beq .wait_for_jiffy 1417 | 1418 | .fast_update ; Actual update code. 1419 | jsr game_loop_enemies ; Update enemies. 1420 | 1421 | ; Maybe spawn an extra spar. 1422 | lda sid_voice3_oscillator_ro ; Get a random value. 1423 | bne .dont_spawn_spar ; If not 0, don't spawn an extra spar. 1424 | lda sid_voice3_oscillator_ro ; Get another random value. 1425 | cmp #NO_EXTRA_SPAR_SPAWN_CHANCE ; Compare it to extra spar spawn chance. 1426 | bcc .dont_spawn_spar ; If lower, don't spawn. 1427 | lda spars_spawned_by_0d33 ; How many extra spars have we spawned so far? 1428 | cmp #MAX_EXTRA_SPAWNED_SPARS ; Have we reached the maximum? 1429 | bcs .dont_spawn_spar ; If so, don't spawn more. 1430 | inc spars_spawned_by_0d33 ; We're going to spawn one more. 1431 | jsr set_xy_to_random_empty_space_coord ; Pick a random empty spot 1432 | lda #c_spar ; Put a spar there 1433 | jsr write_a_to_screen_position_xy 1434 | jsr select_random_spar_type ; And color it randomly. 1435 | 1436 | .dont_spawn_spar 1437 | jmp game_loop 1438 | 1439 | ; ------------------------------------------------------------------------ 1440 | label_0d58 1441 | ldx #$00 1442 | stx $fd 1443 | clc 1444 | adc $fd ; What? 1445 | tax 1446 | tya 1447 | asl 1448 | asl 1449 | asl 1450 | tay 1451 | 1452 | label_0d65 1453 | lda $2980, y 1454 | jsr self_modified_sta_plus_x 1455 | inx 1456 | inx 1457 | inx 1458 | iny 1459 | stx $fd 1460 | cpx #$27 1461 | bcc label_0d65 1462 | rts 1463 | 1464 | ; ----------------------------------------------------------------------- 1465 | 1466 | load_udg_localvars 1467 | lda udg_slot_to_load_to ; "Slot number" 1468 | clc 1469 | ror ; Divide by 2 and set carry if it was odd. 1470 | ldx #$00 1471 | bcc label_0d80 ; Evens go at $xx00, odds go at $xx80. 1472 | ldx #$80 1473 | 1474 | label_0d80 1475 | stx self_mod_sta_base_address_lo 1476 | clc 1477 | adc #$2a ; A still holds slot number divided by 2, add 1478 | ; base page. 1479 | sta self_mod_sta_base_address_hi 1480 | lda #$00 1481 | ldx #$7f 1482 | 1483 | .clear_128_bytes 1484 | jsr self_modified_sta_plus_x 1485 | dex 1486 | bpl .clear_128_bytes 1487 | lda udg_number_to_load 1488 | asl ; x2 1489 | asl ; x4 1490 | asl ; x8 1491 | tay 1492 | ldx #$00 1493 | 1494 | load_one_udg 1495 | lda first_frames, y 1496 | jsr self_modified_sta_plus_x 1497 | iny 1498 | inx 1499 | cpx #8 ; 8 lines per character 1500 | bne load_one_udg 1501 | 1502 | load_second_frame_shifted_right 1503 | lda second_frames-8, y ; -8, because y is starting at 8 after previous 1504 | lsr 1505 | lsr 1506 | lsr 1507 | lsr 1508 | jsr self_modified_sta_plus_x 1509 | inx 1510 | iny 1511 | cpx #16 ; 8 lines per character. 16, because x is 1512 | ; starting at 8 after previous loop. 1513 | bne load_second_frame_shifted_right 1514 | 1515 | load_second_frame_shifted_left 1516 | lda second_frames-16, y 1517 | asl 1518 | asl 1519 | asl 1520 | asl 1521 | jsr self_modified_sta_plus_x 1522 | inx 1523 | iny 1524 | cpx #24 1525 | bne load_second_frame_shifted_left 1526 | 1527 | load_second_frame_unshifted 1528 | lda second_frames-24, y 1529 | jsr self_modified_sta_plus_x 1530 | inx 1531 | iny 1532 | cpx #32 1533 | bne load_second_frame_unshifted 1534 | jsr label_0de4 1535 | ldy #$00 1536 | ldx #$40 1537 | jsr label_0e15 1538 | ldy #$20 1539 | ldx #$60 1540 | jmp label_0e15 1541 | 1542 | label_0de4 1543 | lda #$00 1544 | sta $fc 1545 | 1546 | label_0de8 1547 | txa 1548 | sec 1549 | sbc #$20 1550 | tay 1551 | jsr self_modified_lda_plus_y 1552 | ldy $fc 1553 | and onebit_masks_zero_is_msb, y 1554 | cmp onebit_masks_zero_is_msb, y 1555 | bne label_0e08 1556 | txa 1557 | tay 1558 | jsr self_modified_lda_plus_y 1559 | ldy $fc 1560 | clc 1561 | adc onebit_masks_zero_is_lsb, y 1562 | jsr self_modified_sta_plus_x 1563 | 1564 | label_0e08 1565 | iny 1566 | sty $fc 1567 | cpy #$08 1568 | bne label_0de8 1569 | inx 1570 | cpx #$40 1571 | bne label_0de4 1572 | rts 1573 | 1574 | label_0e15 1575 | stx $fc 1576 | sty $fd 1577 | lda #$04 1578 | sta $fb 1579 | 1580 | label_0e1d 1581 | lda #$00 1582 | sta temp_entity_x_coord 1583 | 1584 | label_0e21 1585 | lda #$00 1586 | sta $fe 1587 | 1588 | label_0e25 1589 | lda $fe 1590 | clc 1591 | adc $fd 1592 | tay 1593 | jsr self_modified_lda_plus_y 1594 | ldx temp_entity_x_coord 1595 | and onebit_masks_zero_is_msb, x 1596 | cmp onebit_masks_zero_is_msb, x 1597 | bne label_0e4e 1598 | lda $03 1599 | clc 1600 | adc $fc 1601 | tay 1602 | jsr self_modified_lda_plus_y 1603 | clc 1604 | ldx $fe 1605 | adc onebit_masks_zero_is_lsb, x 1606 | pha 1607 | tya 1608 | tax 1609 | pla 1610 | jsr self_modified_sta_plus_x 1611 | 1612 | label_0e4e 1613 | inc $fe 1614 | lda $fe 1615 | cmp #$08 1616 | bne label_0e25 1617 | inc temp_entity_x_coord 1618 | lda temp_entity_x_coord 1619 | cmp #$08 1620 | bne label_0e21 1621 | lda $fc 1622 | clc 1623 | adc #$08 1624 | sta $fc 1625 | lda $fd 1626 | clc 1627 | adc #$08 1628 | sta $fd 1629 | dec $fb 1630 | bne label_0e1d 1631 | rts 1632 | 1633 | ; -------------------------------------------------------------------- 1634 | 1635 | self_modified_sta_plus_x 1636 | 1637 | self_mod_sta_base_address_lo = * + 1 1638 | self_mod_sta_base_address_hi = * + 2 1639 | 1640 | ; Self modifying code here.. 1641 | sta $ffff, x 1642 | rts 1643 | 1644 | ; --------------------------------------------------------------------- 1645 | 1646 | self_modified_lda_plus_y 1647 | lda self_mod_sta_base_address_lo 1648 | sta self_mod_lda_base_address_lo 1649 | lda self_mod_sta_base_address_hi 1650 | sta self_mod_lda_base_address_hi 1651 | 1652 | self_mod_lda_base_address_lo = *+1 1653 | self_mod_lda_base_address_hi = *+2 1654 | 1655 | lda $ffff, y 1656 | rts 1657 | 1658 | ; --------------------------------------------------------------------- 1659 | 1660 | load_two_low_bits_of_osc3_to_accumulator 1661 | lda sid_voice3_oscillator_ro 1662 | and #$03 1663 | rts 1664 | 1665 | ; --------------------------------------------------------------------- 1666 | 1667 | 1668 | !zone inc_and_clear_smb_64bytes 1669 | 1670 | ; Adds 64 to the current self-mod base address, and then clears 64 1671 | ; bytes of memory ahead of the new address. 1672 | 1673 | inc_and_clear_smb_64bytes 1674 | lda self_mod_sta_base_address_lo ; Get current address low byte. 1675 | clc ; Add 64. 1676 | adc #$40 1677 | bcc .adding_64_no_carry ; Did it trigger carry? 1678 | inc self_mod_sta_base_address_hi ; If so, increment address high byte. 1679 | 1680 | .adding_64_no_carry 1681 | sta self_mod_sta_base_address_lo ; Write back address low byte. 1682 | lda #$00 ; Load a (value to store) with 0. 1683 | ldx #$3e ; Load x (countdown) with 62. 1684 | ; 62 is used instead of 64 because we will use BPL below, 1685 | ; which will exit only when the countdown goes negative. 1686 | ; 62 will count down to 1, then 0, then -1, for 64 counts. 1687 | 1688 | .clear_64bytes_loop 1689 | jsr self_modified_sta_plus_x ; Write 0 to base address 1690 | dex ; Decrease countdown 1691 | bpl .clear_64bytes_loop ; If it's not -1, loop 1692 | rts ; We're done 1693 | 1694 | ; ---------------------------------------------------------------- 1695 | 1696 | !ifndef remove_dead_code { 1697 | !byte $20,$58,$0F ; JSR $0f58? 1698 | } 1699 | 1700 | !zone draw_map 1701 | 1702 | draw_new_map 1703 | ; Choose a random map number 0-7 which is not the same as current. 1704 | lda sid_voice3_oscillator_ro 1705 | and #$07 1706 | clc 1707 | adc #$26 1708 | cmp current_wall_character 1709 | beq draw_new_map 1710 | sta current_wall_character 1711 | 1712 | ; Choose a random color from those in the lookup table. 1713 | .choose_map_color 1714 | lda sid_voice3_oscillator_ro 1715 | and #$07 1716 | tax 1717 | lda map_colors, x 1718 | cmp current_map_color 1719 | beq .choose_map_color 1720 | sta current_map_color 1721 | 1722 | lda #$00 1723 | sta $bb 1724 | ldx level_bcd_units 1725 | lda level_bcd_tens 1726 | bne label_0ed2 1727 | cpx #$05 1728 | bcc label_0ee2 1729 | 1730 | label_0ed2 1731 | lda sid_voice3_oscillator_ro 1732 | sta $bb 1733 | 1734 | label_0ed7 1735 | jsr load_two_low_bits_of_osc3_to_accumulator 1736 | tax 1737 | inx 1738 | cpx $c8 1739 | beq label_0ed7 1740 | stx $c8 1741 | 1742 | 1743 | .current_x_coordinate = $fd 1744 | .current_drawing_character = $06 1745 | .current_bit_number = $03 1746 | .current_map_offset = $02 1747 | 1748 | label_0ee2 1749 | lda map_start_addresses, x 1750 | sta .current_map_offset 1751 | lda #$00 1752 | sta .current_bit_number 1753 | sta .current_x_coordinate 1754 | ldy #$02 1755 | 1756 | .draw_map_character 1757 | ldx .current_map_offset 1758 | lda $bb 1759 | bmi label_0efb 1760 | lda label_2006, x 1761 | jmp label_0efe 1762 | 1763 | label_0efb 1764 | lda label_20e2, x 1765 | 1766 | 1767 | 1768 | label_0efe 1769 | ldx .current_bit_number 1770 | and onebit_masks_zero_is_msb, x 1771 | beq .draw_empty_space 1772 | lda current_wall_character 1773 | !byte $2c ; BIT skip hack 1774 | .draw_empty_space 1775 | lda #$20 ; May be skipped 1776 | sta .current_drawing_character 1777 | ldx .current_x_coordinate 1778 | jsr write_a_to_screen_position_xy 1779 | lda current_map_color 1780 | jsr write_a_to_colors_position_xy 1781 | lda #$26 1782 | sec 1783 | sbc .current_x_coordinate 1784 | tax 1785 | lda .current_drawing_character 1786 | jsr write_a_to_screen_position_xy 1787 | lda current_map_color 1788 | jsr write_a_to_colors_position_xy 1789 | inc .current_bit_number 1790 | inc .current_x_coordinate 1791 | lda .current_bit_number 1792 | cmp #$08 1793 | bne .no_new_byte 1794 | lda #$00 1795 | sta .current_bit_number 1796 | inc .current_map_offset 1797 | 1798 | .no_new_byte 1799 | lda .current_x_coordinate 1800 | cmp #20 1801 | bne .draw_map_character 1802 | iny 1803 | cpy #24 1804 | beq .done_drawing_map 1805 | lda #$00 1806 | sta .current_x_coordinate 1807 | beq .draw_map_character 1808 | 1809 | .done_drawing_map 1810 | ldx #$27 1811 | 1812 | .copy_screen_forward 1813 | lda screen+$50, x 1814 | sta screen+$3c0, x 1815 | lda current_map_color 1816 | sta colors+$3c0, x 1817 | dex 1818 | bpl .copy_screen_forward 1819 | rts 1820 | 1821 | ; --------------------------------------------------------------------- 1822 | 1823 | !zone update_status_bar 1824 | 1825 | ; Offsets to the given scores, on the second line of the screen, from the start of screen memory. 1826 | 1827 | sbpos_player1_score = 40 1828 | sbpos_player2_score = 67 1829 | sbpos_high_score = 53 1830 | sbpos_player1_lives = 51 1831 | sbpos_player2_lives = 78 1832 | sbpos_level_tens = 63 1833 | sbpos_level_ones = sbpos_level_tens + 1 1834 | sbpos_player1_shields = 49 1835 | sbpos_player2_shields = 76 1836 | 1837 | update_status_bar: 1838 | ; Update the whole stats bar. First, player scores: 1839 | 1840 | ldx #PLAYER_SCORE_DIGITS-1 ; Count down player score digits 1841 | clc ; Set up for addition 1842 | 1843 | .score_digits_loop 1844 | lda player_1_score_digits, x ; Load x'th digit of player score 1845 | adc #NUMBER_TO_PETSCII_ADJUSTMENT ; Convert it to PETSCII value 1846 | sta screen+sbpos_player1_score, x ; Store it in x'th index of screen starting at score position 1847 | 1848 | lda player_2_score_digits, x ; Same for player 2 score 1849 | adc #NUMBER_TO_PETSCII_ADJUSTMENT ; (and for everything else below) 1850 | sta screen+sbpos_player2_score, x 1851 | 1852 | lda high_score_digits, x ; And for high score 1853 | adc #NUMBER_TO_PETSCII_ADJUSTMENT 1854 | sta screen+sbpos_high_score, x 1855 | 1856 | dex ; Count down player score digits 1857 | bpl .score_digits_loop ; Go back to do rest of score 1858 | 1859 | ; Entry point used when scores don't need to be updated. 1860 | update_status_bar_not_scores: 1861 | lda p1_lives ; Player 1 lives 1862 | clc 1863 | adc #NUMBER_TO_PETSCII_ADJUSTMENT 1864 | sta screen+sbpos_player1_lives 1865 | 1866 | lda p2_lives ; Player 2 lives 1867 | adc #NUMBER_TO_PETSCII_ADJUSTMENT 1868 | sta screen+sbpos_player2_lives 1869 | 1870 | lda level_bcd_tens 1871 | adc #NUMBER_TO_PETSCII_ADJUSTMENT 1872 | sta screen+sbpos_level_tens ; Level tens 1873 | 1874 | lda level_bcd_units 1875 | adc #NUMBER_TO_PETSCII_ADJUSTMENT 1876 | sta screen+sbpos_level_ones ; Level units 1877 | 1878 | ; Entry point for updating just the shields. 1879 | update_status_bar_just_shields: 1880 | lda entity_shields ; Player 1 shields 1881 | clc 1882 | adc #NUMBER_TO_PETSCII_ADJUSTMENT 1883 | sta screen+sbpos_player1_shields 1884 | 1885 | lda p2_shields ; Player 2 shields 1886 | adc #NUMBER_TO_PETSCII_ADJUSTMENT 1887 | sta screen+sbpos_player2_shields 1888 | rts 1889 | 1890 | ; ---------------------------------------------------------------------- 1891 | 1892 | ; SELF MODIFYING CODE ALERT 1893 | !zone read_write_a_to_screen_buffer 1894 | 1895 | .temp_acc_store = $0c 1896 | 1897 | write_a_to_screen_position_xy 1898 | sta .temp_acc_store 1899 | lda #$9d ; STA absolute, x 1900 | sta .selfmod_instruction 1901 | bne .calculate_screen_address 1902 | 1903 | read_a_from_screen_position_xy 1904 | lda #$bd ; LDA absolute, x 1905 | sta .selfmod_instruction 1906 | 1907 | .calculate_screen_address 1908 | lda screen_line_address_lowbytes, y 1909 | sta .selfmod_instruction+1 1910 | lda screen_line_address_highbytes, y 1911 | sta .selfmod_instruction+2 1912 | lda .temp_acc_store ; ?? 1913 | 1914 | .selfmod_instruction: 1915 | lda $0400, x ; This instruction is always changed above 1916 | rts 1917 | 1918 | ; ---------------------------------------------------------------------- 1919 | 1920 | !zone read_write_a_to_screen_adjacent_buffers 1921 | 1922 | write_a_to_colors_position_xy 1923 | sta $0c 1924 | lda #$9d ; STA absolute, x 1925 | sta .selfmod_instruction2 1926 | bne .calculate_color_address 1927 | 1928 | read_a_from_colors_position_xy 1929 | lda #$bd ; LDA absolute, x 1930 | sta .selfmod_instruction2 1931 | 1932 | .calculate_color_address 1933 | ; Get the screen address, which begins at $0400 1934 | lda screen_line_address_lowbytes, y 1935 | sta .selfmod_instruction2+1 1936 | lda screen_line_address_highbytes, y 1937 | clc 1938 | adc #$d4 ; Add $d4 to the high byte to make it begin at $d800, colors 1939 | sta .selfmod_instruction2+2 1940 | 1941 | if_were_going_to_selfmodify_why_not_just_jump_in_from_another_routine: 1942 | lda $0c 1943 | .selfmod_instruction2: 1944 | lda $0400, x 1945 | rts 1946 | 1947 | ; --------------------------------------------------------------------- 1948 | 1949 | ; Writes a to screen position plus $bc00, ie, $c000. This isn't a 1950 | ; significant address that I can see.. Not a separate zone because it 1951 | ; reuses the self modified instruction above. Also, this uses the BIT 1952 | ; skip hack where the previous ones didn't although they could have. 1953 | ; Possibly the author added this in Crossroads 2 and didn't originally 1954 | ; know about the BIT hack? 1955 | 1956 | write_a_to_screen_entityId_buffer_position_xy 1957 | sta $0c 1958 | lda #$9d ; STA absolute, x 1959 | !byte $2c ; BIT skipping hack 1960 | 1961 | read_a_from_entityId_buffer_position_x_y 1962 | lda #$bd ; LDA absolute, x 1963 | 1964 | sta .selfmod_instruction2 1965 | lda screen_line_address_lowbytes, y 1966 | sta .selfmod_instruction2+1 1967 | lda screen_line_address_highbytes, y 1968 | clc 1969 | adc #$bc 1970 | sta .selfmod_instruction2+2 1971 | jmp if_were_going_to_selfmodify_why_not_just_jump_in_from_another_routine 1972 | 1973 | ; ----------------------------------------------------------------- 1974 | 1975 | !zone clear_explosions 1976 | 1977 | clear_explosions: 1978 | ldx #$07 1979 | lda #$00 1980 | 1981 | .explosion_clear_loop 1982 | sta explosion_status, x 1983 | sta vic_sprite_coord_array, x ; Covers sprite coordinates 0-3 1984 | sta vic_sprite_coord_array+8, x ; Covers sprite coordinates 4-7 1985 | dex 1986 | bpl .explosion_clear_loop 1987 | rts 1988 | 1989 | ; --------------------------------------------------------------------- 1990 | 1991 | !zone interrupt_service_routine 1992 | 1993 | interrupt_service_routine: 1994 | inc interrupt_counter 1995 | ldx game_status_flags 1996 | lda sound_buffer, x 1997 | sta sid_volume_filter 1998 | beq label_1028 1999 | lda jiffy_clock 2000 | and #01 2001 | bne label_102b 2002 | label_1028: 2003 | jmp $ea31 ; Jump to system ISR 2004 | 2005 | 2006 | .currently_checking_player = $6a 2007 | 2008 | label_102b: 2009 | ldx #01 2010 | stx .currently_checking_player 2011 | 2012 | .isr_player_update: 2013 | lda player_fire_cooldown_counter, x 2014 | beq label_1035 2015 | dec player_fire_cooldown_counter, x 2016 | 2017 | label_1035: 2018 | dec player_move_cooldown_counter, x 2019 | bne label_1041 2020 | lda player_move_cooldown, x 2021 | sta player_move_cooldown_counter, x 2022 | lda #01 2023 | sta player_has_ticked, x 2024 | 2025 | label_1041: 2026 | lda player_sound_flag, x 2027 | beq .isr_done_checking_player 2028 | ldy sid_voice_offsets, x 2029 | cmp #05 2030 | bcc label_1067 2031 | bne label_1054 2032 | lda $68, x 2033 | ldx #$21 2034 | bne label_107a 2035 | 2036 | label_1054: 2037 | cmp #07 2038 | beq label_105e 2039 | lda $68, x 2040 | ldx #$81 2041 | bne label_107a 2042 | 2043 | label_105e: 2044 | lda $68, x 2045 | clc 2046 | adc #$f6 2047 | ldx #$81 2048 | bne label_107a 2049 | 2050 | label_1067: 2051 | tax 2052 | lda sid_voice3_oscillator_ro 2053 | and label_1f41, x 2054 | clc 2055 | adc label_1f3d, x 2056 | sta $8f 2057 | lda label_1f39, x 2058 | tax 2059 | lda $8f 2060 | 2061 | label_107a: 2062 | sta sid_voice1_high_freq, y 2063 | lda #$09 2064 | sta sid_voice1_att_dec, y 2065 | lda #$00 2066 | sta sid_voice1_control, y 2067 | txa 2068 | sta sid_voice1_control, y 2069 | ldx .currently_checking_player 2070 | dec $68, x 2071 | bne .isr_done_checking_player 2072 | lda #00 2073 | sta player_sound_flag, x 2074 | sta sid_voice1_control, y 2075 | 2076 | .isr_done_checking_player: 2077 | dex 2078 | dec .currently_checking_player 2079 | bpl .isr_player_update 2080 | 2081 | 2082 | dec $40 2083 | bne dont_update_difficulty 2084 | 2085 | lda #$03 2086 | sta $40 2087 | lda escalation 2088 | sec 2089 | sbc enemy_sweep_count 2090 | beq done_difficulty_check 2091 | bcs .increase_difficulty 2092 | dec difficulty 2093 | bne done_difficulty_check ; If it didnt' become zero, branch.. 2094 | 2095 | inc difficulty ; So it did become zero.. here it becomes one.. 2096 | bne done_difficulty_check ; How would this not be true? 2097 | .increase_difficulty: 2098 | inc difficulty 2099 | bne done_difficulty_check ; If it didn't become zero, branch.. 2100 | dec difficulty ; It was zero, so here it becomes $ff. 2101 | 2102 | done_difficulty_check: 2103 | !ifdef show_timing_info { 2104 | ldx #20 2105 | lda enemy_sweep_count 2106 | jsr display_hex_value 2107 | ldx #32 2108 | lda difficulty 2109 | jsr display_hex_value 2110 | } 2111 | 2112 | lda #00 2113 | sta enemy_sweep_count 2114 | 2115 | dont_update_difficulty: 2116 | dec spar_animation_timer 2117 | bne .dont_animate_spars 2118 | lda #02 2119 | sta spar_animation_timer 2120 | 2121 | ; Animate rotating spars. 2122 | ldx current_spar_frame 2123 | dex 2124 | bpl .no_spar_frame_wraparound 2125 | ldx #$02 2126 | .no_spar_frame_wraparound: 2127 | stx current_spar_frame 2128 | ldy multiply_by_8, x 2129 | ldx #$07 2130 | 2131 | .copy_new_spar_image: 2132 | lda spar_images, y 2133 | sta $29f8, x 2134 | iny 2135 | dex 2136 | bpl .copy_new_spar_image 2137 | 2138 | .dont_animate_spars: 2139 | ldx #$07 2140 | 2141 | .do_explosions_loop: 2142 | lda explosion_status, x 2143 | beq label_1143 2144 | ldy explosion_or_implosion, x 2145 | lda explosion_sprite_pointer_offset, x 2146 | clc 2147 | adc data_explosion_deltas, y 2148 | cmp data_explosion_limits, y 2149 | beq label_110f 2150 | sta explosion_sprite_pointer_offset, x 2151 | sec 2152 | sbc #$02 2153 | cmp data_explosion_limits, y 2154 | bne label_1139 2155 | ldy exploding_entity_index, x 2156 | lda entity_status_byte, y 2157 | and #$bf ; Reset bit 7 2158 | sta entity_status_byte, y 2159 | jmp label_1139 2160 | 2161 | label_110f: 2162 | cpy #00 2163 | beq .end_explosion 2164 | lda $4038, x 2165 | beq .end_explosion 2166 | lda explosion_count_up_array, x 2167 | clc 2168 | adc #01 2169 | cmp #$0f 2170 | bcs .end_explosion 2171 | sta explosion_count_up_array, x 2172 | lda $4038, x 2173 | adc #$f5 2174 | bne label_1140 2175 | 2176 | .end_explosion: 2177 | ; Clear explosion status entry 2178 | lda #$00 2179 | sta explosion_status, x 2180 | 2181 | ; Sprite coord array is in pairs x/y, so multiply explosion number 2182 | ; by 2 to get sprite number used for it 2183 | txa 2184 | asl 2185 | tay 2186 | 2187 | ; Move that sprite to y coordinate 0 2188 | lda #$00 2189 | sta vic_sprite_coord_array+1, y 2190 | 2191 | label_1139: 2192 | lda explosion_base_sprite_pointer, x 2193 | clc 2194 | adc explosion_sprite_pointer_offset, x 2195 | 2196 | label_1140: 2197 | sta vic_sprite_pointer_array, x 2198 | 2199 | label_1143: 2200 | dex 2201 | bmi label_1149 2202 | jmp .do_explosions_loop 2203 | 2204 | label_1149: 2205 | jmp $ea31 ; System interrupt service routine 2206 | 2207 | ; ---------------------------------------------------------------------- 2208 | 2209 | 2210 | reset_entity_count_and_udgs 2211 | lda #$00 ; Set empty entity to 0 2212 | sta max_enemy_entity 2213 | sta $bc ; ?? 2214 | 2215 | ; Reset UDG slot index array to $ff 2216 | ldx #$12 2217 | lda #$ff 2218 | .reset_udg_index_array 2219 | sta slot_udg_loaded_into, x 2220 | sta $4083, x 2221 | dex 2222 | bpl .reset_udg_index_array 2223 | 2224 | lda #$00 2225 | sta udg_slot_to_load_to 2226 | lda #$10 2227 | sta udg_number_to_load 2228 | 2229 | .load_initial_udgs_loop ; Load 13 initial UDGs from $10 upwards 2230 | jsr load_udg_localvars ; Actually load current UDG 2231 | lda udg_slot_to_load_to ; Add it to index array 2232 | ldy udg_number_to_load 2233 | sta slot_udg_loaded_into, y 2234 | inc udg_number_to_load ; Increment UDG and slot to load 2235 | inc udg_slot_to_load_to 2236 | cpy #$13 ; Repeat if less than 13 loaded 2237 | bcc .load_initial_udgs_loop 2238 | 2239 | ldx #$0c 2240 | stx last_enemy_processed 2241 | dex 2242 | stx last_entity_killed_by_overpopulation 2243 | lda sid_voice3_oscillator_ro 2244 | and #$1f 2245 | adc #$28 2246 | sta enemies_left_to_spawn 2247 | rts 2248 | 2249 | ; ------------------------------------------------------------------- 2250 | 2251 | !zone spawn_enemy_maybe 2252 | 2253 | 2254 | spawn_enemy_maybe 2255 | lda sid_voice3_oscillator_ro 2256 | and #$0f 2257 | tax 2258 | lda level_number_byte 2259 | cmp enemy_release_schedule, x 2260 | bcc spawn_enemy_maybe 2261 | lda slot_udg_loaded_into, x 2262 | bpl label_11dc 2263 | lda udg_slot_to_load_to 2264 | cmp #$0a 2265 | bcc label_11bd 2266 | bne spawn_enemy_maybe 2267 | cpx #$03 2268 | beq spawn_enemy_maybe 2269 | cpx #$04 2270 | beq spawn_enemy_maybe 2271 | lda $4099 2272 | bmi label_11bd 2273 | lda $4098 2274 | bpl label_11bd 2275 | lda $409a 2276 | bmi label_11bd 2277 | ldx #$02 2278 | 2279 | label_11bd 2280 | inc udg_slot_to_load_to 2281 | lda udg_slot_to_load_to 2282 | sta slot_udg_loaded_into, x 2283 | stx udg_number_to_load 2284 | jsr load_udg_localvars 2285 | ldx udg_number_to_load 2286 | lda level_number_byte 2287 | cmp label_1fe2, x 2288 | bcc label_11dc 2289 | lda sid_voice3_oscillator_ro 2290 | and #$03 2291 | beq label_11dc 2292 | sta $4083, x 2293 | 2294 | label_11dc 2295 | stx udg_number_to_load 2296 | jsr set_xy_to_random_empty_space_coord 2297 | lda udg_number_to_load 2298 | jsr spawn_enemy_type_a_at_position_xy 2299 | ldx $a3 2300 | lda #$00 2301 | jsr explode_entity_maybe 2302 | ldx $a3 2303 | lda udg_number_to_load 2304 | cmp #$0c 2305 | bne label_120f 2306 | lda level_number_byte 2307 | cmp #$14 2308 | bcc label_120f 2309 | lda #$02 2310 | sta entity_upd_cooldown, x 2311 | lda #$49 2312 | sta entity_color_and_flags, x 2313 | lda #$05 2314 | sta entity_shields, x 2315 | lda #$18 2316 | sta entity_status_byte, x 2317 | 2318 | label_120f 2319 | lda extra_enemies_spawnable 2320 | bpl erase_entity_x_from_screen 2321 | lda #$00 2322 | sta entity_shields, x 2323 | rts 2324 | 2325 | ; -------------------------------------------------------------------- 2326 | 2327 | !zone erase_entity_x_from_screen 2328 | 2329 | erase_entity_x_from_screen: 2330 | ldy entity_y_coords, x 2331 | lda entity_x_coords, x 2332 | tax 2333 | lda #$00 2334 | jsr write_a_to_colors_position_xy 2335 | lda #$00 2336 | jmp write_a_to_screen_position_xy 2337 | 2338 | ; -------------------------------------------------------------------- 2339 | 2340 | ; Fire the two bullets which appear when a player spawns. 2341 | 2342 | !zone fire_player_spawn_bullets_from_player_y 2343 | 2344 | .temp_y_store = $0f 2345 | fire_player_spawn_bullets_from_player_y 2346 | sty .temp_y_store ; Store player number 2347 | 2348 | ; Fire the first bullet, which always goes upwards. 2349 | lda #dir_up 2350 | jsr fire_bullet_from_entity_y_in_direction_a 2351 | 2352 | ; Fire the second bullet, which goes the way the player starts. 2353 | ldy .temp_y_store 2354 | lda player_spawn_facing, y 2355 | jmp fire_bullet_from_entity_y_in_direction_a 2356 | 2357 | ; --------------------------------------------------------------------- 2358 | 2359 | sound_related_something 2360 | cpy #$02 2361 | bcs label_1246 2362 | ldy #$00 2363 | cmp #$05 2364 | beq label_124f 2365 | iny 2366 | bne label_124f 2367 | 2368 | label_1246 2369 | ldy player_sound_flag 2370 | beq label_124f 2371 | ldy player_sound_flag+1 2372 | bne label_1258 2373 | iny 2374 | 2375 | label_124f 2376 | sta player_sound_flag, y 2377 | lda #$14 2378 | sta $0068, y 2379 | rts 2380 | 2381 | label_1258 2382 | ldy #$00 2383 | lda player_sound_flag 2384 | cmp #$06 2385 | beq label_124f 2386 | iny 2387 | lda $67 2388 | cmp #$06 2389 | beq label_124f 2390 | rts 2391 | 2392 | !ifndef remove_dead_code { 2393 | !byte $AA 2394 | } 2395 | 2396 | 2397 | ; ----------------------------------------------------------------- 2398 | 2399 | char_to_write = $fb 2400 | side_to_write = $8d 2401 | color_to_write = $fc 2402 | 2403 | !zone draw_entity_x 2404 | 2405 | draw_entity_x: 2406 | lda entity_color_and_flags, x 2407 | sta color_to_write 2408 | 2409 | draw_entity_x_override_color: 2410 | lda entity_color_and_flags, x 2411 | and #csf_visible 2412 | bne label_1279 2413 | lda #$00 2414 | sta color_to_write 2415 | 2416 | label_1279 2417 | stx side_to_write 2418 | lda entity_facing, x 2419 | tay 2420 | lda unknown_facing_table, y 2421 | clc 2422 | adc entity_base_charno, x 2423 | sta char_to_write 2424 | lda entity_status_byte, x 2425 | bpl label_128f 2426 | inc char_to_write 2427 | 2428 | label_128f 2429 | lda entity_status_byte, x 2430 | and #esb_secondframe 2431 | beq .no_charno_offset 2432 | inc char_to_write 2433 | inc char_to_write 2434 | inc char_to_write 2435 | 2436 | .no_charno_offset: 2437 | stx temp_entity_x_coord 2438 | jsr write_scrn_char_side_from_localvars_to_entity_x_coords 2439 | ldx temp_entity_x_coord 2440 | lda entity_status_byte, x 2441 | bpl .no_second_half 2442 | inc char_to_write 2443 | 2444 | draw_second_half_of_midsquare_entity_x: 2445 | jsr propose_forward_move_coords_for_entity_x 2446 | ldx proposed_entity_x_coord 2447 | ldy proposed_entity_y_coord 2448 | jsr write_scrn_char_side_from_localvars_to_xy 2449 | 2450 | .no_second_half: 2451 | rts 2452 | 2453 | ; -------------------------------------------------------------------- 2454 | 2455 | !zone write_scrn_char_side_from_localvars_to_entity_x_coords 2456 | 2457 | write_scrn_char_side_from_localvars_to_entity_x_coords 2458 | lda entity_y_coords, x 2459 | jsr wraparound_y_coordinate_a 2460 | tay 2461 | lda entity_x_coords, x 2462 | jsr wraparound_x_coordinate_a 2463 | tax 2464 | 2465 | 2466 | write_scrn_char_side_from_localvars_to_xy 2467 | lda color_to_write 2468 | jsr write_a_to_colors_position_xy 2469 | lda char_to_write 2470 | jsr write_a_to_screen_position_xy 2471 | lda side_to_write 2472 | jmp write_a_to_screen_entityId_buffer_position_xy 2473 | 2474 | ; -------------------------------------------------------------------- 2475 | 2476 | !zone set_xy_to_random_empty_space_coord 2477 | 2478 | .initial_rand = $fc 2479 | set_xy_to_random_empty_space_coord 2480 | lda sid_voice3_oscillator_ro 2481 | and #$1f ; random value 0-31.. 2482 | sta .initial_rand 2483 | lda sid_voice3_oscillator_ro 2484 | and #$07 ; add random value 0-7, to make 0-38. 2485 | clc 2486 | adc .initial_rand 2487 | tax ; store in x 2488 | lda sid_voice3_oscillator_ro 2489 | and #$0f ; random value 0-15 2490 | adc #$02 ; add 2 for 2 rows of status bar.. 2491 | sta .initial_rand 2492 | lda sid_voice3_oscillator_ro 2493 | and #$07 ; add random value 0-7 to make 2-24 2494 | adc .initial_rand 2495 | tay 2496 | jsr read_a_from_screen_position_xy ; get value at that position 2497 | cmp #c_empty ; is it blank? 2498 | bne set_xy_to_random_empty_space_coord ; if not, try again 2499 | rts 2500 | 2501 | ; ---------------------------------------------------------------------- 2502 | 2503 | explode_entity_maybe 2504 | sta $fc 2505 | tay 2506 | stx $fe 2507 | lda #$05 2508 | sta extra_enemies_spawnable 2509 | cpy #$00 2510 | bne label_130a 2511 | dec extra_enemies_spawnable 2512 | 2513 | label_130a 2514 | ldx label_1e9b, y 2515 | 2516 | label_130d 2517 | lda explosion_status, x 2518 | beq label_133b 2519 | lda explosion_or_implosion, x 2520 | bne label_1328 2521 | dec extra_enemies_spawnable 2522 | bpl label_1328 2523 | lda $fe 2524 | cmp #$02 2525 | bcc label_1322 2526 | rts 2527 | 2528 | label_1322 2529 | clc 2530 | adc #$05 2531 | tax 2532 | bne label_133b 2533 | 2534 | label_1328 2535 | dex 2536 | bpl label_130d 2537 | 2538 | label_132b 2539 | ldx last_processed_explosion 2540 | inx 2541 | cpx #$08 2542 | bcc label_1334 2543 | ldx #$00 2544 | 2545 | label_1334 2546 | stx last_processed_explosion 2547 | lda explosion_or_implosion, x 2548 | beq label_132b 2549 | 2550 | label_133b 2551 | lda #$00 2552 | sta explosion_count_up_array, x 2553 | lda $fc 2554 | sta explosion_or_implosion, x 2555 | beq label_1359 2556 | ldy entity_number_that_hit_player 2557 | cpy #$0c 2558 | bcs label_1359 2559 | ldy $0a 2560 | lda entity_shields, y 2561 | bne label_1359 2562 | lda entity_score_awarded, y 2563 | bne label_1361 2564 | 2565 | label_1359 2566 | lda #$08 2567 | tay 2568 | jsr sound_related_something 2569 | lda #$00 2570 | 2571 | label_1361 2572 | sta $4038, x 2573 | ldy $fc 2574 | lda label_1f1a, y 2575 | sta explosion_sprite_pointer_offset, x 2576 | lda sid_voice3_oscillator_ro 2577 | and #$01 2578 | tay 2579 | lda label_1f09, y 2580 | sta explosion_base_sprite_pointer, x 2581 | lda $fe 2582 | sta exploding_entity_index, x 2583 | tay 2584 | lda entity_color_and_flags, y 2585 | sta vic_sprite_color_array, x 2586 | lda entity_status_byte, y 2587 | bmi label_138d 2588 | lda #$00 2589 | beq label_1396 2590 | 2591 | label_138d 2592 | lda entity_facing, y 2593 | tay 2594 | sta $fd 2595 | lda label_1edb, y 2596 | 2597 | label_1396 2598 | clc 2599 | adc #$14 2600 | sta $fc 2601 | ldy $fe 2602 | lda entity_x_coords, y 2603 | cmp #$1e 2604 | bcs label_13b0 2605 | lda #$ff 2606 | sec 2607 | sbc onebit_masks_zero_is_lsb, x 2608 | and vic_sprite_x_hibits 2609 | jmp label_13b6 2610 | 2611 | label_13b0 2612 | lda onebit_masks_zero_is_lsb, x 2613 | ora vic_sprite_x_hibits 2614 | 2615 | label_13b6 2616 | sta vic_sprite_x_hibits 2617 | lda entity_x_coords, y 2618 | asl 2619 | asl 2620 | asl 2621 | clc 2622 | adc $fc 2623 | sta $fc 2624 | txa 2625 | asl 2626 | tay 2627 | lda $fc 2628 | sta vic_sprite_coord_array, y 2629 | ldy $fe 2630 | lda entity_status_byte, y 2631 | bmi label_13d7 2632 | lda #$00 2633 | beq label_13dc 2634 | 2635 | label_13d7 2636 | ldy $fd 2637 | lda label_1edf, y 2638 | 2639 | label_13dc 2640 | clc 2641 | adc #$2d 2642 | sta $fc 2643 | ldy $fe 2644 | lda entity_y_coords, y 2645 | asl 2646 | asl 2647 | asl 2648 | clc 2649 | adc $fc 2650 | sta $fc 2651 | txa 2652 | asl 2653 | tay 2654 | lda $fc 2655 | sta vic_sprite_coord_array+1, y 2656 | inc explosion_status, x 2657 | rts 2658 | 2659 | ; -------------------------------------------------------------------- 2660 | 2661 | !zone spawn_enemy_type_a_at_position_xy 2662 | 2663 | .temp = $04 2664 | 2665 | spawn_enemy_type_a_at_position_xy 2666 | sta .temp 2667 | tya 2668 | pha 2669 | txa 2670 | pha 2671 | jsr find_free_enemy_entity_in_x_and_locals 2672 | lda .temp 2673 | jsr load_enemy_type_a_data_into_entity_slot_x_with_last_loaded_udg 2674 | pla 2675 | sta entity_x_coords, x 2676 | pla 2677 | sta entity_y_coords, x 2678 | jsr load_two_low_bits_of_osc3_to_accumulator 2679 | sta entity_facing, x 2680 | lda #$01 2681 | sta entity_upd_countdown, x 2682 | lda #$00 2683 | sta entity_spars_eaten, x 2684 | rts 2685 | 2686 | ; ---------------------------------------------------------------- 2687 | 2688 | !zone find_free_enemy_entity_in_x_and_locals 2689 | 2690 | find_free_enemy_entity_in_x_and_locals 2691 | ldx #$0c ; $c seems to be the first offset for enemy entities. 2692 | 2693 | ; Look for an entity with zero shields (dead) to reuse its position. 2694 | .find_zero_shield_entity 2695 | lda entity_shields, x 2696 | beq .found_zero_shield_entity 2697 | inx 2698 | bne .find_zero_shield_entity ; Keep looking until X wraps to zero.. 2699 | 2700 | ; X wrapped to zero? Bugger, there's no free space. Move the 2701 | ; overpopulation kill pointer forwards by one, and wrap it around 2702 | ; if also goes off the end. 2703 | 2704 | ldx last_entity_killed_by_overpopulation ; Entity max? 2705 | inx 2706 | bne .no_overpop_wrap 2707 | ldx #$0c ; Reuse 1st entity?? 2708 | 2709 | .no_overpop_wrap 2710 | 2711 | ; Wipe the unlucky entity off the screeen, and drop any spars it's 2712 | ; holding. 2713 | stx last_entity_killed_by_overpopulation 2714 | jsr blank_out_entity_x_nondestructive 2715 | ldx last_entity_killed_by_overpopulation 2716 | jsr drop_spars_from_entity_x 2717 | ldx last_entity_killed_by_overpopulation 2718 | 2719 | .found_zero_shield_entity 2720 | cpx max_enemy_entity ; If found entity no was less than current max, 2721 | bcc .empty_entity_already_existed ; leave it alone. 2722 | stx max_enemy_entity ; Else, update max to found entity number. 2723 | 2724 | .empty_entity_already_existed 2725 | stx $a3 ; I'm not sure when/if this is used.. 2726 | rts 2727 | 2728 | ; ----------------------------------------------------------------- 2729 | ; Some kind of new entity setup?? 2730 | 2731 | !zone load_enemy_type_a_data_into_entity_slot_x_with_last_loaded_udg 2732 | 2733 | load_enemy_type_a_data_into_entity_slot_x_with_last_loaded_udg 2734 | tay 2735 | sta entity_enemy_type, x 2736 | lda enemy_type_colors, y 2737 | sta entity_color_and_flags, x 2738 | lda enemy_initial_status, y 2739 | sta entity_status_byte, x 2740 | lda enemy_data_a, y 2741 | sta entity_type_fired_me, x 2742 | lda enemy_bullet_types, y 2743 | sta entity_bullet_type, x 2744 | lda enemy_data_cd, y 2745 | pha 2746 | and #$0f 2747 | sta entity_data_cdlow, x 2748 | pla 2749 | lsr 2750 | lsr 2751 | lsr 2752 | lsr 2753 | sta entity_bullet_speed, x 2754 | lda enemy_data_low_shields_high_score, y 2755 | pha 2756 | and #$0f 2757 | sta entity_shields, x 2758 | pla 2759 | lsr 2760 | lsr 2761 | lsr 2762 | lsr 2763 | sta entity_score_awarded, x 2764 | lda enemy_data_low_vision_high_update_cooldown, y 2765 | pha 2766 | and #$0f 2767 | sta entity_vision_distance, x 2768 | pla 2769 | lsr 2770 | lsr 2771 | lsr 2772 | lsr 2773 | sta entity_upd_cooldown, x 2774 | lda slot_udg_loaded_into, y 2775 | asl 2776 | asl 2777 | asl 2778 | asl 2779 | clc 2780 | adc #$40 2781 | sta entity_base_charno, x 2782 | rts 2783 | 2784 | ; ------------------------------------------------------------------- 2785 | 2786 | !zone blank_out_entity_x_nondestructive 2787 | 2788 | ; Deletes entity x from screen by overwriting with a space, with 2789 | ; color and side values determined by local var values. Goes to 2790 | ; great lengths to avoid overwriting x in the process. 2791 | blank_out_entity_x_nondestructive 2792 | lda #c_empty 2793 | sta char_to_write 2794 | txa 2795 | pha 2796 | jsr write_scrn_char_side_from_localvars_to_entity_x_coords 2797 | pla 2798 | tax 2799 | lda entity_status_byte, x 2800 | bpl .no_second_half 2801 | jmp draw_second_half_of_midsquare_entity_x 2802 | 2803 | .no_second_half 2804 | rts 2805 | 2806 | ; -------------------------------------------------------------------- 2807 | 2808 | !zone give_player_x_score_for_entity_y 2809 | 2810 | give_player_x_score_for_entity_y 2811 | lda entity_score_awarded, y 2812 | ldy multiply_by_8, x 2813 | clc 2814 | adc player_1_score_digits+5, y 2815 | sta player_1_score_digits+5, y 2816 | jsr score_update 2817 | jmp update_status_bar 2818 | 2819 | ; --------------------------------------------------------------------- 2820 | 2821 | !zone score_update 2822 | 2823 | .saved_player_number = $07 2824 | .current_rollover_digit = $fc 2825 | 2826 | score_update 2827 | stx .saved_player_number 2828 | lda #$05 2829 | sta .current_rollover_digit 2830 | clc 2831 | adc multiply_by_8, x 2832 | tax 2833 | 2834 | .bcd_rollover_loop 2835 | lda player_1_score_digits, x ; Get current digit 2836 | cmp #$0a ; Is it over 10? 2837 | bcc .no_bcd_rollover ; If not, don't continue. 2838 | sec ; Yes. Subtract 10 to get proper digit 2839 | sbc #$0a 2840 | sta player_1_score_digits, x ; Store corrected digit 2841 | dex ; And increase next digit 2842 | inc player_1_score_digits, x 2843 | inx 2844 | bne .bcd_rollover_loop ; Repeat ("digit" might have been 20+..) 2845 | 2846 | .no_bcd_rollover 2847 | dex ; Proceed to next digit 2848 | dec .current_rollover_digit 2849 | bpl .bcd_rollover_loop 2850 | 2851 | 2852 | ldx .saved_player_number 2853 | ldy multiply_by_8, x 2854 | lda $6043, y 2855 | lsr 2856 | cmp $ae, x 2857 | beq .no_extra_life 2858 | sta $ae, x 2859 | 2860 | ; Gives player an extra life, capped at 9. 2861 | lda p1_lives, x ; Get player lives 2862 | clc ; Add 1 2863 | adc #$01 2864 | cmp #$0a ; If 10 or more 2865 | bcc .no_lives_cap ; Ok, else 2866 | lda #$09 ; Reduce to 9 2867 | 2868 | .no_lives_cap 2869 | sta p1_lives, x 2870 | 2871 | .no_extra_life 2872 | ldx #$00 2873 | stx $fc 2874 | 2875 | label_150f 2876 | lda player_1_score_digits, y 2877 | cmp high_score_digits, x 2878 | bcc label_1526 2879 | beq label_151e 2880 | 2881 | label_1519 2882 | sta high_score_digits, x 2883 | dec $fc 2884 | 2885 | label_151e 2886 | iny 2887 | inx 2888 | cpx #$06 2889 | bcc label_150f 2890 | beq label_152a 2891 | 2892 | label_1526 2893 | cmp $fc 2894 | bcc label_1519 2895 | 2896 | label_152a 2897 | ldx .saved_player_number 2898 | rts 2899 | 2900 | ; --------------------------------------------------------------------- 2901 | 2902 | ; ENEMIES GAME LOOP. This is game loop part 3, and the only part that runs on 2903 | ; the title screen. 2904 | 2905 | !zone game_loop_enemies 2906 | 2907 | game_loop_enemies: 2908 | lda enemies_left_to_spawn ; Do we still have enemies to spawn? 2909 | beq .initial_spawns_done ; If not, just do random spawns. 2910 | jsr spawn_enemy_maybe ; If so, spawn an enemy. 2911 | lda extra_enemies_spawnable ; After that, do we have scope to spawn extra enemies? 2912 | bmi done_enemy_spawning ; If no, we're done with spawning. 2913 | dec enemies_left_to_spawn ; Otherwise, think about spawning one. 2914 | 2915 | .initial_spawns_done 2916 | lda sid_voice3_oscillator_ro ; Get random value 2917 | bne done_enemy_spawning ; If it's not zero (3/4 chance), don't spawn. 2918 | lda sid_voice3_oscillator_ro ; Get another random value 2919 | cmp extra_enemy_spawn_chance ; Compare to level spawn chance. 2920 | bcs done_enemy_spawning ; If higher, don't spawn. 2921 | jsr spawn_enemy_maybe ; Otherwise, spawn an enemy. 2922 | 2923 | ; Actual enemy processing. For speed, we only run ONE enemy's AI each cycle. 2924 | ; However, we can skip over any number of ineligible enemies along the way. 2925 | 2926 | done_enemy_spawning 2927 | inc last_enemy_processed ; Move to next active enemy. 2928 | ldx last_enemy_processed ; Load active enemy number. 2929 | cpx max_enemy_entity ; Compare to max entity. 2930 | bcc process_entity_x_no_return ; If it's LESS, treat as regular entity 2931 | ; processing. If the entity is dead, frozen, 2932 | ; or not ticked, this will return to $1549. 2933 | ; If an entity is processed, this will eventually 2934 | ; tail call to draw_entity_x, which will RTS 2935 | ; and return to $0d33. 2936 | 2937 | beq .maybe_prune_last_dead_entity ; If it's EQUAL, process the enemy as 2938 | ; normal if it's alive, but if it's dead, 2939 | ; lower the max. This means that each 2940 | ; cycle the max will tend towards the 2941 | ; number of active entities. 2942 | bcs .reset_enemy_sweep 2943 | 2944 | .maybe_prune_last_dead_entity 2945 | lda entity_shields, x ; Is the entity at the max point alive? 2946 | bne process_entity_x_not_dead ; Yes, process it as usual. 2947 | dec max_enemy_entity ; Otherwise, lower the max. 2948 | 2949 | .reset_enemy_sweep 2950 | ldx #$0b ; Set last enemy to $0b, one entity before 2951 | stx last_enemy_processed ; the start of possible enemies. 2952 | inc enemy_sweep_count 2953 | rts 2954 | 2955 | ; ------------------------------------------------------------------- 2956 | 2957 | !zone enemy_update_maybe 2958 | 2959 | process_entity_x_no_return 2960 | lda entity_shields, x ; If entity is dead, don't update it. 2961 | beq done_enemy_spawning 2962 | 2963 | process_entity_x_not_dead 2964 | lda entity_status_byte, x ; Check frozen bit? 2965 | and #esb_frozen ; If set, don't update, 2966 | bne done_enemy_spawning ; nor count this as the updated enemy this cycle. 2967 | 2968 | dec entity_upd_countdown, x ; Update entity's tick countdown. 2969 | bne done_enemy_spawning ; If not 0, no further update, and this isn't 2970 | ; the updated enemy this cycle. 2971 | 2972 | lda entity_upd_cooldown, x ; If 0, reset to cooldown. 2973 | sta entity_upd_countdown, x 2974 | lda entity_spars_eaten, x 2975 | bpl .do_enemy_update 2976 | lda #$00 ; Not sure how spars eaten would go negative?? 2977 | sta entity_spars_eaten, x 2978 | jmp draw_entity_x 2979 | 2980 | .do_enemy_update: 2981 | lda entity_status_byte, x ; Are we between squares? 2982 | bpl .full_enemy_update ; If not, do a full update. 2983 | ; Otherwise, all we can do is move forward. 2984 | jmp move_forward_and_redraw_entity_x 2985 | 2986 | 2987 | .full_enemy_update 2988 | lda entity_bullet_type, x ; Check if we are a bullet, or a monster. 2989 | bpl .creature_ai ; If we're a monster, go do smarter stuff. 2990 | 2991 | .stored_entity_number = $13 2992 | 2993 | ; We are a bullet. 2994 | 2995 | update_bullet: 2996 | stx .stored_entity_number 2997 | jsr load_a_with_screen_at_entity_x_forward_coords 2998 | ldx .stored_entity_number 2999 | cmp #c_empty ; Are we moving into empty space? 3000 | bne .bullet_hit_something ; No? 3001 | jmp clear_bit_3_on_entity_x_and_draw ; If we are, just move forward. 3002 | 3003 | .bullet_hit_something 3004 | ldy entity_bullet_type, x 3005 | bmi label_15ad ; A still holds screen value at this point?? 3006 | dec difficulty ; Decrease difficulty?? 3007 | bne label_15ad 3008 | inc difficulty 3009 | 3010 | label_15ad 3011 | cmp #c_player 3012 | bcc .bullet_hit_wall 3013 | jsr blank_out_entity_x_nondestructive 3014 | ldx .stored_entity_number 3015 | jsr set_0a_and_y_to_entityid_that_x_collides_with 3016 | jmp process_collision_between_09_and_0a 3017 | 3018 | 3019 | ; If a bullet hit a wall, just kill it - set shields to 0 and delete it from the screen. 3020 | 3021 | .bullet_hit_wall 3022 | lda #$00 3023 | sta entity_shields, x 3024 | jmp blank_out_entity_x_nondestructive 3025 | 3026 | ; ------------------------------------------------------------------ 3027 | 3028 | .creature_ai 3029 | jsr load_vision_buffers_entity_x 3030 | ldy #dir_left 3031 | 3032 | .check_direction_y 3033 | ldx last_enemy_processed 3034 | lda vision_char_seen_indir, y 3035 | cmp #c_spar ; Did we see something with LESS value than a spar? 3036 | bcc .saw_nothing_interesting ; It's not interesting. 3037 | cmp #c_player ; Did we see the player OR GREATER? 3038 | bcs .saw_entity ; Count it as an entity seen. 3039 | lda entity_color_and_flags, x ; If we're here, we saw a spar. 3040 | and #csf_collects_spars ; Are we interested in them? 3041 | beq .saw_nothing_interesting ; If not, ignore it. 3042 | jsr apply_proximity_bonus_in_direction_y ; If so, add proximity votes. 3043 | 3044 | .saw_nothing_interesting 3045 | dey ; Check next direction. 3046 | bpl .check_direction_y 3047 | jmp .end_voting_prefer_existing_avoid_uturn ; If all done, end voting. 3048 | 3049 | .saw_entity 3050 | ldx vision_entityId_seen_indir, y ; Get entity we saw. 3051 | lda entity_enemy_type, x ; What type it is? 3052 | cmp #et_bullet ; Is it LESS than bullet (ie, not a bullet?) 3053 | bcc .saw_non_projectile ; Go to non projectile. 3054 | cmp #et_worm ; Is it a worm (which is bullet+1)? 3055 | beq .saw_non_projectile ; Go to non projectile. 3056 | ldx last_enemy_processed ; Get our status byte. 3057 | lda entity_status_byte, x 3058 | and #esb_brave ; Are we "brave" (don't care about other entities?) 3059 | bne .brave ; If so, don't avoid entity. 3060 | jsr apply_double_proximity_penalty_in_direction_y_and_single_in_opposite 3061 | 3062 | .brave 3063 | lda entity_bullet_type, x 3064 | cmp #et_worm 3065 | beq .saw_nothing_interesting 3066 | !ifndef remove_dead_code { 3067 | beq .generate_fire_chance ; bug?? never reached, if Z is true, we already branched above. 3068 | } 3069 | 3070 | .saw_non_projectile ; a should be holding seen enemy type from $15e9. 3071 | ; On fall through from above, it is holding bullet 3072 | ; type?? 3073 | ldx last_enemy_processed 3074 | cmp entity_enemy_type, x ; Is it the same as me? 3075 | beq .saw_critical_type 3076 | cmp entity_data_cdlow, x 3077 | beq .saw_critical_type 3078 | cmp entity_type_fired_me, x 3079 | bne .didnt_see_critical_type 3080 | 3081 | .saw_critical_type 3082 | lda #$01 ; Flag that we saw a critical type in this direction. 3083 | sta vision_saw_friendly_flag, y 3084 | lda entity_status_byte, x 3085 | and #esb_randomdirbumps 3086 | beq .saw_nothing_interesting 3087 | tya 3088 | tax 3089 | inc ai_direction_votes, x 3090 | jsr bump_random_direction_votes 3091 | jsr bump_random_direction_votes 3092 | jmp .saw_nothing_interesting 3093 | 3094 | .didnt_see_critical_type 3095 | ldx vision_entityId_seen_indir, y 3096 | lda entity_enemy_type, x 3097 | cmp #et_vacuum ; Vacuums are scary because of their death attack. 3098 | bne .not_vacuum ; If it was a vacuum we saw.. 3099 | lda entity_facing, x ; If it's facing in this direction.. 3100 | tax 3101 | tya 3102 | cmp opposite_facing, x 3103 | beq .run_away ; Run away! 3104 | 3105 | .not_vacuum ; (Or if vacuum that's not facing this way) 3106 | ldx last_enemy_processed ; Look at our colorflags 3107 | lda entity_color_and_flags, x ; If MSB is not set 3108 | bpl .approach_or_wander ; Consider approach, else run away. 3109 | 3110 | .run_away 3111 | ldx last_enemy_processed 3112 | jsr apply_double_proximity_penalty_in_direction_y_and_single_in_opposite 3113 | bne .generate_fire_chance 3114 | 3115 | .approach_or_wander 3116 | lda entity_color_and_flags, x 3117 | and #csf_aggressive 3118 | beq .generate_fire_chance 3119 | jsr apply_proximity_bonus_in_direction_y 3120 | 3121 | .generate_fire_chance 3122 | lda entity_status_byte, x ; Get firing chance from our status byte. 3123 | and #esb_bullet_chance_mask 3124 | sta temp_entity_x_coord 3125 | jsr load_two_low_bits_of_osc3_to_accumulator 3126 | sec ; Subtract a random two bit value. 3127 | sbc temp_entity_x_coord ; Later, whether or not we fire will be determined 3128 | sta ai_fire_bullet_in_direction_score, y ; by whether the subtracted value was greater than the 3129 | ; firing chance. 3130 | jmp .saw_nothing_interesting 3131 | 3132 | ; -- Everything above goes back to .saw_nothing_interesting until all directions are checked. 3133 | 3134 | .end_voting_prefer_existing_avoid_uturn 3135 | ldx last_enemy_processed ; Find existing direction we're facing. 3136 | lda entity_facing, x 3137 | tax 3138 | tay 3139 | inc ai_direction_votes, x ; Add one vote to direction we're facing. 3140 | ldx opposite_facing, y ; Add two votes against direction we're not facing (ie, avoid 3141 | dec ai_direction_votes, x ; u-turns if possible.) 3142 | dec ai_direction_votes, x ; Note that 1/2 votes is relatively little compared to proximity bonuses. 3143 | jsr bump_random_direction_votes 3144 | 3145 | .tied_best_direction 3146 | jsr bump_random_direction_votes 3147 | 3148 | .best_direction = $0e 3149 | .most_direction_votes = $fd 3150 | 3151 | .find_best_direction 3152 | ldy #dir_left ; Loop through facings again 3153 | sty .best_direction ; Set left (3) as initial best direction 3154 | lda ai_direction_votes, y 3155 | dey 3156 | sta .most_direction_votes 3157 | 3158 | .find_best_direction_loop 3159 | lda ai_direction_votes, y ; Got votes for this facing 3160 | cmp .most_direction_votes ; Is it more than current best? 3161 | bcc .not_best_direction ; Nope, do nothing. 3162 | beq .tied_best_direction ; Tie - cast a random vote then restart this loop. 3163 | sta .most_direction_votes ; Yes, it's the new best direction. 3164 | sty .best_direction 3165 | 3166 | .not_best_direction 3167 | dey ; Try the next direction 3168 | bpl .find_best_direction_loop ; Repeat until all directions tried. 3169 | 3170 | 3171 | ldy .best_direction ; Check what's in the best direction. 3172 | lda vision_dist_seen_indir, y ; Is there something next to us in that direction? 3173 | cmp #$01 3174 | bne .nothing_adjacent 3175 | lda vision_char_seen_indir, y 3176 | beq label_16c3 ; ?? Not sure how it would end up being zero, but hey. 3177 | cmp #$1b ; Open square bracket. Not sure how one of those would show up either. 3178 | bcc label_16c3 3179 | cmp #c_spar ; Is it a spar or higher? (An player or entity) 3180 | bcs .nothing_adjacent ; If so, don't care about it. 3181 | lda #$01 ; Otherwise, we screwed up, lower votes in this direction to 1 3182 | sta ai_direction_votes, y ; And pick a new best direction. 3183 | bne .find_best_direction ; Always taken, but BNE is more efficient than JMP. 3184 | 3185 | label_16c3 3186 | jmp .normal_end_enemy_processing 3187 | 3188 | .nothing_adjacent ; Do we want to fire? 3189 | ldy #dir_left ; Loop through directions. 3190 | 3191 | .generate_fire_chance_loop 3192 | sty last_facing_for_joystick_position 3193 | cpy .best_direction ; If it's the direction we've decided to move, 3194 | beq .dont_fire_direction_were_going ; Don't fire in that direction. 3195 | jsr consider_firing ; Otherwise, go to subroutine to consider firing. 3196 | 3197 | .dont_fire_direction_were_going 3198 | ldy last_facing_for_joystick_position 3199 | dey ; Try next direction. 3200 | bpl .generate_fire_chance_loop 3201 | 3202 | 3203 | lda .best_direction 3204 | ldx last_enemy_processed 3205 | cmp entity_facing, x ; See which way we're facing. 3206 | beq .already_facing_best_direction ; If we're already facing the target direction, stay that way. 3207 | sta entity_facing, x ; Otherwise, spend this cycle turning. 3208 | jsr draw_entity_x 3209 | jmp .maybe_fire_way_we_turned ; Since we're just turning, maybe firing isn't such a dumb idea. 3210 | 3211 | .already_facing_best_direction 3212 | ldx last_enemy_processed 3213 | ldy .best_direction 3214 | lda vision_dist_seen_indir, y ; Second stage adjacency check. 3215 | cmp #$01 ; We only checked for walls/spars etc, above. 3216 | beq .saw_entity_adjacent 3217 | lda entity_enemy_type, x ; Are we a vacuum? 3218 | cmp #et_vacuum 3219 | bne label_174b 3220 | ; If we are a vacuum.. 3221 | lda vision_char_seen_indir, y ; What did we see? 3222 | cmp #c_player ; Is it the player or an enemy? 3223 | bcc .calm_vacuum ; If not, calm down. 3224 | lda #$03 ; If yes, chaaaaaarge! 3225 | sta entity_upd_countdown, x ; Set update frequency and cooldown to 3 3226 | sta entity_upd_cooldown, x 3227 | ldx vision_entityId_seen_indir, y ; Get facing of the thing we saw. 3228 | lda entity_facing, x 3229 | sta $0a 3230 | tay 3231 | lda opposite_facing, y ; Take opposite of that facing. 3232 | cmp .best_direction ; If that's best direction (it's already moving away) 3233 | beq .already_fleeing_vacuum 3234 | ldy entity_status_byte, x ; If it's between squares 3235 | bmi label_172e 3236 | ldy .best_direction ; Otherwise, have entity we saw run away. 3237 | lda opposite_facing, y ; Get opposite of our facing 3238 | sta entity_facing, x ; and turn other entity to face it. 3239 | jmp draw_entity_x ; Then draw it (note: vacuum itself did nothing this cycle) 3240 | 3241 | .already_fleeing_vacuum 3242 | lda entity_status_byte, x ; X is still our target, from $170c above. 3243 | bpl label_173e 3244 | 3245 | label_172e 3246 | jsr move_forward_and_redraw_entity_x 3247 | ldx $8d 3248 | lda entity_status_byte, x 3249 | ora #esb_secondframe 3250 | sta entity_status_byte, x 3251 | jmp draw_entity_x 3252 | 3253 | label_173e 3254 | jmp clear_bit_3_on_entity_x_and_draw 3255 | 3256 | .calm_vacuum 3257 | ldx last_enemy_processed ; Reload ID of vacuum 3258 | lda #$09 ; And set cooldowns to 9 again. 3259 | sta entity_upd_countdown, x 3260 | sta entity_upd_cooldown, x 3261 | 3262 | label_174b 3263 | jmp .maybe_fire_intended_direction 3264 | 3265 | .saw_entity_adjacent 3266 | lda vision_char_seen_indir, y ; What did we see adjacent? 3267 | cmp #c_spar ; Was it a spar? 3268 | bne label_1770 3269 | inc entity_spars_eaten, x ; We ate it 3270 | inc entity_shields, x ; We get a shield for doing so 3271 | lda entity_enemy_type, x 3272 | cmp #et_skull ; Are we a skull? 3273 | bne .no_skull_speedup ; If not, branch. 3274 | lda #$03 ; If yes, we get a speed up for eating a spar. 3275 | sta entity_upd_cooldown, x 3276 | 3277 | .no_skull_speedup 3278 | lda #$04 ; Play "spar eaten" sound 3279 | tay 3280 | jsr sound_related_something 3281 | jmp .maybe_fire_intended_direction 3282 | 3283 | label_1770 3284 | bcs label_1775 3285 | jmp .end_voting_prefer_existing_avoid_uturn 3286 | 3287 | label_1775 3288 | lda vision_saw_friendly_flag, y ; Was it a special type? 3289 | bne .moved_into_special_type 3290 | lda vision_entityId_seen_indir, y ; Load collision variables and process collision 3291 | sta $0a 3292 | stx entity_number_that_hit_player 3293 | jsr process_collision_between_09_and_0a 3294 | ldx last_enemy_processed 3295 | lda entity_shields, x ; Done with collision, how's our shield? 3296 | beq .we_died_in_collision ; If it's zero, we killed ourselves.. 3297 | ldx $0a ; How's the other guy's shield? 3298 | lda entity_shields, x 3299 | beq .maybe_fire_intended_direction ; If we killed them, maybe we could fire this way. 3300 | bne .normal_end_enemy_processing ; Otherwise, just continue as normal. 3301 | 3302 | .moved_into_special_type 3303 | ldx vision_entityId_seen_indir, y ; What type was it? 3304 | lda entity_enemy_type, x 3305 | cmp #et_tagteam2 ; Was it a tag team? 3306 | bne .normal_end_enemy_processing ; If not, just don't move. 3307 | ldx last_enemy_processed 3308 | lda entity_enemy_type, x ; What type are we? 3309 | cmp #et_mutant ; Are we a mutant? 3310 | bne .normal_end_enemy_processing ; Then don't worry. 3311 | lda entity_spars_eaten, x 3312 | pha ; Push number of spars we ate. 3313 | lda #$00 ; And kill ourselves. 3314 | sta entity_shields, x 3315 | sty $0a ; Save direction we moved into tagmate. 3316 | jsr blank_out_entity_x_nondestructive 3317 | ldy $0a 3318 | ldx vision_entityId_seen_indir, y ; Get creature we moved into. 3319 | lda entity_status_byte, x ; Get its status. 3320 | and #$80 ; Turn off "between squares" flag. 3321 | pha 3322 | lda #et_tagteam1 ; Replace it with a tagteam type 1. 3323 | jsr load_enemy_type_a_data_into_entity_slot_x_with_last_loaded_udg 3324 | pla ; Add its old flags to tagteam type1 flags. 3325 | ora entity_status_byte, x 3326 | and #$bf 3327 | sta entity_status_byte, x 3328 | pla 3329 | clc 3330 | adc entity_spars_eaten, x ; Add spars we previously ate to spars it ate. 3331 | sta entity_spars_eaten, x 3332 | jmp draw_entity_x ; And draw it. 3333 | 3334 | .normal_end_enemy_processing 3335 | ldx last_enemy_processed 3336 | jsr flip_bit_3_on_status_of_entity_x 3337 | jmp draw_entity_x 3338 | 3339 | .maybe_fire_intended_direction 3340 | ldx last_enemy_processed 3341 | jsr clear_bit_3_on_entity_x_and_draw 3342 | jmp .maybe_fire_way_we_turned 3343 | 3344 | apply_proximity_bonus_in_direction_y 3345 | lda #$28 ; 40 3346 | sec 3347 | sbc vision_dist_seen_indir, y 3348 | clc 3349 | adc ai_direction_votes, y 3350 | sta ai_direction_votes, y 3351 | 3352 | .we_died_in_collision 3353 | rts 3354 | 3355 | ; ------------------------------------------------------------------- 3356 | 3357 | apply_proximity_penalty_in_direction_y 3358 | lda #$28 ; 40 3359 | sec 3360 | sbc vision_dist_seen_indir, y ; a = 40-(4065 entry) 3361 | sta temp_entity_x_coord ; $03 = 40-(4065 entry) 3362 | lda ai_direction_votes, y ; a = (406d entry) 3363 | sec 3364 | sbc temp_entity_x_coord ; a = (406d entry)-40-(4065 entry) 3365 | sta ai_direction_votes, y 3366 | rts 3367 | 3368 | ; ------------------------------------------------------------------ 3369 | 3370 | .maybe_fire_way_we_turned 3371 | ldy .best_direction 3372 | 3373 | consider_firing: 3374 | lda ai_fire_bullet_in_direction_score, y 3375 | bmi label_1811 3376 | rts 3377 | 3378 | label_1811 3379 | jsr find_free_enemy_entity_in_x_and_locals 3380 | tya 3381 | ldy last_enemy_processed 3382 | jsr fire_bullet_as_entity_x_in_direction_y 3383 | lda #$06 3384 | tay 3385 | jmp sound_related_something 3386 | 3387 | bump_random_direction_votes 3388 | jsr load_two_low_bits_of_osc3_to_accumulator 3389 | tax 3390 | inc ai_direction_votes, x 3391 | rts 3392 | 3393 | apply_double_proximity_penalty_in_direction_y_and_single_in_opposite 3394 | jsr apply_proximity_penalty_in_direction_y 3395 | jsr apply_proximity_penalty_in_direction_y 3396 | tya 3397 | pha 3398 | lda opposite_facing, y 3399 | tay 3400 | jsr apply_proximity_penalty_in_direction_y 3401 | pla 3402 | tay 3403 | rts 3404 | 3405 | ; ------------------------------------------------------------------- 3406 | 3407 | !zone game_loop_players 3408 | 3409 | ; PLAYER PROCESSING. This is game loop part 2, called in the main game 3410 | ; loop from $0d08. 3411 | 3412 | 3413 | checking_player_number = $3a 3414 | 3415 | game_loop_players 3416 | ldx #$01 ; Player 2 is checked first and we 3417 | stx checking_player_number ; count down. 3418 | 3419 | .check_players_loop 3420 | ldx checking_player_number 3421 | lda player_has_ticked, x ; Has player been ticked by ISR? 3422 | beq .dont_process_player ; No, don't process them. 3423 | lda p1_lives, x ; Is player alive? 3424 | beq .dont_process_player ; No, don't process them? 3425 | lda #$00 ; Mark tick as used up. 3426 | sta player_has_ticked, x 3427 | lda entity_status_byte, x ; Is bit 7 set on player? 3428 | and #esb_frozen 3429 | bne .dont_process_player ; If so, don't process them. 3430 | jsr player_movement ; Calls to actually do processing. 3431 | jsr player_firing 3432 | 3433 | .dont_process_player 3434 | dec checking_player_number ; Decrement player check number and loop. 3435 | bpl .check_players_loop 3436 | 3437 | lda entity_spars_eaten ; Get p1's collected spars. 3438 | clc 3439 | adc entity_spars_eaten+1 ; Add p2's collected spars. 3440 | cmp #SPARS_TO_WIN_LEVEL 3441 | bcc .level_not_complete ; If <5, level isn't complete. 3442 | jmp end_of_level 3443 | 3444 | .level_not_complete 3445 | lda p1_lives ; Is player 1 alive? 3446 | bne .game_not_over ; If yes, game isn't over. 3447 | lda p2_lives ; Is player 2 alive? 3448 | bne .game_not_over ; If yes, game isn't over. 3449 | jmp show_game_over ; Game IS over.. 3450 | 3451 | .game_not_over 3452 | jmp game_loop_reentry_from_players 3453 | 3454 | ; ---------------------------------------------------------------- 3455 | 3456 | !zone player_movement 3457 | 3458 | joystick_input = $4d 3459 | .joystick_requested_facing = $04 3460 | 3461 | player_movement: 3462 | lda port_2_joystick, x ; If x is 1 actually reads port 1 joystick 3463 | sta joystick_input ; Save joystick value. 3464 | stx processing_entity_number 3465 | and #$0f ; Mask off lower 4 bits, which are movement. 3466 | sec 3467 | sbc #$05 ; Values 0-4 are invalid as joystick input. 3468 | tay 3469 | lda joystick_offset_table, y 3470 | sta .joystick_requested_facing 3471 | bmi .joystick_idle ; Invalid/idle joystick positions get $80 3472 | ; from the table, which has MSB set and so 3473 | ; is considered negative and triggers BMI. 3474 | lda entity_facing, x ; Get our current facing? 3475 | cmp .joystick_requested_facing ; Same facing as joystick requests? 3476 | bne .player_needs_turn ; If not, we need to turn. 3477 | lda entity_status_byte, x 3478 | bpl .move_player_forward 3479 | 3480 | label_1899 3481 | jmp move_forward_and_redraw_entity_x 3482 | 3483 | .joystick_idle 3484 | ldx processing_entity_number 3485 | jmp draw_entity_x ; EXITS 3486 | 3487 | .old_facing = $06 3488 | 3489 | .player_needs_turn 3490 | lda entity_facing, x 3491 | tay 3492 | sta .old_facing 3493 | lda entity_status_byte, x 3494 | bmi label_18c4 3495 | 3496 | ; Check we're not turning into a wall. 3497 | ; Get screen contents at next square in proposed direction. 3498 | ldy .joystick_requested_facing 3499 | jsr propose_direction_y_move_coords_for_entity_x 3500 | jsr load_a_with_screen_at_proposed_coords 3501 | ldx processing_entity_number 3502 | 3503 | ; If empty/spar/enemy, ok to turn. 3504 | cmp #c_empty 3505 | beq .complete_player_turn 3506 | cmp #c_spar ; Sets carry if a >= $3f.. 3507 | bcs .complete_player_turn 3508 | 3509 | ; Abandon turn and move forward instead. 3510 | lda .old_facing 3511 | sta last_facing_for_joystick_position 3512 | bcc .move_player_forward 3513 | 3514 | label_18c4 3515 | lda opposite_facing, y 3516 | cmp last_facing_for_joystick_position 3517 | bne label_1899 3518 | jsr propose_forward_move_coords_for_entity_x 3519 | jsr copy_proposed_coords_to_actual_coords_entity_x 3520 | 3521 | .complete_player_turn 3522 | lda last_facing_for_joystick_position 3523 | sta entity_facing, x 3524 | jmp .joystick_idle 3525 | 3526 | .color_of_entered_space = $42 3527 | 3528 | .move_player_forward 3529 | ; Find the character and color of the space the player is moving 3530 | ; into. 3531 | jsr load_a_with_screen_at_entity_x_forward_coords 3532 | pha 3533 | jsr read_a_from_colors_position_xy 3534 | and #$0f 3535 | sta .color_of_entered_space 3536 | ldx processing_entity_number 3537 | pla 3538 | 3539 | ; See what's there. 3540 | cmp #c_empty ; Empty, no problem. 3541 | beq .player_no_collision 3542 | cmp #c_spar ; A spar, process collecting it. 3543 | beq .player_collected_spar 3544 | cmp #c_spar ; Higher than a spar, it's a wall. 3545 | bcc .player_walked_into_solid 3546 | 3547 | ; Uh-oh. We walked into another entity. Find what it was from the 3548 | ; entityID map. 3549 | jsr set_0a_and_y_to_entityid_that_x_collides_with 3550 | cpy #eid_last_player+1 ; EntityID<2: walked into another player! 3551 | bcc .player_walked_into_solid ; Treat them as a wall. 3552 | 3553 | lda entity_enemy_type, y 3554 | cmp #et_dog 3555 | beq .player_walked_into_solid 3556 | cpy #eid_first_enemy 3557 | bcs .player_walked_into_enemy 3558 | lda entity_facing, y 3559 | ldx $3a 3560 | cmp entity_facing, x 3561 | beq .player_walked_into_solid 3562 | 3563 | .player_walked_into_enemy 3564 | jsr process_collision_between_09_and_0a 3565 | ldy $0a 3566 | lda entity_shields, y 3567 | bne .enemy_player_walked_into_didnt_die 3568 | ldx entity_number_that_hit_player 3569 | jmp give_player_x_score_for_entity_y 3570 | 3571 | .enemy_player_walked_into_didnt_die 3572 | rts 3573 | 3574 | .player_collected_spar 3575 | inc entity_spars_eaten, x 3576 | lda .color_of_entered_space 3577 | cmp #SHIELD_SPAR_COLOR 3578 | beq .player_collected_shield_spar 3579 | cmp #SPEED_SPAR_COLOR 3580 | beq .player_collected_speed_spar 3581 | lda #POWEREDUP_PLAYER_FIRE_COOLDOWN ; Fire spar collected 3582 | sta player_fire_cooldown, x 3583 | bne .player_collected_shield_spar 3584 | 3585 | .player_collected_speed_spar 3586 | lda #POWEREDUP_PLAYER_MOVE_COOLDOWN 3587 | sta player_move_cooldown, x 3588 | 3589 | .player_collected_shield_spar 3590 | ldy #$01 3591 | lda #$04 3592 | jsr sound_related_something 3593 | ldy entity_shields, x ; Add 1 shield to entity x 3594 | iny 3595 | cpy #MAX_PLAYER_SHIELDS+1 ; Cap at 9 3596 | bcc .no_shield_cap 3597 | ldy #MAX_PLAYER_SHIELDS 3598 | 3599 | .no_shield_cap 3600 | tya 3601 | sta entity_shields, x 3602 | jsr update_status_bar_just_shields 3603 | jmp .player_no_collision 3604 | 3605 | !ifndef remove_dead_code { 3606 | !byte $D0,$06 3607 | } 3608 | 3609 | 3610 | .player_walked_into_solid 3611 | jsr flip_bit_3_on_status_of_entity_x 3612 | jmp .joystick_idle 3613 | 3614 | .player_no_collision 3615 | ldx processing_entity_number 3616 | jmp clear_bit_3_on_entity_x_and_draw 3617 | 3618 | ; --------------------------------------------------------------------- 3619 | 3620 | !zone propose_forward_move_coords_for_entity_x 3621 | 3622 | propose_forward_move_coords_for_entity_x 3623 | ldy entity_facing, x 3624 | 3625 | propose_direction_y_move_coords_for_entity_x 3626 | lda entity_x_coords, x 3627 | clc 3628 | adc facing_offset_table_horz, y 3629 | jsr wraparound_x_coordinate_a 3630 | sta proposed_entity_x_coord 3631 | lda entity_y_coords, x 3632 | clc 3633 | adc facing_offset_table_vert, y 3634 | jsr wraparound_y_coordinate_a 3635 | sta proposed_entity_y_coord 3636 | rts 3637 | 3638 | ; ----------------------------------------------------------------- 3639 | ; If accumulator is 0-38 (valid x locations), leave unchanged. 3640 | ; If negative, set to 38 (left wrap). 3641 | ; If 39 or more, set to 0 (right wrap). 3642 | 3643 | !zone wraparound_x_coordinate_a 3644 | 3645 | wraparound_x_coordinate_a 3646 | bpl .no_left_wrap 3647 | lda #$26 3648 | 3649 | .no_left_wrap 3650 | cmp #$27 3651 | bcc .no_right_wrap 3652 | lda #$00 3653 | 3654 | .no_right_wrap 3655 | rts 3656 | 3657 | ; ---------------------------------------------------------------- 3658 | 3659 | ; If accumulator is 2-24 (valid y locations on screen after status 3660 | ; bar), leave unchanged. 3661 | ; If it's 1 (one line off the top), wrap around to 24. If it's 3662 | ; over 24, wrap around to 2. 3663 | 3664 | !zone wraparound_y_coordinate_a 3665 | 3666 | wraparound_y_coordinate_a 3667 | cmp #$01 ; Accumulator != 1? 3668 | bne .no_top_wrap 3669 | lda #$18 3670 | 3671 | .no_top_wrap 3672 | cmp #$19 ; Accumulator < $19 (25?) 3673 | bcc .no_bottom_wrap 3674 | lda #$02 3675 | 3676 | .no_bottom_wrap 3677 | rts 3678 | 3679 | ; ---------------------------------------------------------------- 3680 | 3681 | !zone flip_top_bit_and_clear_third_bit_of_entity_x_status 3682 | 3683 | flip_top_bit_and_clear_third_bit_of_entity_x_status 3684 | lda entity_status_byte, x 3685 | eor #$80 3686 | sta entity_status_byte, x 3687 | lda entity_status_byte, x 3688 | and #$fb 3689 | sta entity_status_byte, x 3690 | rts 3691 | 3692 | ; ----------------------------------------------------------------- 3693 | 3694 | !zone kill_respawn_player 3695 | 3696 | reduce_player_x_lives 3697 | dec p1_lives, x 3698 | jsr init_player_x_shields_and_cooldowns 3699 | 3700 | spawn_player 3701 | lda level_number_byte 3702 | lsr 3703 | !ifdef minimum_escalation { 3704 | cmp #minimum_escalation 3705 | bcs .minimum_escalation_ok 3706 | lda #minimum_escalation 3707 | .minimum_escalation_ok: 3708 | } 3709 | sta escalation 3710 | !ifdef show_timing_info { 3711 | txa 3712 | pha 3713 | ldx #5 3714 | lda escalation 3715 | jsr display_hex_value 3716 | pla 3717 | tax 3718 | } 3719 | 3720 | stx processing_entity_number 3721 | lda p1_lives, x 3722 | beq .player_dead_dead 3723 | lda #et_player 3724 | jsr load_enemy_type_a_data_into_entity_slot_x_with_last_loaded_udg 3725 | lda p1_shields_copy, x 3726 | sta entity_shields, x 3727 | lda #$01 3728 | sta player_move_cooldown_counter, x 3729 | sta player_fire_cooldown_counter, x 3730 | lda player_color, x 3731 | ora #csf_visible 3732 | sta entity_color_and_flags, x 3733 | lda player_spawn_xcoord, x 3734 | sta proposed_entity_x_coord 3735 | lda #$17 3736 | sta proposed_entity_y_coord 3737 | jsr copy_proposed_coords_to_actual_coords_entity_x 3738 | lda player_spawn_facing, x 3739 | sta entity_facing, x 3740 | lda #$00 3741 | jsr explode_entity_maybe 3742 | ldx processing_entity_number 3743 | jsr load_a_with_screen_at_proposed_coords 3744 | ldx processing_entity_number 3745 | cmp #c_empty 3746 | beq .player_spawn_clear 3747 | cmp #c_spar 3748 | bne .player_spawned_on_entity 3749 | inc entity_spars_eaten, x 3750 | bne .player_spawn_clear 3751 | 3752 | .player_spawned_on_entity ; If player spawned on entity, kill it. 3753 | jsr set_0a_and_y_to_entityid_that_x_overlaps 3754 | ldx $0a 3755 | jsr blank_out_entity_x_nondestructive 3756 | ldx $0a 3757 | lda #$00 3758 | sta entity_shields, x 3759 | jsr drop_spars_from_entity_x 3760 | 3761 | .player_spawn_clear 3762 | ldy processing_entity_number 3763 | jsr fire_player_spawn_bullets_from_player_y 3764 | 3765 | .player_dead_dead 3766 | jmp update_status_bar_not_scores ; Tail call RTS 3767 | 3768 | ; ------------------------------------------------------------------ 3769 | 3770 | 3771 | !zone load_vision_buffers_entity_x 3772 | 3773 | .considering_facing = $fc 3774 | .distance_countdown = $fd 3775 | .max_distance = $02 3776 | 3777 | load_vision_buffers_entity_x 3778 | stx processing_entity_number 3779 | lda entity_vision_distance, x 3780 | sta .distance_countdown 3781 | sta .max_distance 3782 | ldy #$03 3783 | sty .considering_facing 3784 | 3785 | label_1a1d 3786 | lda #$a0 3787 | sta ai_direction_votes, y 3788 | lda #$00 3789 | sta vision_dist_seen_indir, y 3790 | sta vision_saw_friendly_flag, y 3791 | sta ai_fire_bullet_in_direction_score, y 3792 | dey 3793 | bpl label_1a1d 3794 | sta $42 3795 | ldx processing_entity_number 3796 | ldy entity_enemy_type, x 3797 | lda $4083, y 3798 | bpl .look_one_way 3799 | inc $42 3800 | 3801 | .temp_x_coord = $03 3802 | .temp_y_coord = $fb 3803 | 3804 | .look_one_way 3805 | ldx processing_entity_number 3806 | lda entity_x_coords, x 3807 | sta .temp_x_coord 3808 | lda entity_y_coords, x 3809 | sta .temp_y_coord 3810 | 3811 | .trace_distance_loop 3812 | ldy .considering_facing 3813 | lda .temp_x_coord 3814 | clc 3815 | adc facing_offset_table_horz, y 3816 | jsr wraparound_x_coordinate_a 3817 | tax 3818 | sta .temp_x_coord 3819 | lda .temp_y_coord 3820 | clc 3821 | adc facing_offset_table_vert, y 3822 | jsr wraparound_y_coordinate_a 3823 | tay 3824 | sta .temp_y_coord 3825 | jsr read_a_from_screen_position_xy 3826 | ldx .considering_facing 3827 | sta vision_char_seen_indir, x 3828 | inc vision_dist_seen_indir, x 3829 | lda vision_char_seen_indir, x 3830 | cmp #c_empty 3831 | bne .seen_something 3832 | dec .distance_countdown 3833 | bne .trace_distance_loop 3834 | beq .done_looking_this_way 3835 | 3836 | .seen_something 3837 | cmp #$40 3838 | bcc .done_looking_this_way 3839 | ldx .temp_x_coord 3840 | jsr read_a_from_entityId_buffer_position_x_y 3841 | inc $42 3842 | ldx .considering_facing 3843 | sta vision_entityId_seen_indir, x 3844 | 3845 | .done_looking_this_way 3846 | dec .considering_facing 3847 | bmi .done_looking 3848 | lda .max_distance 3849 | sta .distance_countdown 3850 | jmp .look_one_way 3851 | 3852 | .done_looking 3853 | ldx processing_entity_number 3854 | lda $42 3855 | beq label_1aa1 3856 | lda #$20 3857 | sta $42 3858 | 3859 | label_1aa1 3860 | lda entity_color_and_flags, x 3861 | and #$df ; Clear bit 6 3862 | ora $42 ; But reset it, if $42 was set above 3863 | sta entity_color_and_flags, x 3864 | rts 3865 | 3866 | ; ------------------------------------------------------------------ 3867 | 3868 | !zone show_game_over 3869 | 3870 | show_game_over: 3871 | 3872 | ; Draw game over message on screen. Make it flash by copying value 3873 | ; of jiffy clock into color map at location of message. 3874 | 3875 | ldx #$08 ; Length of message 3876 | .game_over_print_loop 3877 | lda game_over_message, x 3878 | beq .game_over_skip_letter 3879 | sta screen+$217, x 3880 | lda jiffy_clock 3881 | sta colors+$217, x 3882 | .game_over_skip_letter 3883 | dex 3884 | bpl .game_over_print_loop 3885 | 3886 | jsr show_press_f7 3887 | beq .game_over_f7_pressed 3888 | jmp done_escalation 3889 | 3890 | .game_over_f7_pressed 3891 | lda #$93 ; Clear screen 3892 | jsr $ffd2 ; OS print character call 3893 | jmp title_screen_init 3894 | 3895 | ; --------------------------------------------------------------- 3896 | 3897 | 3898 | !zone copy_proposed_coords_to_actual_coords_entity_x 3899 | 3900 | copy_proposed_coords_to_actual_coords_entity_x 3901 | lda proposed_entity_x_coord 3902 | sta entity_x_coords, x 3903 | lda proposed_entity_y_coord 3904 | sta entity_y_coords, x 3905 | rts 3906 | 3907 | ; --------------------------------------------------------------- 3908 | 3909 | !zone update_player_bullets 3910 | 3911 | update_player_bullets: 3912 | ldx #$02 3913 | lda #$00 3914 | sta interrupt_counter 3915 | 3916 | .check_bullets_loop 3917 | lda entity_shields, x 3918 | beq .no_bullet 3919 | lda entity_status_byte, x 3920 | bpl label_1aef 3921 | jsr move_forward_and_redraw_entity_x 3922 | jmp label_1af2 3923 | 3924 | label_1aef 3925 | jsr update_bullet 3926 | 3927 | label_1af2 3928 | ldx $13 3929 | 3930 | .no_bullet 3931 | inx 3932 | cpx #$0c 3933 | bne .check_bullets_loop 3934 | rts 3935 | 3936 | ; ------------------------------------------------------------------- 3937 | 3938 | !zone read_from_entityId_buffer 3939 | 3940 | .tempstore_x = $09 3941 | 3942 | set_0a_and_y_to_entityid_that_x_collides_with 3943 | stx .tempstore_x 3944 | jsr propose_forward_move_coords_for_entity_x 3945 | 3946 | ; Using this entry point doesn't update tempstore_x, so clobbers x? 3947 | set_0a_and_y_to_entityid_at_proposed_coord 3948 | ldx proposed_entity_x_coord 3949 | ldy proposed_entity_y_coord 3950 | bne label_1b0e ; ?? A should never be 0 here. 3951 | 3952 | set_0a_and_y_to_entityid_that_x_overlaps 3953 | stx .tempstore_x 3954 | ldy entity_y_coords, x 3955 | lda entity_x_coords, x 3956 | tax 3957 | 3958 | label_1b0e 3959 | jsr read_a_from_entityId_buffer_position_x_y 3960 | tay 3961 | ldx .tempstore_x 3962 | sty $0a 3963 | 3964 | label_1b16 3965 | rts 3966 | 3967 | ; ------------------------------------------------------------------- 3968 | 3969 | !zone player_firing 3970 | 3971 | .bullet_direction = $fe 3972 | 3973 | player_firing 3974 | lda joystick_input ; We count on this having been set up by 3975 | ; player_movement which was called immediately before. 3976 | and #$10 ; Does player want to fire? 3977 | bne label_1b16 ; No, exit. 3978 | ldy checking_player_number ; .. And on this having been set up by 3979 | ; game_loop_player which is calling us. 3980 | lda player_fire_cooldown_counter, y 3981 | beq .player_fires 3982 | rts 3983 | 3984 | .player_fires 3985 | lda #$05 3986 | jsr sound_related_something 3987 | ldy checking_player_number 3988 | lda player_fire_cooldown, y 3989 | sta player_fire_cooldown_counter, y 3990 | lda entity_facing, y 3991 | 3992 | fire_bullet_from_entity_y_in_direction_a 3993 | sta .bullet_direction 3994 | sty processing_entity_number 3995 | 3996 | ; Find a free bullet entity slot 3997 | 3998 | ldx #$02 3999 | .find_bullet_slot_loop 4000 | lda entity_shields, x 4001 | beq .found_bullet_slot 4002 | inx 4003 | cpx #$0c 4004 | bne .find_bullet_slot_loop 4005 | 4006 | ; No free bullet found. Wipe out oldest bullet 4007 | 4008 | ldx oldest_bullet_entity_id 4009 | stx $fd 4010 | jsr blank_out_entity_x_nondestructive 4011 | ldx oldest_bullet_entity_id ; Increment old bullet id and wrap 4012 | inx ; around at 13.. 4013 | cpx #$0c 4014 | bne .no_old_bullet_wrap 4015 | ldx #$02 4016 | 4017 | .no_old_bullet_wrap 4018 | stx oldest_bullet_entity_id 4019 | ldx $fd 4020 | 4021 | .found_bullet_slot 4022 | lda .bullet_direction 4023 | ldy processing_entity_number 4024 | stx $8d 4025 | 4026 | fire_bullet_as_entity_x_in_direction_y: 4027 | sta entity_facing, x 4028 | lda entity_bullet_speed, y 4029 | pha 4030 | lda entity_bullet_type, y 4031 | stx processing_entity_number 4032 | sty $fd 4033 | jsr load_enemy_type_a_data_into_entity_slot_x_with_last_loaded_udg 4034 | pla 4035 | sta entity_upd_cooldown, x 4036 | lda #$01 4037 | sta entity_upd_countdown, x 4038 | ldy $fd 4039 | lda entity_enemy_type, x 4040 | cmp #$12 4041 | bne label_1b88 4042 | lda entity_enemy_type, y 4043 | sta entity_type_fired_me, x 4044 | 4045 | label_1b88 4046 | lda entity_color_and_flags, x 4047 | and #$f0 4048 | ora entity_color_and_flags, y 4049 | sta entity_color_and_flags, x 4050 | lda entity_status_byte, y 4051 | and #$40 4052 | beq label_1b9f 4053 | lda #$20 4054 | sta entity_shields, x 4055 | 4056 | label_1b9f 4057 | ldy entity_facing, x 4058 | ldx $fd 4059 | jsr propose_direction_y_move_coords_for_entity_x 4060 | ldx processing_entity_number 4061 | jsr copy_proposed_coords_to_actual_coords_entity_x 4062 | ldx $fd 4063 | lda entity_status_byte, x 4064 | bpl label_1bbb 4065 | ldx processing_entity_number 4066 | jsr propose_forward_move_coords_for_entity_x 4067 | jsr copy_proposed_coords_to_actual_coords_entity_x 4068 | 4069 | label_1bbb 4070 | lda $fd 4071 | cmp #$02 4072 | bcs label_1bc6 4073 | ldx processing_entity_number 4074 | sta entity_bullet_type, x 4075 | 4076 | label_1bc6 4077 | jsr load_a_with_screen_at_proposed_coords 4078 | ldx processing_entity_number 4079 | cmp #c_empty ; empty 4080 | beq label_1beb 4081 | cmp #c_player ; player 4082 | bcs label_1bd9 4083 | lda #$00 ; collided with something else, die 4084 | sta entity_shields, x 4085 | rts 4086 | 4087 | label_1bd9 4088 | stx entity_number_that_hit_player 4089 | jsr set_0a_and_y_to_entityid_at_proposed_coord 4090 | jsr process_collision_between_09_and_0a 4091 | ldx $0a 4092 | lda entity_shields, x 4093 | bmi label_1bea 4094 | bne label_1bf8 4095 | 4096 | label_1bea 4097 | rts 4098 | 4099 | label_1beb 4100 | lda entity_bullet_type, x 4101 | bmi label_1bf8 4102 | inc difficulty 4103 | bne label_1bf8 4104 | lda #$ff 4105 | sta difficulty 4106 | 4107 | label_1bf8 4108 | jmp draw_entity_x 4109 | 4110 | ; -------------------------------------------------------------------- 4111 | !zone collision_handling 4112 | 4113 | process_collision_between_09_and_0a: 4114 | 4115 | .first_colliding_entity = $09 4116 | .second_colliding_entity = $0a 4117 | 4118 | ldy .second_colliding_entity 4119 | lda entity_bullet_type, y 4120 | cmp #et_worm 4121 | bne label_1c33 4122 | ldx .first_colliding_entity 4123 | lda entity_status_byte, x 4124 | and #esb_invulnerable 4125 | beq label_1c33 4126 | 4127 | lda entity_shields, x 4128 | cmp #$14 4129 | bcs label_1c33 4130 | 4131 | lda entity_facing, y 4132 | tay 4133 | lda entity_facing, x 4134 | cmp opposite_facing, y 4135 | beq label_1c33 4136 | 4137 | ldy entity_facing, x 4138 | lda opposite_facing, y 4139 | sta entity_facing, x 4140 | lda #$01 4141 | ldx .first_colliding_entity 4142 | ldy entity_bullet_type, x 4143 | jmp sound_related_something ; EXIT 4144 | 4145 | label_1c33 4146 | ldx .second_colliding_entity 4147 | dec entity_shields, x 4148 | lda #$01 4149 | jsr explode_entity_maybe 4150 | ldy #$03 4151 | ldx .first_colliding_entity 4152 | lda entity_status_byte, x 4153 | and #esb_invulnerable 4154 | beq label_1c4c 4155 | dec entity_shields, x 4156 | 4157 | !byte $2c ; BIT skip hack 4158 | label_1c4c 4159 | ldy #$07 4160 | sty $0b 4161 | lda entity_enemy_type, x 4162 | cmp #et_vacuum 4163 | beq .vacuum_instant_death 4164 | lda entity_bullet_type, x 4165 | bmi label_1c7c 4166 | cmp #$02 4167 | bcs label_1c7c 4168 | lda entity_shields, x 4169 | cmp #$02 4170 | bcc label_1c7c 4171 | 4172 | .vacuum_instant_death 4173 | ldx .second_colliding_entity 4174 | lda #$00 4175 | sta entity_shields, x 4176 | beq label_1c7c ;; ?? 4177 | lda entity_status_byte, x 4178 | and #esb_invulnerable 4179 | beq label_1c7c 4180 | lda #$01 4181 | jsr explode_entity_maybe 4182 | 4183 | label_1c7c 4184 | ldx .second_colliding_entity 4185 | lda entity_shields, x 4186 | bne .second_entity_survived 4187 | lda $0b 4188 | cmp #$07 4189 | beq label_1c8d 4190 | lda #$02 4191 | sta $0b 4192 | 4193 | label_1c8d 4194 | jsr blank_out_entity_x_nondestructive 4195 | ldx .second_colliding_entity 4196 | jsr drop_spars_from_entity_x 4197 | 4198 | .second_entity_survived 4199 | ldx .first_colliding_entity 4200 | lda entity_shields, x 4201 | bne .first_entity_survived 4202 | jsr blank_out_entity_x_nondestructive 4203 | ldx .first_colliding_entity 4204 | jsr drop_spars_from_entity_x 4205 | 4206 | .first_entity_survived 4207 | ldx .first_colliding_entity 4208 | cpx #$02 4209 | bcs .first_entity_wasnt_player 4210 | jsr update_status_bar_just_shields 4211 | lda entity_shields, x 4212 | bmi .player_life_lost 4213 | bne .first_entity_wasnt_player ; 4214 | 4215 | .player_life_lost 4216 | jmp reduce_player_x_lives 4217 | 4218 | .first_entity_wasnt_player 4219 | lda entity_bullet_type, x 4220 | cmp #$02 4221 | bcs label_1cc9 4222 | ldy $0a 4223 | ldx entity_shields, y 4224 | bne label_1cc9 4225 | tax 4226 | jsr give_player_x_score_for_entity_y 4227 | 4228 | label_1cc9 4229 | ldy #$02 4230 | ldx .first_colliding_entity 4231 | cpx #$0c 4232 | bcs label_1cd2 4233 | dey 4234 | 4235 | label_1cd2 4236 | ldx .second_colliding_entity 4237 | cpx #$0c 4238 | bcs label_1cd9 4239 | dey 4240 | 4241 | label_1cd9 4242 | lda $0b 4243 | jsr sound_related_something 4244 | ldx .second_colliding_entity 4245 | cpx #$02 4246 | bcs reused_rts 4247 | jsr update_status_bar_just_shields 4248 | lda entity_shields, x 4249 | beq .player_life_lost 4250 | bmi .player_life_lost 4251 | 4252 | reused_rts 4253 | rts 4254 | 4255 | ; -------------------------------------------------------------------- 4256 | 4257 | !zone drop_spars_from_entity_x 4258 | 4259 | ; Called when an entity dies. Find the number of spars it's supposed 4260 | ; to drop and drop them in random empty locations. 4261 | 4262 | .spars_left_to_drop = $fe 4263 | 4264 | drop_spars_from_entity_x: 4265 | lda entity_spars_eaten, x ; Get and store number to drop 4266 | sta .spars_left_to_drop 4267 | lda #$00 ; Reset number to drop in entity array 4268 | sta entity_spars_eaten, x 4269 | 4270 | .drop_spars_loop: 4271 | dec .spars_left_to_drop ; Count down number left to drop 4272 | bmi reused_rts ; If all done, return via nearby rts(!) 4273 | jsr set_xy_to_random_empty_space_coord ; Find a random space 4274 | lda #c_spar ; spar ; Draw a spar there 4275 | jsr write_a_to_screen_position_xy 4276 | jsr select_random_spar_type ; Choose random spar type/color 4277 | bne .drop_spars_loop 4278 | 4279 | ; -------------------------------------------------------------------- 4280 | 4281 | !zone end_of_level 4282 | 4283 | end_of_level 4284 | jsr clear_explosions 4285 | ldx #$01 4286 | 4287 | .check_player_x 4288 | ldy multiply_by_8, x 4289 | 4290 | ; Check if player x is active/alive; don't process if not. 4291 | lda p1_lives, x ; Check if player is alive/active. 4292 | beq .player_x_dead ; If not, don't process. 4293 | 4294 | ; Award players points equal to number of spars they ate x5. 4295 | lda entity_spars_eaten, x ; Get number of spars they ate 4296 | asl ; x2 4297 | asl ; x4 4298 | clc 4299 | adc entity_spars_eaten, x ; Add once more for x5 4300 | adc player_1_score_digits+5, y ; Add this to player's score 4301 | sta player_1_score_digits+5, y 4302 | 4303 | ; Reset player's spars eaten count for the new level. 4304 | lda #$00 4305 | sta entity_spars_eaten, x 4306 | 4307 | 4308 | lda level_units_b 4309 | cmp level_number_byte 4310 | bne .player_x_dead 4311 | asl 4312 | asl 4313 | adc $6044, y 4314 | sec 4315 | sbc #$04 4316 | sta $6044, y 4317 | 4318 | .player_x_dead 4319 | jsr score_update 4320 | dex 4321 | bpl .check_player_x 4322 | 4323 | ; Increment level 4324 | ldx level_bcd_units ; Get level units 4325 | inx ; Add 1 4326 | cpx #10 ; Did it go over 10? 4327 | bcc .no_level_bcd_tens_increase ; No, so no carry 4328 | ldx #$00 ; Carry, set units to 0 4329 | inc level_bcd_tens ; And carry 1 to the tens 4330 | .no_level_bcd_tens_increase 4331 | stx level_bcd_units ; Store new units 4332 | 4333 | ; Wait for user to press F7. 4334 | .wait_for_f7 4335 | jsr show_press_f7 4336 | bne .wait_for_f7 4337 | 4338 | jsr update_status_bar 4339 | jsr draw_new_map 4340 | lda entity_shields 4341 | sta p1_shields_copy 4342 | lda p2_shields 4343 | sta p2_shields_copy 4344 | inc level_number_byte 4345 | jmp per_level_init 4346 | 4347 | ; ------------------------------------------------------------------- 4348 | 4349 | !zone move_forward_and_redraw_entity_x 4350 | 4351 | .temp_x_store = $13 4352 | 4353 | move_forward_and_redraw_entity_x 4354 | stx .temp_x_store 4355 | jsr blank_out_entity_x_nondestructive 4356 | ldx .temp_x_store 4357 | jsr propose_forward_move_coords_for_entity_x 4358 | jsr copy_proposed_coords_to_actual_coords_entity_x 4359 | jsr flip_top_bit_and_clear_third_bit_of_entity_x_status 4360 | jmp draw_entity_x 4361 | 4362 | ; ------------------------------------------------------------------- 4363 | 4364 | !zone clear_bit_3_on_entity_x_and_draw 4365 | 4366 | .stored_x_value = $13 4367 | clear_bit_3_on_entity_x_and_draw 4368 | stx .stored_x_value 4369 | lda entity_status_byte, x 4370 | and #$fb ; Clear bit 3 4371 | sta entity_status_byte, x ; Oddly the JSR below does this, too. 4372 | jsr flip_top_bit_and_clear_third_bit_of_entity_x_status 4373 | jsr draw_entity_x 4374 | ldx .stored_x_value 4375 | jmp draw_entity_x_override_color 4376 | 4377 | ; --------------------------------------------------------------- 4378 | 4379 | !zone flip_bit_3_on_status_of_entity_x 4380 | 4381 | flip_bit_3_on_status_of_entity_x 4382 | lda entity_status_byte, x 4383 | eor #esb_secondframe 4384 | sta entity_status_byte, x 4385 | rts 4386 | 4387 | ; -------------------------------------------------------------------- 4388 | 4389 | !zone show_press_f7 4390 | 4391 | ; Shows the "Press F7" message. Also checks if F7 is actually being 4392 | ; pressed and sets eq flag accordingly. 4393 | 4394 | show_press_f7 4395 | ldx #$07 ; 7 characters 4396 | .print_pressf7_loop 4397 | lda press_f7_message, x ; Get character of "PRESS F7" 4398 | beq .pressf7_skip_letter ; If zero, don't draw 4399 | sta screen+$1c7, x ; Put character on screen 4400 | lda #$0a ; Set matching color cell to 10 4401 | sta colors+$1c7, x 4402 | .pressf7_skip_letter 4403 | dex ; Loop 4404 | bpl .print_pressf7_loop 4405 | 4406 | lda pressed_key_code ; Read pressed key 4407 | cmp #$03 ; Compare to F7 ($3) 4408 | rts 4409 | 4410 | ; -------------------------------------------------------------------- 4411 | 4412 | ; Choose a random type (color) for a newly spawned spar. Called 4413 | ; directly after spawning a spar with x/y still holding its location. 4414 | ; 3/4 chance of a shield spar. Otherwise, 50/50 fire or move spar. 4415 | 4416 | !zone select_random_spar_type 4417 | 4418 | select_random_spar_type 4419 | ; Always 3/4 chance of a shield spar. 4420 | lda sid_voice3_oscillator_ro ; Get random value from osc 4421 | and #$03 ; Mask off bits 4422 | bne .select_shield_spar ; If not 0 (3/4), shield spar. 4423 | ; If level too low, always shield spar. 4424 | lda #$02 ; If level too low, always shield spar. 4425 | cmp level_number_byte 4426 | bcs .select_shield_spar 4427 | ; Select 50/50 between other two spar types. 4428 | lda sid_voice3_oscillator_ro ; Get random value from osc 4429 | and #$01 ; Mask off just one bit 4430 | beq .select_speed_spar ; If zero, spar type 6 4431 | lda #FIRE_SPAR_COLOR ; Else, spar type 2 4432 | !byte $2c ; BIT skip hack 4433 | .select_speed_spar 4434 | lda #SPEED_SPAR_COLOR 4435 | !byte $2c ; BIT skip hack 4436 | .select_shield_spar 4437 | lda #SHIELD_SPAR_COLOR 4438 | jmp write_a_to_colors_position_xy 4439 | 4440 | ; -------------------------------------------------------------------- 4441 | !zone load_a_with_screen_at_entity_x_forward_coords 4442 | 4443 | load_a_with_screen_at_entity_x_forward_coords 4444 | jsr propose_forward_move_coords_for_entity_x 4445 | 4446 | !zone load_a_with_screen_at_proposed_coords 4447 | 4448 | load_a_with_screen_at_proposed_coords 4449 | ldx proposed_entity_x_coord 4450 | ldy proposed_entity_y_coord 4451 | jmp read_a_from_screen_position_xy 4452 | 4453 | ; --------------------------------------------------------------------- 4454 | 4455 | !zone init_player_x_shields_and_cooldowns 4456 | 4457 | ; Reset player x's shield and move/fire cooldown value to the default. 4458 | 4459 | init_player_x_shields_and_cooldowns 4460 | lda #DEFAULT_PLAYER_SHIELDS 4461 | sta p1_shields_copy, x 4462 | lda #DEFAULT_PLAYER_MOVE_COOLDOWN 4463 | sta player_move_cooldown, x 4464 | lda #DEFAULT_PLAYER_FIRE_COOLDOWN 4465 | sta player_fire_cooldown, x 4466 | rts 4467 | 4468 | ;------------------------------------------------------------------ 4469 | 4470 | !ifdef show_timing_info { 4471 | 4472 | !zone display_hex_value 4473 | display_hex_value: 4474 | tay 4475 | and #$0F 4476 | clc 4477 | cmp #10 4478 | bcc .alpha_1 4479 | sbc #9 4480 | !byte $2c 4481 | .alpha_1 4482 | adc #NUMBER_TO_PETSCII_ADJUSTMENT 4483 | sta screen+1, x 4484 | tya 4485 | lsr 4486 | lsr 4487 | lsr 4488 | lsr 4489 | clc 4490 | cmp #10 4491 | bcc .alpha_2 4492 | sbc #9 4493 | !byte $2c 4494 | .alpha_2 4495 | adc #NUMBER_TO_PETSCII_ADJUSTMENT 4496 | sta screen, x 4497 | rts 4498 | } 4499 | 4500 | !zone post_code_data 4501 | 4502 | msg_banner: 4503 | 4504 | !text $93,$1C," CROSSROADS II : ",$9C,"PANDEMONIUM " 4505 | 4506 | 4507 | !byte $1C,$C0,$1E,$20,$00 4508 | 4509 | main_scrolltext: 4510 | !byte $F6 4511 | 4512 | label_1e14: 4513 | 4514 | !byte $2E,$2E,$2E,$03,$0F,$10,$19,$12,$09,$07 4515 | ; . . . C O P Y R I G 4516 | !byte $08,$14,$20,$31,$39,$38,$38,$20 4517 | ; H T _ 1 9 8 8 _ 4518 | !byte $03,$0F,$0D,$10,$15,$14,$05,$21 4519 | ; C O M P U T E ! 4520 | !byte $20,$10,$15,$02,$0C,$09,$03,$01 4521 | ; _ P U B L I C A 4522 | !byte $14,$09,$0F,$0E,$13,$F2,$2E,$2E 4523 | ; I I O N S crl . . 4524 | !byte $2E,$17,$05,$0C,$03,$0F,$0D,$05 4525 | ; . W E L C O M E 4526 | !byte $20,$14,$0F,$20,$10,$01,$0E,$04 4527 | ; _ T O _ P A N D 4528 | !byte $05,$0D,$0F,$0D,$09,$15,$0D,$F7 4529 | ; E M O N I U M crl 4530 | !byte $2E,$2E,$2E,$10,$12,$05,$13,$13 4531 | ; . . . P R E S S 4532 | !byte $20,$06,$09,$12,$05,$20,$02,$15 4533 | ; _ F I R E _ B U 4534 | !byte $14,$14,$0F,$0E,$20,$14,$0F,$20 4535 | ; T T O N _ T O _ 4536 | !byte $13,$14,$01,$12,$14 4537 | ; S T A R T 4538 | 4539 | ; This is the programmer's credit. Because Compute! removed the credit from the previous game, in this 4540 | ; version it's encrypted by adding the hex value of the corresponding line from the spar graphics 4541 | ; (below) to the character code. 4542 | 4543 | hidden_credit_text: 4544 | !byte $F5,$5E,$40,$4C,$7A,$61,$2C,$13,$14,$1D,$1E,$7F,$7E,$18,$19,$12,$14,$11,$76 4545 | ;Key $00 $30 $12 $1e $78 $48 $0c $00 $00 $18 $08 $7a $5e $10 $18 $00 $00 $0c $64 4546 | ;Plain$f5 $2e $2e $2e $02 $19 $20 $13 $14 $05 $16 $05 $20 $08 $01 $12 P14 $05 $12 4547 | ; crl . . . B Y _ S T E V E _ H A R T E R 4548 | 4549 | msg_start_at_level: 4550 | !byte $13,$14,$01,$12,$14,$20,$01,$14 4551 | ; S T A R T _ A T 4552 | !byte $20,$0C,$05,$16,$05,$0C,$20,$31 4553 | ; _ L E V E L _ 4554 | 4555 | 4556 | scroll_left_control_codes: 4557 | !byte $13 ; Home 4558 | !byte $11 ; Cursor Down 4559 | !byte $1D ; Cursor Right 4560 | !byte $14 ; Delete 4561 | !byte $00 ; End marker 4562 | 4563 | label_1e9b: 4564 | !byte $04,$07 4565 | 4566 | msg_status_bar_headers: 4567 | 4568 | !ifndef show_timing_info { 4569 | !text $13,$1C,"PLAYER 1 ",$96,"S ",$9e,"L",$1f," HIGH ",$1e,"LEVEL ",$1c,"PLAYER 2 ",$96,"S ",$9e,"L",$00 4570 | } 4571 | 4572 | !ifdef show_timing_info { 4573 | !text $13,$1C,"ESC ",$96,"S ",$9e,"L",$1f," SWEEPS ",$1e," LV ",$1c,"DIFF ",$96,"S ",$9e,"L",$00 4574 | } 4575 | 4576 | 4577 | ;!byte ,$50,$4C,$41,$59,$45,$52,$20 4578 | ; P L A Y E R _ 4579 | ;!byte $31,$20,$96,$53,$20,$9E,$4C,$1F 4580 | ; 1 _ ctl 4581 | ;!byte $20,$20,$20,$48,$49,$47,$48,$20 4582 | ;!byte $20,$1E,$4C,$45,$56,$45,$4C,$20 4583 | ;!byte $1C,$50,$4C,$41,$59,$45,$52,$20 4584 | ;!byte $32,$20,$96,$53,$20,$9E,$4C,$00 4585 | 4586 | map_start_addresses: 4587 | !byte $00,$00,$37,$6e,$A5 4588 | 4589 | map_colors: 4590 | !byte $02,$04,$05 4591 | !byte $06,$08,$09,$0B,$0E 4592 | 4593 | label_1edb: 4594 | !byte $00,$00,$04,$FC 4595 | 4596 | label_1edf: 4597 | !byte $04,$FC,$00,$00 4598 | 4599 | ; Gives X and Y coordinate offsets represented by each of the four 4600 | ; facings: 0 down, 1 up, 3 right, 4 left. $FF serves as -1. 4601 | facing_offset_table_horz: 4602 | !byte $00,$00,$01,$FF 4603 | 4604 | facing_offset_table_vert: 4605 | !byte $01,$FF,$00,$00 4606 | 4607 | ; Used in routines above to look up facing value from joystick bitmap. 4608 | ; Note that 5 is subtracted before the value is used as the index 4609 | ; because joystick values 0-4 are all impossible. 4610 | joystick_offset_table: 4611 | !byte $00 ; %0101, down+right => down 4612 | !byte $01 ; %0110, up+right => up 4613 | !byte $02 ; %0111, right => right 4614 | !byte $80 ; %1000, impossible (up+down+left) => idle 4615 | !byte $00 ; %1001, left+down => down 4616 | !byte $01 ; %1010, left+up => up 4617 | !byte $03 ; %1011, left => left 4618 | !byte $80 ; %1100, impossible (up+down) 4619 | !byte $00 ; %1101, down 4620 | !byte $01 ; %1110, up 4621 | !byte $80 ; %1111, idle 4622 | 4623 | onebit_masks_zero_is_msb: 4624 | !byte $80,$40,$20,$10,$08,$04,$02 ; $01 is reused from the next array 4625 | 4626 | onebit_masks_zero_is_lsb: 4627 | !byte $01,$02,$04,$08,$10,$20,$40,$80 4628 | 4629 | player_function_keys: 4630 | !byte $04 ; F1 4631 | !byte $05 ; F3 4632 | 4633 | player_spawn_xcoord: 4634 | !byte $01,$25 4635 | 4636 | label_1f09: 4637 | !byte $C0,$DB 4638 | 4639 | unknown_facing_table: 4640 | !byte $08,$0C,$00 4641 | !byte $04 4642 | 4643 | opposite_facing: 4644 | !byte $01,$00,$03,$02 4645 | 4646 | player_spawn_facing: 4647 | !byte $02,$03 4648 | 4649 | multiply_by_8: 4650 | !byte $00,$08,$10 4651 | 4652 | player_color: 4653 | !byte $02,$05 4654 | 4655 | label_1f1a: 4656 | !byte $19,$03 4657 | 4658 | data_explosion_limits: 4659 | !byte $02,$1a 4660 | 4661 | data_explosion_deltas: 4662 | !byte $FF,$01 4663 | 4664 | spar_images: 4665 | 4666 | !byte %........ 4667 | !byte %..##.... 4668 | !byte %...#..#. 4669 | !byte %...####. 4670 | !byte %.####... 4671 | !byte %.#..#... 4672 | !byte %....##.. 4673 | !byte %........ 4674 | 4675 | !byte %........ 4676 | !byte %...##... 4677 | !byte %....#... 4678 | !byte %.####.#. 4679 | !byte %.#.####. 4680 | !byte %...#.... 4681 | !byte %...##... 4682 | !byte %........ 4683 | 4684 | !byte %........ 4685 | !byte %....##.. 4686 | !byte %.##..#.. 4687 | !byte %.#.##... 4688 | !byte %...##.#. 4689 | !byte %..#..##. 4690 | !byte %..##.... 4691 | !byte %........ 4692 | 4693 | sid_voice_offsets: 4694 | !byte $00 4695 | 4696 | label_1f39: 4697 | !byte $07,$21,$81,$11 4698 | 4699 | label_1f3d: 4700 | !byte $11,$03,$00,$10 4701 | 4702 | label_1f41: 4703 | !byte $40,$07,$1F,$0F,$07 4704 | 4705 | 4706 | possible_sound_buffer: 4707 | !byte $8F,$00 4708 | 4709 | ;Enemy data tables: 4710 | 4711 | non = $7f 4712 | bul = $11 4713 | wrm = $12 4714 | spr = $13 4715 | na = $ff 4716 | 4717 | ; EGG VAC TT1 TT2 MUT LSK SKL CHM MKY RH1 THR ARC DOG RH2 FLI LON PLY BLT WRM SPR 4718 | enemy_release_schedule: !byte $01,$07,$11,$08,$02,$04,$05,$03,$05,$06,$04,$08,$01,$09,$01,$01 4719 | enemy_data_cd: !byte $00,$01,$13,$02,$32,$07,$00,$05,$1F,$80,$3B,$2A,$09,$40,$05,$08,$10,$00,$20,$00 4720 | enemy_data_low_shields_high_score: !byte $32,$83,$94,$32,$22,$44,$75,$55,$52,$73,$64,$85,$11,$64,$11,$33,$04,$01,$21,$01 4721 | enemy_data_low_vision_high_update_cooldown: !byte $88,$9B,$5D,$77,$96,$69,$5A,$58,$6F,$FF,$9C,$8F,$A7,$6D,$C6,$88,$21,$21,$4A,$21 4722 | enemy_data_a: !byte $06,$FF,$04,$04,$03,$0E,$00,$0E,$FF,$12,$FF,$FF,$10,$12,$07,$FF,$FF,$FF 4723 | enemy_bullet_types: !byte non,non,bul,non,bul,non,non,non,bul,wrm,spr,spr,non,wrm,non,non,bul,na ,bul,na 4724 | enemy_type_colors: !byte $7E,$75,$7A,$AA,$BA,$77,$71,$72,$A9,$34,$BC,$7B,$A9,$7D,$B6,$68,$22,$22,$60,$20 4725 | enemy_initial_status: !byte $58,$40,$52,$48,$79,$40,$50,$58,$5A,$53,$7A,$5A,$68,$62,$78,$58,$62,$20,$21,$20 4726 | 4727 | label_1fe2: 4728 | !byte $05,$12,$1E,$06 4729 | !byte $09,$0C,$11,$0E,$10,$1A,$18,$18 4730 | !byte $CF,$1C,$08,$0B,$00,$00,$32 4731 | 4732 | game_over_message: 4733 | !byte $07,$01,$0D,$05,$00,$0F,$16,$05,$12 4734 | ; G A M E _ O V E R 4735 | 4736 | press_f7_message: 4737 | !byte $10,$12,$05,$13,$13,$00,$06,$37 4738 | ; P R E S S _ F 7 4739 | 4740 | label_2006: 4741 | !byte $FF,$BF,$E0,$20,$00,$FA,$AA,$A8 4742 | !byte $20,$00,$AA,$FF,$EA,$80,$08,$AB 4743 | !byte $FE,$8A,$80,$08,$AB,$BF,$88,$82 4744 | !byte $00,$BB,$A0,$00,$00,$00,$FB,$A0 4745 | !byte $08,$0A,$00,$AA,$BF,$8A,$88,$08 4746 | !byte $AE,$BE,$8A,$00,$28,$8E,$BA,$EA 4747 | !byte $08,$00,$BE,$AA,$E8,$02,$00,$FF 4748 | !byte $BE,$D0,$00,$24,$80,$01,$38,$00 4749 | !byte $09,$C0,$00,$42,$00,$05,$90,$00 4750 | !byte $4D,$FB,$F7,$00,$00,$0D,$DB,$FB 4751 | !byte $10,$20,$1F,$6A,$FD,$00,$00,$0A 4752 | !byte $BB,$FD,$22,$20,$0F,$AA,$00,$00 4753 | !byte $00,$0E,$AA,$00,$08,$A0,$0A,$BA 4754 | !byte $00,$AB,$AF,$F8,$00,$01,$FF,$FB 4755 | !byte $E8,$80,$20,$23,$FE,$FA,$80,$00 4756 | !byte $AF,$FB,$FA,$80,$A0,$A8,$0A,$08 4757 | !byte $80,$A0,$D8,$0E,$00,$00,$00,$D8 4758 | !byte $0E,$08,$80,$A0,$A8,$0A,$0A,$80 4759 | !byte $A0,$AF,$FB,$FA,$00,$00,$AB,$FB 4760 | !byte $F0,$00,$00,$AF,$7A,$EA,$14,$22 4761 | !byte $BD,$5F,$A8,$00,$02,$FF,$BF,$F0 4762 | !byte $00,$01,$80,$00,$00,$00,$01,$80 4763 | !byte $00,$00,$00,$01,$80,$00,$00,$00 4764 | !byte $01,$80,$00,$00,$00,$01,$80,$00 4765 | !byte $00,$00,$01,$80,$00,$00,$00,$01 4766 | !byte $FF,$BF,$F0,$00,$00,$EF,$AF,$E2 4767 | !byte $02,$00,$BF,$BE,$DA,$00,$21,$AE 4768 | !byte $BB,$D0,$08,$01 4769 | 4770 | label_20e2: 4771 | !byte $FF,$FE,$00,$00 4772 | !byte $20,$BB,$FA,$08,$80,$00,$23,$DE 4773 | !byte $0B,$A0,$00,$82,$00,$0F,$A0,$00 4774 | !byte $00,$00,$00,$00,$00,$00,$00,$00 4775 | !byte $00,$00,$00,$00,$0E,$E0,$00,$82 4776 | !byte $00,$0A,$A0,$00,$AB,$BE,$08,$00 4777 | !byte $20,$BA,$BA,$08,$28,$00,$BA,$EA 4778 | !byte $08,$00,$20,$F7,$EF,$F0,$00,$00 4779 | !byte $BB,$EB,$80,$00,$08,$EA,$EA,$82 4780 | !byte $A8,$A8,$8A,$EE,$82,$22,$A8,$EE 4781 | !byte $EA,$80,$20,$08,$E8,$AF,$E0,$A2 4782 | !byte $02,$FB,$E0,$20,$00,$02,$BF,$A1 4783 | !byte $E0,$02,$10,$BD,$A1,$08,$02,$10 4784 | !byte $BD,$A1,$00,$5A,$1F,$B5,$A0,$08 4785 | !byte $02,$00,$F7,$5F,$F0,$44,$00,$BD 4786 | !byte $40,$08,$14,$00,$B5,$40,$0B,$55 4787 | !byte $FF,$84,$00,$0B,$D5,$FD,$A0,$44 4788 | !byte $1A,$DD,$5C,$80,$00,$1B,$FD,$5C 4789 | !byte $80,$04,$1F,$AD,$FF,$0A,$D1,$1E 4790 | !byte $E0,$44,$81,$D1,$1A,$D0,$44,$0D 4791 | !byte $D1,$1A,$04,$44,$B5,$51,$18,$14 4792 | !byte $44,$FF,$F5,$D8,$00,$41,$BE,$FF 4793 | !byte $D8,$28,$05,$3A,$80,$48,$08,$05 4794 | !byte $BE,$80,$4A,$0B,$FD,$BE,$80,$58 4795 | !byte $0B,$F5,$BE,$80,$00,$2B,$FD,$BE 4796 | !byte $20,$08,$0A,$00,$BE,$A0,$08,$08 4797 | !byte $00,$FD,$BF,$D0,$00,$00,$AD,$7F 4798 | !byte $D8,$10,$41,$BD,$75,$D8,$10,$41 4799 | 4800 | program_end: 4801 | 4802 | 4803 | --------------------------------------------------------------------------------