.set rC, 3 # SHOULD NOT BE USE UNTIL checkAreaLock ENDS .set r817F, 4 .set rBtn, 5 .set rC4, 5 .set rIdx, 6 .set rAns, 7 .set rAnsEp, 8 .set rD, 9 # BL trick .set rFM, 11 # FlagManager .set rTmp, 10 .set rApp, 31 # gpApplication .set rNextGameMode, 29 .set crAreaLock, 7 .set crArea9, 6 .set crArea234568, 5 .set $btnLevelSelect, 0x8 # D_UP .set $btnShineSelect, 0x4 # D_DOWN .macro li32 reg val lis \reg, \val@h ori \reg, \reg, \val@l .endm .L.prepare: ## prepare registers lis r817F, 0x817F lwz rFM, TFlagManager_smInstance$r13(r13) ## read button input: [M]*1 [C]*1 [btn]*2 lis r12, JUTGamePad_mPadButton@ha lwz rBtn, JUTGamePad_mPadButton@l(r12) /** NOTE: DO NOT CHANGE r12 UNTIL checkAreaLock ENDS */ .L.checkAreaLock: ## r0 = 0x22 - btn subfic r0, rBtn, 0x22 ### (lower 16 bit of r0 & ~1) == 0 => use r0&1 as AreaLock enable state rlwinm. rTmp, r0, 0, 0x10, 0x1E beq .L.checkAreaLock.1 ### else, load r0 = current state from RAM lbz r0, $LevelSelect.AreaLock@l(r817F) .L.checkAreaLock.1: ## !cr0.eq: AreaLock enabled rlwinm. r0, r0, 0, 0x1 ## write current enable state to RAM stb r0, $LevelSelect.AreaLock@l(r817F) ## activate AreaLock only if director finished (rNextGameMode > 1) cmplwi cr1, r3, 1 crandc eq, 4*cr1+gt, eq bne+ .L.checkAreaLock.done ## set button input to (handleRestartN) if AreaLock enabled li rBtn, $btnLevelSelect stw rBtn, JUTGamePad_mPadButton@l(r12) .L.checkAreaLock.done: ## orig mr. rNextGameMode, r3 ## return now if still setting up (nextGameMode != 0) beq .L.done ## disable the code if paused .L.checkPaused: ### r12 = *gpMarDirector lwz r12, gpMarDirector$r13(r13) cmplwi r12, 0 beq .L.checkPaused.done ### r12 = gpMarDirector->gameMode lbz r12, 0x64(r12) ### if gameMode == 5 or 10 li r0, 0x21 # (LSB 0, 5 == 1) rlwnm. r0, r0, r12, 31-10, 31-10 # LSB 10 bne .L.done .L.checkPaused.done: ## check button (Shine Select) .L.checkButton.ShineSelect: andi. r0, rBtn, $btnShineSelect beq+ .L.checkButton.ShineSelect.done ### disable Shine Select when already in Shine Select lbz r0, 0x8(rApp) # directory type cmpwi r0, 8 # shine select beq .L.checkButton.ShineSelect.done .ShineSelect: ## rAns = shineStageTable[curArea] lbz r0, 0xE(rApp) # current area lis rTmp, shineStageTable@ha la rTmp, shineStageTable@l(rTmp) lbzx rAns, rTmp, r0 ## ignore Plaza (rAns <= 1) cmpwi rAns, 1 ble .L.done ## map 7~8 to 8~9 addi r0, rAns, 1 rlwinm r0, r0, 32-3, 0x1 add rAns, rAns, r0 ## rAns = rAns << 8 | 0xff rlwinm rAns, rAns, 8, 0, 31 ori rAns, rAns, 0xFF ## TODO handle invalid shine stage (0, 1, 0xFF) b handleRestartZ .L.checkButton.ShineSelect.done: ### check button (Level Select) .L.checkButton.LevelSelect: andi. r0, rBtn, $btnLevelSelect beq+ .L.done ## Level Select bl .L.LevelSelect .D: .D.Special: # 8 bit/entry: [1bit] epFlag==7 | [7bit] area .long 0x00141516 .long 0x0017181D .long 0x34000090 # Red coin fish@NB8: 0x80|0x10 .D.Secrets: # 8 bit/entry: [1bit] ep==1 | [7bit] area .long 0x2F2E3020 .long 0x32293328 .long 0x2A1FBA3C .D.Sublevels: # 8 bit/entry .long 0x371E213A .long 0x0E2C3900 .D.Plaza: .long 0x00010507 .long 0x08090200 .D.Extra: .D.PinnaPark: ## ep: 0,1,2,3,4,5,7 | area=D ## epFlag: 0,2,4,5,6,7,0 .long 0x123457D0 .long 0x24567000 .D.SirenaHotel: ## ep: 0,1,2,2,3,4 | area=7 ## episo: 1,2,3,4,6,7 .long 0x12234070 .long 0x23467001 .L.LevelSelect: mflr rD .L.main: ## calc index ## btn: S YXBA -LRZ ---- ## XBRL=8,4,2,1 rlwinm rIdx, rBtn, 32-7, 0xC # X,B=8,4 rlwimi rIdx, rBtn, 32-4, 0x2 # R=2 rlwimi rIdx, rBtn, 32-6, 0x1 # L=1 ## Z=4 rlwinm r0, rBtn, 32- 2, 0x4 # Z=4 or rIdx, rIdx, r0 ## YSY=8,4,2 rlwinm r0, rBtn, 32- 8, 0x8 # Y=+8 rlwimi r0, rBtn, 32-10, 0x6 # S,Y=4,+2 ## merge XZRL and YSY- or rIdx, rIdx, r0 # TODO? handle rIdx>=12 ## check C==0(Special) or 9(Secrets) rlwinm. rC, rBtn, 32-16, 0xF beq handleSpecial cmpwi rC, 9 beq handleSecrets ## calc C index ### [(*), 6, 2, (*); 4, 5, 3, (*); 0, (*), 1] ### 110 0/10 00/0 100/ 101 0|11 00/0 000/ 000 0/01 00 .set CIdxMagic, 06204530001<<(32-3*10) ### CIdx = magic <<(3*C) &7 lis r0, CIdxMagic@h ori r0, r0, CIdxMagic@l mulli rC, rC, 3 rlwnm rC, r0, rC, 0x7 ## prepare CIdx<<2 (destroy rBtn) slwi rC4, rC, 2 ## Y+Z(14) -> SirenaHotel ## X+Z(12) -> PinnaPark cmpwi rIdx, 12 bge handleExtra ## Y(10) -> Plaza cmpwi rIdx, 10 bge handlePlaza ## X(8) -> Sublevels cmpwi rIdx, 8 bge handleSublevels ## stage ### area: [2, 3, 4, 5, 6, 8, 9, (*)] ### magic = 0x34568902 rotl sizeof(0xFF) ### ans = idx | (magic<<(Cidx<<2)) &0x0F00 ### ep = idx lis r0, 0x5689 ori r0, r0, 0x0234 slwi r12, rC, 2 rlwnm r12, r0, r12, 0x0F00 or rAns, rIdx, r12 rlwinm rAnsEp, rIdx, 0, 0x7 b .L.loadStage handleSpecial: lhz rAns, 0xE(rApp) # set for handleRestart{N,Z} ## neutral cmpwi rIdx, 0 beq handleRestartN ## Z restart cmpwi rIdx, 4 beq handleRestartZ ## Y restart cmpwi rIdx, 10 beq handleRestartY ## Special # rD = .D.Special lbzx r0, rD, rIdx # offset = idx rlwinm rAns, r0, 8, 0x3F00 rlwinm rAnsEp, r0, 32-7, 0x1 mulli rAnsEp, rAnsEp, 7 b .L.loadStage handleRestartN: ## set curArea = prevArea lhz r0, 0xA(rApp) sth r0, 0xE(rApp) handleRestartZ: ## load curMap, ep lbz rAnsEp, 0xDF(rFM) b .L.loadStageWithoutBackup handleRestartY: # load 817F0000 lhz rAns, $LevelSelect.area@l(r817F) lbz rAnsEp, $LevelSelect.epFlag@l(r817F) b .L.loadStage handleSecrets: la r12, .D.Secrets-.D(rD) lbzx r0, r12, rIdx rlwinm rAns, r0, 8, 0x3F00 rlwimi rAns, r0, 32-7, 0x0001 # ep: 2,5,3,0,1,5,1,3,4,5,0,* .set SecretEpMagic, 05301513450<<2 | 02 lis r0, SecretEpMagic@h ori r0, r0, SecretEpMagic@l mulli r12, rIdx, 3 rlwnm rAnsEp, r0, r12, 0x7 b .L.loadStage handleSublevels: la r12, .D.Sublevels-.D(rD) lbzx r0, r12, rC # Cidx as index rlwinm rAns, r0, 8, 0x3F00 # ep: 1,1,3,7,3,2,3 .set SublevelEpMagic, 0x13732301 lis r0, SublevelEpMagic@h ori r0, r0, SublevelEpMagic@l rlwnm rAnsEp, r0, rC4, 0x7 b .L.loadStage handleExtra: la r12, .D.Extra-.D-12*4(rD) rlwinm r0, rIdx, 2, 0x38 # offset: {12,14}<<2 lwzux r0, r12, r0 rlwnm rAns, r0, rC4, 0x7 # ep rlwimi rAns, r0, 4, 0x0F00 # a0 => aEE lwz r0, 4(r12) rlwnm rAnsEp, r0, rC4, 0x7 b .L.loadStage handlePlaza: ## [0, 1, 5, 7; 8, 9, 2, (*)] ## 15789200 ## ans == 0x0100 | (magic << (arr:=CIdx<<2) &0xF) .set PlazaEpMagic, 0x15789200 lis r0, PlazaEpMagic@h ori r0, r0, PlazaEpMagic@l rlwnm rAns, r0, rC4, 0xF ori rAns, rAns, 0x0100 li rAnsEp, 0 .L.loadStage: ### backup to 817F0000 (for Y) sth rAns, $LevelSelect.area@l(r817F) stb rAnsEp, $LevelSelect.epFlag@l(r817F) /* rAns, rAnsEp, rFM, rApp, r817F */ .L.loadStageWithoutBackup: ## reset QFT stb rNextGameMode, 0xB3(r817F) # >0 ## FlagManager ### epFlag(40003) stb rAnsEp, 0xDF(rFM) ### reset coin counter(40002) li r0, 0 ## FIXME: make use of other register stw r0, 0xD8(rFM) ### set flag lhz r0, 0xCC(rFM) #### Got a Shine in previous stage (30006) ori r0, r0, 0x4000 #### clear watched Pinna kidnap FMV flag (prevent spawn in PP unlocked position) rlwinm r0, r0, 0, 0x14, 0x12 sth r0, 0xCC(rFM) ## rApp = gpApplication ### write nextArea sth rAns, 0x12(rApp) .L.handleStickCD: lwz r12, 0x20(rApp) # TMarioGamePad* ## area rlwinm r0, rAns, 32-8, 0xFF # area ## crArea9(eq): area == 9 cmpwi crArea9, r0, 9 ## crArea234568(eq) ### cr1(gt): area >= 0x10 cmplwi cr1, r0, 0xF ### cr0(eq): area magic == 0 li rTmp, 0x7D # 234568 => 111_1101 rlwnm. rTmp, rTmp, r0, 31-8, 31-8 # LSB 8 ### crArea234568(eq) = !(area >= 0x10) && !(area magic == 0) crnor 4*crArea234568+eq, 4*cr1+gt, eq ## SirenaHotel(0x07) or Casino(0x0E) ? 59 : 0 cmpwi r0, 0x07 # SirenaHotel cmpwi cr1, r0, 0x0E # Casino cror eq, eq, 4*cr1+eq # (NOTE: cannot use rlwnm trick since area may >= 0x20) li r0, 59 beq- .L.handleStickCD.apply li r0, 0 .L.handleStickCD.apply: sth r0, 0xe4(r12) .L.handleStickFlag: ## clear 0x2 bit of 0xe2 flag lhz r0, 0xe2(r12) rlwinm r0, r0, 0, 31, 29 sth r0, 0xe2(r12) ## set nextGameMode if gpMarDirector == NULL ### nextGameMode = nextArea == (shine select) ? 8 : 5 ## ep==0xFF ? 3 : 0 (Note: all valid ep id < 0x40) ## cr0(eq) == ep!=0xFF rlwinm. rNextGameMode, rAns, 32-6, 0x3 addi rNextGameMode, rNextGameMode, 5 .L.setFader: ## TSMSFader::setFadeStatus(gpApplication.fader, FadedOut(=0)) lwz r12, 0x34(rApp) .L.setFader.status: ### this->status = FadedOut(0); li r0, 0 stw r0, 0x20(r12) .L.setFader.color: ## TSMSFader::setColor(gpApplication.fader, color) /** * (9, *) => white (0xd2d2d2ff) * (*, 0xFF) => black (0xff) * (2|3|4|5|6|8, *) => white * _ => black */ ### area == 9 => white beq crArea9, .L.setFader.color.white ### !(ep != 0xFF) => black (Note: DO NOT DESTROY cr0 UNTIL HERE!) bne cr0, .L.setFader.color.black ### area != 2|3|4|5|6|8 => black bne crArea234568, .L.setFader.color.black .L.setFader.color.white: li32 r0, 0xd2d2d200 .L.setFader.color.black: ori r0, r0, 0xff # r0 = 0 in .L.setFader.status .L.setFader.color.apply: stw r0, 0x18(r12) ### this->color->a = 0xff; (overwritten afterward) ### (this->wipeRequest).type = 0x12; li r0, 0x12 stw r0, 0x24(r12) .L.done: