diff options
Diffstat (limited to 'src/replay.S')
-rw-r--r-- | src/replay.S | 799 |
1 files changed, 799 insertions, 0 deletions
diff --git a/src/replay.S b/src/replay.S new file mode 100644 index 0000000..8c3f6c7 --- /dev/null +++ b/src/replay.S @@ -0,0 +1,799 @@ +# Fucking Nintendo, how do they work + +.extern IOS_Open +.extern IOS_Close +.extern IOS_Read +.extern IOS_Write +.extern OSGetTime +.extern OSTicksToCalendarTime +.extern OSReport +.extern CurrentWorld +.extern CurrentLevel +.extern CurrentStartedArea +.extern CurrentStartedEntrance +.extern snprintf +.extern GetSomeGlobalClass +.extern SomeUnknownClass5408 +.extern SomeWipeClass +.extern continueFromReplayHookStart +.extern continueFromReplayEndHook +.extern returnFromRecorder +.extern QueryGlobal5758 +.extern GetRandomSeed +.extern Player_ID +.extern Player_Powerup +.extern Player_Flags +.extern EGG__Heap__alloc__FUliPv +.extern EGG__Heap__free__FPvPv +.extern GameHeap2 +.extern EggControllerClassPtrMaybe +.extern GameMgr +.extern StrangeReplayValue1 +.extern StrangeReplayValue2 +.extern StrangeReplayValue3 +.extern WiimotePtr1 +.extern Player_ID +.extern RandomSeed + +.set sp, 1 + +# mode 1 = read, 2 = write? + +.text +.align 4 + +.global replayStart +.global replayEnd +.global replayRecord + +.global luigiOverride +luigiOverride: + #blr + lis r3, Player_ID@h + ori r3, r3, Player_ID@l + li r4, 1 + stw r4, 0(r3) + blr + +.global getAndSaveRandomSeed +getAndSaveRandomSeed: # b from 8091F930 + lis r3, RandomSeed@h + ori r3, r3, RandomSeed@l + lwz r3, 0(r3) + lis r4, saveRandomSeed@h + ori r4, r4, saveRandomSeed@l + stw r3, 0(r4) + + mr r4, r3 + lis r3, str_gotSeed@h + ori r3, r3, str_gotSeed@l + crclr 4*cr1+eq + bl OSReport + + lwz r0, 0x74(sp) + mtlr r0 + addi sp, sp, 0x70 + blr + + +replayStart: # b from 809246E0 + bl OSGetTime + lis r5, replayTime@h + ori r5, r5, replayTime@l + bl OSTicksToCalendarTime + + li r29, 0 + li r30, 0 + +replayStartLoop: + + lis r3, str_replayFileNameBuffer@h + ori r3, r3, str_replayFileNameBuffer@l + + li r4, 64 + + lis r5, str_replayFileNameFormat@h + ori r5, r5, str_replayFileNameFormat@l + + lis r6, CurrentWorld@h + ori r6, r6, CurrentWorld@l + lbz r6, 0(r6) + addi r6, r6, 1 + + lis r7, CurrentLevel@h + ori r7, r7, CurrentLevel@l + lbz r7, 0(r7) + addi r7, r7, 1 + + lis r8, replayTime_hour@h + ori r8, r8, replayTime_hour@l + lwz r8, 0(r8) + + lis r9, replayTime_min@h + ori r9, r9, replayTime_min@l + lwz r9, 0(r9) + + mr r10, r29 + + crclr 4*cr1+eq + bl snprintf + + lis r4, str_replayFileNameBuffer@h + ori r4, r4, str_replayFileNameBuffer@l + lis r3, str_startMsg@h + ori r3, r3, str_startMsg@l + crclr 4*cr1+eq + bl OSReport + + lis r3, str_replayFileNameBuffer@h + ori r3, r3, str_replayFileNameBuffer@l + + li r4, 0x602 # O_WRITE | O_CREAT | O_TRUNC + + bl IOS_Open + + cmpwi r3, 0 + blt iosOpenFail + + lis r4, replayHandles@h + ori r4, r4, replayHandles@l + stwx r3, r4, r30 + + mr r4, r3 + lis r3, str_iosOpenMsg@h + ori r3, r3, str_iosOpenMsg@l + crclr 4*cr1+eq + bl OSReport + + # now write the header + lis r4, replayHeaders@h + ori r4, r4, replayHeaders@l + lwzx r4, r4, r30 + + lis r6, CurrentWorld@h + ori r6, r6, CurrentWorld@l + lis r7, CurrentLevel@h + ori r7, r7, CurrentLevel@l + lis r8, CurrentStartedArea@h + ori r8, r8, CurrentStartedArea@l # WRONG + lis r9, CurrentStartedEntrance@h + ori r9, r9, CurrentStartedEntrance@l # WRONG + + lbz r6, 0(r6) + lbz r7, 0(r7) + + stb r6, 0(r4) + stb r7, 1(r4) + stb r8, 2(r4) + stb r9, 3(r4) + + lis r3, saveRandomSeed@h + ori r3, r3, saveRandomSeed@l + lwz r3, 0(r3) + stw r3, 4(r4) + + # player ID specific stuff + mr r5, r29 + slwi r5, r5, 2 + + lis r3, Player_ID@h + ori r3, r3, Player_ID@l + lwzx r3, r3, r5 + slwi r6, r3, 2 # store this so we can get the powerup and flags + stw r3, 0x10(r4) + + lis r3, Player_Powerup@h + ori r3, r3, Player_Powerup@l + lwzx r3, r3, r6 + stw r3, 0x14(r4) + + lis r3, Player_Flags@h + ori r3, r3, Player_Flags@l + lwzx r3, r3, r6 + stw r3, 0x18(r4) + + lis r3, GameMgr@h + ori r3, r3, GameMgr@l + lwz r3, 0(r3) + lbz r3, 0x380(r3) + stb r3, 0x21(r4) + + # now set up variables + lis r4, replayFrameCounts@h + ori r4, r4, replayFrameCounts@l + li r3, 0 + stwx r3, r4, r30 + + lis r3, replayFlags@h + ori r3, r3, replayFlags@l + li r4, 1 + not r0, r4 + lhz r4, 0(r3) + clrlwi r0, r0, 16 + and r4, r4, r0 + slwi r5, r29, 1 # player ID * 2 + sthx r4, r3, r5 + + li r3, 0 + lis r4, keepTiltValues@h + ori r4, r4, keepTiltValues@l + stwx r3, r4, r30 + + lis r4, replayDataBufferSize@h + ori r4, r4, replayDataBufferSize@l + lwz r3, 0(r4) + + # alloc the memory + li r4, 4 + lis r5, GameHeap2@h + ori r5, r5, GameHeap2@l + lwz r5, 0(r5) + bl EGG__Heap__alloc__FUliPv + + lis r4, replayDataBuffers@h + ori r4, r4, replayDataBuffers@l + stwx r3, r4, r30 + + lis r4, replayDataBufferPointers@h + ori r4, r4, replayDataBufferPointers@l + stwx r3, r4, r30 + + mr r4, r3 + lis r3, str_bufferObtained@h + ori r3, r3, str_bufferObtained@l + crclr 4*cr1+eq + bl OSReport + + b startNextReplay + +iosOpenFail: + mr r4, r3 + lis r3, str_iosOpenFailed@h + ori r3, r3, str_iosOpenFailed@l + crclr 4*cr1+eq + bl OSReport + +startNextReplay: + + # the loop + addi r29, r29, 1 + addi r30, r30, 4 + cmpwi r29, 4 + blt replayStartLoop + + # and done! + li r3, 1 + b continueFromReplayHookStart # 809246E4 + + + +magicalReplayCheck: + stwu sp, -0x10(sp) + mflr r0 + stw r0, 0x14(sp) + stw r31, 0x0C(sp) + mr r31, r3 + + bl GetSomeGlobalClass + + lwz r0, 0x1D0(r3) + cmpwi r0, 2 + bne no_flag_20 + + ori r31, r31, 0x20 + b done_flag_20 + +no_flag_20: + li r4, 0x20 + not r4, r4 + and r31, r31, r4 + +done_flag_20: + lis r3, SomeUnknownClass5408@h # 8042A578 + ori r3, r3, SomeUnknownClass5408@l + lwz r3, 0(r3) + lbz r3, 4(r3) + + cmpwi r3, 0 + beq no_flag_40 + + ori r31, r31, 0x40 + b done_flag_40 + +no_flag_40: + li r4, 0x40 + not r4, r4 + and r31, r31, r4 + +done_flag_40: + lis r3, SomeWipeClass@h # 8042A720 + ori r3, r3, SomeWipeClass@l + lwz r3, 0(r3) + lwz r12, 0(r3) + lwz r12, 0x10(r12) + mtctr r12 + bctrl + + subi r0, r3, 1 + cntlzw r0, r0 + srwi. r0, r0, 5 + beq set_flag_2 + + li r4, 2 + not r4, r4 + and r31, r31, r4 + b done_flag_2 + +set_flag_2: + ori r31, r31, 2 + +done_flag_2: + li r3, 1 + bl QueryGlobal5758 + + cmpwi r3, 0 + beq no_flag_4 + + ori r31, r31, 4 + b done_flag_4 + +no_flag_4: + li r4, 4 + not r4, r4 + and r31, r31, r4 + +done_flag_4: + li r3, 4 + bl QueryGlobal5758 + + cmpwi r3, 0 + beq no_flag_100 + + ori r31, r31, 0x100 + b done_flag_100 + +no_flag_100: + li r4, 0x100 + not r4, r4 + and r31, r31, r4 + +done_flag_100: + li r3, 2 + bl QueryGlobal5758 + + cmpwi r3, 0 + beq no_flag_8 + + ori r31, r31, 8 + b done_flag_8 + +no_flag_8: + li r4, 8 + not r4, r4 + and r31, r31, r4 + +done_flag_8: + # okay, we're done + mr r3, r31 + + lwz r0, 0x14(sp) + lwz r31, 0x0C(sp) + mtlr r0 + addi sp, sp, 0x10 + blr + + + + + +replayEnd: # bl from 80102238 + stwu sp, -0x20(sp) + mflr r0 + stw r0, 0x24(sp) + stw r31, 0x1C(sp) + stw r30, 0x18(sp) + stw r29, 0x14(sp) + + cmpwi r3, 1 + bne justLeave + + li r29, 0 + li r30, 0 + +replayEndLoop: + lis r31, replayHandles@h + ori r31, r31, replayHandles@l + add r31, r31, r30 # becomes a pointer to the handle, not the handle itself + + lwz r3, 0(r31) + cmpwi r3, 0 + beq dontEndThisReplay + + lis r4, replayHeaders@h + ori r4, r4, replayHeaders@l + lwzx r4, r4, r30 + li r5, 0x40 + bl IOS_Write + + lwz r3, 0(r31) + lis r4, replayDataBuffers@h + ori r4, r4, replayDataBuffers@l + lwzx r4, r4, r30 + lis r5, replayDataBufferPointers@h # calc written size + ori r5, r5, replayDataBufferPointers@l + lwzx r5, r5, r30 + subf r5, r4, r5 + bl IOS_Write + + lwz r3, 0(r31) + lis r4, replayFooter@h + ori r4, r4, replayFooter@l + li r5, 4 + bl IOS_Write + + lwz r3, 0(r31) + bl IOS_Close + + li r3, 0 + stw r3, 0(r31) + + lis r4, replayDataBuffers@h + ori r4, r4, replayDataBuffers@l + lwzx r3, r4, r30 + li r4, 0 + bl EGG__Heap__free__FPvPv + + lis r4, replayDataBuffers@h + ori r4, r4, replayDataBuffers@l + li r0, 0 + stwx r0, r4, r30 + + lis r3, str_endMsg@h + ori r3, r3, str_endMsg@l + lis r4, replayFrameCounts@h + ori r4, r4, replayFrameCounts@l + lwzx r4, r4, r30 + crclr 4*cr1+eq + bl OSReport + + # before we leave, set the flag again + lis r3, replayFlags@h + ori r3, r3, replayFlags@l + add r3, r3, r29 + add r3, r3, r29 + lhz r4, 0(r3) + ori r4, r4, 1 + sth r4, 0(r3) + +dontEndThisReplay: + + # now loop + addi r29, r29, 1 + addi r30, r30, 4 + cmpwi r29, 4 + blt replayEndLoop + + li r3, 1 + +justLeave: + + lwz r0, 0x24(sp) + lwz r31, 0x1C(sp) + lwz r30, 0x18(sp) + lwz r29, 0x14(sp) + mtlr r0 + addi sp, sp, 0x20 + blr + #b continueFromReplayEndHook # 8010223C + + + + +replayRecord: + # fun shit. + stwu sp, -0x10(sp) + mflr r0 + stw r0, 0x14(sp) + stw r31, 0xC(sp) + stw r30, 8(sp) + + li r30, 0 + +recordLoop: + # get the controller class + lis r31, EggControllerClassPtrMaybe@h + ori r31, r31, EggControllerClassPtrMaybe@l + lwz r31, 0(r31) + slwi r3, r30, 2 + addi r3, r3, 4 + lwzx r31, r31, r3 + + # get player number + mr r4, r30 + + lis r3, replayFlags@h + ori r3, r3, replayFlags@l + add r3, r3, r4 + add r3, r3, r4 # get pointer to flags + lhz r3, 0(r3) + + bl magicalReplayCheck + lwz r5, 4(r31) + lis r4, replayFlags@h + ori r4, r4, replayFlags@l + add r4, r4, r5 + add r4, r4, r5 + sth r3, 0(r4) + + #mr r4, r3 + #lis r3, str_debugFlags@h + #ori r3, r3, str_debugFlags@l + #crclr 4*cr1+eq + #bl OSReport + + #lis r3, replayFlags@h + #ori r3, r3, replayFlags@l + #lhz r3, 0(r3) + cmpwi r3, 0 + bne goToNextRecorder + + # set this to player number * 4 + # r31 is our controller class + lwz r9, 4(r31) + slwi r9, r9, 2 + + lis r3, replayFrameCounts@h + ori r3, r3, replayFrameCounts@l + lwzx r4, r3, r9 + addi r4, r4, 1 + stwx r4, r3, r9 + + # put together the data + # first grab a pointer + lis r7, replayDataBufferPointers@h + ori r7, r7, replayDataBufferPointers@l + lwzx r6, r7, r9 + + cmpwi r6, 0 + beq goToNextRecorder + + # first off, grab the initial flags + li r3, 0 + + lbz r4, 0x8C(r31) # shake flag + cmpwi r4, 1 + bne dontShake + oris r3, r3, 0x2000 +dontShake: + + # now do the tilt stuff + lis r4, keepTiltValues@h + ori r4, r4, keepTiltValues@l + lwzx r0, r4, r9 # last value + lhz r5, 0x8E(r31) # new value + stwx r5, r4, r9 # store new value + cmpw r5, r0 + beq tiltDidntChange + oris r3, r3, 0x80 +tiltDidntChange: + + # ok, so we decided that, now write the flags + weird value + etc! + stw r3, 0(r6) + + # calculate the weird value + li r3, 0 + + lis r10, StrangeReplayValue1@h + ori r10, r10, StrangeReplayValue1@l + lhz r10, 0(r10) + slwi r10, r10, 16 + or r3, r3, r10 + + lis r10, StrangeReplayValue2@h + ori r10, r10, StrangeReplayValue2@l + lbz r10, 0(r10) + slwi r10, r10, 8 + or r3, r3, r10 + + lis r10, StrangeReplayValue3@h + ori r10, r10, StrangeReplayValue3@l + lbz r10, 0(r10) + or r3, r3, r10 + + stw r3, 4(r6) + + # buttons + lwz r3, 0xC(r31) + li r4, 0x0F0F + and r3, r3, r4 + stw r3, 8(r6) + + addi r6, r6, 0xC # we wrote 0xC bytes + + # now the tilt segment + beq dontWriteTilt + sth r5, 0(r6) + li r3, 0 + sth r3, 2(r6) + addi r6, r6, 4 + +dontWriteTilt: + # are we done now?! + # I hope so. + + lis r7, replayDataBufferPointers@h + ori r7, r7, replayDataBufferPointers@l + stwx r6, r7, r9 + + # before we do this. check if we should end the replay + # the raw button presses are at 0x18 in the Wiimote class + lis r5, WiimotePtr1@h + ori r5, r5, WiimotePtr1@l + lwzx r3, r5, r9 + lwz r3, 0x18(r3) + li r4, 0x0400 # B button mask + and. r3, r3, r4 + beq goToNextRecorder + + # end it! + li r3, 1 + bl replayEnd + b leaveRecordLoop + +goToNextRecorder: + + addi r30, r30, 1 + cmpwi r30, 4 + blt recordLoop + +leaveRecordLoop: + + lwz r31, 0xC(sp) + lwz r30, 8(sp) + lwz r0, 0x14(sp) + mtlr r0 + addi sp, sp, 0x10 + blr + + +.data + +replayFlags: .short 1, 1, 1, 1 +.align 4 + +replayHandles: .long 0, 0, 0, 0 + +replayFrameCounts: .long 0, 0, 0, 0 + +replayTime: +replayTime_sec: .long 0 +replayTime_min: .long 0 +replayTime_hour: .long 0 +replayTime_mday: .long 0 +replayTime_mon: .long 0 +replayTime_year: .long 0 +replayTime_wday: .long 0 +replayTime_yday: .long 0 +replayTime_msec: .long 0 +replayTime_usec: .long 0 + +str_replayFileNameFormat: + .string "file/Replay_%02d-%02d_from_%02d-%02d_p%d.bin" + +str_replayFileNameBuffer: + .byte 0,0,0,0,0,0,0,0 + .byte 0,0,0,0,0,0,0,0 + .byte 0,0,0,0,0,0,0,0 + .byte 0,0,0,0,0,0,0,0 + .byte 0,0,0,0,0,0,0,0 + .byte 0,0,0,0,0,0,0,0 + .byte 0,0,0,0,0,0,0,0 + .byte 0,0,0,0,0,0,0,0 + +str_startMsg: + .string "*** Replay Recorder by Treeki -- Starting to record. Filename: %s\n" + +str_iosOpenMsg: + .string "*** Replay Recorder -- IOS_Open returned: %d\n" + +str_iosOpenFailed: + .string "*** Replay Recorder -- IOS_Open failed! It returned: %d -- The replay will not be saved.\n" + +str_bufferObtained: + .string "*** Replay Recorder -- Allocated replay buffer at %p\n" + +str_endMsg: + .string "*** Replay Recorder -- Recording complete. %d frames saved.\n" + +str_debugFlags: + .string "DEBUG:%04x\n" + +str_gotSeed: + .string "Got random seed: %08x\n" + +.align 4 + +replayHeaders: + .long replayHeader0 + .long replayHeader1 + .long replayHeader2 + .long replayHeader3 + +replayHeader0: +replayHeader0_world: .byte 0 +replayHeader0_level: .byte 0 +replayHeader0_area: .byte 0 +replayHeader0_entrance: .byte 0 +replayHeader0_seed: .long 0 +replayHeader0_padding08: .long 0xFFFFFFFF, 0xFFFFFFFF +replayHeader0_playerID: .long 0 +replayHeader0_powerup: .long 0 +replayHeader0_playerFlg: .long 0 +replayHeader0_padding1C: .long 0xFFFFFFFF +replayHeader0_padding20: .byte 0xFF +replayHeader0_switchFlg: .byte 0 +replayHeader0_padding22: .byte 0xFF, 0xFF +replayHeader0_padding24: .long 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF +replayHeader0_padding30: .long 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF +replayHeader1: +replayHeader1_world: .byte 0 +replayHeader1_level: .byte 0 +replayHeader1_area: .byte 0 +replayHeader1_entrance: .byte 0 +replayHeader1_seed: .long 0 +replayHeader1_padding08: .long 0xFFFFFFFF, 0xFFFFFFFF +replayHeader1_playerID: .long 0 +replayHeader1_powerup: .long 0 +replayHeader1_playerFlg: .long 0 +replayHeader1_padding1C: .long 0xFFFFFFFF +replayHeader1_padding20: .byte 0xFF +replayHeader1_switchFlg: .byte 0 +replayHeader1_padding22: .byte 0xFF, 0xFF +replayHeader1_padding24: .long 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF +replayHeader1_padding30: .long 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF +replayHeader2: +replayHeader2_world: .byte 0 +replayHeader2_level: .byte 0 +replayHeader2_area: .byte 0 +replayHeader2_entrance: .byte 0 +replayHeader2_seed: .long 0 +replayHeader2_padding08: .long 0xFFFFFFFF, 0xFFFFFFFF +replayHeader2_playerID: .long 0 +replayHeader2_powerup: .long 0 +replayHeader2_playerFlg: .long 0 +replayHeader2_padding1C: .long 0xFFFFFFFF +replayHeader2_padding20: .byte 0xFF +replayHeader2_switchFlg: .byte 0 +replayHeader2_padding22: .byte 0xFF, 0xFF +replayHeader2_padding24: .long 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF +replayHeader2_padding30: .long 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF +replayHeader3: +replayHeader3_world: .byte 0 +replayHeader3_level: .byte 0 +replayHeader3_area: .byte 0 +replayHeader3_entrance: .byte 0 +replayHeader3_seed: .long 0 +replayHeader3_padding08: .long 0xFFFFFFFF, 0xFFFFFFFF +replayHeader3_playerID: .long 0 +replayHeader3_powerup: .long 0 +replayHeader3_playerFlg: .long 0 +replayHeader3_padding1C: .long 0xFFFFFFFF +replayHeader3_padding20: .byte 0xFF +replayHeader3_switchFlg: .byte 0 +replayHeader3_padding22: .byte 0xFF, 0xFF +replayHeader3_padding24: .long 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF +replayHeader3_padding30: .long 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF + +# header size is 0x40 bytes + +replayFooter: .long 0xFFFFFFFF + +replayDataBuffers: .long 0, 0, 0, 0 +replayDataBufferPointers: .long 0, 0, 0, 0 +replayDataBufferSize: .long 0x80000 + +saveRandomSeed: .long 0 + + +keepTiltValues: .long 0, 0, 0, 0 + |