[BotW_Cutscene_V208] moduleMatches = 0x6267BFD0 .origin = codecave cutsceneMode: .int $cutsceneFPSLimitMode lastCutsceneId: .int 0 cutsceneFPSLimit: .float 0 _setCutsceneFPSLimit: stw r0, 4(r31) ; Original instruction ; Register r9 still holds the ID of this cutscene ; Register r29 is the parameter structure that this object is created with which also holds the event name lwz r12, 8(r29) ; Check if the event name is not 0 cmpwi r12, 0 beqlr ; Check if the to-be-created event is a cutscene by checking if the event name starts with *emo lbz r3, 1(r12) cmpwi r3, 0x65 ; e bnelr lbz r3, 2(r12) cmpwi r3, 0x6D ; m bnelr lbz r3, 3(r12) cmpwi r3, 0x6F ; o bnelr ; Enforce cutscene mode settings lis r3, cutsceneMode@ha lwz r3, cutsceneMode@l(r3) cmpwi r3, 0 beqlr cmpwi r3, 2 beq _setCutscene60FPSLimit cmpwi r3, 3 beq _setCutscene30FPSLimit ; Load each digit of the "Demo000_0" string pointer in the params, then add the numbers together li r22, 0 lbz r3, 4(r12) addi r3, r3, -0x30 mulli r3, r3, 1000 add r22, r22, r3 lbz r3, 5(r12) addi r3, r3, -0x30 mulli r3, r3, 100 add r22, r22, r3 lbz r3, 6(r12) addi r3, r3, -0x30 mulli r3, r3, 10 add r22, r22, r3 lbz r3, 8(r12) addi r3, r3, -0x30 mulli r3, r3, 1 add r22, r22, r3 cmpwi r22, 3480 ; demo348_0 ; Could be part of the crash at the Rito Village bridge beq _setCutscene30FPSLimit cmpwi r22, 3481 ; demo348_1 ; Crash at the Rito Village bridge beq _setCutscene30FPSLimit cmpwi r22, 1620 ; demo162_0 ; Perhaps the crash at the end of vah ruta beq _setCutscene30FPSLimit cmpwi r22, 1630 ; demo163_0 ; Perhaps the crash at the end of vah ruta beq _setCutscene30FPSLimit cmpwi r22, 3340 ; demo334_0 ; Perhaps the crash at the end of vah ruta beq _setCutscene30FPSLimit # cmpwi r22, 1020 ; demo102_0 ; Start Game - Bright light waking up link on blackscreen # beq _setCutscene30FPSLimit cmpwi r22, 1690 ; demo169_0 ; Start Game - Zelda waking up link dialogue on blackscreen beq _setCutscene30FPSLimit cmpwi r22, 1030 ; demo103_0 ; Start Game - Walking out of shrine of resurrection beq _setCutscene60FPSLimit ; A bunch of divine beast enter and exit events. Could definitely be narrowed down in the future. cmpwi r22, 1100 ; demo110_0 beq _setCutscene30FPSLimit cmpwi r22, 1110 ; demo111_0 beq _setCutscene30FPSLimit cmpwi r22, 1120 ; demo112_0 beq _setCutscene30FPSLimit cmpwi r22, 1130 ; demo113_0 beq _setCutscene30FPSLimit cmpwi r22, 1140 ; demo114_0 beq _setCutscene30FPSLimit cmpwi r22, 1150 ; demo115_0 beq _setCutscene30FPSLimit cmpwi r22, 1160 ; demo116_0 beq _setCutscene30FPSLimit cmpwi r22, 1170 ; demo117_0 beq _setCutscene30FPSLimit cmpwi r22, 1180 ; demo118_0 beq _setCutscene30FPSLimit cmpwi r22, 1190 ; demo119_0 beq _setCutscene30FPSLimit cmpwi r22, 1200 ; demo120_0 beq _setCutscene30FPSLimit cmpwi r22, 1210 ; demo121_0 beq _setCutscene30FPSLimit cmpwi r22, 1220 ; demo122_0 beq _setCutscene30FPSLimit cmpwi r22, 1230 ; demo123_0 beq _setCutscene30FPSLimit cmpwi r22, 1240 ; demo124_0 beq _setCutscene30FPSLimit cmpwi r22, 1250 ; demo125_0 beq _setCutscene30FPSLimit blr ; 30FPS limit case _setCutscene30FPSLimit: lis r3, const_30@ha lfs f10, const_30@l(r3) b _returnWithCutsceneFPSLimit ; 60FPS limit case _setCutscene60FPSLimit: lis r3, const_60@ha lfs f10, const_60@l(r3) b _returnWithCutsceneFPSLimit _returnWithCutsceneFPSLimit: lis r3, lastCutsceneId@ha stw r9, lastCutsceneId@l(r3) lis r3, cutsceneFPSLimit@ha stfs f10, cutsceneFPSLimit@l(r3) blr _removeCutsceneFPSLimit: lwz r11, 0x27C(r30) ; Original instruction lwz r9, 0x274(r30) lis r8, lastCutsceneId@ha lwz r8, lastCutsceneId@l(r8) cmpw r9, r8 bnelr lis r8, const_0.0@ha lfs f10, const_0.0@l(r8) lis r8, cutsceneFPSLimit@ha stfs f10, cutsceneFPSLimit@l(r8) blr ; Check if a cutscene is ongoing with a set FPS limit _checkCutsceneFPSLimit: lis r11, const_0.0@ha lfs f7, const_0.0@l(r11) lis r11, cutsceneFPSLimit@ha lfs f12, cutsceneFPSLimit@l(r11) fcmpu cr0, f12, f7 beq _calculateDynamicFPS ; If a cutscene FPS limit is set, lower FPS _lowerCutsceneFPS: ; Calculate how many ticks a frame has to take to render at the given FPS limit lis r11, const_1@ha lfs f7, const_1@l(r11) fdivs f12, f7, f12 lis r11, timerTickSpeed@ha lfs f7, timerTickSpeed@l(r11) fmuls f12, f7, f12 ; Subtract the time that it took for the actual frame to render and make sure that it's not negative (which means a frame already took longer to render then the FPS limit) fsubs f12, f12, f10 lis r12, const_0.0@ha lfs f7, const_0.0@l(r12) fcmpu cr0, f7, f12 ble .+0x8 fmr f12, f7 ; Convert the remaining ticks that should be spend idling to an integer (but it requires storing it in memory) fctiwz f12, f12 lis r11, floatConvHa@ha stfd f12, floatConvHa@l(r11) ; Load the converted integer ticks and sleep for the given amount of time mr r12, r4 li r3, 0 lis r11, floatConvL@ha lwz r4, floatConvL@l(r11) mflr r11 bl import.coreinit.OSSleepTicks mtlr r11 mr r4, r12 lis r11, cutsceneFPSLimit@ha lfs f10, cutsceneFPSLimit@l(r11) ; Skip dynamic FPS code when cutscene FPS limit is in place since the game should always run at 30FPS b _setGamespeed ; Hook evt::EventFlowBase's ctor (event object creation) 0x031D2D2C = bla _setCutsceneFPSLimit ; Hook evt::EventFlowBase's dtor (event object destruction) 0x031D3798 = bla _removeCutsceneFPSLimit