mirror of
				https://github.com/Zelda64Recomp/Zelda64Recomp.git
				synced 2025-10-30 08:03:03 +00:00 
			
		
		
		
	Add owl statues as possible autosave entrances.
This commit is contained in:
		
							parent
							
								
									0bc0fd2610
								
							
						
					
					
						commit
						f6edf3c5b4
					
				
					 1 changed files with 140 additions and 10 deletions
				
			
		|  | @ -7,7 +7,7 @@ | |||
| #include "overlays/actors/ovl_Obj_Warpstone/z_obj_warpstone.h" | ||||
| #include "misc_funcs.h" | ||||
| 
 | ||||
| #define SAVE_TYPE_AUTOSAVE 2  | ||||
| #define SAVE_TYPE_AUTOSAVE 2 | ||||
| 
 | ||||
| u8 gCanPause; | ||||
| s32 ShrinkWindow_Letterbox_GetSizeTarget(void); | ||||
|  | @ -23,7 +23,7 @@ RECOMP_PATCH void KaleidoSetup_Update(PlayState* play) { | |||
|     if (CHECK_BTN_ALL(input->cur.button, BTN_R)) { | ||||
|         if (msgCtx && msgCtx) {} | ||||
|     } | ||||
|      | ||||
| 
 | ||||
|     if ((pauseCtx->state == PAUSE_STATE_OFF) && (pauseCtx->debugEditor == DEBUG_EDITOR_NONE) && | ||||
|         (play->gameOverCtx.state == GAMEOVER_INACTIVE)) { | ||||
|         if ((play->transitionTrigger == TRANS_TRIGGER_OFF) && (play->transitionMode == TRANS_MODE_OFF)) { | ||||
|  | @ -73,9 +73,15 @@ void recomp_reset_autosave_timer_slow(); | |||
| RECOMP_DECLARE_EVENT(recomp_on_autosave(PlayState* play)); | ||||
| RECOMP_DECLARE_EVENT(recomp_after_autosave(PlayState* play)); | ||||
| 
 | ||||
| s16 sGreatFairyEntranceMap[] = { | ||||
|     ENTRANCE(SOUTH_CLOCK_TOWN, 0), ENTRANCE(WOODFALL, 0), ENTRANCE(SNOWHEAD, 0), ENTRANCE(ZORA_CAPE, 0), ENTRANCE(IKANA_CANYON, 0), | ||||
|     ENTRANCE(SOUTH_CLOCK_TOWN, 0), ENTRANCE(WOODFALL, 0), ENTRANCE(SNOWHEAD, 0), ENTRANCE(ZORA_CAPE, 0), ENTRANCE(IKANA_CANYON, 0), | ||||
| }; | ||||
| 
 | ||||
| RECOMP_EXPORT void recomp_do_autosave(PlayState* play) { | ||||
|     // @recomp_event recomp_on_autosave(PlayState* play): Autosave triggered.
 | ||||
|     recomp_on_autosave(play); | ||||
| 
 | ||||
|     // Transfer the scene flags into the cycle flags.
 | ||||
|     Play_SaveCycleSceneFlags(&play->state); | ||||
|     // Transfer the cycle flags into the save buffer. Logic copied from func_8014546C.
 | ||||
|  | @ -87,6 +93,26 @@ RECOMP_EXPORT void recomp_do_autosave(PlayState* play) { | |||
|         gSaveContext.save.saveInfo.permanentSceneFlags[i].collectible = gSaveContext.cycleSceneFlags[i].collectible; | ||||
|     } | ||||
| 
 | ||||
|     s32 original_entrance = gSaveContext.save.entrance; | ||||
|     s32 entrance = original_entrance; | ||||
|     s32 scene_id = Entrance_GetSceneIdAbsolute(entrance); | ||||
|     // Map grottos/shrines to entrances to be used in different regions. Logic adapted from KaleidoScope_DrawWorldMap.
 | ||||
|     if (scene_id == SCENE_KAKUSIANA) { | ||||
|         if (play->roomCtx.curRoom.num == 5) { | ||||
|             entrance = ENTRANCE(GORON_VILLAGE_WINTER, 0); | ||||
|         } else if ((play->roomCtx.curRoom.num == 6) || (play->roomCtx.curRoom.num == 8) || | ||||
|                     (play->roomCtx.curRoom.num == 12)) { | ||||
|             entrance = ENTRANCE(DEKU_PALACE, 0); | ||||
|         } else { | ||||
|             entrance = gSaveContext.respawn[RESPAWN_MODE_UNK_3].entrance; | ||||
|         } | ||||
|     } | ||||
|     // Map fairy fountains to entrances to be used in different regions.
 | ||||
|     if (scene_id == SCENE_YOUSEI_IZUMI) { | ||||
|         entrance = sGreatFairyEntranceMap[play->curSpawn]; | ||||
|     } | ||||
|     gSaveContext.save.entrance = entrance; | ||||
| 
 | ||||
|     s32 fileNum = gSaveContext.fileNum; | ||||
| 
 | ||||
|     gSaveContext.save.isOwlSave = SAVE_TYPE_AUTOSAVE; | ||||
|  | @ -97,12 +123,13 @@ RECOMP_EXPORT void recomp_do_autosave(PlayState* play) { | |||
|     SramContext* sramCtx = &play->sramCtx; | ||||
|     // Copy the saved parts of the global save context into the sram saving buffer.
 | ||||
|     Lib_MemCpy(sramCtx->saveBuf, &gSaveContext, offsetof(SaveContext, fileNum)); | ||||
|     // Synchronously save into the owl save slot and the backup owl save slot. 
 | ||||
|     // Synchronously save into the owl save slot and the backup owl save slot.
 | ||||
|     Sram_SyncWriteToFlash(sramCtx, gFlashOwlSaveStartPages[fileNum * 2], gFlashOwlSaveNumPages[fileNum * 2]); | ||||
|     Sram_SyncWriteToFlash(sramCtx, gFlashOwlSaveStartPages[fileNum * 2 + 1], gFlashOwlSaveNumPages[fileNum * 2 + 1]); | ||||
| 
 | ||||
|     gSaveContext.save.entrance = original_entrance; | ||||
|     gSaveContext.save.isOwlSave = false; | ||||
|      | ||||
| 
 | ||||
|     // @recomp_event recomp_on_autosave(PlayState* play): Autosave finished.
 | ||||
|     recomp_after_autosave(play); | ||||
| } | ||||
|  | @ -351,7 +378,7 @@ void draw_autosave_icon(PlayState* play) { | |||
|             255, 255, 255, alpha, G_EX_ORIGIN_RIGHT); | ||||
|         gEXForceUpscale2D(OVERLAY_DISP++, 0); | ||||
|     } | ||||
|          | ||||
| 
 | ||||
|     if (recomp_autosave_debug_enabled() && autosave_was_ready) { | ||||
|         gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 255, 0, 0, 255); | ||||
|         gDPSetCombineLERP(OVERLAY_DISP++, 0, 0, 0, PRIMITIVE, 0, 0, 0, PRIMITIVE, 0, 0, 0, PRIMITIVE, 0, 0, 0, PRIMITIVE); | ||||
|  | @ -420,7 +447,7 @@ void autosave_post_play_update(PlayState* play) { | |||
|         // * The player is allowed to pause.
 | ||||
|         if (gSaveContext.hudVisibility == HUD_VISIBILITY_ALL && | ||||
|             R_TIME_SPEED != 0 && | ||||
|             !Environment_IsTimeStopped() &&  | ||||
|             !Environment_IsTimeStopped() && | ||||
|             play->msgCtx.msgMode == MSGMODE_NONE && | ||||
|             play->pauseCtx.state == PAUSE_STATE_OFF && | ||||
|             gSaveContext.save.cutsceneIndex < 0xFFF0 && | ||||
|  | @ -448,7 +475,7 @@ void autosave_post_play_update(PlayState* play) { | |||
|         } | ||||
|     } | ||||
|     else { | ||||
|         // Update the last autosave time to the current time to prevent autosaving immediately if autosaves are turned back on. 
 | ||||
|         // Update the last autosave time to the current time to prevent autosaving immediately if autosaves are turned back on.
 | ||||
|         recomp_reset_autosave_timer(); | ||||
|     } | ||||
|     gCanPause = false; | ||||
|  | @ -465,7 +492,7 @@ extern u16 D_801C6A58[]; | |||
| #define CHECK_NEWF(newf)                                                                                 \ | ||||
|     ((newf)[0] != 'Z' || (newf)[1] != 'E' || (newf)[2] != 'L' || (newf)[3] != 'D' || (newf)[4] != 'A' || \ | ||||
|      (newf)[5] != '3') | ||||
|       | ||||
| 
 | ||||
| typedef struct { | ||||
|     /* 0x00 */ s16 csId; | ||||
|     /* 0x02 */ s16 length; | ||||
|  | @ -495,7 +522,7 @@ RECOMP_PATCH s16 CutsceneManager_FindEntranceCsId(void) { | |||
|             (sSceneCutsceneList[csId].scriptIndex < (play = sCutsceneMgr.play)->csCtx.scriptListCount) && | ||||
|             (sCutsceneMgr.play->curSpawn == | ||||
|              sCutsceneMgr.play->csCtx.scriptList[sSceneCutsceneList[csId].scriptIndex].spawn)) { | ||||
|              | ||||
| 
 | ||||
|             // @recomp Check if the entry cutscene should be skipped and do so.
 | ||||
|             if (skip_entry_cutscene) { | ||||
|                 skip_entry_cutscene = false; | ||||
|  | @ -515,13 +542,116 @@ RECOMP_PATCH s16 CutsceneManager_FindEntranceCsId(void) { | |||
|     return -1; | ||||
| } | ||||
| 
 | ||||
| s32 sRegionToOwlWarpId[REGION_MAX] = { | ||||
|     OWL_WARP_GREAT_BAY_COAST,   // REGION_GREAT_BAY
 | ||||
|     OWL_WARP_ZORA_CAPE,         // REGION_ZORA_HALL
 | ||||
|     OWL_WARP_MILK_ROAD,         // REGION_ROMANI_RANCH
 | ||||
|     OWL_WARP_SOUTHERN_SWAMP,    // REGION_DEKU_PALACE
 | ||||
|     OWL_WARP_SOUTHERN_SWAMP,    // REGION_WOODFALL
 | ||||
|     OWL_WARP_NONE,              // REGION_CLOCK_TOWN
 | ||||
|     OWL_WARP_MOUNTAIN_VILLAGE,  // REGION_SNOWHEAD
 | ||||
|     OWL_WARP_IKANA_CANYON,      // REGION_IKANA_GRAVEYARD
 | ||||
|     OWL_WARP_IKANA_CANYON,      // REGION_IKANA_CANYON
 | ||||
|     OWL_WARP_MOUNTAIN_VILLAGE,  // REGION_GORON_VILLAGE
 | ||||
|     OWL_WARP_STONE_TOWER,       // REGION_STONE_TOWER
 | ||||
| }; | ||||
| 
 | ||||
| s32 sSecondaryOwlWarp[OWL_WARP_MAX - 1] = { | ||||
|     OWL_WARP_ZORA_CAPE,         // OWL_WARP_GREAT_BAY_COAST,
 | ||||
|     OWL_WARP_GREAT_BAY_COAST,   // OWL_WARP_ZORA_CAPE,
 | ||||
|     OWL_WARP_MOUNTAIN_VILLAGE,  // OWL_WARP_SNOWHEAD,
 | ||||
|     OWL_WARP_SNOWHEAD,          // OWL_WARP_MOUNTAIN_VILLAGE,
 | ||||
|     OWL_WARP_NONE,              // OWL_WARP_CLOCK_TOWN,
 | ||||
|     OWL_WARP_NONE,              // OWL_WARP_MILK_ROAD,
 | ||||
|     OWL_WARP_SOUTHERN_SWAMP,    // OWL_WARP_WOODFALL,
 | ||||
|     OWL_WARP_WOODFALL,          // OWL_WARP_SOUTHERN_SWAMP,
 | ||||
|     OWL_WARP_STONE_TOWER,       // OWL_WARP_IKANA_CANYON,
 | ||||
|     OWL_WARP_IKANA_CANYON,      // OWL_WARP_STONE_TOWER,
 | ||||
| }; | ||||
| 
 | ||||
| s32 get_closest_owl_statue(s16 sceneId) { | ||||
|     s32 n = 0; | ||||
|     s32 j = 0; | ||||
| 
 | ||||
|     // Find the region that player is currently in.
 | ||||
|     // Loop over region (n) and regionIndex (j). Logic adapted from KaleidoScope_DrawWorldMap.
 | ||||
|     while (true) { | ||||
|         if (gSceneIdsPerRegion[n][j] == 0xFFFF) { | ||||
|             n++; | ||||
|             j = 0; | ||||
|             if (n == REGION_MAX) { | ||||
|                 n = 0; | ||||
| 
 | ||||
|                 while (true) { | ||||
|                     if (gSceneIdsPerRegion[n][j] == 0xFFFF) { | ||||
|                         n++; | ||||
|                         if (n == REGION_MAX) { | ||||
|                             break; | ||||
|                         } | ||||
|                         j = 0; | ||||
|                         if (Entrance_GetSceneIdAbsolute( | ||||
|                                 ((void)0, gSaveContext.respawn[RESPAWN_MODE_UNK_3].entrance)) == | ||||
|                             gSceneIdsPerRegion[n][j]) { | ||||
|                             break; | ||||
|                         } | ||||
|                     } | ||||
|                     j++; | ||||
|                 } | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         if (sceneId == gSceneIdsPerRegion[n][j]) { | ||||
|             break; | ||||
|         } | ||||
|         j++; | ||||
|     } | ||||
| 
 | ||||
|     if (n != REGION_MAX) { | ||||
|         // Map current region to the corresponding owl statue.
 | ||||
|         s32 owlWarpId = sRegionToOwlWarpId[n]; | ||||
|         // Handle cases with two different warps in the same region.
 | ||||
|         if ((owlWarpId == OWL_WARP_MOUNTAIN_VILLAGE) && | ||||
|             ((sceneId == SCENE_14YUKIDAMANOMITI) || (sceneId == SCENE_12HAKUGINMAE))) { // Path to Snowhead, Snowhead
 | ||||
|             owlWarpId = OWL_WARP_SNOWHEAD; | ||||
|         } else if ((owlWarpId == OWL_WARP_SOUTHERN_SWAMP) && (sceneId == SCENE_21MITURINMAE)) { // Woodfall
 | ||||
|             owlWarpId = OWL_WARP_WOODFALL; | ||||
|         } | ||||
| 
 | ||||
|         // Check if desired owl statue is active.
 | ||||
|         for (j = 0; j < 2; j++) { | ||||
|             if (owlWarpId == OWL_WARP_NONE) { | ||||
|                 break; | ||||
|             } | ||||
| 
 | ||||
|             if ((gSaveContext.save.saveInfo.playerData.owlActivationFlags >> owlWarpId) & 1) { | ||||
|                 // Get owl warp entrance.
 | ||||
|                 s32 entrance = D_801C6A58[owlWarpId]; | ||||
|                 if ((entrance == ENTRANCE(SOUTHERN_SWAMP_POISONED, 10)) && | ||||
|                     CHECK_WEEKEVENTREG(WEEKEVENTREG_CLEARED_WOODFALL_TEMPLE)) { | ||||
|                     entrance = ENTRANCE(SOUTHERN_SWAMP_CLEARED, 10); | ||||
|                 } else if ((entrance == ENTRANCE(MOUNTAIN_VILLAGE_WINTER, 8)) && | ||||
|                         CHECK_WEEKEVENTREG(WEEKEVENTREG_CLEARED_SNOWHEAD_TEMPLE)) { | ||||
|                     entrance = ENTRANCE(MOUNTAIN_VILLAGE_SPRING, 8); | ||||
|                 } | ||||
| 
 | ||||
|                 return entrance; | ||||
|             } else { | ||||
|                 owlWarpId = sSecondaryOwlWarp[owlWarpId]; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return ENTRANCE(SOUTH_CLOCK_TOWN, 0); | ||||
| } | ||||
| 
 | ||||
| s32 spawn_entrance_from_autosave_entrance(s16 autosave_entrance) { | ||||
|     s32 scene_id = Entrance_GetSceneIdAbsolute(gSaveContext.save.entrance); | ||||
|     recomp_printf("Loaded entrance: %d in scene: %d\n", autosave_entrance, scene_id); | ||||
| 
 | ||||
|     switch (scene_id) { | ||||
|         default: | ||||
|             return ENTRANCE(SOUTH_CLOCK_TOWN, 0); | ||||
|             return get_closest_owl_statue(scene_id); | ||||
|         case SCENE_MITURIN: // Woodfall Temple
 | ||||
|         case SCENE_MITURIN_BS: // Odolwa's Lair
 | ||||
|             return ENTRANCE(WOODFALL_TEMPLE, 0); | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 danielryb
						danielryb