diff --git a/CMakeLists.txt b/CMakeLists.txt index 3cda3ab1b..f4b762b3b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,8 +7,8 @@ set(CMAKE_CXX_STANDARD 20 CACHE STRING "The C++ standard to use") set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15" CACHE STRING "Minimum OS X deployment version" FORCE) project(Ship LANGUAGES C CXX - VERSION 5.1.0) -set(PROJECT_BUILD_NAME "BRADLEY ALFA" CACHE STRING "") + VERSION 5.1.1) +set(PROJECT_BUILD_NAME "BRADLEY BRAVO" CACHE STRING "") set(PROJECT_TEAM "github.com/harbourmasters" CACHE STRING "") set_property(DIRECTORY ${CMAKE_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT soh) diff --git a/libultraship b/libultraship index e1fa7a2c0..df3a6dd29 160000 --- a/libultraship +++ b/libultraship @@ -1 +1 @@ -Subproject commit e1fa7a2c0e6baeed083cd2b8f22c260e2db48d29 +Subproject commit df3a6dd292c3fbed56969f17d9d018b44c8d2a46 diff --git a/soh/include/z64audio.h b/soh/include/z64audio.h index 6b4613fff..0e602f9d8 100644 --- a/soh/include/z64audio.h +++ b/soh/include/z64audio.h @@ -26,6 +26,8 @@ extern char* fontMap[256]; +#define MAX_AUTHENTIC_SEQID 110 + typedef enum { /* 0 */ ADSR_STATE_DISABLED, /* 1 */ ADSR_STATE_INITIAL, diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index 1302ac4de..bb58d3240 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -1162,6 +1162,65 @@ void Randomizer::ParseMasterQuestDungeonsFile(const char* spoilerFileName) { } } +int16_t Randomizer::GetVanillaMerchantPrice(RandomizerCheck check) { + switch (check) { + case RC_HF_DEKU_SCRUB_GROTTO: + return 10; + case RC_LW_DEKU_SCRUB_NEAR_DEKU_THEATER_LEFT: + case RC_DODONGOS_CAVERN_DEKU_SCRUB_SIDE_ROOM_NEAR_DODONGOS: + case RC_DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_REAR: + return 15; + case RC_LW_DEKU_SCRUB_NEAR_DEKU_THEATER_RIGHT: + case RC_LH_DEKU_SCRUB_GROTTO_LEFT: + case RC_GC_DEKU_SCRUB_GROTTO_LEFT: + case RC_DMC_DEKU_SCRUB_GROTTO_LEFT: + case RC_LLR_DEKU_SCRUB_GROTTO_LEFT: + case RC_DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_LEFT: + case RC_JABU_JABUS_BELLY_DEKU_SCRUB: + case RC_GANONS_CASTLE_MQ_DEKU_SCRUB_RIGHT: + return 20; + case RC_LW_DEKU_SCRUB_NEAR_BRIDGE: + case RC_LW_DEKU_SCRUB_GROTTO_REAR: + case RC_LW_DEKU_SCRUB_GROTTO_FRONT: + case RC_SFM_DEKU_SCRUB_GROTTO_REAR: + case RC_SFM_DEKU_SCRUB_GROTTO_FRONT: + case RC_LH_DEKU_SCRUB_GROTTO_RIGHT: + case RC_LH_DEKU_SCRUB_GROTTO_CENTER: + case RC_GV_DEKU_SCRUB_GROTTO_REAR: + case RC_GV_DEKU_SCRUB_GROTTO_FRONT: + case RC_COLOSSUS_DEKU_SCRUB_GROTTO_REAR: + case RC_COLOSSUS_DEKU_SCRUB_GROTTO_FRONT: + case RC_GC_DEKU_SCRUB_GROTTO_RIGHT: + case RC_GC_DEKU_SCRUB_GROTTO_CENTER: + case RC_DMC_DEKU_SCRUB: + case RC_DMC_DEKU_SCRUB_GROTTO_RIGHT: + case RC_DMC_DEKU_SCRUB_GROTTO_CENTER: + case RC_ZR_DEKU_SCRUB_GROTTO_REAR: + case RC_ZR_DEKU_SCRUB_GROTTO_FRONT: + case RC_LLR_DEKU_SCRUB_GROTTO_RIGHT: + case RC_LLR_DEKU_SCRUB_GROTTO_CENTER: + case RC_DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_RIGHT: + case RC_DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_FRONT: + case RC_DODONGOS_CAVERN_MQ_DEKU_SCRUB_SIDE_ROOM_NEAR_LOWER_LIZALFOS: + case RC_GANONS_CASTLE_DEKU_SCRUB_CENTER_LEFT: + case RC_GANONS_CASTLE_DEKU_SCRUB_CENTER_RIGHT: + case RC_GANONS_CASTLE_DEKU_SCRUB_RIGHT: + case RC_GANONS_CASTLE_DEKU_SCRUB_LEFT: + case RC_GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER_LEFT: + case RC_GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER: + case RC_GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER_RIGHT: + case RC_GANONS_CASTLE_MQ_DEKU_SCRUB_LEFT: + return 40; + case RC_DEKU_TREE_MQ_DEKU_SCRUB: + case RC_DODONGOS_CAVERN_DEKU_SCRUB_LOBBY: + case RC_DODONGOS_CAVERN_MQ_DEKU_SCRUB_STAIRCASE: + return 50; + default: + // we check for -1 when calling this to know if we don't have a price + return -1; + } +} + void Randomizer::ParseItemLocationsFile(const char* spoilerFileName, bool silent) { std::ifstream spoilerFileStream(sanitize(spoilerFileName)); if (!spoilerFileStream) @@ -1186,7 +1245,6 @@ void Randomizer::ParseItemLocationsFile(const char* spoilerFileName, bool silent if (it->is_structured()) { json itemJson = *it; for (auto itemit = itemJson.begin(); itemit != itemJson.end(); ++itemit) { - // todo handle prices if (itemit.key() == "item") { gSaveContext.itemLocations[randomizerCheck].check = randomizerCheck; gSaveContext.itemLocations[randomizerCheck].get.rgID = SpoilerfileGetNameToEnum[itemit.value()]; @@ -1204,6 +1262,10 @@ void Randomizer::ParseItemLocationsFile(const char* spoilerFileName, bool silent gSaveContext.itemLocations[randomizerCheck].check = SpoilerfileCheckNameToEnum[it.key()]; gSaveContext.itemLocations[randomizerCheck].get.rgID = SpoilerfileGetNameToEnum[it.value()]; gSaveContext.itemLocations[randomizerCheck].get.fakeRgID = RG_NONE; + int16_t price = GetVanillaMerchantPrice(randomizerCheck); + if (price != -1) { + merchantPrices[gSaveContext.itemLocations[randomizerCheck].check] = price; + } } } diff --git a/soh/soh/Enhancements/randomizer/randomizer.h b/soh/soh/Enhancements/randomizer/randomizer.h index 98b04f6c4..0af90e5d0 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.h +++ b/soh/soh/Enhancements/randomizer/randomizer.h @@ -31,6 +31,7 @@ class Randomizer { void ParseEntranceDataFile(const char* spoilerFileName, bool silent); bool IsItemVanilla(RandomizerGet randoGet); GetItemEntry GetItemEntryFromRGData(RandomizerGetData rgData, GetItemID ogItemId, bool checkObtainability = true); + int16_t GetVanillaMerchantPrice(RandomizerCheck check); public: Randomizer(); diff --git a/soh/soh/Enhancements/sfx-editor/SfxEditor.h b/soh/soh/Enhancements/sfx-editor/SfxEditor.h index a9a856515..526cd41f9 100644 --- a/soh/soh/Enhancements/sfx-editor/SfxEditor.h +++ b/soh/soh/Enhancements/sfx-editor/SfxEditor.h @@ -7,7 +7,6 @@ void SfxEditor_AddSequence(char *otrPath, uint16_t seqNum); #endif #define INSTRUMENT_OFFSET 0x81 -#define MAX_AUTHENTIC_SEQID 110 enum SeqType { SEQ_NOSHUFFLE = 0, diff --git a/soh/soh/SaveManager.cpp b/soh/soh/SaveManager.cpp index f0b0a522b..0e613edc0 100644 --- a/soh/soh/SaveManager.cpp +++ b/soh/soh/SaveManager.cpp @@ -24,7 +24,8 @@ std::filesystem::path SaveManager::GetFileName(int fileNum) { SaveManager::SaveManager() { AddLoadFunction("base", 1, LoadBaseVersion1); AddLoadFunction("base", 2, LoadBaseVersion2); - AddSaveFunction("base", 2, SaveBase); + AddLoadFunction("base", 3, LoadBaseVersion3); + AddSaveFunction("base", 3, SaveBase); AddLoadFunction("randomizer", 1, LoadRandomizerVersion1); AddLoadFunction("randomizer", 2, LoadRandomizerVersion2); @@ -825,9 +826,9 @@ void SaveManager::LoadBaseVersion1() { SaveManager::Instance->LoadData("rupees", gSaveContext.rupees); SaveManager::Instance->LoadData("swordHealth", gSaveContext.swordHealth); SaveManager::Instance->LoadData("naviTimer", gSaveContext.naviTimer); - SaveManager::Instance->LoadData("isMagicAcquired", gSaveContext.isMagicAcquired); - SaveManager::Instance->LoadData("isDoubleMagicAcquired", gSaveContext.isDoubleMagicAcquired); - SaveManager::Instance->LoadData("isDoubleDefenseAcquired", gSaveContext.isDoubleDefenseAcquired); + SaveManager::Instance->LoadData("magicAcquired", gSaveContext.isMagicAcquired); + SaveManager::Instance->LoadData("doubleMagic", gSaveContext.isDoubleMagicAcquired); + SaveManager::Instance->LoadData("doubleDefense", gSaveContext.isDoubleDefenseAcquired); SaveManager::Instance->LoadData("bgsFlag", gSaveContext.bgsFlag); SaveManager::Instance->LoadData("ocarinaGameRoundNum", gSaveContext.ocarinaGameRoundNum); SaveManager::Instance->LoadStruct("childEquips", []() { @@ -923,8 +924,8 @@ void SaveManager::LoadBaseVersion1() { SaveManager::Instance->LoadData("", gSaveContext.infTable[i]); }); SaveManager::Instance->LoadData("worldMapAreaData", gSaveContext.worldMapAreaData); - SaveManager::Instance->LoadData("scarecrowLongSongSet", gSaveContext.scarecrowLongSongSet); - SaveManager::Instance->LoadArray("scarecrowLongSong", sizeof(gSaveContext.scarecrowLongSong), [](size_t i) { + SaveManager::Instance->LoadData("scarecrowCustomSongSet", gSaveContext.scarecrowLongSongSet); + SaveManager::Instance->LoadArray("scarecrowCustomSong", sizeof(gSaveContext.scarecrowLongSong), [](size_t i) { SaveManager::Instance->LoadData("", ((u8*)&gSaveContext.scarecrowLongSong)[i]); }); SaveManager::Instance->LoadData("scarecrowSpawnSongSet", gSaveContext.scarecrowSpawnSongSet); @@ -947,6 +948,212 @@ void SaveManager::LoadBaseVersion1() { } void SaveManager::LoadBaseVersion2() { + SaveManager::Instance->LoadData("entranceIndex", gSaveContext.entranceIndex); + SaveManager::Instance->LoadData("linkAge", gSaveContext.linkAge); + SaveManager::Instance->LoadData("cutsceneIndex", gSaveContext.cutsceneIndex); + SaveManager::Instance->LoadData("dayTime", gSaveContext.dayTime); + SaveManager::Instance->LoadData("nightFlag", gSaveContext.nightFlag); + SaveManager::Instance->LoadData("totalDays", gSaveContext.totalDays); + SaveManager::Instance->LoadData("bgsDayCount", gSaveContext.bgsDayCount); + SaveManager::Instance->LoadData("deaths", gSaveContext.deaths); + SaveManager::Instance->LoadArray("playerName", ARRAY_COUNT(gSaveContext.playerName), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.playerName[i]); + }); + SaveManager::Instance->LoadData("n64ddFlag", gSaveContext.n64ddFlag); + SaveManager::Instance->LoadData("healthCapacity", gSaveContext.healthCapacity); + SaveManager::Instance->LoadData("health", gSaveContext.health); + SaveManager::Instance->LoadData("magicLevel", gSaveContext.magicLevel); + SaveManager::Instance->LoadData("magic", gSaveContext.magic); + SaveManager::Instance->LoadData("rupees", gSaveContext.rupees); + SaveManager::Instance->LoadData("swordHealth", gSaveContext.swordHealth); + SaveManager::Instance->LoadData("naviTimer", gSaveContext.naviTimer); + SaveManager::Instance->LoadData("magicAcquired", gSaveContext.isMagicAcquired); + SaveManager::Instance->LoadData("doubleMagic", gSaveContext.isDoubleMagicAcquired); + SaveManager::Instance->LoadData("doubleDefense", gSaveContext.isDoubleDefenseAcquired); + SaveManager::Instance->LoadData("bgsFlag", gSaveContext.bgsFlag); + SaveManager::Instance->LoadData("ocarinaGameRoundNum", gSaveContext.ocarinaGameRoundNum); + SaveManager::Instance->LoadStruct("childEquips", []() { + SaveManager::Instance->LoadArray("buttonItems", ARRAY_COUNT(gSaveContext.childEquips.buttonItems), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.childEquips.buttonItems[i], + static_cast(ITEM_NONE)); + }); + SaveManager::Instance->LoadArray("cButtonSlots", ARRAY_COUNT(gSaveContext.childEquips.cButtonSlots), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.childEquips.cButtonSlots[i], + static_cast(SLOT_NONE)); + }); + SaveManager::Instance->LoadData("equipment", gSaveContext.childEquips.equipment); + }); + SaveManager::Instance->LoadStruct("adultEquips", []() { + SaveManager::Instance->LoadArray("buttonItems", ARRAY_COUNT(gSaveContext.adultEquips.buttonItems), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.adultEquips.buttonItems[i], + static_cast(ITEM_NONE)); + }); + SaveManager::Instance->LoadArray("cButtonSlots", ARRAY_COUNT(gSaveContext.adultEquips.cButtonSlots), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.adultEquips.cButtonSlots[i], + static_cast(SLOT_NONE)); + }); + SaveManager::Instance->LoadData("equipment", gSaveContext.adultEquips.equipment); + }); + SaveManager::Instance->LoadData("unk_54", gSaveContext.unk_54); + SaveManager::Instance->LoadData("savedSceneNum", gSaveContext.savedSceneNum); + SaveManager::Instance->LoadStruct("equips", []() { + SaveManager::Instance->LoadArray("buttonItems", ARRAY_COUNT(gSaveContext.equips.buttonItems), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.equips.buttonItems[i], static_cast(ITEM_NONE)); + }); + SaveManager::Instance->LoadArray("cButtonSlots", ARRAY_COUNT(gSaveContext.equips.cButtonSlots), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.equips.cButtonSlots[i], static_cast(SLOT_NONE)); + }); + SaveManager::Instance->LoadData("equipment", gSaveContext.equips.equipment); + }); + SaveManager::Instance->LoadStruct("inventory", []() { + SaveManager::Instance->LoadArray("items", ARRAY_COUNT(gSaveContext.inventory.items), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.inventory.items[i]); + }); + SaveManager::Instance->LoadArray("ammo", ARRAY_COUNT(gSaveContext.inventory.ammo), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.inventory.ammo[i]); + }); + SaveManager::Instance->LoadData("equipment", gSaveContext.inventory.equipment); + SaveManager::Instance->LoadData("upgrades", gSaveContext.inventory.upgrades); + SaveManager::Instance->LoadData("questItems", gSaveContext.inventory.questItems); + SaveManager::Instance->LoadArray("dungeonItems", ARRAY_COUNT(gSaveContext.inventory.dungeonItems), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.inventory.dungeonItems[i]); + }); + SaveManager::Instance->LoadArray("dungeonKeys", ARRAY_COUNT(gSaveContext.inventory.dungeonKeys), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.inventory.dungeonKeys[i]); + }); + SaveManager::Instance->LoadData("defenseHearts", gSaveContext.inventory.defenseHearts); + SaveManager::Instance->LoadData("gsTokens", gSaveContext.inventory.gsTokens); + }); + SaveManager::Instance->LoadStruct("sohStats", []() { + SaveManager::Instance->LoadData("heartPieces", gSaveContext.sohStats.heartPieces); + SaveManager::Instance->LoadData("heartContainers", gSaveContext.sohStats.heartContainers); + SaveManager::Instance->LoadArray("dungeonKeys", ARRAY_COUNT(gSaveContext.sohStats.dungeonKeys), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.sohStats.dungeonKeys[i]); + }); + SaveManager::Instance->LoadData("playTimer", gSaveContext.sohStats.playTimer); + SaveManager::Instance->LoadData("pauseTimer", gSaveContext.sohStats.pauseTimer); + SaveManager::Instance->LoadArray("timestamps", ARRAY_COUNT(gSaveContext.sohStats.timestamp), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.sohStats.timestamp[i]); + }); + SaveManager::Instance->LoadArray("counts", ARRAY_COUNT(gSaveContext.sohStats.count), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.sohStats.count[i]); + }); + SaveManager::Instance->LoadArray("scenesDiscovered", ARRAY_COUNT(gSaveContext.sohStats.scenesDiscovered), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.sohStats.scenesDiscovered[i]); + }); + SaveManager::Instance->LoadArray("entrancesDiscovered", ARRAY_COUNT(gSaveContext.sohStats.entrancesDiscovered), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.sohStats.entrancesDiscovered[i]); + }); + }); + SaveManager::Instance->LoadArray("sceneFlags", ARRAY_COUNT(gSaveContext.sceneFlags), [](size_t i) { + SaveManager::Instance->LoadStruct("", [&i]() { + SaveManager::Instance->LoadData("chest", gSaveContext.sceneFlags[i].chest); + SaveManager::Instance->LoadData("swch", gSaveContext.sceneFlags[i].swch); + SaveManager::Instance->LoadData("clear", gSaveContext.sceneFlags[i].clear); + SaveManager::Instance->LoadData("collect", gSaveContext.sceneFlags[i].collect); + SaveManager::Instance->LoadData("unk", gSaveContext.sceneFlags[i].unk); + SaveManager::Instance->LoadData("rooms", gSaveContext.sceneFlags[i].rooms); + SaveManager::Instance->LoadData("floors", gSaveContext.sceneFlags[i].floors); + }); + }); + SaveManager::Instance->LoadStruct("fw", []() { + SaveManager::Instance->LoadStruct("pos", []() { + SaveManager::Instance->LoadData("x", gSaveContext.fw.pos.x); + SaveManager::Instance->LoadData("y", gSaveContext.fw.pos.y); + SaveManager::Instance->LoadData("z", gSaveContext.fw.pos.z); + }); + SaveManager::Instance->LoadData("yaw", gSaveContext.fw.yaw); + SaveManager::Instance->LoadData("playerParams", gSaveContext.fw.playerParams); + SaveManager::Instance->LoadData("entranceIndex", gSaveContext.fw.entranceIndex); + SaveManager::Instance->LoadData("roomIndex", gSaveContext.fw.roomIndex); + SaveManager::Instance->LoadData("set", gSaveContext.fw.set); + SaveManager::Instance->LoadData("tempSwchFlags", gSaveContext.fw.tempSwchFlags); + SaveManager::Instance->LoadData("tempCollectFlags", gSaveContext.fw.tempCollectFlags); + }); + SaveManager::Instance->LoadArray("gsFlags", ARRAY_COUNT(gSaveContext.gsFlags), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.gsFlags[i]); + }); + SaveManager::Instance->LoadArray("highScores", ARRAY_COUNT(gSaveContext.highScores), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.highScores[i]); + }); + SaveManager::Instance->LoadArray("eventChkInf", ARRAY_COUNT(gSaveContext.eventChkInf), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.eventChkInf[i]); + }); + SaveManager::Instance->LoadArray("itemGetInf", ARRAY_COUNT(gSaveContext.itemGetInf), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.itemGetInf[i]); + }); + SaveManager::Instance->LoadArray("infTable", ARRAY_COUNT(gSaveContext.infTable), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.infTable[i]); + }); + SaveManager::Instance->LoadData("worldMapAreaData", gSaveContext.worldMapAreaData); + SaveManager::Instance->LoadData("scarecrowCustomSongSet", gSaveContext.scarecrowLongSongSet); + SaveManager::Instance->LoadArray("scarecrowCustomSong", ARRAY_COUNT(gSaveContext.scarecrowLongSong), [](size_t i) { + SaveManager::Instance->LoadStruct("", [&i]() { + SaveManager::Instance->LoadData("noteIdx", gSaveContext.scarecrowLongSong[i].noteIdx); + SaveManager::Instance->LoadData("unk_01", gSaveContext.scarecrowLongSong[i].unk_01); + SaveManager::Instance->LoadData("unk_02", gSaveContext.scarecrowLongSong[i].unk_02); + SaveManager::Instance->LoadData("volume", gSaveContext.scarecrowLongSong[i].volume); + SaveManager::Instance->LoadData("vibrato", gSaveContext.scarecrowLongSong[i].vibrato); + SaveManager::Instance->LoadData("tone", gSaveContext.scarecrowLongSong[i].tone); + SaveManager::Instance->LoadData("semitone", gSaveContext.scarecrowLongSong[i].semitone); + }); + }); + SaveManager::Instance->LoadData("scarecrowSpawnSongSet", gSaveContext.scarecrowSpawnSongSet); + SaveManager::Instance->LoadArray("scarecrowSpawnSong", ARRAY_COUNT(gSaveContext.scarecrowSpawnSong), [](size_t i) { + SaveManager::Instance->LoadStruct("", [&i]() { + SaveManager::Instance->LoadData("noteIdx", gSaveContext.scarecrowSpawnSong[i].noteIdx); + SaveManager::Instance->LoadData("unk_01", gSaveContext.scarecrowSpawnSong[i].unk_01); + SaveManager::Instance->LoadData("unk_02", gSaveContext.scarecrowSpawnSong[i].unk_02); + SaveManager::Instance->LoadData("volume", gSaveContext.scarecrowSpawnSong[i].volume); + SaveManager::Instance->LoadData("vibrato", gSaveContext.scarecrowSpawnSong[i].vibrato); + SaveManager::Instance->LoadData("tone", gSaveContext.scarecrowSpawnSong[i].tone); + SaveManager::Instance->LoadData("semitone", gSaveContext.scarecrowSpawnSong[i].semitone); + }); + }); + SaveManager::Instance->LoadStruct("horseData", []() { + SaveManager::Instance->LoadData("scene", gSaveContext.horseData.scene); + SaveManager::Instance->LoadStruct("pos", []() { + SaveManager::Instance->LoadData("x", gSaveContext.horseData.pos.x); + SaveManager::Instance->LoadData("y", gSaveContext.horseData.pos.y); + SaveManager::Instance->LoadData("z", gSaveContext.horseData.pos.z); + }); + SaveManager::Instance->LoadData("angle", gSaveContext.horseData.angle); + }); + + SaveManager::Instance->LoadArray("randomizerInf", ARRAY_COUNT(gSaveContext.randomizerInf), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.randomizerInf[i]); + }); + SaveManager::Instance->LoadData("isMasterQuest", gSaveContext.isMasterQuest); + + // Workaround for breaking save compatibility from 5.0.2 -> 5.1.0 in commit d7c35221421bf712b5ead56a360f81f624aca4bc + if (!gSaveContext.isMagicAcquired) { + SaveManager::Instance->LoadData("isMagicAcquired", gSaveContext.isMagicAcquired); + } + if (!gSaveContext.isDoubleMagicAcquired) { + SaveManager::Instance->LoadData("isDoubleMagicAcquired", gSaveContext.isDoubleMagicAcquired); + } + if (!gSaveContext.isDoubleDefenseAcquired) { + SaveManager::Instance->LoadData("isDoubleDefenseAcquired", gSaveContext.isDoubleDefenseAcquired); + } + if (!gSaveContext.scarecrowLongSongSet) { + SaveManager::Instance->LoadData("scarecrowLongSongSet", gSaveContext.scarecrowLongSongSet); + if (gSaveContext.scarecrowLongSongSet) { + SaveManager::Instance->LoadArray("scarecrowLongSong", ARRAY_COUNT(gSaveContext.scarecrowLongSong), [](size_t i) { + SaveManager::Instance->LoadStruct("", [&i]() { + SaveManager::Instance->LoadData("noteIdx", gSaveContext.scarecrowLongSong[i].noteIdx); + SaveManager::Instance->LoadData("unk_01", gSaveContext.scarecrowLongSong[i].unk_01); + SaveManager::Instance->LoadData("unk_02", gSaveContext.scarecrowLongSong[i].unk_02); + SaveManager::Instance->LoadData("volume", gSaveContext.scarecrowLongSong[i].volume); + SaveManager::Instance->LoadData("vibrato", gSaveContext.scarecrowLongSong[i].vibrato); + SaveManager::Instance->LoadData("tone", gSaveContext.scarecrowLongSong[i].tone); + SaveManager::Instance->LoadData("semitone", gSaveContext.scarecrowLongSong[i].semitone); + }); + }); + } + } +} + +void SaveManager::LoadBaseVersion3() { SaveManager::Instance->LoadData("entranceIndex", gSaveContext.entranceIndex); SaveManager::Instance->LoadData("linkAge", gSaveContext.linkAge); SaveManager::Instance->LoadData("cutsceneIndex", gSaveContext.cutsceneIndex); diff --git a/soh/soh/SaveManager.h b/soh/soh/SaveManager.h index 6bcfbb01e..39669c520 100644 --- a/soh/soh/SaveManager.h +++ b/soh/soh/SaveManager.h @@ -122,6 +122,7 @@ public: static void LoadBaseVersion1(); static void LoadBaseVersion2(); + static void LoadBaseVersion3(); static void SaveBase(); std::vector initFuncs; diff --git a/soh/src/code/audio_load.c b/soh/src/code/audio_load.c index 354119cb2..ad6310157 100644 --- a/soh/src/code/audio_load.c +++ b/soh/src/code/audio_load.c @@ -78,6 +78,8 @@ void* sUnusedHandler = NULL; s32 gAudioContextInitalized = false; char* sequenceMap[MAX_SEQUENCES]; +// A map of authentic sequence IDs to their cache policies, for use with sequence swapping. +u8 seqCachePolicyMap[MAX_AUTHENTIC_SEQID]; char* fontMap[256]; uintptr_t fontStart; @@ -569,15 +571,20 @@ s32 AudioLoad_SyncInitSeqPlayerInternal(s32 playerIdx, s32 seqId, s32 arg2) { s32 index; s32 numFonts; s32 fontId; + s8 authCachePolicy = -1; // since 0 is a valid cache policy value AudioSeq_SequencePlayerDisable(seqPlayer); fontId = 0xFF; if (gAudioContext.seqReplaced[playerIdx]) { + authCachePolicy = seqCachePolicyMap[seqId]; seqId = gAudioContext.seqToPlay[playerIdx]; } SequenceData seqData2 = ResourceMgr_LoadSeqByName(sequenceMap[seqId]); + if (authCachePolicy != -1) { + seqData2.cachePolicy = authCachePolicy; + } for (int i = 0; i < seqData2.numFonts; i++) { @@ -1316,6 +1323,7 @@ void AudioLoad_Init(void* heap, size_t heapSize) { strcpy(str, seqList[i]); sequenceMap[sDat.seqNumber] = str; + seqCachePolicyMap[sDat.seqNumber] = sDat.cachePolicy; } free(seqList); diff --git a/soh/src/overlays/actors/ovl_En_Dns/z_en_dns.c b/soh/src/overlays/actors/ovl_En_Dns/z_en_dns.c index 492842d1e..4051ad619 100644 --- a/soh/src/overlays/actors/ovl_En_Dns/z_en_dns.c +++ b/soh/src/overlays/actors/ovl_En_Dns/z_en_dns.c @@ -178,6 +178,13 @@ void EnDns_Init(Actor* thisx, PlayState* play) { this->dnsItemEntry->itemPrice = this->scrubIdentity.itemPrice; } + if (Randomizer_GetSettingValue(RSK_SHUFFLE_SCRUBS) == RO_SCRUBS_EXPENSIVE) { + // temporary workaround: always use 40 rupees as price instead of 70 + if (this->actor.params == 0x0006) { + this->dnsItemEntry->itemPrice = 40; + } + } + if (this->scrubIdentity.isShuffled) { this->dnsItemEntry->getItemId = this->scrubIdentity.getItemId; this->dnsItemEntry->purchaseableCheck = EnDns_RandomizerPurchaseableCheck; diff --git a/soh/src/overlays/actors/ovl_player_actor/z_player.c b/soh/src/overlays/actors/ovl_player_actor/z_player.c index 08f0da8d0..f58248db0 100644 --- a/soh/src/overlays/actors/ovl_player_actor/z_player.c +++ b/soh/src/overlays/actors/ovl_player_actor/z_player.c @@ -1710,7 +1710,7 @@ s32 func_808332E4(Player* this) { void func_808332F4(Player* this, PlayState* play) { GetItemEntry giEntry; - if (this->getItemEntry.objectId == OBJECT_INVALID) { + if (this->getItemEntry.objectId == OBJECT_INVALID || (this->getItemId != this->getItemEntry.getItemId)) { giEntry = ItemTable_Retrieve(this->getItemId); } else { giEntry = this->getItemEntry; @@ -12576,7 +12576,7 @@ s32 func_8084DFF4(PlayState* play, Player* this) { } if (this->unk_84F == 0) { - if (this->getItemEntry.objectId == OBJECT_INVALID) { + if (this->getItemEntry.objectId == OBJECT_INVALID || (this->getItemId != this->getItemEntry.getItemId)) { giEntry = ItemTable_Retrieve(this->getItemId); } else { giEntry = this->getItemEntry;