From: Nick Downing Date: Sun, 21 Jul 2024 07:38:55 +0000 (-0800) Subject: Reverse engineer star blazer game main loop and input system, bring sky blazer disass... X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=ce25b5135ad020a3daa8b45170948d76baf5f566;p=star_disasm.git Reverse engineer star blazer game main loop and input system, bring sky blazer disassembly up to date, reverse engineer differences (mainly the input system) --- diff --git a/.gitignore b/.gitignore index 9a4a37d..570fa5b 100644 --- a/.gitignore +++ b/.gitignore @@ -68,6 +68,8 @@ /star_blazer/shape_index_pixel.inc /star_blazer/shape_pixel.json /star_blazer/sky_blazer.asm +/star_blazer/sky_blazer.asm0 +/star_blazer/sky_blazer1.txt /star_blazer/sky_blazer_draw_misc.json /star_blazer/sky_blazer_draw_misc_table.inc /star_blazer/sky_blazer_object.json diff --git a/star_blazer/Makefile b/star_blazer/Makefile index c988657..f316898 100644 --- a/star_blazer/Makefile +++ b/star_blazer/Makefile @@ -9,6 +9,7 @@ LOAD_ADDR=0x800 .PHONY: all all: \ star_blazer.dsk \ +sky_blazer.asm \ sky_blazer_shape_index.inc \ sky_blazer_shape_data.inc \ sky_blazer_object_index.inc \ @@ -154,8 +155,11 @@ sky_blazer_draw_misc.json: sky_blazer.txt sky_blazer0.ihx sky_blazer.asm: \ sky_blazer0.ihx \ sky_blazer_trace.txt \ -sky_blazer.txt - ../utils/disasm.py --trace=sky_blazer_trace.txt sky_blazer.txt $< $@ +sky_blazer.txt \ +sky_blazer.asm.patch + ../utils/disasm.py --trace=sky_blazer_trace.txt sky_blazer.txt $< $@ sky_blazer1.txt + cp $@ $@0 + patch $@ <$@.patch sky_blazer0.ihx: \ Sky\ Blazer\ (4am\ and\ san\ inc\ crack).nib \ diff --git a/star_blazer/equivalence.py b/star_blazer/equivalence.py new file mode 100755 index 0000000..384a80e --- /dev/null +++ b/star_blazer/equivalence.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python3 + +import sys + +prefixes = {'barr', 'bvar', 'loc', 'sub', 'rts', 'ptr', 'vec'} + +lines = list(sys.stdin) +assert lines[0][:3] == '---' +assert lines[1][:3] == '+++' +lines = lines[2:] +for i in range(len(lines) - 3): + if ( + lines[i][:1] == ' ' and + lines[i + 1][:1] == '-' and + lines[i + 2][:1] == '+' and + lines[i + 3][:1] == ' ' + ): + offset = 0 + + old = lines[i + 1][1:].strip() + j = old.find(',') + if j >= 0: + old = old[:j] + j = old.find(':') + if j >= 0: + old = old[:j] + j = old.find(' + ') + if j >= 0: + offset -= int(old[j + 3:], 0) + old = old[:j] + else: + j = old.find(' - ') + if j >= 0: + offset += int(old[j + 3:], 0) + old = old[:j] + + new = lines[i + 2][1:].strip() + j = new.find(',') + if j >= 0: + new = new[:j] + j = new.find(':') + if j >= 0: + new = new[:j] + j = new.find(' + ') + if j >= 0: + offset += int(new[j + 3:], 0) + new = new[:j] + else: + j = new.find(' - ') + if j >= 0: + offset -= int(new[j + 3:], 0) + new = new[:j] + + j = new.find('_') + if j >= 0 and new[:j] in prefixes: + addr = int(new[j + 1:], 16) + offset + print(f's/^#0x....,\\(0x....,{old:s},\\)/0x{addr:04x},\\1/') + else: + print('old', old, 'new', new, 'offset', offset) diff --git a/star_blazer/equivalence.sh b/star_blazer/equivalence.sh new file mode 100755 index 0000000..4e23949 --- /dev/null +++ b/star_blazer/equivalence.sh @@ -0,0 +1,8 @@ +#!/bin/sh +./uncomment.sh a +./uncomment.sh b +diff --unified a b >c +./equivalence.py d +# matches in the zpage tend to be false because of ambiguity +# therefore, sort in reverse so that matches later in the file have priority +LC_ALL=C sort -r e diff --git a/star_blazer/sky_blazer.asm.patch b/star_blazer/sky_blazer.asm.patch new file mode 100644 index 0000000..dded0c0 --- /dev/null +++ b/star_blazer/sky_blazer.asm.patch @@ -0,0 +1,1301 @@ +--- sky_blazer.asm0 2024-07-20 23:30:36.964896855 -0800 ++++ sky_blazer.asm 2024-07-20 23:34:52.942221251 -0800 +@@ -1,3 +1,10 @@ ++UNREACHABLE = 1 ++DHGR = 0 ++PIXEL_SHAPE = 0 ++SHAPE = 1 ++OBJECT = 1 ++DRAW_MISC = 1 ++ + HIRES_SCREEN = 0x2000 ; 2000 + HW_KBD = 0xc000 ; c000 + HW_KBDSTRB = 0xc010 ; c010 +@@ -11,19 +18,48 @@ + HW_PADDL1 = 0xc065 ; c065 + HW_PTRIG = 0xc070 ; c070 + ++.if DHGR ++; read ++HW_SETDHIRES = 0xc05e ++HW_SETIOUDIS = 0xc07e ++HW_CLRIOUDIS = 0xc07f ++HW_LC_BANK2_RAM_WP = 0xc080 ++HW_LC_BANK2_ROM_WE = 0xc081 ++HW_LC_BANK2_ROM_WP = 0xc082 ++HW_LC_BANK2_RAM_WE = 0xc083 ++HW_LC_BANK1_RAM_WP = 0xc084 ++HW_LC_BANK1_ROM_WE = 0xc085 ++HW_LC_BANK1_ROM_WP = 0xc086 ++HW_LC_BANK1_RAM_WE = 0xc087 ++ ++; write ++HW_CLR80COL = 0xc000 ++HW_SET80COL = 0xc001 ++HW_RDMAINRAM = 0xc002 ++HW_RDCARDRAM = 0xc003 ++HW_WRMAINRAM = 0xc004 ++HW_WRCARDRAM = 0xc005 ++HW_CLR80VID = 0xc00c ++HW_SET80VID = 0xc00d ++.endif ++ ++.include "object_defs.inc" ++ ++ .globl start ++ + .area zpage + + .ds 0x22 ; 0000 + vec_init_game: +- .ds 2 ; 0022 r ++ .dw init_game ; 0022 r + vec_start_game: +- .ds 2 ; 0024 r ++ .dw start_game ; 0024 r + .ds 2 ; 0026 + vec_calculate_object_shape: +- .ds 2 ; 0028 r ++ .dw calculate_object_shape ; 0028 r + .ds 0x24 ; 002a + vec_draw_misc_from_table: +- .ds 2 ; 004e r ++ .dw draw_misc_from_table ; 004e r + .ds 0x30 ; 0050 + half_dimension: + .ds 1 ; 0080 rw +@@ -47,12 +83,22 @@ + draw_y: .ds 1 ; 008a rw + video_line_ptr: + .ds 2 ; 008b rw ++.if DHGR ++draw_misc_aux_mask: ++ .ds 1 ++draw_misc_aux_mask_xor: ++ .ds 1 ++.endif + draw_misc_mask: + .ds 1 ; 008d rw + draw_misc_mask_temp: + .ds 1 ; 008e rw + draw_misc_mask_xor: + .ds 1 ; 008f rw ++.if DHGR ++draw_misc_shape_xor: ++ .ds 1 ++.endif + ; 24-bit register, repurposed for divide routine as + ; accumulator: divisor + ; accumulator + 1: remainder +@@ -422,20 +468,20 @@ + ; object1080_velocity_scale_for_position_(hi|lo) + ; returns a = high byte of scaled value + get_scaled_object_velocity_x_to_a: +- lda object1080_velocity_y_hi + 0x60,y ; 0b5a r ++ lda object1080_velocity_x_lo - 0x10,y ;object1080_velocity_y_hi + 0x60,y ; 0b5a r + sta *accumulator ; 0b5d r +- lda object1080_state + 0x60,y ; 0b5f r ++ lda object1080_velocity_x_hi - 0x10,y ;object1080_state + 0x60,y ; 0b5f r + jmp loc_0b6d ; 0b62 r + get_scaled_object_velocity_y_to_a: +- lda object1080_velocity_x_lo + 0x60,y ; 0b65 r ++ lda object1080_velocity_y_lo - 0x10,y ;object1080_velocity_x_lo + 0x60,y ; 0b65 r + sta *accumulator ; 0b68 r +- lda object1080_velocity_x_hi + 0x60,y ; 0b6a r ++ lda object1080_velocity_y_hi - 0x10,y ;object1080_velocity_x_hi + 0x60,y ; 0b6a r + loc_0b6d: + sty *y_save ; 0b6d r + sta *accumulator + 1 ; 0b6f r +- lda object1080_velocity_y_random_range + 0x60,y ; 0b71 r ++ lda object1080_velocity_scale_for_position_hi - 0x10,y ;object1080_velocity_y_random_range + 0x60,y ; 0b71 r + sta *temp ; 0b74 r +- lda object1080_velocity_scale_for_position_hi + 0x60,y ; 0b76 r ++ lda object1080_velocity_scale_for_position_lo - 0x10,y ;object1080_velocity_scale_for_position_hi + 0x60,y ; 0b76 r + ldy *temp ; 0b79 r + jsr multiply_ya_by_accumulator_optimized ; 0b7b r + tya ; 0b7e r +@@ -450,46 +496,46 @@ + copy_object_position_plus_scaled_velocity: + jsr get_scaled_object_velocity_x_to_a ; 0b82 r + clc ; 0b85 r +- adc object1080_shape + 0x60,y ; 0b86 r +- sta object1080_shape + 0x60,x ; 0b89 r ++ adc object1080_x_hi - 0x10,y ;object1080_shape + 0x60,y ; 0b86 r ++ sta object1080_x_hi - 0x10,x ;object1080_shape + 0x60,x ; 0b89 r + jsr get_scaled_object_velocity_y_to_a ; 0b8c r + clc ; 0b8f r +- adc object1080_x_hi + 0x60,y ; 0b90 r +- sta object1080_x_hi + 0x60,x ; 0b93 r ++ adc object1080_y_hi - 0x10,y ;object1080_x_hi + 0x60,y ; 0b90 r ++ sta object1080_y_hi - 0x10,x ;object1080_x_hi + 0x60,x ; 0b93 r + rts ; 0b96 r + copy_object_position_plus_scaled_velocity_rotate_90: + jsr get_scaled_object_velocity_y_to_a ; 0b97 r + jsr neg_a ; 0b9a r + clc ; 0b9d r +- adc object1080_shape + 0x60,y ; 0b9e r +- sta object1080_shape + 0x60,x ; 0ba1 r ++ adc object1080_x_hi - 0x10,y ;object1080_shape + 0x60,y ; 0b9e r ++ sta object1080_x_hi - 0x10,x ;object1080_shape + 0x60,x ; 0ba1 r + jsr get_scaled_object_velocity_x_to_a ; 0ba4 r + clc ; 0ba7 r +- adc object1080_x_hi + 0x60,y ; 0ba8 r +- sta object1080_x_hi + 0x60,x ; 0bab r ++ adc object1080_y_hi - 0x10,y ;object1080_x_hi + 0x60,y ; 0ba8 r ++ sta object1080_y_hi - 0x10,x ;object1080_x_hi + 0x60,x ; 0bab r + rts ; 0bae r + copy_object_position_plus_scaled_velocity_rotate_180: + jsr get_scaled_object_velocity_x_to_a ; 0baf r + jsr neg_a ; 0bb2 r + clc ; 0bb5 r +- adc object1080_shape + 0x60,y ; 0bb6 r +- sta object1080_shape + 0x60,x ; 0bb9 r ++ adc object1080_x_hi - 0x10,y ;object1080_shape + 0x60,y ; 0bb6 r ++ sta object1080_x_hi - 0x10,x ;object1080_shape + 0x60,x ; 0bb9 r + jsr get_scaled_object_velocity_y_to_a ; 0bbc r + jsr neg_a ; 0bbf r + clc ; 0bc2 r +- adc object1080_x_hi + 0x60,y ; 0bc3 r +- sta object1080_x_hi + 0x60,x ; 0bc6 r ++ adc object1080_y_hi - 0x10,y ;object1080_x_hi + 0x60,y ; 0bc3 r ++ sta object1080_y_hi - 0x10,x ;object1080_x_hi + 0x60,x ; 0bc6 r + rts ; 0bc9 r + copy_object_position_plus_scaled_velocity_rotate_270: + jsr get_scaled_object_velocity_y_to_a ; 0bca r + clc ; 0bcd r +- adc object1080_shape + 0x60,y ; 0bce r +- sta object1080_shape + 0x60,x ; 0bd1 r ++ adc object1080_x_hi - 0x10,y ;object1080_shape + 0x60,y ; 0bce r ++ sta object1080_x_hi - 0x10,x ;object1080_shape + 0x60,x ; 0bd1 r + jsr get_scaled_object_velocity_x_to_a ; 0bd4 r + jsr neg_a ; 0bd7 r + clc ; 0bda r +- adc object1080_x_hi + 0x60,y ; 0bdb r +- sta object1080_x_hi + 0x60,x ; 0bde r ++ adc object1080_y_hi - 0x10,y ;object1080_x_hi + 0x60,y ; 0bdb r ++ sta object1080_y_hi - 0x10,x ;object1080_x_hi + 0x60,x ; 0bde r + rts ; 0be1 r + ; call with y = object to calculate for + ; uses coefficient from the following table: +@@ -519,27 +565,27 @@ + ; only the 0 and 180 degrees rotation occurred in the trace + copy_scaled_object_velocity: + jsr get_scaled_object_velocity_x_to_ya ; 0c06 r +- sta object1080_velocity_y_hi + 0x60,x ; 0c09 r ++ sta object1080_velocity_x_lo - 0x10,x ;object1080_velocity_y_hi + 0x60,x ; 0c09 r + tya ; 0c0c r +- sta object1080_state + 0x60,x ; 0c0d r ++ sta object1080_velocity_x_hi - 0x10,x ;object1080_state + 0x60,x ; 0c0d r + ldy *y_save ; 0c10 r + jsr get_scaled_object_velocity_y_to_ya ; 0c12 r +- sta object1080_velocity_x_lo + 0x60,x ; 0c15 r ++ sta object1080_velocity_y_lo - 0x10,x ;object1080_velocity_x_lo + 0x60,x ; 0c15 r + tya ; 0c18 r +- sta object1080_velocity_x_hi + 0x60,x ; 0c19 r ++ sta object1080_velocity_y_hi - 0x10,x ;object1080_velocity_x_hi + 0x60,x ; 0c19 r + ldy *y_save ; 0c1c r + rts ; 0c1e r + copy_scaled_object_velocity_rotate_90: + jsr get_scaled_object_velocity_y_to_ya ; 0c1f r + jsr neg_ya ; 0c22 r +- sta object1080_velocity_y_hi + 0x60,x ; 0c25 r ++ sta object1080_velocity_x_lo - 0x10,x ;object1080_velocity_y_hi + 0x60,x ; 0c25 r + tya ; 0c28 r +- sta object1080_state + 0x60,x ; 0c29 r ++ sta object1080_velocity_x_hi - 0x10,x ;object1080_state + 0x60,x ; 0c29 r + ldy *y_save ; 0c2c r + jsr get_scaled_object_velocity_x_to_ya ; 0c2e r +- sta object1080_velocity_x_lo + 0x60,x ; 0c31 r ++ sta object1080_velocity_y_lo - 0x10,x ;object1080_velocity_x_lo + 0x60,x ; 0c31 r + tya ; 0c34 r +- sta object1080_velocity_x_hi + 0x60,x ; 0c35 r ++ sta object1080_velocity_y_hi - 0x10,x ;object1080_velocity_x_hi + 0x60,x ; 0c35 r + ldy *y_save ; 0c38 r + rts ; 0c3a r + copy_scaled_object_velocity_rotate_180: +@@ -558,15 +604,15 @@ + rts ; 0c57 -> 0c59 -> 0fcb r s=f1 + copy_scaled_object_velocity_rotate_270: + jsr get_scaled_object_velocity_y_to_ya ; 0c5a r +- sta object1080_velocity_y_hi + 0x60,x ; 0c5d r ++ sta object1080_velocity_x_lo - 0x10,x ;object1080_velocity_y_hi + 0x60,x ; 0c5d r + tya ; 0c60 r +- sta object1080_state + 0x60,x ; 0c61 r ++ sta object1080_velocity_x_hi - 0x10,x ;object1080_state + 0x60,x ; 0c61 r + ldy *y_save ; 0c64 r + jsr get_scaled_object_velocity_x_to_ya ; 0c66 r + jsr neg_ya ; 0c69 r +- sta object1080_velocity_x_lo + 0x60,x ; 0c6c r ++ sta object1080_velocity_y_lo - 0x10,x ;object1080_velocity_x_lo + 0x60,x ; 0c6c r + tya ; 0c6f r +- sta object1080_velocity_x_hi + 0x60,x ; 0c70 r ++ sta object1080_velocity_y_hi - 0x10,x ;object1080_velocity_x_hi + 0x60,x ; 0c70 r + ldy *y_save ; 0c73 r + rts ; 0c75 r + horizontal_collision: +@@ -608,8 +654,8 @@ + horizontal_collision_and_zero: + jsr horizontal_collision ; 0cc4 r + lda #0x00 ; 0cc7 r +- sta object1080_velocity_y_hi + 0x60,x ; 0cc9 r +- sta object1080_state + 0x60,x ; 0ccc r ++ sta object1080_velocity_x_lo - 0x10,x ;object1080_velocity_y_hi + 0x60,x ; 0cc9 r ++ sta object1080_velocity_x_hi - 0x10,x ;object1080_state + 0x60,x ; 0ccc r + rts ; 0ccf r + vertical_collision_and_zero: + jsr vertical_collision ; 1015 -> 0cd0 -> 0c9d r s=f6 +@@ -942,9 +988,10 @@ + bcs ucode_decimal_set_save ; 0ebf r + ucode_decimal_set_mission_specific_value: + ldy *decimal + 6 ; 0ec1 r +- lda initial_decimal_plus_0xe,y ; 0ec3 r ++ lda mission_table_decimal_plus_4 - 1,y ;initial_decimal_plus_0xe,y ; 0ec3 r ++ + pha ; 0ec6 r +- lda initial_decimal_plus_0xf,y ; 0ec7 r ++ lda mission_table_decimal_plus_5 - 1,y ;initial_decimal_plus_0xf,y ; 0ec7 r + tay ; 0eca r + pla ; 0ecb r + bcs ucode_decimal_set_save ; 0ecc r +@@ -1312,7 +1359,7 @@ + tsx ; 1095 -> 1097 -> 1098 r + stx *ucode_sp ; 1097 -> 1098 -> 109a r + ldx *ucode_x_save ; 1098 -> 109a -> 109c r +- lda object1080_y1 + 0x60,x ; 109a -> 109c -> 109f r x=01..7f ++ lda object1080_state - 0x10,x ;object1080_y1 + 0x60,x ; 109a -> 109c -> 109f r x=01..7f + sta *ucode_fire_in_state_fn_count ; 109c -> 109f -> 10a1 r + ; alternative entry point for execute_ucode_words that comes from scoring? + execute_ucode_words_entry: +@@ -1344,7 +1391,7 @@ + ; jsr execute_object1080_ucode_countdown + ; bpl rts_15d6 + execute_ucode_words_done: +- lda object1080_y1 + 0x60,x ; 1093,10a5,10ba,10c2,10c6 -> 10cd -> 10d0 r x=01..7f ++ lda object1080_state - 0x10,x ;object1080_y1 + 0x60,x ; 1093,10a5,10ba,10c2,10c6 -> 10cd -> 10d0 r x=01..7f + rts ; 10cd -> 10d0 -> 123e,143a,1615,1629,1633,1649,165b,1759 r s=f8..fe,02 + ; call with the following set up: + ; execute_ucode_words_ptr +@@ -1865,16 +1912,20 @@ + bpl loc_14c9 ; 14a0 -> 14a3 -> 14a5,14c9 r n=0..1 + iny ; 14a3 -> 14a5 -> 14a6 r + bne ucode_test_fire_all_objects_active ; 14a5 -> 14a6 -> 149b r z=0 ++.if UNREACHABLE + beq loc_14c9 ; 14a8 r ++.endif + ucode_test_fire_all_objects_inactive: + lda (*ucode_collision_or_fire_ptr),y ; 14aa r + beq loc_14c9 ; 14ac r + tax ; 14ae r +- lda object1080_y1 + 0x60,x ; 14af r ++ lda object1080_state - 0x10,x ;object1080_y1 + 0x60,x ; 14af r + bmi loc_14ca ; 14b2 r + iny ; 14b4 r + bne ucode_test_fire_all_objects_inactive ; 14b5 r ++.if UNREACHABLE + beq loc_14c9 ; 14b7 r ++.endif + ; opcode is followed by null-terminated list of objects to test + ; note: some of these opcodes never executed in the trace + ; 0x01 loc_149b test that all objects are active (object1080_state >= 0x80) +@@ -1907,17 +1958,21 @@ + bmi loc_14c9 ; 14d5 -> 14d8 -> 14c9,14da r n=0..1 + iny ; 14d8 -> 14da -> 14db r + bne ucode_test_fire_any_object_active ; 14da -> 14db -> 14d0 r z=0 ++.if UNREACHABLE + beq loc_14c9 ; 14dd r + rts ; 14df r ++.endif + ucode_test_fire_any_object_inactive: + lda (*ucode_collision_or_fire_ptr),y ; 14e0 r + beq loc_14c9 ; 14e2 r + tax ; 14e4 r +- lda object1080_y1 + 0x60,x ; 14e5 r ++ lda object1080_state - 0x10,x ;object1080_y1 + 0x60,x ; 14e5 r + bpl loc_14ca ; 14e8 r + iny ; 14ea r + bne ucode_test_fire_any_object_inactive ; 14eb r ++.if UNREACHABLE + beq loc_14c9 ; 14ed r ++.endif + test_object_fire_in_state_f0: + lda object6080_fire_count - 0x60,x ; 1668 -> 14ef -> 14f2 r x=60..7f + beq test_object_fire_false ; 14ef -> 14f2 -> 14f4,153f r z=0..1 +@@ -2308,11 +2363,35 @@ + ; the entry point to the executable + ; in star blazer it had joystick detection code, deleted in sky blazer + ; so in sky blazer it just jumps to init_game via vec_init_game +-start: jmp (vec_init_game) ; -> 17d1 -> 1708 r ++start: ++.if DHGR ++ ; shadow code that needs to run with "sta HW_RDCARDRAM" ++ ; from draw_object to draw_misc_from_table (this is generous) ++SHADOW_PAGES = (draw_misc_from_table - draw_object + 0xff) / 0x100 ++SHADOW_START = draw_misc_from_table - SHADOW_PAGES * 0x100 ++ lda #SHADOW_START ++ sta video_line_ptr + 1 ++ ldx #SHADOW_PAGES ++ ldy # 17d1 -> 1708 r ++.if UNREACHABLE + .db 0x00 ; 17d4 + .db 0x00 ; 17d5 + .db 0x00 ; 17d6 + .db 0x00 ; 17d7 ++.endif + ; the next 3 routines were added in sky blazer in space freed up by + ; the deletion of the joystick detection code, it seems to have been + ; manually patched rather than reassembled as it is not tightly packed +@@ -2320,7 +2399,9 @@ + lda #0xff ; 1710 -> 17d8 -> 17da r + sta *stuck_joystick ; 17d8 -> 17da -> 17dc r + jmp video_init ; 17da -> 17dc -> 1937 r ++.if UNREACHABLE + .db 0x00 ; 17df ++.endif + patch_read_pb0: + bit HW_PB0 ; 179b -> 17e0 -> 17e3 r + bpl 0$ ; 17e0 -> 17e3 -> 17e5,17ec r n=0..1 +@@ -2338,7 +2419,10 @@ + sta hw_spkr_ptr ; 17f5 r + rts ; 17f8 r + ++; above code is a bit bigger for DHGR so we are past address 0x1800 by here ++.ifeq DHGR + .area text1 ++.endif + + divide_a_by_y: + sta *accumulator + 1 ; 0a90,0aa0,0ab5,0ad5 -> 1800 -> 1802 r +@@ -2404,10 +2488,12 @@ + lda *result + 1 ; 186e r + ldy *result + 2 ; 1870 r + rts ; 1872 r ++.if UNREACHABLE + inc *random_seed ; 1873 r + bne 4$ ; 1875 r + inc *random_seed + 1 ; 1877 r + 4$: rts ; 1879 r ++.endif + random_init: + lda *random_seed ; 16ae -> 187a -> 187c r + ora #0x01 ; 187a -> 187c -> 187e r +@@ -2573,16 +2659,30 @@ + ldx #>HIRES_SCREEN ; 199b -> 199d -> 199f r + stx *video_line_ptr + 1 ; 199d -> 199f -> 19a1 r + tay ; 199f -> 19a1 -> 19a2 r +-0$: sta (*video_line_ptr),y ; 19a1,19a5,19aa -> 19a2 -> 19a4 r y=00..ff ++0$: ++.if DHGR ++ sta HW_WRCARDRAM ++ sta (*video_line_ptr),y ++ sta HW_WRMAINRAM ++.endif ++ sta (*video_line_ptr),y ; 19a1,19a5,19aa -> 19a2 -> 19a4 r y=00..ff + iny ; 19a2 -> 19a4 -> 19a5 r + bne 0$ ; 19a4 -> 19a5 -> 19a2,19a7 r z=0..1 + inc *video_line_ptr + 1 ; 19a5 -> 19a7 -> 19a9 r + dex ; 19a7 -> 19a9 -> 19aa r + bne 0$ ; 19a9 -> 19aa -> 19a2,19ac r z=0..1 ++.if DHGR ++ lda HW_CLRIOUDIS ++ sta HW_CLR80COL ++.endif + sta HW_TXTCLR ; 19aa -> 19ac -> 19af r + sta HW_MIXCLR ; 19ac -> 19af -> 19b2 r + sta HW_PAGE1 ; 19af -> 19b2 -> 19b5 r + sta HW_HIRES ; 19b2 -> 19b5 -> 19b8 r ++.if DHGR ++ lda HW_SETDHIRES ++ sta HW_SET80VID ++.endif + rts ; 19b5 -> 19b8 -> 1713 r s=fe + video_clear_rectangle: + ldx *clip_y0 ; 1064 -> 19b9 -> 19bb r +@@ -2590,8 +2690,20 @@ + sta *video_line_ptr ; 19bb -> 19be -> 19c0 r + lda video_line_table_hi - 0x20,x ; 19be -> 19c0 -> 19c3 r x=28..cf + sta *video_line_ptr + 1 ; 19c0 -> 19c3 -> 19c5 r ++.if DHGR ++ lda #0 ++ sta HW_WRCARDRAM ++ ldy *clip_x0 ++90$: sta (*video_line_ptr),y ; 19c7,19ce -> 19c9 -> 19cb r y=6c..93 ++ iny ; 19c9 -> 19cb -> 19cc r ++ cpy *clip_x1 ; 19cb -> 19cc -> 19ce r y=6d..94 ++ bcc 90$ ; 19cc -> 19ce -> 19c9,19d0 r c=0..1 ++ sta HW_WRMAINRAM ++ ldy *clip_x0 ++.else + ldy *clip_x0 ; 19c3 -> 19c5 -> 19c7 r + lda #0x00 ; 19c5 -> 19c7 -> 19c9 r ++.endif + 1$: sta (*video_line_ptr),y ; 19c7,19ce -> 19c9 -> 19cb r y=6c..93 + iny ; 19c9 -> 19cb -> 19cc r + cpy *clip_x1 ; 19cb -> 19cc -> 19ce r y=6d..94 +@@ -2641,6 +2753,7 @@ + sta object1080_y0 - 0x10,x ; 1a1b -> 1a1e -> 1a21 r x=10..7f + adc #0x01 ; 1a1e -> 1a21 -> 1a23 r c=0..1 d=0 + sta object1080_y1 - 0x10,x ; 1a21 -> 1a23 -> 1a26 r x=10..7f ++.ifeq PIXEL_SHAPE + rts ; 1a23 -> 1a26 -> 1076,1179,1602 r s=f2..fa,02 + pixel_data_table_left: + .db 0x83 ; 1a27 r +@@ -2723,14 +2836,17 @@ + lda object1080_onscreen_shape_ptr_hi - 0x10,x ; 1aa5 -> 1aa7 -> 1aaa r x=20..4f + ora (*video_line_ptr),y ; 1aa7 -> 1aaa -> 1aac r y=6d..93,02 + sta (*video_line_ptr),y ; 1aaa -> 1aac -> 1aae r y=6d..93,02 ++.endif + rts_1aae: + rts ; 1a7b,1a7f,1aa1,1aa5,1aac,1ac1,1ad6 -> 1aae -> 15cd r s=fc + draw_object: + lda object1080_onscreen - 0x10,x ; 16a8 -> 1aaf -> 1ab2 r x=14..77 + bne rts_1aae ; 1aaf -> 1ab2 -> 1ab4 r z=1 + lda object1080_shape - 0x10,x ; 1ab2 -> 1ab4 -> 1ab7 r x=14..77 ++.ifeq PIXEL_SHAPE + cmp #0x08 ; 1ab4 -> 1ab7 -> 1ab9 r a=01..8b + bcc draw_pixel_object ; 1ab7 -> 1ab9 -> 1a45,1abb r c=0..1 ++.endif + lda object1080_y0 - 0x10,x ; 1ab9 -> 1abb -> 1abe r x=14..77 + cmp object1080_y1 - 0x10,x ; 1abb -> 1abe -> 1ac1 r a=00..ff x=14..77 + bcs rts_1aae ; 1abe -> 1ac1 -> 1aae,1ac3 r c=0..1 +@@ -2783,7 +2899,12 @@ + stx *x_save ; 1b32 -> 1b35 -> 1b37 r + lda *draw_y ; 1b35 -> 1b37 -> 1b39 r + cmp *clip_y0 ; 1b37 -> 1b39 -> 1b3b r a=00..f9 ++.if DHGR ++ bcs . + 5 ++ jmp 8$ ++.else + bcc 8$ ; 1b39 -> 1b3b -> 1b3d,1b83 r c=0..1 ++.endif + lda *clip_y1 ; 1b3b -> 1b3d -> 1b3f r + cmp *draw_y1 ; 1b3d -> 1b3f -> 1b41 r a=d0 + bcc 8$ ; 1b3f -> 1b41 -> 1b43,1b83 r c=0..1 +@@ -2794,16 +2915,59 @@ + cmp *draw_x1 ; 1b49 -> 1b4b -> 1b4d r a=94 + bcc 8$ ; 1b4b -> 1b4d -> 1b4f,1b83 r c=0..1 + lda object1080_onscreen_shape_ptr_lo - 0x10,x ; 1b4d -> 1b4f -> 1b52 r x=14..77 ++.if DHGR ++ sta 92$ ++.endif + sta 7$ ; 1b4f -> 1b52 -> 1b55 r ++.if DHGR ++ tay ++.endif + lda object1080_onscreen_shape_ptr_hi - 0x10,x ; 1b52 -> 1b55 -> 1b58 r x=14..77 ++.if DHGR ++ sta 92$ + 1 ++.endif + sta 7$ + 1 ; 1b55 -> 1b58 -> 1b5b r ++.if DHGR ++ sta HW_WRCARDRAM ++ sty 91$ ++ sta 91$ + 1 ++ ;sta HW_WRMAINRAM ++.endif + ldx #0x00 ; 1b58 -> 1b5b -> 1b5d r + ldy *draw_y ; 1b5b -> 1b5d -> 1b5f r + 5$: lda video_line_table_lo - 0x20,y ; 1b5d,1b7e -> 1b5f -> 1b62 r y=28..cf + sta *video_line_ptr ; 1b5f -> 1b62 -> 1b64 r + lda video_line_table_hi - 0x20,y ; 1b62 -> 1b64 -> 1b67 r y=28..cf + sta *video_line_ptr + 1 ; 1b64 -> 1b67 -> 1b69 r ++.if DHGR ++ sta HW_RDCARDRAM ++ sta HW_WRCARDRAM ++ ldy *draw_x0 ++ stx *dimension ++90$: .db 0xbd ; lda NNNN,x ++91$: .dw 0 ++ ora (*video_line_ptr),y ++ sta (*video_line_ptr),y ++ inx ++ iny ++ cpy *draw_x1 ++ bcc 90$ ++ ldx *dimension ++ sta HW_RDMAINRAM ++ sta HW_WRMAINRAM ++.endif + ldy *draw_x0 ; 1b67 -> 1b69 -> 1b6b r ++.if DHGR ; draw overflow pixel ++ dey ++ bmi 93$ ++ .db 0xbd ; lda NNNN,x ++92$: .dw 0 ++ lsr a ++ and #0x40 ++ ora (*video_line_ptr),y ++ sta (*video_line_ptr),y ++93$: iny ++.endif + 6$: .db 0xbd ; 1b69,1b76 -> 1b6b -> 1b6e r "lda bvar_6f9f,x" x=00..39 + 7$: .dw 0x6f9f ; 1b6c rw + ora (*video_line_ptr),y ; 1b6b -> 1b6e -> 1b70 r y=6c..93 +@@ -2820,16 +2984,50 @@ + rts ; 1b80 -> 1b82 -> 15cd r s=fc + 8$: inc object1080_onscreen_clipped - 0x10,x ; 1b3b,1b41,1b47,1b4d -> 1b83 -> 1b86 r x=14..77 + lda object1080_onscreen_shape_ptr_lo - 0x10,x ; 1b83 -> 1b86 -> 1b89 r x=14..77 ++.if DHGR ++ sta 94$ ++.endif + sta 11$ ; 1b86 -> 1b89 -> 1b8c r ++.if DHGR ++ tay ++.endif + lda object1080_onscreen_shape_ptr_hi - 0x10,x ; 1b89 -> 1b8c -> 1b8f r x=14..77 ++.if DHGR ++ sta 94$ + 1 ++.endif + sta 11$ + 1 ; 1b8c -> 1b8f -> 1b92 r ++.if DHGR ++ sta HW_WRCARDRAM ++ sty 96$ ++ sta 96$ + 1 ++ sta HW_WRMAINRAM ++.endif + ldx #0x00 ; 1b8f -> 1b92 -> 1b94 r + ldy *draw_y ; 1b92 -> 1b94 -> 1b96 r +-9$: lda x_table_times2_mod7_minus_03 + 0xe0,y ; 1b94,1bc7 -> 1b96 -> 1b99 r y=00..fc ++9$: lda video_line_table_lo - 0x20,y ;x_table_times2_mod7_minus_03 + 0xe0,y ; 1b94,1bc7 -> 1b96 -> 1b99 r y=11..d8 + sta *video_line_ptr ; 1b96 -> 1b99 -> 1b9b r +- lda video_line_table_lo + 0xa0,y ; 1b99 -> 1b9b -> 1b9e r y=00..fc ++ lda video_line_table_hi - 0x20,y ;video_line_table_lo + 0xa0,y ; 1b99 -> 1b9b -> 1b9e r y=11..d8 + sta *video_line_ptr + 1 ; 1b9b -> 1b9e -> 1ba0 r + ldy *draw_x0 ; 1b9e -> 1ba0 -> 1ba2 r ++.if DHGR ; draw overflow pixel ++ lda *draw_y ++ cmp *clip_y0 ++ bcc 12$ ++ cmp *clip_y1 ++ bcs 12$ ++ dey ++ cpy *clip_x0 ++ bcc 95$ ++ cpy *clip_x1 ++ bcs 95$ ++ .db 0xbd ; lda NNNN,x ++94$: .dw 0 ++ lsr a ++ and #0x40 ++ ora (*video_line_ptr),y ++ sta (*video_line_ptr),y ++95$: iny ++.endif + 10$: lda *draw_y ; 1ba0,1bbf -> 1ba2 -> 1ba4 r + cmp *clip_y0 ; 1ba2 -> 1ba4 -> 1ba6 r a=00..fc + bcc 12$ ; 1ba4 -> 1ba6 -> 1ba8,1bbb r c=0..1 +@@ -2839,6 +3037,16 @@ + bcc 12$ ; 1bac -> 1bae -> 1bb0,1bbb r c=0..1 + cpy *clip_x1 ; 1bae -> 1bb0 -> 1bb2 r y=6c..a4 + bcs 12$ ; 1bb0 -> 1bb2 -> 1bb4,1bbb r c=0..1 ++.if DHGR ++ sta HW_RDCARDRAM ++ sta HW_WRCARDRAM ++ .db 0xbd ; lda NNNN,x ++96$: .dw 0 ++ ora (*video_line_ptr),y ++ sta (*video_line_ptr),y ++ sta HW_RDMAINRAM ++ sta HW_WRMAINRAM ++.endif + .db 0xbd ; 1bb2 -> 1bb4 -> 1bb7 r "lda 0x6fab,x" x=00..39 + 11$: .dw 0x6fab ; 1bb5 rw + ora (*video_line_ptr),y ; 1bb4 -> 1bb7 -> 1bb9 r y=6c..93 +@@ -2852,6 +3060,7 @@ + cpy *draw_y1 ; 1bc3 -> 1bc5 -> 1bc7 r y=01..fd + bcc 9$ ; 1bc5 -> 1bc7 -> 1b96,1bc9 r c=0..1 + ldx *x_save ; 1bc7 -> 1bc9 -> 1bcb r ++.ifeq PIXEL_SHAPE + rts ; 1bc9 -> 1bcb -> 15cd r s=fc + erase_pixel_object: + lda #0x00 ; 1c12 -> 1bcc -> 1bce r +@@ -2883,12 +3092,15 @@ + eor #0xff ; 1c03 -> 1c06 -> 1c08 r + and (*video_line_ptr),y ; 1c06 -> 1c08 -> 1c0a r y=6d..93,02 + sta (*video_line_ptr),y ; 1c08 -> 1c0a -> 1c0c r y=6d..93,02 ++.endif + rts_1c0c: + rts ; 1bd6,1bda,1bfd,1c01,1c0a,1c10 -> 1c0c -> 1076,15cd,16a8 r s=f4..fc,02 + erase_object: + lda object1080_onscreen - 0x10,x ; 11ba,16a5,16ab -> 1c0d -> 1c10 r x=10..7f + beq rts_1c0c ; 1c0d -> 1c10 -> 1c0c,1c12 r z=0..1 ++.ifeq PIXEL_SHAPE + bmi erase_pixel_object ; 1c10 -> 1c12 -> 1bcc,1c14 r n=0..1 ++.endif + lda #0x00 ; 1c12 -> 1c14 -> 1c16 r + sta object1080_onscreen - 0x10,x ; 1c14 -> 1c16 -> 1c19 r x=14..77 + lda object1080_onscreen_x0 - 0x10,x ; 1c16 -> 1c19 -> 1c1c r x=14..77 +@@ -2903,16 +3115,61 @@ + stx *x_save ; 1c2d -> 1c30 -> 1c32 r + bne 3$ ; 1c30 -> 1c32 -> 1c34,1c6a r z=0..1 + lda object1080_onscreen_shape_ptr_lo - 0x10,x ; 1c32 -> 1c34 -> 1c37 r x=14..77 ++.if DHGR ++ sta 92$ ++.endif + sta 2$ ; 1c34 -> 1c37 -> 1c3a r ++.if DHGR ++ tay ++.endif + lda object1080_onscreen_shape_ptr_hi - 0x10,x ; 1c37 -> 1c3a -> 1c3d r x=14..77 ++.if DHGR ++ sta 92$ + 1 ++.endif + sta 2$ + 1 ; 1c3a -> 1c3d -> 1c40 r ++.if DHGR ++ sta HW_WRCARDRAM ++ sty 91$ ++ sta 91$ + 1 ++ ;sta HW_WRMAINRAM ++.endif + ldx #0x00 ; 1c3d -> 1c40 -> 1c42 r + ldy *draw_y ; 1c40 -> 1c42 -> 1c44 r + 0$: lda video_line_table_lo - 0x20,y ; 1c42,1c65 -> 1c44 -> 1c47 r y=28..cf + sta *video_line_ptr ; 1c44 -> 1c47 -> 1c49 r + lda video_line_table_hi - 0x20,y ; 1c47 -> 1c49 -> 1c4c r y=28..cf + sta *video_line_ptr + 1 ; 1c49 -> 1c4c -> 1c4e r ++.if DHGR ++ sta HW_RDCARDRAM ++ sta HW_WRCARDRAM ++ ldy *draw_x0 ++ stx *dimension ++90$: .db 0xbd ; lda NNNN,x ++91$: .dw 0 ++ eor #0xff ++ and (*video_line_ptr),y ++ sta (*video_line_ptr),y ++ inx ++ iny ++ cpy *draw_x1 ++ bcc 90$ ++ ldx *dimension ++ sta HW_RDMAINRAM ++ sta HW_WRMAINRAM ++.endif + ldy *draw_x0 ; 1c4c -> 1c4e -> 1c50 r ++.if DHGR ; erase overflow pixel ++ dey ++ bmi 93$ ++ .db 0xbd ; lda NNNN,x ++92$: .dw 0 ++ lsr a ++ and #0x40 ++ eor #0xff ++ and (*video_line_ptr),y ++ sta (*video_line_ptr),y ++93$: iny ++.endif + 1$: .db 0xbd ; 1c4e,1c5d -> 1c50 -> 1c53 r "lda 0x6f93,x" x=00..39 + 2$: .dw 0x6f93 ; 1c51 rw + eor #0xff ; 1c50 -> 1c53 -> 1c55 r +@@ -2929,16 +3186,51 @@ + ldx *x_save ; 1c65 -> 1c67 -> 1c69 r + rts ; 1c67 -> 1c69 -> 1076,16a8 r s=f4..fa,02 + 3$: lda object1080_onscreen_shape_ptr_lo - 0x10,x ; 1c32 -> 1c6a -> 1c6d r x=14..77 ++.if DHGR ++ sta 94$ ++.endif + sta 6$ ; 1c6a -> 1c6d -> 1c70 r ++.if DHGR ++ tay ++.endif + lda object1080_onscreen_shape_ptr_hi - 0x10,x ; 1c6d -> 1c70 -> 1c73 r x=14..77 ++.if DHGR ++ sta 94$ + 1 ++.endif + sta 6$ + 1 ; 1c70 -> 1c73 -> 1c76 r ++.if DHGR ++ sta HW_WRCARDRAM ++ sty 96$ ++ sta 96$ + 1 ++ sta HW_WRMAINRAM ++.endif + ldx #0x00 ; 1c73 -> 1c76 -> 1c78 r + ldy *draw_y ; 1c76 -> 1c78 -> 1c7a r +-4$: lda x_table_times2_mod7_minus_03 + 0xe0,y ; 1c78,1cad -> 1c7a -> 1c7d r y=00..fc ++4$: lda video_line_table_lo - 0x20,y ;x_table_times2_mod7_minus_03 + 0xe0,y ; 1c78,1cad -> 1c7a -> 1c7d r y=11..d8 + sta *video_line_ptr ; 1c7a -> 1c7d -> 1c7f r +- lda video_line_table_lo + 0xa0,y ; 1c7d -> 1c7f -> 1c82 r y=00..fc ++ lda video_line_table_hi - 0x20,y ;video_line_table_lo + 0xa0,y ; 1c7d -> 1c7f -> 1c82 r y=11..d8 + sta *video_line_ptr + 1 ; 1c7f -> 1c82 -> 1c84 r + ldy *draw_x0 ; 1c82 -> 1c84 -> 1c86 r ++.if DHGR ; erase overflow pixel ++ lda *draw_y ++ cmp *clip_y0 ++ bcc 7$ ++ cmp *clip_y1 ++ bcs 7$ ++ dey ++ cpy *clip_x0 ++ bcc 95$ ++ cpy *clip_x1 ++ bcs 95$ ++ .db 0xbd ; lda NNNN,x ++94$: .dw 0 ++ lsr a ++ and #0x40 ++ eor #0xff ++ and (*video_line_ptr),y ++ sta (*video_line_ptr),y ++95$: iny ++.endif + 5$: lda *draw_y ; 1c84,1ca5 -> 1c86 -> 1c88 r + cmp *clip_y0 ; 1c86 -> 1c88 -> 1c8a r a=00..fc + bcc 7$ ; 1c88 -> 1c8a -> 1c8c,1ca1 r c=0..1 +@@ -2948,6 +3240,17 @@ + bcc 7$ ; 1c90 -> 1c92 -> 1c94,1ca1 r c=0..1 + cpy *clip_x1 ; 1c92 -> 1c94 -> 1c96 r y=6c..a4 + bcs 7$ ; 1c94 -> 1c96 -> 1c98,1ca1 r c=0..1 ++.if DHGR ++ sta HW_RDCARDRAM ++ sta HW_WRCARDRAM ++ .db 0xbd ; lda NNNN,x ++96$: .dw 0 ++ eor #0xff ++ and (*video_line_ptr),y ++ sta (*video_line_ptr),y ++ sta HW_RDMAINRAM ++ sta HW_WRMAINRAM ++.endif + .db 0xbd ; 1c96 -> 1c98 -> 1c9b r "lda 0x6fab,x" x=00..39 + 6$: .dw 0x6fab ; 1c99 rw + eor #0xff ; 1c98 -> 1c9b -> 1c9d r +@@ -2967,9 +3270,24 @@ + stx *x_save ; 1db0 -> 1cb2 -> 1cb4 r + tay ; 1cb2 -> 1cb4 -> 1cb5 r + lda shape_data_ptr_lo,y ; 1cb4 -> 1cb5 -> 1cb8 r y=1c..ff ++.if DHGR ++ sta 93$ ++.endif + sta 3$ ; 1cb5 -> 1cb8 -> 1cbb r ++.if DHGR ++ tax ++.endif + lda shape_data_ptr_hi,y ; 1cb8 -> 1cbb -> 1cbe r y=1c..ff ++.if DHGR ++ sta 93$ + 1 ++.endif + sta 3$ + 1 ; 1cbb -> 1cbe -> 1cc1 r ++.if DHGR ++ sta HW_WRCARDRAM ++ stx 91$ ++ sta 91$ + 1 ++ sta HW_WRMAINRAM ++.endif + lda shape_width_bytes,y ; 1cbe -> 1cc1 -> 1cc4 r y=1c..ff + clc ; 1cc1 -> 1cc4 -> 1cc5 r + adc *draw_x0 ; 1cc4 -> 1cc5 -> 1cc7 r c=0 d=0 +@@ -2977,6 +3295,11 @@ + lda *draw_x0 ; 1cc7 -> 1cc9 -> 1ccb r + lsr a ; 1cc9 -> 1ccb -> 1ccc r + bcc 0$ ; 1ccb -> 1ccc -> 1cce,1cd4 r c=0..1 ++.if DHGR ++ lda *draw_misc_aux_mask ++ eor *draw_misc_aux_mask_xor ++ sta *draw_misc_aux_mask ++.endif + lda *draw_misc_mask ; 1ccc -> 1cce -> 1cd0 r + eor *draw_misc_mask_xor ; 1cce -> 1cd0 -> 1cd2 r + sta *draw_misc_mask ; 1cd0 -> 1cd2 -> 1cd4 r +@@ -2992,9 +3315,56 @@ + lda video_line_table_hi,y ; 1ce5 -> 1ce7 -> 1cea r y=00..bc + adc #0x00 ; 1ce7 -> 1cea -> 1cec r c=0..1 d=0 + sta *video_line_ptr + 1 ; 1cea -> 1cec -> 1cee r ++.if DHGR ++ sta HW_RDCARDRAM ++ sta HW_WRCARDRAM ++ lda *draw_misc_aux_mask ++ sta *draw_misc_mask_temp ++ ldy *draw_x0 ++ stx *dimension ++90$: lda *draw_y ++ cmp #0xc0 ++ bcs 92$ ++ cpy #0x28 ++ bcs 92$ ++ .db 0xbd ; lda NNNN,x ++91$: .dw 0 ++ and *draw_misc_mask_temp ++ sta (*video_line_ptr),y ++92$: lda *draw_misc_mask_temp ++ eor *draw_misc_aux_mask_xor ++ sta *draw_misc_mask_temp ++ inx ++ iny ++ cpy *draw_x1 ++ bcc 90$ ++ ldx *dimension ++ sta HW_RDMAINRAM ++ sta HW_WRMAINRAM ++.endif + lda *draw_misc_mask ; 1cec -> 1cee -> 1cf0 r + sta *draw_misc_mask_temp ; 1cee -> 1cf0 -> 1cf2 r + ldy *draw_x0 ; 1cf0 -> 1cf2 -> 1cf4 r ++.if DHGR ; draw overflow pixel ++ lda *draw_y ++ cmp #0xc0 ++ bcs 95$ ++ dey ++ cpy #0x28 ++ bcs 94$ ++ .db 0xbd ; lda NNNN,x ++93$: .dw 0 ++ lsr a ++ and *draw_misc_mask_temp ++ eor (*video_line_ptr),y ++ and #0x40 ++ eor (*video_line_ptr),y ++ sta (*video_line_ptr),y ++94$: iny ++95$: lda *draw_misc_mask_temp ++ eor *draw_misc_mask_xor ++ sta *draw_misc_mask_temp ++.endif + 2$: lda *draw_y ; 1cf2,1d0f -> 1cf4 -> 1cf6 r + cmp #0xc0 ; 1cf4 -> 1cf6 -> 1cf8 r a=00..bc + bcs 4$ ; 1cf6 -> 1cf8 -> 1cfa r c=0 +@@ -3014,7 +3384,12 @@ + inc *draw_y ; 1d0f -> 1d11 -> 1d13 r + ldy *draw_y ; 1d11 -> 1d13 -> 1d15 r + cpy *draw_y1 ; 1d13 -> 1d15 -> 1d17 r y=01..bd ++.if DHGR ++ bcs . + 5 ++ jmp 1$ ++.else + bcc 1$ ; 1d15 -> 1d17 -> 1ce0,1d19 r c=0..1 ++.endif + ldx *x_save ; 1d17 -> 1d19 -> 1d1b r + rts ; 1d19 -> 1d1b -> 1db3 r s=ed..f6 + draw_misc_from_table: +@@ -3027,7 +3402,7 @@ + asl a ; 1d23 -> 1d24 -> 1d25 r + sta *draw_misc_ptr ; 1d24 -> 1d25 -> 1d27 r + lda #0x00 ; 1d25 -> 1d27 -> 1d29 r +- adc #0x46 ; 1d27 -> 1d29 -> 1d2b r c=0..1 d=0 ++ adc #>draw_misc_table ; 1d27 -> 1d29 -> 1d2b r c=0..1 d=0 + sta *draw_misc_ptr + 1 ; 1d29 -> 1d2b -> 1d2d r + lda *half_dimension ; 1d2b -> 1d2d -> 1d2f r + lsr a ; 1d2d -> 1d2f -> 1d30 r +@@ -3036,10 +3411,20 @@ + lsr a ; 1d31 -> 1d32 -> 1d33 r + lsr a ; 1d32 -> 1d33 -> 1d34 r + tay ; 1d33 -> 1d34 -> 1d35 r ++.if DHGR ++ lda draw_misc_aux_mask_table,y ++ sta *draw_misc_aux_mask ++ lda draw_misc_aux_mask_xor_table,y ++ sta *draw_misc_aux_mask_xor ++.endif + lda draw_misc_mask_table,y ; 1d34 -> 1d35 -> 1d38 r y=00..06 + sta *draw_misc_mask ; 1d35 -> 1d38 -> 1d3a r + lda draw_misc_mask_xor_table,y ; 1d38 -> 1d3a -> 1d3d r y=00..06 + sta *draw_misc_mask_xor ; 1d3a -> 1d3d -> 1d3f r ++.if DHGR ++ lda draw_misc_shape_xor_table,y ++ sta *draw_misc_shape_xor ++.endif + lda *half_dimension ; 1d3d -> 1d3f -> 1d41 r + and #0x1f ; 1d3f -> 1d41 -> 1d43 r + cmp #0x08 ; 1d41 -> 1d43 -> 1d45 r a=00..1f +@@ -3057,6 +3442,14 @@ + iny ; 1d57 -> 1d59 -> 1d5a r + 1$: lda (*draw_misc_ptr),y ; 1d59,1d69 -> 1d5a -> 1d5c r y=03..0c + beq 2$ ; 1d5a -> 1d5c -> 1d5e r z=0 ++.if DHGR ++ cmp #0xd0 ; sky ++ bcc 90$ ++ cmp #0xd2 ; blazer + 1 ++ bcs 90$ ++ eor *draw_misc_shape_xor ++90$: ++.endif + jsr do_draw_misc ; 1d5c -> 1d5e -> 1da6 r s=f4..fa,02 + 2$: iny ; 1db5 -> 1d61 -> 1d62 r + cpy #0x10 ; 1d61 -> 1d62 -> 1d64 r y=04..0d +@@ -3112,6 +3505,84 @@ + ldy *draw_misc_y_save ; 1d1b -> 1db3 -> 1db5 r + rts_1db5: + rts ; 1da1,1db3 -> 1db5 -> 1076,1d61,1d7d,1d82,1d87 r s=ef..f8 ++.if DHGR ++; bit 0 6 0 6 0 6 0 6 hex ++; 1111111 1111111 1111111 1111111 7f 7f 7f 7f ++; 0000000 0000000 0000000 0000000 00 00 00 00 ++; 0110011 0011001 1001100 1100110 66 4c 19 33 ++; 1001100 1100110 0110011 0011001 19 33 66 4c ++; 1111111 1111111 1111111 1111111 7f 7f 7f 7f ++; 0011001 1001100 1100110 0110011 4c 19 33 66 ++; 1100110 0110011 0011001 1001100 33 66 4c 19 ++; 1111111 1111111 1111111 1111111 7f 7f 7f 7f ++draw_misc_aux_mask_table: ++ .db 0x7f ++ .db 0x00 ++ .db 0x66 ++ .db 0x19 ++ .db 0x7f ++ .db 0x4c ++ .db 0x33 ++ .db 0x7f ++draw_misc_mask_table: ++.if 1 ; swapped for overflow pixel ++ .db 0x7f ++ .db 0x00 ++ .db 0x33 ++ .db 0x4c ++ .db 0x7f ++ .db 0x66 ++ .db 0x19 ++ .db 0x7f ++.else ++ .db 0x7f ++ .db 0x00 ++ .db 0x4c ++ .db 0x33 ++ .db 0x7f ++ .db 0x19 ++ .db 0x66 ++ .db 0x7f ++.endif ++draw_misc_aux_mask_xor_table: ++ .db 0x7f ^ 0x7f ++ .db 0x00 ^ 0x00 ++ .db 0x19 ^ 0x66 ++ .db 0x66 ^ 0x19 ++ .db 0x7f ^ 0x7f ++ .db 0x33 ^ 0x4c ++ .db 0x4c ^ 0x33 ++ .db 0x7f ^ 0x7f ++draw_misc_mask_xor_table: ++ .db 0x7f ^ 0x7f ++ .db 0x00 ^ 0x00 ++ .db 0x33 ^ 0x4c ++ .db 0x4c ^ 0x33 ++ .db 0x7f ^ 0x7f ++ .db 0x66 ^ 0x19 ++ .db 0x19 ^ 0x66 ++ .db 0x7f ^ 0x7f ++; emulate the shifting of the star blazer text with hibit clear ++; done by XORing the value below onto the shape index (d0 or d1) ++draw_misc_shape_xor_table: ++ .db 0 ++ .db 0xc8 ^ 0xd0 ++ .db 0xc8 ^ 0xd0 ++ .db 0xc8 ^ 0xd0 ++ .db 0xc8 ^ 0xd0 ++ .db 0 ++ .db 0 ++ .db 0 ++.else ++; bit 0 6 0 6 7 hex ++; 1111111 1111111 1 ff ff ++; 0000000 0000000 0 00 00 ++; 0101010 1010101 0 2a 55 ++; 1010101 0101010 0 55 2a ++; 1111111 1111111 0 7f 7f ++; 0101010 1010101 1 aa d5 ++; 1010101 0101010 1 d5 aa ++; 1111111 1111111 1 ff ff + draw_misc_mask_table: + .db 0xff ; 1db6 r + .db 0x00 ; 1db7 r +@@ -3122,15 +3593,17 @@ + .db 0xd5 ; 1dbc r + .db 0xff ; 1dbd r + draw_misc_mask_xor_table: +- .db 0x00 ; 1dbe r +- .db 0x00 ; 1dbf r +- .db 0x7f ; 1dc0 r +- .db 0x7f ; 1dc1 r +- .db 0x00 ; 1dc2 r +- .db 0x7f ; 1dc3 r +- .db 0x7f ; 1dc4 r +- .db 0x00 ; 1dc5 r ++ .db 0xff ^ 0xff ;0x00 ; 1dbe r ++ .db 0x00 ^ 0x00 ;0x00 ; 1dbf r ++ .db 0x55 ^ 0x2a ;0x7f ; 1dc0 r ++ .db 0x2a ^ 0x55 ;0x7f ; 1dc1 r ++ .db 0x7f ^ 0x7f ;0x00 ; 1dc2 r ++ .db 0xd5 ^ 0xaa ;0x7f ; 1dc3 r ++ .db 0xaa ^ 0xd5 ;0x7f ; 1dc4 r ++ .db 0xff ^ 0xff ;0x00 ; 1dc5 r ++.endif + ++; for DHGR the following code will be moved to the end to make room + .area text2 + + do_player_input: +@@ -3442,6 +3915,15 @@ + + .area data2 + ++.if DHGR ++.include "../shape/dhgr_pixel_shape_index.inc" ++.else ++.if PIXEL_SHAPE ++.include "shape_index_pixel.inc" ++.else ++.if SHAPE ++.include "shape_index.inc" ++.else + shape_data_ptr_lo: + .db = 0x80 = key waiting (uses lsr to clear it) +; used by calculate_direction_nibble +0x00d5,0x0001,abs_velocity_x_lo,word +0x00d6,0x0002,abs_velocity_x_mul0pt1875,word +0x00d8,0x0002,abs_velocity_x_mul0pt6875,word +0x00da,0x0002,abs_velocity_x_mul1pt5,word +0x00dc,0x0002,abs_velocity_x_mul5,word +; temporary save location for index into ucode_homing table +0x00e1,0x0001,homing_offset_save,byte +; saves the object number being tested against +0x00e2,0x0001,ucode_collision_or_fire_x_save,byte +; saves the index into the microcode table in ucode_collision_or_fire_ptr +0x00e3,0x0001,ucode_collision_or_fire_y_save,byte +; used by execute_ucode_homing to store base of ucode_homing table +0x00e4,0x0002,ucode_homing_ptr,word +; base of microcode for ucode_collision_test, ucode_test_fire_in_state_fn +0x00e6,0x0002,ucode_collision_or_fire_ptr,word +; following 3 variables are used by test_object_collision +; saves object1080_state value for object, controls which 0xfN section to do, +; the value is copied to this variable to speed up the repeated comparisons +0x00e8,0x0001,collision_object_state,byte +; hi bit saves the cf value that will be returned from test_object_collision, +; needed because after processing each collision, we continue to test for more +0x00e9,0x0001,collision_result,byte +; hi bit says whether we are in the state-specific section, if set it means +; a new 0xfN section header is end of the state-specific section and we finish +0x00ea,0x0001,collision_specific,byte +; 0xff = demo mode, 0x00 = play mode +0x00f0,0x0001,demo_mode,byte +; bit 7: enable joystick +; bit 6: disable sound (never set in sky blazer, uses hw_spkr_ptr instead) +; bit 5: pause/single-step +; bit 1: spacebar firing (when set, requests a simulated button press) +; bit 0: which joystick channel to read (0=x, 1=y, toggles each time) +0x00f1,0x0001,control_state,byte +; >= 0x80 = key waiting (uses lsr to clear it) 0x00f2,0x0001,key_state,byte +; added in sky blazer +; bit 7 = 1 on startup, changes to 0 if we ever see button PB0 not pressed, +; so that the button presses can be disregarded if the button is stuck down +; (a stuck button would have bypassed the joystick test in star blazer and +; allowed to use the joystick even if the axes were returning insane values) +0x00f3,0x0001,stuck_joystick,byte 0x0200,0x0002,vec_restart,word 0x0400,0x0070,object1080_onscreen,byte 0x0480,0x0070,object1080_onscreen_clipped,byte @@ -109,7 +146,12 @@ items 0x0a12,0x0001,neg_ya,code 0x0a21,0x0001,lsr_24bit_by_4,code 0x0a2b,0x0001,lsr_24bit_by_2,code -0x0a38,0x0001,get_scaled_accumulator_to_ya,code +; called with ya = a number from one of these tables: +; object1080_velocity_scale_for_position_(hi|lo) +; object1080_velocity_scale_(hi|lo) +; essentially does multiply_ya_by_accumulator, but checks for ya in +; {0, 0x80, 0x100, 0x200} first in order to do a faster computation +0x0a38,0x0001,multiply_ya_by_accumulator_optimized,code 0x0a6a,0x0001,add_ya_to_object_velocity_x,code 0x0a79,0x0001,add_ya_to_object_velocity_y,code 0x0a88,0x0001,randomize_object_position,code @@ -118,74 +160,129 @@ items 0x0aff,0x0001,copy_object_velocity,code 0x0b18,0x0001,randomize_object_position_relative,code 0x0b30,0x0001,randomize_object_velocity_relative,code -0x0b5a,0x0001,get_object_velocity_x_and_calculate_a,code -0x0b65,0x0001,get_object_velocity_y_and_calculate_a,code -0x0b82,0x0001,move_object_pos_pos,code -0x0b97,0x0001,move_object_neg_pos,code -0x0baf,0x0001,move_object_neg_neg,code -0x0bca,0x0001,move_object_pos_neg,code -0x0be2,0x0001,get_object_velocity_x_and_calculate_ya,code -0x0bed,0x0001,get_object_velocity_y_and_calculate_ya,code -0x0c06,0x0001,update_object_velocity,code -0x0c1f,0x0001,update_object_velocity_rotate_90,code -0x0c3b,0x0001,update_object_velocity_rotate_180,code -0x0c5a,0x0001,update_object_velocity_rotate_270,code +; call with y = object to calculate for +; uses coefficient from the following table: +; object1080_velocity_scale_for_position_(hi|lo) +; returns a = high byte of scaled value +0x0b5a,0x0001,get_scaled_object_velocity_x_to_a,code +0x0b65,0x0001,get_scaled_object_velocity_y_to_a,code +; call with source object in y, destination object in x +; uses coefficient from the following table, indexed by y: +; object1080_velocity_scale_for_position_(hi|lo) +; velocity can be rotated through 0, 90, 180, 270 degrees +; could be used for flinging the explosion debris outwards, +; but not executed in my trace, so may be an unused feature +0x0b82,0x0001,copy_object_position_plus_scaled_velocity,code +0x0b97,0x0001,copy_object_position_plus_scaled_velocity_rotate_90,code +0x0baf,0x0001,copy_object_position_plus_scaled_velocity_rotate_180,code +0x0bca,0x0001,copy_object_position_plus_scaled_velocity_rotate_270,code +; call with y = object to calculate for +; uses coefficient from the following table: +; object1080_velocity_scale_(hi|lo) +; returns ya = scaled value, y_save = original y value +0x0be2,0x0001,get_scaled_object_velocity_x_to_ya,code +0x0bed,0x0001,get_scaled_object_velocity_y_to_ya,code +; call with source object in y, destination object in x +; uses coefficient from the following table, indexed by y: +; object1080_velocity_scale_(hi|lo) +; velocity can be rotated through 0, 90, 180, 270 degrees +; only the 0 and 180 degrees rotation occurred in the trace +0x0c06,0x0001,copy_scaled_object_velocity,code +0x0c1f,0x0001,copy_scaled_object_velocity_rotate_90,code +0x0c3b,0x0001,copy_scaled_object_velocity_rotate_180,code +0x0c5a,0x0001,copy_scaled_object_velocity_rotate_270,code 0x0c76,0x0001,horizontal_collision,code 0x0c9d,0x0001,vertical_collision,code 0x0cc4,0x0001,horizontal_collision_and_zero,code 0x0cd0,0x0001,vertical_collision_and_zero,code 0x0cdc,0x0001,horizontal_collision_and_copy,code 0x0cec,0x0001,vertical_collision_and_copy,code -0x0cfc,0x0001,calculate_object_abs_difference0,code -0x0d06,0x0001,calculate_object_abs_difference2,code -0x0d10,0x0001,calculate_object_abs_difference1,code -0x0d1a,0x0001,calculate_object_abs_difference3,code -0x0d24,0x0001,calculate_object_abs_x_difference,code -0x0d2e,0x0001,calculate_object_abs_y_difference,code -0x0d38,0x0001,maybe_copy_one_of_arr_52a0_52e0_5320_5360_to_arr_b480,code +0x0cfc,0x0001,calculate_object_x_quadratic_countdown,code +0x0d06,0x0001,calculate_object_y_quadratic_countdown,code +0x0d10,0x0001,calculate_object_x_cubic_countdown,code +0x0d1a,0x0001,calculate_object_y_cubic_countdown,code +0x0d24,0x0001,calculate_object_x_homing_countdown,code +0x0d2e,0x0001,calculate_object_y_homing_countdown,code +0x0d38,0x0001,copy_fire_count_init_to_fire_count,code +; call with: +; x = current object +; a = value for object1080_animate_countdown +; ucode_ptr_d0 = table of shapes to index by direction nibble +; recomputes object bounds after new shape has been determined 0x0d5e,0x0001,calculate_object_direction,code +; call with: +; x = current object +; a = value for object1080_state (if nonzero) +; references ucode_animate_shape_ptr table, indexed by current object +; if there is no table, set shape to 0 (loc_0d66) +; if value passed in was nonzero (always), set object state first (loc_0db9) 0x0d6c,0x0001,calculate_object_shape,code -# example: object1080_ucode_animate_shape_4d_headquarters_radar_icbm -# -> implied start of section 0xf0 -# .db 0x72 headquarters shape -# .db 0xf2 -> start of section 0xf2 -# .db 0x76 icbm shape -# .db 0xf1 -> start of section 0xf1 -# .db 0x73 radar0 shape -# .db 0x74 radar1 shape -# .db 0x75 radar2 shape -# .db 0x74 radar1 shape -# .db 0xf9 -> repeating, & 0xf3 for start sentinel (0xf1) -# .db 0x00 sentinel -# object1080_animate_shape_index + 0x4d holds the index into above table -# loc_0da6 does a post-increment -# loc_0daf controls wraparound when sentinel >= 0xf0 reached -# loc_0dac for 0xff -# loc_0db9 for 0xf8..0xfe (repeating, & 0xf3 for the start sentinel) -# 0xf0..0xf3 value is poked into object1080_state + object, and -# something happens when it changes, if object >= 0x60 ... then loc_0dcb -# loc_0dcb for 0xf0..0xf7 -# scan the table from the beginning (except if sentinel was 0xf0) -# loc_0ddc when end of table is reached -# scan until we find the value at object1080_state + object -# loc_0ddc a = table index where start sentinel was found (or end sentinel) -# update object1080_animate_shape_index with this index (causes the -# wrapping to restart the animation sequence) ... resume at loc_0da6 -# note: the ucode_word routine seems implicated in launching this: -# 0$: ldy object1080_state - 0x10,x -# bpl 2$ -# and #0x03 -# ora #0xf0 -# jmp [vec_calculate_object_shape] +; called from: +; - reset_object_state +; - move_object_by_velocity +; in theory can also be called by calculate_object_shape by fallthru, but this +; does not happen in the trace, and analysis of all callsites reveals it can't +; example: object1080_ucode_animate_shape_4d_headquarters_radar_icbm +; -> implied start of section 0xf0 +; .db 0x72 headquarters shape +; .db 0xf2 -> start of section 0xf2 +; .db 0x76 icbm shape +; .db 0xf1 -> start of section 0xf1 +; .db 0x73 radar0 shape +; .db 0x74 radar1 shape +; .db 0x75 radar2 shape +; .db 0x74 radar1 shape +; .db 0xf9 -> set the object state to 0xf1 and then restart lookup +; .db 0x00 sentinel +; object1080_animate_shape_index + 0x4d holds the index into above table +; loc_0da6 does a post-increment +; loc_0daf controls wraparound when sentinel >= 0xf0 reached +; loc_0dac for 0xff +; finished, return via compute_object_bounds +; loc_0db9 for 0xf8..0xfe +; (note this is also the entry point from calculate_object_shape) +; set object state with the value & 0xf3 +; if new state is different than before: +; call copy_fire_count_init_to_fire_count (has a table for each state) +; then resume at loc_0dcb (scan the table from the beginning) +; loc_0dcb for 0xf0..0xf7 +; scan the table from the beginning (except if sentinel was 0xf0) +; loc_0ddc when end of table is reached +; scan until we find the value at object1080_state + object +; loc_0ddc a = table index where start sentinel was found (or end sentinel) +; update object1080_animate_shape_index with this index (causes the +; wrapping to restart the animation sequence) ... resume at loc_0da6 +; note: the ucode_word routine seems implicated in launching this: +; 0$: ldy object1080_state - 0x10,x +; bpl 2$ +; and #0x03 +; ora #0xf0 +; jmp [vec_calculate_object_shape] 0x0d81,0x0001,ucode_set_object_shape,code +; calculate multiples of abs(vel_x) +; let direction = count of truth of abs(vel_y) >= each multiple +; if abs(vel_y) >= 5 abs(vel_x), direction = 4 +; else if abs(vel_y) >= 1.5 abs(vel_x), direction = 3 +; else if abs(vel_y) >= 0.6875 abs(vel_x), direction = 2 +; else if abs(vel_y) >= 0.1875 abs(vel_x), direction = 1 +; else direction = 0 +; if vel_y is negative, let direction = 0x10 - direction +; if vel_x is negative, let direction = 8 - direction +; return y = lower nibble of direction +; analysis: +; 0.6875 is an approximation to 1/1.5 = 0.667 +; 0.1875 is an approximation to 1/5 = 0.2 +; angle breaks are 0, 10.6, 34.5, 56.3, 78.7, 90 deg +; approximation to 0, 11.25, 33.75, 56.25, 78.75, 90 deg +; tan(56.25) = 1.4966 ~= 1.5, tan(78.75) = 5.0273 ~= 5 0x0de5,0x0001,calculate_direction_nibble,code 0x0ebc,0x0001,ucode_decimal_set_0,code -0x0ec1,0x0001,ucode_decimal_set_score_var_4b80_score_var_4b00_by_mission,code +0x0ec1,0x0001,ucode_decimal_set_mission_specific_value,code 0x0ece,0x0001,ucode_decimal_set_1,code -0x0ed4,0x0001,ucode_decimal_set_score_var_4880_score_var_4800,code -0x0edc,0x0001,ucode_decimal_set_score_var_4980_score_var_4900,code -0x0ee4,0x0001,ucode_decimal_set_score_var_4a80_score_var_4a00,code -0x0eec,0x0001,ucode_decimal_set_score_var_4b80_score_var_4b00,code +0x0ed4,0x0001,ucode_decimal_set_initial_decimal_4,code +0x0edc,0x0001,ucode_decimal_set_initial_decimal_5,code +0x0ee4,0x0001,ucode_decimal_set_initial_decimal_6,code +0x0eec,0x0001,ucode_decimal_set_initial_decimal_7,code 0x0ef2,0x0001,ucode_decimal_set_save,code 0x0ef7,0x0010,ucode_decimal_set_vectors,word,code_m1 0x0f07,0x0010,ucode_update_bits_4_to_6_vectors,word,code_m1 @@ -200,174 +297,195 @@ items 0x0fb1,0x0001,adjust_score_for_reset_object,code 0x0fb9,0x0001,ucode_byte,code 0x0fdb,0x0001,go_ucode_decimal,code -# enter with ucode_word_object = 1st byte of ucode pair, a = 2nd byte -# these values come from do_ucode_word (I think the only external caller) -# does ldx *ucode_word_object first, so in below, "object" refers to this -# 1st byte: -# < 0x10: go to ucode_escape -# if 1st byte bit 0 = 1, only do the rest if demo mode (otherwise continue) -# if 1st byte bit 1 = 1, only do the rest if NOT demo mode (otherwise done) -# < 0x04: go to 2$ -# 2nd byte: -# < 0x20: clear demo mode, set mission from 2nd byte bits 0..3 -# < 0x30: set demo mode, set mission from 2nd byte bits 0..3 -# < 0xa0: vector to start game -# >= 0xa0: start game demo -# < 0x08: go to ucode_decimal, with unusual bcc -> bcc instruction -# 2nd byte bits 4..7 -# == 0x30: vector to update a decimal based on 2nd byte bits 0..2 -# .dw set_decimal_0 - 1 -# .dw set_decimal_0 - 1 -# .dw set_decimal_score_var_4b80_score_var_4b00_by_mission - 1 -# .dw set_decimal_1 - 1 -# .dw set_decimal_score_var_4880_score_var_4800 - 1 -# .dw set_decimal_score_var_4980_score_var_4900 - 1 -# .dw set_decimal_score_var_4a80_score_var_4a00 - 1 -# .dw set_decimal_score_var_4b80_score_var_4b00 - 1 -# == 0x40: decimal increment -# 2nd byte bits 0..2 are *2 and give index into decimals array -# == 0x50: decimal decrement -# 2nd byte bits 0..2 are *2 and give index into decimals array -# == 0x70: go to 0$ -# 2nd byte bits 0..2 are *2 and give index into decimals array -# == 0x20: vector to draw misc from table -# 2nd byte bits 0..2 are +1 and sent into draw_misc_from_table -# otherwise ignored -# < 0x0c: go to 6$ -# 2nd byte: -# < 0xe1: vector to draw_misc_from_table (title display, etc) -# >= 0xe1: -# 2nd byte bit 0 = 0: vector to restart -# 2nd byte bit 0 = 1: video clear rectangle -# >= 0x0c: 2nd byte is a sound channel? 01..10 -# store 1st byte into sound_status_ab80[2nd byte - 1] -# >= 0x10: 1st byte is object for opcode in 2nd byte -# 2nd byte: -# < 0x08: go to 0$ -# if object is active, change its shape using 2nd byte bits 0..1 -# < 0x0e: go to 3$ -# vector to ucode_08_to_0e_vectors routine based on 2nd byte bits 0..2 -# .dw horizontal_collision_and_zero - 1 -# .dw vertical_collision_and_zero - 1 -# .dw horizontal_collision - 1 -# .dw vertical_collision - 1 -# .dw horizontal_collision_and_copy - 1 -# .dw vertical_collision_and_copy - 1 -# = 0x0e: go to 1$ -# decrement object1080_countdown_b190, returns zf=1 terminal count? -# != 0x0f: go to ucode_byte -# if bit 7 = 0, then only do the rest if the object is inactive -# vector to routine based on 2nd byte bits 4..6 -# .dw rts_0a11 - 1 -# .dw randomize_object_position - 1 -# .dw copy_object_position - 1 -# .dw randomize_object_position_relative - 1 -# .dw move_object_pos_pos - 1 -# .dw move_object_neg_pos - 1 -# .dw move_object_neg_neg - 1 -# .dw move_object_pos_neg - 1 -# vector to routine based on 2nd byte bits 0..2 -# .dw rts_0a11 - 1 -# .dw randomize_object_velocity - 1 -# .dw copy_object_velocity - 1 -# .dw randomize_object_velocity_relative - 1 -# .dw update_object_velocity - 1 -# .dw update_object_velocity_rotate_90 - 1 -# .dw update_object_velocity_rotate_180 - 1 -# .dw update_object_velocity_rotate_270 - 1 -# if bit 3 = 1, and object1080_state[x] != 0: -# make object active and compute bounds -# else -# reset object state -# = 0x0f: if object is active, make it inactive and erase it +; enter with ucode_word_object = 1st byte of ucode pair, a = 2nd byte +; these values come from do_ucode_word (I think the only external caller) +; does ldx *ucode_word_object first, so in below, "object" refers to this +; 1st byte: +; < 0x10: go to ucode_escape +; if 1st byte bit 0 = 1, only do the rest if demo mode (otherwise continue) +; if 1st byte bit 1 = 1, only do the rest if NOT demo mode (otherwise done) +; < 0x04: go to 2$ +; 2nd byte: +; < 0x20: clear demo mode, set mission from 2nd byte bits 0..3 +; < 0x30: set demo mode, set mission from 2nd byte bits 0..3 +; < 0xa0: vector to start game +; >= 0xa0: start game demo +; < 0x08: go to ucode_decimal, with unusual bcc -> bcc instruction +; 2nd byte bits 4..7 +; == 0x30: vector to update a decimal based on 2nd byte bits 0..2 +; .dw set_decimal_0 - 1 +; .dw set_decimal_0 - 1 +; .dw set_decimal_mission_specific_value - 1 +; .dw set_decimal_1 - 1 +; .dw set_decimal_initial_decimal_4 - 1 +; .dw set_decimal_initial_decimal_5 - 1 +; .dw set_decimal_initial_decimal_6 - 1 +; .dw set_decimal_initial_decimal_7 - 1 +; == 0x40: decimal increment +; 2nd byte bits 0..2 are *2 and give index into decimals array +; == 0x50: decimal decrement +; 2nd byte bits 0..2 are *2 and give index into decimals array +; == 0x70: go to 0$ +; 2nd byte bits 0..2 are *2 and give index into decimals array +; == 0x20: vector to draw misc from table +; 2nd byte bits 0..2 are +1 and sent into draw_misc_from_table +; otherwise ignored +; < 0x0c: go to 6$ +; 2nd byte: +; < 0xe1: vector to draw_misc_from_table (title display, etc) +; >= 0xe1: +; 2nd byte bit 0 = 0: vector to restart +; 2nd byte bit 0 = 1: video clear rectangle +; >= 0x0c: 2nd byte is a sound channel? 01..10 +; store 1st byte into sound_status_active[2nd byte - 1] +; >= 0x10: 1st byte is object for opcode in 2nd byte +; 2nd byte: +; < 0x08: go to 0$ +; if object is active: set its state 0xf0..0xf3 using 2nd byte bits 0..1 +; (done by call set_object_shape which causes its shape to be recalculated) +; < 0x0e: go to 3$ +; vector to ucode_08_to_0e_vectors routine based on 2nd byte bits 0..2 +; .dw horizontal_collision_and_zero - 1 +; .dw vertical_collision_and_zero - 1 +; .dw horizontal_collision - 1 +; .dw vertical_collision - 1 +; .dw horizontal_collision_and_copy - 1 +; .dw vertical_collision_and_copy - 1 +; = 0x0e: go to 1$ +; decrement object1080_countdown2, returns zf=1 terminal count? +; != 0x0f: go to ucode_byte +; if bit 7 = 0, then only do the rest if the object is inactive +; vector to routine based on 2nd byte bits 4..6 +; .dw rts_0a11 - 1 +; .dw randomize_object_position - 1 +; .dw copy_object_position - 1 +; .dw randomize_object_position_relative - 1 +; .dw move_object_pos_pos - 1 +; .dw move_object_neg_pos - 1 +; .dw move_object_neg_neg - 1 +; .dw move_object_pos_neg - 1 +; vector to routine based on 2nd byte bits 0..2 +; .dw rts_0a11 - 1 +; .dw randomize_object_velocity - 1 +; .dw copy_object_velocity - 1 +; .dw randomize_object_velocity_relative - 1 +; .dw update_object_velocity - 1 +; .dw update_object_velocity_rotate_90 - 1 +; .dw update_object_velocity_rotate_180 - 1 +; .dw update_object_velocity_rotate_270 - 1 +; if bit 3 = 1, and object1080_state[x] != 0: +; make object active and compute bounds +; else +; reset object state +; = 0x0f: if object is active, make it inactive and erase it 0x0fdd,0x0001,ucode_word,code 0x1009,0x0001,vector_to_ucode,code 0x1016,0x0001,ucode_escape,code -# enter with a = value for ucode_word_object, ucode_ptr_c0 setup, -# y = index into table at ucode_ptr_c0 (it will be incremented twice) -# routine loads first byte from the ucode table and calls ucode_word +; enter with a = value for ucode_word_object, ucode_ptr_c0 setup, +; y = index into table at ucode_ptr_c0 (it will be incremented twice) +; routine loads first byte from the ucode table and calls ucode_word 0x106a,0x0001,do_ucode_word,code -0x107c,0x0001,decimal_zero,code -# zf=1 -> go to loc_10cd -# otherwise load ucode_object_state from object1080_state, -# and enter a loop scanning ucode table at ucode_ptr_c0 from index 0, -# when value read from ucode table is: -# == 0x00: go to loc_10cd -# >= 0xf0: see if it's the start sentinel in ucode_object_state -# if it's not then keep skipping 2 locations until end of table or found -# when found, skip 2 locations and check for more commands (0 is end of -# table, >= 0xf0 is a different section, otherwise execute + zf=0 repeat -# otherwise execute it via do_ucode_word, and check zf return because -# zf=1 means terminate the loop at loc_10cd otherwise keep executing loop -# in summary there seems to be a global section at the start of the table that -# is always executed, and a specific section to execute based on current state -0x1093,0x0001,ucode_execute_words,code +; called from: +; adjust_score: with x = 0xa when something happens to score (?) +; ucode_decimal_(inc|dec): with x = 8..0xf based on index in decimal[] array +; executes ucode_mission_init_or_decimal_reached_zero microcode for object in x +0x107c,0x0001,decimal_reached_zero,code +; zf=1 -> go to loc_10cd +; otherwise load ucode_fire_in_state_fn_count from object1080_state, +; and enter a loop scanning ucode table at ucode_ptr_c0 from index 0, +; when value read from ucode table is: +; == 0x00: go to loc_10cd +; >= 0xf0: see if it's the start sentinel in ucode_fire_in_state_fn_count +; if it's not then keep skipping 2 locations until end of table or found +; when found, skip 2 locations and check for more commands (0 is end of +; table, >= 0xf0 is a different section, otherwise execute + zf=0 repeat +; otherwise execute it via do_ucode_word, and check zf return because +; zf=1 means terminate the loop at loc_10cd otherwise keep executing loop +; in summary there seems to be a global section at the start of the table that +; is always executed, and a specific section to execute based on current state +0x1093,0x0001,execute_ucode_words,code 0x109c,0x0001,,code_ign # bug? spans ae80 and aef0 tables, don't merge them -# alternative entry point for ucode_execute_words that comes from scoring? -0x10a1,0x0001,ucode_execute_words_entry,code -# returns the current value of object1080_state for the object in x -# I think this might be to provide the correct flags return? -0x10cd,0x0001,ucode_execute_words_done,code_ign # bug? spans ae80 and aef0 tables, don't merge them -# it seems to read values from table at ucode_ptr_c0 with some complicated -# indirection (value from table = index to use for next read from table?) and -# it executes them by calling do_ucode_word, this may read adjacent value? -# ucode_object_state = counter that gets decremented to 0 -# bvar_00cb = start index in table, and is advanced by the routine -0x10d1,0x0001,ucode_execute_fire_in_state_fn,code +; alternative entry point for execute_ucode_words that comes from scoring? +0x10a1,0x0001,execute_ucode_words_entry,code +; returns the current value of object1080_state for the object in x +; this is tested by bpl to see if object went inactive, e.g. in update_object: +; jsr execute_object1080_ucode_countdown +; bpl rts_15d6 +0x10cd,0x0001,execute_ucode_words_done,code_ign # bug? spans ae80 and aef0 tables, don't merge them +; call with the following set up: +; execute_ucode_words_ptr +; ucode_fire_in_state_fn_index +; ucode_fire_in_state_fn_count +; executes ucode words cyclically until count exhausted +0x10d1,0x0001,execute_ucode_fire_in_state_fn,code 0x10ed,0x0001,adjust_score,code 0x1153,0x0001,reset_decimals,code 0x1160,0x0001,reset_object_state,code 0x11a7,0x0001,make_object_active_and_compute_bounds,code 0x11b2,0x0001,make_object_inactive_and_erase,code -# called from update_object, when: -# object1080_countdown_b120 or object1080_countdown_b190 expires +; called from update_object, when: +; object1080_countdown or object1080_countdown2 expires 0x11bd,0x0001,execute_object1080_ucode_countdown,code -# called from update_object, when: -# test_object_collision returns cf=1 +; called from update_object, when: +; test_object_collision returns cf=1 0x11cd,0x0001,execute_object1080_ucode_collision,code -# called from update_object for objects >= 40, when: -# object1080_x_hi outside [object4080_x_hi_min, object4080_x_hi_max) +; called from update_object for objects >= 40, when: +; object1080_x_hi outside [object4080_x_hi_min, object4080_x_hi_max) 0x11dd,0x0001,execute_object4080_ucode_x_outside,code -# called from update_object for objects >= 40, when: -# object1080_y_hi outside [object4080_y_hi_min, object4080_y_hi_max) +; called from update_object for objects >= 40, when: +; object1080_y_hi outside [object4080_y_hi_min, object4080_y_hi_max) 0x11ed,0x0001,execute_object4080_ucode_y_outside,code -# called from update_object for objects >= 60, when: -# object1080_state == 0xf0 -# and then test_object_fire_in_state_f0 returns cf=1 -0x11fd,0x0001,execute_object6080_ucode_fire_in_state_f0,code -# called from update_object for objects >= 60, when: -# object1080_state == 0xf1 -# and then test_object_fire_in_state_f1 returns cf=1 -0x1222,0x0001,execute_object6080_ucode_fire_in_state_f1,code -# called from update_object for objects >= 60, when: -# object1080_state == 0xf2 -# and then test_object_fire_in_state_f2 returns cf=1 -0x1247,0x0001,execute_object6080_ucode_fire_in_state_f2,code -# called from update_object for objects >= 60, when: -# object1080_state == 0xf3 -# and then test_object_fire_in_state_f3 returns cf=1 -0x126c,0x0001,execute_object6080_ucode_fire_in_state_f3,code -# called from accelerate_object_towards_another -# seems to have a chance to intervene in the homing logic -0x1291,0x0001,execute_object6080_ucode_homing,code +; called from update_object for objects >= 60, when: +; object1080_state == 0xf0 +; and then test_object_fire_in_state_f0 returns cf=1 +0x11fd,0x0001,execute_ucode_fire_in_state_f0,code +; called from update_object for objects >= 60, when: +; object1080_state == 0xf1 +; and then test_object_fire_in_state_f1 returns cf=1 +0x1222,0x0001,execute_ucode_fire_in_state_f1,code +; called from update_object for objects >= 60, when: +; object1080_state == 0xf2 +; and then test_object_fire_in_state_f2 returns cf=1 +0x1247,0x0001,execute_ucode_fire_in_state_f2,code +; called from update_object for objects >= 60, when: +; object1080_state == 0xf3 +; and then test_object_fire_in_state_f3 returns cf=1 +0x126c,0x0001,execute_ucode_fire_in_state_f3,code +; called from accelerate_object_towards_another +; call with x = current object, reads the ucode_homing table for object x +; table contains object numbers which are tested in order for whether active +; (i.e. bit 7 is set in the object1080_state field of the object being tested) +; returns y = active object number, or 0 if none (and zf as appropriate) +; the general section is tested first, followed by a state-specific section +; e.g. object x is in state f2, it will only check the general and f2 section +0x1291,0x0001,execute_ucode_homing,code +; call with x = current object, performs the x and y homing countdowns +; when x or y acceleration is to occur, does the following steps: +; - reset the x or y coming countdown by redoing the abs computation +; - call execute_ucode_homing to choose the object to home to +; - if found, calculate x or y difference and adjust x or y velocity by this +; (sense of adjustment is controllable and presumably the scale is 1/256) 0x12e1,0x0001,accelerate_object_towards_another,code 0x133f,0x0001,sign_extend_a_to_ya_asl_by_4,code -0x1350,0x0001,accelerate_object_somehow,code +0x1350,0x0001,accelerate_object_by_constant,code 0x1388,0x0001,move_object_by_velocity,code +; call with x = object whose collisions are to be tested +; looks up microcode table from object1080_ucode_collision_test_ptr +; the table contains byte values of objects to be tested against +; there is a general section followed by state-specific 0xfN sections 0x13d0,0x0001,test_object_collision,code -0x1447,0x0001,accelerate_object_anyhow,code +0x1447,0x0001,accelerate_object_by_velocity,code 0x149b,0x0001,ucode_test_fire_all_objects_active,code 0x14aa,0x0001,ucode_test_fire_all_objects_inactive,code -# opcode is followed by null-terminated list of objects to test -# note: some of these opcodes never executed in the trace -# references to object1080_y1 + 0x60 should be object1080_state - 0x10 -# 0x01 loc_149b test that all objects are active (object1080_state >= 0x80) -# 0x02 loc_14aa test that all objects are inactive (object1080_state < 0x80) -# 0x03 loc_14d0 test that any object is active (object1080_state >= 0x80) -# 0x04 loc_14e0 test that any object is inactive (object1080_state >= 0x80) -# otherwise fall into: -# loc_14c9: cf=0 -# loc_14ca: return cf (cf=1 from cmp equality), a=object1080_state (for zf?) +; opcode is followed by null-terminated list of objects to test +; note: some of these opcodes never executed in the trace +; 0x01 loc_149b test that all objects are active (object1080_state >= 0x80) +; 0x02 loc_14aa test that all objects are inactive (object1080_state < 0x80) +; 0x03 loc_14d0 test that any object is active (object1080_state >= 0x80) +; 0x04 loc_14e0 test that any object is inactive (object1080_state >= 0x80) +; otherwise fall into: +; loc_14c9: cf=0 +; loc_14ca: return cf (cf=1 from cmp equality), a=object1080_state (for zf?) 0x14b9,0x0001,ucode_test_object_fire,code 0x14d0,0x0001,ucode_test_fire_any_object_active,code 0x14e0,0x0001,ucode_test_fire_any_object_inactive,code @@ -379,34 +497,78 @@ items 0x1549,0x0001,test_object_fire_in_state_f2,code 0x1569,0x0001,test_object_fire_in_state_f3,code 0x1589,0x0001,objects_init,code -0x1595,0x0001,objects_init_entry,code +0x1595,0x0001,objects_reinit,code +; maybe update object whose number is in cyclic_object +; then increment cyclic_object so it cycles through 0x10..0x7f +; cf=1 return indicates it is time to check the keyboard +0x15b2,0x0001,cyclic_update_object,code 0x15d7,0x0001,update_object_player,code 0x15ee,0x0001,update_object,code 0x15ff,0x0001,update_object_entry,code -0x16ae,0x0001,all_init,code -# takes mission number in x, does not set mission if x = 0 +0x16ae,0x0001,init_mission,code +; takes mission number in x, does not set mission if x = 0 0x16f1,0x0001,clear_demo_set_mission,code -# takes mission number in x, does not set mission if x = 0 +; takes mission number in x, does not set mission if x = 0 0x16f7,0x0001,set_demo_set_mission,code 0x16fd,0x0001,inc_mission,code 0x1708,0x0001,init_game,code,,10000 # suppress local for patch 0x1719,0x0001,start_game_demo,code 0x171b,0x0001,start_game,code,,10000 # suppress local for patch -0x1750,0x0001,test_key,code -0x1797,0x0001,read_buttons,code +; in the below, 0$ is outer game loop, 4$ is inner game loop +; 0$: cancel previous keyboard input +; 1$: if new keyboard input is present: +; move incoming key to key_state (high bit set = key present) +; strobe keyboard interface to clear it +; check for control characters, may restart game via vec_start_game +; 2$: if in demo mode: +; call test_start_game, may start game via vec_start_game +; 3$: if in single-step mode: +; if no key present, return to 1$ +; 4$: if sound enabled: +; make "update_sound_count" repeated calls to cyclic_update_sound +; 6$: make "update_object_count" repeated calls to cyclic_update_object +; (this handles all of the in-game display updating as a side effect) +; if any of these calls return cf=1, abort the loop and return to 0$ +; otherwise, upon completion of the loop, return to 4$ +0x1750,0x0001,start_mission,code +; if joystick button or spacebar is pressed, start game via vec_start_game +; clears single-step mode and sets joystick mode according to input source +0x1797,0x0001,test_start_game,code 0x17b1,0x0001,not_demo_vector_to_start_game,code +; ctrl-r (0x92): restart game via vec_start_game (clears single-step mode) +; ctrl-c (0x83): toggle bit 7 of control_state (enable joystick) +; ctrl-s (0x93): toggle bit 6 of control_state (disable sound) +; esc (0x9b): toggle bit 5 of control_state (pause/single-step) 0x17b6,0x0001,check_control_characters,code +; the entry point to the executable +; in star blazer it had joystick detection code, deleted in sky blazer +; so in sky blazer it just jumps to init_game via vec_init_game 0x17d1,0x0001,start,code +; the next 3 routines were added in sky blazer in space freed up by +; the deletion of the joystick detection code, it seems to have been +; manually patched rather than reassembled as it is not tightly packed +0x17d8,0x0001,patch_video_init,code +0x17e0,0x0001,patch_read_pb0,code +0x17f0,0x0001,patch_toggle_sound,code 0x1800,0x0001,divide_a_by_y,code 0x1829,0x0001,multiply_ya_by_accumulator,code 0x1873,0x0001,,code # unreachable 0x187a,0x0001,random_init,code 0x1881,0x0001,random_byte,code 0x18a2,0x0001,sound_init,code -0x18b0,0x0001,next_sound,code +0x18b0,0x0001,cyclic_update_sound,code +0x18bf,0x0001,update_sound,code +; toggles in sky blazer, HW_SPKR (sound on) or HW_TAPEOUT (sound off) +; apparently this is to equalize the execution speed when sound is off +0x18ed,0x0001,hw_spkr_ptr,word +0x1917,0x0001,update_sound_reset,code +; enter here when there are still more repeats of the tone to be played back +0x1929,0x0001,update_sound_repeat,code 0x1937,0x0001,video_init,code 0x1999,0x0001,restart,code 0x19b9,0x0001,video_clear_rectangle,code +; selects 0th, 1st or 2nd third of the screen in hi-res graphics memory layout +0x19d6,0x0003,times_40_table,byte 0x19da,0x0001,compute_object_bounds,code 0x1a27,0x0007,pixel_data_table_left,byte 0x1a2e,0x0007,pixel_data_table_right,byte @@ -438,8 +600,28 @@ items 0x1da6,0x0001,do_draw_misc,code 0x1db6,0x0008,draw_misc_mask_table,byte 0x1dbe,0x0008,draw_misc_mask_xor_table,byte -# returns cf=1 if firing (random for demo mode) +0x1e00,0x0001,do_player_input,byte +; returns cf=1 if firing (random for demo mode) 0x1e03,0x0001,test_player_fire,code +0x1e23,0x0001,spacebar_firing,code +; if in demo mode, generates a random player input +; otherwise tests the keyboard, joystick, joystick buttons +0x1e2a,0x0001,player_input,byte +0x1f80,0x0010,sound_table_repeat_countdown,byte +; read-only lookup table for initial sound period +0x1f90,0x0010,sound_table_period,byte +; read-only lookup table for sound period change before each repeat +0x1fa0,0x0010,sound_table_period_delta,byte +; read-only lookup table for sound period that triggers reset to initial values +0x1fb0,0x0010,sound_table_period_limit,byte +; read-only lookup table for initial sound duration +0x1fc0,0x0010,sound_table_duration,byte +; read-only lookup table for sound duration change before each repeat +0x1fd0,0x0010,sound_table_duration_delta,byte +; read-only lookup table for initial sound delay between each repeat +0x1fe0,0x0010,sound_table_delay,byte +; read-only lookup table for sound delay change before each repeat +0x1ff0,0x0010,sound_table_delay_delta,byte 0x2000,0x2000,HIRES_SCREEN,byte 0x4000,0x0100,shape_data_ptr_lo,byte,byte 0x4100,0x0100,shape_data_ptr_hi,byte,byte @@ -447,40 +629,53 @@ items 0x4300,0x0100,shape_height,byte 0x4400,0x0100,shape_size_bytes,byte 0x4500,0x0100,shape_width,byte -# 0x20 entries of 0x10 bytes +; 0x20 entries of 0x10 bytes 0x4600,0x0200,draw_misc_table,byte,,10000 # suppress local for patch -0x4800,0x0001,score_var_4800,byte -0x4801,0x000f,score_table_4801,byte -0x4810,0x0070,object1080_countdown_b120_init,byte -0x4880,0x0001,score_var_4880,byte -0x4881,0x000f,score_table_4881,byte -0x4890,0x0070,object1080_countdown_b190_init,byte -0x4900,0x0001,score_var_4900,byte -0x4901,0x000f,score_table_4901,byte -0x4910,0x0070,object1080_animate0,byte -0x4980,0x0001,score_var_4980,byte -0x4981,0x000f,score_table_4981,byte -0x4990,0x0070,object1080_animate1,byte -0x4a00,0x0001,score_var_4a00,byte -0x4a01,0x000f,score_table_4a01,byte -# 0x4a10 spare -0x4a80,0x0001,score_var_4a80,byte -0x4a81,0x000f,score_table_4a81,byte -# 0x4a90 spare -0x4b00,0x0001,score_var_4b00,byte -0x4b01,0x000f,score_table_4b01,byte -0x4b10,0x0070,object1080_4b10,byte -0x4b80,0x0001,score_var_4b80,byte -0x4b81,0x000f,score_table_4b81,byte -0x4b90,0x0070,object1080_4b90,byte +; initial fuel (hi 2 digits) +0x4800,0x0001,initial_decimal_plus_9,byte +0x4801,0x000f,mission_table_clip_x0,byte +0x4810,0x0070,object1080_countdown_init,byte +; initial fuel (lo 2 digits) +0x4880,0x0001,initial_decimal_plus_8,byte +0x4881,0x000f,mission_table_clip_x1,byte +0x4890,0x0070,object1080_countdown2_init,byte +; initial bomb (hi 2 digits) +0x4900,0x0001,initial_decimal_plus_0xb,byte +0x4901,0x000f,mission_table_clip_y0,byte +0x4910,0x0070,object1080_animate_countdown_init,byte +; initial bomb (lo 2 digits) +0x4980,0x0001,initial_decimal_plus_0xa,byte +0x4981,0x000f,mission_table_clip_y1,byte +; non-zero for missiles, means shape is based on direction +0x4990,0x0070,object1080_animate_by_direction,byte +; initial ship left (hi 2 digits) +0x4a00,0x0001,initial_decimal_plus_0xd,byte +0x4a01,0x000f,mission_table_update_object_count,byte +; 0x4a10 spare +; initial ship left (lo 2 digits) +0x4a80,0x0001,initial_decimal_plus_0xc,byte +0x4a81,0x000f,mission_table_update_sound_count,byte +; 0x4a90 spare +; initial bonus/1000 (hi 2 digits) +0x4b00,0x0001,initial_decimal_plus_0xf,byte +0x4b01,0x000f,mission_table_decimal_plus_5,byte +0x4b10,0x0070,object1080_score,byte +; initial bonus/1000 (lo 2 digits) +0x4b80,0x0001,initial_decimal_plus_0xe,byte +0x4b81,0x000f,mission_table_decimal_plus_4,byte +; used by cyclic_update_object +; if object is active it gets updated +; otherwise a delay loop runs controlled by this +; probably to control game speed and sound generation +0x4b90,0x0070,object1080_dummy_update,byte 0x4c00,0x0070,object1080_velocity_x_random_base,byte 0x4c70,0x0070,object1080_velocity_x_random_range,byte 0x4ce0,0x0070,object1080_velocity_y_random_base,byte 0x4d50,0x0070,object1080_velocity_y_random_range,byte -# 0x4dc0 spare -0x4ed0,0x0030,object4070_4ed0,byte # might be bigger -# 0x4f00 spare -0x4f40,0x0040,object4080_4f40,byte +0x4dc0,0x0070,object1080_velocity_scale_for_position_hi,byte +0x4e30,0x0070,object1080_velocity_scale_for_position_lo,byte +0x4ea0,0x0070,object1080_velocity_scale_hi,byte +0x4f10,0x0070,object1080_velocity_scale_lo,byte 0x4f80,0x0040,object4080_x_random_base,byte 0x4fc0,0x0040,object4080_x_random_range,byte 0x5000,0x0040,object4080_x_hi_min,byte @@ -489,28 +684,74 @@ items 0x50c0,0x0040,object4080_y_random_range,byte 0x5100,0x0040,object4080_y_hi_min,byte 0x5140,0x0040,object4080_y_hi_max,byte -0x5180,0x0030,object5080_x_difference,byte -0x51b0,0x0030,object5080_y_difference,byte -0x5240,0x0030,object5080_difference_5240,byte -0x5270,0x0030,object5080_difference_5270,byte -0x52a0,0x0030,object5080_difference_52a0,byte -0x52d0,0x0030,object5080_difference_52d0,byte +; read-only table used for homing movements +; sign controls homing sense (- towards, + away from) +; absolute value controls how often x acceleration happens +; -1 for missile +; -4 for helicopter_enemy_plane +; -4 for tank +; other objects do not home in the x direction +0x5180,0x0030,object5080_x_homing_sense,byte +; read-only table used for homing movements +; sign controls homing sense (- towards, + away from) +; absolute value controls how often y acceleration happens +; -3 for bird +; -1 for missile +; -12,-8,-4,-10,-6 for helicopter_enemy_plane +; other objects do not home in the y direction +0x51b0,0x0030,object5080_y_homing_sense,byte +; read-only table used for quadratic movements +; frequency and direction of x acceleration by constant +0x5240,0x0030,object5080_x_quadratic_sense,byte +; read-only table used for cubic movements +; frequency and direction of x acceleration by velocity +; note: positive used for bullets (means it will get slower) +; note: negative used for missiles (means it will get faster; +; used in conjunction with homing so not exactly a cubic path) +0x5270,0x0030,object5080_x_cubic_sense,byte +; read-only table used for quadratic movements +; frequency and direction of y acceleration by constant +0x52a0,0x0030,object5080_y_quadratic_sense,byte +; read-only table used for cubic movements +; frequency and direction of y acceleration by velocity +; note: negative used for missiles (means it will get faster; +; used in conjunction with homing so not exactly a cubic path) +0x52d0,0x0030,object5080_y_cubic_sense,byte 0x5300,0x0020,object6080_fire_count_init_in_state_f0,byte -# used from execute_object6080_ucode_fire_in_state_f0 -0x5320,0x0020,object6080_5320,byte +; read-only table accessed by execute_ucode_fire_in_state_f0 +; how many instructions execute_ucode_fire_in_state_fn will execute +0x5320,0x0020,object6080_ucode_fire_in_state_f0_count,byte 0x5340,0x0020,object6080_fire_count_init_in_state_f1,byte -# used from execute_object6080_ucode_fire_in_state_f1 -0x5360,0x0020,object6080_5360,byte +; read-only table accessed by execute_ucode_fire_in_state_f1 +; how many instructions execute_ucode_fire_in_state_fn will execute +0x5360,0x0020,object6080_ucode_fire_in_state_f1_count,byte 0x5380,0x0020,object6080_fire_count_init_in_state_f2,byte -# used from execute_object6080_ucode_fire_in_state_f2 -0x53a0,0x0020,object6080_53a0,byte +; read-only table accessed by execute_ucode_fire_in_state_f2 +; how many instructions execute_ucode_fire_in_state_fn will execute +0x53a0,0x0020,object6080_ucode_fire_in_state_f2_count,byte 0x53c0,0x0020,object6080_fire_count_init_in_state_f3,byte -# used from execute_object6080_ucode_fire_in_state_f2 -0x53e0,0x0020,object6080_53e0,byte -# the partitioning below is approximate and just tries to cover everything +; read-only table accessed by execute_ucode_fire_in_state_f3 +; how many instructions execute_ucode_fire_in_state_fn will execute +0x53e0,0x0020,object6080_ucode_fire_in_state_f3_count,byte +; the partitioning below is approximate and just tries to cover everything 0x5400,0x0020,,word 0x5420,0x00e0,object1080_ucode_animate_shape_ptr,word -0x5500,0x0020,object0010_ucode_init_or_zero_ptr,word +; objects 0..0xf have special purposes in the game +; (actually not really objects, but it is convenient to treat them as such) +; 0 does not have microcode +; 1..5 have microcode: the initialization code for each mission +; 6 has microcode: draws "great performance", "bonus" +; 7 has microcode: draws "great performance", "game over" +; 8..0xf have microcode to execute when each decimal[] is decremented to 0 +; 8 for decimal = score/10: does not have microcode +; 9 for decimal + 2 = high score/10: does not have microcode +; 0xa for decimal + 4 = spare: runs when something happens to score (?) +; 0xb for decimal + 6 = mission: does not have microcode +; 0xc for decimal + 8 = fuel: has microcode +; 0xd for decimal + 0xa = bomb: has microcode +; 0xe for decimal + 0xc = ship left: has microcode +; 0xf for decimal + 0xe = bonus/1000: has microcode +0x5500,0x0020,object0010_ucode_mission_init_or_decimal_reached_zero_ptr,word 0x5520,0x00e0,object1080_ucode_countdown_ptr,word 0x5600,0x0020,,word 0x5620,0x00e0,object1080_ucode_collision_test_ptr,word @@ -529,21 +770,26 @@ items 0x5b00,0x0040,object6080_ucode_fire_in_state_f2_ptr,word 0x5b40,0x0040,object6080_ucode_test_fire_in_state_f3_ptr,word 0x5b80,0x0040,object6080_ucode_fire_in_state_f3_ptr,word -# 0x5bc0 padding -# 0x5c00 shape data -# 0x8c08 padding -# 0x8e00 ucode data -# 0x9ded end of image +; 0x5bc0 padding +; 0x5c00 shape data +; 0x8c08 padding +; 0x8e00 ucode data +; 0x9ded end of image 0xa800,0x0001,x_table_times2_div7_plus_5b,byte 0xa900,0x0001,x_table_times2_mod7_minus_03,byte 0xaa00,0x0001,video_line_table_lo,byte 0xaac0,0x0001,video_line_table_hi,byte -0xab80,0x0001,sound_status_ab80,byte -# ab90? -0xaba0,0x0001,sound_status_aba0,byte -0xabb0,0x0001,sound_status_abb0,byte -0xabc0,0x0001,sound_status_abc0,byte -0xabd0,0x0001,sound_status_abd0,byte +; 0 => sound is not playing +; positive => sound is to be initialized +; negative => sound is playing +0xab80,0x0001,sound_status_active,byte +; countdown for how many times the sound plays a tone before terminating +0xab90,0x0001,sound_status_repeat_countdown,byte +0xaba0,0x0001,sound_status_period,byte +0xabb0,0x0001,sound_status_duration,byte +0xabc0,0x0001,sound_status_delay,byte +; countdown for how many update calls until next repeat of the sound plays +0xabd0,0x0001,sound_status_delay_countdown,byte 0xabe0,0x0070,object1080_shape,byte 0xac50,0x0070,object1080_x_hi,byte 0xacc0,0x0070,object1080_y_hi,byte @@ -551,51 +797,78 @@ items 0xada0,0x0070,object1080_x1,byte 0xae10,0x0070,object1080_y0,byte 0xae80,0x0070,object1080_y1,byte -# often a value 0xf0..0xf3 to identify relevant section in ucode table, -# but I think it has other purposes too (bit 7 may mean object is active?) +; positive => object is disabled +; negative => object is enabled, in state 0xf0..0xf3 +; the object can be enabled/disabled in various places: +; - objects_init: zeros object1080_state +; - objects_reinit: clears hi bit of object1080_state +; - make_object_active_and_compute_bounds: sets hi bit of object1080_state +; (presumably this relies on some earlier code to set the 0xf0..0xf3 state) +; - make_object_inactive_and_erase: clears hi bit of object1080_state +; the state 0xf0..0xf3 can be changed in the following ways: +; - loc_0daf: comes from microcode value 0xf8..0xfb in animate shape table +; - loc_0db9: calling calculate_object_shape, passing a non-zero value in a +; - reset_object_state (from microcode instruction): sets it back to 0xf0 0xaef0,0x0070,object1080_state,byte 0xaf60,0x0070,object1080_velocity_x_hi,byte 0xafd0,0x0070,object1080_velocity_y_hi,byte 0xb040,0x0070,object1080_velocity_x_lo,byte 0xb0b0,0x0070,object1080_velocity_y_lo,byte -0xb120,0x0070,object1080_countdown_b120,byte -0xb190,0x0070,object1080_countdown_b190,byte +0xb120,0x0070,object1080_countdown,byte +0xb190,0x0070,object1080_countdown2,byte 0xb200,0x0070,object1080_x_lo,byte 0xb270,0x0070,object1080_y_lo,byte -0xb2e0,0x0070,object1080_animate2,byte +; countdown to when move_object_by_velocity calls set_object_shape +0xb2e0,0x0070,object1080_animate_countdown,byte 0xb350,0x0070,object1080_animate_shape_index,byte -0xb3c0,0x0030,object5080_abs_x_difference,byte -0xb3f0,0x0030,object5080_abs_y_difference,byte -# accelerate_object_somehow -# used as a countdown for whether x should be accelerated by +/- 0x4c -0xb420,0x0030,object5080_abs_difference_b420,byte -# accelerate_object_somehow -# used as a countdown for whether y should be accelerated by +/- 0x40 -0xb450,0x0030,object5080_abs_difference_b450,byte -# accelerate_object_anyhow -# used as a countdown for whether x should be accelerated by calculated value -0xb480,0x0030,object5080_abs_difference_b480,byte -# accelerate_object_anyhow -# used as a countdown for whether y should be accelerated by calculated value -0xb4b0,0x0030,object5080_abs_difference_b4b0,byte +; initialized with the abs value of object5080_x_homing_sense +; when = 0, it means object does not home in x direction +; when > 0, it is the countdown until next x acceleration +; (each time it reaches 0 it is reset from the abs computation) +0xb3c0,0x0030,object5080_x_homing_countdown,byte +; initialized with the abs value of object5080_y_homing_sense +; when = 0, it means object does not home in y direction +; when > 0, it is the countdown until next y acceleration +; (each time it reaches 0 it is reset from the abs computation) +0xb3f0,0x0030,object5080_y_homing_countdown,byte +; accelerate_object_by_constant +; used as a countdown for whether x should be accelerated by +/- 0x4c +; makes player fly away, tank drive away, etc +0xb420,0x0030,object5080_x_quadratic_countdown,byte +; accelerate_object_by_constant +; used as a countdown for whether y should be accelerated by +/- 0x40 +; makes player fly away/fall to the ground, etc +0xb450,0x0030,object5080_y_quadratic_countdown,byte +; accelerate_object_by_velocity +; used as a countdown for whether x should be accelerated by x velocity +; (divided by 1024?) -- should result in a cubic movement +0xb480,0x0030,object5080_x_cubic_countdown,byte +; accelerate_object_by_velocity +; used as a countdown for whether y should be accelerated by y velocity +; (divided by 1024?) -- should result in a cubic movement +0xb4b0,0x0030,object5080_y_cubic_countdown,byte 0xb4e0,0x0020,object6080_fire_count,byte -# used from execute_object6080_ucode_fire_in_state_f0 -0xb500,0x0020,object6080_b500,byte -# used from execute_object6080_ucode_fire_in_state_f1 -0xb520,0x0020,object6080_b520,byte -# used from execute_object6080_ucode_fire_in_state_f2 -0xb540,0x0020,object6080_b540,byte -# used from execute_object6080_ucode_fire_in_state_f3 -0xb560,0x0020,object6080_b560,byte +; used from execute_ucode_fire_in_state_f0 +; offset to next instruction execute_ucode_fire_in_state_fn will execute +0xb500,0x0020,object6080_ucode_fire_in_state_f0_index,byte +; used from execute_ucode_fire_in_state_f1 +; offset to next instruction execute_ucode_fire_in_state_fn will execute +0xb520,0x0020,object6080_ucode_fire_in_state_f1_index,byte +; used from execute_ucode_fire_in_state_f2 +; offset to next instruction execute_ucode_fire_in_state_fn will execute +0xb540,0x0020,object6080_ucode_fire_in_state_f2_index,byte +; used from execute_ucode_fire_in_state_f3 +; offset to next instruction execute_ucode_fire_in_state_fn will execute +0xb560,0x0020,object6080_ucode_fire_in_state_f3_index,byte 0xc000,0x0001,HW_KBD,byte 0xc010,0x0001,HW_KBDSTRB,byte +0xc020,0x0001,HW_TAPEOUT,byte 0xc030,0x0001,HW_SPKR,byte 0xc050,0x0001,HW_TXTCLR,byte 0xc052,0x0001,HW_MIXCLR,byte 0xc054,0x0001,HW_PAGE1,byte 0xc057,0x0001,HW_HIRES,byte 0xc061,0x0001,HW_PB0,byte -0xc062,0x0001,HW_PB1,byte 0xc065,0x0001,HW_PADDL1,byte 0xc070,0x0001,HW_PTRIG,byte @@ -737,6 +1010,7 @@ shapes 0xff,blank objects +0x00,spare 0x01,init_mission_1 0x02,init_mission_2 0x03,init_mission_3 @@ -744,11 +1018,14 @@ objects 0x05,init_mission_5 0x06,draw_great_performance_bonus 0x07,draw_great_performance_game_over -0x0a,set_mission_7 -0x0c,draw_empty_fuel -0x0d,init_ship -0x0e,draw_high_score -0x0f,draw_bonus +0x08,spare +0x09,spare +0x0a,something_happened_to_score +0x0b,spare +0x0c,fuel_exhausted +0x0d,bomb_exhausted +0x0e,ship_left_exhausted +0x0f,bonus_exhausted 0x10,draw_fuel_bomb 0x11,draw_ship_left 0x12,draw_high_score_copyright diff --git a/star_blazer/sky_blazer0_segments.txt b/star_blazer/sky_blazer0_segments.txt index 01fd99c..988d233 100644 --- a/star_blazer/sky_blazer0_segments.txt +++ b/star_blazer/sky_blazer0_segments.txt @@ -9,7 +9,5 @@ [0x1f80, 0x2000) [0x4000, 0x4a10) [0x4a80, 0x4a90) -[0x4b00, 0x4dc0) -[0x4ed0, 0x4f00) -[0x4f40, 0x8c00) +[0x4b00, 0x8c00) [0x8c00, 0x9beb) diff --git a/star_blazer/sky_blazer_object_defs.inc b/star_blazer/sky_blazer_object_defs.inc index b13ef3e..d82e022 100644 --- a/star_blazer/sky_blazer_object_defs.inc +++ b/star_blazer/sky_blazer_object_defs.inc @@ -265,10 +265,10 @@ SECTION_F0 = 0xf0 SECTION_F1 = 0xf1 SECTION_F2 = 0xf2 SECTION_F3 = 0xf3 -SECTION_F8_REPEAT = 0xf8 -SECTION_F9_REPEAT = 0xf9 -SECTION_FA_REPEAT = 0xfa -SECTION_FB_REPEAT = 0xfb +SECTION_F8_SET_STATE_F0 = 0xf8 +SECTION_F9_SET_STATE_F1 = 0xf9 +SECTION_FA_SET_STATE_F2 = 0xfa +SECTION_FB_SET_STATE_F3 = 0xfb SECTION_FF = 0xff ; word-wide sections @@ -321,17 +321,17 @@ UCODE_DECIMAL_ADJUST = 0x7000 ; decimal set UCODE_DECIMAL_SET_0 = 0x100 -UCODE_DECIMAL_SET_SCORE_VAR_4B80_SCORE_VAR_4B00_BY_MISSION = 0x200 +UCODE_DECIMAL_SET_MISSION_SPECIFIC_VALUE = 0x200 UCODE_DECIMAL_SET_1 = 0x300 -UCODE_DECIMAL_SET_SCORE_VAR_4880_SCORE_VAR_4800 = 0x400 -UCODE_DECIMAL_SET_SCORE_VAR_4980_SCORE_VAR_4900 = 0x500 -UCODE_DECIMAL_SET_SCORE_VAR_4A80_SCORE_VAR_4A00 = 0x600 -UCODE_DECIMAL_SET_SCORE_VAR_4B80_SCORE_VAR_4B00 = 0x700 +UCODE_DECIMAL_SET_INITIAL_DECIMAL_4 = 0x400 +UCODE_DECIMAL_SET_INITIAL_DECIMAL_5 = 0x500 +UCODE_DECIMAL_SET_INITIAL_DECIMAL_6 = 0x600 +UCODE_DECIMAL_SET_INITIAL_DECIMAL_7 = 0x700 ; decimal other UCODE_DECIMAL_0_SCORE = 0x0000 UCODE_DECIMAL_1_HIGH_SCORE = 0x0100 -UCODE_DECIMAL_2 = 0x0200 +UCODE_DECIMAL_2_SPARE = 0x0200 UCODE_DECIMAL_3_MISSION = 0x0300 UCODE_DECIMAL_4_FUEL = 0x0400 UCODE_DECIMAL_5_BOMB = 0x0500 @@ -345,7 +345,7 @@ UCODE_DRAW_MISC_CLEAR_RECTANGLE = 0xe100 ; draw misc bits 0 to 4 UCODE_DRAW_MISC_DECIMAL_0_SCORE = 0x0000 UCODE_DRAW_MISC_DECIMAL_1_HIGH_SCORE = 0x0100 -UCODE_DRAW_MISC_DECIMAL_2 = 0x0200 +UCODE_DRAW_MISC_DECIMAL_2_SPARE = 0x0200 UCODE_DRAW_MISC_DECIMAL_3_MISSION = 0x0300 UCODE_DRAW_MISC_DECIMAL_4_FUEL = 0x0400 UCODE_DRAW_MISC_DECIMAL_5_BOMB = 0x0500 @@ -402,27 +402,39 @@ UCODE_SOUND_EFFECT_D_EXPLOSION = 0x0d00 UCODE_SOUND_EFFECT_E_EXPLOSION = 0x0e00 UCODE_SOUND_EFFECT_F_EXPLOSION = 0x0f00 -; the following occur by themselves +; the following take an object number >= 0x10 in the low byte +; (if the object number would be < 0x10 then it's an escape as above) +; the following occur by themselves (not a bitmap): + +; 0x0000 does not occur because it would indicate the end of the microcode? +; 0x0400, 0x0500, 0x0600, 0x0700: synonyms for 0x0000, 0x0100, 0x0200, 0x0300 ; byte +UCODE_IF_ACTIVE_SET_STATE_F1 = 0x0100 +UCODE_IF_ACTIVE_SET_STATE_F2 = 0x0200 +UCODE_IF_ACTIVE_SET_STATE_F3 = 0x0300 +UCODE_IF_ACTIVE_SET_STATE_F0 = 0x0400 UCODE_HORIZONTAL_COLLISION_AND_ZERO = 0x0800 UCODE_VERTICAL_COLLISION_AND_ZERO = 0x0900 UCODE_HORIZONTAL_COLLISION = 0x0a00 UCODE_VERTICAL_COLLISION = 0x0b00 UCODE_HORIZONTAL_COLLISION_AND_COPY = 0x0c00 UCODE_VERTICAL_COLLISION_AND_COPY = 0x0d00 +UCODE_DECREMENT_COUNTDOWN2 = 0x0e00 UCODE_INACTIVATE_OBJECT = 0x0f00 -; the following are used with UCODE_UPDATE_OBJECT(_IF_INACTIVE) +; the following occur as a bitmap, used with UCODE_UPDATE_OBJECT(_IF_INACTIVE) +; for UCODE_UPDATE_OBJECT_IF_INACTIVE, one of the *POSITION* bits must be set, +; otherwise the opcode would be < 0x1000 (the values that occur by themselves) ; update bits 0 to 2 UCODE_RANDOMIZE_OBJECT_VELOCITY = 0x0100 UCODE_COPY_OBJECT_VELOCITY = 0x0200 UCODE_RANDOMIZE_OBJECT_VELOCITY_RELATIVE = 0x0300 -UCODE_UPDATE_OBJECT_VELOCITY = 0x0400 -UCODE_UPDATE_OBJECT_VELOCITY_ROTATE_90 = 0x0500 -UCODE_UPDATE_OBJECT_VELOCITY_ROTATE_180 = 0x0600 -UCODE_UPDATE_OBJECT_VELOCITY_ROTATE_270 = 0x0700 +UCODE_COPY_SCALED_OBJECT_VELOCITY = 0x0400 +UCODE_COPY_SCALED_OBJECT_VELOCITY_ROTATE_90 = 0x0500 +UCODE_COPY_SCALED_OBJECT_VELOCITY_ROTATE_180 = 0x0600 +UCODE_COPY_SCALED_OBJECT_VELOCITY_ROTATE_270 = 0x0700 ; update bit 3 UCODE_RESET_OBJECT = 0x0000 @@ -432,10 +444,10 @@ UCODE_ACTIVATE_OBJECT = 0x0800 UCODE_RANDOMIZE_OBJECT_POSITION = 0x1000 UCODE_COPY_OBJECT_POSITION = 0x2000 UCODE_RANDOMIZE_OBJECT_POSITION_RELATIVE = 0x3000 -UCODE_MOVE_OBJECT_POS_POS = 0x4000 -UCODE_MOVE_OBJECT_NEG_POS = 0x5000 -UCODE_MOVE_OBJECT_NEG_NEG = 0x6000 -UCODE_MOVE_OBJECT_POS_NEG = 0x7000 +UCODE_COPY_OBJECT_POSITION_PLUS_SCALED_VELOCITY = 0x4000 +UCODE_COPY_OBJECT_POSITION_PLUS_SCALED_VELOCITY_ROTATE_90 = 0x5000 +UCODE_COPY_OBJECT_POSITION_PLUS_SCALED_VELOCITY_ROTATE_180 = 0x6000 +UCODE_COPY_OBJECT_POSITION_PLUS_SCALED_VELOCITY_ROTATE_270 = 0x7000 ; update bit 7 UCODE_UPDATE_OBJECT_IF_INACTIVE = 0x0000 diff --git a/star_blazer/star_blazer.asm.patch b/star_blazer/star_blazer.asm.patch index d04c215..9753e7b 100644 --- a/star_blazer/star_blazer.asm.patch +++ b/star_blazer/star_blazer.asm.patch @@ -1,5 +1,5 @@ ---- star_blazer.asm0 2024-07-19 00:00:54.594263249 +1000 -+++ star_blazer.asm 2024-07-19 00:01:14.178307255 +1000 +--- star_blazer.asm0 2024-07-20 22:51:05.009210965 -0800 ++++ star_blazer.asm 2024-07-20 22:51:49.064421478 -0800 @@ -1,3 +1,10 @@ +UNREACHABLE = 1 +DHGR = 0 @@ -227,7 +227,7 @@ rts ; 0ccf r vertical_collision_and_zero: jsr vertical_collision ; 1015 -> 0cd0 -> 0c9d r s=f5 -@@ -925,9 +971,10 @@ +@@ -936,9 +982,10 @@ bcs ucode_decimal_set_save ; 0ebf r ucode_decimal_set_mission_specific_value: ldy *decimal + 6 ; 0ec1 r @@ -240,7 +240,7 @@ tay ; 0eca r pla ; 0ecb r bcs ucode_decimal_set_save ; 0ecc r -@@ -1294,7 +1341,7 @@ +@@ -1306,7 +1353,7 @@ tsx ; 1095 -> 1097 -> 1098 r stx *ucode_sp ; 1097 -> 1098 -> 109a r ldx *ucode_x_save ; 1098 -> 109a -> 109c r @@ -249,7 +249,7 @@ sta *ucode_fire_in_state_fn_count ; 109c -> 109f -> 10a1 r ; alternative entry point for execute_ucode_words that comes from scoring? execute_ucode_words_entry: -@@ -1326,7 +1373,7 @@ +@@ -1338,7 +1385,7 @@ ; jsr execute_object1080_ucode_countdown ; bpl rts_15d6 execute_ucode_words_done: @@ -258,7 +258,7 @@ rts ; 10cd -> 10d0 -> 123e,143a,1615,1629,1633,1649,165b,1759 r s=f7..fd,02 ; call with the following set up: ; execute_ucode_words_ptr -@@ -1847,16 +1894,20 @@ +@@ -1859,16 +1906,20 @@ bpl loc_14c9 ; 14a0 -> 14a3 -> 14a5,14c9 r n=0..1 iny ; 14a3 -> 14a5 -> 14a6 r bne ucode_test_fire_all_objects_active ; 14a5 -> 14a6 -> 149b r z=0 @@ -280,7 +280,7 @@ ; opcode is followed by null-terminated list of objects to test ; note: some of these opcodes never executed in the trace ; 0x01 loc_149b test that all objects are active (object1080_state >= 0x80) -@@ -1889,17 +1940,21 @@ +@@ -1901,17 +1952,21 @@ bmi loc_14c9 ; 14d5 -> 14d8 -> 14da r n=0 iny ; 14d8 -> 14da -> 14db r bne ucode_test_fire_any_object_active ; 14da -> 14db -> 14d0 r z=0 @@ -303,10 +303,10 @@ test_object_fire_in_state_f0: lda object6080_fire_count - 0x60,x ; 1668 -> 14ef -> 14f2 r x=60..7f beq test_object_fire_false ; 14ef -> 14f2 -> 14f4,153f r z=0..1 -@@ -2263,10 +2318,35 @@ - sta *button_state ; 17ce r - rts_17d0: - rts ; 17ab,17ca -> 17d0 -> 1768,176f r s=fd +@@ -2304,10 +2359,35 @@ + ; if invalid joystick input detected, permanently disable joystick + ; (but this test can be bypassed by pressing either joystick button) + ; then jumps to init_game via vec_init_game -start: lda HW_PB0 ; -> 17d1 -> 17d4 r +start: +.if DHGR @@ -340,10 +340,10 @@ ldx #0x01 ; 17db r 0$: jsr ROM_PREAD ; 17dd r cpy #0xff ; 17e0 r -@@ -2277,9 +2357,17 @@ - sta bvar_179e ; 17e9 r - sta bvar_17a3 ; 17ec r - sta bvar_1e0e ; 17ef r +@@ -2318,9 +2398,17 @@ + sta disable_joystick0 ; 17e9 r + sta disable_joystick1 ; 17ec r + sta disable_joystick2 ; 17ef r -1$: jmp (vec_init_game) ; 17d9 -> 17f2 -> 1708 r +1$: +.if 0 ;DHGR ; language card @@ -359,7 +359,7 @@ divide_a_by_y: sta *accumulator + 1 ; 0a90,0aa0,0ab5,0ad5 -> 1800 -> 1802 r -@@ -2345,10 +2433,12 @@ +@@ -2386,10 +2474,12 @@ lda *result + 1 ; 186e r ldy *result + 2 ; 1870 r rts ; 1872 r @@ -372,7 +372,7 @@ random_init: lda *random_seed ; 16ae -> 187a -> 187c r ora #0x01 ; 187a -> 187c -> 187e r -@@ -2508,16 +2598,30 @@ +@@ -2549,16 +2639,30 @@ ldx #>HIRES_SCREEN ; 199b -> 199d -> 199f r stx *video_line_ptr + 1 ; 199d -> 199f -> 19a1 r tay ; 199f -> 19a1 -> 19a2 r @@ -404,7 +404,7 @@ rts ; 19b5 -> 19b8 -> 1713 r s=fd video_clear_rectangle: ldx *clip_y0 ; 1064 -> 19b9 -> 19bb r -@@ -2525,8 +2629,20 @@ +@@ -2566,8 +2670,20 @@ sta *video_line_ptr ; 19bb -> 19be -> 19c0 r lda video_line_table_hi - 0x20,x ; 19be -> 19c0 -> 19c3 r x=28..cf sta *video_line_ptr + 1 ; 19c0 -> 19c3 -> 19c5 r @@ -425,7 +425,7 @@ 1$: sta (*video_line_ptr),y ; 19c7,19ce -> 19c9 -> 19cb r y=6c..93 iny ; 19c9 -> 19cb -> 19cc r cpy *clip_x1 ; 19cb -> 19cc -> 19ce r y=6d..94 -@@ -2576,6 +2692,7 @@ +@@ -2617,6 +2733,7 @@ sta object1080_y0 - 0x10,x ; 1a1b -> 1a1e -> 1a21 r x=10..7f adc #0x01 ; 1a1e -> 1a21 -> 1a23 r c=0..1 d=0 sta object1080_y1 - 0x10,x ; 1a21 -> 1a23 -> 1a26 r x=10..7f @@ -433,7 +433,7 @@ rts ; 1a23 -> 1a26 -> 1076,1179,1602 r s=f1..f9,02 pixel_data_table_left: .db 0x83 ; 1a27 r -@@ -2658,14 +2775,17 @@ +@@ -2699,14 +2816,17 @@ lda object1080_onscreen_shape_ptr_hi - 0x10,x ; 1aa5 -> 1aa7 -> 1aaa r x=20..4f ora (*video_line_ptr),y ; 1aa7 -> 1aaa -> 1aac r y=6d..93,02 sta (*video_line_ptr),y ; 1aaa -> 1aac -> 1aae r y=6d..93,02 @@ -451,7 +451,7 @@ lda object1080_y0 - 0x10,x ; 1ab9 -> 1abb -> 1abe r x=14..77 cmp object1080_y1 - 0x10,x ; 1abb -> 1abe -> 1ac1 r a=11..d4 x=14..77 bcs rts_1aae ; 1abe -> 1ac1 -> 1ac3 r c=0 -@@ -2718,7 +2838,12 @@ +@@ -2759,7 +2879,12 @@ stx *x_save ; 1b32 -> 1b35 -> 1b37 r lda *draw_y ; 1b35 -> 1b37 -> 1b39 r cmp *clip_y0 ; 1b37 -> 1b39 -> 1b3b r a=11..d4 @@ -464,7 +464,7 @@ lda *clip_y1 ; 1b3b -> 1b3d -> 1b3f r cmp *draw_y1 ; 1b3d -> 1b3f -> 1b41 r a=d0 bcc 8$ ; 1b3f -> 1b41 -> 1b43,1b83 r c=0..1 -@@ -2729,16 +2854,59 @@ +@@ -2770,16 +2895,59 @@ cmp *draw_x1 ; 1b49 -> 1b4b -> 1b4d r a=94 bcc 8$ ; 1b4b -> 1b4d -> 1b4f,1b83 r c=0..1 lda object1080_onscreen_shape_ptr_lo - 0x10,x ; 1b4d -> 1b4f -> 1b52 r x=14..77 @@ -524,7 +524,7 @@ 6$: .db 0xbd ; 1b69,1b76 -> 1b6b -> 1b6e r "lda bvar_6f9f,x" x=00..39 7$: .dw 0x6f9f ; 1b6c rw ora (*video_line_ptr),y ; 1b6b -> 1b6e -> 1b70 r y=6c..93 -@@ -2755,16 +2923,50 @@ +@@ -2796,16 +2964,50 @@ rts ; 1b80 -> 1b82 -> 15cd r s=fb 8$: inc object1080_onscreen_clipped - 0x10,x ; 1b3b,1b41,1b47,1b4d -> 1b83 -> 1b86 r x=14..77 lda object1080_onscreen_shape_ptr_lo - 0x10,x ; 1b83 -> 1b86 -> 1b89 r x=14..77 @@ -577,7 +577,7 @@ 10$: lda *draw_y ; 1ba0,1bbf -> 1ba2 -> 1ba4 r cmp *clip_y0 ; 1ba2 -> 1ba4 -> 1ba6 r a=11..d8 bcc 12$ ; 1ba4 -> 1ba6 -> 1ba8,1bbb r c=0..1 -@@ -2774,6 +2976,16 @@ +@@ -2815,6 +3017,16 @@ bcc 12$ ; 1bac -> 1bae -> 1bb0,1bbb r c=0..1 cpy *clip_x1 ; 1bae -> 1bb0 -> 1bb2 r y=6c..a4 bcs 12$ ; 1bb0 -> 1bb2 -> 1bb4,1bbb r c=0..1 @@ -594,7 +594,7 @@ .db 0xbd ; 1bb2 -> 1bb4 -> 1bb7 r "lda 0x6fab,x" x=00..39 11$: .dw 0x6fab ; 1bb5 rw ora (*video_line_ptr),y ; 1bb4 -> 1bb7 -> 1bb9 r y=6c..93 -@@ -2787,6 +2999,7 @@ +@@ -2828,6 +3040,7 @@ cpy *draw_y1 ; 1bc3 -> 1bc5 -> 1bc7 r y=12..d9 bcc 9$ ; 1bc5 -> 1bc7 -> 1b96,1bc9 r c=0..1 ldx *x_save ; 1bc7 -> 1bc9 -> 1bcb r @@ -602,7 +602,7 @@ rts ; 1bc9 -> 1bcb -> 15cd r s=fb erase_pixel_object: lda #0x00 ; 1c12 -> 1bcc -> 1bce r -@@ -2818,12 +3031,15 @@ +@@ -2859,12 +3072,15 @@ eor #0xff ; 1c03 -> 1c06 -> 1c08 r and (*video_line_ptr),y ; 1c06 -> 1c08 -> 1c0a r y=6d..93,02 sta (*video_line_ptr),y ; 1c08 -> 1c0a -> 1c0c r y=6d..93,02 @@ -618,7 +618,7 @@ lda #0x00 ; 1c12 -> 1c14 -> 1c16 r sta object1080_onscreen - 0x10,x ; 1c14 -> 1c16 -> 1c19 r x=14..77 lda object1080_onscreen_x0 - 0x10,x ; 1c16 -> 1c19 -> 1c1c r x=14..77 -@@ -2838,16 +3054,61 @@ +@@ -2879,16 +3095,61 @@ stx *x_save ; 1c2d -> 1c30 -> 1c32 r bne 3$ ; 1c30 -> 1c32 -> 1c34,1c6a r z=0..1 lda object1080_onscreen_shape_ptr_lo - 0x10,x ; 1c32 -> 1c34 -> 1c37 r x=14..77 @@ -680,7 +680,7 @@ 1$: .db 0xbd ; 1c4e,1c5d -> 1c50 -> 1c53 r "lda 0x6f93,x" x=00..39 2$: .dw 0x6f93 ; 1c51 rw eor #0xff ; 1c50 -> 1c53 -> 1c55 r -@@ -2864,16 +3125,51 @@ +@@ -2905,16 +3166,51 @@ ldx *x_save ; 1c65 -> 1c67 -> 1c69 r rts ; 1c67 -> 1c69 -> 1076,16a8 r s=f3..f9,02 3$: lda object1080_onscreen_shape_ptr_lo - 0x10,x ; 1c32 -> 1c6a -> 1c6d r x=14..77 @@ -734,7 +734,7 @@ 5$: lda *draw_y ; 1c84,1ca5 -> 1c86 -> 1c88 r cmp *clip_y0 ; 1c86 -> 1c88 -> 1c8a r a=11..d8 bcc 7$ ; 1c88 -> 1c8a -> 1c8c,1ca1 r c=0..1 -@@ -2883,6 +3179,17 @@ +@@ -2924,6 +3220,17 @@ bcc 7$ ; 1c90 -> 1c92 -> 1c94,1ca1 r c=0..1 cpy *clip_x1 ; 1c92 -> 1c94 -> 1c96 r y=6c..a4 bcs 7$ ; 1c94 -> 1c96 -> 1c98,1ca1 r c=0..1 @@ -752,7 +752,7 @@ .db 0xbd ; 1c96 -> 1c98 -> 1c9b r "lda 0x6fab,x" x=00..39 6$: .dw 0x6fab ; 1c99 rw eor #0xff ; 1c98 -> 1c9b -> 1c9d r -@@ -2902,9 +3209,24 @@ +@@ -2943,9 +3250,24 @@ stx *x_save ; 1db0 -> 1cb2 -> 1cb4 r tay ; 1cb2 -> 1cb4 -> 1cb5 r lda shape_data_ptr_lo,y ; 1cb4 -> 1cb5 -> 1cb8 r y=16..ff @@ -777,7 +777,7 @@ lda shape_width_bytes,y ; 1cbe -> 1cc1 -> 1cc4 r y=16..ff clc ; 1cc1 -> 1cc4 -> 1cc5 r adc *draw_x0 ; 1cc4 -> 1cc5 -> 1cc7 r c=0 d=0 -@@ -2912,6 +3234,11 @@ +@@ -2953,6 +3275,11 @@ lda *draw_x0 ; 1cc7 -> 1cc9 -> 1ccb r lsr a ; 1cc9 -> 1ccb -> 1ccc r bcc 0$ ; 1ccb -> 1ccc -> 1cce,1cd4 r c=0..1 @@ -789,7 +789,7 @@ lda *draw_misc_mask ; 1ccc -> 1cce -> 1cd0 r eor *draw_misc_mask_xor ; 1cce -> 1cd0 -> 1cd2 r sta *draw_misc_mask ; 1cd0 -> 1cd2 -> 1cd4 r -@@ -2927,9 +3254,56 @@ +@@ -2968,9 +3295,56 @@ lda video_line_table_hi,y ; 1ce5 -> 1ce7 -> 1cea r y=00..bc adc #0x00 ; 1ce7 -> 1cea -> 1cec r c=0..1 d=0 sta *video_line_ptr + 1 ; 1cea -> 1cec -> 1cee r @@ -846,7 +846,7 @@ 2$: lda *draw_y ; 1cf2,1d0f -> 1cf4 -> 1cf6 r cmp #0xc0 ; 1cf4 -> 1cf6 -> 1cf8 r a=00..bc bcs 4$ ; 1cf6 -> 1cf8 -> 1cfa r c=0 -@@ -2949,7 +3323,12 @@ +@@ -2990,7 +3364,12 @@ inc *draw_y ; 1d0f -> 1d11 -> 1d13 r ldy *draw_y ; 1d11 -> 1d13 -> 1d15 r cpy *draw_y1 ; 1d13 -> 1d15 -> 1d17 r y=01..bd @@ -859,7 +859,7 @@ ldx *x_save ; 1d17 -> 1d19 -> 1d1b r rts ; 1d19 -> 1d1b -> 1db3 r s=ec..f5 draw_misc_from_table: -@@ -2962,7 +3341,7 @@ +@@ -3003,7 +3382,7 @@ asl a ; 1d23 -> 1d24 -> 1d25 r sta *draw_misc_ptr ; 1d24 -> 1d25 -> 1d27 r lda #0x00 ; 1d25 -> 1d27 -> 1d29 r @@ -868,7 +868,7 @@ sta *draw_misc_ptr + 1 ; 1d29 -> 1d2b -> 1d2d r lda *half_dimension ; 1d2b -> 1d2d -> 1d2f r lsr a ; 1d2d -> 1d2f -> 1d30 r -@@ -2971,10 +3350,20 @@ +@@ -3012,10 +3391,20 @@ lsr a ; 1d31 -> 1d32 -> 1d33 r lsr a ; 1d32 -> 1d33 -> 1d34 r tay ; 1d33 -> 1d34 -> 1d35 r @@ -889,7 +889,7 @@ lda *half_dimension ; 1d3d -> 1d3f -> 1d41 r and #0x1f ; 1d3f -> 1d41 -> 1d43 r cmp #0x08 ; 1d41 -> 1d43 -> 1d45 r a=00..1f -@@ -2992,6 +3381,14 @@ +@@ -3033,6 +3422,14 @@ iny ; 1d57 -> 1d59 -> 1d5a r 1$: lda (*draw_misc_ptr),y ; 1d59,1d69 -> 1d5a -> 1d5c r y=03..0c beq 2$ ; 1d5a -> 1d5c -> 1d5e,1d61 r z=0..1 @@ -904,7 +904,7 @@ jsr do_draw_misc ; 1d5c -> 1d5e -> 1da6 r s=f3..f9,02 2$: iny ; 1d5c,1db5 -> 1d61 -> 1d62 r cpy #0x10 ; 1d61 -> 1d62 -> 1d64 r y=04..0d -@@ -3047,6 +3444,84 @@ +@@ -3088,6 +3485,84 @@ ldy *draw_misc_y_save ; 1d1b -> 1db3 -> 1db5 r rts_1db5: rts ; 1da1,1db3 -> 1db5 -> 1076,1d61,1d7d,1d82,1d87 r s=ee..f7 @@ -989,7 +989,7 @@ draw_misc_mask_table: .db 0xff ; 1db6 r .db 0x00 ; 1db7 r -@@ -3057,15 +3532,17 @@ +@@ -3098,15 +3573,17 @@ .db 0xd5 ; 1dbc r .db 0xff ; 1dbd r draw_misc_mask_xor_table: @@ -1015,7 +1015,7 @@ .area text2 do_player_input: -@@ -3378,6 +3855,15 @@ +@@ -3420,6 +3897,15 @@ .area data2 @@ -1031,7 +1031,7 @@ shape_data_ptr_lo: .db = 0x80 = key waiting (uses lsr to clear it) 0x00f2,0x0001,key_state,byte 0x0200,0x0002,vec_restart,word @@ -494,6 +494,7 @@ items 0x1595,0x0001,objects_reinit,code ; maybe update object whose number is in cyclic_object ; then increment cyclic_object so it cycles through 0x10..0x7f +; cf=1 return indicates it is time to check the keyboard 0x15b2,0x0001,cyclic_update_object,code 0x15d7,0x0001,update_object_player,code 0x15ee,0x0001,update_object,code @@ -507,10 +508,40 @@ items 0x1708,0x0001,init_game,code,,10000 # suppress local for patch 0x1719,0x0001,start_game_demo,code 0x171b,0x0001,start_game,code,,10000 # suppress local for patch +; in the below, 0$ is outer game loop, 4$ is inner game loop +; 0$: cancel previous keyboard input +; 1$: if new keyboard input is present: +; move incoming key to key_state (high bit set = key present) +; strobe keyboard interface to clear it +; check for control characters, may restart game via vec_start_game +; 2$: if in demo mode: +; call test_start_game, may start game via vec_start_game +; 3$: if in single-step mode: +; if no key present, return to 1$ +; 4$: if sound enabled: +; make "update_sound_count" repeated calls to cyclic_update_sound +; 6$: make "update_object_count" repeated calls to cyclic_update_object +; (this handles all of the in-game display updating as a side effect) +; if any of these calls return cf=1, abort the loop and return to 0$ +; otherwise, upon completion of the loop, return to 4$ 0x1750,0x0001,start_mission,code -0x1797,0x0001,read_buttons,code +; if joystick button or spacebar is pressed, start game via vec_start_game +; clears single-step mode and sets joystick mode according to input source +0x1797,0x0001,test_start_game,code +; overwritten with 0x24 (bit zp) if invalid joystick input detected at startup +0x179e,0x0001,disable_joystick0,code +; overwritten with 0x24 (bit zp) if invalid joystick input detected at startup +0x17a3,0x0001,disable_joystick1,code 0x17b1,0x0001,not_demo_vector_to_start_game,code +; ctrl-r (0x92): restart game via vec_start_game (clears single-step mode) +; ctrl-c (0x83): toggle bit 7 of control_state (enable joystick) +; ctrl-s (0x93): toggle bit 6 of control_state (disable sound) +; esc (0x9b): toggle bit 5 of control_state (pause/single-step) 0x17b6,0x0001,check_control_characters,code +; the entry point to the executable +; if invalid joystick input detected, permanently disable joystick +; (but this test can be bypassed by pressing either joystick button) +; then jumps to init_game via vec_init_game 0x17d1,0x0001,start,code 0x1800,0x0001,divide_a_by_y,code 0x1829,0x0001,multiply_ya_by_accumulator,code @@ -562,6 +593,9 @@ items 0x1e00,0x0001,do_player_input,byte ; returns cf=1 if firing (random for demo mode) 0x1e03,0x0001,test_player_fire,code +; overwritten with 0x24 (bit zp) if invalid joystick input detected at startup +0x1e0e,0x0001,disable_joystick2,code +0x1e23,0x0001,spacebar_firing,code ; if in demo mode, generates a random player input ; otherwise tests the keyboard, joystick, joystick buttons 0x1e2a,0x0001,player_input,byte diff --git a/star_blazer/object_defs.inc b/star_blazer/star_blazer_object_defs.inc similarity index 99% rename from star_blazer/object_defs.inc rename to star_blazer/star_blazer_object_defs.inc index 2f52a86..6dced2f 100644 --- a/star_blazer/object_defs.inc +++ b/star_blazer/star_blazer_object_defs.inc @@ -410,13 +410,13 @@ UCODE_SOUND_EFFECT_F_EXPLOSION = 0x0f00 ; the following occur by themselves (not a bitmap): -; UCODE_IF_ACTIVE_SET_STATE_F0 doesn't seem to occur, use RESET_OBJECT instead? +; 0x0000 does not occur because it would indicate the end of the microcode? ; 0x0400, 0x0500, 0x0600, 0x0700: synonyms for 0x0000, 0x0100, 0x0200, 0x0300 ; byte -UCODE_IF_ACTIVE_SET_STATE_F0 = 0x0000 UCODE_IF_ACTIVE_SET_STATE_F1 = 0x0100 UCODE_IF_ACTIVE_SET_STATE_F2 = 0x0200 UCODE_IF_ACTIVE_SET_STATE_F3 = 0x0300 +UCODE_IF_ACTIVE_SET_STATE_F0 = 0x0400 UCODE_HORIZONTAL_COLLISION_AND_ZERO = 0x0800 UCODE_VERTICAL_COLLISION_AND_ZERO = 0x0900 UCODE_HORIZONTAL_COLLISION = 0x0a00 diff --git a/star_blazer/uncomment.sh b/star_blazer/uncomment.sh new file mode 100755 index 0000000..b491806 --- /dev/null +++ b/star_blazer/uncomment.sh @@ -0,0 +1,9 @@ +#!/bin/sh + +# use like this: +# ./uncomment.sh a +# ./uncomment.sh b +# diff --unified a b >c + +sed -e 's/[ \t]*;.*//; s/[0-9]\+\$/$/; s/:\t/:\n\t/' |\ +sed -e 's/^\(\t...\)\(\t[^0-9#*]\)/\1\n\t\2/; s/^\(\t...\t\*\)/\1\n\t\t/' diff --git a/utils/disasm.py b/utils/disasm.py index e7eb9b1..b898b59 100755 --- a/utils/disasm.py +++ b/utils/disasm.py @@ -385,6 +385,7 @@ def add_item( # code items should only ever be the opcode # if more than 1 byte then something has gone wrong # the stack trace lets us see what was being disassembled + #print('xxx', hex(addr)) assert info.size == 1 or info.type < ITEM_CODE # if the combined item is different, replace/insert it