;============================================================================================================= ;============================================ SHIP AI DISASSEMBLY ============================================ ;============================================ by Black_Falcon ============================================ ;============================================================================================================= ;Lots of stuff for basic behaviour, but it's pretty straightforward and easy to understand ;You can play around with the settings, everything should be explained ;can be applied using xkas (by default it doesn't change a single byte) ;Sprite data and gfx instructions are NOT included (I simply didn't bother) ;for organizing purposes, I suggest viewing this file using N++ along with my custom stylesheet: ; https://dl.dropboxusercontent.com/u/18141148/website/Hacking%20Stuffz/65816%20asm%28xkas_v.06%29.xml ; have fun! lorom { ;================ SETTINGS !shipsoundtimer = #$0046 ;how many frames to wait until ship sound is played again (loops) !landheightcheck = #$0300 ;when landing on Zebes, the ship starts to slow down at this height !heightcap = #$045F ;caps the height from the floor after landing, basically the spot where the ship is supposed to stop ;timers and movement speed: !Samusgoupwait1 = #$0090 ;frames until Samus starts moving up after landing NOTE: only used once! !Samusgoupwait2 = #$0090 ;frames until Samus starts moving up (regular) !Samusgoupspeed1 = #$0001 ;pixels per frame for how fast Samus moves up after landing NOTE: only used once! !Samusgoupspeed2 = #$0002 ;pixels per frame for how fast Samus moves up (regular) !Samusgodownwait = #$0090 ;frames to wait until Samus is moving down into the ship (regular) !Samusgodownspeed = #$0002 ;pixels per frame for how fast Samus moves down (regular) !Samusmovewait1 = #$0090 ;frames until Samus can move again after landing NOTE: only used once! !Samusmovewait2 = #$0090 ;frames until Samus can move again after refilling (regular) ;Sounds: !Soundhatchopen1 = #$0014 ;sound value for opening ship hatch (library 3) NOTE: only used once! !Soundhatchclose1 = #$0015 ;sound value for closing ship hatch (library 3) NOTE: only used once! !Soundhatchopen2 = #$0014 ;sound value for opening ship hatch after entering (regular, library 3) !Soundhatchclose2 = #$0015 ;sound value for closing ship hatch after entering (regular, library 3) !Soundhatchopen3 = #$0014 ;sound value for opening ship hatch after refilling (regular, library 3) !Soundhatchclose3 = #$0015 ;sound value for closing ship hatch after refilling (regular, library 3) ;refilling: !Refillwait = #$0090 ;frames to wait until stuff is refilled !refillhealth = #$0002 ;values for how fast to refill stuff (units per frame) !refillmissiles = #$0002 !refillsupers = #$0002 !refillpowers = #$0002 ;takeoff: !Takeoffspeed = #$0002 ;speed at which the ship moves up until takeoffheightcheck1 is reached !Takeoffheightcheck = #$0380 ;ship starts to accelerate at this height instead going on a constant speed } { org $A0D07F ;============== UPPER SHIP PART AI HEADER DW $1000 : DW $A59E : DW $0014 : DW $0028 : DW $005C : DW $0028 DW $00A2 : DW $0000 : DW $0000 : DW SETUP1 : DW $0001 : DW $0000 DW RUNNING1 : DW $800F : DW $804C : DW $8041 : DW $0000 : DW $0000 DW $0000 : DW $0000 : DW $804C : DW $0000 : DW $0000 : DW $0000 DW $804C : DW $804C : DW $0000 : DL $ADB600 : DB $02 : DW $F3C2 DW $EC1C : DW $0000 } { org $A0D0BF ;============== LOWER SHIP PART AI HEADER DW $0200 : DW $A59E : DW $0014 : DW $0028 : DW $0060 : DW $0028 DW $00A2 : DW $0000 : DW $0000 : DW SETUP2 : DW $0001 : DW $0000 DW $804C : DW $800F : DW $804C : DW $804C : DW $0000 : DW $0000 ;Running routine points to a simple RTL DW $0000 : DW $0000 : DW $804C : DW $0000 : DW $0000 : DW $0000 DW $804C : DW $804C : DW $0000 : DL $ADB600 : DB $02 : DW $F3C2 DW $EC1C : DW $0000 } ;_____________________________________________________________________________________________________________ ;___________________________________________ MAIN ENTRY POINT __________________________________________ ;_____________________________________________________________________________________________________________ org $A2A622 { SEQUENCE: ;============== MOVEMENT SEQUENCE TABLE (used when ship arrives at the lowest possible spot after landing) DW $0001 : DW $0001 : DW $0001 : DW $0001 : DW $0001 : DW $0001 DW $0000 : DW $0000 : DW $0000 : DW $0000 : DW $0000 DW $FFFF : DW $FFFF : DW $FFFF : DW $FFFF : DW $FFFF : DW $FFFF } { SETUP1: ;============== A2A644 UPPER SHIP PART SETUP ROUTINE LDX $0E54 LDA $0F86,x : ORA #$2400 : STA $0F86,x LDA #$0001 : STA $0F94,x STZ $0F90,x LDA #$A616 : STA $0F92,x LDA #$0E00 : STA $0F96,x LDA $0998 : CMP #$0028 : BEQ + ;check for demo mode - LDA $7ED914 : CMP #$0022 : BNE ++ ;check for landing after ceres LDA $0AFA : SEC : SBC #$0011 : STA $0F7E,x ;take Samus' Y position as a reference for ship's Y position LDA #$A80C : STA $0FB2,x : BRA +++ ;Landing instruction ++ LDA $0F7E,x : SEC : SBC #$0019 : STA $0F7E,x : STA $0FB0,x ;subtract 0x19 from Y and store it to some other address? LDA #IDLE : STA $0FB2,x : BRA +++ ;idle routine (ship moving up/down, checking for button input and Samus position) + LDA $1F55 : BNE - ;check demo scene LDA #$0472 : STA $0AFA ;Samus' Y LDA $0F7E,x : SEC : SBC #$0019 : STA $0F7E,x : STA $0FB0,x ;Same as above, I have no idea why it does that, probably hardcoded position fix or something LDA #$AB60 : STA $0FB2,x ;eject Samus LDA #$0090 : STA $0FA8 ;Timer +++ LDY #$E1C0 : JSL $8DC4E9 ;makes Samus face forward LDA #$0001 : STA $0FAE,x ;another timer STZ $0FAC ;Stuff nobody cares about RTL } { SETUP2: ;============== A2A6D2 LOWER SHIP PART SETUP ROUTINE LDX $0E54 LDA $0F86,x : ORA #$2400 : STA $0F86,x LDA #$0001 : STA $0F94,x STZ $0F90,x LDA $0FB6,x : BEQ + ;check speed2 LDA #$A60E : STA $0F92,x : BRA ++ ;load door + LDA #$A61C : STA $0F92,x ;load lower part of the ship ++ LDA $0F58,x : STA $0F98,x LDA #$0E00 : STA $0F96,x LDA $0FB6,x : BNE + ;branch if door LDA $7ED914 : CMP #$0022 : BNE ++ ;check if landing on Zebes LDA $0AFA : CLC : ADC #$0017 : STA $0F7E,x : BRA +++ ;set position based on Samus' Y ++ LDA $0F7E,x : CLC : ADC #$000F : STA $0F7E,x ;again, hardcoded adjustment? LDA #$0047 : STA $0FAE,x : BRA +++ ;timer, maybe for red lights + LDA $0EFE,x : DEC A : STA $0F7E,x LDA $0998 : CMP #$0028 : BNE +++ LDA $1F55 : BNE +++ LDA #$0001 : STA $0F94,x LDA #$A5BE : STA $0F92,x +++ LDA #$A7D7 : STA $0FB2,x : RTL } { RUNNING1: ;============== MAIN RUNNING ROUTINE LDX $0E54 : DEC $0FEE,x : BEQ + : BPL ++ ;timer check + LDA #$004D : JSL $8090CB ;Ship Sound LDA !shipsoundtimer : STA $0FEE,x ;store timer again ++ LDA $0FB2,x : CMP #WAIT : BMI + ;just check for certain instructions to disable bobbing CMP #RUMBLE : BPL + JSR BOBBING ;bob up/down + JMP ($0FB2,x) : RTL ;jump to instructions, never returns } { BOBBING: ;------- A2A784 BOBBING SUBROUTINE DEC $0FAE,x : BEQ + : BPL ++ + LDA $0FAC,x : ASL A : TAY : LDA BOBPATTERN,y : AND #$00FF : STA $0FAE,x LDA BOBPATTERN+1,y : AND #$00FF : BIT #$0080 : BEQ + ORA #$FF00 + STA $12 LDA $0F7E,x : CLC : ADC $12 : STA $0F7E,x LDA $0FBE,x : CLC : ADC $12 : STA $0FBE,x LDA $0FFE,x : CLC : ADC $12 : STA $0FFE,x LDA $0FAC,x : INC A : AND #$0003 : STA $0FAC,x ++ RTS BOBPATTERN: DB $10, $01, $10, $FF, $10, $FF, $10, $01 } RTL ;------------ A2A7D7 remainder, never used { WEIRD: ;------------ A2A7D8 makes the ship and samus move up really fast to a certain point, then continue to land? probably used for debugging LDA $0AFA : SEC : SBC #$0008 : STA $0AFA ;make Samus and all 3 ship parts move up (8 p/f is quite fast..) LDA $0FFE,x : SEC : SBC #$0008 : STA $0FFE,x LDA $0FBE,x : SEC : SBC #$0008 : STA $0FBE,x LDA $0F7E,x : SEC : SBC #$0008 : STA $0F7E,x : CMP #$0080 : BPL + ;until a height of 0080 has been reached LDA #LANDING1 : STA $0FB2,x ;after going up, go down again? + RTL } { LANDING1: ;------------ A2A80C Part 1 of the Landing sequence, right after the 'fly to zebes cutscene' LDA $0F7E,x : CMP !landheightcheck : BPL + ;check for specific height to slow down the ship LDA $0AFC : CLC : ADC #$8000 : STA $0AFC ;Samus subY LDA $0AFA : ADC #$0004 : STA $0AFA ;Samus Y LDA $1000,x : CLC : ADC #$8000 : STA $1000,x ;other enemy parts' pixel and subpixel Y LDA $0FFE,x : ADC #$0004 : STA $0FFE,x LDA $0FC0,x : CLC : ADC #$8000 : STA $0FC0,x LDA $0FBE,x : ADC #$0004 : STA $0FBE,x LDA $0F80,x : CLC : ADC #$8000 : STA $0F80,x LDA $0F7E,x : ADC #$0004 : STA $0F7E,x ;make Samus and enemy 00 to 02 move down 4.5 pixels/frame RTL + LDA $0AFC : CLC : ADC #$8000 : STA $0AFC LDA $0AFA : ADC #$0002 : STA $0AFA LDA $1000,x : CLC : ADC #$8000 : STA $1000,x LDA $0FFE,x : ADC #$0002 : STA $0FFE,x LDA $0FC0,x : CLC : ADC #$8000 : STA $0FC0,x LDA $0FBE,x : ADC #$0002 : STA $0FBE,x LDA $0F80,x : CLC : ADC #$8000 : STA $0F80,x ;make Samus and enemy 00 to 02 move down 2.5 pixels/frame LDA $0F7E,x : ADC #$0002 : STA $0F7E,x : CMP !heightcap : BMI + ;make the ship stop at this height (see label) LDA !heightcap : STA $0F7E,x : CLC : ADC #$0028 : STA $0FBE,x LDA $0F7E,x : DEC A : STA $0FFE,x LDA #LANDING2 : STA $0FB2,x ;store next instruction STZ $0FB0,x + RTL } { LANDING2: ;------------ A2A8D0 Part 2 of the Landing sequence, runs right when the ship arrives and before Samus comes up LDA $0FB0,x : ASL A : TAY ;small sequence for moving the ship after it arrived on its destination LDA $0AFA : CLC : ADC SEQUENCE,y : STA $0AFA LDA $0FFE,x : CLC : ADC SEQUENCE,y : STA $0FFE,x LDA $0FBE,x : CLC : ADC SEQUENCE,y : STA $0FBE,x LDA $0F7E,x : CLC : ADC SEQUENCE,y : STA $0F7E,x ;this simulates the ship's inertia (so it doesn't suddenly just stop) LDA $0FB0,x : INC A : STA $0FB0,x : CMP #$0011 : BMI + ;this is based on a timer LDA #WAIT : STA $0FB2,x LDA $0F7E,x : STA $0FB0,x LDA #$0001 : STA $0FAE,x STZ $0FAC LDA $0F7A,x : INC A : STA $0AF6 : STA $0B10 ;correct Samus's X position LDA #$0001 : STA $1014,x LDA #$A5BE : STA $1012,x LDA !Samusgoupwait1 : STA $0FA8 ;timer to wait for Samus to come up LDA !Soundhatchopen1 : JSL $80914D + RTL } { WAIT: ;------------ A2A942 DEC $0FA8 : BEQ + : BPL ++ ;decrease timer + LDA #SAMUSGOUP1 : STA $0FB2,x ++ RTL SAMUSGOUP1: LDA $0FB0,x : SEC : SBC #$001E : STA $12 LDA $0AFA : SEC : SBC !Samusgoupspeed1 : STA $0AFA : CMP $12 : BPL + ;make Samus move up the ship elevator LDA #FIRSTLAND : STA $0FB2,x LDA #$0001 : STA $1014,x LDA #$A5EE : STA $1012,x ;enemy 02 closing animation gfx instruction LDA !Samusmovewait1 : STA $0FA8 LDA !Soundhatchclose1 : JSL $80914D ;ship door close sound + RTL } { FIRSTLAND: ;------------ A2A987 Routine runs when Samus first comes out of the ship, only change if you know exactly what you're doing! DEC $0FA8 : BEQ + : BPL ++ ;check timer + LDA #IDLE : STA $0FB2,x ;store next instruction LDA #$E695 : STA $0A42 ;to do with re-enabling Samus movement LDA #$E725 : STA $0A44 ;don't touch these! LDA #$0005 : STA $7ED914 ;stores main gamestate LDA $7ED8F8 : ORA #$0001 : STA $7ED8F8 STZ $078B LDA $0952 : JSL $818000 ;save the game ++ RTL } { IDLE: ;------------ A2A9BD LDA $0998 : CMP #$0008 : BNE + ;gamestate needs to be 8 (main) LDA $0A42 : CMP #$E695 : BNE + ;Samus needs to be 'unlocked' LDA $0F7A,x : SEC : SBC #$0008 : CMP $0AF6 : BPL + ;Next four lines check for where Samus LDA $0F7A,x : CLC : ADC #$0008 : CMP $0AF6 : BMI + ;has to stand in order to get into the ship LDA $0F7E,x : SEC : SBC #$0040 : CMP $0AFA : BPL + LDA $0F7E,x : CMP $0AFA : BMI + LDA $0A1F : AND #$00FF : BNE + ;check movement type LDA $8F : BIT #$0400 : BNE ++ ;check button unput down + RTL ++ LDA #WAIT1 : STA $0FB2,x ;next instruction LDA $0AF6 : CMP #$0480 : BEQ + ;if samus is off-center, correct her X position LDA $0F7A,x : STA $0AF6 : STA $0B10 + JSL $91E3F6 ;Stop timer? Stores some stuff LDA #$001A : JSL $90F084 ;puts samus into facing forward pose STZ $0E18 ;direction to move for elevators LDA $0F7E,x : DEC A : STA $0FFE,x LDA #$0001 : STA $1014,x LDA #$A5BE : STA $1012,x ;instruction for the ship's door opening animation LDA !Samusgodownwait : STA $0FA8 LDA !Soundhatchopen2 : JSL $80914D : RTL ;sound } { WAIT1: ;------------ A2AA4F DEC $0FA8 : BEQ + : BPL ++ + LDA #SAMUSGODOWN : STA $0FB2,x ++ RTL } { SAMUSGODOWN: ;------------ A2AA5D LDA $0FB0,x : CLC : ADC #$0012 : STA $12 LDA $0AFA : CLC : ADC !Samusgodownspeed : STA $0AFA CMP $12 : BMI + LDA #WAIT2 : STA $0FB2,x LDA #$0001 : STA $1014,x LDA #$A5EE : STA $1012,x LDA !Refillwait : STA $0FA8 LDA #$0015 : JSL $80914D + RTL } { WAIT2: ;------------ A2AA94 DEC $0FA8 : BEQ + : BPL ++ + LDA #REFILL : STA $0FB2,x ++ RTL } { REFILL: ;------------ A2AAA2 LDA #$000E : JSL $808233 : BCS + ;event check LDA !refillhealth : JSL $91DF12 ;refill stuff until it's maxed out (health and reserve tanks) LDA !refillmissiles : JSL $91DF80 ;missiles LDA !refillsupers : JSL $91DFD3 ;supers LDA !refillpowers : JSL $91DFF0 ;powers LDA $09D6 : CMP $09D4 : BMI ++ LDA $09C2 : CMP $09C4 : BMI ++ LDA $09C6 : CMP $09C8 : BMI ++ LDA $09CA : CMP $09CC : BMI ++ LDA $09CE : CMP $09D0 : BMI ++ BRA +++ LDA $8D : BIT #$8000 : BEQ +++ ;Controller 2 Input check, never runs, 7 bytes of free space for.. uh, ..free, yeah... + LDA #DUSTVRAM : STA $0FB2,x ;initiate takeoff STZ $0FF2,x : STZ $0FF0,x ;zero enemy 01 related values STZ $0DEC : STZ $0DEE ;vertical speed values? STZ $0DF0 : STZ $0DF2 ;unknown, probably related to speed LDA #$000A : JSL $90F084 : RTL ;not sure, stores #$E90E into $0A5C, CLC and RTS. having no clue what it does atm +++ LDA #SAVEDIALOGUE : STA $0FB2,x ++ RTL } { SAVEDIALOGUE: ;------------ A2AB1F LDA #$001C : JSL $858080 : CMP #$0002 : BEQ + ;load message box 1C (save prompt dialogue) LDA $7ED8F8 : ORA #$0001 : STA $7ED8F8 STZ $078B LDA $0952 : JSL $818000 ;saves the game + LDA #WAIT3 : STA $0FB2,x LDA #$0001 : STA $1014,x ;timer regarding enemy 02 gfx instructions LDA #$A5BE : STA $1012,x ;ship opening animation (enemy 02 gfx instruction) LDA !Samusgoupwait2 : STA $0FA8 ;how many frames to wait LDA !Soundhatchopen3 : JSL $80914D ;ship hatch opening sound RTL } { WAIT3: ;------------ A2AB60 DEC $0FA8 : BEQ + : BPL ++ + LDA #SAMUSGOUP2 : STA $0FB2,x ++ RTL } { SAMUSGOUP2: ;------------ A2AB6E LDA $0FB0,x : SEC : SBC #$001E : STA $12 LDA $0AFA : SEC : SBC !Samusgoupspeed2 : STA $0AFA CMP $12 : BPL + LDA #WAIT4 : STA $0FB2,x LDA #$0001 : STA $1014,x LDA #$A5EE : STA $1012,x LDA !Samusmovewait2 : STA $0FA8 ;frames until Samus can move again LDA !Soundhatchclose3 : JSL $80914D ;ship hatch closing sound + RTL } { WAIT4: ;------------ A2ABA5 Wait a bit, then unlock Samus DEC $0FA8 : BEQ + : BPL ++ + LDA #IDLE : STA $0FB2,x ; so yeah, that's it for the normal ship behaviour LDA $0998 : CMP #$0028 : BPL ++ LDA #$E695 : STA $0A42 LDA #$E725 : STA $0A44 ++ RTL } { DUSTVRAM: ;------------ A2ABC7 loads large dust particles into vram (5 animation frames) LDY $0DEC PHX LDX $0330 : LDA #$0400 : STA $D0,x INX : INX : LDA DUSTSOURCE,y : STA $D0,x ;source address INX : INX : SEP #$20 : LDA #$94 : STA $D0,x : REP #$20 ;source bank1 INX : LDA DUSTDESTINATION,y : STA $D0,x ;vram destination INX : INX : STX $0330 PLX LDA $0DEC : INC A : INC A : STA $0DEC : CMP #$000A : BMI + ;check if all tiles have been loaded LDA #RUMBLE : STA $0FB2,x STZ $0DEC + RTL DUSTSOURCE: DW $C800 ;94C800 DW $CC00 DW $D000 DW $D400 DW $D800 DUSTDESTINATION: DW $7600 ;vram word address, EC00 in byte address DW $7800 ;vram word address, F000 in byte address DW $7A00 ;vram word address, F400 in byte address DW $7C00 ;vram word address, F800 in byte address DW $7E00 ;vram word address, FC00 in byte address } { RUMBLE: ;------------ A2AC1B LDA $0FF0,x : CMP #$0040 : BPL + ;timer check? BIT #$0001 : BEQ ++ ;branch every odd number of times LDA $0AFA : CLC : ADC #$0001 : STA $0AFA : STA $0B14 : BRA +++ ;makes samus 'vibrate' (you can't actually see it) ++ LDA $0AFA : SEC : SBC #$0001 : STA $0AFA : STA $0B14 : BRA +++ + BIT #$0001 : BEQ + LDA $0AFA : CLC : ADC #$0002 : STA $0AFA : STA $0B14 : BRA +++ ;makes her vibrate harder (that sounds so wrong...) + LDA $0AFA : SEC : SBC #$0002 : STA $0AFA : STA $0B14 +++ LDA $0AFA : SEC : SBC #$0011 : STA $0F7E,x : DEC A : STA $0FFE,x ;base ship's position on Samus' (makes the ship vibrate) LDA $0AFA : CLC : ADC #$0017 : STA $0FBE,x LDA $0FF0,x : INC A : STA $0FF0,x : CMP #$0080 : BMI + ;wait 0x80 frames for takeoff (no label for this because it does some trickery here) LDA #TAKEOFF1 : STA $0FB2,x STZ $0FA8 RTL + CMP #$0040 : BNE + ;animate dust after 0x40 frames LDA #$0000 : LDY #$A379 : JSL $868097 LDA #$0002 : LDY #$A379 : JSL $868097 LDA #$0004 : LDY #$A379 : JSL $868097 LDA #$0006 : LDY #$A379 : JSL $868097 LDA #$0008 : LDY #$A379 : JSL $868097 LDA #$000A : LDY #$A379 : JSL $868097 + RTL } { TAKEOFF1: ;------------ A2ACD7 LDA $0AFA : SEC : SBC !Takeoffspeed : STA $0AFA LDA $0AFA : SEC : SBC #$0011 : STA $0F7E,x : DEC A : STA $0FFE,x LDA $0AFA : CLC : ADC #$0017 : STA $0FBE,x LDA $0F7E,x : CMP !Takeoffheightcheck : BPL + LDA #TAKEOFF2 : STA $0FB2,x LDA #$0200 : STA $0FF2,x + RTL } { TAKEOFF2: ;------------ A2AD0E JSL TAKEOFF3 LDA $0F7E,x : CMP #$0100 : BPL + ;after a certain height is reached, store game state Zebes explodes (fades to black, ship continues to fly up) LDA #TAKEOFF3 : STA $0FB2,x ;fly up until game blacks out LDA #$0026 : STA $0998 STZ $0723 : STZ $0725 + RTL } { TAKEOFF3: ;------------ A2AD2D accelerates the ship until it reaches the ceiling LDA $0FF2,x : CLC : ADC #$0040 : STA $0FF2,x ;timer of some sort AND #$FF00 : CMP #$0A00 : BMI + ; LDA #$0900 : STA $0FF2,x + LDA $0FF2,x : XBA : PHA : AND #$FF00 : STA $14 PLA : AND #$00FF : STA $12 LDA $0AFC : SEC : SBC $14 : STA $0AFC LDA $0AFA : SBC $12 : STA $0AFA LDA $0AFA : SEC : SBC #$0011 STA $0F7E,x : DEC A : STA $0FFE,x LDA $0AFA : CLC : ADC #$0017 : STA $0FBE,x RTL }