2022-03-21 21:51:23 -04:00
|
|
|
#include "global.h"
|
|
|
|
#include "vt.h"
|
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Initialize new save.
|
|
|
|
* This save has an empty inventory with 3 hearts and single magic.
|
|
|
|
*/
|
|
|
|
void Sram_InitNewSave(void) {
|
2022-06-20 13:41:43 -04:00
|
|
|
Save_InitFile(false);
|
2022-03-21 21:51:23 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Initialize debug save. This is also used on the Title Screen
|
|
|
|
* This save has a mostly full inventory with 10 hearts and single magic.
|
|
|
|
*
|
|
|
|
* Some noteable flags that are set:
|
|
|
|
* Showed Mido sword/shield, met Deku Tree, Deku Tree mouth opened,
|
|
|
|
* used blue warp in Gohmas room, Zelda fled castle, light arrow cutscene watched,
|
|
|
|
* and set water level in Water Temple to lowest level.
|
|
|
|
*/
|
|
|
|
void Sram_InitDebugSave(void) {
|
2022-06-20 13:41:43 -04:00
|
|
|
Save_InitFile(true);
|
2022-03-21 21:51:23 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Copy save currently on the buffer to Save Context and complete various tasks to open the save.
|
|
|
|
* This includes:
|
|
|
|
* - Set proper entrance depending on where the game was saved
|
|
|
|
* - If health is less than 3 hearts, give 3 hearts
|
|
|
|
* - If either scarecrow song is set, copy them from save context to the proper location
|
|
|
|
* - Handle a case where the player saved and quit after zelda cutscene but didnt get the song
|
|
|
|
* - Give and equip master sword if player is adult and doesnt have kokiri sword (bug?)
|
|
|
|
* - Revert any trade items that spoil
|
|
|
|
*/
|
2022-06-20 13:41:43 -04:00
|
|
|
void Sram_OpenSave() {
|
2022-03-21 21:51:23 -04:00
|
|
|
static s16 dungeonEntrances[] = {
|
|
|
|
0x0000, 0x0004, 0x0028, 0x0169, 0x0165, 0x0010, 0x0082, 0x0037,
|
|
|
|
0x0098, 0x0088, 0x041B, 0x0008, 0x0486, 0x0467, 0x0179, 0x056C,
|
|
|
|
};
|
|
|
|
u16 i;
|
|
|
|
u16 j;
|
|
|
|
u8* ptr;
|
|
|
|
|
2022-06-20 13:41:43 -04:00
|
|
|
Save_LoadFile();
|
2022-03-21 21:51:23 -04:00
|
|
|
|
|
|
|
switch (gSaveContext.savedSceneNum) {
|
|
|
|
case SCENE_YDAN:
|
|
|
|
case SCENE_DDAN:
|
|
|
|
case SCENE_BDAN:
|
|
|
|
case SCENE_BMORI1:
|
|
|
|
case SCENE_HIDAN:
|
|
|
|
case SCENE_MIZUSIN:
|
|
|
|
case SCENE_JYASINZOU:
|
|
|
|
case SCENE_HAKADAN:
|
|
|
|
case SCENE_HAKADANCH:
|
|
|
|
case SCENE_ICE_DOUKUTO:
|
|
|
|
case SCENE_GANON:
|
|
|
|
case SCENE_MEN:
|
|
|
|
case SCENE_GERUDOWAY:
|
|
|
|
case SCENE_GANONTIKA:
|
|
|
|
gSaveContext.entranceIndex = dungeonEntrances[gSaveContext.savedSceneNum];
|
|
|
|
break;
|
|
|
|
case SCENE_YDAN_BOSS:
|
|
|
|
gSaveContext.entranceIndex = 0;
|
|
|
|
break;
|
|
|
|
case SCENE_DDAN_BOSS:
|
|
|
|
gSaveContext.entranceIndex = 4;
|
|
|
|
break;
|
|
|
|
case SCENE_BDAN_BOSS:
|
|
|
|
gSaveContext.entranceIndex = 0x28;
|
|
|
|
break;
|
|
|
|
case SCENE_MORIBOSSROOM:
|
|
|
|
gSaveContext.entranceIndex = 0x169;
|
|
|
|
break;
|
|
|
|
case SCENE_FIRE_BS:
|
|
|
|
gSaveContext.entranceIndex = 0x165;
|
|
|
|
break;
|
|
|
|
case SCENE_MIZUSIN_BS:
|
|
|
|
gSaveContext.entranceIndex = 0x10;
|
|
|
|
break;
|
|
|
|
case SCENE_JYASINBOSS:
|
|
|
|
gSaveContext.entranceIndex = 0x82;
|
|
|
|
break;
|
|
|
|
case SCENE_HAKADAN_BS:
|
|
|
|
gSaveContext.entranceIndex = 0x37;
|
|
|
|
break;
|
|
|
|
case SCENE_GANON_SONOGO:
|
|
|
|
case SCENE_GANONTIKA_SONOGO:
|
|
|
|
case SCENE_GANON_BOSS:
|
|
|
|
case SCENE_GANON_FINAL:
|
|
|
|
case SCENE_GANON_DEMO:
|
|
|
|
gSaveContext.entranceIndex = 0x41B;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
if (gSaveContext.savedSceneNum != SCENE_LINK_HOME) {
|
|
|
|
gSaveContext.entranceIndex = (LINK_AGE_IN_YEARS == YEARS_CHILD) ? 0xBB : 0x5F4;
|
|
|
|
} else {
|
|
|
|
gSaveContext.entranceIndex = 0xBB;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
osSyncPrintf("scene_no = %d\n", gSaveContext.entranceIndex);
|
|
|
|
osSyncPrintf(VT_RST);
|
|
|
|
|
|
|
|
if (gSaveContext.health < 0x30) {
|
|
|
|
gSaveContext.health = 0x30;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (gSaveContext.scarecrowCustomSongSet) {
|
|
|
|
osSyncPrintf(VT_FGCOL(BLUE));
|
|
|
|
osSyncPrintf("\n====================================================================\n");
|
|
|
|
|
|
|
|
memcpy(gScarecrowCustomSongPtr, gSaveContext.scarecrowCustomSong, sizeof(gSaveContext.scarecrowCustomSong));
|
|
|
|
|
|
|
|
ptr = (u8*)gScarecrowCustomSongPtr;
|
|
|
|
for (i = 0; i < ARRAY_COUNT(gSaveContext.scarecrowCustomSong); i++, ptr++) {
|
|
|
|
osSyncPrintf("%d, ", *ptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
osSyncPrintf("\n====================================================================\n");
|
|
|
|
osSyncPrintf(VT_RST);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (gSaveContext.scarecrowSpawnSongSet) {
|
|
|
|
osSyncPrintf(VT_FGCOL(GREEN));
|
|
|
|
osSyncPrintf("\n====================================================================\n");
|
|
|
|
|
|
|
|
memcpy(gScarecrowSpawnSongPtr, gSaveContext.scarecrowSpawnSong, sizeof(gSaveContext.scarecrowSpawnSong));
|
|
|
|
|
|
|
|
ptr = gScarecrowSpawnSongPtr;
|
|
|
|
for (i = 0; i < ARRAY_COUNT(gSaveContext.scarecrowSpawnSong); i++, ptr++) {
|
|
|
|
osSyncPrintf("%d, ", *ptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
osSyncPrintf("\n====================================================================\n");
|
|
|
|
osSyncPrintf(VT_RST);
|
|
|
|
}
|
|
|
|
|
|
|
|
// if zelda cutscene has been watched but lullaby was not obtained, restore cutscene and take away letter
|
|
|
|
if ((gSaveContext.eventChkInf[4] & 1) && !CHECK_QUEST_ITEM(QUEST_SONG_LULLABY)) {
|
|
|
|
i = gSaveContext.eventChkInf[4] & ~1;
|
|
|
|
gSaveContext.eventChkInf[4] = i;
|
|
|
|
|
|
|
|
INV_CONTENT(ITEM_LETTER_ZELDA) = ITEM_CHICKEN;
|
|
|
|
|
|
|
|
for (j = 1; j < 4; j++) {
|
|
|
|
if (gSaveContext.equips.buttonItems[j] == ITEM_LETTER_ZELDA) {
|
|
|
|
gSaveContext.equips.buttonItems[j] = ITEM_CHICKEN;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// check for owning kokiri sword.. to restore master sword? bug or debug feature?
|
|
|
|
if (LINK_AGE_IN_YEARS == YEARS_ADULT && !CHECK_OWNED_EQUIP(EQUIP_SWORD, 1)) {
|
|
|
|
gSaveContext.inventory.equipment |= gBitFlags[1] << gEquipShifts[EQUIP_SWORD];
|
|
|
|
gSaveContext.equips.buttonItems[0] = ITEM_SWORD_MASTER;
|
|
|
|
gSaveContext.equips.equipment &= ~0xF;
|
|
|
|
gSaveContext.equips.equipment |= 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_COUNT(gSpoilingItems); i++) {
|
|
|
|
if (INV_CONTENT(ITEM_TRADE_ADULT) == gSpoilingItems[i]) {
|
|
|
|
INV_CONTENT(gSpoilingItemReverts[i]) = gSpoilingItemReverts[i];
|
|
|
|
|
|
|
|
for (j = 1; j < 4; j++) {
|
|
|
|
if (gSaveContext.equips.buttonItems[j] == gSpoilingItems[i]) {
|
|
|
|
gSaveContext.equips.buttonItems[j] = gSpoilingItemReverts[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
gSaveContext.magicLevel = 0;
|
|
|
|
}
|
|
|
|
|
2022-06-20 13:41:43 -04:00
|
|
|
void Sram_InitSave(FileChooseContext* fileChooseCtx) {
|
2022-03-21 21:51:23 -04:00
|
|
|
u16 offset;
|
|
|
|
u16 j;
|
|
|
|
u16* ptr;
|
|
|
|
u16 checksum;
|
|
|
|
|
|
|
|
if (fileChooseCtx->buttonIndex != 0 || !CVar_GetS32("gDebugEnabled", 0)) {
|
|
|
|
Sram_InitNewSave();
|
|
|
|
} else {
|
|
|
|
Sram_InitDebugSave();
|
|
|
|
}
|
|
|
|
|
|
|
|
gSaveContext.entranceIndex = 0xBB;
|
|
|
|
gSaveContext.linkAge = 1;
|
|
|
|
gSaveContext.dayTime = 0x6AAB;
|
|
|
|
gSaveContext.cutsceneIndex = 0xFFF1;
|
|
|
|
|
|
|
|
if ((fileChooseCtx->buttonIndex == 0 && CVar_GetS32("gDebugEnabled", 0)) || CVar_GetS32("gNaviSkipCutscene", 0)) {
|
|
|
|
gSaveContext.cutsceneIndex = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (offset = 0; offset < 8; offset++) {
|
2022-06-20 13:41:43 -04:00
|
|
|
gSaveContext.playerName[offset] = Save_GetSaveMetaInfo(fileChooseCtx->buttonIndex)->playerName[offset];
|
2022-03-21 21:51:23 -04:00
|
|
|
}
|
|
|
|
|
2022-06-20 13:41:43 -04:00
|
|
|
Save_SaveFile();
|
2022-03-21 21:51:23 -04:00
|
|
|
}
|
|
|
|
|
2022-06-20 13:41:43 -04:00
|
|
|
void Sram_InitSram(GameState* gameState) {
|
|
|
|
Save_Init();
|
2022-03-21 21:51:23 -04:00
|
|
|
|
|
|
|
func_800F6700(gSaveContext.audioSetting);
|
|
|
|
}
|