mirror of
https://github.com/HarbourMasters/Shipwright.git
synced 2025-02-16 15:20:11 -05:00
Merge pull request #3399 from HarbourMasters/develop-macready
macready -> dev
This commit is contained in:
commit
2075213544
@ -5,8 +5,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")
|
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15" CACHE STRING "Minimum OS X deployment version")
|
||||||
|
|
||||||
project(Ship VERSION 8.0.0 LANGUAGES C CXX)
|
project(Ship VERSION 8.0.1 LANGUAGES C CXX)
|
||||||
set(PROJECT_BUILD_NAME "MacReady Alfa" CACHE STRING "")
|
set(PROJECT_BUILD_NAME "MacReady Bravo" CACHE STRING "")
|
||||||
set(PROJECT_TEAM "github.com/harbourmasters" CACHE STRING "")
|
set(PROJECT_TEAM "github.com/harbourmasters" CACHE STRING "")
|
||||||
|
|
||||||
set_property(DIRECTORY ${CMAKE_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT soh)
|
set_property(DIRECTORY ${CMAKE_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT soh)
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit 0d8f5570a8e57f302ec6633d65615ee21ab39454
|
Subproject commit 04b85b95fab07a394b62dcd28a502a3040f08e0c
|
@ -1 +1 @@
|
|||||||
Subproject commit c75ff3653f699cb1a8c017b10e4b3986259d8cf0
|
Subproject commit 9509806ae3ca6e35882fb976de70c5bde471b8f5
|
@ -439,7 +439,7 @@ static std::unordered_map<u16, const char*> actorDescriptions = {
|
|||||||
{ ACTOR_EN_DAIKU_KAKARIKO, "Carpenters (Kakariko)" },
|
{ ACTOR_EN_DAIKU_KAKARIKO, "Carpenters (Kakariko)" },
|
||||||
{ ACTOR_BG_BOWL_WALL, "Bombchu Bowling Alley Wall" },
|
{ ACTOR_BG_BOWL_WALL, "Bombchu Bowling Alley Wall" },
|
||||||
{ ACTOR_EN_WALL_TUBO, "Bombchu Bowling Alley Bullseyes" },
|
{ ACTOR_EN_WALL_TUBO, "Bombchu Bowling Alley Bullseyes" },
|
||||||
{ ACTOR_EN_PO_DESERT, "Poe Guide (Desert Wasteland)" },
|
{ ACTOR_EN_PO_DESERT, "Poe Guide (Haunted Wasteland)" },
|
||||||
{ ACTOR_EN_CROW, "Guay" },
|
{ ACTOR_EN_CROW, "Guay" },
|
||||||
{ ACTOR_DOOR_KILLER, "Fake Door" },
|
{ ACTOR_DOOR_KILLER, "Fake Door" },
|
||||||
{ ACTOR_BG_SPOT11_OASIS, "Oasis (Desert Colossus)" },
|
{ ACTOR_BG_SPOT11_OASIS, "Oasis (Desert Colossus)" },
|
||||||
|
@ -400,8 +400,9 @@ void AudioCollection::InitializeShufflePool() {
|
|||||||
if (shufflePoolInitialized) return;
|
if (shufflePoolInitialized) return;
|
||||||
|
|
||||||
for (auto& [seqId, seqInfo] : sequenceMap) {
|
for (auto& [seqId, seqInfo] : sequenceMap) {
|
||||||
|
if (!seqInfo.canBeUsedAsReplacement) continue;
|
||||||
const std::string cvarKey = "gAudioEditor.Excluded." + seqInfo.sfxKey;
|
const std::string cvarKey = "gAudioEditor.Excluded." + seqInfo.sfxKey;
|
||||||
if (CVarGetInteger(cvarKey.c_str(), 0) && !seqInfo.canBeUsedAsReplacement) {
|
if (CVarGetInteger(cvarKey.c_str(), 0)) {
|
||||||
excludedSequences.insert(&seqInfo);
|
excludedSequences.insert(&seqInfo);
|
||||||
} else {
|
} else {
|
||||||
includedSequences.insert(&seqInfo);
|
includedSequences.insert(&seqInfo);
|
||||||
|
@ -1767,6 +1767,10 @@ void CosmeticsEditorWindow::DrawElement() {
|
|||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
UIWidgets::EnhancementCombobox("gCosmetics.DefaultColorScheme", colorSchemes, COLORSCHEME_N64);
|
UIWidgets::EnhancementCombobox("gCosmetics.DefaultColorScheme", colorSchemes, COLORSCHEME_N64);
|
||||||
UIWidgets::EnhancementCheckbox("Advanced Mode", "gCosmetics.AdvancedMode");
|
UIWidgets::EnhancementCheckbox("Advanced Mode", "gCosmetics.AdvancedMode");
|
||||||
|
UIWidgets::InsertHelpHoverText(
|
||||||
|
"Some cosmetic options may not apply if you have any mods that provide custom models for the cosmetic option.\n\n"
|
||||||
|
"For example, if you have custom Link model, then the Link's Hair color option will most likely not apply."
|
||||||
|
);
|
||||||
if (CVarGetInteger("gCosmetics.AdvancedMode", 0)) {
|
if (CVarGetInteger("gCosmetics.AdvancedMode", 0)) {
|
||||||
if (ImGui::Button("Lock All Advanced", ImVec2(ImGui::GetContentRegionAvail().x / 2, 30.0f))) {
|
if (ImGui::Button("Lock All Advanced", ImVec2(ImGui::GetContentRegionAvail().x / 2, 30.0f))) {
|
||||||
for (auto& [id, cosmeticOption] : cosmeticOptions) {
|
for (auto& [id, cosmeticOption] : cosmeticOptions) {
|
||||||
|
@ -207,6 +207,7 @@ static bool ResetHandler(std::shared_ptr<LUS::Console> Console, std::vector<std:
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gPlayState->gameplayFrames = 0;
|
||||||
SET_NEXT_GAMESTATE(&gPlayState->state, TitleSetup_Init, GameState);
|
SET_NEXT_GAMESTATE(&gPlayState->state, TitleSetup_Init, GameState);
|
||||||
gPlayState->state.running = false;
|
gPlayState->state.running = false;
|
||||||
GameInteractor::Instance->ExecuteHooks<GameInteractor::OnExitGame>(gSaveContext.fileNum);
|
GameInteractor::Instance->ExecuteHooks<GameInteractor::OnExitGame>(gSaveContext.fileNum);
|
||||||
|
@ -35,8 +35,6 @@ extern PlayState* gPlayState;
|
|||||||
extern void Overlay_DisplayText(float duration, const char* text);
|
extern void Overlay_DisplayText(float duration, const char* text);
|
||||||
uint32_t ResourceMgr_IsSceneMasterQuest(s16 sceneNum);
|
uint32_t ResourceMgr_IsSceneMasterQuest(s16 sceneNum);
|
||||||
}
|
}
|
||||||
bool performDelayedSave = false;
|
|
||||||
bool performSave = false;
|
|
||||||
|
|
||||||
// TODO: When there's more uses of something like this, create a new GI::RawAction?
|
// TODO: When there's more uses of something like this, create a new GI::RawAction?
|
||||||
void ReloadSceneTogglingLinkAge() {
|
void ReloadSceneTogglingLinkAge() {
|
||||||
@ -258,14 +256,12 @@ void RegisterOcarinaTimeTravel() {
|
|||||||
|
|
||||||
void AutoSave(GetItemEntry itemEntry) {
|
void AutoSave(GetItemEntry itemEntry) {
|
||||||
u8 item = itemEntry.itemId;
|
u8 item = itemEntry.itemId;
|
||||||
|
bool performSave = false;
|
||||||
// Don't autosave immediately after buying items from shops to prevent getting them for free!
|
// Don't autosave immediately after buying items from shops to prevent getting them for free!
|
||||||
// Don't autosave in the Chamber of Sages since resuming from that map breaks the game
|
// Don't autosave in the Chamber of Sages since resuming from that map breaks the game
|
||||||
// Don't autosave during the Ganon fight when picking up the Master Sword
|
// Don't autosave during the Ganon fight when picking up the Master Sword
|
||||||
// Don't autosave in the fishing pond to prevent getting rod on B outside of the pond
|
|
||||||
// Don't autosave in the bombchu bowling alley to prevent having chus on B outside of the minigame
|
|
||||||
// Don't autosave in grottos since resuming from grottos breaks the game.
|
|
||||||
if ((CVarGetInteger("gAutosave", AUTOSAVE_OFF) != AUTOSAVE_OFF) && (gPlayState != NULL) && (gSaveContext.pendingSale == ITEM_NONE) &&
|
if ((CVarGetInteger("gAutosave", AUTOSAVE_OFF) != AUTOSAVE_OFF) && (gPlayState != NULL) && (gSaveContext.pendingSale == ITEM_NONE) &&
|
||||||
(gPlayState->gameplayFrames > 60 && gSaveContext.cutsceneIndex < 0xFFF0) && (gPlayState->sceneNum != SCENE_GANON_BOSS)) {
|
(gPlayState->gameplayFrames > 60 && gSaveContext.cutsceneIndex < 0xFFF0) && (gPlayState->sceneNum != SCENE_GANON_BOSS) && (gPlayState->sceneNum != SCENE_CHAMBER_OF_THE_SAGES)) {
|
||||||
if (((CVarGetInteger("gAutosave", AUTOSAVE_OFF) == AUTOSAVE_LOCATION_AND_ALL_ITEMS) || (CVarGetInteger("gAutosave", AUTOSAVE_OFF) == AUTOSAVE_ALL_ITEMS)) && (item != ITEM_NONE)) {
|
if (((CVarGetInteger("gAutosave", AUTOSAVE_OFF) == AUTOSAVE_LOCATION_AND_ALL_ITEMS) || (CVarGetInteger("gAutosave", AUTOSAVE_OFF) == AUTOSAVE_ALL_ITEMS)) && (item != ITEM_NONE)) {
|
||||||
// Autosave for all items
|
// Autosave for all items
|
||||||
performSave = true;
|
performSave = true;
|
||||||
@ -326,25 +322,9 @@ void AutoSave(GetItemEntry itemEntry) {
|
|||||||
CVarGetInteger("gAutosave", AUTOSAVE_OFF) == AUTOSAVE_LOCATION) {
|
CVarGetInteger("gAutosave", AUTOSAVE_OFF) == AUTOSAVE_LOCATION) {
|
||||||
performSave = true;
|
performSave = true;
|
||||||
}
|
}
|
||||||
if (gPlayState->sceneNum == SCENE_FAIRYS_FOUNTAIN || gPlayState->sceneNum == SCENE_GROTTOS ||
|
if (performSave) {
|
||||||
gPlayState->sceneNum == SCENE_CHAMBER_OF_THE_SAGES || gPlayState->sceneNum == SCENE_FISHING_POND ||
|
|
||||||
gPlayState->sceneNum == SCENE_BOMBCHU_BOWLING_ALLEY) {
|
|
||||||
if (CVarGetInteger("gAutosave", AUTOSAVE_OFF) == AUTOSAVE_LOCATION_AND_MAJOR_ITEMS ||
|
|
||||||
CVarGetInteger("gAutosave", AUTOSAVE_OFF) == AUTOSAVE_LOCATION_AND_ALL_ITEMS ||
|
|
||||||
CVarGetInteger("gAutosave", AUTOSAVE_OFF) == AUTOSAVE_LOCATION) {
|
|
||||||
performSave = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (performSave) {
|
|
||||||
performSave = false;
|
|
||||||
performDelayedSave = true;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (performSave || performDelayedSave) {
|
|
||||||
Play_PerformSave(gPlayState);
|
Play_PerformSave(gPlayState);
|
||||||
performSave = false;
|
performSave = false;
|
||||||
performDelayedSave = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -783,7 +783,7 @@ std::map<RandomizerCheckArea, std::string> rcAreaNames = {
|
|||||||
{ RCAREA_LAKE_HYLIA, "Lake Hylia"},
|
{ RCAREA_LAKE_HYLIA, "Lake Hylia"},
|
||||||
{ RCAREA_GERUDO_VALLEY, "Gerudo Valley"},
|
{ RCAREA_GERUDO_VALLEY, "Gerudo Valley"},
|
||||||
{ RCAREA_GERUDO_FORTRESS, "Gerudo Fortress"},
|
{ RCAREA_GERUDO_FORTRESS, "Gerudo Fortress"},
|
||||||
{ RCAREA_WASTELAND, "Desert Wasteland"},
|
{ RCAREA_WASTELAND, "Haunted Wasteland"},
|
||||||
{ RCAREA_DESERT_COLOSSUS, "Desert Colossus"},
|
{ RCAREA_DESERT_COLOSSUS, "Desert Colossus"},
|
||||||
{ RCAREA_MARKET, "Hyrule Market"},
|
{ RCAREA_MARKET, "Hyrule Market"},
|
||||||
{ RCAREA_HYRULE_CASTLE, "Hyrule Castle"},
|
{ RCAREA_HYRULE_CASTLE, "Hyrule Castle"},
|
||||||
|
@ -452,6 +452,63 @@ bool HasItemBeenCollected(RandomizerCheck rc) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CheckTrackerLoadGame(int32_t fileNum) {
|
||||||
|
LoadSettings();
|
||||||
|
TrySetAreas();
|
||||||
|
for (auto [rc, rcObj] : RandomizerCheckObjects::GetAllRCObjects()) {
|
||||||
|
RandomizerCheckTrackerData rcTrackerData = gSaveContext.checkTrackerData[rc];
|
||||||
|
if (rc == RC_UNKNOWN_CHECK || rc == RC_MAX || rc == RC_LINKS_POCKET ||
|
||||||
|
!RandomizerCheckObjects::GetAllRCObjects().contains(rc))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
RandomizerCheckObject realRcObj;
|
||||||
|
if (rc == RC_GIFT_FROM_SAGES && !IS_RANDO) {
|
||||||
|
realRcObj = RCO_RAORU;
|
||||||
|
} else {
|
||||||
|
realRcObj = rcObj;
|
||||||
|
}
|
||||||
|
if (!IsVisibleInCheckTracker(realRcObj)) continue;
|
||||||
|
|
||||||
|
checksByArea.find(realRcObj.rcArea)->second.push_back(realRcObj);
|
||||||
|
if (rcTrackerData.status == RCSHOW_SAVED || rcTrackerData.skipped) {
|
||||||
|
areaChecksGotten[realRcObj.rcArea]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (areaChecksGotten[realRcObj.rcArea] != 0 || RandomizerCheckObjects::AreaIsOverworld(realRcObj.rcArea)) {
|
||||||
|
areasSpoiled |= (1 << realRcObj.rcArea);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_LINKS_POCKET) != RO_LINKS_POCKET_NOTHING && IS_RANDO) {
|
||||||
|
s8 startingAge = OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_STARTING_AGE);
|
||||||
|
RandomizerCheckArea startingArea;
|
||||||
|
switch (startingAge) {
|
||||||
|
case RO_AGE_CHILD:
|
||||||
|
startingArea = RCAREA_KOKIRI_FOREST;
|
||||||
|
break;
|
||||||
|
case RO_AGE_ADULT:
|
||||||
|
startingArea = RCAREA_MARKET;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
startingArea = RCAREA_KOKIRI_FOREST;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
RandomizerCheckObject linksPocket = { RC_LINKS_POCKET, RCVORMQ_BOTH, RCTYPE_LINKS_POCKET, startingArea, ACTOR_ID_MAX, SCENE_ID_MAX, 0x00, GI_NONE, false, "Link's Pocket", "Link's Pocket" };
|
||||||
|
|
||||||
|
checksByArea.find(startingArea)->second.push_back(linksPocket);
|
||||||
|
areaChecksGotten[startingArea]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
showVOrMQ = (OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_RANDOM_MQ_DUNGEONS) == RO_MQ_DUNGEONS_RANDOM_NUMBER ||
|
||||||
|
(OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_RANDOM_MQ_DUNGEONS) == RO_MQ_DUNGEONS_SET_NUMBER &&
|
||||||
|
OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_MQ_DUNGEON_COUNT) < 12));
|
||||||
|
LinksPocket();
|
||||||
|
SongFromImpa();
|
||||||
|
GiftFromSages();
|
||||||
|
initialized = true;
|
||||||
|
UpdateAllOrdering();
|
||||||
|
UpdateInventoryChecks();
|
||||||
|
}
|
||||||
|
|
||||||
void CheckTrackerDialogClosed() {
|
void CheckTrackerDialogClosed() {
|
||||||
if (messageCloseCheck) {
|
if (messageCloseCheck) {
|
||||||
messageCloseCheck = false;
|
messageCloseCheck = false;
|
||||||
@ -679,9 +736,6 @@ void SaveFile(SaveContext* saveContext, int sectionID, bool fullSave) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void LoadFile() {
|
void LoadFile() {
|
||||||
Teardown();
|
|
||||||
LoadSettings();
|
|
||||||
TrySetAreas();
|
|
||||||
SaveManager::Instance->LoadArray("checks", RC_MAX, [](size_t i) {
|
SaveManager::Instance->LoadArray("checks", RC_MAX, [](size_t i) {
|
||||||
SaveManager::Instance->LoadStruct("", [&]() {
|
SaveManager::Instance->LoadStruct("", [&]() {
|
||||||
SaveManager::Instance->LoadData("status", gSaveContext.checkTrackerData[i].status);
|
SaveManager::Instance->LoadData("status", gSaveContext.checkTrackerData[i].status);
|
||||||
@ -689,58 +743,7 @@ void LoadFile() {
|
|||||||
SaveManager::Instance->LoadData("price", gSaveContext.checkTrackerData[i].price);
|
SaveManager::Instance->LoadData("price", gSaveContext.checkTrackerData[i].price);
|
||||||
SaveManager::Instance->LoadData("hintItem", gSaveContext.checkTrackerData[i].hintItem);
|
SaveManager::Instance->LoadData("hintItem", gSaveContext.checkTrackerData[i].hintItem);
|
||||||
});
|
});
|
||||||
RandomizerCheckTrackerData entry = gSaveContext.checkTrackerData[i];
|
|
||||||
RandomizerCheck rc = static_cast<RandomizerCheck>(i);
|
|
||||||
if (rc == RC_UNKNOWN_CHECK || rc == RC_MAX ||
|
|
||||||
!RandomizerCheckObjects::GetAllRCObjects().contains(rc))
|
|
||||||
return;
|
|
||||||
|
|
||||||
RandomizerCheckObject entry2;
|
|
||||||
if (rc == RC_GIFT_FROM_SAGES && !IS_RANDO) {
|
|
||||||
entry2 = RCO_RAORU;
|
|
||||||
} else {
|
|
||||||
entry2 = RandomizerCheckObjects::GetAllRCObjects().find(rc)->second;
|
|
||||||
}
|
|
||||||
if (!IsVisibleInCheckTracker(entry2)) return;
|
|
||||||
|
|
||||||
checksByArea.find(entry2.rcArea)->second.push_back(entry2);
|
|
||||||
if (entry.status == RCSHOW_SAVED || entry.skipped) {
|
|
||||||
areaChecksGotten[entry2.rcArea]++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (areaChecksGotten[entry2.rcArea] != 0 || RandomizerCheckObjects::AreaIsOverworld(entry2.rcArea)) {
|
|
||||||
areasSpoiled |= (1 << entry2.rcArea);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
if (OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_LINKS_POCKET) != RO_LINKS_POCKET_NOTHING && IS_RANDO) {
|
|
||||||
s8 startingAge = OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_STARTING_AGE);
|
|
||||||
RandomizerCheckArea startingArea;
|
|
||||||
switch (startingAge) {
|
|
||||||
case RO_AGE_CHILD:
|
|
||||||
startingArea = RCAREA_KOKIRI_FOREST;
|
|
||||||
break;
|
|
||||||
case RO_AGE_ADULT:
|
|
||||||
startingArea = RCAREA_MARKET;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
startingArea = RCAREA_KOKIRI_FOREST;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
RandomizerCheckObject linksPocket = { RC_LINKS_POCKET, RCVORMQ_BOTH, RCTYPE_LINKS_POCKET, startingArea, ACTOR_ID_MAX, SCENE_ID_MAX, 0x00, GI_NONE, false, "Link's Pocket", "Link's Pocket" };
|
|
||||||
|
|
||||||
checksByArea.find(startingArea)->second.push_back(linksPocket);
|
|
||||||
areaChecksGotten[startingArea]++;
|
|
||||||
}
|
|
||||||
|
|
||||||
showVOrMQ = (OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_RANDOM_MQ_DUNGEONS) == RO_MQ_DUNGEONS_RANDOM_NUMBER ||
|
|
||||||
(OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_RANDOM_MQ_DUNGEONS) == RO_MQ_DUNGEONS_SET_NUMBER &&
|
|
||||||
OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_MQ_DUNGEON_COUNT) < 12));
|
|
||||||
LinksPocket();
|
|
||||||
SongFromImpa();
|
|
||||||
GiftFromSages();
|
|
||||||
initialized = true;
|
|
||||||
UpdateAllOrdering();
|
|
||||||
UpdateInventoryChecks();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Teardown() {
|
void Teardown() {
|
||||||
@ -1533,6 +1536,7 @@ void CheckTrackerWindow::InitElement() {
|
|||||||
SaveManager::Instance->AddInitFunction(InitTrackerData);
|
SaveManager::Instance->AddInitFunction(InitTrackerData);
|
||||||
sectionId = SaveManager::Instance->AddSaveFunction("trackerData", 1, SaveFile, true, -1);
|
sectionId = SaveManager::Instance->AddSaveFunction("trackerData", 1, SaveFile, true, -1);
|
||||||
SaveManager::Instance->AddLoadFunction("trackerData", 1, LoadFile);
|
SaveManager::Instance->AddLoadFunction("trackerData", 1, LoadFile);
|
||||||
|
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnLoadGame>(CheckTrackerLoadGame);
|
||||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnExitGame>([](uint32_t fileNum) {
|
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnExitGame>([](uint32_t fileNum) {
|
||||||
Teardown();
|
Teardown();
|
||||||
});
|
});
|
||||||
|
@ -219,7 +219,7 @@ std::unordered_map<RandomizerTrickArea, std::string> rtAreaNames = {
|
|||||||
{ RTAREA_LAKE_HYLIA, "Lake Hylia"},
|
{ RTAREA_LAKE_HYLIA, "Lake Hylia"},
|
||||||
{ RTAREA_GERUDO_VALLEY, "Gerudo Valley"},
|
{ RTAREA_GERUDO_VALLEY, "Gerudo Valley"},
|
||||||
{ RTAREA_GERUDO_FORTRESS, "Gerudo Fortress"},
|
{ RTAREA_GERUDO_FORTRESS, "Gerudo Fortress"},
|
||||||
{ RTAREA_WASTELAND, "Desert Wasteland"},
|
{ RTAREA_WASTELAND, "Haunted Wasteland"},
|
||||||
{ RTAREA_DESERT_COLOSSUS, "Desert Colossus"},
|
{ RTAREA_DESERT_COLOSSUS, "Desert Colossus"},
|
||||||
{ RTAREA_MARKET, "Hyrule Market"},
|
{ RTAREA_MARKET, "Hyrule Market"},
|
||||||
{ RTAREA_HYRULE_CASTLE, "Hyrule Castle"},
|
{ RTAREA_HYRULE_CASTLE, "Hyrule Castle"},
|
||||||
|
@ -1569,6 +1569,11 @@ extern "C" Gfx* ResourceMgr_LoadGfxByName(const char* path)
|
|||||||
return (Gfx*)&res->Instructions[0];
|
return (Gfx*)&res->Instructions[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" uint8_t ResourceMgr_FileIsCustomByName(const char* path) {
|
||||||
|
auto res = std::static_pointer_cast<LUS::DisplayList>(GetResourceByNameHandlingMQ(path));
|
||||||
|
return res->GetInitData()->IsCustom;
|
||||||
|
}
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int index;
|
int index;
|
||||||
Gfx instruction;
|
Gfx instruction;
|
||||||
@ -1600,6 +1605,11 @@ extern "C" void ResourceMgr_PatchGfxByName(const char* path, const char* patchNa
|
|||||||
// index /= 2;
|
// index /= 2;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
// Do not patch custom assets as they most likely do not have the same instructions as authentic assets
|
||||||
|
if (res->GetInitData()->IsCustom) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Gfx* gfx = (Gfx*)&res->Instructions[index];
|
Gfx* gfx = (Gfx*)&res->Instructions[index];
|
||||||
|
|
||||||
if (!originalGfx.contains(path) || !originalGfx[path].contains(patchName)) {
|
if (!originalGfx.contains(path) || !originalGfx[path].contains(patchName)) {
|
||||||
@ -1616,6 +1626,11 @@ extern "C" void ResourceMgr_PatchGfxCopyCommandByName(const char* path, const ch
|
|||||||
auto res = std::static_pointer_cast<LUS::DisplayList>(
|
auto res = std::static_pointer_cast<LUS::DisplayList>(
|
||||||
LUS::Context::GetInstance()->GetResourceManager()->LoadResource(path));
|
LUS::Context::GetInstance()->GetResourceManager()->LoadResource(path));
|
||||||
|
|
||||||
|
// Do not patch custom assets as they most likely do not have the same instructions as authentic assets
|
||||||
|
if (res->GetInitData()->IsCustom) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Gfx* destinationGfx = (Gfx*)&res->Instructions[destinationIndex];
|
Gfx* destinationGfx = (Gfx*)&res->Instructions[destinationIndex];
|
||||||
Gfx sourceGfx = res->Instructions[sourceIndex];
|
Gfx sourceGfx = res->Instructions[sourceIndex];
|
||||||
|
|
||||||
|
@ -101,6 +101,7 @@ AnimationHeaderCommon* ResourceMgr_LoadAnimByName(const char* path);
|
|||||||
char* ResourceMgr_GetNameByCRC(uint64_t crc, char* alloc);
|
char* ResourceMgr_GetNameByCRC(uint64_t crc, char* alloc);
|
||||||
Gfx* ResourceMgr_LoadGfxByCRC(uint64_t crc);
|
Gfx* ResourceMgr_LoadGfxByCRC(uint64_t crc);
|
||||||
Gfx* ResourceMgr_LoadGfxByName(const char* path);
|
Gfx* ResourceMgr_LoadGfxByName(const char* path);
|
||||||
|
uint8_t ResourceMgr_FileIsCustomByName(const char* path);
|
||||||
void ResourceMgr_PatchGfxByName(const char* path, const char* patchName, int index, Gfx instruction);
|
void ResourceMgr_PatchGfxByName(const char* path, const char* patchName, int index, Gfx instruction);
|
||||||
void ResourceMgr_UnpatchGfxByName(const char* path, const char* patchName);
|
void ResourceMgr_UnpatchGfxByName(const char* path, const char* patchName);
|
||||||
char* ResourceMgr_LoadArrayByNameAsVec3s(const char* path);
|
char* ResourceMgr_LoadArrayByNameAsVec3s(const char* path);
|
||||||
|
@ -47,6 +47,11 @@ std::filesystem::path SaveManager::GetFileName(int fileNum) {
|
|||||||
return sSavePath / ("file" + std::to_string(fileNum + 1) + ".sav");
|
return sSavePath / ("file" + std::to_string(fileNum + 1) + ".sav");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::filesystem::path SaveManager::GetFileTempName(int fileNum) {
|
||||||
|
const std::filesystem::path sSavePath(LUS::Context::GetPathRelativeToAppDirectory("Save"));
|
||||||
|
return sSavePath / ("file" + std::to_string(fileNum + 1) + ".temp");
|
||||||
|
}
|
||||||
|
|
||||||
SaveManager::SaveManager() {
|
SaveManager::SaveManager() {
|
||||||
coreSectionIDsByName["base"] = SECTION_ID_BASE;
|
coreSectionIDsByName["base"] = SECTION_ID_BASE;
|
||||||
coreSectionIDsByName["randomizer"] = SECTION_ID_RANDOMIZER;
|
coreSectionIDsByName["randomizer"] = SECTION_ID_RANDOMIZER;
|
||||||
@ -65,6 +70,10 @@ SaveManager::SaveManager() {
|
|||||||
|
|
||||||
AddInitFunction(InitFileImpl);
|
AddInitFunction(InitFileImpl);
|
||||||
|
|
||||||
|
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnExitGame>([this](uint32_t fileNum) { ThreadPoolWait(); });
|
||||||
|
|
||||||
|
smThreadPool = std::make_shared<BS::thread_pool>(1);
|
||||||
|
|
||||||
for (SaveFileMetaInfo& info : fileMetaInfo) {
|
for (SaveFileMetaInfo& info : fileMetaInfo) {
|
||||||
info.valid = false;
|
info.valid = false;
|
||||||
info.deaths = 0;
|
info.deaths = 0;
|
||||||
@ -357,12 +366,14 @@ void SaveManager::SaveRandomizer(SaveContext* saveContext, int sectionID, bool f
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Init() here is an extension of InitSram, and thus not truly an initializer for SaveManager itself. don't put any class initialization stuff here
|
||||||
void SaveManager::Init() {
|
void SaveManager::Init() {
|
||||||
|
// Wait on saves that snuck through the Wait in OnExitGame
|
||||||
|
ThreadPoolWait();
|
||||||
const std::filesystem::path sSavePath(LUS::Context::GetPathRelativeToAppDirectory("Save"));
|
const std::filesystem::path sSavePath(LUS::Context::GetPathRelativeToAppDirectory("Save"));
|
||||||
const std::filesystem::path sGlobalPath = sSavePath / std::string("global.sav");
|
const std::filesystem::path sGlobalPath = sSavePath / std::string("global.sav");
|
||||||
auto sOldSavePath = LUS::Context::GetPathRelativeToAppDirectory("oot_save.sav");
|
auto sOldSavePath = LUS::Context::GetPathRelativeToAppDirectory("oot_save.sav");
|
||||||
auto sOldBackupSavePath = LUS::Context::GetPathRelativeToAppDirectory("oot_save.bak");
|
auto sOldBackupSavePath = LUS::Context::GetPathRelativeToAppDirectory("oot_save.bak");
|
||||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnExitGame>([this](uint32_t fileNum) { ThreadPoolWait(); });
|
|
||||||
|
|
||||||
// If the save directory does not exist, create it
|
// If the save directory does not exist, create it
|
||||||
if (!std::filesystem::exists(sSavePath)) {
|
if (!std::filesystem::exists(sSavePath)) {
|
||||||
@ -403,7 +414,6 @@ void SaveManager::Init() {
|
|||||||
} else {
|
} else {
|
||||||
CreateDefaultGlobal();
|
CreateDefaultGlobal();
|
||||||
}
|
}
|
||||||
smThreadPool = std::make_shared<BS::thread_pool>(1);
|
|
||||||
|
|
||||||
// Load files to initialize metadata
|
// Load files to initialize metadata
|
||||||
for (int fileNum = 0; fileNum < MaxFiles; fileNum++) {
|
for (int fileNum = 0; fileNum < MaxFiles; fileNum++) {
|
||||||
@ -869,6 +879,32 @@ void SaveManager::InitFileMaxed() {
|
|||||||
gSaveContext.sceneFlags[5].swch = 0x40000000;
|
gSaveContext.sceneFlags[5].swch = 0x40000000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(__WIIU__) || defined(__SWITCH__)
|
||||||
|
// std::filesystem::copy_file doesn't work properly with the Wii U's toolchain atm
|
||||||
|
int copy_file(const char* src, const char* dst) {
|
||||||
|
alignas(0x40) uint8_t buf[4096];
|
||||||
|
FILE* r = fopen(src, "r");
|
||||||
|
if (!r) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
FILE* w = fopen(dst, "w");
|
||||||
|
if (!w) {
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t res;
|
||||||
|
while ((res = fread(buf, 1, sizeof(buf), r)) > 0) {
|
||||||
|
if (fwrite(buf, 1, res, w) != res) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(r);
|
||||||
|
fclose(w);
|
||||||
|
return res >= 0 ? 0 : res;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// Threaded SaveFile takes copy of gSaveContext for local unmodified storage
|
// Threaded SaveFile takes copy of gSaveContext for local unmodified storage
|
||||||
|
|
||||||
void SaveManager::SaveFileThreaded(int fileNum, SaveContext* saveContext, int sectionID) {
|
void SaveManager::SaveFileThreaded(int fileNum, SaveContext* saveContext, int sectionID) {
|
||||||
@ -910,19 +946,42 @@ void SaveManager::SaveFileThreaded(int fileNum, SaveContext* saveContext, int se
|
|||||||
svi.func(saveContext, sectionID, false);
|
svi.func(saveContext, sectionID, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::filesystem::path fileName = GetFileName(fileNum);
|
||||||
|
std::filesystem::path tempFile = GetFileTempName(fileNum);
|
||||||
|
|
||||||
|
if (std::filesystem::exists(tempFile)) {
|
||||||
|
std::filesystem::remove(tempFile);
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(__SWITCH__) || defined(__WIIU__)
|
#if defined(__SWITCH__) || defined(__WIIU__)
|
||||||
FILE* w = fopen(GetFileName(fileNum).c_str(), "w");
|
FILE* w = fopen(tempFile.c_str(), "w");
|
||||||
std::string json_string = saveBlock.dump(4);
|
std::string json_string = saveBlock.dump(4);
|
||||||
fwrite(json_string.c_str(), sizeof(char), json_string.length(), w);
|
fwrite(json_string.c_str(), sizeof(char), json_string.length(), w);
|
||||||
fclose(w);
|
fclose(w);
|
||||||
#else
|
#else
|
||||||
std::ofstream output(GetFileName(fileNum));
|
std::ofstream output(tempFile);
|
||||||
output << std::setw(4) << saveBlock << std::endl;
|
output << std::setw(4) << saveBlock << std::endl;
|
||||||
|
output.close();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (std::filesystem::exists(fileName)) {
|
||||||
|
std::filesystem::remove(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(__SWITCH__) || defined(__WIIU__)
|
||||||
|
copy_file(tempFile.c_str(), fileName.c_str());
|
||||||
|
#else
|
||||||
|
std::filesystem::copy_file(tempFile, fileName);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (std::filesystem::exists(tempFile)) {
|
||||||
|
std::filesystem::remove(tempFile);
|
||||||
|
}
|
||||||
|
|
||||||
delete saveContext;
|
delete saveContext;
|
||||||
InitMeta(fileNum);
|
InitMeta(fileNum);
|
||||||
GameInteractor::Instance->ExecuteHooks<GameInteractor::OnSaveFile>(fileNum);
|
GameInteractor::Instance->ExecuteHooks<GameInteractor::OnSaveFile>(fileNum);
|
||||||
|
SPDLOG_INFO("Save File Finish - fileNum: {}", fileNum);
|
||||||
}
|
}
|
||||||
|
|
||||||
// SaveSection creates a copy of gSaveContext to prevent mid-save data modification, and passes its reference to SaveFileThreaded
|
// SaveSection creates a copy of gSaveContext to prevent mid-save data modification, and passes its reference to SaveFileThreaded
|
||||||
@ -2105,32 +2164,6 @@ void SaveManager::LoadStruct(const std::string& name, LoadStructFunc func) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(__WIIU__) || defined(__SWITCH__)
|
|
||||||
// std::filesystem::copy_file doesn't work properly with the Wii U's toolchain atm
|
|
||||||
int copy_file(const char* src, const char* dst) {
|
|
||||||
alignas(0x40) uint8_t buf[4096];
|
|
||||||
FILE* r = fopen(src, "r");
|
|
||||||
if (!r) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
FILE* w = fopen(dst, "w");
|
|
||||||
if (!w) {
|
|
||||||
return -2;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t res;
|
|
||||||
while ((res = fread(buf, 1, sizeof(buf), r)) > 0) {
|
|
||||||
if (fwrite(buf, 1, res, w) != res) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(r);
|
|
||||||
fclose(w);
|
|
||||||
return res >= 0 ? 0 : res;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void SaveManager::CopyZeldaFile(int from, int to) {
|
void SaveManager::CopyZeldaFile(int from, int to) {
|
||||||
assert(std::filesystem::exists(GetFileName(from)));
|
assert(std::filesystem::exists(GetFileName(from)));
|
||||||
DeleteZeldaFile(to);
|
DeleteZeldaFile(to);
|
||||||
|
@ -142,6 +142,7 @@ class SaveManager {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
std::filesystem::path GetFileName(int fileNum);
|
std::filesystem::path GetFileName(int fileNum);
|
||||||
|
std::filesystem::path GetFileTempName(int fileNum);
|
||||||
nlohmann::json saveBlock;
|
nlohmann::json saveBlock;
|
||||||
|
|
||||||
void ConvertFromUnversioned();
|
void ConvertFromUnversioned();
|
||||||
|
@ -532,6 +532,8 @@ void DrawEnhancementsMenu() {
|
|||||||
" - Small keys: Small silver chest\n"
|
" - Small keys: Small silver chest\n"
|
||||||
" - Boss keys: Vanilla size and texture\n"
|
" - Boss keys: Vanilla size and texture\n"
|
||||||
" - Skulltula Tokens: Small skulltula chest\n"
|
" - Skulltula Tokens: Small skulltula chest\n"
|
||||||
|
"\n"
|
||||||
|
"NOTE: Textures will not apply if you are using a mod pack with a custom chest model."
|
||||||
);
|
);
|
||||||
if (CVarGetInteger("gChestSizeAndTextureMatchesContents", CSMC_DISABLED) != CSMC_DISABLED) {
|
if (CVarGetInteger("gChestSizeAndTextureMatchesContents", CSMC_DISABLED) != CSMC_DISABLED) {
|
||||||
UIWidgets::PaddedEnhancementCheckbox("Chests of Agony", "gChestSizeDependsStoneOfAgony", true, false);
|
UIWidgets::PaddedEnhancementCheckbox("Chests of Agony", "gChestSizeDependsStoneOfAgony", true, false);
|
||||||
@ -1061,6 +1063,8 @@ void DrawEnhancementsMenu() {
|
|||||||
UIWidgets::Tooltip("Fixes the bushes to drop items correctly rather than spawning undefined items.");
|
UIWidgets::Tooltip("Fixes the bushes to drop items correctly rather than spawning undefined items.");
|
||||||
UIWidgets::PaddedEnhancementCheckbox("Fix falling from vine edges", "gFixVineFall", true, false);
|
UIWidgets::PaddedEnhancementCheckbox("Fix falling from vine edges", "gFixVineFall", true, false);
|
||||||
UIWidgets::Tooltip("Prevents immediately falling off climbable surfaces if climbing on the edges.");
|
UIWidgets::Tooltip("Prevents immediately falling off climbable surfaces if climbing on the edges.");
|
||||||
|
UIWidgets::PaddedEnhancementCheckbox("Fix Link's eyes open while sleeping", "gFixEyesOpenWhileSleeping", true, false);
|
||||||
|
UIWidgets::Tooltip("Fixes Link's eyes being open in the opening cutscene when he is supposed to be sleeping.");
|
||||||
|
|
||||||
ImGui::EndMenu();
|
ImGui::EndMenu();
|
||||||
}
|
}
|
||||||
|
@ -103,38 +103,42 @@ void SkeletonFactoryV0::ParseFileXML(tinyxml2::XMLElement* reader, std::shared_p
|
|||||||
{
|
{
|
||||||
std::shared_ptr<Skeleton> skel = std::static_pointer_cast<Skeleton>(resource);
|
std::shared_ptr<Skeleton> skel = std::static_pointer_cast<Skeleton>(resource);
|
||||||
|
|
||||||
std::string skeletonType = reader->Attribute("Type");
|
skel->type = SkeletonType::Flex; // Default to Flex for legacy reasons
|
||||||
// std::string skeletonLimbType = reader->Attribute("LimbType");
|
if (reader->FindAttribute("Type")) {
|
||||||
int numLimbs = reader->IntAttribute("LimbCount");
|
std::string skeletonType = reader->Attribute("Type");
|
||||||
int numDLs = reader->IntAttribute("DisplayListCount");
|
|
||||||
|
|
||||||
if (skeletonType == "Flex") {
|
if (skeletonType == "Flex") {
|
||||||
skel->type = SkeletonType::Flex;
|
skel->type = SkeletonType::Flex;
|
||||||
} else if (skeletonType == "Curve") {
|
} else if (skeletonType == "Curve") {
|
||||||
skel->type = SkeletonType::Curve;
|
skel->type = SkeletonType::Curve;
|
||||||
} else if (skeletonType == "Normal") {
|
} else if (skeletonType == "Normal") {
|
||||||
skel->type = SkeletonType::Normal;
|
skel->type = SkeletonType::Normal;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
skel->type = SkeletonType::Flex;
|
skel->limbType = LimbType::LOD; // Default to LOD for legacy reasons
|
||||||
skel->limbType = LimbType::LOD;
|
if (reader->FindAttribute("LimbType")) {
|
||||||
|
std::string skeletonLimbType = reader->Attribute("LimbType");
|
||||||
|
|
||||||
// if (skeletonLimbType == "Standard")
|
if (skeletonLimbType == "Standard") {
|
||||||
// skel->limbType = LimbType::Standard;
|
skel->limbType = LimbType::Standard;
|
||||||
// else if (skeletonLimbType == "LOD")
|
} else if (skeletonLimbType == "LOD") {
|
||||||
// skel->limbType = LimbType::LOD;
|
skel->limbType = LimbType::LOD;
|
||||||
// else if (skeletonLimbType == "Curve")
|
} else if (skeletonLimbType == "Curve") {
|
||||||
// skel->limbType = LimbType::Curve;
|
skel->limbType = LimbType::Curve;
|
||||||
// else if (skeletonLimbType == "Skin")
|
} else if (skeletonLimbType == "Skin") {
|
||||||
// skel->limbType = LimbType::Skin;
|
skel->limbType = LimbType::Skin;
|
||||||
// else if (skeletonLimbType == "Legacy")
|
} else if (skeletonLimbType == "Legacy") {
|
||||||
// Sskel->limbType = LimbType::Legacy;
|
skel->limbType = LimbType::Legacy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
skel->limbCount = reader->IntAttribute("LimbCount");
|
||||||
|
skel->dListCount = reader->IntAttribute("DisplayListCount");
|
||||||
|
|
||||||
auto child = reader->FirstChildElement();
|
auto child = reader->FirstChildElement();
|
||||||
|
|
||||||
skel->limbCount = numLimbs;
|
|
||||||
skel->dListCount = numDLs;
|
|
||||||
|
|
||||||
while (child != nullptr) {
|
while (child != nullptr) {
|
||||||
std::string childName = child->Name();
|
std::string childName = child->Name();
|
||||||
|
|
||||||
|
@ -204,6 +204,17 @@ u8 Inventory_DeleteEquipment(PlayState* play, s16 equipment) {
|
|||||||
|
|
||||||
if (equipment == EQUIP_TYPE_TUNIC) {
|
if (equipment == EQUIP_TYPE_TUNIC) {
|
||||||
gSaveContext.equips.equipment |= EQUIP_VALUE_TUNIC_KOKIRI << (EQUIP_TYPE_TUNIC * 4);
|
gSaveContext.equips.equipment |= EQUIP_VALUE_TUNIC_KOKIRI << (EQUIP_TYPE_TUNIC * 4);
|
||||||
|
// non-vanilla: remove goron and zora tunics from item buttons if assignable tunics is on
|
||||||
|
if (CVarGetInteger("gAssignableTunicsAndBoots", 0) && equipValue != EQUIP_VALUE_TUNIC_KOKIRI) {
|
||||||
|
ItemID item = (equipValue == EQUIP_VALUE_TUNIC_GORON ? ITEM_TUNIC_GORON : ITEM_TUNIC_ZORA);
|
||||||
|
for (int i = 1; i < ARRAY_COUNT(gSaveContext.equips.buttonItems); i++) {
|
||||||
|
if (gSaveContext.equips.buttonItems[i] == item) {
|
||||||
|
gSaveContext.equips.buttonItems[i] = ITEM_NONE;
|
||||||
|
gSaveContext.equips.cButtonSlots[i - 1] = SLOT_NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// end non-vanilla
|
||||||
}
|
}
|
||||||
|
|
||||||
if (equipment == EQUIP_TYPE_SWORD) {
|
if (equipment == EQUIP_TYPE_SWORD) {
|
||||||
|
@ -1469,6 +1469,7 @@ void Inventory_SwapAgeEquipment(void) {
|
|||||||
gSaveContext.equips.buttonItems[0] = ITEM_SWORD_MASTER;
|
gSaveContext.equips.buttonItems[0] = ITEM_SWORD_MASTER;
|
||||||
} else {
|
} else {
|
||||||
gSaveContext.equips.buttonItems[0] = ITEM_NONE;
|
gSaveContext.equips.buttonItems[0] = ITEM_NONE;
|
||||||
|
Flags_SetInfTable(INFTABLE_SWORDLESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gSaveContext.inventory.items[SLOT_NUT] != ITEM_NONE) {
|
if (gSaveContext.inventory.items[SLOT_NUT] != ITEM_NONE) {
|
||||||
|
@ -33,6 +33,7 @@ u64 D_801614D0[0xA00];
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
PlayState* gPlayState;
|
PlayState* gPlayState;
|
||||||
|
s16 firstInit = 0;
|
||||||
|
|
||||||
s16 gEnPartnerId;
|
s16 gEnPartnerId;
|
||||||
|
|
||||||
@ -490,6 +491,12 @@ void Play_Init(GameState* thisx) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Properly initialize the frame counter so it doesn't use garbage data
|
||||||
|
if (!firstInit) {
|
||||||
|
play->gameplayFrames = 0;
|
||||||
|
firstInit = 1;
|
||||||
|
}
|
||||||
|
|
||||||
// Invalid entrance, so immediately exit the game to opening title
|
// Invalid entrance, so immediately exit the game to opening title
|
||||||
if (gSaveContext.entranceIndex == -1) {
|
if (gSaveContext.entranceIndex == -1) {
|
||||||
gSaveContext.entranceIndex = 0;
|
gSaveContext.entranceIndex = 0;
|
||||||
@ -2329,8 +2336,28 @@ void Play_PerformSave(PlayState* play) {
|
|||||||
if (play != NULL && gSaveContext.fileNum != 0xFF) {
|
if (play != NULL && gSaveContext.fileNum != 0xFF) {
|
||||||
Play_SaveSceneFlags(play);
|
Play_SaveSceneFlags(play);
|
||||||
gSaveContext.savedSceneNum = play->sceneNum;
|
gSaveContext.savedSceneNum = play->sceneNum;
|
||||||
|
|
||||||
|
// Track values from temp B
|
||||||
|
uint8_t prevB = gSaveContext.equips.buttonItems[0];
|
||||||
|
uint8_t prevStatus = gSaveContext.buttonStatus[0];
|
||||||
|
|
||||||
|
// Replicate the B button restore from minigames/epona that kaleido does
|
||||||
|
if (gSaveContext.equips.buttonItems[0] == ITEM_SLINGSHOT ||
|
||||||
|
gSaveContext.equips.buttonItems[0] == ITEM_BOW ||
|
||||||
|
gSaveContext.equips.buttonItems[0] == ITEM_BOMBCHU ||
|
||||||
|
gSaveContext.equips.buttonItems[0] == ITEM_FISHING_POLE ||
|
||||||
|
(gSaveContext.equips.buttonItems[0] == ITEM_NONE && !Flags_GetInfTable(INFTABLE_SWORDLESS))) {
|
||||||
|
|
||||||
|
gSaveContext.equips.buttonItems[0] = gSaveContext.buttonStatus[0];
|
||||||
|
Interface_RandoRestoreSwordless();
|
||||||
|
}
|
||||||
|
|
||||||
Save_SaveFile();
|
Save_SaveFile();
|
||||||
|
|
||||||
|
// Restore temp B values back
|
||||||
|
gSaveContext.equips.buttonItems[0] = prevB;
|
||||||
|
gSaveContext.buttonStatus[0] = prevStatus;
|
||||||
|
|
||||||
uint8_t triforceHuntCompleted =
|
uint8_t triforceHuntCompleted =
|
||||||
IS_RANDO &&
|
IS_RANDO &&
|
||||||
gSaveContext.triforcePiecesCollected == Randomizer_GetSettingValue(RSK_TRIFORCE_HUNT_PIECES_REQUIRED) &&
|
gSaveContext.triforcePiecesCollected == Randomizer_GetSettingValue(RSK_TRIFORCE_HUNT_PIECES_REQUIRED) &&
|
||||||
|
@ -88,6 +88,7 @@ Gfx gKeyTreasureChestChestFrontDL[128] = {0};
|
|||||||
Gfx gChristmasRedTreasureChestChestFrontDL[128] = {0};
|
Gfx gChristmasRedTreasureChestChestFrontDL[128] = {0};
|
||||||
Gfx gChristmasGreenTreasureChestChestFrontDL[128] = {0};
|
Gfx gChristmasGreenTreasureChestChestFrontDL[128] = {0};
|
||||||
u8 hasCreatedRandoChestTextures = 0;
|
u8 hasCreatedRandoChestTextures = 0;
|
||||||
|
u8 hasCustomChestDLs = 0;
|
||||||
u8 hasChristmasChestTexturesAvailable = 0;
|
u8 hasChristmasChestTexturesAvailable = 0;
|
||||||
|
|
||||||
void EnBox_SetupAction(EnBox* this, EnBoxActionFunc actionFunc) {
|
void EnBox_SetupAction(EnBox* this, EnBoxActionFunc actionFunc) {
|
||||||
@ -690,7 +691,7 @@ void EnBox_UpdateSizeAndTexture(EnBox* this, PlayState* play) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Change texture
|
// Change texture
|
||||||
if (!isVanilla && (csmc == CSMC_BOTH || csmc == CSMC_TEXTURE)) {
|
if (!isVanilla && hasCreatedRandoChestTextures && !hasCustomChestDLs && (csmc == CSMC_BOTH || csmc == CSMC_TEXTURE)) {
|
||||||
switch (getItemCategory) {
|
switch (getItemCategory) {
|
||||||
case ITEM_CATEGORY_MAJOR:
|
case ITEM_CATEGORY_MAJOR:
|
||||||
this->boxBodyDL = gGoldTreasureChestChestFrontDL;
|
this->boxBodyDL = gGoldTreasureChestChestFrontDL;
|
||||||
@ -725,7 +726,7 @@ void EnBox_UpdateSizeAndTexture(EnBox* this, PlayState* play) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CVarGetInteger("gLetItSnow", 0) && hasChristmasChestTexturesAvailable) {
|
if (CVarGetInteger("gLetItSnow", 0) && hasChristmasChestTexturesAvailable && hasCreatedRandoChestTextures && !hasCustomChestDLs) {
|
||||||
if (this->dyna.actor.scale.x == 0.01f) {
|
if (this->dyna.actor.scale.x == 0.01f) {
|
||||||
this->boxBodyDL = gChristmasRedTreasureChestChestFrontDL;
|
this->boxBodyDL = gChristmasRedTreasureChestChestFrontDL;
|
||||||
this->boxLidDL = gChristmasRedTreasureChestChestSideAndLidDL;
|
this->boxLidDL = gChristmasRedTreasureChestChestSideAndLidDL;
|
||||||
@ -767,7 +768,18 @@ void EnBox_UpdateSizeAndTexture(EnBox* this, PlayState* play) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void EnBox_CreateExtraChestTextures() {
|
void EnBox_CreateExtraChestTextures() {
|
||||||
|
// Don't patch textures for custom chest models, as they do not import textures the exact same way as vanilla chests
|
||||||
|
// OTRTODO: Make it so model packs can provide a unique DL per chest type, instead of us copying the brown chest and attempting to patch
|
||||||
|
if (ResourceMgr_FileIsCustomByName(gTreasureChestChestFrontDL) ||
|
||||||
|
ResourceMgr_FileIsCustomByName(gTreasureChestChestSideAndLidDL)) {
|
||||||
|
hasCustomChestDLs = 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
hasCustomChestDLs = 0;
|
||||||
|
|
||||||
if (hasCreatedRandoChestTextures) return;
|
if (hasCreatedRandoChestTextures) return;
|
||||||
|
|
||||||
Gfx gTreasureChestChestTextures[] = {
|
Gfx gTreasureChestChestTextures[] = {
|
||||||
gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, gSkullTreasureChestFrontTex),
|
gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, gSkullTreasureChestFrontTex),
|
||||||
gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, gSkullTreasureChestSideAndTopTex),
|
gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, gSkullTreasureChestSideAndTopTex),
|
||||||
|
@ -15169,6 +15169,10 @@ void func_80852C50(PlayState* play, Player* this, CsCmdActorAction* arg2) {
|
|||||||
|
|
||||||
sp24 = D_808547C4[this->unk_446];
|
sp24 = D_808547C4[this->unk_446];
|
||||||
func_80852B4C(play, this, linkCsAction, &D_80854E50[ABS(sp24)]);
|
func_80852B4C(play, this, linkCsAction, &D_80854E50[ABS(sp24)]);
|
||||||
|
|
||||||
|
if (CVarGetInteger("gFixEyesOpenWhileSleeping", 0) && (play->csCtx.linkAction->action == 28 || play->csCtx.linkAction->action == 29)) {
|
||||||
|
this->skelAnime.jointTable[22].x = 8;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void func_80852E14(Player* this, PlayState* play) {
|
void func_80852E14(Player* this, PlayState* play) {
|
||||||
|
@ -4290,6 +4290,8 @@ void KaleidoScope_Update(PlayState* play)
|
|||||||
if (IS_RANDO && Randomizer_GetSettingValue(RSK_SHUFFLE_ENTRANCES)) {
|
if (IS_RANDO && Randomizer_GetSettingValue(RSK_SHUFFLE_ENTRANCES)) {
|
||||||
Grotto_ForceGrottoReturn();
|
Grotto_ForceGrottoReturn();
|
||||||
}
|
}
|
||||||
|
// Reset frame counter to prevent autosave on respawn
|
||||||
|
play->gameplayFrames = 0;
|
||||||
gSaveContext.nextTransitionType = 2;
|
gSaveContext.nextTransitionType = 2;
|
||||||
gSaveContext.health = CVarGetInteger("gFullHealthSpawn", 0) ? gSaveContext.healthCapacity : 0x30;
|
gSaveContext.health = CVarGetInteger("gFullHealthSpawn", 0) ? gSaveContext.healthCapacity : 0x30;
|
||||||
Audio_QueueSeqCmd(0xF << 28 | SEQ_PLAYER_BGM_MAIN << 24 | 0xA);
|
Audio_QueueSeqCmd(0xF << 28 | SEQ_PLAYER_BGM_MAIN << 24 | 0xA);
|
||||||
|
Loading…
Reference in New Issue
Block a user