From 961aa789c2aab475eed9407c72af0a08e1d6a2c5 Mon Sep 17 00:00:00 2001 From: Michael Miceli Date: Sat, 1 Jun 2024 21:10:31 -0400 Subject: [PATCH] define memory map explicity --- build.bat | 3 +- build.ps1 | 3 +- build.sh | 3 +- contra.cfg | 6 + docs/Bugs.md | 1 - docs/Enemy Glossary.md | 1 - docs/Sound Documentation.md | 1 - src/bank0.asm | 6 +- src/bank1.asm | 28 +- src/bank2.asm | 2 +- src/bank3.asm | 2 +- src/bank4.asm | 2 +- src/bank5.asm | 15 +- src/bank6.asm | 26 +- src/bank7.asm | 89 +- src/constants.asm | 678 +++++--------- src/ines_header.asm | 2 +- src/ram.asm | 1714 +++++++++++++++++++++++++++++++++++ 18 files changed, 2063 insertions(+), 519 deletions(-) create mode 100644 src/ram.asm diff --git a/build.bat b/build.bat index d555009..2dea348 100644 --- a/build.bat +++ b/build.bat @@ -68,6 +68,7 @@ rem show commands run in output echo Assembling PRG Rom Banks @echo on +ca65 -D %GAME% --debug-info -o obj\ram.o src\ram.asm ca65 -D %GAME% --debug-info -o obj\constants.o src\constants.asm ca65 -D %GAME% --debug-info -o obj\ines_header.o src\ines_header.asm ca65 -D %GAME% --debug-info -o obj\bank0.o src\bank0.asm @@ -85,5 +86,5 @@ rem link assemblies together to single .nes ROM echo "Creating .nes ROM" @echo on -ld65 -C contra.cfg --dbgfile %DBG_NAME% .\obj\constants.o .\obj\ines_header.o .\obj\bank0.o .\obj\bank1.o .\obj\bank2.o .\obj\bank3.o .\obj\bank4.o .\obj\bank5.o .\obj\bank6.o .\obj\bank7.o -o %ROM_NAME% +ld65 -C contra.cfg --dbgfile %DBG_NAME% .\obj\ram.o .\obj\constants.o .\obj\ines_header.o .\obj\bank0.o .\obj\bank1.o .\obj\bank2.o .\obj\bank3.o .\obj\bank4.o .\obj\bank5.o .\obj\bank6.o .\obj\bank7.o -o %ROM_NAME% @echo off \ No newline at end of file diff --git a/build.ps1 b/build.ps1 index 46204ee..36861e6 100644 --- a/build.ps1 +++ b/build.ps1 @@ -110,6 +110,7 @@ Write-Output "Assembling PRG Rom Banks" # show commands run in output Set-PSDebug -Trace 1 +ca65 -D $Game --debug-info -o obj\ram.o src\ram.asm ca65 -D $Game --debug-info -o obj\constants.o src\constants.asm ca65 -D $Game --debug-info -o obj\ines_header.o src\ines_header.asm ca65 -D $Game --debug-info -o obj\bank0.o src\bank0.asm @@ -127,7 +128,7 @@ Set-PSDebug -Trace 0 Write-Output "Creating .nes ROM" Set-PSDebug -Trace 1 -ld65 -C contra.cfg --dbgfile $DBG_NAME .\obj\constants.o .\obj\ines_header.o .\obj\bank0.o .\obj\bank1.o .\obj\bank2.o .\obj\bank3.o .\obj\bank4.o .\obj\bank5.o .\obj\bank6.o .\obj\bank7.o -o $ROM_NAME +ld65 -C contra.cfg --dbgfile $DBG_NAME .\obj\ram.o .\obj\constants.o .\obj\ines_header.o .\obj\bank0.o .\obj\bank1.o .\obj\bank2.o .\obj\bank3.o .\obj\bank4.o .\obj\bank5.o .\obj\bank6.o .\obj\bank7.o -o $ROM_NAME # compare assembled ROM hash to expected hash if file exists Set-PSDebug -Trace 0 diff --git a/build.sh b/build.sh index ee75d98..49ba17f 100644 --- a/build.sh +++ b/build.sh @@ -105,6 +105,7 @@ done < $ASSETS_NAME echo "$GAME" > $ASSET_GAME_TYPE echo "Assembling PRG Rom Banks" +ca65 -D $GAME --debug-info -o obj/ram.o src/ram.asm ca65 -D $GAME --debug-info -o obj/constants.o src/constants.asm ca65 -D $GAME --debug-info -o obj/ines_header.o src/ines_header.asm ca65 -D $GAME --debug-info -o obj/bank0.o src/bank0.asm @@ -117,7 +118,7 @@ ca65 -D $GAME --debug-info -o obj/bank6.o src/bank6.asm ca65 -D $GAME --debug-info -o obj/bank7.o src/bank7.asm echo "Creating .nes ROM" -ld65 -C contra.cfg --dbgfile $DBG_NAME ./obj/constants.o ./obj/ines_header.o ./obj/bank0.o ./obj/bank1.o ./obj/bank2.o ./obj/bank3.o ./obj/bank4.o ./obj/bank5.o ./obj/bank6.o ./obj/bank7.o -o $ROM_NAME +ld65 -C contra.cfg --dbgfile $DBG_NAME ./obj/ram.o ./obj/constants.o ./obj/ines_header.o ./obj/bank0.o ./obj/bank1.o ./obj/bank2.o ./obj/bank3.o ./obj/bank4.o ./obj/bank5.o ./obj/bank6.o ./obj/bank7.o -o $ROM_NAME if test -f $ROM_NAME then diff --git a/contra.cfg b/contra.cfg index 65d6dbf..2f4a2a9 100644 --- a/contra.cfg +++ b/contra.cfg @@ -1,5 +1,9 @@ # defines where the banks will be loaded into CPU address space MEMORY { + # Define CPU memory map for zero page, not saved to ROM + ZEROPAGE: start = $00, size = $100, type = rw; + RAM: start = $100, size = $6ff, type = rw, fill = no; + # INES Cartridge Header, not loaded into CPU memory HEADER: start = $0000, size = $0010, fill = yes; @@ -25,6 +29,8 @@ MEMORY { # defines the order of the segments as they are stored in the .nes ROM file SEGMENTS { + ZEROPAGE: load = ZEROPAGE, type = zp; + RAM: load = RAM, type = bss; HEADER: load = HEADER, type = ro; OAMRAM: load = OAMRAM, type = bss, define=yes, optional=yes; BANK_0: load = BANK_0, type = ro; diff --git a/docs/Bugs.md b/docs/Bugs.md index ed41b4e..0ab2cd6 100644 --- a/docs/Bugs.md +++ b/docs/Bugs.md @@ -16,7 +16,6 @@ player is in water and presses the d-pad down button. |-------------------------------------|-------------------------------------|-------------------------------------|-------------------------------------| | ![0](attachments/pw_0.png?raw=true) | ![1](attachments/pw_1.png?raw=true) | ![2](attachments/pw_2.png?raw=true) | ![3](attachments/pw_3.png?raw=true) | - ``` @set_enter_water_sprite: ... diff --git a/docs/Enemy Glossary.md b/docs/Enemy Glossary.md index 44db8b8..30cef43 100644 --- a/docs/Enemy Glossary.md +++ b/docs/Enemy Glossary.md @@ -1200,7 +1200,6 @@ Other Names: Gordea, JJ, Jumping Joey, Jumping Jack Flash, Giant Boss Robot, No attributes exist for this enemy. His health is calculated based on player's `PLAYER_WEAPON_STRENGTH` value. The formula is below - #### Logic * `ENEMY_VAR_1` - random number used to control boss action: jump, attack, diff --git a/docs/Sound Documentation.md b/docs/Sound Documentation.md index ba8db9e..cd36a5b 100644 --- a/docs/Sound Documentation.md +++ b/docs/Sound Documentation.md @@ -128,7 +128,6 @@ game by various other sounds. | #$5c | n/a | high hat | n/a | n/a | low | delta modulation | | #$ff | n/a | snowfield boss defeated door open (bug) | n/a | n/a | low | delta modulation | - The sound for pausing the game is not in the sound mode menu, presumably to not confuse players into thinking the game is paused. As for names, I can guess at some of the abbreviations and name meanings. diff --git a/src/bank0.asm b/src/bank0.asm index c7d98cd..beadd91 100644 --- a/src/bank0.asm +++ b/src/bank0.asm @@ -1,4 +1,4 @@ -; Contra US Disassembly - v1.2 +; Contra US Disassembly - v1.3 ; https://github.com/vermiceli/nes-contra-us ; Bank 0 is used exclusively for enemy routines. Enemy routines are the logic ; controlling enemy behaviors, AI, movements, and attack patterns. Almost every @@ -2800,7 +2800,7 @@ eye_projectile_routine_00: lda #$06 ; a = #$06 (projectile speed) sta $06 lda #$01 ; a = #$01 (quadrant_aim_dir_01) - sta $0f ; quadrant_aim_dir_lookup_tbl offset + sta $0f ; quadrant_aim_dir_lookup_ptr_tbl offset jsr get_quadrant_aim_dir_for_player ; set a to the aim direction within a quadrant ; based on source position ($09, $08) targeting player index $0a jsr set_bullet_velocities ; set the projectile X and Y velocities (both high and low) based on register a (#$01) @@ -5688,7 +5688,7 @@ spinning_bubbles_routine_00: lda spinning_bubbles_speed_tbl,y ; load bullet velocity routine table value (bullet_velocity_adjust_xx) sta $06 ; store bullet direction velocity routine value (bullet_velocity_adjust_xx) in $06 lda #$01 ; a = #$01 (quadrant_aim_dir_01) - sta $0f ; set quadrant_aim_dir_lookup_tbl offset to #$01 + sta $0f ; set quadrant_aim_dir_lookup_ptr_tbl offset to #$01 jsr get_quadrant_aim_dir_for_player ; set a to the aim direction within a quadrant ; based on source position ($09, $08) targeting player index $0a pha ; push quadrant aim dir to the stack diff --git a/src/bank1.asm b/src/bank1.asm index c57bbc9..5631370 100644 --- a/src/bank1.asm +++ b/src/bank1.asm @@ -1,4 +1,4 @@ -; Contra US Disassembly - v1.2 +; Contra US Disassembly - v1.3 ; https://github.com/vermiceli/nes-contra-us ; Bank 1 is responsible for audio and sprites. The audio code takes up about ; 3/4 of the bank. The remaining 1/4 of the bank is for sprite data and code to @@ -323,7 +323,7 @@ set_pulse_config: @continue: ora SOUND_CFG_HIGH,x ; merge with high nibble of pulse config value jsr ldx_pulse_triangle_reg ; set x to apu channel register [0, 1, 4, 5, 8, #$c] - bcs @exit + bcs @exit ; exit if there is already a sound playing on that channel that has priority sta APU_PULSE_CONFIG,x ; set either pulse channel 1 or 2 config ; a is either (PULSE_VOLUME,x - UNKNOWN_SOUND_01) | SOUND_CFG_HIGH,x ; or #$00 | SOUND_CFG_HIGH,x @@ -517,7 +517,7 @@ read_sound_command_00: ; output ; * x - SOUND_CURRENT_SLOT [0-3] read_high_sound_cmd: - lda SOUND_CURRENT_SLOT ; loud sound slot index + lda SOUND_CURRENT_SLOT ; load sound slot index cmp #$03 ; compare to sound slot #$03 (noise/dmc channel) beq parse_percussion_cmd ; branch if sound slot #$03 (noise/dmc channel) lda ($e0),y ; not noise channel, load sound byte @@ -671,7 +671,7 @@ interpret_sound_byte: @set_sweep_continue: jsr ldx_pulse_triangle_reg ; set x to apu channel register [0, 1, 4, 5, 8, #$c] - bcs @next_high_control_sound_byte + bcs @next_high_control_sound_byte ; branch if there is already a sound playing on that channel that has priority sta APU_PULSE_SWEEP,x ; enable or disable sweep @next_high_control_sound_byte: @@ -712,7 +712,7 @@ interpret_sound_byte: ; set config register ($4000, $4004, or $400c) and period & length register @set_cfg_period_length: jsr ldx_pulse_triangle_reg ; set x to apu channel register [0, 1, 4, 5, 8, #$c] - bcs @load_set_period_length + bcs @load_set_period_length ; branch if there is already a sound playing on that channel that has priority sta $4000,x ; set pulse, triangle, or noise channel configuration @load_set_period_length: @@ -853,7 +853,7 @@ set_note: sta SOUND_PULSE_LENGTH,x ; set in memory copy of current pulse length ora #$08 ; set bit 0 of high timer to be 1 jsr ldx_pulse_triangle_reg ; set x to apu channel register [0, 1, 4, 5, 8, #$c] - bcs @set_period + bcs @set_period ; branch if there is already a sound playing on that channel that has priority sta APU_PULSE_LENGTH,x ; set duration and high 3 bits of the pulse, or triangle channel ; set low period @@ -866,7 +866,7 @@ set_note: @set_apu_period: jsr ldx_pulse_triangle_reg ; set x to apu channel register [0, 1, 4, 5, 8, #$c] - bcs @restore_x_adv_sound_ptr ; if carry set, do not update APU register + bcs @restore_x_adv_sound_ptr ; branch if there is already a sound playing on that channel that has priority ; continue to restore x to the sound slot index, update SOUND_CMD_LOW_ADDR value, and exit sta APU_PULSE_PERIOD,x ; update APU pulse period @@ -1007,7 +1007,9 @@ skip_3_read_sound_command_01: ; (except SOUND_FLAGS are loaded within read_sound_command_00) ; set sound channel configuration (mute), advance sound command address +; input ; * a - amount to multiply SOUND_CMD_LENGTH by +; * y - current sound_xx read offset sound_cmd_routine_00: jsr calc_cmd_delay ; multiply SOUND_CMD_LENGTH by a lda #$00 ; sound config low nibble = #$00 (mute sound channel) @@ -1017,7 +1019,7 @@ sound_cmd_routine_00: @continue: jsr ldx_pulse_triangle_reg ; set x to apu channel register [0, 1, 4, 5, 8, #$c] - bcs @adv_read_addr + bcs @adv_read_addr ; branch if there is already a sound playing on that channel that has priority sta $4000,x ; set pulse 1, pulse 2, or triangle configuration @adv_read_addr: @@ -1028,12 +1030,14 @@ sound_cmd_routine_00: jmp adv_sound_cmd_addr ; set the sound_xx command read offset to current read location + 1 ; set in memory configuration for channel, set multiplier, and sometimes read_high_sound_cmd +; input ; * a - low nibble of sound byte value +; * y - current sound_xx read offset sound_cmd_routine_01: sta SOUND_LENGTH_MULTIPLIER,x ; store value used to calculate SOUND_CMD_LENGTH - iny + iny ; increment sound code read offset lda ($e0),y ; load sound code byte - cpx #$02 ; compare to sound slot #$02 (triangle channel) + cpx #$02 ; compare current sound slot to sound slot #$02 (triangle channel) beq set_sound_triangle_config ; branch if triangle channel to set triangle config in memory and read_high_sound_cmd and #$0f ; not triangle sound slot, get low nibble sec @@ -1293,7 +1297,7 @@ sound_exit_00: mute_channel: lda #$30 ; a = #$30 (mute pulse channel register) jsr ldx_pulse_triangle_reg ; set x to apu channel register [0, 1, 4, 5, 8, #$c] - bcs @continue + bcs @continue ; branch if there is already a sound playing on that channel that has priority sta $4000,x ; update pulse channel config (mute pulse channel 1 or 2 register) @continue: @@ -1373,7 +1377,7 @@ sound_cmd_ptr_tbl: ; table for note period to use when writing notes to the APU (#$30 bytes) ; the frequency of the pulse channels is a division of the CPU Clock (1.789773MHz NTSC, 1.662607MHz PAL) -; the output frequency (f) of the generator can be determined by the 11-bit period value (f_pulse) written to $4002–$4003/$4006–$4007 +; the output frequency (f) of the generator can be determined by the 11-bit period value (f_pulse) written to $4002-$4003/$4006-$4007 ; note that triangle channel is one octave lower ; frequency = cpu_speed / (#$0f * (f_pulse + 1)) ; ex: 1789773 / (#$0f * (#$06ae + 1)) => 65.38 Hz diff --git a/src/bank2.asm b/src/bank2.asm index 1cf3644..65a7c4d 100644 --- a/src/bank2.asm +++ b/src/bank2.asm @@ -1,4 +1,4 @@ -; Contra US Disassembly - v1.2 +; Contra US Disassembly - v1.3 ; https://github.com/vermiceli/nes-contra-us ; Bank 2 starts with RLE-encoded level data (graphic super tiles for the level ; screens). It then contains compressed tile data and alternate tile data and diff --git a/src/bank3.asm b/src/bank3.asm index e4a8e90..85ddfff 100644 --- a/src/bank3.asm +++ b/src/bank3.asm @@ -1,4 +1,4 @@ -; Contra US Disassembly - v1.2 +; Contra US Disassembly - v1.3 ; https://github.com/vermiceli/nes-contra-us ; Bank 3 starts with the data that specifies which pattern table tiles comprises ; super-tiles along with the color palettes. This bank also has the routines diff --git a/src/bank4.asm b/src/bank4.asm index 8d75d2d..288adf6 100644 --- a/src/bank4.asm +++ b/src/bank4.asm @@ -1,4 +1,4 @@ -; Contra US Disassembly - v1.2 +; Contra US Disassembly - v1.3 ; https://github.com/vermiceli/nes-contra-us ; Bank 4 mostly contains compressed graphic data. The rest of bank 4 is the code ; for the ending scene animation and the ending credits, including the ending diff --git a/src/bank5.asm b/src/bank5.asm index 5d0dab0..a61f178 100644 --- a/src/bank5.asm +++ b/src/bank5.asm @@ -1,4 +1,4 @@ -; Contra US Disassembly - v1.2 +; Contra US Disassembly - v1.3 ; https://github.com/vermiceli/nes-contra-us ; Bank 5 mostly contains compressed graphic data. The rest of bank 5 is the ; code and lookup tables for automated input for the 3 demo (attract) levels. @@ -86,15 +86,16 @@ graphic_data_17: graphic_data_18: .incbin "assets/graphic_data/graphic_data_18.bin" -; run as part of showing the demo -; DEMO_FIRE_DELAY_TIMER starts at 0 increments to #$ff and stops +; simulates player input for demo levels for both players +; begins firing after #$e0 frames (see DEMO_FIRE_DELAY_TIMER) load_demo_input_table: lda CONTROLLER_STATE_DIFF ; get player input and #$30 ; start and select button bne end_demo_level ; exit demo if player has pressed start or select - inc DEMO_FIRE_DELAY_TIMER ; increase DEMO_FIRE_DELAY_TIMER by 1 + inc DEMO_FIRE_DELAY_TIMER ; starts at 0 increments to #$ff and stops + ; used by demo logic to wait #$e0 frames until begin firing bne @player_loop ; branch when DEMO_FIRE_DELAY_TIMER is not 0 (hasn't wrapped around) - dec DEMO_FIRE_DELAY_TIMER ; decrease DEMO_FIRE_DELAY_TIMER by 1 (setting to -1), this means delay is complete + dec DEMO_FIRE_DELAY_TIMER ; wrapped around, pin to #$ff @player_loop: ldx #$01 ; initialize X to 1 (player loop starting at player 2) @@ -163,7 +164,7 @@ set_player_demo_input: ; for non M, nor L weapon, press b button every #$07 frames @fire_weapon_input: lda FRAME_COUNTER ; load frame counter - and #$07 ; checking every 7th frame + and #$07 ; checking every 8th frame bne player_demo_input_chg_player ; move to next player without firing weapon lda CONTROLLER_STATE_DIFF,x ; load current controller input ora #$40 ; press b button @@ -195,7 +196,7 @@ demo_input_pointer_table: ; * second byte is number of even-numbered frames to apply the input for ; while possible, player firing isn't specified in these input tables ; instead, that is handled automatically as part of running the demo -; * m or l weapons are always firing, other weapons fire every #$07 frames +; * m or l weapons are always firing, other weapons fire every #$08 frames ; $00, $00 is filler so the demo level doesn't end by reading a #$ff ; input table for level 1 player 1 for demo (#$5A bytes) demo_input_tbl_l1_p1: diff --git a/src/bank6.asm b/src/bank6.asm index 26e940a..6b87624 100644 --- a/src/bank6.asm +++ b/src/bank6.asm @@ -1,4 +1,4 @@ -; Contra US Disassembly - v1.2 +; Contra US Disassembly - v1.3 ; https://github.com/vermiceli/nes-contra-us ; Bank 6 contains compressed graphics data, data for short text sequences like ; level names and menu options. Bank 6 also contains the code for the players' @@ -289,7 +289,7 @@ intro_background_palette2: ; ensure player in valid state to fire a bullet, e.g. not being electrocuted check_player_fire: lda PLAYER_HIDDEN,x ; 0 - visible; #$01/#$ff = invisible (any non-zero) - ora $c8,x ; counter for electrocution + ora ELECTROCUTED_TIMER,x ; counter for electrocution bne check_player_fire_exit ; exit if being electrocuted or $ba,x is set lda PLAYER_WATER_STATE,x ; see if player in water beq @player_shoot_test @@ -862,7 +862,7 @@ set_bullet_velocity: asl ; double twice to get correct offset tay lda ($01),y ; load x velocity fast value - sta PLAYER_BULLET_VEL_X_FAST,x ; store x velocity fast value + sta PLAYER_BULLET_X_VEL_FAST,x ; store x velocity fast value iny ; increment velocity table read offset lda ($01),y ; load x fractional velocity value sta PLAYER_BULLET_X_VEL_FRACT,x ; store x fractional velocity value @@ -1000,7 +1000,7 @@ set_indoor_bullet_vel: @set_x_vel: jsr @set_vel_for_speed_code ; determine fast and fractional velocity based on a and whether rapid fire is enabled lda $0f ; load resulting fast velocity - sta PLAYER_BULLET_VEL_X_FAST,x ; set indoor bullet fast x velocity + sta PLAYER_BULLET_X_VEL_FAST,x ; set indoor bullet fast x velocity lda $0e ; load resulting fractional velocity sta PLAYER_BULLET_X_VEL_FRACT,x ; set indoor bullet fractional x velocity rts @@ -1118,7 +1118,7 @@ s_weapon_init_bullet_velocities: lda ($04),y sta PLAYER_BULLET_Y_VEL_FAST,x lda ($06),y - sta PLAYER_BULLET_VEL_X_FAST,x + sta PLAYER_BULLET_X_VEL_FAST,x rts ; table for player aim direction (#$c bytes) @@ -1651,7 +1651,7 @@ update_player_fs_bullet_x_pos: adc PLAYER_BULLET_X_VEL_FRACT,x ; add x fractional velocity, noting the carry being set if overflow sta PLAYER_BULLET_VEL_FS_X_ACCUM,x ; add accumulated value back lda PLAYER_BULLET_FS_X,x - adc PLAYER_BULLET_VEL_X_FAST,x ; add fast X velocity and any carry from accumulator + adc PLAYER_BULLET_X_VEL_FAST,x ; add fast X velocity and any carry from accumulator sta PLAYER_BULLET_FS_X,x rts @@ -1660,19 +1660,19 @@ update_player_bullet_pos: jsr check_bullet_solid_bg_collision ; if specified, check for bullet collision with solid background ; and if so move bullet routine to player_bullet_collision_routine bmi bullet_logic_exit ; exit if bullet collided with solid object - lda PLAYER_BULLET_VEL_X_ACCUM,x ; load accumulator value for bullet X velocity + lda PLAYER_BULLET_X_VEL_ACCUM,x ; load accumulator value for bullet X velocity clc ; clear carry in preparation for addition adc PLAYER_BULLET_X_VEL_FRACT,x ; add x fractional velocity, noting the carry being set if overflow - sta PLAYER_BULLET_VEL_X_ACCUM,x ; add accumulated value back + sta PLAYER_BULLET_X_VEL_ACCUM,x ; add accumulated value back lda PLAYER_BULLET_X_POS,x ; load bullet X position - adc PLAYER_BULLET_VEL_X_FAST,x ; add fast X velocity and any carry from accumulator + adc PLAYER_BULLET_X_VEL_FAST,x ; add fast X velocity and any carry from accumulator sta PLAYER_BULLET_X_POS,x ; set new X position update_player_bullet_y_pos: clc ; clear carry in preparation for addition - lda PLAYER_BULLET_VEL_Y_ACCUM,x ; load accumulator value for bullet Y velocity + lda PLAYER_BULLET_Y_VEL_ACCUM,x ; load accumulator value for bullet Y velocity adc PLAYER_BULLET_Y_VEL_FRACT,x ; add y fractional velocity, noting the carry being set if overflow - sta PLAYER_BULLET_VEL_Y_ACCUM,x ; add accumulated value back + sta PLAYER_BULLET_Y_VEL_ACCUM,x ; add accumulated value back lda PLAYER_BULLET_Y_POS,x ; load bullet Y position adc PLAYER_BULLET_Y_VEL_FAST,x ; add fast Y velocity and any carry from accumulator sta PLAYER_BULLET_Y_POS,x ; set new Y position @@ -1726,7 +1726,7 @@ clear_bullet_values: sta PLAYER_BULLET_F_RAPID,x sta PLAYER_BULLET_DIST,x sta PLAYER_BULLET_AIM_DIR,x - sta PLAYER_BULLET_VEL_X_FAST,x + sta PLAYER_BULLET_X_VEL_FAST,x sta PLAYER_BULLET_X_VEL_FRACT,x sta PLAYER_BULLET_Y_VEL_FAST,x sta PLAYER_BULLET_Y_VEL_FRACT,x @@ -1822,7 +1822,7 @@ update_s_bullet_indoor_pos: lda PLAYER_BULLET_VEL_FS_X_ACCUM,x ; ignore, no affect clc ; ignore, no affect adc PLAYER_BULLET_S_ADJ_ACCUM,x ; ignore, no affect - sta PLAYER_BULLET_VEL_X_ACCUM,x ; unused result, never read for S indoor bullets !(WHY?) + sta PLAYER_BULLET_X_VEL_ACCUM,x ; unused result, never read for S indoor bullets !(WHY?) lda PLAYER_BULLET_FS_X,x ; load center x position on screen f bullet swirls around clc ; clear carry in preparation for addition adc PLAYER_BULLET_S_INDOOR_ADJ,x ; add the indoor adjustment diff --git a/src/bank7.asm b/src/bank7.asm index fb2c632..321fa84 100644 --- a/src/bank7.asm +++ b/src/bank7.asm @@ -1,4 +1,4 @@ -; Contra US Disassembly - v1.2 +; Contra US Disassembly - v1.3 ; https://github.com/vermiceli/nes-contra-us ; Bank 7 is the core of the game's programming. Reset, NMI, and IRQ vectors are ; in this bank and is the entry point to the game. Bank 7 is always loaded in @@ -4889,7 +4889,6 @@ set_vel_for_speed_code_a: sta $0e ; set $0e to #$00 ldy #$07 ; set number of bits to rotate speed code to #$07 - ; for a given value $0f, set fast ($0f) and fractional ($0e) velocities based on y ; negate final results if $12 is greater than or equal to #$00 ; also used directly for indoor bullets @@ -9734,7 +9733,7 @@ aim_and_create_enemy_bullet: sty $06 ; store bullet speed code in $06 sta $00 ; store bullet type temporarily lda #$01 ; a = #$01, use quadrant_aim_dir_01 - sta $0f ; quadrant_aim_dir_lookup_tbl offset (quadrant_aim_dir_01) + sta $0f ; quadrant_aim_dir_lookup_ptr_tbl offset (quadrant_aim_dir_01) lda $0a ; load player y position bpl @continue ; branch if >= #$00 lda $0c ; load player y position @@ -9857,10 +9856,10 @@ create_enemy_bullet: @continue: sta $06 ; store speed code in $06 - lda $08 ; load enemy bullet y position - sta ENEMY_Y_POS,x ; store enemy bullet y position on screen - lda $09 ; load enemy bullet x position - sta ENEMY_X_POS,x ; store enemy bullet x position on screen + lda $08 ; load created bullet enemy y position + sta ENEMY_Y_POS,x ; set created bullet enemy y position + lda $09 ; load created bullet enemy y position + sta ENEMY_X_POS,x ; set created bullet enemy x position lda $0a and #$1f ; keep bits ...x xxxx (quadrant aim dir) @@ -10151,7 +10150,7 @@ rotate_enemy_var_1: rts ; determines which direction to rotate based on quadrant_aim_dir_00 -; targetting player index ($0a) +; targeting player index ($0a) ; input ; * $0a - player index to target, 0 = player 1, 1 = player 2 ; * $08 - source y position @@ -10162,10 +10161,10 @@ rotate_enemy_var_1: ; * $0c - new enemy aim direction get_rotate_00: lda #$00 ; a = #$00 (use quadrant_aim_dir_00) - beq get_rotate_dir_for_index ; always jump, get enemy aim direction and rotation direction using quadrant_aim_dir_00 + beq get_rotate_dir_for_index ; always branch, get enemy aim direction and rotation direction using quadrant_aim_dir_00 ; determines which direction to rotate based on quadrant_aim_dir_01 -; targetting player index ($0a) +; targeting player index ($0a) ; input ; * $0a - player index to target, 0 = player 1, 1 = player 2 ; * $08 - source y position @@ -10177,10 +10176,10 @@ get_rotate_00: get_rotate_01: lda #$01 ; a = #$01 (use quadrant_aim_dir_01) -; determines which direction to rotate based on quadrant_aim_dir_lookup_tbl index offset (a) -; targetting player index ($0a) +; determines which direction to rotate based on quadrant_aim_dir_lookup_ptr_tbl index offset (a) +; targeting player index ($0a) ; input -; * a - quadrant_aim_dir_lookup_tbl offset table +; * a - quadrant_aim_dir_lookup_ptr_tbl offset table ; * $0a - player index to target, 0 = player 1, 1 = player 2 ; * $08 - source y position ; * $09 - source x position @@ -10189,7 +10188,7 @@ get_rotate_01: ; * a - rotation direction, #$00 clockwise, #$01 counterclockwise, #$80 no rotation needed ; * $0c - new enemy aim direction get_rotate_dir_for_index: - sta $0f ; set quadrant_aim_dir_lookup_tbl index offset + sta $0f ; set quadrant_aim_dir_lookup_ptr_tbl index offset lda $0a ; load player index bpl @get_quadrant_aim_dir ; branch if closest player has been determined lda $0c ; no player to target, not sure when this happens (see player_enemy_x_dist) @@ -10211,14 +10210,14 @@ get_rotate_dir_for_index: ; * $07 - specifies quadrant to aim in (0 = quadrant IV, 1 = quadrant I, 2 = quadrant III, 3 = quadrant II) ; * bit 0 - 0 = bottom half of plane (quadrants III and IV), 1 = top half of plane (quadrants I and II) ; * bit 1 - 0 = right half of the plan (quadrants I and IV), 1 = left half of plane (quadrants II and III) -; * $0f - quadrant_aim_dir_lookup_tbl offset +; * $0f - quadrant_aim_dir_lookup_ptr_tbl offset ; output ; * negative flag - set when enemy is already aiming at player and no rotation is needed ; * a - rotation direction, #$00 clockwise, #$01 counterclockwise, #$80 no rotation needed ; * $0c - new enemy aim direction get_rotate_dir: sta $0c ; store quadrant aim direction code in $0c - lda $0f ; load quadrant_aim_dir_lookup_tbl offset (which quadrant_aim_dir_xx to use) + lda $0f ; load quadrant_aim_dir_lookup_ptr_tbl offset (which quadrant_aim_dir_xx to use) lsr ; move bit 0 to the carry lda #$06 ; using either quadrant_aim_dir_00, or quadrant_aim_dir_02 ; midway direction, i.e. 9 o'clock @@ -10324,7 +10323,7 @@ get_rotate_dir: dragon_arm_orb_seek_should_move: jsr set_08_09_to_enemy_pos ; set $08 and $09 to enemy x's X and Y position lda #$02 ; dragon arm orb is only enemy that uses quadrant_aim_dir_02 - sta $0f ; set quadrant_aim_dir_lookup_tbl offset to use quadrant_aim_dir_02 + sta $0f ; set quadrant_aim_dir_lookup_ptr_tbl offset to use quadrant_aim_dir_02 jsr get_quadrant_aim_dir_for_player ; set a to the aim direction within a quadrant ; based on source position ($09, $08) targeting player index $0a sta $0c ; store enemy aim direction in $0c @@ -10393,7 +10392,7 @@ dragon_arm_orb_seek_should_move: ; determines the aim direction within a quadrant based on source position ($09, $08) targeting player index $0a ; input -; * $0f - quadrant_aim_dir_lookup_tbl offset [#$00-#$02] +; * $0f - quadrant_aim_dir_lookup_ptr_tbl offset [#$00-#$02] ; * $0a - player index of player to target (#$00 for p1 or #$01 for p2) ; * $08 - source y position ; * $09 - source x position @@ -10443,7 +10442,7 @@ get_quadrant_aim_dir_for_player: ; * $09 - source x position ; * $0a - closest player y position ; * $0b - closest player x position -; * $0f - which of the #$03 tables from quadrant_aim_dir_lookup_tbl to use +; * $0f - which of the #$03 tables from quadrant_aim_dir_lookup_ptr_tbl to use ; output ; * a - quadrant aim direction (quadrant_aim_dir_xx value) ; * $07 - specifies quadrant to aim in (0 = quadrant IV, 1 = quadrant I, 2 = quadrant III, 3 = quadrant II) @@ -10453,7 +10452,7 @@ get_quadrant_aim_dir: ldy #$00 ; default assume player is to the right and equal to or below enemy lda $0a ; load closest player y position sec ; set carry flag in preparation for subtraction - sbc $08 ; subract enemy y position from player y position + sbc $08 ; subtract enemy y position from player y position bcs @shift_get_x_diff ; branch if no overflow occurred (enemy above player or same vertical position) eor #$ff ; enemy below player, handle overflow, flip all bits and add one adc #$01 @@ -10477,33 +10476,33 @@ get_quadrant_aim_dir: iny ; if y was 0, now is 2, if y was 1, now is 3 @continue: - lsr ; shift the difference between player and enemy x difference 6 bits - lsr ; (every #$40 pixels difference is a new horizontal direction) + lsr ; shift the difference between player and enemy x difference 6 bits + lsr ; (every #$40 pixels difference is a new horizontal direction) lsr lsr lsr - sty $07 ; store position of player relative to enemy in $07 (above/below, left/right) - lsr ; push bit 5 to the carry flag for use after plp instruction below - sta $0b ; overwrite player x position with shifted bits 6 and 7 - ; (values [#$00-#$03]) of horizontal distance - php ; backup CPU status flags on stack - lda $0f ; load which of the #$03 tables from quadrant_aim_dir_lookup_tbl to use - asl ; double since each entry is #$2 bytes - tay ; transfer to offset register - lda quadrant_aim_dir_lookup_tbl,y ; get low byte of quadrant_aim_dir_xx address - sta $0c ; store low byte of pointer address in $0c - lda quadrant_aim_dir_lookup_tbl+1,y ; get high byte of quadrant_aim_dir_xx address - sta $0d ; store high byte of pointer address in $0d - lda $0a ; load y difference to determine row offset + sty $07 ; store position of player relative to enemy in $07 (above/below, left/right) + lsr ; push bit 5 to the carry flag for use after plp instruction below + sta $0b ; overwrite player x position with shifted bits 6 and 7 + ; (values [#$00-#$03]) of horizontal distance + php ; backup CPU status flags on stack + lda $0f ; load which of the #$03 tables from quadrant_aim_dir_lookup_ptr_tbl to use + asl ; double since each entry is #$2 bytes + tay ; transfer to offset register + lda quadrant_aim_dir_lookup_ptr_tbl,y ; get low byte of quadrant_aim_dir_xx address + sta $0c ; store low byte of pointer address in $0c + lda quadrant_aim_dir_lookup_ptr_tbl+1,y ; get high byte of quadrant_aim_dir_xx address + sta $0d ; store high byte of pointer address in $0d + lda $0a ; load y difference to determine row offset asl - asl ; quadruple since each entry is #$04 bytes to get correct row - adc $0b ; add the x distance between player and enemy as offset into the entry to load - ; this gets the column of the aim direction - tay ; transfer to offset register - lda ($0c),y ; load specific byte - plp ; restore CPU status flags from stack - bcs @set_and_exit ; branch if bit 5 of difference between player and enemy was set - lsr ; this segments screen into bands for which nibble to use + asl ; quadruple since each entry is #$04 bytes to get correct row + adc $0b ; add the x distance between player and enemy as offset into the entry to load + ; this gets the column of the aim direction + tay ; transfer to offset register + lda ($0c),y ; load specific byte + plp ; restore CPU status flags from stack + bcs @set_and_exit ; branch if bit 5 of difference between player and enemy was set + lsr ; this segments screen into bands for which nibble to use lsr lsr lsr @@ -10512,8 +10511,8 @@ get_quadrant_aim_dir: and #$0f ; keep low nibble rts -; pointer table for set of quadran aim directions (#$3 * #$2 = #$6 bytes) -quadrant_aim_dir_lookup_tbl: +; pointer table for set of quadrant aim directions (#$3 * #$2 = #$6 bytes) +quadrant_aim_dir_lookup_ptr_tbl: .addr quadrant_aim_dir_00 ; CPU address $f5b2 (soldiers, weapon boxes, red turrets, wall core) .addr quadrant_aim_dir_01 ; CPU address $f5d2 (rotating gun, wall turrets, sniper, eye projectile, spinning bubbles, jumping soldier, white blob) .addr quadrant_aim_dir_02 ; CPU address $f5f2 (dragon arm seeking) diff --git a/src/constants.asm b/src/constants.asm index 25e9db1..44c13d4 100644 --- a/src/constants.asm +++ b/src/constants.asm @@ -1,438 +1,258 @@ -; Contra US Disassembly - v1.2 +; Contra US Disassembly - v1.3 ; https://github.com/vermiceli/nes-contra-us ; constants.asm contains the list of constants with meaningful names for the ; memory addresses used by the game. It also contains constants for the various ; palette colors. +.importzp GAME_ROUTINE_INDEX ; $18 +.importzp GAME_END_ROUTINE_INDEX ; $19 +.importzp GAME_ROUTINE_INIT_FLAG ; $19 +.importzp FRAME_COUNTER ; $1a +.importzp NMI_CHECK ; $1b +.importzp DEMO_MODE ; $1c +.importzp PLAYER_MODE_1D ; $1d +.importzp DEMO_LEVEL_END_FLAG ; $1f +.importzp PPU_READY ; $20 +.importzp GRAPHICS_BUFFER_OFFSET ; $21 +.importzp PLAYER_MODE ; $22 +.importzp GRAPHICS_BUFFER_MODE ; $23 +.importzp KONAMI_CODE_STATUS ; $24 +.importzp PAUSE_STATE ; $25 +.importzp DEMO_LEVEL ; $27 +.importzp INTRO_THEME_DELAY ; $28 +.importzp GAME_OVER_DELAY_TIMER ; $29 +.importzp DELAY_TIME_LOW_BYTE ; $2a +.importzp DELAY_TIME_HIGH_BYTE ; $2b +.importzp LEVEL_ROUTINE_INDEX ; $2c +.importzp END_LEVEL_ROUTINE_INDEX ; $2d +.importzp DEMO_FIRE_DELAY_TIMER ; $2e +.importzp PLAYER_WEAPON_STRENGTH ; $2f +.importzp CURRENT_LEVEL ; $30 +.importzp GAME_COMPLETION_COUNT ; $31 +.importzp P1_NUM_LIVES ; $32 +.importzp P2_NUM_LIVES ; $33 +.importzp RANDOM_NUM ; $34 +.importzp NUM_PALETTES_TO_LOAD ; $36 +.importzp INDOOR_SCREEN_CLEARED ; $37 +.importzp P1_GAME_OVER_STATUS ; $38 +.importzp P2_GAME_OVER_STATUS ; $39 +.importzp NUM_CONTINUES ; $3a +.importzp BOSS_DEFEATED_FLAG ; $3b +.importzp EXTRA_LIFE_SCORE_LOW ; $3c +.importzp EXTRA_LIFE_SCORE_HIGH ; $3d +.importzp KONAMI_CODE_NUM_CORRECT ; $3f +.importzp LEVEL_LOCATION_TYPE ; $40 +.importzp LEVEL_SCROLLING_TYPE ; $41 +.importzp LEVEL_SCREEN_SUPERTILES_PTR ; $42 +.importzp LEVEL_SUPERTILE_DATA_PTR ; $44 +.importzp LEVEL_SUPERTILE_PALETTE_DATA ; $46 +.importzp LEVEL_ALT_GRAPHICS_POS ; $48 +.importzp COLLISION_CODE_1_TILE_INDEX ; $49 +.importzp COLLISION_CODE_0_TILE_INDEX ; $4a +.importzp COLLISION_CODE_2_TILE_INDEX ; $4b +.importzp LEVEL_PALETTE_CYCLE_INDEXES ; $4c +.importzp LEVEL_PALETTE_INDEX ; $50 +.importzp LEVEL_STOP_SCROLL ; $58 +.importzp LEVEL_SOLID_BG_COLLISION_CHECK ; $59 +.importzp DEMO_INPUT_NUM_FRAMES ; $5a +.importzp DEMO_INPUT_VAL ; $5c +.importzp DEMO_INPUT_TBL_INDEX ; $5e +.importzp PPU_WRITE_TILE_OFFSET ; $60 +.importzp LEVEL_TRANSITION_TIMER ; $61 +.importzp PPU_WRITE_ADDRESS_LOW_BYTE ; $62 +.importzp PPU_WRITE_ADDRESS_HIGH_BYTE ; $63 +.importzp LEVEL_SCREEN_NUMBER ; $64 +.importzp LEVEL_SCREEN_SCROLL_OFFSET ; $65 +.importzp ATTRIBUTE_TBL_WRITE_LOW_BYTE ; $66 +.importzp ATTRIBUTE_TBL_WRITE_HIGH_BYTE ; $67 +.importzp FRAME_SCROLL ; $68 +.importzp SUPERTILE_NAMETABLE_OFFSET ; $69 +.importzp SPRITE_LOAD_TYPE ; $6a +.importzp CONT_END_SELECTION ; $6b +.importzp ALT_GRAPHIC_DATA_LOADING_FLAG ; $71 +.importzp LEVEL_PALETTE_CYCLE ; $72 +.importzp INDOOR_SCROLL ; $73 +.importzp BG_PALETTE_ADJ_TIMER ; $74 +.importzp AUTO_SCROLL_TIMER_00 ; $75 +.importzp AUTO_SCROLL_TIMER_01 ; $76 +.importzp TANK_AUTO_SCROLL ; $77 +.importzp PAUSE_PALETTE_CYCLE ; $78 +.importzp SOLDIER_GENERATION_ROUTINE ; $79 +.importzp SOLDIER_GENERATION_TIMER ; $7a +.importzp SOLDIER_GENERATION_X_POS ; $7b +.importzp SOLDIER_GENERATION_Y_POS ; $7c +.importzp FALCON_FLASH_TIMER ; $7d +.importzp TANK_ICE_JOINT_SCROLL_FLAG ; $7f +.importzp ENEMY_LEVEL_ROUTINES ; $80 +.importzp ENEMY_SCREEN_READ_OFFSET ; $82 +.importzp ENEMY_CURRENT_SLOT ; $83 +.importzp BOSS_AUTO_SCROLL_COMPLETE ; $84 +.importzp BOSS_SCREEN_ENEMIES_DESTROYED ; $85 +.importzp WALL_CORE_REMAINING ; $86 +.importzp WALL_PLATING_DESTROYED_COUNT ; $87 +.importzp INDOOR_ENEMY_ATTACK_COUNT ; $88 +.importzp INDOOR_RED_SOLDIER_CREATED ; $89 +.importzp GRENADE_LAUNCHER_FLAG ; $8a +.importzp ALIEN_FETUS_AIM_TIMER_INDEX ; $8b +.importzp ENEMY_ATTACK_FLAG ; $8e +.importzp PLAYER_STATE ; $90 +.importzp INDOOR_TRANSITION_X_ACCUM ; $92 +.importzp PLAYER_JUMP_COEFFICIENT ; $94 +.importzp INDOOR_TRANSITION_X_FRACT_VEL ; $96 +.importzp PLAYER_X_VELOCITY ; $98 +.importzp INDOOR_TRANSITION_Y_FRACT_VEL ; $9a +.importzp INDOOR_TRANSITION_Y_FAST_VEL ; $9c +.importzp PLAYER_ANIM_FRAME_TIMER ; $9e +.importzp PLAYER_JUMP_STATUS ; $a0 +.importzp PLAYER_FRAME_SCROLL ; $a2 +.importzp EDGE_FALL_CODE ; $a4 +.importzp PLAYER_ANIMATION_FRAME_INDEX ; $a6 +.importzp PLAYER_INDOOR_ANIM_Y ; $a8 +.importzp P1_CURRENT_WEAPON ; $aa +.importzp P2_CURRENT_WEAPON ; $ab +.importzp PLAYER_M_WEAPON_FIRE_TIME ; $ac +.importzp NEW_LIFE_INVINCIBILITY_TIMER ; $ae +.importzp INVINCIBILITY_TIMER ; $b0 +.importzp PLAYER_WATER_STATE ; $b2 +.importzp PLAYER_DEATH_FLAG ; $b4 +.importzp PLAYER_ON_ENEMY ; $b6 +.importzp PLAYER_FALL_X_FREEZE ; $b8 +.importzp PLAYER_HIDDEN ; $ba +.importzp PLAYER_SPRITE_SEQUENCE ; $bc +.importzp PLAYER_INDOOR_ANIM_X ; $be +.importzp PLAYER_AIM_PREV_FRAME ; $c0 +.importzp PLAYER_AIM_DIR ; $c2 +.importzp PLAYER_Y_FRACT_VELOCITY ; $c4 +.importzp PLAYER_Y_FAST_VELOCITY ; $c6 +.importzp ELECTROCUTED_TIMER ; $c8 +.importzp INDOOR_PLAYER_JUMP_FLAG ; $ca +.importzp PLAYER_WATER_TIMER ; $cc +.importzp PLAYER_RECOIL_TIMER ; $ce +.importzp INDOOR_PLAYER_ADV_FLAG ; $d0 +.importzp PLAYER_SPECIAL_SPRITE_TIMER ; $d2 +.importzp PLAYER_FAST_X_VEL_BOOST ; $d4 +.importzp PLAYER_SPRITE_CODE ; $d6 +.importzp PLAYER_SPRITE_FLIP ; $d8 +.importzp PLAYER_BG_FLAG_EDGE_DETECT ; $da +.importzp PLAYER_GAME_OVER_BIT_FIELD ; $df +.importzp SOUND_TABLE_PTR ; $ec +.importzp CONTROLLER_STATE ; $f1 +.importzp CONTROLLER_STATE_DIFF ; $f5 +.importzp CTRL_KNOWN_GOOD ; $f9 +.importzp VERTICAL_SCROLL ; $fc +.importzp HORIZONTAL_SCROLL ; $fd +.importzp PPUMASK_SETTINGS ; $fe +.importzp PPUCTRL_SETTINGS ; $ff + +.import SOUND_CMD_LENGTH ; $0100 +.import SOUND_CODE ; $0106 +.import SOUND_PULSE_LENGTH ; $010c +.import SOUND_CMD_LOW_ADDR ; $0112 +.import SOUND_CMD_HIGH_ADDR ; $0118 +.import SOUND_VOL_ENV ; $011e +.import SOUND_CURRENT_SLOT ; $0120 +.import PERCUSSION_INDEX_BACKUP ; $0121 +.import INIT_SOUND_CODE ; $0122 +.import SOUND_CHNL_REG_OFFSET ; $0123 +.import SOUND_FLAGS ; $0124 +.import LVL_PULSE_VOL_INDEX ; $012a +.import PULSE_VOL_DURATION ; $012a +.import PAUSE_STATE_01 ; $012f +.import DECRESCENDO_END_PAUSE ; $0131 +.import SOUND_PITCH_ADJ ; $0132 +.import UNKNOWN_SOUND_00 ; $0136 +.import UNKNOWN_SOUND_01 ; $013c +.import SOUND_CFG_LOW ; $0142 +.import SOUND_TRIANGLE_CFG ; $0144 +.import SOUND_REPEAT_COUNT ; $0148 +.import SOUND_CFG_HIGH ; $014e +.import SOUND_LENGTH_MULTIPLIER ; $0154 +.import SOUND_PERIOD_ROTATE ; $015a +.import PULSE_VOLUME ; $0160 +.import NEW_SOUND_CODE_LOW_ADDR ; $0166 +.import NEW_SOUND_CODE_HIGH_ADDR ; $016c +.import SOUND_PULSE_PERIOD ; $0172 +.import VIBRATO_CTRL ; $0178 +.import SOUND_VOL_TIMER ; $017a +.import PULSE_NOTE ; $017c +.import VIBRATO_DELAY ; $017e +.import VIBRATO_AMOUNT ; $0180 +.import LEVEL_END_DELAY_TIMER ; $0190 +.import LEVEL_END_SQ_1_TIMER ; $0191 +.import LEVEL_END_LVL_ROUTINE_STATE ; $0193 +.import LEVEL_END_PLAYERS_ALIVE ; $0194 +.import SOLDIER_GEN_SCREEN ; $0195 +.import SCREEN_GEN_SOLDIERS ; $0196 +.import OAMDMA_CPU_BUFFER ; $0200 +.import CPU_SPRITE_BUFFER ; $0300 +.import PLAYER_SPRITES ; $0300 +.import ENEMY_SPRITES ; $030a +.import SPRITE_Y_POS ; $031a +.import ENEMY_Y_POS ; $0324 +.import SPRITE_X_POS ; $0334 +.import ENEMY_X_POS ; $033e +.import SPRITE_ATTR ; $034e +.import ENEMY_SPRITE_ATTR ; $0358 +.import PLAYER_BULLET_SPRITE_CODE ; $0368 +.import PLAYER_BULLET_SPRITE_ATTR ; $0378 +.import PLAYER_BULLET_SLOT ; $0388 +.import PLAYER_BULLET_Y_VEL_ACCUM ; $0398 +.import PLAYER_BULLET_X_VEL_ACCUM ; $03a8 +.import PLAYER_BULLET_Y_POS ; $03b8 +.import PLAYER_BULLET_X_POS ; $03c8 +.import PLAYER_BULLET_Y_VEL_FRACT ; $03d8 +.import PLAYER_BULLET_X_VEL_FRACT ; $03e8 +.import PLAYER_BULLET_Y_VEL_FAST ; $03f8 +.import PLAYER_BULLET_X_VEL_FAST ; $0408 +.import PLAYER_BULLET_TIMER ; $0418 +.import PLAYER_BULLET_AIM_DIR ; $0428 +.import PLAYER_BULLET_ROUTINE ; $0438 +.import PLAYER_BULLET_OWNER ; $0448 +.import PLAYER_BULLET_F_RAPID ; $0458 +.import PLAYER_BULLET_S_INDOOR_ADJ ; $0458 +.import PLAYER_BULLET_DIST ; $0468 +.import PLAYER_BULLET_S_ADJ_ACCUM ; $0468 +.import PLAYER_BULLET_FS_X ; $0478 +.import PLAYER_BULLET_F_Y ; $0488 +.import PLAYER_BULLET_S_RAPID ; $0488 +.import PLAYER_BULLET_VEL_FS_X_ACCUM ; $0498 +.import PLAYER_BULLET_VEL_F_Y_ACCUM ; $04a8 +.import PLAYER_BULLET_S_BULLET_NUM ; $04a8 +.import ENEMY_ROUTINE ; $04b8 +.import ENEMY_Y_VEL_ACCUM ; $04c8 +.import ENEMY_X_VEL_ACCUM ; $04d8 +.import ENEMY_Y_VELOCITY_FAST ; $04e8 +.import ENEMY_Y_VELOCITY_FRACT ; $04f8 +.import ENEMY_X_VELOCITY_FAST ; $0508 +.import ENEMY_X_VELOCITY_FRACT ; $0518 +.import ENEMY_TYPE ; $0528 +.import ENEMY_ANIMATION_DELAY ; $0538 +.import ENEMY_VAR_A ; $0548 +.import ENEMY_ATTACK_DELAY ; $0558 +.import ENEMY_VAR_B ; $0558 +.import ENEMY_FRAME ; $0568 +.import ENEMY_HP ; $0578 +.import ENEMY_SCORE_COLLISION ; $0588 +.import ENEMY_STATE_WIDTH ; $0598 +.import ENEMY_ATTRIBUTES ; $05a8 +.import ENEMY_VAR_1 ; $05b8 +.import ENEMY_VAR_2 ; $05c8 +.import ENEMY_VAR_3 ; $05d8 +.import ENEMY_VAR_4 ; $05e8 +.import LEVEL_SCREEN_SUPERTILES ; $0600 +.import BG_COLLISION_DATA ; $0680 +.import CPU_GRAPHICS_BUFFER ; $0700 +.import PALETTE_CPU_BUFFER ; $07c0 +.import HIGH_SCORE_LOW ; $07e0 +.import HIGH_SCORE_HIGH ; $07e1 +.import PLAYER_1_SCORE_LOW ; $07e2 +.import PLAYER_1_SCORE_HIGH ; $07e3 +.import PLAYER_2_SCORE_LOW ; $07e4 +.import PLAYER_2_SCORE_HIGH ; $07e5 +.import PREVIOUS_ROM_BANK ; $07ec +.import PREVIOUS_ROM_BANK_1 ; $07ed + BANK_NUMBER = $8000 -GAME_ROUTINE_INDEX = $18 ; which part of the game routine to execute (see game_routine_pointer_table) -GAME_END_ROUTINE_INDEX = $19 ; used after beating the game to know which part of the ending sequence to execute for sequencing the animations, credits, restart, etc. (see game_end_routine_tbl) -GAME_ROUTINE_INIT_FLAG = $19 ; (same address as above) used to determine if the current game_routine has been initialized, used in game_routine_02 and game_routine_03 -FRAME_COUNTER = $1a ; the frame counter loops from #$00 to #$ff increments once per frame. Also known as the global timer -NMI_CHECK = $1b ; set to #$01 at start of nmi and #$00 at end - ; used to track if nmi occurred during game loop - ; bit 7 is set when inside play_sound, i.e. init_sound_code_vars -DEMO_MODE = $1c ; #$00 not in demo mode, #$01 demo mode on -PLAYER_MODE_1D = $1d ; #$01 for 1 player, #$07 for 2 player. Not sure why developer just didn't use PLAYER_MODE instead -DEMO_LEVEL_END_FLAG = $1f ; whether or not demo for the level is complete and new demo level should play -PPU_READY = $20 ; #$00 when at least 5 executions of nmi_start have happened since last configure_PPU call -GRAPHICS_BUFFER_OFFSET = $21 ; current write offset into CPU_GRAPHICS_BUFFER (CPU_GRAPHICS_BUFFER contains pattern table tiles that are written to PPU) -PLAYER_MODE = $22 ; #$00 = single player, #$01 = 2 player -GRAPHICS_BUFFER_MODE = $23 ; defines the format of the CPU_GRAPHICS_BUFFER. #$ff is for super-tile data, #$00 is for text strings and palette data -KONAMI_CODE_STATUS = $24 ; #$00 not entered, #$01 entered, (30 lives code) -PAUSE_STATE = $25 ; #$00 when not paused, #$01 when paused -DEMO_LEVEL = $27 ; the current level when in DEMO mode - ; only ever 0, 1 or 2 as those are the only levels demoed -INTRO_THEME_DELAY = $28 ; timer to prevent starting a level until the intro theme is complete (including explosion sound). - ; initialized to #a4, decrements every other frame for ~5 seconds for NTSC -GAME_OVER_DELAY_TIMER = $29 ; goes from #$60 to #$00, timer after dying before showing score -DELAY_TIME_LOW_BYTE = $2a ; the low byte of the delay -DELAY_TIME_HIGH_BYTE = $2b ; the high byte of the delay -LEVEL_ROUTINE_INDEX = $2c ; the index into level_routine_ptr_tbl of the routine to run -END_LEVEL_ROUTINE_INDEX = $2d ; offset into either end_level_sequence_ptr_tbl or end_game_sequence_ptr_tbl -DEMO_FIRE_DELAY_TIMER = $2e ; the number of frames to delay before starting to fire when demoing -PLAYER_WEAPON_STRENGTH = $2f ; the damage strength of the player's current weapon (see weapon_strength) based on bits 0-2 of P1_CURRENT_WEAPON,x - ; Default = #$00, M = #$02, F = #$01, S = #$03, L = #$02 -CURRENT_LEVEL = $30 ; #$00-#$09, #$00 to #$07 represent levels 1 through 8. #$9 is interpreted as game over sequence -GAME_COMPLETION_COUNT = $31 ; the number of times the game has been completed (final boss defeated) -P1_NUM_LIVES = $32 ; P1 number of lives, #$00 is last life, on game over stays #$00, but P1_GAME_OVER_STATUS becomes #$01 -P2_NUM_LIVES = $33 ; P2 number of lives, #$00 is last life, on game over stays #$00, but P2_GAME_OVER_STATUS becomes #$01 -RANDOM_NUM = $34 ; random number increased in forever_loop -NUM_PALETTES_TO_LOAD = $36 ; the number of palettes to load into CPU memory -INDOOR_SCREEN_CLEARED = $37 ; whether indoor screen has had all cores destroyed (0 = not cleared, 1 = cleared, #$80 = cleared and fence removed) -P1_GAME_OVER_STATUS = $38 ; #$00 not game over, #$01 game over -P2_GAME_OVER_STATUS = $39 ; #$00 not game over, #$01 game over or player 2 not playing (1 player game) -NUM_CONTINUES = $3a ; the number of continues remaining -BOSS_DEFEATED_FLAG = $3b ; whether or not the level boss has been defeated (0 = no, 1 = yes) - ; after set to 1, end level sequence logic uses this value as well using values #$81 and #$02 -EXTRA_LIFE_SCORE_LOW = $3c ; the low byte of the score required for the next extra life -EXTRA_LIFE_SCORE_HIGH = $3d ; the high byte of the score required for the next extra life - ; $3e is the EXTRA_LIFE_SCORE_LOW for player 2 -KONAMI_CODE_NUM_CORRECT = $3f ; the number of successful inputs of the Konami code sequence #$0a for all correct - ; also used as player 2's EXTRA_LIFE_SCORE_HIGH byte during game play - -; level header data -LEVEL_LOCATION_TYPE = $40 ; current level type #$00 outdoor, #$01 indoor (base level); #$80 on indoor/base boss screen and indoor/base levels when players advancing to next screen -LEVEL_SCROLLING_TYPE = $41 ; current level scrolling type #$00 horizontal (and indoor/base level) #$01 vertical -LEVEL_SCREEN_SUPERTILES_PTR = $42 ; $42,$43 stores 2-byte address to bank 2 containing which super-tiles to use for each screen of the level (level_x_supertiles_screen_ptr_table) -LEVEL_SUPERTILE_DATA_PTR = $44 ; current level 2-byte pointer to super-tile data, which defines pattern table tiles of the super-tiles that are used to make level blocks -LEVEL_SUPERTILE_PALETTE_DATA = $46 ; current level 2-byte pointer address to the palettes used for each super-tile, each byte describes the 4 palettes for a single super-tile -LEVEL_ALT_GRAPHICS_POS = $48 ; how far into level (in number of screens) before loading alternate graphic data -COLLISION_CODE_1_TILE_INDEX = $49 ; pattern table tiles below this tile index (but not #$00) are considered Collision Code 1 (floor) -COLLISION_CODE_0_TILE_INDEX = $4a ; pattern table tiles >= $49 and less than this tile index are considered Collision Code 0 (empty) -COLLISION_CODE_2_TILE_INDEX = $4b ; pattern table tiles >= $4a and less than this tile index are considered Collision Code 2 (water) - -LEVEL_PALETTE_CYCLE_INDEXES = $4c ; palette indexes into game_palettes to cycle through for the level for the 4th nametable palette index [$4c-4f] -LEVEL_PALETTE_INDEX = $50 ; the level's initial background palettes [$50 to $54) and sprite palettes [$54 to $58). Offsets into game_palettes table - -LEVEL_STOP_SCROLL = $58 ; the screen of the level to stop scrolling, set to #$ff when boss auto scroll starts -LEVEL_SOLID_BG_COLLISION_CHECK = $59 ; used to determine whether to check for bullet and weapon item solid bg collisions - ; 1. When non-zero, specifies weapon item should check for solid bg collisions (weapon_item_check_bg_collision) - ; 2. When negative, used to let bullet (player and enemy) collision detection code to know to look for bullet-solid background collisions - ; This is for levels 6 - energy zone and 7 - hangar. (see check_bullet_solid_bg_collision and enemy_bullet_routine_01) - -DEMO_INPUT_NUM_FRAMES = $5a ; used to determine how many even-numbered frames to continue pressing the button specified in $5c for demo - ; $5b the DEMO_INPUT_NUM_FRAMES for player 2 -DEMO_INPUT_VAL = $5c ; the current controller input pressed during a demo - ; $5d is DEMO_INPUT_VAL for player 2 -DEMO_INPUT_TBL_INDEX = $5e ; when in demo, this stores the offset into specific demo_input_tbl_lX_pX table - ; $5f is for player 2 -PPU_WRITE_TILE_OFFSET = $60 ; the current write offset of the super-tile data, number of tiles outside the current view - ; horizontal levels loops #$00 to #$1f, vert starts with #$1d goes down to #$00 before looping -LEVEL_TRANSITION_TIMER = $61 ; used in vertical levels to time animation between sections for every 'up' input - ; used in indoor levels between screens to animate moving forward -PPU_WRITE_ADDRESS_LOW_BYTE = $62 ; used to populate the PPU write address in the CPU_GRAPHICS_BUFFER -PPU_WRITE_ADDRESS_HIGH_BYTE = $63 ; used to populate the PPU write address in the CPU_GRAPHICS_BUFFER -LEVEL_SCREEN_NUMBER = $64 ; the screen number of the current level (how many screens into the level) -LEVEL_SCREEN_SCROLL_OFFSET = $65 ; the number of pixels into LEVEL_SCREEN_NUMBER the level has scrolled. Goes from #$00-#$ff for each screen (256 pixels) - ; for horizontal levels, this is how many pixels scrolled to the right - ; for vertical levels, this is how many pixels up scrolled, note this value is equal to #$f0 - VERTICAL_SCROLL - ; for indoor levels, after defeating a wall, increases from #$00 to #03 -ATTRIBUTE_TBL_WRITE_LOW_BYTE = $66 ; the low byte of the attribute table write address to write to (always #$c0, never read) -ATTRIBUTE_TBL_WRITE_HIGH_BYTE = $67 ; the high byte of the attribute table write address to write to -FRAME_SCROLL = $68 ; how much to scroll the screen this frame based on player velocity (usually #$00 or #$01), for vertical levels, up to #$04 - ; note that this is not the scroll distance within the screen -SUPERTILE_NAMETABLE_OFFSET = $69 ; base nametable offset into memory address into CPU graphics buffer starting at $0600 (LEVEL_SCREEN_SUPERTILES) - ; always either #$00 (nametable 0) or #$40 (nametable 1), points to area that contains the super-tile indexes for screen -SPRITE_LOAD_TYPE = $6a ; which sprites to load #$0 for normal sprites, #$1 for HUD sprites -CONT_END_SELECTION = $6b ; #$00 when "CONTINUE" is selected, #$01 when "END" is selected, used only in game over screen (level_routine_06) -ALT_GRAPHIC_DATA_LOADING_FLAG = $71 ; #$00 means that the alternate graphics data should not be loaded, #$01 means it should be #$02 means it currently is being loaded -LEVEL_PALETTE_CYCLE = $72 ; the current iteration of the palette animation loop #$00 up to entry for level in lvl_palette_animation_count -INDOOR_SCROLL = $73 ; scrolling on indoor level changes (#$00 = not scrolling; #$01 = scrolling, #$02 = finished scrolling) -BG_PALETTE_ADJ_TIMER = $74 ; timer used for adjusting background palette colors (not sprite palettes). Used for fade-in effect of dragon and boss ufo as well as indoor transitions -AUTO_SCROLL_TIMER_00 = $75 ; used when completing scroll to show a boss, e.g. vertical level dragon screen -AUTO_SCROLL_TIMER_01 = $76 ; used when completing scroll to show a boss, e.g. alien guardian -TANK_AUTO_SCROLL = $77 ; amount to scroll every frame, regardless of AUTO_SCROLL_TIMER_xx, used for snow field tanks (dogras), breaks levels if used on other levels -PAUSE_PALETTE_CYCLE = $78 ; #$00 - nametable palettes #$03 and #$04 will cycle through colors like normal. Non-zero values will pause palette color cycling (ice field tank pauses palette cycle) -SOLDIER_GENERATION_ROUTINE = $79 ; which routine is currently in use for generating soldiers (index into soldier_generation_ptr_tbl) -SOLDIER_GENERATION_TIMER = $7a ; a timer between soldier generation. #$00 means no generation. see level_soldier_generation_timer. When used in a level, every frame decrements by 2 (unless scrolling, then only by 1) -SOLDIER_GENERATION_X_POS = $7b ; the initial x position of the generated soldier -SOLDIER_GENERATION_Y_POS = $7c ; the initial y position of the generated soldier -FALCON_FLASH_TIMER = $7d ; the number of frames to flash the screen for falcon weapon item -TANK_ICE_JOINT_SCROLL_FLAG = $7f ; whether or not to have the ice joint enemy move left while player walks right to simulate being on the background -ENEMY_LEVEL_ROUTINES = $80 ; two byte address to the correct enemy_routine_level_XX for the current level, used to retrieve enemy routines for the level-specific enemies -ENEMY_SCREEN_READ_OFFSET = $82 ; read offset into level_xx_enemy_screen_xx table, which specifies the enemies on each screen of a level -ENEMY_CURRENT_SLOT = $83 ; when in use, specifies the current enemy slot that is being executed, used to be able to restore x register after method has used it -BOSS_AUTO_SCROLL_COMPLETE = $84 ; set when boss reveal auto-scrolling has completed, see AUTO_SCROLL_TIMER_00 and AUTO_SCROLL_TIMER_01 -BOSS_SCREEN_ENEMIES_DESTROYED = $85 ; used on level 3 and level 7 boss screens to keep track of how many dragon arm orbs or mortar launchers have been destroyed respectively -WALL_CORE_REMAINING = $86 ; remaining wall cores/wall platings to destroy until can advance to next screen. For level 4 boss, used to count remaining boss gemini -WALL_PLATING_DESTROYED_COUNT = $87 ; used in indoor/base boss levels to keep track of how many wall platings (ENEMY_TYPE #$0a) have been destroyed -INDOOR_ENEMY_ATTACK_COUNT = $88 ; used in indoor/base levels to specify how many 'rounds' of attack have happened per screen, max #$07 before certain enemies no longer generate - ; indoor soldiers, jumping soldiers, indoor rollers, and wall core check this value -INDOOR_RED_SOLDIER_CREATED = $89 ; used in indoor/base levels to indicate if a red jumping soldier has been created, to prevent creation of another -GRENADE_LAUNCHER_FLAG = $8a ; used in indoor/base levels to indicate that a grenade launcher enemy (ENEMY_TYPE #$17) is on the screen. Prevents other indoor enemies from being generated -ALIEN_FETUS_AIM_TIMER_INDEX = $8b ; used to keep track of the index into alien_fetus_aim_timer_tbl to set the delay between re-aiming towards the player -ENEMY_ATTACK_FLAG = $8e ; whether or not enemies will fire at player, also whether or not random enemies are generated, bosses ignore this value -PLAYER_STATE = $90 ; #$00 falling into level (only run once to init fall), #$01 normal state, #$02 when dead, #$03 can't move - ; $91 is for p2, if p2 not playing, set to #$00 -INDOOR_TRANSITION_X_ACCUM = $92 ; a variable to store INDOOR_TRANSITION_X_FRACT_VEL being added to itself to account for overflow before adding to player x velocity when moving between screens on indoor/base levels - ; $93 is for p2 -PLAYER_JUMP_COEFFICIENT = $94 ; related to jump height (used by speed runners to jump higher) (https://www.youtube.com/watch?v=K7MjxHvWof8 and https://www.youtube.com/watch?v=yrnW9yQXa9I) - ; used to keep track of fractional y velocity on vertical levels for overflowing fractional velocity. It isn't cleared between jumps - ; also used when walking into screen for indoor screen changes to keep track of overflow of animation y fractional velocity - ; $95 is for player 2 -INDOOR_TRANSITION_X_FRACT_VEL = $96 ; indoor animation transition when walking into screen x fractional velocity - ; $97 is for player 2 -PLAYER_X_VELOCITY = $98 ; the player's fast x velocity (#$00, #$01, or #$ff) - ; $99 is for p2 -INDOOR_TRANSITION_Y_FRACT_VEL = $9a ; indoor animation transition when walking into screen y fractional velocity - ; $9b is for player 2 -INDOOR_TRANSITION_Y_FAST_VEL = $9c ; indoor animation transition when walking into screen y fast velocity - ; $9d is for player 2 -PLAYER_ANIM_FRAME_TIMER = $9e ; value that is incremented every frame when player is walking, used to wait #$08 frames before incrementing PLAYER_ANIMATION_FRAME_INDEX for animating player walking - ; $9f is for player 2 -PLAYER_JUMP_STATUS = $a0 ; the status of the player jump (facing direction); similar to EDGE_FALL_CODE - ; high nibble is for facing direction - ; bit 7 - set when jumping left - ; low nibble is #$01 when jumping, #$00 when not - ; $a1 is for player 2 -PLAYER_FRAME_SCROLL = $a2 ; how much player 1 is causing the frame to scroll by, see FRAME_SCROLL - ; $a3 is for player 2, larger of the 2 is set to FRAME_SCROLL -EDGE_FALL_CODE = $a4 ; similar to PLAYER_JUMP_STATUS. Used to initiate gravity pulling player down - ; if bit 7 set, then falling through platform - ; if bit 6 is set, then walking left off edge - ; if bit 5 is set, then walking right off ledge - ; can change if change direction during fall, bit 0 always set when EDGE_FALL_CODE non-zero - ; $a5 is for player 2 -PLAYER_ANIMATION_FRAME_INDEX = $a6 ; which frame of the player animation. Depends on player state. For example, if player is running, this cycles from #$00 to #$05 - ; $a7 is for player 2 -PLAYER_INDOOR_ANIM_Y = $a8 ; the y position the player was at when they started walking into screen after clearing an indoor level. I believe it's always #$a8 since y pos is hard-coded for indoor levels - ; $a9 is player 2 -P1_CURRENT_WEAPON = $aa ; low nibble is what weapon P1 has, high nibble 1 is rapid fire flag, commonly abbreviated MFSL - ; #$00 - Regular, #$01 - Machine Gun, #$02 - Flame Thrower, #$03 - Spray, #$04 - Laser, bit 4 set for rapid fire -P2_CURRENT_WEAPON = $ab ; byte 0 is what weapon P2 has, byte 1 is rapid fire flag -PLAYER_M_WEAPON_FIRE_TIME = $ac ; used when holding down the B button with the m weapon. High nibble is number of bullets generated (up to #$06), low nibble is counter before next bullet is generated (up to #$07) - ; $ad is for player 2 -NEW_LIFE_INVINCIBILITY_TIMER = $ae ; timer for invincibility after dying - ; $af is for player 2 -INVINCIBILITY_TIMER = $b0 ; timer for player invincibility (b (barrier) weapon) (decreases every 8 frames), usually set to #$80 except level 7 when set to #$90 - ; $b1 is for player 2 -PLAYER_WATER_STATE = $b2 ; bit 1 - horizontal sprite flip flag - ; bit 2 - set when player in water, or exiting water - ; bit 3 - player is walking out of water - ; bit 4 - finished initialization for entering water - ; bit 7 - player is walking out of water - ; $b3 is for player 2 -PLAYER_DEATH_FLAG = $b4 ; bit 0 specifies whether player has died, bit 1 specifies player was facing left when hit, used so player dies lying in appropriate direction - ; $b5 is for player 2 -PLAYER_ON_ENEMY = $b6 ; whether or not the player is on top of another enemy (#$14 - mining cart, #$15 - stationary mining cart, #$10 - floating rock platform) - ; $b7 is for player 2 -PLAYER_FALL_X_FREEZE = $b8 ; used to prevent changing X velocity shortly after walking off/falling through ledge, set to Y post of ledge + #$14 - ; $b9 is for player 2 -PLAYER_HIDDEN = $ba ; #$00 player visible, #$01/#$ff player invisible (any non-zero). I believe it is meant to track distance off screen the player is - ; $bb is for player 2 -PLAYER_SPRITE_SEQUENCE = $bc ; which animation to show for the player - ; outdoor - #$00 standing (no animation), #$01 gun pointing up, #$02 crouching, #$03 walking or curled jump animation, #$04 dead animation - ; indoor - (see indoor_player_sprite_tbl), #$00 standing facing back wall, #$01 electrocuted, #$02 crouching, #$03 walking left/right animation, #$05 walking into screen (advancing), #$06 dead animation - ; $bd is for player 2 -PLAYER_INDOOR_ANIM_X = $be ; the x position the player was at when they started walking into screen after clearing an indoor level - ; $bf is player 2 -PLAYER_AIM_PREV_FRAME = $c0 ; backup of PLAYER_AIM_DIR - ; $c1 is for player 2 -PLAYER_AIM_DIR = $c2 ; which direction the player is aiming [#$00-#$0a] depends on level and jump status (00 up facing right, 1 up-right, 2 right, 3 right-down, 4 crouching facing right, 5 crouching facing left, etc) - ; there are #$02 up and #$02 down values depending on facing direction - ; $c3 is for player 2 -PLAYER_Y_FRACT_VELOCITY = $c4 ; the fractional portion of the player's y velocity - ; $c5 is for player 2 -PLAYER_Y_FAST_VELOCITY = $c6 ; the integer portion of the player's y velocity. Positive pulls down, negative pulls up - ; $c7 is for player 2 -ELECTROCUTED_TIMER = $c8 ; timer for player being electrocuted, used to freeze player and modify look after touching electricity - ; $c9 is for player 2 -INDOOR_PLAYER_JUMP_FLAG = $ca ; used when entering new screen to tell the engine to cause the player to jump - ; $cb is player 2 -PLAYER_WATER_TIMER = $cc ; timer used for getting into and out of water - ; $cd is for player 2 -PLAYER_RECOIL_TIMER = $ce ; how many frames to be pushed back/down from recoil - ; $cf is for player 2 -INDOOR_PLAYER_ADV_FLAG = $d0 ; whether or not the player is walking into screen when advancing between screens on indoor levels, used for animating player - ; $d1 is for player 2 -PLAYER_SPECIAL_SPRITE_TIMER = $d2 ; used to track animation for player death animation - ; outdoor is a timer that increments once player hit, every #$08 frames updates to next animation frame until #$04 - ; also used to track jumping curl animation (loops from #$00-#$04) - ; $d3 is for player 2 -PLAYER_FAST_X_VEL_BOOST = $d4 ; the x fast velocity boost from landing on a non-dangerous enemy, e.g. moving cart or floating rock in vertical level - ; $d5 is for player 2 -PLAYER_SPRITE_CODE = $d6 ; sprite code of the player - ; $d7 is for player 2 -PLAYER_SPRITE_FLIP = $d8 ; stores player sprite horizontal (bit 6) and vertical (bit 7) flip flags before saving into SPRITE_ATTR, other bits are used - ; bit 3 specifies whether the PLAYER_ANIMATION_FRAME_INDEX is even or odd (see @check_anim_frame_and_collision) - ; $d9 is for player 2 -PLAYER_BG_FLAG_EDGE_DETECT = $da ; bit 7 specifies the player's sprite attribute for background priority, allows player to walk behind opaque background (OAM byte 2 bit 5) - ; 0 (clear) sprite in foreground, 1 (set) sprite is background - ; bit 0 allows the player to keep walking horizontally off a ledge without falling - ; $db is for player 2 -PLAYER_GAME_OVER_BIT_FIELD = $df ; combination of both players game over status - ; #$00 = p1 not game over, p2 game over (or not playing), #$01 = p1 game over, p2 not game over, #$02 = p1 nor p2 are in game over -SOUND_TABLE_PTR = $ec ; low byte of address pointing of index into sound_table_00 offset INIT_SOUND_CODE -CONTROLLER_STATE = $f1 ; stores the currently-pressed buttons for player 1 - ; bit 7 - A, bit 6 - B, bit 5 - select, bit 4 - start - ; bit 3 - up, bit 2 - down, bit 1 - left, bit 0 - right - ; $f2 stores the currently-pressed buttons for player 2 -CONTROLLER_STATE_DIFF = $f5 ; stores the difference between the controller input between reads. Useful for events that should only trigger on first button press - ; $f6 is for player 2 -CTRL_KNOWN_GOOD = $f9 ; used in input-reading code to know the last known valid read of controller input (similar to CONTROLLER_STATE) - ; $fa is for player 2 -VERTICAL_SCROLL = $fc ; the number of pixels to vertically scroll down - ; (y component of PPUSCROLL) (see level_vert_scroll_and_song for initial values) - ; horizontal levels are always #$e0 (224 pixels or 28 tiles down), indoor/base are always #$e8 (232 or 29 tiles down) - ; waterfall level (vertical level) starts at #$00 and decrements as players move up screen (wrapping) -HORIZONTAL_SCROLL = $fd ; the horizontal scroll component of the PPUSCROLL, [#$00 - #$ff] -PPUMASK_SETTINGS = $fe ; used to store value of PPUMASK before writing to PPU -PPUCTRL_SETTINGS = $ff ; used to set PPUCTRL value for next frame - -SOUND_CMD_LENGTH = $0100 ; how many video frames the sound count should last for, i.e. the time to wait before reading next sound command - ; #$06 bytes, one for each sound slot -SOUND_CODE = $0106 ; the sound code for the sound slot, #$06 slots -SOUND_PULSE_LENGTH = $010c ; APU_PULSE_LENGTH, #$06 slots -SOUND_CMD_LOW_ADDR = $0112 ; low byte of address to current sound command in sound_xx data. #$06 slots, one per sound slot -SOUND_CMD_HIGH_ADDR = $0118 ; high byte of address to current sound command in sound_xx data. #$06 slots, one per sound slot -SOUND_VOL_ENV = $011e ; either an offset into pulse_volume_ptr_tbl (c.f. LVL_PULSE_VOL_INDEX) which specifies the volume for the frame - ; or a specific volume to use. When bit 7 is set, then the volume will auto decrescendo -SOUND_CURRENT_SLOT = $0120 ; the current sound slot [#$00-#$05] -PERCUSSION_INDEX_BACKUP = $0121 ; backup location for percussion_tbl index to restore after call to play_sound -INIT_SOUND_CODE = $0122 ; the sound code to load; sound codes greater than #$5a are dmc sounds -SOUND_CHNL_REG_OFFSET = $0123 ; sound channel configuration register offset, i.e. #$00 for first pulse channel, #$04 for second, #$08 for triangle, #$0c for noise -SOUND_FLAGS = $0124 ; sound channel flags - ; bit 0 - 0 = sound_xx command byte >= #$30 (read_low_sound_cmd), 1 = sound_xx command byte 0 < #$30 (read_high_sound_cmd) - ; bit 1 - 1 = DECRESCENDO_END_PAUSE has triggered and decrescendo can resume, 0 = keep volume constant - ; bit 2 - 0 = use lvl_config_pulse to set volume for frame, 1 = automatic decrescendo logic (handling DECRESCENDO_END_PAUSE) - ; bit 3 - used in sound_cmd_routine_03, signifies that a shared (child) sound command (sound_xx_part) is executing, specified by #$fd, or #$fe in sound command - ; used to know, after finishing parsing a sound command, whether or not to done or should return to parent sound command - ; bit 4 - slightly flatten note (see @flatten_note and @flip_flatten_note_adv) - ; bit 5 - 1 = PULSE_VOL_DURATION has counted down and decrescendo should be paused until DECRESCENDO_END_PAUSE - ; set to ignore SOUND_VOL_ENV negative check, i.e. override to decrescendo - ; bit 6 - mute flag (1 = muted, 0 = not muted) - ; bit 7 - sweep flag -LVL_PULSE_VOL_INDEX = $012a ; index into lvl_x_pulse_volume_xx to read -PULSE_VOL_DURATION = $012a ; the number of video frames to decrement the volume for, before stopping decrescendo and keeping final volume -PAUSE_STATE_01 = $012f ; whether or not the game is paused, used for sound logic -DECRESCENDO_END_PAUSE = $0130 ; number of video frames before end of sound command in which the decrescendo will resume - ; $0131 is for pulse channel 2 -SOUND_PITCH_ADJ = $0132 ; the amount added to the sound byte low nibble before loading the correct note_period_tbl values -UNKNOWN_SOUND_00 = $0136 ; amount to multiply to SOUND_CMD_LENGTH,x when calculating DECRESCENDO_END_PAUSE,x -UNKNOWN_SOUND_01 = $013c ; used to adjust volume amount when setting volume -SOUND_CFG_LOW = $0142 ; the value to merge with the high nibble before storing in apu channel config register -SOUND_TRIANGLE_CFG = $0144 ; in memory value for APU_TRIANGLE_CONFIG -SOUND_REPEAT_COUNT = $0148 ; used for #$fe sound commands to specify how many times to repeat a shared sound part, e.g. .byte $fe, $03, .addr sound_xx_part to loop 3 times. #$06 slots -SOUND_CFG_HIGH = $014e ; the value to merge with the volume when saving the pulse config -SOUND_LENGTH_MULTIPLIER = $0154 ; value used when determining how many video frames to wait before reading next sound command, #$06 bytes, one for each sound slot - ; ultimately used when calculating SOUND_CMD_LENGTH, and kept around between sound commands so subsequent notes can be the same length - ; for low sound codes, SOUND_LENGTH_MULTIPLIER is set to SOUND_CMD_LENGTH directly with no multiplication (see @high_nibble_not_1) -SOUND_PERIOD_ROTATE = $015a ; when not #$04, the number of times to shift the high byte of note_period_tbl into the low byte -PULSE_VOLUME = $0160 ; low nibble only, stores the volume for the pulse channels -NEW_SOUND_CODE_LOW_ADDR = $0166 ; sound command return location low byte once sound command specified in move_sound_code_read_addr executes, e.g. jungle boss siren -NEW_SOUND_CODE_HIGH_ADDR = $016c ; sound command return location high byte once sound command specified in move_sound_code_read_addr executes, e.g. jungle boss siren -SOUND_PULSE_PERIOD = $0172 ; APU_PULSE_PERIOD -VIBRATO_CTRL = $0178 ; vibrato control mode [#$00-#$03], #$80 = no vibrato - ; even values cause the note to stay the same, odd values cause vibrato #$03 = pitch up, #$01 = pitch down - ; $0178 is for sound slot #$00 and $0719 is for sound slot #$01 -SOUND_VOL_TIMER = $017a ; sound command counter; increments up to VIBRATO_DELAY, at which vibrato will be checked - ; only increments when VIBRATO_CTRL is non-negative, i.e. not #$80 -PULSE_NOTE = $017c ; the note that is sustained or has the vibrato applied to for pulse channels (in Contra only ever sustained no vibrato) - ; $017c is for sound slot #$00 and $071d is for sound slot #$01 -VIBRATO_DELAY = $017e ; used to delay start of vibrato until SOUND_VOL_TIMER has counted up to this value - ; if a note isn't as long as VIBRATO_DELAY, i.e. SOUND_CMD_LENGTH < VIBRATO_DELAY, then vibrato won't be considered for a note - ; $017e is for sound slot #$00 and $071f is for sound slot #$01 -VIBRATO_AMOUNT = $0180 ; the amount of vibrato to apply -LEVEL_END_DELAY_TIMER = $0190 ; a delay timer before beginning level end animation sequence -LEVEL_END_SQ_1_TIMER = $0191 ; a delay timer specifying the duration of end_level_sequence_01, decremented every other frame -LEVEL_END_LVL_ROUTINE_STATE = $0192 ; used by level end routines (end_of_lvl_routine_...) for managing animation state. - ; for example, indoor level end animations have 4 states: walk to elevator, initialize elevator sprite, ride elevator - ; $0193 is for player 2 -LEVEL_END_PLAYERS_ALIVE = $0194 ; the number of players alive at the end of the level, used to know if should play level end music -SOLDIER_GEN_SCREEN = $0195 ; the current screen that soldiers are being generated for -SCREEN_GEN_SOLDIERS = $0196 ; the total number of soldiers that have been generated for the current screen (exe_soldier_generation) -OAMDMA_CPU_BUFFER = $0200 ; $0200-$02ff OAMDMA (sprite) read data, read once per frame, populated by load_sprite_to_CPU_mem, draw_hud_sprites, or draw_player_hud_sprites - -CPU_SPRITE_BUFFER = $0300 ; sprites on screen, each byte is an entry into sprite_ptr_tbl [$0300-$0387], memory is segmented as defined below -PLAYER_SPRITES = $0300 ; player sprites, p1 and p2 sprite, then player bullets, each byte is an entry into sprite_ptr_tbl (#$0a bytes) -ENEMY_SPRITES = $030a ; enemy sprites to load on screen, each byte is an entry into sprite_ptr_tbl (#$0f bytes) -SPRITE_Y_POS = $031a ; y position on screen of each player sprite. First 2 bytes are for player sprites. Starts at #$00 for top increases downward (#$0a bytes) -ENEMY_Y_POS = $0324 ; y position on screen of each enemy sprite. Starts at #$00 for top increases downward (#$0f bytes) -SPRITE_X_POS = $0334 ; x position of screen of each player sprite. First 2 bytes are for player sprites (#$0a bytes) -ENEMY_X_POS = $033e ; x position on screen of each enemy sprite (#$0f bytes) -SPRITE_ATTR = $034e ; sprite attribute, specifies palette, vertical flip, horizontal flip (#$0a bytes) - ; and whether to adjust y position - ; bit 0 and 1 - sprite palette - ; bit 2 - 0 to use default palette as specified in sprite code - ; - 1 to use palette specified in bits 0 and 1 - ; bit 3 - whether to add #$01 to sprite y position, used for recoil effect firing weapon - ; bit 5 - bg priority - ; bit 6 - whether to flip the sprite horizontally - ; bit 7 - whether to flip the sprite vertically - ; bytes 0 and 1 are p1 and p2 sprite attributes, then each byte is the player bullet sprite attributes - ; examples: player being electrocuted or invincible (flashes various colors) -ENEMY_SPRITE_ATTR = $0358 ; enemy sprite attribute. See specification above (#$0f bytes) - -PLAYER_BULLET_SPRITE_CODE = $0368 ; The sprite codes to load for the bullet, eventually copied into CPU_SPRITE_BUFFER starting at offset 2 -PLAYER_BULLET_SPRITE_ATTR = $0378 ; The sprite attributes for the bullet (see SPRITE_ATTR for specification) - ; used for L bullets for flipping the angled sprites depending on direction -PLAYER_BULLET_SLOT = $0388 ; #$00 when no bullet, otherwise stores bullet type + 1, i.e. #$01 basic, #$02 M, #$03 F bullet, #$04 S, #$05 L, can be negative sometimes -PLAYER_BULLET_VEL_Y_ACCUM = $0398 ; an accumulator to keep track of PLAYER_BULLET_Y_VEL_FRACT being added to itself have elapsed before adding 1 to PLAYER_BULLET_Y_POS -PLAYER_BULLET_VEL_X_ACCUM = $03a8 ; an accumulator to keep track of PLAYER_BULLET_X_VEL_FRACT being added to itself have elapsed before adding 1 to PLAYER_BULLET_X_POS -PLAYER_BULLET_Y_POS = $03b8 ; the bullet's sprite y position -PLAYER_BULLET_X_POS = $03c8 ; the bullet's sprite x position - ; for F bullets, PLAYER_BULLET_FS_X and PLAYER_BULLET_X_POS together determine x position -PLAYER_BULLET_Y_VEL_FRACT = $03d8 ; percentage out of 0-255 set number of frames until Y position is incremented by an additional 1 unit -PLAYER_BULLET_X_VEL_FRACT = $03e8 ; percentage out of 0-255 set number of frames until X position is incremented by an additional 1 unit -PLAYER_BULLET_Y_VEL_FAST = $03f8 ; player bullet velocity y integer portion -PLAYER_BULLET_VEL_X_FAST = $0408 ; player bullet velocity x integer portion -PLAYER_BULLET_TIMER = $0418 ; 'timer' starts at #$00. Used by F, S (indoor only) and L - ; for indoor S, used to specify size of bullet - ; For F, used to set x and y pos when traveling to create swirl (see f_bullet_outdoor_x_swirl_amt_tbl, and f_bullet_outdoor_y_swirl_amt_tbl) - ; increments or decrements every frame depending on firing direction (left decrement, right increment) - ; For L used to spread out 4 lasers for one shot -PLAYER_BULLET_AIM_DIR = $0428 ; the direction of the bullet #$00 for up facing right, incrementing clockwise up to #09 for up facing left -PLAYER_BULLET_ROUTINE = $0438 ; #$00, #$01, or #$03, offset into player_bullet_routine_XX_(indoor_)ptr_tbl -PLAYER_BULLET_OWNER = $0448 ; #$00 player 1 bullet, #$01 player 2 bullet, each byte is for a bullet -PLAYER_BULLET_F_RAPID = $0458 ; #$01 for player indoor bullets for F weapon when rapid fire is enabled -PLAYER_BULLET_S_INDOOR_ADJ = $0458 ; (same address as previous) for indoor S bullets, specifies whether to adjust PLAYER_BULLET_X_POS by an additional -1 (#$ff) every frame (see s_bullet_pos_mod_tbl) -PLAYER_BULLET_DIST = $0468 ; represents how far a bullet has traveled - ; For S outdoor bullets, used to determine the size (scale) of the bullet - ; For F on indoor levels, used to determine spiraling position based on distance from player -PLAYER_BULLET_S_ADJ_ACCUM = $0468 ; (same address as previous) for indoor S weapons, stores accumulated fractional velocity where overflow affects PLAYER_BULLET_S_INDOOR_ADJ (see update_s_bullet_indoor_pos) -PLAYER_BULLET_FS_X = $0478 ; Used to offset from general x direction of bullet for swirl effect in F bullet and spread effect in S bullet (indoor) - ; Specifies center x position on screen f bullet swirls around. Used when firing f bullet either left, right, or at an angle -PLAYER_BULLET_F_Y = $0488 ; Specifies center y position on screen f bullet swirls around. Used when firing f bullet either up, down, or at an angle. -PLAYER_BULLET_S_RAPID = $0488 ; (same address as previous) for S weapon in indoor levels, specifies whether weapon is rapid fire or not, not sure why $09 wasn't used like other bullet routines -PLAYER_BULLET_VEL_FS_X_ACCUM = $0498 ; (for F weapon only) an accumulator to keep track of PLAYER_BULLET_X_VEL_FRACT being added to itself have elapsed before adding 1 to PLAYER_BULLET_X_POS -PLAYER_BULLET_VEL_F_Y_ACCUM = $04a8 ; (for F weapon only) an accumulator to keep track of PLAYER_BULLET_Y_VEL_FRACT being added to itself have elapsed before adding 1 to PLAYER_BULLET_Y_POS -PLAYER_BULLET_S_BULLET_NUM = $04a8 ; (same address as previous) for S weapon only, specifies the number the bullet in the current 'spray' for the shot - ; per shot of S weapon, #$05 bullets are generated. If no other bullets exist then - ; $04a8 would have #$00, $04a9 would have #$01, $04a9 would have #$02, etc. - -; each enemy property is #$10 bytes, one byte per enemy -ENEMY_ROUTINE = $04b8 ; enemy routine indexes starting at offset #$f ($04c7) going to #$0 ($04b8) - ; subtract 1 to get real routine, since all offsets are off by 1 (...routine_ptr_tbl -2) - ; ex: for exploding bridge, setting ENEMY_ROUTINE to #$02 causes exploding_bridge_routine_01 to run the next frame - -; the following 6 address ranges control the change in position of the enemy -; every frame the position is moved by VELOCITY_FAST units -; VELOCITY_FRACT can enable only moving by 1 unit every n frames -; for example, if ENEMY_Y_VELOCITY_FAST is #$00 and ENEMY_Y_VELOCITY_FRACT is #$c0, (#$c0/#$ff = 75%), -; then the enemy will move one position to the right 3 out of every 4 frames -ENEMY_Y_VEL_ACCUM = $04c8 ; an accumulator to keep track of ENEMY_Y_VELOCITY_FRACT being added to itself have elapsed before adding 1 to ENEMY_Y_POS -ENEMY_X_VEL_ACCUM = $04d8 ; an accumulator to keep track of ENEMY_X_VELOCITY_FRACT being added to itself have elapsed before adding 1 to ENEMY_X_POS -ENEMY_Y_VELOCITY_FAST = $04e8 ; the number of units to add to ENEMY_Y_POS every frame -ENEMY_Y_VELOCITY_FRACT = $04f8 ; percentage out of 0-255 of a unit to add, e.g. if #$80 (#$80/#$ff = 50%), then every other frame will cause Y pos to increment by 1 -ENEMY_X_VELOCITY_FAST = $0508 ; the number of units to add to ENEMY_X_POS every frame -ENEMY_X_VELOCITY_FRACT = $0518 ; percentage out of 0-255 of a unit to add, e.g. if #$80 (#$80/#$ff = 50%), then every other frame will cause X pos to increment by 1 - -ENEMY_TYPE = $0528 ; enemy type, e.g. #$03 = flying capsule -ENEMY_ANIMATION_DELAY = $0538 ; used for various delays by enemy logic -ENEMY_VAR_A = $0548 ; the sound code to play when enemy hit by player bullet, also used for other logic - ; dragon arm orb uses it for adjusting enemy position, fire beam uses it for animation delay -ENEMY_ATTACK_DELAY = $0558 ; the delay before an enemy attacks, for weapon items and grenades this is used for helping calculate falling arc trajectory instead of enemy delay -ENEMY_VAR_B = $0558 ; for weapon items and grenades this is used for helping calculate falling arc trajectory -ENEMY_FRAME = $0568 ; animation frame the enemy is in, typically indexes into an enemy type-specific table of sprite codes -ENEMY_SCORE_COLLISION = $0588 ; represents 3 things for an enemy - ; SSSS CCCC - score code (see `score_codes_tbl`), and collision type (entry in collision_box_codes_XX) - ; also explosion type -ENEMY_HP = $0578 ; the HP of the enemy -ENEMY_STATE_WIDTH = $0598 ; loaded from enemy_prop_ptr_tbl - ; bit 7 set to allow bullets to travel through enemy, e.g. weapon item - ; bit 6 specifies whether player can land on enemy (floating rock and moving cart), bit 4 also has to be 0 (see `beq @land_on_enemy`) - ; bit 4 and 5 specify the collision box type (see collision_box_codes_tbl) - ; bit 3 determines the explosion type (explosion_type_ptr_tbl), either explosion_type_00 or explosion_type_01 - ; bit 2 for bullets specifies whether to play sound on collision - ; bit 1 specifies whether to play explosion noise; also specifies width of enemy - ; bit 0 - #$00 test player-enemy collision, #$01 means to skip player-enemy collision test -ENEMY_ATTRIBUTES = $05a8 ; enemy type-specific attributes that define how an enemy behaves and/or looks -ENEMY_VAR_1 = $05b8 ; a byte available to each enemy for whatever they want to use it for (#$f bytes, 1 per enemy) -ENEMY_VAR_2 = $05c8 ; a byte available to each enemy for whatever they want to use it for (#$f bytes, 1 per enemy) -ENEMY_VAR_3 = $05d8 ; a byte available to each enemy for whatever they want to use it for (#$f bytes, 1 per enemy) -ENEMY_VAR_4 = $05e8 ; a byte available to each enemy for whatever they want to use it for (#$f bytes, 1 per enemy) -LEVEL_SCREEN_SUPERTILES = $0600 ; CPU memory address where super tiles indexes for the screens of the level are loaded (level_X_supertiles_screen_XX data) - ; 2 screens are stored in the CPU buffer. The second screen loaded at $0640. Indexes are into level_x_supertile_data - ; This data specifies the super-tiles (indexes) to load for the screens -BG_COLLISION_DATA = $0680 ; map of collision types for each of the super-tiles for both nametables, each 2 bits encode 1/4 of a super-tile's collision information - ; first 8 nibbles are a row of the top of super-tile, the next 8 are the middle middle. Not used on base (indoor) levels -CPU_GRAPHICS_BUFFER = $0700 ; used to store data that will be then moved to the PPU later on. $700 to $750, repeating structure - ; * byte $700 is multifaceted - ; * if $700 is #$0, then done writing graphics buffer to PPU - ; * if $700 is greater than #$0, then there is data to write, this byte is the offset into vram_address_increment - ; * both #$01, and #$03 signify VRAM address increment to 0, meaning to add #$1 every write to PPU (write across) - ; * #$02 signifies VRAM address increment is 1, meaning add #$20 (32 in decimal) every write to PPU (write down) - ; if GRAPHICS_BUFFER_MODE is #$ff - ; * byte $701 is length of the tiles being written per group - ; * byte $702 is the number of $701-sized blocks to write to the PPU - ; * for each block, the block prefixed with 2 bytes specifying PPU address (high byte, then low byte) - ; if GRAPHICS_BUFFER_MODE is #$00 - ; * if byte #$00 is #$00, then no drawing takes place for frame - ; * blocks of text/palette data prefixed with 2 bytes specifying PPU address (high byte, then low byte) - ; the block of text is ended with a #$ff, if the byte after #$ff is the vram_address_increment offset - ; then the the process continues, i.e. read #$02 PPU address bytes, read next text - -PALETTE_CPU_BUFFER = $07c0 ; [$07c0-$07df] the CPU memory address of the palettes eventually loaded into the PPU $3f00 to $3f1f - -HIGH_SCORE_LOW = $07e0 ; the low byte of the high score score -HIGH_SCORE_HIGH = $07e1 ; the high byte of the high score score -PLAYER_1_SCORE_LOW = $07e2 ; the low byte of player 1 high score -PLAYER_1_SCORE_HIGH = $07e3 ; the high byte of player 1 high score -PLAYER_2_SCORE_LOW = $07e4 ; the low byte of player 1 high score -PLAYER_2_SCORE_HIGH = $07e5 ; the high byte of player 1 high score -PREVIOUS_ROM_BANK = $07ec ; the previously-loaded PRG BANK ($8000-$bfff) -PREVIOUS_ROM_BANK_1 = $07ed ; the previously-loaded PRG BANK, but used only for load_bank_1 (from play_sound) ; PPU (picture processing unit) PPUCTRL = $2000 diff --git a/src/ines_header.asm b/src/ines_header.asm index 5bc8ffc..bd8688d 100644 --- a/src/ines_header.asm +++ b/src/ines_header.asm @@ -1,4 +1,4 @@ -; Contra US Disassembly - v1.2 +; Contra US Disassembly - v1.3 ; https://github.com/vermiceli/nes-contra-us .segment "HEADER" diff --git a/src/ram.asm b/src/ram.asm new file mode 100644 index 0000000..3be87eb --- /dev/null +++ b/src/ram.asm @@ -0,0 +1,1714 @@ +; Contra US Disassembly - v1.3 +; https://github.com/vermiceli/nes-contra-us +; ram.asm contains memory map used by the game. + +.segment "ZEROPAGE" + +.exportzp GAME_ROUTINE_INDEX ; $18 +.exportzp GAME_END_ROUTINE_INDEX ; $19 +.exportzp GAME_ROUTINE_INIT_FLAG ; $19 +.exportzp FRAME_COUNTER ; $1a +.exportzp NMI_CHECK ; $1b +.exportzp DEMO_MODE ; $1c +.exportzp PLAYER_MODE_1D ; $1d +.exportzp DEMO_LEVEL_END_FLAG ; $1f +.exportzp PPU_READY ; $20 +.exportzp GRAPHICS_BUFFER_OFFSET ; $21 +.exportzp PLAYER_MODE ; $22 +.exportzp GRAPHICS_BUFFER_MODE ; $23 +.exportzp KONAMI_CODE_STATUS ; $24 +.exportzp PAUSE_STATE ; $25 +.exportzp DEMO_LEVEL ; $27 +.exportzp INTRO_THEME_DELAY ; $28 +.exportzp GAME_OVER_DELAY_TIMER ; $29 +.exportzp DELAY_TIME_LOW_BYTE ; $2a +.exportzp DELAY_TIME_HIGH_BYTE ; $2b +.exportzp LEVEL_ROUTINE_INDEX ; $2c +.exportzp END_LEVEL_ROUTINE_INDEX ; $2d +.exportzp DEMO_FIRE_DELAY_TIMER ; $2e +.exportzp PLAYER_WEAPON_STRENGTH ; $2f +.exportzp CURRENT_LEVEL ; $30 +.exportzp GAME_COMPLETION_COUNT ; $31 +.exportzp P1_NUM_LIVES ; $32 +.exportzp P2_NUM_LIVES ; $33 +.exportzp RANDOM_NUM ; $34 +.exportzp NUM_PALETTES_TO_LOAD ; $36 +.exportzp INDOOR_SCREEN_CLEARED ; $37 +.exportzp P1_GAME_OVER_STATUS ; $38 +.exportzp P2_GAME_OVER_STATUS ; $39 +.exportzp NUM_CONTINUES ; $3a +.exportzp BOSS_DEFEATED_FLAG ; $3b +.exportzp EXTRA_LIFE_SCORE_LOW ; $3c +.exportzp EXTRA_LIFE_SCORE_HIGH ; $3d +.exportzp KONAMI_CODE_NUM_CORRECT ; $3f +.exportzp LEVEL_LOCATION_TYPE ; $40 +.exportzp LEVEL_SCROLLING_TYPE ; $41 +.exportzp LEVEL_SCREEN_SUPERTILES_PTR ; $42 +.exportzp LEVEL_SUPERTILE_DATA_PTR ; $44 +.exportzp LEVEL_SUPERTILE_PALETTE_DATA ; $46 +.exportzp LEVEL_ALT_GRAPHICS_POS ; $48 +.exportzp COLLISION_CODE_1_TILE_INDEX ; $49 +.exportzp COLLISION_CODE_0_TILE_INDEX ; $4a +.exportzp COLLISION_CODE_2_TILE_INDEX ; $4b +.exportzp LEVEL_PALETTE_CYCLE_INDEXES ; $4c +.exportzp LEVEL_PALETTE_INDEX ; $50 +.exportzp LEVEL_STOP_SCROLL ; $58 +.exportzp LEVEL_SOLID_BG_COLLISION_CHECK ; $59 +.exportzp DEMO_INPUT_NUM_FRAMES ; $5a +.exportzp DEMO_INPUT_VAL ; $5c +.exportzp DEMO_INPUT_TBL_INDEX ; $5e +.exportzp PPU_WRITE_TILE_OFFSET ; $60 +.exportzp LEVEL_TRANSITION_TIMER ; $61 +.exportzp PPU_WRITE_ADDRESS_LOW_BYTE ; $62 +.exportzp PPU_WRITE_ADDRESS_HIGH_BYTE ; $63 +.exportzp LEVEL_SCREEN_NUMBER ; $64 +.exportzp LEVEL_SCREEN_SCROLL_OFFSET ; $65 +.exportzp ATTRIBUTE_TBL_WRITE_LOW_BYTE ; $66 +.exportzp ATTRIBUTE_TBL_WRITE_HIGH_BYTE ; $67 +.exportzp FRAME_SCROLL ; $68 +.exportzp SUPERTILE_NAMETABLE_OFFSET ; $69 +.exportzp SPRITE_LOAD_TYPE ; $6a +.exportzp CONT_END_SELECTION ; $6b +.exportzp ALT_GRAPHIC_DATA_LOADING_FLAG ; $71 +.exportzp LEVEL_PALETTE_CYCLE ; $72 +.exportzp INDOOR_SCROLL ; $73 +.exportzp BG_PALETTE_ADJ_TIMER ; $74 +.exportzp AUTO_SCROLL_TIMER_00 ; $75 +.exportzp AUTO_SCROLL_TIMER_01 ; $76 +.exportzp TANK_AUTO_SCROLL ; $77 +.exportzp PAUSE_PALETTE_CYCLE ; $78 +.exportzp SOLDIER_GENERATION_ROUTINE ; $79 +.exportzp SOLDIER_GENERATION_TIMER ; $7a +.exportzp SOLDIER_GENERATION_X_POS ; $7b +.exportzp SOLDIER_GENERATION_Y_POS ; $7c +.exportzp FALCON_FLASH_TIMER ; $7d +.exportzp TANK_ICE_JOINT_SCROLL_FLAG ; $7f +.exportzp ENEMY_LEVEL_ROUTINES ; $80 +.exportzp ENEMY_SCREEN_READ_OFFSET ; $82 +.exportzp ENEMY_CURRENT_SLOT ; $83 +.exportzp BOSS_AUTO_SCROLL_COMPLETE ; $84 +.exportzp BOSS_SCREEN_ENEMIES_DESTROYED ; $85 +.exportzp WALL_CORE_REMAINING ; $86 +.exportzp WALL_PLATING_DESTROYED_COUNT ; $87 +.exportzp INDOOR_ENEMY_ATTACK_COUNT ; $88 +.exportzp INDOOR_RED_SOLDIER_CREATED ; $89 +.exportzp GRENADE_LAUNCHER_FLAG ; $8a +.exportzp ALIEN_FETUS_AIM_TIMER_INDEX ; $8b +.exportzp ENEMY_ATTACK_FLAG ; $8e +.exportzp PLAYER_STATE ; $90 +.exportzp INDOOR_TRANSITION_X_ACCUM ; $92 +.exportzp PLAYER_JUMP_COEFFICIENT ; $94 +.exportzp INDOOR_TRANSITION_X_FRACT_VEL ; $96 +.exportzp PLAYER_X_VELOCITY ; $98 +.exportzp INDOOR_TRANSITION_Y_FRACT_VEL ; $9a +.exportzp INDOOR_TRANSITION_Y_FAST_VEL ; $9c +.exportzp PLAYER_ANIM_FRAME_TIMER ; $9e +.exportzp PLAYER_JUMP_STATUS ; $a0 +.exportzp PLAYER_FRAME_SCROLL ; $a2 +.exportzp EDGE_FALL_CODE ; $a4 +.exportzp PLAYER_ANIMATION_FRAME_INDEX ; $a6 +.exportzp PLAYER_INDOOR_ANIM_Y ; $a8 +.exportzp P1_CURRENT_WEAPON ; $aa +.exportzp P2_CURRENT_WEAPON ; $ab +.exportzp PLAYER_M_WEAPON_FIRE_TIME ; $ac +.exportzp NEW_LIFE_INVINCIBILITY_TIMER ; $ae +.exportzp INVINCIBILITY_TIMER ; $b0 +.exportzp PLAYER_WATER_STATE ; $b2 +.exportzp PLAYER_DEATH_FLAG ; $b4 +.exportzp PLAYER_ON_ENEMY ; $b6 +.exportzp PLAYER_FALL_X_FREEZE ; $b8 +.exportzp PLAYER_HIDDEN ; $ba +.exportzp PLAYER_SPRITE_SEQUENCE ; $bc +.exportzp PLAYER_INDOOR_ANIM_X ; $be +.exportzp PLAYER_AIM_PREV_FRAME ; $c0 +.exportzp PLAYER_AIM_DIR ; $c2 +.exportzp PLAYER_Y_FRACT_VELOCITY ; $c4 +.exportzp PLAYER_Y_FAST_VELOCITY ; $c6 +.exportzp ELECTROCUTED_TIMER ; $c8 +.exportzp INDOOR_PLAYER_JUMP_FLAG ; $ca +.exportzp PLAYER_WATER_TIMER ; $cc +.exportzp PLAYER_RECOIL_TIMER ; $ce +.exportzp INDOOR_PLAYER_ADV_FLAG ; $d0 +.exportzp PLAYER_SPECIAL_SPRITE_TIMER ; $d2 +.exportzp PLAYER_FAST_X_VEL_BOOST ; $d4 +.exportzp PLAYER_SPRITE_CODE ; $d6 +.exportzp PLAYER_SPRITE_FLIP ; $d8 +.exportzp PLAYER_BG_FLAG_EDGE_DETECT ; $da +.exportzp PLAYER_GAME_OVER_BIT_FIELD ; $df +.exportzp SOUND_TABLE_PTR ; $ec +.exportzp CONTROLLER_STATE ; $f1 +.exportzp CONTROLLER_STATE_DIFF ; $f5 +.exportzp CTRL_KNOWN_GOOD ; $f9 +.exportzp VERTICAL_SCROLL ; $fc +.exportzp HORIZONTAL_SCROLL ; $fd +.exportzp PPUMASK_SETTINGS ; $fe +.exportzp PPUCTRL_SETTINGS ; $ff + +.res 24 + +; $18 - which part of the game routine to execute +; see game_routine_pointer_table +GAME_ROUTINE_INDEX: + .res 1 + +; $19 - GAME_END_ROUTINE_INDEX - used after beating the game to know which part +; of the ending sequence to execute for sequencing the animations, credits, +; restart, etc. (see game_end_routine_tbl) +; $19 - GAME_ROUTINE_INIT_FLAG - used to determine if the current game_routine +; has been initialized, used in game_routine_02 and game_routine_03 +GAME_END_ROUTINE_INDEX: +GAME_ROUTINE_INIT_FLAG: + .res 1 + +; $1a - the frame counter loops from #$00 to #$ff increments once per frame +; also known as the global timer +FRAME_COUNTER: + .res 1 + +; $1b - set to #$01 at start of nmi and #$00 at end +; used to track if nmi occurred during game loop +; bit 7 is set when inside play_sound, i.e. init_sound_code_vars +NMI_CHECK: + .res 1 + +; $1c - #$00 not in demo mode, #$01 demo mode on +DEMO_MODE: + .res 1 + +; $1d - #$01 for 1 player, #$07 for 2 player +; not sure why developer just didn't use PLAYER_MODE instead +PLAYER_MODE_1D: + .res 1 + +.res 1 + +; $1f - whether or not demo for level is complete and new demo level should play +DEMO_LEVEL_END_FLAG: + .res 1 + +; $20 - #$00 when at least 5 executions of nmi_start have happened since last +; configure_PPU call +PPU_READY: + .res 1 + +; $21 - current write offset into CPU_GRAPHICS_BUFFER +; contains graphics write commands that are written to PPU +GRAPHICS_BUFFER_OFFSET: + .res 1 + +; $22 - #$00 = single player, #$01 = 2 player +PLAYER_MODE: + .res 1 + +; $23 - defines the format of the CPU_GRAPHICS_BUFFER +; * #$ff is for super-tile data +; * #$00 is for text strings and palette data +GRAPHICS_BUFFER_MODE: + .res 1 + +; $24 - #$00 not entered, #$01 entered, (30 lives code) +KONAMI_CODE_STATUS: + .res 1 + +; $25 - #$00 when not paused, #$01 when paused +PAUSE_STATE: + .res 1 + +.res 1 + +; $27 - the current level when in DEMO mode +; only ever 0, 1 or 2 as those are the only levels demoed +DEMO_LEVEL: + .res 1 + +; $28 - timer to prevent starting a level until the intro theme is complete +; (including explosion sound) +; initialized to #a4, decrements every other frame for ~5 seconds for NTSC +INTRO_THEME_DELAY: + .res 1 + +; $29 - goes from #$60 to #$00, timer after dying before showing score +GAME_OVER_DELAY_TIMER: + .res 1 + +; $2a - the low byte of the delay +DELAY_TIME_LOW_BYTE: + .res 1 + +; $2b - the high byte of the delay +DELAY_TIME_HIGH_BYTE: + .res 1 + +; $2c - the index into level_routine_ptr_tbl of the routine to run +LEVEL_ROUTINE_INDEX: + .res 1 + +; $2d - offset into either end_level_sequence_ptr_tbl or +; end_game_sequence_ptr_tbl +END_LEVEL_ROUTINE_INDEX: + .res 1 + +; $2e - the number of frames since beginning of demo for level +; used to delay #$50 frames before firing +DEMO_FIRE_DELAY_TIMER: + .res 1 + +; $2f - the damage strength of the player's current weapon (see weapon_strength) +; based on bits 0-2 of P1_CURRENT_WEAPON,x +; Default = #$00, M = #$02, F = #$01, S = #$03, L = #$02 +PLAYER_WEAPON_STRENGTH: + .res 1 + +; $30 - #$00-#$09, #$00 to #$07 represent levels 1 through 8 +; #$09 is interpreted as game over sequence +CURRENT_LEVEL: + .res 1 + +; $31 - the number of times the game has been completed (final boss defeated) +GAME_COMPLETION_COUNT: + .res 1 + +; $32 -P1 number of lives, #$00 is last life, on game over stays #$00 +; but P1_GAME_OVER_STATUS becomes #$01 +P1_NUM_LIVES: + .res 1 + +; $33 - P2 number of lives, #$00 is last life, on game over stays #$00 +; but P2_GAME_OVER_STATUS becomes #$01 +P2_NUM_LIVES: + .res 1 + +; $34 - random number increased in forever_loop +RANDOM_NUM: + .res 1 + +; OAMDMA_CPU_BUFFER write offset +.res 1 + +; $36 - the number of palettes to load into CPU memory +NUM_PALETTES_TO_LOAD: + .res 1 + +; $37 - whether indoor screen has had all cores destroyed +; (0 = not cleared, 1 = cleared, #$80 = cleared and fence removed) +INDOOR_SCREEN_CLEARED: + .res 1 + +; $38 - #$00 not game over, #$01 game over +P1_GAME_OVER_STATUS: + .res 1 + +; $39 - #$00 not game over, #$01 game over or player 2 not playing +; (1 player game) +P2_GAME_OVER_STATUS: + .res 1 + +; $3a - the number of continues remaining +NUM_CONTINUES: + .res 1 + +; $3b - whether or not the level boss has been defeated (0 = no, 1 = yes) +; after value is set to 1, the end level sequence logic uses this value as well +; (using values #$81 and #$02) +BOSS_DEFEATED_FLAG: + .res 1 + +; $3c - the low byte of the score required for the next extra life +EXTRA_LIFE_SCORE_LOW: + .res 1 + +; $3d - the high byte of the score required for the next extra life +; $3e is the EXTRA_LIFE_SCORE_LOW for player 2 +EXTRA_LIFE_SCORE_HIGH: + .res 2 + +; $3f - the number of successful inputs of the Konami code sequence +; when value is #$0a then all input correctly inputted +; also used as player 2's EXTRA_LIFE_SCORE_HIGH byte during game play +KONAMI_CODE_NUM_CORRECT: + .res 1 + +; $40 - current level type +; * #$00 = outdoor +; * #$01 = indoor (base level) +; * #$80 on indoor/base boss screen and indoor/base when players advancing to +; next screen +LEVEL_LOCATION_TYPE: + .res 1 + +; $41 - current level scrolling type +; * #$00 = horizontal, and indoor/base level +; * #$01 = vertical +LEVEL_SCROLLING_TYPE: + .res 1 + +; $42 - stores 2-byte address to bank 2 containing which super-tiles to use for +; each screen of the level (level_x_supertiles_screen_ptr_table) +LEVEL_SCREEN_SUPERTILES_PTR: + .res 2 + +; $44 - current level 2-byte pointer to super-tile data, which defines pattern +; table tiles of the super-tiles that are used to make level blocks +LEVEL_SUPERTILE_DATA_PTR: + .res 2 + +; $46 - current level 2-byte pointer address to the palettes used for each +; super-tile, each byte describes the 4 palettes for a single super-tile +LEVEL_SUPERTILE_PALETTE_DATA: + .res 2 + +; $48 - how far into level (in number of screens) before loading alternate +; graphic data +LEVEL_ALT_GRAPHICS_POS: + .res 1 + +; $49 - pattern table tiles below this tile index (but not #$00) are considered +; Collision Code 1 (floor) +COLLISION_CODE_1_TILE_INDEX: + .res 1 + +; $4a - pattern table tiles >= $49 and less than this tile index are considered +; Collision Code 0 (empty) +COLLISION_CODE_0_TILE_INDEX: + .res 1 + +; $4b - pattern table tiles >= $4a and less than this tile index are considered +; Collision Code 2 (water) +COLLISION_CODE_2_TILE_INDEX: + .res 1 + +; $4c - palette indexes into game_palettes to cycle through for the level for +; the 4th nametable palette index [$4c-4f] +LEVEL_PALETTE_CYCLE_INDEXES: + .res 4 + +; $50 - the level's initial background palettes [$50 to $54) and sprite palettes +; [$54 to $58). Offsets into game_palettes table +LEVEL_PALETTE_INDEX: + .res 8 + +; $58 - the screen of the level to stop scrolling, set to #$ff when boss auto +; scroll starts +LEVEL_STOP_SCROLL: + .res 1 + +; $59 - used to determine whether to check for bullet and weapon item solid bg +; collisions +; 1. When non-zero, specifies weapon item should check for solid bg collisions +; (weapon_item_check_bg_collision) +; 2. When negative, used to let bullet (player and enemy) collision detection +; code to know to look for bullet-solid background collisions +; This is for levels 6 - energy zone and 7 - hangar. (see +; check_bullet_solid_bg_collision and enemy_bullet_routine_01) +LEVEL_SOLID_BG_COLLISION_CHECK: + .res 1 + +; $5a - used to determine how many even-numbered frames to continue pressing the +; button specified in $5c for demo +; $5b the DEMO_INPUT_NUM_FRAMES for player 2 +DEMO_INPUT_NUM_FRAMES: + .res 2 + +; $5c - the current controller input pressed during a demo +; $5d is DEMO_INPUT_VAL for player 2 +DEMO_INPUT_VAL: + .res 2 + +; $5e - when in demo, stores the offset into specific demo_input_tbl_lX_pX table +; $5f is for player 2 +DEMO_INPUT_TBL_INDEX: + .res 2 + +; $60 - the current write offset of the super-tile data, number of tiles outside +; the current view. +; * horizontal levels loops #$00 to #$1f +; * vert starts with #$1d goes down to #$00 before looping +PPU_WRITE_TILE_OFFSET: + .res 1 + +; $61 - used in vertical levels to time animation between sections for every +; 'up' input +; used in indoor levels between screens to animate moving forward +LEVEL_TRANSITION_TIMER: + .res 1 + +; $62 - used to populate the PPU write address in the CPU_GRAPHICS_BUFFER +PPU_WRITE_ADDRESS_LOW_BYTE: + .res 1 + +; $63 - used to populate the PPU write address in the CPU_GRAPHICS_BUFFER +PPU_WRITE_ADDRESS_HIGH_BYTE: + .res 1 + +; $64 - the screen number of the current level (how many screens into the level) +LEVEL_SCREEN_NUMBER: + .res 1 + +; $65 - the number of pixels into LEVEL_SCREEN_NUMBER the level has scrolled. +; Goes from #$00-#$ff for each screen (256 pixels) +; for horizontal levels, this is how many pixels scrolled to the right +; for vertical levels, this is how many pixels up scrolled, note this value is +; equal to #$f0 - VERTICAL_SCROLL +; for indoor levels, after defeating a wall, increases from #$00 to #03 +LEVEL_SCREEN_SCROLL_OFFSET: + .res 1 + +; $66 - the low byte of the attribute table write address to write to +; (always #$c0, never read) +ATTRIBUTE_TBL_WRITE_LOW_BYTE: + .res 1 + +; $67 - the high byte of the attribute table write address to write to +ATTRIBUTE_TBL_WRITE_HIGH_BYTE: + .res 1 + +; $68 - how much to scroll the screen this frame based on player velocity +; (usually #$00 or #$01) +; for vertical levels, up to #$04 +; note that this is not the scroll distance within the screen +FRAME_SCROLL: + .res 1 + +; $69 - base nametable offset into memory address into CPU graphics buffer +; starting at $0600 (LEVEL_SCREEN_SUPERTILES) +; always either #$00 (nametable 0) or #$40 (nametable 1) +; points to area that contains the super-tile indexes for screen +SUPERTILE_NAMETABLE_OFFSET: + .res 1 + +; $6a - which sprites to load #$00 for normal sprites, #$01 for HUD sprites +SPRITE_LOAD_TYPE: + .res 1 + +; $6b - #$00 when "CONTINUE" is selected, #$01 when "END" is selected +; used only in game over screen (level_routine_06) +CONT_END_SELECTION: + .res 1 + +.res 5 + +; $71 - #$00 means that the alternate graphics data should not be loaded +; #$01 means it should be #$02 means it currently is being loaded +ALT_GRAPHIC_DATA_LOADING_FLAG: + .res 1 + +; $72 - the current iteration of the palette animation loop #$00 up to entry for +; level in lvl_palette_animation_count +LEVEL_PALETTE_CYCLE: + .res 1 + +; $73 - scrolling on indoor level changes +; * #$00 = not scrolling +; * #$01 = scrolling +; * #$02 = finished scrolling +INDOOR_SCROLL: + .res 1 + +; $74 - timer used for adjusting background palette colors (not sprite palettes) +; Used for fade-in effect of dragon and boss ufo as well as indoor transitions +BG_PALETTE_ADJ_TIMER: + .res 1 + +; $75 - used when completing scroll to show a boss +; e.g. vertical level dragon screen +AUTO_SCROLL_TIMER_00: + .res 1 + +; $76 - used when completing scroll to show a boss, e.g. alien guardian +AUTO_SCROLL_TIMER_01: + .res 1 + +; $77 - amount to scroll every frame, regardless of AUTO_SCROLL_TIMER_xx +; used for snow field tanks (dogras), breaks levels if used on other levels +TANK_AUTO_SCROLL: + .res 1 + +; $78 +; * #$00 - nametable palettes #$03 and #$04 will cycle colors like normal +; * Non-zero values will pause palette color cycling (ice field tank pauses +; palette cycle) +PAUSE_PALETTE_CYCLE: + .res 1 + +; $79 - which routine is currently in use for generating soldiers +; (index into soldier_generation_ptr_tbl) +SOLDIER_GENERATION_ROUTINE: + .res 1 + +; $7a - a timer between soldier generation. #$00 means no generation +; see level_soldier_generation_timer. +; When used in a level, every frame decrements by 2 +; (unless scrolling, then only by 1) +SOLDIER_GENERATION_TIMER: + .res 1 + +; $7b - the initial x position of the generated soldier +SOLDIER_GENERATION_X_POS: + .res 1 + +; $7c - the initial y position of the generated soldier +SOLDIER_GENERATION_Y_POS: + .res 1 + +; $7d - the number of frames to flash the screen for falcon weapon item +FALCON_FLASH_TIMER: + .res 1 + +.res 1 + +; $7f - whether to have ice joint enemy move left while player walks right +; to simulate being on the background +TANK_ICE_JOINT_SCROLL_FLAG: + .res 1 + +; $80 - two byte address to enemy_routine_level_XX for the current level +; used to retrieve enemy routines for the level-specific enemies +ENEMY_LEVEL_ROUTINES: + .res 2 + +; $82 - read offset into level_xx_enemy_screen_xx table +; which specifies the enemies on each screen of a level +ENEMY_SCREEN_READ_OFFSET: + .res 1 + +; $83 - when in use, specifies the current enemy slot that is being executed +; used to be able to restore x register after method has used it +ENEMY_CURRENT_SLOT: + .res 1 + +; $84 - set when boss reveal auto-scrolling has completed +; see AUTO_SCROLL_TIMER_00 and AUTO_SCROLL_TIMER_01 +BOSS_AUTO_SCROLL_COMPLETE: + .res 1 + +; $85 - used on level 3 and level 7 boss screens to keep track of how many +; dragon arm orbs or mortar launchers have been destroyed respectively +BOSS_SCREEN_ENEMIES_DESTROYED: + .res 1 + +; $86 - remaining wall cores/wall platings to destroy until can advance screen +; For level 4 boss, used to count remaining boss gemini +WALL_CORE_REMAINING: + .res 1 + +; $87 - used in indoor/base boss levels to keep track of how many wall platings +; (ENEMY_TYPE #$0a) have been destroyed +WALL_PLATING_DESTROYED_COUNT: + .res 1 + +; $88 - used in indoor/base levels to specify how many 'rounds' of attack have +; happened per screen, max #$07 before certain enemies no longer generate +; indoor soldiers, jumping soldiers, indoor rollers, and wall core use this +INDOOR_ENEMY_ATTACK_COUNT: + .res 1 + +; $89 - used in indoor/base levels to indicate if a red jumping soldier has been +; created to prevent creation of another +INDOOR_RED_SOLDIER_CREATED: + .res 1 + +; $8a - used in indoor/base levels to indicate that a grenade launcher enemy +; (ENEMY_TYPE #$17) is on the screen +; Prevents other indoor enemies from being generated +GRENADE_LAUNCHER_FLAG: + .res 1 + +; $8b - used to keep track of the index into alien_fetus_aim_timer_tbl to set +; the delay between re-aiming towards the player +ALIEN_FETUS_AIM_TIMER_INDEX: + .res 1 + +.res 2 + +; $8e - whether or not enemies will fire at player, also whether or not random +; enemies are generated, bosses ignore this value +ENEMY_ATTACK_FLAG: + .res 1 + +.res 1 + +; $90 +; * #$00 falling into level (only run once to init fall) +; * #$01 normal state +; * #$02 when dead +; * #$03 can't move +; $91 is for p2, if p2 not playing, set to #$00 +PLAYER_STATE: + .res 2 + +; $92 - a variable to store INDOOR_TRANSITION_X_FRACT_VEL being added to itself +; to account for overflow before adding to player x velocity when moving between +; screens on indoor/base levels +; $93 is for p2 +INDOOR_TRANSITION_X_ACCUM: + .res 2 + +; $94 - related to jump height (used by speed runners to jump higher) +; * https://www.youtube.com/watch?v=K7MjxHvWof8 +; * https://www.youtube.com/watch?v=yrnW9yQXa9I +; used to keep track of fractional y velocity on vertical levels for overflowing +; fractional velocity +; Notably, this value isn't cleared between jumps +; also used when walking into screen for indoor screen changes to keep track of +; overflow of animation y fractional velocity +; $95 is for player 2 +PLAYER_JUMP_COEFFICIENT: + .res 2 + +; $96 - indoor animation transition when walking into screen x fractional +; velocity +; $97 is for player 2 +INDOOR_TRANSITION_X_FRACT_VEL: + .res 2 + +; $98 - the player's fast x velocity (#$00, #$01, or #$ff) +; $99 is for p2 +PLAYER_X_VELOCITY: + .res 2 + +; $9a - indoor animation transition when walking into screen y fractional +; velocity +; $9b is for player 2 +INDOOR_TRANSITION_Y_FRACT_VEL: + .res 2 + +; $9c - indoor animation transition when walking into screen y fast velocity +; $9d is for player 2 +INDOOR_TRANSITION_Y_FAST_VEL: + .res 2 + +; $9e - value that is incremented every frame when player is walking +; used to wait #$08 frames before incrementing PLAYER_ANIMATION_FRAME_INDEX for +; animating player walking +; $9f is for player 2 +PLAYER_ANIM_FRAME_TIMER: + .res 2 + +; $a0 - the status of the player jump (facing direction) +; similar to EDGE_FALL_CODE +; high nibble is for facing direction +; bit 7 - set when jumping left +; low nibble is #$01 when jumping, #$00 when not +; $a1 is for player 2 +PLAYER_JUMP_STATUS: + .res 2 + +; $a2 - how much player 1 is causing the frame to scroll by, see FRAME_SCROLL +; $a3 is for player 2, larger of the 2 is set to FRAME_SCROLL +PLAYER_FRAME_SCROLL: + .res 2 + +; $a4 - similar to PLAYER_JUMP_STATUS. Used to start gravity pulling player down +; if bit 7 set, then falling through platform +; if bit 6 is set, then walking left off edge +; if bit 5 is set, then walking right off ledge +; can change if change direction during fall +; bit 0 always set when EDGE_FALL_CODE non-zero +; $a5 is for player 2 +EDGE_FALL_CODE: + .res 2 + +; $a6 - which frame of the player animation. Depends on player state. +; For example, if player is running, this cycles from #$00 to #$05 +; $a7 is for player 2 +PLAYER_ANIMATION_FRAME_INDEX: + .res 2 + +; $a8 - the y position the player was at when they started walking into screen +; after clearing an indoor level. +; I believe it's always #$a8 since y pos is hard-coded for indoor levels +; $a9 is player 2 +PLAYER_INDOOR_ANIM_Y: + .res 2 + +; $aa - P1 current weapon and rapid fire flag (commonly abbreviated MFSL) +; low nibble is weapon +; when high nibble is 1 rapid fire enabled; +; * #$00 - Regular +; * #$01 - Machine Gun +; * #$02 - Flame Thrower +; * #$03 - Spray +; * #$04 - Laser +; bit 4 set for rapid fire +P1_CURRENT_WEAPON: + .res 1 + +; $ab - P2 current weapon and rapid fire flag (commonly abbreviated MFSL) +; low nibble is weapon +; when high nibble is 1 rapid fire enabled; +; * #$00 - Regular +; * #$01 - Machine Gun +; * #$02 - Flame Thrower +; * #$03 - Spray +; * #$04 - Laser +; bit 4 set for rapid fire +P2_CURRENT_WEAPON: + .res 1 + +; $ac - used when holding down the B button with the m weapon +; high nibble is number of bullets generated (up to #$06) +; low nibble is counter before next bullet is generated (up to #$07) +; $ad is for player 2 +PLAYER_M_WEAPON_FIRE_TIME: + .res 2 + +; $ae - timer for invincibility after dying +; $af is for player 2 +NEW_LIFE_INVINCIBILITY_TIMER: + .res 2 + +; $b0 - timer for player invincibility (b (barrier) weapon) +; (decreases every 8 frames) +; usually set to #$80 except level 7 when set to #$90 +; $b1 is for player 2 +INVINCIBILITY_TIMER: + .res 2 + +; $b2 - bit 1 - horizontal sprite flip flag +; bit 2 - set when player in water, or exiting water +; bit 3 - player is walking out of water +; bit 4 - finished initialization for entering water +; bit 7 - player is walking out of water +; $b3 is for player 2 +PLAYER_WATER_STATE: + .res 2 + +; $b4 +; * bit 0 specifies whether player has died +; * bit 1 specifies player was facing left when hit, used so player dies lying +; in appropriate direction +; $b5 is for player 2 +PLAYER_DEATH_FLAG: + .res 2 + +; $b6 - whether or not the player is on top of another enemy +; set for #$14 - mining cart, #$15 - stationary mining cart, and #$10 - floating +; rock platform) +; $b7 is for player 2 +PLAYER_ON_ENEMY: + .res 2 + +; $b8 - used to prevent changing X velocity shortly after walking off/falling +; through ledge, set to Y post of ledge + #$14 +; $b9 is for player 2 +PLAYER_FALL_X_FREEZE: + .res 2 + +; $ba - #$00 player visible, #$01/#$ff player invisible (any non-zero). +; I believe it is meant to track distance off screen the player is +; $bb is for player 2 +PLAYER_HIDDEN: + .res 2 + +; $bc - which animation to show for the player +; * outdoor +; * #$00 standing (no animation) +; * #$01 gun pointing up +; * #$02 crouching +; * #$03 walking or curled jump animation +; * #$04 dead animation +; * indoor - (see indoor_player_sprite_tbl) +; * #$00 standing facing back wall +; * #$01 electrocuted +; * #$02 crouching +; * #$03 walking left/right animation +; * #$05 walking into screen (advancing) +; * #$06 dead animation +; $bd is for player 2 +PLAYER_SPRITE_SEQUENCE: + .res 2 + +; $be - the x position the player was at when they started walking into screen +; after clearing an indoor level +; $bf is player 2 +PLAYER_INDOOR_ANIM_X: + .res 2 + +; $c0 - backup of PLAYER_AIM_DIR +; $c1 is for player 2 +PLAYER_AIM_PREV_FRAME: + .res 2 + +; $c2 - which direction the player is aiming [#$00-#$0a] depends on level and +; jump status (00 up facing right, 1 up-right, 2 right, 3 right-down, +; 4 crouching facing right, 5 crouching facing left, etc) +; there are #$02 up and #$02 down values depending on facing direction +; $c3 is for player 2 +PLAYER_AIM_DIR: + .res 2 + +; $c4 - the fractional portion of the player's y velocity +; $c5 is for player 2 +PLAYER_Y_FRACT_VELOCITY: + .res 2 + +; $c6 - the integer portion of the player's y velocity +; positive pulls down, negative pulls up +; $c7 is for player 2 +PLAYER_Y_FAST_VELOCITY: + .res 2 + +; $c8 - timer for player being electrocuted +; used to freeze player after touching electricity +; $c9 is for player 2 +ELECTROCUTED_TIMER: + .res 2 + +; $ca - used when entering new screen to cause the player to jump +; $cb is player 2 +INDOOR_PLAYER_JUMP_FLAG: + .res 2 + +; $cc - timer used for getting into and out of water +; $cd is for player 2 +PLAYER_WATER_TIMER: + .res 2 + +; $ce - how many frames to be pushed back/down from recoil +; $cf is for player 2 +PLAYER_RECOIL_TIMER: + .res 2 + +; $d0 - whether or not the player is walking into screen when advancing between +; screens on indoor levels, used for animating player +; $d1 is for player 2 +INDOOR_PLAYER_ADV_FLAG: + .res 2 + +; $d2 - used to track animation for player death animation +; outdoor is a timer that increments once player hit +; every #$08 frames updates to next animation frame until #$04 +; also used to track jumping curl animation (loops from #$00-#$04) +; $d3 is for player 2 +PLAYER_SPECIAL_SPRITE_TIMER: + .res 2 + +; $d4 - the x fast velocity boost from landing on a non-dangerous enemy +; e.g. moving cart or floating rock in vertical level +; $d5 is for player 2 +PLAYER_FAST_X_VEL_BOOST: + .res 2 + +; $d6 - sprite code of the player +; $d7 is for player 2 +PLAYER_SPRITE_CODE: + .res 2 + +; $d8 - stores player sprite horizontal (bit 6) and vertical (bit 7) flip flags +; before saving into SPRITE_ATTR +; bit 3 specifies whether the PLAYER_ANIMATION_FRAME_INDEX is even or odd +; (see @check_anim_frame_and_collision) +; $d9 is for player 2 +PLAYER_SPRITE_FLIP: + .res 2 + +; $da - bit 7 specifies the player's sprite attribute for background priority, +; allows player to walk behind opaque background (OAM byte 2 bit 5) +; 0 (clear) sprite in foreground, 1 (set) sprite is background +; bit 0 allows the player to keep walking horizontally off a ledge without +; falling +; $db is for player 2 +PLAYER_BG_FLAG_EDGE_DETECT: + .res 2 + +.res 3 + +; $df - combination of both players game over status +; * #$00 = p1 not game over, p2 game over (or not playing) +; * #$01 = p1 game over, p2 not game over +; * #$02 = p1 nor p2 are in game over +PLAYER_GAME_OVER_BIT_FIELD: + .res 1 + +.res 12 + +; $ec - low byte of address pointing of index into sound_table_00 +; offset INIT_SOUND_CODE +SOUND_TABLE_PTR: + .res 1 + +.res 4 + +; $f1 - stores the currently-pressed buttons for player 1 +; bit 7 - A, bit 6 - B, bit 5 - select, bit 4 - start +; bit 3 - up, bit 2 - down, bit 1 - left, bit 0 - right +; $f2 stores the currently-pressed buttons for player 2 +CONTROLLER_STATE: + .res 2 + +; $f3 +.res 2 + +; $f5 - stores the difference between the controller input between reads +; useful for events that should only trigger on first button press +; $f6 is for player 2 +CONTROLLER_STATE_DIFF: + .res 2 + +.res 2 + +; $f9 - used in input-reading code to know the last known valid read of +; controller input (similar to CONTROLLER_STATE) +; $fa is for player 2 +CTRL_KNOWN_GOOD: + .res 2 + +; unused +.res 1 + +; $fc - the number of pixels to vertically scroll down +; (y component of PPUSCROLL) (see level_vert_scroll_and_song for initial values) +; horizontal levels are always #$e0 (224 pixels or 28 tiles down) +; indoor/base are always #$e8 (232 or 29 tiles down) +; waterfall level (vertical level) starts at #$00 and decrements as players move +; up screen (wrapping) +VERTICAL_SCROLL: + .res 1 + +; $fd - the horizontal scroll component of the PPUSCROLL, [#$00 - #$ff] +HORIZONTAL_SCROLL: + .res 1 + +; $fe - used to store value of PPUMASK before writing to PPU +PPUMASK_SETTINGS: + .res 1 + +; $ff - used to set PPUCTRL value for next frame +PPUCTRL_SETTINGS: + .res 1 + +.segment "RAM" + +.export SOUND_CMD_LENGTH ; $0100 +.export SOUND_CODE ; $0106 +.export SOUND_PULSE_LENGTH ; $010c +.export SOUND_CMD_LOW_ADDR ; $0112 +.export SOUND_CMD_HIGH_ADDR ; $0118 +.export SOUND_VOL_ENV ; $011e +.export SOUND_CURRENT_SLOT ; $0120 +.export PERCUSSION_INDEX_BACKUP ; $0121 +.export INIT_SOUND_CODE ; $0122 +.export SOUND_CHNL_REG_OFFSET ; $0123 +.export SOUND_FLAGS ; $0124 +.export LVL_PULSE_VOL_INDEX ; $012a +.export PULSE_VOL_DURATION ; $012a +.export PAUSE_STATE_01 ; $012f +.export DECRESCENDO_END_PAUSE ; $0131 +.export SOUND_PITCH_ADJ ; $0132 +.export UNKNOWN_SOUND_00 ; $0136 +.export UNKNOWN_SOUND_01 ; $013c +.export SOUND_CFG_LOW ; $0142 +.export SOUND_TRIANGLE_CFG ; $0144 +.export SOUND_REPEAT_COUNT ; $0148 +.export SOUND_CFG_HIGH ; $014e +.export SOUND_LENGTH_MULTIPLIER ; $0154 +.export SOUND_PERIOD_ROTATE ; $015a +.export PULSE_VOLUME ; $0160 +.export NEW_SOUND_CODE_LOW_ADDR ; $0166 +.export NEW_SOUND_CODE_HIGH_ADDR ; $016c +.export SOUND_PULSE_PERIOD ; $0172 +.export VIBRATO_CTRL ; $0178 +.export SOUND_VOL_TIMER ; $017a +.export PULSE_NOTE ; $017c +.export VIBRATO_DELAY ; $017e +.export VIBRATO_AMOUNT ; $0180 +.export LEVEL_END_DELAY_TIMER ; $0190 +.export LEVEL_END_SQ_1_TIMER ; $0191 +.export LEVEL_END_LVL_ROUTINE_STATE ; $0193 +.export LEVEL_END_PLAYERS_ALIVE ; $0194 +.export SOLDIER_GEN_SCREEN ; $0195 +.export SCREEN_GEN_SOLDIERS ; $0196 +.export OAMDMA_CPU_BUFFER ; $0200 +.export CPU_SPRITE_BUFFER ; $0300 +.export PLAYER_SPRITES ; $0300 +.export ENEMY_SPRITES ; $030a +.export SPRITE_Y_POS ; $031a +.export ENEMY_Y_POS ; $0324 +.export SPRITE_X_POS ; $0334 +.export ENEMY_X_POS ; $033e +.export SPRITE_ATTR ; $034e +.export ENEMY_SPRITE_ATTR ; $0358 +.export PLAYER_BULLET_SPRITE_CODE ; $0368 +.export PLAYER_BULLET_SPRITE_ATTR ; $0378 +.export PLAYER_BULLET_SLOT ; $0388 +.export PLAYER_BULLET_Y_VEL_ACCUM ; $0398 +.export PLAYER_BULLET_X_VEL_ACCUM ; $03a8 +.export PLAYER_BULLET_Y_POS ; $03b8 +.export PLAYER_BULLET_X_POS ; $03c8 +.export PLAYER_BULLET_Y_VEL_FRACT ; $03d8 +.export PLAYER_BULLET_X_VEL_FRACT ; $03e8 +.export PLAYER_BULLET_Y_VEL_FAST ; $03f8 +.export PLAYER_BULLET_X_VEL_FAST ; $0408 +.export PLAYER_BULLET_TIMER ; $0418 +.export PLAYER_BULLET_AIM_DIR ; $0428 +.export PLAYER_BULLET_ROUTINE ; $0438 +.export PLAYER_BULLET_OWNER ; $0448 +.export PLAYER_BULLET_F_RAPID ; $0458 +.export PLAYER_BULLET_S_INDOOR_ADJ ; $0458 +.export PLAYER_BULLET_DIST ; $0468 +.export PLAYER_BULLET_S_ADJ_ACCUM ; $0468 +.export PLAYER_BULLET_FS_X ; $0478 +.export PLAYER_BULLET_F_Y ; $0488 +.export PLAYER_BULLET_S_RAPID ; $0488 +.export PLAYER_BULLET_VEL_FS_X_ACCUM ; $0498 +.export PLAYER_BULLET_VEL_F_Y_ACCUM ; $04a8 +.export PLAYER_BULLET_S_BULLET_NUM ; $04a8 +.export ENEMY_ROUTINE ; $04b8 +.export ENEMY_Y_VEL_ACCUM ; $04c8 +.export ENEMY_X_VEL_ACCUM ; $04d8 +.export ENEMY_Y_VELOCITY_FAST ; $04e8 +.export ENEMY_Y_VELOCITY_FRACT ; $04f8 +.export ENEMY_X_VELOCITY_FAST ; $0508 +.export ENEMY_X_VELOCITY_FRACT ; $0518 +.export ENEMY_TYPE ; $0528 +.export ENEMY_ANIMATION_DELAY ; $0538 +.export ENEMY_VAR_A ; $0548 +.export ENEMY_ATTACK_DELAY ; $0558 +.export ENEMY_VAR_B ; $0558 +.export ENEMY_FRAME ; $0568 +.export ENEMY_HP ; $0578 +.export ENEMY_SCORE_COLLISION ; $0588 +.export ENEMY_STATE_WIDTH ; $0598 +.export ENEMY_ATTRIBUTES ; $05a8 +.export ENEMY_VAR_1 ; $05b8 +.export ENEMY_VAR_2 ; $05c8 +.export ENEMY_VAR_3 ; $05d8 +.export ENEMY_VAR_4 ; $05e8 +.export LEVEL_SCREEN_SUPERTILES ; $0600 +.export BG_COLLISION_DATA ; $0680 +.export CPU_GRAPHICS_BUFFER ; $0700 +.export PALETTE_CPU_BUFFER ; $07c0 +.export HIGH_SCORE_LOW ; $07e0 +.export HIGH_SCORE_HIGH ; $07e1 +.export PLAYER_1_SCORE_LOW ; $07e2 +.export PLAYER_1_SCORE_HIGH ; $07e3 +.export PLAYER_2_SCORE_LOW ; $07e4 +.export PLAYER_2_SCORE_HIGH ; $07e5 +.export PREVIOUS_ROM_BANK ; $07ec +.export PREVIOUS_ROM_BANK_1 ; $07ed + +; $0100 - how many video frames the sound count should last for +; i.e. the time to wait before reading next sound command +; #$06 bytes, one for each sound slot +SOUND_CMD_LENGTH: + .res 6 + +; $0106 - the sound code for the sound slot, #$06 slots +SOUND_CODE: + .res 6 + +; $010c - APU_PULSE_LENGTH, #$06 slots +SOUND_PULSE_LENGTH: + .res 6 + +; $0112 - low byte of address to current sound command in sound_xx data +; #$06 slots, one per sound slot +SOUND_CMD_LOW_ADDR: + .res 6 + +; $0118 - high byte of address to current sound command in sound_xx data +; #$06 slots, one per sound slot +SOUND_CMD_HIGH_ADDR: + .res 6 + +; $011e - either an offset into pulse_volume_ptr_tbl (see LVL_PULSE_VOL_INDEX) +; which specifies the volume for the frame or a specific volume to use. +; When bit 7 is set, then the volume will auto decrescendo +SOUND_VOL_ENV: + .res 2 + +; $0120 - the current sound slot [#$00-#$05] +SOUND_CURRENT_SLOT: + .res 1 + +; $0121 - backup for percussion_tbl index to restore after call to play_sound +PERCUSSION_INDEX_BACKUP: + .res 1 + +; $0122 - the sound code to load; sound codes greater than #$5a are dmc sounds +INIT_SOUND_CODE: + .res 1 + +; $0123 - sound channel configuration register offset +; * #$00 for first pulse channel +; * #$04 for second +; * #$08 for triangle +; * #$0c for noise +SOUND_CHNL_REG_OFFSET: + .res 1 + +; $0124 - sound channel flags +; * bit 0 +; * 0 = sound_xx command byte >= #$30 (read_low_sound_cmd) +; * 1 = sound_xx command byte 0 < #$30 (read_high_sound_cmd) +; * bit 1 +; * 1 = DECRESCENDO_END_PAUSE has triggered and decrescendo can resume +; * 0 = keep volume constant +; * bit 2 +; * 0 = use lvl_config_pulse to set volume for frame +; * 1 = automatic decrescendo logic (handling DECRESCENDO_END_PAUSE) +; * bit 3 - used in sound_cmd_routine_03, signifies that a shared (child) sound +; command (sound_xx_part) is executing, specified by #$fd, or #$fe in sound +; command +; * used to know, after finishing parsing a sound command, whether or not +; complete or should return to parent sound command +; * bit 4 - slightly flatten note (see @flatten_note and @flip_flatten_note_adv) +; * bit 5 +; * 1 = PULSE_VOL_DURATION has counted down and decrescendo should bepaused +; until DECRESCENDO_END_PAUSE. Set to ignore SOUND_VOL_ENV negative check, +; i.e. override to decrescendo +; * bit 6 - mute flag (1 = muted, 0 = not muted) +; * bit 7 - sweep flag +SOUND_FLAGS: + .res 6 + +; $012a - LVL_PULSE_VOL_INDEX - index into lvl_x_pulse_volume_xx to read +; $012a - PULSE_VOL_DURATION - the number of video frames to decrement the volume +; for, before stopping decrescendo and keeping final volume +LVL_PULSE_VOL_INDEX: +PULSE_VOL_DURATION: + .res 5 + +; $012f - whether or not the game is paused, used for sound logic +PAUSE_STATE_01: + .res 1 + +; $0130 - number of video frames before end of sound command in which the +; decrescendo will resume +; $0131 is for pulse channel 2 +DECRESCENDO_END_PAUSE: + .res 2 + +; $0132 - the amount added to the sound byte low nibble before loading the +; correct note_period_tbl values +SOUND_PITCH_ADJ: + .res 4 + +; $0136 - amount to multiply to SOUND_CMD_LENGTH,x when calculating +; DECRESCENDO_END_PAUSE,x +UNKNOWN_SOUND_00: + .res 6 + +; $013c - used to adjust volume amount when setting volume +UNKNOWN_SOUND_01: + .res 6 + +; $0142 - the value to merge with the high nibble before storing in apu channel +; config register +SOUND_CFG_LOW: + .res 2 + +; $0144 - in memory value for APU_TRIANGLE_CONFIG +SOUND_TRIANGLE_CFG: + .res 4 + +; $0148 - used for #$fe sound commands to specify how many times to repeat a +; shared sound part, e.g. .byte $fe, $03, .addr sound_xx_part to loop 3 times +; #$06 slots +SOUND_REPEAT_COUNT: + .res 6 + +; $014e - the value to merge with the volume when saving the pulse config +SOUND_CFG_HIGH: + .res 6 + +; $0154 - value used when determining how many video frames to wait before +; reading next sound command, #$06 bytes, one for each sound slot +; ultimately used when calculating SOUND_CMD_LENGTH, and kept around between +; sound commands so subsequent notes can be the same length for low sound codes, +; SOUND_LENGTH_MULTIPLIER is set to SOUND_CMD_LENGTH directly with no +; multiplication (see @high_nibble_not_1) +SOUND_LENGTH_MULTIPLIER: + .res 6 + +; $015a - when not #$04, the number of times to shift the high byte of +; note_period_tbl into the low byte +SOUND_PERIOD_ROTATE: + .res 6 + +; $0160 - low nibble only, stores the volume for the pulse channels +PULSE_VOLUME: + .res 6 + +; $0166 - sound command return location low byte once sound command specified in +; move_sound_code_read_addr executes, e.g. jungle boss siren +NEW_SOUND_CODE_LOW_ADDR: + .res 6 + +; $016c - sound command return location high byte once sound command specified +; in move_sound_code_read_addr executes, e.g. jungle boss siren +NEW_SOUND_CODE_HIGH_ADDR: + .res 6 + +; $0172 - APU_PULSE_PERIOD +SOUND_PULSE_PERIOD: + .res 6 + +; $0178 - vibrato control mode [#$00-#$03], #$80 = no vibrato +; even values cause the note to stay the same, odd values cause vibrato +; #$03 = pitch up, #$01 = pitch down +; $0178 is for sound slot #$00 and $0719 is for sound slot #$01 +VIBRATO_CTRL: + .res 2 + +; $017a - sound command counter +; increments up to VIBRATO_DELAY, at which +; vibrato will be checked +; only increments when VIBRATO_CTRL is non-negative, i.e. not #$80 +SOUND_VOL_TIMER: + .res 2 + +; $017c - the note that is sustained or has the vibrato applied to for pulse +; channels (in Contra only ever sustained no vibrato) +; $017c is for sound slot #$00 and $071d is for sound slot #$01 +PULSE_NOTE: + .res 2 + +; $017e - used to delay start of vibrato until SOUND_VOL_TIMER has counted up +; to this value +; if a note isn't as long as VIBRATO_DELAY +; i.e. SOUND_CMD_LENGTH < VIBRATO_DELAY, then vibrato won't be occur for a note +; $017e is for sound slot #$00 and $071f is for sound slot #$01 +VIBRATO_DELAY: + .res 2 + +; $0180 - the amount of vibrato to apply +VIBRATO_AMOUNT: + .res 2 + +.res 14 + +; $0190 - a delay timer before beginning level end animation sequence +LEVEL_END_DELAY_TIMER: + .res 1 + +; $0191 - a delay timer specifying the duration of end_level_sequence_01 +; decremented every other frame +LEVEL_END_SQ_1_TIMER: + .res 1 + +; $0192 - used by level end routines (end_of_lvl_routine_...) for managing +; animation state. +; for example, indoor level end animations have 4 states: walk to elevator, +; initialize elevator sprite, ride elevator +; $0193 is for player 2 +LEVEL_END_LVL_ROUTINE_STATE: + .res 2 + +; $0194 - the number of players alive at the end of the level, used to know if +; should play level end music +LEVEL_END_PLAYERS_ALIVE: + .res 1 + +; $0195 - the current screen that soldiers are being generated for +SOLDIER_GEN_SCREEN: + .res 1 + +; $0196 - the total number of soldiers that have been generated for the current +; screen (exe_soldier_generation) +SCREEN_GEN_SOLDIERS: + .res 1 + +.res 105 + +; $0200 - $0200-$02ff OAMDMA (sprite) read data, read once per frame, populated +; by load_sprite_to_CPU_mem, draw_hud_sprites, or draw_player_hud_sprites +OAMDMA_CPU_BUFFER: + .res 256 + +; $0300 +; * CPU_SPRITE_BUFFER - sprites on screen, each byte is an entry into +; sprite_ptr_tbl [$0300-$0387], memory is segmented as defined below +; * PLAYER_SPRITES - player sprites, p1 and p2 sprite, then player bullets, each +; byte is an entry into sprite_ptr_tbl (#$0a bytes) +CPU_SPRITE_BUFFER: +PLAYER_SPRITES: + .res 10 + +; $030a - enemy sprites to load on screen, each byte is an entry into +; sprite_ptr_tbl (#$0f bytes) +ENEMY_SPRITES: + .res 16 + +; $031a - y position on screen of each player sprite. First 2 bytes are for +; player sprites. Starts at #$00 for top increases downward (#$0a bytes) +SPRITE_Y_POS: + .res 10 + +; $0324 - y position on screen of each enemy sprite. Starts at #$00 for top +; increases downward (#$0f bytes) +ENEMY_Y_POS: + .res 16 + +; $0334 - x position of screen of each player sprite. First 2 bytes are for +; player sprites (#$0a bytes) +SPRITE_X_POS: + .res 10 + +; $033e - x position on screen of each enemy sprite (#$0f bytes) +ENEMY_X_POS: + .res 16 + +; $034e - sprite attribute, specifies palette, vertical flip, horizontal flip +; (#$0a bytes) and whether to adjust y position +; * bit 0 and 1 - sprite palette +; * bit 2 +; * 0 to use default palette as specified in sprite code +; * 1 to use palette specified in bits 0 and 1 +; * bit 3 - whether to add #$01 to sprite y position, used for recoil effect +; firing weapon +; * bit 5 - bg priority +; * bit 6 - whether to flip the sprite horizontally +; * bit 7 - whether to flip the sprite vertically +; * bytes 0 and 1 are p1 and p2 sprite attributes, then each byte is the player +; bullet sprite attributes +; examples: player being electrocuted or invincible (flashes various colors) +SPRITE_ATTR: + .res 10 + +; $0358 - enemy sprite attribute. See specification above (#$0f bytes) +ENEMY_SPRITE_ATTR: + .res 16 + +; $0368 - The sprite codes to load for the bullet, eventually copied into +; CPU_SPRITE_BUFFER starting at offset 2 +PLAYER_BULLET_SPRITE_CODE: + .res 16 + +; $0378 - The sprite attributes for the bullet +; see SPRITE_ATTR for specification +; used for L bullets for flipping the angled sprites depending on direction +PLAYER_BULLET_SPRITE_ATTR: + .res 16 + +; $0388 - #$00 when no bullet, otherwise stores bullet type + 1 +; i.e. #$01 basic, #$02 M, #$03 F bullet, #$04 S, #$05 L, can be negative +PLAYER_BULLET_SLOT: + .res 16 + +; $0398 - an accumulator to keep track of PLAYER_BULLET_Y_VEL_FRACT being added +; to itself have elapsed before adding 1 to PLAYER_BULLET_Y_POS +PLAYER_BULLET_Y_VEL_ACCUM: + .res 16 + +; $03a8 - an accumulator to keep track of PLAYER_BULLET_X_VEL_FRACT being added +; to itself have elapsed before adding 1 to PLAYER_BULLET_X_POS +PLAYER_BULLET_X_VEL_ACCUM: + .res 16 + +; $03b8 - the bullet's sprite y position +PLAYER_BULLET_Y_POS: + .res 16 + +; $03c8 - the bullet's sprite x position +; for F bullets, PLAYER_BULLET_FS_X and PLAYER_BULLET_X_POS together determine +; x position +PLAYER_BULLET_X_POS: + .res 16 + +; $03d8 - percentage out of 0-255 set number of frames until Y position is +; incremented by an additional 1 unit +PLAYER_BULLET_Y_VEL_FRACT: + .res 16 + +; $03e8 - percentage out of 0-255 set number of frames until X position is +; incremented by an additional 1 unit +PLAYER_BULLET_X_VEL_FRACT: + .res 16 + +; $03f8 - player bullet velocity y integer portion +PLAYER_BULLET_Y_VEL_FAST: + .res 16 + +; $0408 - player bullet velocity x integer portion +PLAYER_BULLET_X_VEL_FAST: + .res 16 + +; $0418 - 'timer' starts at #$00. Used by F, S (indoor only) and L +; for indoor S, used to specify size of bullet +; For F, used to set x and y pos when traveling to create swirl +; (see f_bullet_outdoor_x_swirl_amt_tbl, and f_bullet_outdoor_y_swirl_amt_tbl) +; increments or decrements every frame depending on firing direction +; (left decrement, right increment) +; For L used to spread out 4 lasers for one shot +PLAYER_BULLET_TIMER: + .res 16 + +; $0428 - the direction of the bullet #$00 for up facing right, incrementing +; clockwise up to #09 for up facing left +PLAYER_BULLET_AIM_DIR: + .res 16 + +; $0438 - #$00, #$01, or #$03, offset into +; player_bullet_routine_XX_(indoor_)ptr_tbl +PLAYER_BULLET_ROUTINE: + .res 16 + +; $0448 - #$00 player 1 bullet, #$01 player 2 bullet, each byte is for a bullet +PLAYER_BULLET_OWNER: + .res 16 + +; $0458 +; * PLAYER_BULLET_F_RAPID - #$01 for player indoor bullets for F weapon when +; rapid fire is enabled +; * PLAYER_BULLET_S_INDOOR_ADJ - for indoor S bullets, specifies whether to +; adjust PLAYER_BULLET_X_POS by an additional -1 (#$ff) every frame +; (see s_bullet_pos_mod_tbl) +PLAYER_BULLET_F_RAPID: +PLAYER_BULLET_S_INDOOR_ADJ: + .res 16 + +; $0468 +; * PLAYER_BULLET_DIST - represents how far a bullet has traveled +; * For S outdoor bullets, used to determine the size (scale) of the bullet +; * For F on indoor levels, used to determine spiraling position based on +; distance from player +; * PLAYER_BULLET_S_ADJ_ACCUM - for indoor S weapons, stores accumulated +; fractional velocity where overflow affects PLAYER_BULLET_S_INDOOR_ADJ +; (see update_s_bullet_indoor_pos) +PLAYER_BULLET_DIST: +PLAYER_BULLET_S_ADJ_ACCUM: + .res 16 + +; $0478 - Used to offset from general x direction of bullet for swirl effect in +; F bullet and spread effect in S bullet (indoor) +; Specifies center x position on screen f bullet swirls around +; Used when firing f bullet either left, right, or at an angle +PLAYER_BULLET_FS_X: + .res 16 + +; $0488 +; * PLAYER_BULLET_F_Y - specifies center y position on screen f bullet swirls +; around. Used when firing f bullet either up, down, or at an angle. +; * PLAYER_BULLET_S_RAPID - for S weapon in indoor levels, specifies whether +; weapon is rapid fire or not, not sure why $09 wasn't used like other bullet +; routines +PLAYER_BULLET_F_Y: +PLAYER_BULLET_S_RAPID: + .res 16 + +; $0498 - (for F weapon only) an accumulator to keep track of +; PLAYER_BULLET_X_VEL_FRACT being added to itself have elapsed before adding 1 +; to PLAYER_BULLET_X_POS +PLAYER_BULLET_VEL_FS_X_ACCUM: + .res 16 + +; $04a8 +; * PLAYER_BULLET_VEL_F_Y_ACCUM - (for F weapon only) an accumulator to keep +; track of PLAYER_BULLET_Y_VEL_FRACT being added to itself have elapsed before +; adding 1 to PLAYER_BULLET_Y_POS +; * PLAYER_BULLET_S_BULLET_NUM - for S weapon only, specifies the number the +; bullet in the current 'spray' for the shot per shot of S weapon, #$05 +; bullets are generated. If no other bullets exist then $04a8 would have #$00 +; $04a9 would have #$01, $04a9 would have #$02, etc. +PLAYER_BULLET_VEL_F_Y_ACCUM: +PLAYER_BULLET_S_BULLET_NUM: + .res 16 + +; each enemy property is #$10 bytes, one byte per enemy + +; $04b8 - index to routine number for enemy +; subtract 1 to get routine, all offsets are off by 1 (...routine_ptr_tbl-2) +; ex: for exploding bridge, setting ENEMY_ROUTINE to #$02 causes +; exploding_bridge_routine_01 to run the next frame +ENEMY_ROUTINE: + .res 16 + +; the following 6 address ranges control the change in position of the enemy +; every frame the position is moved by VELOCITY_FAST units +; VELOCITY_FRACT can enable only moving by 1 unit every n frames +; for example, if ENEMY_Y_VELOCITY_FAST is #$00 and ENEMY_Y_VELOCITY_FRACT is +; #$c0, (#$c0/#$ff = 75%), +; then the enemy will move one position to the right 3 out of every 4 frames + +; $04c8 - an accumulator to keep track of ENEMY_Y_VELOCITY_FRACT being added to +; itself have elapsed before adding 1 to ENEMY_Y_POS +ENEMY_Y_VEL_ACCUM: + .res 16 + +; $04d8 - an accumulator to keep track of ENEMY_X_VELOCITY_FRACT being added to +; itself have elapsed before adding 1 to ENEMY_X_POS +ENEMY_X_VEL_ACCUM: + .res 16 + +; $04e8 - the number of units to add to ENEMY_Y_POS every frame +ENEMY_Y_VELOCITY_FAST: + .res 16 + +; $04f8 - percentage out of 0-255 of a unit to add +; e.g. if #$80 (#$80/#$ff = 50%), then every other frame will cause Y pos to +; increment by 1 +ENEMY_Y_VELOCITY_FRACT: + .res 16 + +; $0508 - the number of units to add to ENEMY_X_POS every frame +ENEMY_X_VELOCITY_FAST: + .res 16 + +; $0518 - percentage out of 0-255 of a unit to add +; e.g. if #$80 (#$80/#$ff = 50%), then every other frame will cause X pos to +; increment by 1 +ENEMY_X_VELOCITY_FRACT: + .res 16 + +; $0528 - enemy type, e.g. #$03 = flying capsule +ENEMY_TYPE: + .res 16 + +; $0538 - used for various delays by enemy logic +ENEMY_ANIMATION_DELAY: + .res 16 + +; $0548 - the sound code to play when enemy hit by player bullet, also used for +; other logic +; dragon arm orb uses it for adjusting enemy position, fire beam uses it for +; animation delay +ENEMY_VAR_A: + .res 16 + +; $0558 +; * ENEMY_ATTACK_DELAY - the delay before an enemy attacks, for weapon items and +; grenades. This is used for helping calculate falling arc trajectory instead +; of enemy delay +; * ENEMY_VAR_B - for weapon items and grenades this is used for helping +; calculate falling arc trajectory +ENEMY_ATTACK_DELAY: +ENEMY_VAR_B: + .res 16 + +; $0568 - animation frame the enemy is in, typically indexes into an enemy +; type-specific table of sprite codes +ENEMY_FRAME: + .res 16 + +; $0578 - the HP of the enemy +ENEMY_HP: + .res 16 + +; $0588 - represents 3 things for an enemy +; SSSS CCCC - score (see `score_codes_tbl`), collision, and explosion type +; (entry in collision_box_codes_XX) +ENEMY_SCORE_COLLISION: + .res 16 + +; $0598 - loaded from enemy_prop_ptr_tbl +; * bit 7 set to allow bullets to travel through enemy, e.g. weapon item +; * bit 6 specifies whether player can land on enemy +; (floating rock and moving cart), bit 4 also has to be 0 +; (see `beq @land_on_enemy`) +; * bit 4 and 5 specify the collision box type (see collision_box_codes_tbl) +; * bit 3 determines the explosion type (explosion_type_ptr_tbl) +; either explosion_type_00 or explosion_type_01 +; * bit 2 for bullets specifies whether to play sound on collision +; * bit 1 specifies whether to play explosion noise; also specifies width of +; enemy +; * bit 0 - #$00 test player-enemy collision, #$01 means to skip player-enemy +; collision test +ENEMY_STATE_WIDTH: + .res 16 + +; $05a8 - enemy type-specific attributes that define how an enemy behaves +; and/or looks +ENEMY_ATTRIBUTES: + .res 16 + +; $05b8 - a byte available to each enemy for whatever they want to use it for +ENEMY_VAR_1: + .res 16 + +; $05c8 - a byte available to each enemy for whatever they want to use it for +ENEMY_VAR_2: + .res 16 + +; $05d8 - a byte available to each enemy for whatever they want to use it for +ENEMY_VAR_3: + .res 16 + +; $05e8 - a byte available to each enemy for whatever they want to use it for +ENEMY_VAR_4: + .res 16 + +.res 8 + +; $0600 - CPU memory address where super tiles indexes for the screens of the +; level are loaded (level_X_supertiles_screen_XX data) +; 2 screens are stored in the CPU buffer. The second screen loaded at $0640. +; indexes are into level_x_supertile_data +; This data specifies the super-tiles (indexes) to load for the screens +LEVEL_SCREEN_SUPERTILES: + .res 128 + +; $0680 - map of collision types for each of the super-tiles for both +; nametables, each 2 bits encode 1/4 of a super-tile's collision information +; first 8 nibbles are a row of the top of super-tile, the next 8 are the middle +; Not used on base (indoor) levels +BG_COLLISION_DATA: + .res 128 + +; $0700 - used to store data that will be then moved to the PPU later on. +; $700 to $750, repeating structure +; * byte $700 is multifaceted +; * if $700 is #$0, then done writing graphics buffer to PPU +; * if $700 is greater than #$0, then there is data to write, this byte is the +; offset into vram_address_increment +; * both #$01, and #$03 signify VRAM address increment to 0, meaning to add #$1 +; every write to PPU (write across) +; * #$02 signifies VRAM address increment is 1, meaning add #$20 (32 in decimal) +; every write to PPU (write down) +; if GRAPHICS_BUFFER_MODE is #$ff +; * byte $701 is length of the tiles being written per group +; * byte $702 is the number of $701-sized blocks to write to the PPU +; * for each block, the block prefixed with 2 bytes specifying PPU address +; (high byte, then low byte) +; if GRAPHICS_BUFFER_MODE is #$00 +; * if byte #$00 is #$00, then no drawing takes place for frame +; * blocks of text/palette data prefixed with 2 bytes specifying PPU address +; (high byte, then low byte) +; the block of text is ended with a #$ff, if the byte after #$ff is the +; vram_address_increment offset +; then the the process continues, i.e. read #$02 PPU address bytes, read next +; text +CPU_GRAPHICS_BUFFER: + .res 80 + +.res 112 + +; $07c0 - [$07c0-$07df] the CPU memory address of the palettes eventually loaded +; into the PPU $3f00 to $3f1f +PALETTE_CPU_BUFFER: + .res 32 + +; $07e0 - the low byte of the high score score +HIGH_SCORE_LOW: + .res 1 + +; $07e1 - the high byte of the high score score +HIGH_SCORE_HIGH: + .res 1 + +; $07e2 - the low byte of player 1 high score +PLAYER_1_SCORE_LOW: + .res 1 + +; $07e3 - the high byte of player 1 high score +PLAYER_1_SCORE_HIGH: + .res 1 + +; $07e4 - the low byte of player 1 high score +PLAYER_2_SCORE_LOW: + .res 1 + +; $07e5 - the high byte of player 1 high score +PLAYER_2_SCORE_HIGH: + .res 1 + +.res 6 + +; $07ec - the previously-loaded PRG BANK ($8000-$bfff) +PREVIOUS_ROM_BANK: + .res 1 + +; $07ed - the previously-loaded PRG BANK, but used only for load_bank_1 +; (from play_sound) +PREVIOUS_ROM_BANK_1: + .res 1 \ No newline at end of file