Skip to content

Instantly share code, notes, and snippets.

@pixjuan
Last active May 8, 2022 05:46
Show Gist options
  • Save pixjuan/e3e26a070b958bd415e467a2e93dbdda to your computer and use it in GitHub Desktop.
Save pixjuan/e3e26a070b958bd415e467a2e93dbdda to your computer and use it in GitHub Desktop.
Apple II Sabotage memory map

Apple II Sabotage Reverse Engineering

The goal is to try to understand the behaviour of the AI in Sabotage (Copyright 1981, Mark Allen), and more generally to do some reverse engineering on this game for educational purpose. I'm taking notes in this gist, I will try to produce something easier to read later. Archive.org got an online playable version of this game : https://archive.org/details/a2_asimov_sabotage

Method

I first used LinApple emulator to make a dump of the memory, then, I used a disassembler to try to understand the game. I also used the Mame debugger to disable various parts of the game and understand their purpose.

Structures

I isolated some structures, it was easy to guess ther size because of the increment that was done on some loops, but it was harder to figure out the exact use of all the fields.

struct bullet

BYTE notsure

WORD bullet_X     : X position of the bullet

WORD bullet_Y     : Y position of the bullet

WORD bullet_DX    : X speed of the bullet

WORD bullet_DY    : Y speed of the bullet

struct para

BYTE notsure

BYTE parastatus:   0      : paratrooper is inactive?
           FF     : special
           >80    : free fall

BYTE index_in_zone40: X position for the paratrooper (the screen is split in 40 columns)

BYTE YPos:          : Y position of the paratrooper

BYTE notsure2:

struct helijet

BYTE index_for_data   : index to fetch graphic data
              2   : heli going right
              4   : heli going left
              6   : jet going right
              8   : jet going left

BYTE Ypos     : Y position

BYTE XPos     : X position

BYTE frame_index  : frame index for the animation

BYTE gfx_type     : a bit like index_for_data? 0 means exploding

BYTE new_Ypos     : Y position after update

BYTE new_XPos     : X position after update

BYTE new_frame_index  :next frame for animation

BYTE XSpeed_maybe : horizontal speed

BYTE YSpeed_maybe : vertical speed

memory map

Address        function / var

0000:4000 init_score() 0000:400E startscreen_400E() 0000:412A mainloop_412A() 0000:4207 wait_function() 0000:4212 check_paddle() 0000:423F check_paddle_fire() 0000:4266 endless_loop() 0000:427A gameloop_427A() 0000:4299 loop_4299() 0000:42E1 angle_tourelle 0000:42E4 random_var_42E4 0000:42E5 random_var_42E5 0000:42E6 highscore_l 0000:42E7 highscore_h 0000:42E9 angle_tourelle3 0000:42EA angle_tourelle2 0000:42EB score_l 0000:42EC score_h 0000:42F5 BulletArray 0000:4345 HeliJet_array 0000:436D para_array 0000:43E5 para_on_floor_array 0000:440D lookup_table_440D 0000:4413 lookup_table_4413 0000:441C send_enemy_441C() 0000:454D drop_para_454D() 0000:455F loop_455F() 0000:45A1 zone40 0000:460C altitude_table_460C 0000:4614 left_alt_array_4614 0000:461C right_alt_array_461C 0000:4624 draw_tourelle 0000:469D lookup_div3_469D 0000:4ABE parafall_4ABE() 0000:4BC3 wait_function2() 0000:4BCB draw_fall_para() 0000:4BE0 draw_para() 0000:4C32 draw_man() 0000:4CE6 paras_stuff_4CE6() 0000:4D36 para_stuff_4D36() 0000:4D4A parastack_height_table 0000:4D56 power_of_two 0000:4D5E LineAddrHigh 0000:4E1E LineAddrLow 0000:4EDE LookupTable_abs7 0000:4FF6 LookupTable_Mod7 0000:510E sub_510E() 0000:52D5 lookup_52D5 0000:52E8 frameIndex_52E8 0000:52E9 XPos_52E9 0000:52EA YPos_52EA 0000:52EB XSpeed_52EB 0000:52EC YSpeed_52EC 0000:52EE explosion_animation_52EE() 0000:5402 init_collide_76_5658() 0000:5420 draw_xplod_frag_5420() 0000:5460 frag_collide_detect_5460() 0000:5491 detect_parafrag_5491() 0000:5552 frag_collide_5552() 0000:560B burst_kill_HLC() 0000:5646 frag_array_5646 0000:5658 ptr_array_5658 0000:58F8 parattack_58F8 0000:5A6B draw_para_walking() 0000:5B58 para_bitmap 0000:5BB8 inc_score() 0000:5BE6 dec_score() 0000:5C12 score_gfx_upd() 0000:5CEC init_stuff() 0000:5DEA fire_stuff() 0000:5E83 bullet_origin_5E83 0000:5EAC draw_move_bullet() 0000:5FCF bullet_related_stuff() 0000:6018 bullet_para_collide() 0000:609B shoot_para_stuff 0000:60AD steerable_bullets 0000:60B8 Bullet_traj 0000:619A send_helijet_619A() 0000:6277 array_6277 0000:628A move_helijet() 0000:6367 locret_6367 0000:6368 draw_helico_jet() 0000:641F helijet_data_ptr 0000:642A helijet_data2 0000:6452 helijet_data3 0000:64C2 helijet_data4 0000:6542 helijet_data5 0000:688A bullet_heli_collide_688A() 0000:68EC no_collision_68EC 0000:68F8 shoot_HLC_stuff 0000:6928 jet_drop_bomb_maybe2() 0000:69D6 jet_drop_bomb_maybe() 0000:6A87 draw_bomb() 0000:6AC9 bullet_stuff_6AC9() 0000:6ACF bullet_stuff_6ACF() 0000:6B1D shootbomb_stuff() 0000:6B2F bomb_frag_6B2F() 0000:6C06 gameloop_6C06() 0000:6C31 draw_stuff_6C31() 0000:6C5C bullet_sound() 0000:7131 init_7131() 0000:7155 init_7155() 0000:7166 init_7166() 0000:718A init_718A() 0000:719A init_719A() 0000:71A4 index_memcpy

@fschuhi
Copy link

fschuhi commented Feb 20, 2019

Interesting and ambitious project. What is the current state? Any other games in the pipeline?

@hfeiges
Copy link

hfeiges commented Feb 7, 2021

Hello,

I really wanted a cheat for Sabotage. After not finding one anywhere, I endeavored to come up with one of my own. This memory map has helped me out a lot...

I added to your post at 6502.org here

Here are some locations that I found (or verified) that you could add to your memory map (after your validation, of course):

$42E8 : dead/alive state (00 is alive, FF is dead to bomber)

$5928...$5932 <- Add up # of men on right side
$5937...$5941 <- Add up # of men on left side
$5930 : 04 <- # of men on right side (game over) <- Modify this value (to > 4) for cheat
$593F : 04 <- # of men on left side (game over) <- Modify this value (to > 4) for cheat

$69D6 : Routine for drop bomb (called from $413E)

$6A65 : Bomb has hit (BCC prior instuction falls through to here If reg A [bomb vertical position?] >= #$9B)
$6A74 : JSR to $6B2F (explosion)  <- Modify this address (to #$60) for cheat (bomb proof, RTS before bomb explosion, skip death)
$6A77 : Post explosion <- Modify this address (to #$60) for cheat (bomb proof, RTS after bomb explosion, skip death)

$6A78 : FF <- Modify this value (to 0) for cheat (bomb proof, reccomended mod for bomb proof cheat)
$6A79 : STA $42E8 (store #$FF (death state) to dead/alive location after bomb hit)

$6B2F : Routine for bomb explosion animation

Here is an applesoft basic implementation of a cheat for sabotage... Please see the post at 6502.org for more explanation. This will give you (basically) unlimited paratroopers on the ground on right side and left side, and make the turret bomb-proof:

10  HOME 
20  PRINT  CHR$ (4);"BLOAD SABOTAGE,A$1D00"
30  POKE 14640,255
40  POKE 14655,255
50  POKE 19064,0
60  CALL 7424

.. Hope someone finds this useful :)

... Howard

.... Edit .....

Here is some extra cheat code... Lines 60-90 address the last 2 vulnerabilities (one man on turret, and three men next to turret), to complete the cheat... With this extra code the game can run forever and ever on its own...

 10  HOME 
 20  PRINT  CHR$ (4);"BLOAD SABOTAGE,A$1D00"
 30  POKE 14640,255
 40  POKE 14655,255
 50  POKE 19064,0
 60  POKE 14604,255
 70  POKE 14611,255
 80  POKE 14618,255
 90  POKE 14625,255
 10000  CALL 7424

@pixjuan
Copy link
Author

pixjuan commented Feb 8, 2021

Interesting and ambitious project. What is the current state? Any other games in the pipeline?

Sorry for the delay, I must have missed the notification for your message.
I recently resumed my work on this project using Ghidra, but I still need some work to clean up and finish this.
I may reverse a few C64 games sometime in the future, but I haven't decided which games I'll do first.

@pixjuan
Copy link
Author

pixjuan commented Feb 8, 2021

Here are some locations that I found (or verified) that you could add to your memory map (after your validation, of course):

Thanks Howard, I will use this information in my next update

@fadden
Copy link

fadden commented Oct 9, 2021

About a year ago I spent a day poking at the game. I didn't get very far; you can see the result here: https://6502disassembly.com/_sb/Sabotage.html

I did identify most of the graphics, so you can see e.g. the turret at $46fd.

@pixjuan
Copy link
Author

pixjuan commented Oct 10, 2021

@fadden Thank you for link!
I didn't know your tool 6502bench, it seems very nice, I like the inline bitmap display.
For Sabotage, I used a more generic tools, IDA first, then Ghidra.
I did a Python script that rips most of the graphics, and started writing a python remake.

Your message reminds me that I really need to get my code and my Ghidra reverse in a publishable state and push it to a repo!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment