Created
June 17, 2021 19:26
-
-
Save charasyn/af92641ad2a1e06395f0c114c1e7e6c4 to your computer and use it in GitHub Desktop.
EarthBound movement script decompiler
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // NPCs and Sprites used: | |
| // TPT 989: Body ; Spr=410 ; Mov=711 | |
| // TPT 990: Main rotor ; Spr=420 ; Mov=8,713 | |
| // TPT 991: Tail rotor ; Spr=424 ; Mov=8,714 | |
| // TPT 992: Shadow ; Spr=230 ; Mov=704,715 | |
| // Spr 106: Coordinator ; Spr=106 ; Mov=712 | |
| /* Pokey text, triggered by movement 711 once players enter region | |
| text_pokey: | |
| unset(flag 522) | |
| "[1F 15 6A 00 C8 02 01]" // Create sprite 106 with movement 712 | |
| "[1F 61]" // Wait for sprite 106 to be done initializing | |
| "[1F E7 6A 00]" // Stop sprite 106 from moving | |
| "[1F 07 03]" // Sound effect | |
| pause(120) | |
| music(172) | |
| "[1F F1 DE 03 C9 02]" // Give TPT 990 movement 713 | |
| "[1F F1 DF 03 CA 02]" // Give TPT 991 movement 714 | |
| "[1F E9 DD 03]" // Allow TPT 989 to move | |
| "[1F 61]" // Wait for main rotor to finish spinning up | |
| "[1F EA 6A 00]" // Allow sprite 106 to move | |
| "[1F F1 E0 03 CB 02]" // Give TPT 992 movement 715 | |
| "[1F 61]" // Wait for helicopter to finish flying around | |
| "[1F E7 6A 00]" // Stop sprite 106 from moving | |
| "[1F E6 DD 03]" // Stop TPT 989 from moving | |
| "[1F E6 DE 03]" // Stop TPT 990 from moving | |
| "[1F E6 DF 03]" // Stop TPT 991 from moving | |
| "[1F 15 A9 01 CC 02 01]" // Create sprite 425 with movement 716 | |
| pause(60) | |
| window_open(1) | |
| "@[1C 02 01], you pin-headed idiot,{pause(15)} you're just a half-step too slow!" next | |
| "@I'm getting outta here!" next | |
| "@Since Monotoli has become a plain,{pause(5)} old man again," | |
| "{pause(15)} I have no more use for him." next | |
| "@This helicopter will really come in handy." next | |
| "@Looks like you're the world-class loser again!" | |
| wait | |
| window_closeall | |
| pause(20) | |
| "[1F 1F A9 01 06]" // Delete sprite 425 - bye-bye to Pokey's face | |
| "[1F EA 6A 00]" // Allow sprite 106 to move | |
| "[1F E9 DD 03]" // Allow TPT 989 to move | |
| "[1F E9 DE 03]" // Allow TPT 990 to move | |
| "[1F E9 DF 03]" // Allow TPT 991 to move | |
| "[1F 07 03]" // Sound effect | |
| "[1F 61]" // Wait for helicopter to go offscreen | |
| "[1F 1F 6A 00 06]" // Delete sprites | |
| "[1F 1E DD 03 06]" // Delete TPT | |
| "[1F 1E DE 03 06]" // Delete TPT | |
| "[1F 1E DF 03 06]" // Delete TPT | |
| pause(12) | |
| set(flag 672) // 0x2a0 - prevents heli from showing next time | |
| unset(flag 11) | |
| eob | |
| */ | |
| define flag_turn_around = 0x020a | |
| // Shadow script 1 - used when static | |
| script_704: /* C386A9 */ | |
| movasm_disable_collisions | |
| priority(0x03) | |
| mov_jmp(script_8) | |
| script_8: /* C3A2AA */ | |
| onmove(0x9FF0) | |
| setanim(0x00) | |
| zerovel | |
| movasm_unk_surface_flags | |
| movasm_update_sprite_graphics_1 | |
| script_8_on_screen: /* C3A2B8 */ | |
| mov_wait(0x08) | |
| asmcall(0xC0C6B6) // Check if on screen (I think) | |
| jne(script_8_on_screen) | |
| movasm_destroy_thisobj | |
| mov_end | |
| // Shadow script 2 - used when flickering while heli is taking off | |
| script_715: /* C389BD */ | |
| movasm_disable_collisions | |
| priority(0x03) | |
| onmove(0x9FF0) | |
| setanim(0x00) | |
| zerovel | |
| movasm_update_sprite_graphics_1 | |
| mov_wait(0x20) | |
| startloop(0x08) | |
| setanim(0xFF) | |
| mov_wait(0x01) | |
| setanim(0x00) | |
| mov_wait(0x01) | |
| endloop | |
| mov_jmp(unknown_C3A204) | |
| unknown_C3A204: /* C3A204 */ | |
| movasm_destroy_thisobj | |
| mov_end | |
| // Invisible sprite script | |
| script_712: /* C387B6 */ | |
| movasm_copy_sprite_position(0x019A) | |
| onposition(0xA039) | |
| onmove(0xA37A) | |
| setanim(0xFF) | |
| mov_wait(0x01) | |
| unlock_text_script | |
| // The text script, once being unlocked here, will immediately | |
| // lock this movement script from executing. | |
| mov_wait(0x01) | |
| task(task_face_players_towards_object) | |
| // Move the helicopter to a given position | |
| movasm_set_speed(0x0080) | |
| mov_var(0x05,0x0001) | |
| mov_var(0x06,0x0D88) | |
| mov_var(0x07,0x0ED8) | |
| mov_jsr(sub_go_to_position) | |
| mov_wait(0x3C) | |
| movasm_set_speed(0x00C0) | |
| mov_var(0x06,0x0DE8) | |
| mov_var(0x07,0x0E78) | |
| mov_jsr(sub_go_to_position) | |
| mov_wait(0x1E) | |
| mov_var(0x06,0x0DC8) | |
| mov_jsr(sub_go_to_position) | |
| movasm_set_speed(0x0300) | |
| mov_var(0x05,0x0003) | |
| mov_var(0x06,0x0D90) | |
| mov_var(0x07,0x0EB8) | |
| mov_jsr(sub_go_to_position) | |
| movasm_set_speed(0x00C0) | |
| mov_var(0x05,0x0001) | |
| mov_var(0x06,0x0D40) | |
| mov_var(0x07,0x0EB0) | |
| mov_jsr(sub_go_to_position) | |
| movasm_set_speed(0x0080) | |
| mov_var(0x06,0x0D30) | |
| mov_var(0x07,0x0EA8) | |
| mov_jsr(sub_go_to_position) | |
| movasm_setevent(flag_turn_around) | |
| movasm_set_speed(0x0040) | |
| mov_var(0x06,0x0D20) | |
| mov_jsr(sub_go_to_position) | |
| unlock_text_script | |
| // Again, this object is locked. | |
| // Now Pokey pokes his head out of the heli and | |
| // talks. Once that's done, this movement code | |
| // is re-enabled so it can fly off-screen. | |
| mov_wait(0x01) | |
| setxvel(0x0160) | |
| setyvel(0xFFC0) | |
| mov_wait(0x20) | |
| setyvel(0xFF80) | |
| mov_wait(0x20) | |
| setyvel(0xFF00) | |
| mov_wait(0x40) | |
| zerovel | |
| unlock_text_script // Indicate we're gone off-screen | |
| halt | |
| sub_go_to_position: /* C3AB59 */ | |
| mov_jsr(sub_init_movement_to_position) | |
| sub_go_to_position_loop: /* C3AB5C */ | |
| mov_wait(0x01) | |
| movasm_walk_toward_position | |
| jeq(sub_go_to_position_loop) | |
| zerovel | |
| mov_rts | |
| sub_init_movement_to_position: /* C3AB44 */ | |
| movasm_find_angle_toward_position | |
| movasm_set_velocity_in_direction | |
| movasm_update_facing_from_angle | |
| movasm_update_facing | |
| movasm_update_sprite_graphics_1 | |
| mov_rts | |
| task_face_players_towards_object: /* C3AFA3 */ | |
| asmcall(0xC48B3B) | |
| mov_wait(0x03) | |
| mov_jmp(task_face_players_towards_object) | |
| // Main heli body script | |
| script_711: /* C3886C */ | |
| priority(0x00) | |
| movasm_set_surface_flags(0x00) | |
| onmove(0x9FC8) | |
| setanim(0x00) | |
| zerovel | |
| movasm_set_surface_flags(0x00) | |
| movasm_update_sprite_graphics_1 | |
| mov_var(0x00,0x0D80) // Region center X | |
| mov_var(0x01,0x0ED8) // Region center Y | |
| mov_var(0x02,0x0018) // Region width on both sides | |
| mov_var(0x03,0x0008) // Region height on both sides | |
| mov_jsr(sub_wait_for_player_to_enter_region) | |
| movasm_execute_text_block(text_pokey) | |
| mov_wait(0x01) | |
| script_711_heli_facing_left: /* C3889F */ | |
| movasm_copy_sprite_position(106) | |
| mov_wait(0x01) | |
| movasm_getevent(flag_turn_around) | |
| jeq(script_711_heli_facing_left) | |
| priority(0x03) | |
| movasm_set_facing_anim(0x02,0x00) | |
| script_711_heli_facing_right: /* C388B8 */ | |
| movasm_copy_sprite_position(106) | |
| mov_wait(0x01) | |
| mov_jmp(script_711_heli_facing_right) | |
| sub_wait_for_player_to_enter_region: /* C3AB8A */ | |
| mov_wait(0x01) | |
| asmcall(0xC46E74) | |
| jeq(sub_wait_for_player_to_enter_region) | |
| mov_rts | |
| // Main rotor script | |
| script_713: /* C388C3 */ | |
| priority(0x00) | |
| movasm_set_surface_flags(0x00) | |
| onmove(0x9FC8) | |
| setanim(0x00) | |
| zerovel | |
| movasm_set_surface_flags(0x00) | |
| task(task_toggle_anim_after_2_frames) | |
| task(task_set_rotor_facing_based_on_var_4) | |
| // Animate rotor spinning up | |
| mov_var(0x04,0x0001) | |
| mov_wait(0x3C) | |
| mov_var(0x04,0x0000) | |
| mov_wait(0x06) | |
| mov_var(0x04,0x0001) | |
| mov_wait(0x14) | |
| mov_var(0x04,0x0000) | |
| mov_wait(0x10) | |
| mov_var(0x04,0x0001) | |
| mov_wait(0x0A) | |
| mov_var(0x04,0x0000) | |
| mov_wait(0x18) | |
| mov_var(0x04,0x0001) | |
| mov_wait(0x06) | |
| mov_var(0x04,0x0000) | |
| mov_wait(0x78) | |
| // Now that rotor is ready, allow cutscene to proceed | |
| unlock_text_script | |
| script_713_heli_facing_left: /* C3890F */ | |
| movasm_copy_sprite_position(106) | |
| addypos(-24) | |
| addxpos(-8) | |
| mov_wait(1) | |
| movasm_getevent(flag_turn_around) | |
| jeq(script_713_heli_facing_left) | |
| priority(0x03) | |
| script_713_heli_facing_right: /* C38928 */ | |
| movasm_copy_sprite_position(106) | |
| addypos(-24) | |
| addxpos(8) | |
| mov_wait(1) | |
| mov_jmp(script_713_heli_facing_right) | |
| // Tail rotor script | |
| script_714: /* C38939 */ | |
| priority(0x00) | |
| movasm_set_surface_flags(0x00) | |
| onmove(0x9FC8) | |
| setanim(0x00) | |
| zerovel | |
| task(task_toggle_anim_after_2_frames) | |
| task(task_set_rotor_facing_based_on_var_4) | |
| mov_var(0x04,0x0000) | |
| script_714_heli_facing_left: /* C38950 */ | |
| movasm_copy_sprite_position(106) | |
| addypos(-16) | |
| addxpos(16) | |
| mov_wait(1) | |
| movasm_getevent(flag_turn_around) | |
| jeq(script_714_heli_facing_left) | |
| script_714_heli_facing_right: /* C38967 */ | |
| movasm_copy_sprite_position(106) | |
| addypos(-16) | |
| addxpos(-16) | |
| mov_wait(1) | |
| mov_jmp(script_714_heli_facing_right) | |
| // Rotor common code | |
| task_set_rotor_facing_based_on_var_4: /* C38978 */ | |
| mov_reg_var(0x04) | |
| jne(unknown_C38992) | |
| movasm_getevent(flag_turn_around) | |
| jne(unknown_C3898C) | |
| mov_reg_imm(0x0006) | |
| mov_jmp(unknown_C38995) | |
| unknown_C3898C: /* C3898C */ | |
| mov_reg_imm(0x0002) | |
| mov_jmp(unknown_C38995) | |
| unknown_C38992: /* C38992 */ | |
| mov_reg_imm(0x0004) | |
| unknown_C38995: /* C38995 */ | |
| movasm_update_facing | |
| mov_wait(0x01) | |
| mov_jmp(task_set_rotor_facing_based_on_var_4) | |
| task_toggle_anim_after_2_frames: /* C3899E */ | |
| setanim(0x00) | |
| movasm_update_sprite_graphics_2 | |
| mov_wait(0x01) | |
| movasm_update_sprite_graphics_2 | |
| mov_wait(0x01) | |
| setanim(0x01) | |
| movasm_update_sprite_graphics_3 | |
| mov_wait(0x01) | |
| movasm_update_sprite_graphics_3 | |
| mov_wait(0x01) | |
| mov_jmp(task_toggle_anim_after_2_frames) | |
| // Script for Pokey's face | |
| script_716: /* C389DD */ | |
| movasm_copy_sprite_position(410) // Heli body | |
| addxpos(21) | |
| addypos(-14) | |
| priority(0x00) | |
| onmove(0x9FF0) | |
| setanim(0x00) | |
| zerovel | |
| movasm_set_surface_flags(0x00) | |
| movasm_update_sprite_graphics_1 | |
| // After setting position and showing the correct graphics, | |
| // stop executing. | |
| halt | |
| // Once Pokey's said his spiel, this sprite will be deleted | |
| // by the CCScript. That way, the location of his face never | |
| // has to be changed from the movement script. | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| script_704: /* C386A9 */ | |
| movasm_disable_collisions | |
| priority(0x03) | |
| mov_jmp(unknown_C3A2AA) | |
| script_712: /* C387B6 */ | |
| movasm_copy_sprite_position(0x019A) | |
| onposition(0xA039) | |
| onmove(0xA37A) | |
| setanim(0xFF) | |
| mov_wait(0x01) | |
| unlock_text_script | |
| mov_wait(0x01) | |
| task(unknown_C3AFA3) | |
| movasm_set_speed(0x0080) | |
| mov_var(0x05,0x0001) | |
| mov_var(0x06,0x0D88) | |
| mov_var(0x07,0x0ED8) | |
| mov_jsr(unknown_C3AB59) | |
| mov_wait(0x3C) | |
| movasm_set_speed(0x00C0) | |
| mov_var(0x06,0x0DE8) | |
| mov_var(0x07,0x0E78) | |
| mov_jsr(unknown_C3AB59) | |
| mov_wait(0x1E) | |
| mov_var(0x06,0x0DC8) | |
| mov_jsr(unknown_C3AB59) | |
| movasm_set_speed(0x0300) | |
| mov_var(0x05,0x0003) | |
| mov_var(0x06,0x0D90) | |
| mov_var(0x07,0x0EB8) | |
| mov_jsr(unknown_C3AB59) | |
| movasm_set_speed(0x00C0) | |
| mov_var(0x05,0x0001) | |
| mov_var(0x06,0x0D40) | |
| mov_var(0x07,0x0EB0) | |
| mov_jsr(unknown_C3AB59) | |
| movasm_set_speed(0x0080) | |
| mov_var(0x06,0x0D30) | |
| mov_var(0x07,0x0EA8) | |
| mov_jsr(unknown_C3AB59) | |
| movasm_setevent(0x020A) | |
| movasm_set_speed(0x0040) | |
| mov_var(0x06,0x0D20) | |
| mov_jsr(unknown_C3AB59) | |
| unlock_text_script | |
| mov_wait(0x01) | |
| setxvel(0x0160) | |
| setyvel(0xFFC0) | |
| mov_wait(0x20) | |
| setyvel(0xFF80) | |
| mov_wait(0x20) | |
| setyvel(0xFF00) | |
| mov_wait(0x40) | |
| zerovel | |
| unlock_text_script | |
| halt | |
| script_711: /* C3886C */ | |
| priority(0x00) | |
| movasm_set_surface_flags(0x00) | |
| onmove(0x9FC8) | |
| setanim(0x00) | |
| zerovel | |
| movasm_set_surface_flags(0x00) | |
| movasm_update_sprite_graphics_1 | |
| mov_var(0x00,0x0D80) | |
| mov_var(0x01,0x0ED8) | |
| mov_var(0x02,0x0018) | |
| mov_var(0x03,0x0008) | |
| mov_jsr(unknown_C3AB8A) | |
| movasm_execute_text_block(0x00C7BD89) | |
| mov_wait(0x01) | |
| unknown_C3889F: /* C3889F */ | |
| movasm_copy_sprite_position(0x006A) | |
| mov_wait(0x01) | |
| movasm_getevent(0x020A) | |
| jeq(unknown_C3889F) | |
| priority(0x03) | |
| movasm_set_facing_anim(0x02,0x00) | |
| unknown_C388B8: /* C388B8 */ | |
| movasm_copy_sprite_position(0x006A) | |
| mov_wait(0x01) | |
| mov_jmp(unknown_C388B8) | |
| script_713: /* C388C3 */ | |
| priority(0x00) | |
| movasm_set_surface_flags(0x00) | |
| onmove(0x9FC8) | |
| setanim(0x00) | |
| zerovel | |
| movasm_set_surface_flags(0x00) | |
| task(unknown_C3899E) | |
| task(unknown_C38978) | |
| mov_var(0x04,0x0001) | |
| mov_wait(0x3C) | |
| mov_var(0x04,0x0000) | |
| mov_wait(0x06) | |
| mov_var(0x04,0x0001) | |
| mov_wait(0x14) | |
| mov_var(0x04,0x0000) | |
| mov_wait(0x10) | |
| mov_var(0x04,0x0001) | |
| mov_wait(0x0A) | |
| mov_var(0x04,0x0000) | |
| mov_wait(0x18) | |
| mov_var(0x04,0x0001) | |
| mov_wait(0x06) | |
| mov_var(0x04,0x0000) | |
| mov_wait(0x78) | |
| unlock_text_script | |
| unknown_C3890F: /* C3890F */ | |
| movasm_copy_sprite_position(0x006A) | |
| addypos(0xFFE8) | |
| addxpos(0xFFF8) | |
| mov_wait(0x01) | |
| movasm_getevent(0x020A) | |
| jeq(unknown_C3890F) | |
| priority(0x03) | |
| unknown_C38928: /* C38928 */ | |
| movasm_copy_sprite_position(0x006A) | |
| addypos(0xFFE8) | |
| addxpos(0x0008) | |
| mov_wait(0x01) | |
| mov_jmp(unknown_C38928) | |
| script_714: /* C38939 */ | |
| priority(0x00) | |
| movasm_set_surface_flags(0x00) | |
| onmove(0x9FC8) | |
| setanim(0x00) | |
| zerovel | |
| task(unknown_C3899E) | |
| task(unknown_C38978) | |
| mov_var(0x04,0x0000) | |
| unknown_C38950: /* C38950 */ | |
| movasm_copy_sprite_position(0x006A) | |
| addypos(0xFFF0) | |
| addxpos(0x0010) | |
| mov_wait(0x01) | |
| movasm_getevent(0x020A) | |
| jeq(unknown_C38950) | |
| unknown_C38967: /* C38967 */ | |
| movasm_copy_sprite_position(0x006A) | |
| addypos(0xFFF0) | |
| addxpos(0xFFF0) | |
| mov_wait(0x01) | |
| mov_jmp(unknown_C38967) | |
| unknown_C38978: /* C38978 */ | |
| mov_reg_var(0x04) | |
| jne(unknown_C38992) | |
| movasm_getevent(0x020A) | |
| jne(unknown_C3898C) | |
| mov_reg_imm(0x0006) | |
| mov_jmp(unknown_C38995) | |
| unknown_C3898C: /* C3898C */ | |
| mov_reg_imm(0x0002) | |
| mov_jmp(unknown_C38995) | |
| unknown_C38992: /* C38992 */ | |
| mov_reg_imm(0x0004) | |
| unknown_C38995: /* C38995 */ | |
| movasm_update_facing | |
| mov_wait(0x01) | |
| mov_jmp(unknown_C38978) | |
| unknown_C3899E: /* C3899E */ | |
| setanim(0x00) | |
| movasm_update_sprite_graphics_2 | |
| mov_wait(0x01) | |
| movasm_update_sprite_graphics_2 | |
| mov_wait(0x01) | |
| setanim(0x01) | |
| movasm_update_sprite_graphics_3 | |
| mov_wait(0x01) | |
| movasm_update_sprite_graphics_3 | |
| mov_wait(0x01) | |
| mov_jmp(unknown_C3899E) | |
| script_715: /* C389BD */ | |
| movasm_disable_collisions | |
| priority(0x03) | |
| onmove(0x9FF0) | |
| setanim(0x00) | |
| zerovel | |
| movasm_update_sprite_graphics_1 | |
| mov_wait(0x20) | |
| startloop(0x08) | |
| setanim(0xFF) | |
| mov_wait(0x01) | |
| setanim(0x00) | |
| mov_wait(0x01) | |
| endloop | |
| mov_jmp(unknown_C3A204) | |
| script_716: /* C389DD */ | |
| movasm_copy_sprite_position(0x019A) | |
| addxpos(0x0015) | |
| addypos(0xFFF2) | |
| priority(0x00) | |
| onmove(0x9FF0) | |
| setanim(0x00) | |
| zerovel | |
| movasm_set_surface_flags(0x00) | |
| movasm_update_sprite_graphics_1 | |
| halt | |
| unknown_C3A204: /* C3A204 */ | |
| movasm_destroy_thisobj | |
| mov_end | |
| unknown_C3A2AA: /* C3A2AA */ | |
| onmove(0x9FF0) | |
| setanim(0x00) | |
| zerovel | |
| movasm_unk_surface_flags | |
| movasm_update_sprite_graphics_1 | |
| unknown_C3A2B8: /* C3A2B8 */ | |
| mov_wait(0x08) | |
| asmcall(0xC0C6B6) | |
| jne(unknown_C3A2B8) | |
| movasm_destroy_thisobj | |
| mov_end | |
| unknown_C3AB44: /* C3AB44 */ | |
| movasm_find_angle_toward_position | |
| movasm_set_velocity_in_direction | |
| movasm_update_facing_from_angle | |
| movasm_update_facing | |
| movasm_update_sprite_graphics_1 | |
| mov_rts | |
| unknown_C3AB59: /* C3AB59 */ | |
| mov_jsr(unknown_C3AB44) | |
| unknown_C3AB5C: /* C3AB5C */ | |
| mov_wait(0x01) | |
| movasm_walk_toward_position | |
| jeq(unknown_C3AB5C) | |
| zerovel | |
| mov_rts | |
| unknown_C3AB8A: /* C3AB8A */ | |
| mov_wait(0x01) | |
| asmcall(0xC46E74) | |
| jeq(unknown_C3AB8A) | |
| mov_rts | |
| unknown_C3AFA3: /* C3AFA3 */ | |
| asmcall(0xC48B3B) | |
| mov_wait(0x03) | |
| mov_jmp(unknown_C3AFA3) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| from collections import defaultdict | |
| import re, mmap | |
| from dataclasses import InitVar, dataclass, field | |
| from typing import DefaultDict, Dict, List, Set, Tuple, Union | |
| from sortedcontainers import SortedList | |
| from functools import total_ordering | |
| cmds_string = ''' | |
| command mov_end "[00]" | |
| command startloop(c) "[01 {byte c}]" // Start a loop with 'c' iterations | |
| command endloop "[02]" // End a loop and go back to start of loop body if still haven't gone through all iterations | |
| command mov_jml(addr) "[03 {adr24(addr)}]" // Analogous to ASM JML, but for movement scripts | |
| command mov_jsl(addr) "[04 {adr24(addr)}]" // Analogous to ASM JSL, but for movement scripts | |
| command mov_rtl "[05]" // Analogous to ASM RTL, but for movement scripts | |
| command mov_wait(frames) "[06 {byte frames}]" // Wait 'frames' frames (think "`pause(frames)") | |
| command task(addr) "[07 {short addr}]" // Register a background task, a movement script that runs alongside this movement script. Must be in the same bank as the current script | |
| command ontick(addr) "[08 {adr24(addr)}]" // Register a "TICK callback", an ASM function that runs every frame for the object | |
| command halt "[09]" // Halt movement script (infinitely loop it, but don't outright end it) | |
| command jeq(addr) "[0A {short addr}]" // Jump to 'addr' if REG is zero (think "BEQ_a(addr)") | |
| command jne(addr) "[0B {short addr}]" // Jump to 'addr' if REG is not zero (think "BNE_a(addr)") | |
| command endtask "[0C]" // End background task (if this movement script is not a task, it just ends the script, I believe) | |
| command mem16_and(addr, val) "[0D {short addr} 00 {short val}]" // *(uint16_t*)mem &= val | |
| command mem16_or(addr, val) "[0D {short addr} 01 {short val}]" // *(uint16_t*)mem |= val | |
| command mem16_add(addr, val) "[0D {short addr} 02 {short val}]" // *(uint16_t*)mem += val | |
| command mem16_xor(addr, val) "[0D {short addr} 03 {short val}]" // *(uint16_t*)mem ^= val | |
| command mov_var(var, value) "[0E {byte var} {short value}]" // Set a specific object VAR to immediate value ('var' must be in range 0..7) | |
| command ontick_nop "[0F]" // Same as "ontick(0xC0943B)", but faster and saves 3 bytes | |
| command multijmp(amount) "[10 {byte amount}]" // Switch on REG and JMP (think control code "[09 XX (YYYYYYYY)*XX]") | |
| command multijsr(amount) "[11 {byte amount}]" // Switch on REG and JSR (think control code "[1F C0 XX (YYYYYYYY)*XX]") | |
| command mov_mem8(addr, val) "[12 {short addr} {byte val}]" // Move 8-bit immediate value to memory | |
| command endlasttask "[13]" // End last registered background task (if no background tasks are running, it just ends the movement script, I believe) | |
| command var_and(var, val) "[14 {byte var} 00 {short val}]" // VAR &= val | |
| command var_or(var, val) "[14 {byte var} 01 {short val}]" // VAR |= val | |
| command var_add(var, val) "[14 {byte var} 02 {short val}]" // VAR += val | |
| command var_xor(var, val) "[14 {byte var} 03 {short val}]" // VAR ^= val | |
| command mov_mem16(addr, val) "[15 {short addr} {short val}]" // Move 16-bit immediate value to memory | |
| command breakeq(addr) "[16 {short addr}]" // JEQ and decrement stack pointer by 3 (clean STARTLOOP stuff) | |
| command breakne(addr) "[17 {short addr}]" // JNE and decrement stack pointer by 3 (clean STARTLOOP stuff) | |
| command mem8_and(addr, val) "[18 {short addr} 00 {byte val}]" // *(uint8_t*)mem &= val | |
| command mem8_or(addr, val) "[18 {short addr} 01 {byte val}]" // *(uint8_t*)mem |= val | |
| command mem8_xor(addr, val) "[18 {short addr} 03 {byte val}]" // *(uint8_t*)mem ^= val | |
| command mem8_add(addr, val) "[18 {short addr} 02 {byte val}]" // *(uint8_t*)mem += val | |
| command mov_jmp(addr) "[19 {short addr}]" // Analogous to ASM JMP, but for movement scripts | |
| command mov_jsr(addr) "[1A {short addr}]" // Analogous to ASM JSR, but for movement scripts | |
| command mov_rts "[1B]" // Analogous to ASM RTS, but for movement scripts | |
| command setsprmap(addr) "[1C {adr24(addr)}]" // Set pointer to spritemap data. This is kinda complicated, I also never used this, so I don't really know much about the "spritemap" format | |
| command mov_reg_imm(val) "[1D {short val}]" // Move 16-bit immediate value to REG | |
| command mov_reg_mem(addr) "[1E {short addr}]" // Move absolute memory address to REG | |
| command mov_var_reg(var) "[1F {byte var}]" // Move REG to object VAR | |
| command mov_reg_var(var) "[20 {byte var}]" // Move object VAR to REG | |
| command wait_var(var) "[21 {byte var}]" // Wait (object VAR) frames | |
| command ondraw(addr) "[22 {short addr}]" // Assign "draw object" callback function. Argument is a short ASM pointer in bank C0 | |
| command onposition(addr) "[23 {short addr}]" // Assign "calculate screen position" callback function. Argument is a short ASM pointer in bank C0 | |
| command startloop_reg "[24]" // Start a loop with REG iterations | |
| command onmove(addr) "[25 {short addr}]" // Assign "move object" callback function. Argument is a short ASM pointer in bank C0 | |
| command setanim_var(var) "[26 {byte var}]" // Set amimation frame to object VAR | |
| command reg_and(val) "[27 00 {short val}]" // REG &= val | |
| command reg_or(val) "[27 01 {short val}]" // REG |= val | |
| command reg_add(val) "[27 02 {short val}]" // REG += val | |
| command reg_xor(val) "[27 03 {short val}]" // REG ^= val | |
| command setxpos(val) "[28 {short val}]" // Set object X position | |
| command setypos(val) "[29 {short val}]" // Set object Y position | |
| command setzpos(val) "[2A {short val}]" // Set object Z position (elevation) | |
| command addxpos(val) "[2B {short val}]" // Add 'val' to object X position (can be negative) | |
| command addypos(val) "[2C {short val}]" // Add 'val' to object Y position (can be negative) | |
| command addzpos(val) "[2D {short val}]" // Add 'val' to object Z position (elevation) (can be negative) | |
| command addxvel(val) "[2E {short val}]" // Add 'val' to object X velocity (can be negative) | |
| command addyvel(val) "[2F {short val}]" // Add 'val' to object Y velocity (can be negative) | |
| command addzvel(val) "[30 {short val}]" // Add 'val' to object Z velocity (elevation) (can be negative) | |
| command zerovel "[39]" // Set object X, Y, Z velocities to zero | |
| command setanim(anim) "[3B {byte anim}]" // Set object animation frame | |
| command incanim "[3C]" // Increment object animation frame | |
| command decanim "[3D]" // Decrement object animation frame | |
| command addanim(val) "[3E {byte val}]" // Add 'val' to object animation frame (can be negative) | |
| command setxvel(val) "[3F {short val}]" // Set object X velocity | |
| command setyvel(val) "[40 {short val}]" // Set object Y velocity | |
| command setzvel(val) "[41 {short val}]" // Set object Z velocity (elevation) | |
| command priority(val) "[43 {byte val}]" // Set object draw priority ('val' must be in range 0..3) | |
| command wait_reg "[44]" // Wait REG frames | |
| // Following are asmcall routines that take parameters | |
| command movasm_update_facing "[42 5F A6 C0]" | |
| command movasm_unk_surface_flags "[42 DB C7 C0]" | |
| command movasm_update_sprite_graphics_1 "[42 BF A4 C0]" | |
| command movasm_update_sprite_graphics_2 "[42 A8 A4 C0]" | |
| command movasm_update_sprite_graphics_3 "[42 B2 A4 C0]" | |
| command movasm_disable_collisions "[42 2F A8 C0]" | |
| command movasm_destroy_thisobj "[42 F1 20 C0]" | |
| command movasm_find_angle_toward_position "[42 DB 6A C4]" | |
| command movasm_update_facing_from_angle "[42 0A 6B C4]" | |
| command movasm_set_velocity_in_direction "[42 44 70 C4]" | |
| command movasm_walk_toward_position "[42 DC A8 C0]" | |
| command unlock_text_script "[42 46 6E C4]" | |
| command asmcall_C05E76(arg1, arg2) "[42 76 5E C0 {byte arg1} {adr24(arg2)}]" | |
| command asmcall_C09E71(arg) "[42 71 9E C0 {short arg}]" | |
| command asmcall_C09FAE(arg) "[42 AE 9F C0 {short arg}]" | |
| command asmcall_C09FBB(arg) "[42 BB 9F C0 {short arg}]" | |
| command asmcall_C0A643(arg) "[42 43 A6 C0 {short arg}]" | |
| command asmcall_C0A651(arg) "[42 51 A6 C0 {byte arg}]" | |
| command movasm_set_surface_flags(arg) "[42 79 A6 C0 {byte arg}]" | |
| command movasm_set_speed(speed) "[42 85 A6 C0 {short speed}]" | |
| command asmcall_C0A6A2(arg) "[42 A2 A6 C0 {short arg}]" | |
| command asmcall_C0A6AD(arg) "[42 AD A6 C0 {short arg}]" | |
| command asmcall_C0A841(arg) "[42 41 A8 C0 {short arg}]" | |
| command movasm_getevent(event) "[42 4C A8 C0 {short event}]" | |
| command movasm_setevent(event) "[42 57 A8 C0 {short event}]" | |
| command asmcall_C0A864(arg) "[42 64 A8 C0 {byte arg}]" | |
| command movasm_copy_sprite_position(spr) "[42 6F A8 C0 {short spr}]" | |
| command asmcall_C0A87A(arg, arg2) "[42 7A A8 C0 {short arg} {short arg2}]" | |
| command movasm_execute_text_block(ptr) "[42 8D A8 C0 {longbe16(ptr)}]" | |
| command movasm_execute_text_block2(ptr) "[42 A0 A8 C0 {longbe16(ptr)}]" | |
| command asmcall_C0A8B3(arg, arg2) "[42 B3 A8 C0 {short arg} {short arg2}]" | |
| command asmcall_C0A907(arg) "[42 07 A9 C0 {byte arg}]" | |
| command asmcall_C0A912(arg, arg2, arg3) "[42 12 A9 C0 {short arg} {short arg2} {byte arg3}]" | |
| command asmcall_C0A92D(arg) "[42 2D A9 C0 {short arg}]" | |
| command asmcall_C0A938(arg) "[42 38 A9 C0 {short arg}]" | |
| command asmcall_C0A943(arg) "[42 43 A9 C0 {byte arg}]" | |
| command asmcall_C0A94E(arg) "[42 4E A9 C0 {short arg}]" | |
| command asmcall_C0A959(arg) "[42 59 A9 C0 {short arg}]" | |
| command asmcall_C0A964(arg, arg2) "[42 64 A9 C0 {short arg} {short arg2}]" | |
| command asmcall_C0A977(arg, arg2) "[42 77 A9 C0 {short arg} {short arg2}]" | |
| command asmcall_C0A98B(arg, arg2) "[42 8B A9 C0 {short arg} {short arg2}]" | |
| command asmcall_C0A99F(arg, arg2) "[42 9F A9 C0 {short arg} {short arg2}]" | |
| command asmcall_C0A9B3(arg, arg2, arg3) "[42 B3 A9 C0 {short arg} {short arg2} {short arg3}]" | |
| command asmcall_C0A9CF(arg, arg2, arg3) "[42 CF A9 C0 {short arg} {short arg2} {short arg3}]" | |
| command asmcall_C0A9EB(arg, arg2, arg3) "[42 EB A9 C0 {short arg} {short arg2} {short arg3}]" | |
| command asmcall_C0AA07(arg, arg2, arg3) "[42 07 AA C0 {short arg} {short arg2} {short arg3}]" | |
| command asmcall_C0AA23(arg, arg2, arg3) "[42 23 AA C0 {short arg} {short arg2} {short arg3}]" | |
| command asmcall_C0AA3F(arg, arg2, arg3) "[42 3F AA C0 {byte arg} {byte arg2} {byte arg3}]" | |
| command movasm_set_facing_anim(facing, anim) "[42 6E AA C0 {byte facing} {byte anim}]" | |
| command asmcall_C0AAB5(arg, arg2, arg3) "[42 B5 AA C0 {short arg} {byte arg2} {byte arg3}]" | |
| command asmcall_C0AAD5(arg, arg2) "[42 D5 AA C0 {byte arg} {short arg2}]" | |
| // The actual generic asmcall is at the end so that it has lowest precedence | |
| command asmcall(addr) "[42 {adr24(addr)}]" // Call other ASM routine | |
| ''' | |
| def addr2off(address): | |
| return address - 0xc00000 | |
| @dataclass | |
| class ParseItem: | |
| pass | |
| @dataclass | |
| class ParseLiteralInt(ParseItem): | |
| value: int | |
| @dataclass | |
| class ParseParamReference(ParseItem): | |
| type: str | |
| var: str | |
| def num_bytes(self): | |
| return {'byte':1,'short':2,'adr24':3,'long':4,'longbe16':4}[self.type] | |
| def match_indices(self): | |
| return {'byte':[0],'short':[0,1],'adr24':[0,1,2],'long':[0,1,2,3],'longbe16':[2,3,0,1]}[self.type] | |
| def parse_code_str(s: str): | |
| parsed = [] | |
| i = 0 | |
| re_const = re.compile(r'([0-9A-Fa-f]{2})') | |
| def check_const(x, i): | |
| match = re_const.match(x, pos=i) | |
| if match: | |
| value = ParseLiteralInt(int(match.group(1), base=16)) | |
| new_i = match.end(0) | |
| return (value, new_i) | |
| return (None, None) | |
| re_param = re.compile(r'\{(byte|short|adr24|long|longbe16)(?:\s+|\()(\w+)\)?\}') | |
| def check_param(x, i): | |
| match = re_param.match(x, pos=i) | |
| if match: | |
| value = ParseParamReference(match.group(1), match.group(2)) | |
| new_i = match.end(0) | |
| return (value, new_i) | |
| return (None, None) | |
| check_funcs = [ | |
| check_const, | |
| check_param | |
| ] | |
| while i < len(s): | |
| while s[i].isspace(): | |
| i += 1 | |
| parse_good = False | |
| for f in check_funcs: | |
| value, new_i = f(s, i) | |
| if value is None: | |
| continue | |
| parsed.append(value) | |
| i = new_i | |
| parse_good = True | |
| break | |
| if not parse_good: | |
| raise ValueError(f'Unable to parse "{s}" at character {i+1}') | |
| return parsed | |
| def build_code_re(parsed): | |
| re_string_parts = [] | |
| for p in parsed: | |
| if isinstance(p, ParseLiteralInt): | |
| re_string_parts.append(b'\\x' + (f'{p.value:02x}').encode('ascii')) | |
| elif isinstance(p, ParseParamReference): | |
| length = p.num_bytes() | |
| for _ in range(length): | |
| re_string_parts.append(b'(.)') | |
| re_string = b''.join(re_string_parts) | |
| try: | |
| cmp = re.compile(re_string, re.DOTALL) | |
| return cmp | |
| except: | |
| print(f'Unable to compile regular expression {re_string}') | |
| raise | |
| @dataclass | |
| class CommandParam: | |
| name: str = field(init=False) | |
| match_indices: List[int] = field(init=False) | |
| parsed_param: InitVar[ParseParamReference] | |
| match_offset: InitVar[int] | |
| def __post_init__(self, parsed_param: ParseParamReference, match_offset: int): | |
| self.name = parsed_param.var | |
| self.match_indices = [match_offset + index for index in parsed_param.match_indices()] | |
| def num_bytes(self): | |
| return len(self.match_indices) | |
| def extract_value_from_match(self, match: re.Match) -> int: | |
| match_bytes = b''.join(match.group(i) for i in self.match_indices) | |
| match_int = int.from_bytes(match_bytes, 'little') | |
| return match_int | |
| @dataclass | |
| class Command: | |
| name: str | |
| code_re: re.Pattern | |
| parameters: List[CommandParam] | |
| # def try_match(self, inp_sequence: bytes, offset: int) -> Tuple[Union[None,CommandInstance],int]: | |
| # pass | |
| @dataclass(eq=True, unsafe_hash=True, frozen=True) | |
| class Label: | |
| name: str = field(compare=False) | |
| address: int | |
| @total_ordering | |
| @dataclass | |
| class CommandInstance: | |
| address: int | |
| cmd: Command | |
| cmd_bytes: bytes = field(init=False) | |
| param_values: Dict[str,int] = field(init=False) | |
| input_sequence: InitVar[bytes] | |
| match: InitVar[re.Match] | |
| def __post_init__(self, input_sequence: bytes, match: re.Match): | |
| # Initialize param_values | |
| self.param_values = {} | |
| for param in self.cmd.parameters: | |
| self.param_values[param.name] = param.extract_value_from_match(match) | |
| # Initialize cmd_bytes | |
| self.cmd_bytes = match.group(0) | |
| def command_terminates(self): | |
| return False | |
| def __repr__(self) -> str: | |
| return self.to_string() | |
| def to_string(self, show_address=False, show_bytes=False) -> str: | |
| param_parts = [] | |
| for param in self.cmd.parameters: | |
| match_int = self.param_values[param.name] | |
| match_hex = '0x' + hex(match_int)[2:].rjust(param.num_bytes()*2, '0').upper() | |
| param_parts.append(match_hex) | |
| if len(param_parts) > 0: | |
| cmdstr = f'{self.cmd.name}({",".join(param_parts)})' | |
| else: | |
| cmdstr = f'{self.cmd.name}' | |
| if show_address: | |
| addrstr = hex(self.address)[2:].rjust(2, '0').upper() | |
| cmdstr = f'/* {addrstr} */ {cmdstr}' | |
| if show_bytes: | |
| binstr = ' '.join(hex(b)[2:].rjust(2, '0').upper() for b in self.cmd_bytes) | |
| cmdstr = f'{cmdstr.ljust(40)} /* {binstr} */' | |
| return cmdstr | |
| def __eq__(self, o: object) -> bool: | |
| if isinstance(o, int): | |
| return self.address == o | |
| if isinstance(o, CommandInstance): | |
| return self.address == o.address | |
| return NotImplemented | |
| def __gt__(self, o: object) -> bool: | |
| if isinstance(o, int): | |
| return self.address > o | |
| if isinstance(o, CommandInstance): | |
| return self.address > o.address | |
| return NotImplemented | |
| @dataclass | |
| class ReturnCommandInstance(CommandInstance): | |
| def command_terminates(self): | |
| return True | |
| def __repr__(self) -> str: | |
| return self.to_string() | |
| @dataclass | |
| class JumpCommandInstance(CommandInstance): | |
| noreturn: bool | |
| target_param: CommandParam = field(init=False) | |
| target_param_name: InitVar[str] | |
| def __post_init__(self, input_sequence: bytes, match: re.Match, target_param_name: str): | |
| super().__post_init__(input_sequence, match) | |
| self.target_param = next((p for p in self.cmd.parameters if p.name == target_param_name), None) | |
| if self.target_param is None: | |
| raise ValueError(f"Invalid parameter '{target_param_name}' for command '{self.cmd.name}'") | |
| def get_target_addresses(self) -> List[int]: | |
| l = self.target_param.num_bytes() | |
| value = self.param_values[self.target_param.name] | |
| if l == 2: | |
| return [self.address & 0xff0000 | value & 0xffff] | |
| elif l == 3 or l == 4: | |
| return [value & 0xffffff] | |
| else: | |
| raise ValueError(f"Can't process address with length {l}") | |
| def command_terminates(self): | |
| return self.noreturn | |
| def __repr__(self) -> str: | |
| return self.to_string() | |
| def to_string(self, show_address=False, show_bytes=False, labels:Dict[int,Label]={}) -> str: | |
| param_parts = [] | |
| for param in self.cmd.parameters: | |
| if param == self.target_param: | |
| target_address = self.get_target_addresses()[0] | |
| match_str = labels[target_address].name | |
| else: | |
| match_int = self.param_values[param.name] | |
| match_str = '0x' + hex(match_int)[2:].rjust(param.num_bytes()*2, '0').upper() | |
| param_parts.append(match_str) | |
| if len(param_parts) > 0: | |
| cmdstr = f'{self.cmd.name}({",".join(param_parts)})' | |
| else: | |
| cmdstr = f'{self.cmd.name}' | |
| if show_address: | |
| addrstr = hex(self.address)[2:].rjust(2, '0').upper() | |
| cmdstr = f'/* {addrstr} */ {cmdstr}' | |
| if show_bytes: | |
| binstr = ' '.join(hex(b)[2:].rjust(2, '0').upper() for b in self.cmd_bytes) | |
| cmdstr = f'{cmdstr.ljust(40)} /* {binstr} */' | |
| return cmdstr | |
| cmd_types = defaultdict(lambda: (CommandInstance,()),{ | |
| 'mov_end':(ReturnCommandInstance,()), | |
| 'halt': (ReturnCommandInstance,()), | |
| 'mov_rtl':(ReturnCommandInstance,()), | |
| 'mov_rts':(ReturnCommandInstance,()), | |
| 'mov_jml':(JumpCommandInstance,(True,'addr')), | |
| 'mov_jmp':(JumpCommandInstance,(True,'addr')), | |
| 'mov_jsl':(JumpCommandInstance,(False,'addr')), | |
| 'mov_jsr':(JumpCommandInstance,(False,'addr')), | |
| 'task': (JumpCommandInstance,(False,'addr')), | |
| 'jeq': (JumpCommandInstance,(False,'addr')), | |
| 'jne': (JumpCommandInstance,(False,'addr')), | |
| }) | |
| def init_cmds(): | |
| cmds = [] | |
| cmd_pattern = re.compile(r'command\s+(\w+)((?:\([^)]*\))?)\s+"\[([^\]]*)\]"') | |
| for line in cmds_string.splitlines(): | |
| line, _, _ = line.partition('//') | |
| line = line.strip() | |
| if len(line) <= 0: | |
| continue | |
| match = cmd_pattern.match(line) | |
| if not match: | |
| print(f'Bad command line "{line}"') | |
| continue | |
| name, param_str, code_str = tuple(match.groups()) | |
| # Get list of parameters | |
| param_str = param_str.strip('()') | |
| if len(param_str) == 0: | |
| param_list = [] | |
| else: | |
| param_list = [x.strip() for x in param_str.split(',')] | |
| param_to_num = {x:i for i,x in enumerate(param_list)} | |
| # Parse code str | |
| code_parsed = parse_code_str(code_str) | |
| # Assign match numbers to parameters | |
| parameters = [None for _ in enumerate(param_list)] | |
| match_offset = 1 | |
| for p in code_parsed: | |
| if not isinstance(p, ParseParamReference): | |
| continue | |
| pobj = CommandParam(p, match_offset) | |
| parameters[param_to_num[p.var]] = pobj | |
| match_offset += p.num_bytes() | |
| # Build code parsing regular expression | |
| code_re = build_code_re(code_parsed) | |
| cmd = Command(name, code_re, parameters) | |
| cmds.append(cmd) | |
| return cmds | |
| cmds: List[Command] = init_cmds() | |
| def try_create_command_instance(input_sequence: bytes, address: int) -> Union[None,CommandInstance]: | |
| for cmd in cmds: | |
| m = cmd.code_re.match(input_sequence, addr2off(address)) | |
| if m is None: | |
| continue | |
| # We have a match! | |
| cmd_type, cmd_init_params = cmd_types[cmd.name] | |
| inst = cmd_type(address,cmd,input_sequence,m,*cmd_init_params) | |
| return inst | |
| return None | |
| funcs = { | |
| # 0xC3878C:"script_710", | |
| 0xC386A9:"script_704", | |
| 0xC3886C:"script_711", | |
| 0xC387B6:"script_712", | |
| 0xC388C3:"script_713", | |
| 0xC38939:"script_714", | |
| 0xC389BD:"script_715", | |
| 0xC389DD:"script_716", | |
| # 0xC389FB:"script_717", | |
| # 0xC38AB1:"script_718", | |
| # 0xC38ADC:"script_719", | |
| # 0xC38B3A:"script_720", | |
| } | |
| with open('ebexpanded.smc','rb') as f: | |
| mm = mmap.mmap(f.fileno(), 0x400000, access=mmap.ACCESS_READ) | |
| labels = {f_addr: Label(f_name, f_addr) for f_addr, f_name in funcs.items()} | |
| label_addresses: Set[int] = set(f_addr for f_addr, f_name in funcs.items()) | |
| disasm = SortedList() | |
| to_process = [x for x in funcs.keys()] | |
| for start_addr in to_process: | |
| if start_addr in funcs: | |
| f_name = funcs[start_addr] | |
| else: | |
| f_name = f'unknown_{start_addr:06X}' | |
| address = start_addr | |
| while True: | |
| if address in disasm: | |
| break | |
| cmd_inst = try_create_command_instance(mm, address) | |
| if cmd_inst is None: | |
| raise ValueError(f'illegal command at address 0x{address:06X}') | |
| disasm.add(cmd_inst) | |
| if isinstance(cmd_inst, JumpCommandInstance): | |
| for target in cmd_inst.get_target_addresses(): | |
| label_addresses.add(target) | |
| labels[target] = Label(f'unknown_{target:06X}', target) | |
| if target in disasm or target in to_process: | |
| continue | |
| to_process.append(target) | |
| if cmd_inst.command_terminates(): | |
| break | |
| address += len(cmd_inst.cmd_bytes) | |
| for tmp_x in disasm: | |
| disasm_line: Union[CommandInstance, JumpCommandInstance, ReturnCommandInstance] = tmp_x | |
| if disasm_line.address in label_addresses: | |
| label = labels[disasm_line.address] | |
| print(f'{label.name}: /* {label.address:06X} */') | |
| if isinstance(disasm_line, JumpCommandInstance): | |
| dasm_text = disasm_line.to_string(labels=labels) | |
| else: | |
| dasm_text = disasm_line.to_string() | |
| print(f' {dasm_text}') | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment