diff --git a/CMakeLists.txt b/CMakeLists.txt index 7333da8d8..ef00ae8f5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ set(CMAKE_C_STANDARD 23 CACHE STRING "The C standard to use") set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15" CACHE STRING "Minimum OS X deployment version") -project(Ship VERSION 9.0.2 LANGUAGES C CXX) +project(Ship VERSION 9.0.5 LANGUAGES C CXX) include(CMake/soh-cvars.cmake) include(CMake/lus-cvars.cmake) @@ -155,6 +155,9 @@ set(GFX_DEBUG_DISASSEMBLER ON) set(GBI_UCODE F3DEX_GBI_2) list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake") +# Enable MPQ and OTR support +set(INCLUDE_MPQ_SUPPORT ON) + ################################################################################ # Set CONTROLLERBUTTONS_T ################################################################################ @@ -165,6 +168,7 @@ add_compile_definitions(CONTROLLERBUTTONS_T=uint32_t) ################################################################################ add_subdirectory(libultraship ${CMAKE_BINARY_DIR}/libultraship) target_compile_options(libultraship PRIVATE "${WARNING_OVERRIDE}") +target_compile_definitions(libultraship PUBLIC INCLUDE_MPQ_SUPPORT) add_subdirectory(ZAPDTR/ZAPD ${CMAKE_BINARY_DIR}/ZAPD) add_subdirectory(OTRExporter) add_subdirectory(soh) diff --git a/libultraship b/libultraship index 6a3f6cd32..7f737f8be 160000 --- a/libultraship +++ b/libultraship @@ -1 +1 @@ -Subproject commit 6a3f6cd327b99f617b623e5b9a3afeae460aac2b +Subproject commit 7f737f8be9580980f5a1fe7784d6e1045f0309da diff --git a/soh/soh/CrashHandlerExt.cpp b/soh/soh/CrashHandlerExt.cpp index cc9c7b1ee..3ca821460 100644 --- a/soh/soh/CrashHandlerExt.cpp +++ b/soh/soh/CrashHandlerExt.cpp @@ -19,7 +19,7 @@ static std::array sCatToStrArray{ "SWITCH", "BG", "PLAYER", "EXPLOSIVE", "NPC", "ENEMY", "PROP", "ITEMACTION", "MISC", "BOSS", "DOOR", "CHEST", }; -#define DEFINE_SCENE(_1, _2, enumName, _4, _5, _6) #enumName +#define DEFINE_SCENE(_1, _2, enumName, _4, _5, _6) #enumName, static std::array sSceneIdToStrArray{ #include "tables/scene_table.h" diff --git a/soh/soh/Enhancements/BonkDamage.cpp b/soh/soh/Enhancements/BonkDamage.cpp new file mode 100644 index 000000000..e11f46b78 --- /dev/null +++ b/soh/soh/Enhancements/BonkDamage.cpp @@ -0,0 +1,51 @@ +#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h" +#include "soh/ShipInit.hpp" +#include "./enhancementTypes.h" + +extern "C" { +#include "functions.h" +#include "macros.h" +extern PlayState* gPlayState; +extern SaveContext gSaveContext; +} + +void RegisterBonkDamage() { + COND_HOOK(OnPlayerBonk, CVarGetInteger(CVAR_ENHANCEMENT("BonkDamageMult"), BONK_DAMAGE_NONE) != BONK_DAMAGE_NONE, + [] { + uint16_t bonkDamage = 0; + switch (CVarGetInteger(CVAR_ENHANCEMENT("BonkDamageMult"), BONK_DAMAGE_NONE)) { + case BONK_DAMAGE_NONE: + return; + case BONK_DAMAGE_OHKO: + gSaveContext.health = 0; + return; + case BONK_DAMAGE_QUARTER_HEART: + bonkDamage = 4; + break; + case BONK_DAMAGE_HALF_HEART: + bonkDamage = 8; + break; + case BONK_DAMAGE_1_HEART: + bonkDamage = 16; + break; + case BONK_DAMAGE_2_HEARTS: + bonkDamage = 32; + break; + case BONK_DAMAGE_4_HEARTS: + bonkDamage = 64; + break; + case BONK_DAMAGE_8_HEARTS: + bonkDamage = 128; + break; + default: + break; + } + + Health_ChangeBy(gPlayState, -bonkDamage); + // Set invincibility to make Link flash red as a visual damage indicator. + Player* player = GET_PLAYER(gPlayState); + player->invincibilityTimer = 28; + }); +} + +static RegisterShipInitFunc registerBonkDamage(RegisterBonkDamage, { CVAR_ENHANCEMENT("BonkDamageMult") }); diff --git a/soh/soh/Enhancements/audio/AudioCollection.cpp b/soh/soh/Enhancements/audio/AudioCollection.cpp index d3f69dad8..a30d3f086 100644 --- a/soh/soh/Enhancements/audio/AudioCollection.cpp +++ b/soh/soh/Enhancements/audio/AudioCollection.cpp @@ -2,6 +2,7 @@ #include "sequence.h" #include "sfx.h" #include "soh/cvar_prefixes.h" +#include "soh/Notification/Notification.h" #include #include #include @@ -458,3 +459,11 @@ extern "C" bool AudioCollection_HasSequenceNum(uint16_t seqId) { extern "C" size_t AudioCollection_SequenceMapSize() { return AudioCollection::Instance->SequenceMapSize(); } + +extern "C" void AudioCollection_EmitSongNameNotification(s32 seqId) { + const char* sequenceName = AudioCollection_GetSequenceName(seqId); + if (sequenceName != NULL) { + Notification::Emit({ .message = "Currently playing: " + std::string(sequenceName), + .remainingTime = (float)CVarGetInteger(CVAR_AUDIO("SeqNameOverlayDuration"), 5) }); + } +} \ No newline at end of file diff --git a/soh/soh/Enhancements/audio/AudioCollection.h b/soh/soh/Enhancements/audio/AudioCollection.h index 2cdb02e21..51a6902cf 100644 --- a/soh/soh/Enhancements/audio/AudioCollection.h +++ b/soh/soh/Enhancements/audio/AudioCollection.h @@ -73,4 +73,5 @@ void AudioCollection_AddToCollection(char* otrPath, uint16_t seqNum); const char* AudioCollection_GetSequenceName(uint16_t seqId); bool AudioCollection_HasSequenceNum(uint16_t seqId); size_t AudioCollection_SequenceMapSize(); +void AudioCollection_EmitSongNameNotification(s32 seqId); #endif \ No newline at end of file diff --git a/soh/soh/Enhancements/audio/AudioEditor.cpp b/soh/soh/Enhancements/audio/AudioEditor.cpp index 4cf1f389d..6660bee7d 100644 --- a/soh/soh/Enhancements/audio/AudioEditor.cpp +++ b/soh/soh/Enhancements/audio/AudioEditor.cpp @@ -298,9 +298,12 @@ void Draw_SfxTab(const std::string& tabId, SeqType type, const std::string& tabN ImGui::TableNextRow(); ImGui::TableNextColumn(); - ImGui::TextColored( - UIWidgets::ColorValues.at(isCurrentlyPlaying ? UIWidgets::Colors::Yellow : UIWidgets::Colors::White), "%s", - seqData.label.c_str()); + if (isCurrentlyPlaying) { + ImGui::TextColored(UIWidgets::ColorValues.at(UIWidgets::Colors::Yellow), "%s %s", ICON_FA_PLAY, + seqData.label.c_str()); + } else { + ImGui::Text("%s", seqData.label.c_str()); + } ImGui::TableNextColumn(); ImGui::PushItemWidth(-FLT_MIN); const int initialValue = map.contains(currentValue) ? currentValue : defaultValue; diff --git a/soh/soh/Enhancements/enhancementTypes.h b/soh/soh/Enhancements/enhancementTypes.h index c1b91cffa..bd025115b 100644 --- a/soh/soh/Enhancements/enhancementTypes.h +++ b/soh/soh/Enhancements/enhancementTypes.h @@ -112,7 +112,9 @@ typedef enum { typedef enum { TIME_TRAVEL_DISABLED, TIME_TRAVEL_OOT, + TIME_TRAVEL_OOT_MS, TIME_TRAVEL_ANY, + TIME_TRAVEL_ANY_MS } TimeTravelType; typedef enum { diff --git a/soh/soh/Enhancements/game-interactor/GameInteractionEffect.cpp b/soh/soh/Enhancements/game-interactor/GameInteractionEffect.cpp index 03667dd86..76e026206 100644 --- a/soh/soh/Enhancements/game-interactor/GameInteractionEffect.cpp +++ b/soh/soh/Enhancements/game-interactor/GameInteractionEffect.cpp @@ -50,7 +50,7 @@ namespace GameInteractionEffect { // MARK: - Flags GameInteractionEffectQueryResult SetSceneFlag::CanBeApplied() { - if (!GameInteractor::IsSaveLoaded()) { + if (!GameInteractor::IsSaveLoaded(true)) { return GameInteractionEffectQueryResult::TemporarilyNotPossible; } @@ -62,7 +62,7 @@ void SetSceneFlag::_Apply() { } GameInteractionEffectQueryResult UnsetSceneFlag::CanBeApplied() { - if (!GameInteractor::IsSaveLoaded()) { + if (!GameInteractor::IsSaveLoaded(true)) { return GameInteractionEffectQueryResult::TemporarilyNotPossible; } @@ -74,7 +74,7 @@ void UnsetSceneFlag::_Apply() { } GameInteractionEffectQueryResult SetFlag::CanBeApplied() { - if (!GameInteractor::IsSaveLoaded()) { + if (!GameInteractor::IsSaveLoaded(true)) { return GameInteractionEffectQueryResult::TemporarilyNotPossible; } @@ -86,7 +86,7 @@ void SetFlag::_Apply() { } GameInteractionEffectQueryResult UnsetFlag::CanBeApplied() { - if (!GameInteractor::IsSaveLoaded()) { + if (!GameInteractor::IsSaveLoaded(true)) { return GameInteractionEffectQueryResult::TemporarilyNotPossible; } @@ -99,7 +99,7 @@ void UnsetFlag::_Apply() { // MARK: - ModifyHeartContainers GameInteractionEffectQueryResult ModifyHeartContainers::CanBeApplied() { - if (!GameInteractor::IsSaveLoaded()) { + if (!GameInteractor::IsSaveLoaded(true)) { return GameInteractionEffectQueryResult::TemporarilyNotPossible; } else if ((parameters[0] > 0 && (gSaveContext.healthCapacity + (parameters[0] * 0x10) > 0x140)) || (parameters[0] < 0 && (gSaveContext.healthCapacity + (parameters[0] * 0x10) < 0x10))) { @@ -115,7 +115,7 @@ void ModifyHeartContainers::_Apply() { // MARK: - FillMagic GameInteractionEffectQueryResult FillMagic::CanBeApplied() { - if (!GameInteractor::IsSaveLoaded()) { + if (!GameInteractor::IsSaveLoaded(true)) { return GameInteractionEffectQueryResult::TemporarilyNotPossible; } else if (!gSaveContext.isMagicAcquired || gSaveContext.magic >= ((gSaveContext.isDoubleMagicAcquired + 1) * 48)) { return GameInteractionEffectQueryResult::NotPossible; @@ -129,7 +129,7 @@ void FillMagic::_Apply() { // MARK: - EmptyMagic GameInteractionEffectQueryResult EmptyMagic::CanBeApplied() { - if (!GameInteractor::IsSaveLoaded()) { + if (!GameInteractor::IsSaveLoaded(true)) { return GameInteractionEffectQueryResult::TemporarilyNotPossible; } else if (!gSaveContext.isMagicAcquired || gSaveContext.magic <= 0) { return GameInteractionEffectQueryResult::NotPossible; @@ -143,7 +143,7 @@ void EmptyMagic::_Apply() { // MARK: - ModifyRupees GameInteractionEffectQueryResult ModifyRupees::CanBeApplied() { - if (!GameInteractor::IsSaveLoaded()) { + if (!GameInteractor::IsSaveLoaded(true)) { return GameInteractionEffectQueryResult::TemporarilyNotPossible; } else if ((parameters[0] < 0 && gSaveContext.rupees <= 0) || (parameters[0] > 0 && gSaveContext.rupees >= CUR_CAPACITY(UPG_WALLET))) { @@ -158,7 +158,7 @@ void ModifyRupees::_Apply() { // MARK: - NoUI GameInteractionEffectQueryResult NoUI::CanBeApplied() { - if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused()) { + if (!GameInteractor::IsSaveLoaded(true) || GameInteractor::IsGameplayPaused()) { return GameInteractionEffectQueryResult::TemporarilyNotPossible; } else { return GameInteractionEffectQueryResult::Possible; @@ -173,7 +173,7 @@ void NoUI::_Remove() { // MARK: - ModifyGravity GameInteractionEffectQueryResult ModifyGravity::CanBeApplied() { - if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused()) { + if (!GameInteractor::IsSaveLoaded(true) || GameInteractor::IsGameplayPaused()) { return GameInteractionEffectQueryResult::TemporarilyNotPossible; } else { return GameInteractionEffectQueryResult::Possible; @@ -188,7 +188,7 @@ void ModifyGravity::_Remove() { // MARK: - ModifyHealth GameInteractionEffectQueryResult ModifyHealth::CanBeApplied() { - if (!GameInteractor::IsSaveLoaded()) { + if (!GameInteractor::IsSaveLoaded(true)) { return GameInteractionEffectQueryResult::TemporarilyNotPossible; } else if ((parameters[0] > 0 && gSaveContext.health == gSaveContext.healthCapacity) || (parameters[0] < 0 && (gSaveContext.health + (16 * parameters[0]) <= 0))) { @@ -204,7 +204,7 @@ void ModifyHealth::_Apply() { // MARK: - SetPlayerHealth GameInteractionEffectQueryResult SetPlayerHealth::CanBeApplied() { Player* player = GET_PLAYER(gPlayState); - if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused()) { + if (!GameInteractor::IsSaveLoaded(true) || GameInteractor::IsGameplayPaused()) { return GameInteractionEffectQueryResult::TemporarilyNotPossible; } else { return GameInteractionEffectQueryResult::Possible; @@ -217,7 +217,7 @@ void SetPlayerHealth::_Apply() { // MARK: - FreezePlayer GameInteractionEffectQueryResult FreezePlayer::CanBeApplied() { Player* player = GET_PLAYER(gPlayState); - if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused() || !PlayerGrounded(player)) { + if (!GameInteractor::IsSaveLoaded(true) || GameInteractor::IsGameplayPaused() || !PlayerGrounded(player)) { return GameInteractionEffectQueryResult::TemporarilyNotPossible; } else { return GameInteractionEffectQueryResult::Possible; @@ -230,7 +230,7 @@ void FreezePlayer::_Apply() { // MARK: - BurnPlayer GameInteractionEffectQueryResult BurnPlayer::CanBeApplied() { Player* player = GET_PLAYER(gPlayState); - if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused() || !PlayerGrounded(player)) { + if (!GameInteractor::IsSaveLoaded(true) || GameInteractor::IsGameplayPaused() || !PlayerGrounded(player)) { return GameInteractionEffectQueryResult::TemporarilyNotPossible; } else { return GameInteractionEffectQueryResult::Possible; @@ -243,7 +243,7 @@ void BurnPlayer::_Apply() { // MARK: - ElectrocutePlayer GameInteractionEffectQueryResult ElectrocutePlayer::CanBeApplied() { Player* player = GET_PLAYER(gPlayState); - if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused() || !PlayerGrounded(player)) { + if (!GameInteractor::IsSaveLoaded(true) || GameInteractor::IsGameplayPaused() || !PlayerGrounded(player)) { return GameInteractionEffectQueryResult::TemporarilyNotPossible; } else { return GameInteractionEffectQueryResult::Possible; @@ -256,7 +256,7 @@ void ElectrocutePlayer::_Apply() { // MARK: - KnockbackPlayer GameInteractionEffectQueryResult KnockbackPlayer::CanBeApplied() { Player* player = GET_PLAYER(gPlayState); - if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused() || + if (!GameInteractor::IsSaveLoaded(true) || GameInteractor::IsGameplayPaused() || player->stateFlags2 & PLAYER_STATE2_CRAWLING) { return GameInteractionEffectQueryResult::TemporarilyNotPossible; } else { @@ -269,7 +269,7 @@ void KnockbackPlayer::_Apply() { // MARK: - ModifyLinkSize GameInteractionEffectQueryResult ModifyLinkSize::CanBeApplied() { - if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused()) { + if (!GameInteractor::IsSaveLoaded(true) || GameInteractor::IsGameplayPaused()) { return GameInteractionEffectQueryResult::TemporarilyNotPossible; } else { return GameInteractionEffectQueryResult::Possible; @@ -284,7 +284,7 @@ void ModifyLinkSize::_Remove() { // MARK: - InvisibleLink GameInteractionEffectQueryResult InvisibleLink::CanBeApplied() { - if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused()) { + if (!GameInteractor::IsSaveLoaded(true) || GameInteractor::IsGameplayPaused()) { return GameInteractionEffectQueryResult::TemporarilyNotPossible; } else { return GameInteractionEffectQueryResult::Possible; @@ -299,7 +299,7 @@ void InvisibleLink::_Remove() { // MARK: - PacifistMode GameInteractionEffectQueryResult PacifistMode::CanBeApplied() { - if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused()) { + if (!GameInteractor::IsSaveLoaded(true) || GameInteractor::IsGameplayPaused()) { return GameInteractionEffectQueryResult::TemporarilyNotPossible; } else { return GameInteractionEffectQueryResult::Possible; @@ -314,7 +314,7 @@ void PacifistMode::_Remove() { // MARK: - DisableZTargeting GameInteractionEffectQueryResult DisableZTargeting::CanBeApplied() { - if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused()) { + if (!GameInteractor::IsSaveLoaded(true) || GameInteractor::IsGameplayPaused()) { return GameInteractionEffectQueryResult::TemporarilyNotPossible; } else { return GameInteractionEffectQueryResult::Possible; @@ -329,7 +329,7 @@ void DisableZTargeting::_Remove() { // MARK: - WeatherRainstorm GameInteractionEffectQueryResult WeatherRainstorm::CanBeApplied() { - if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused()) { + if (!GameInteractor::IsSaveLoaded(true) || GameInteractor::IsGameplayPaused()) { return GameInteractionEffectQueryResult::TemporarilyNotPossible; } else { return GameInteractionEffectQueryResult::Possible; @@ -344,7 +344,7 @@ void WeatherRainstorm::_Remove() { // MARK: - ReverseControls GameInteractionEffectQueryResult ReverseControls::CanBeApplied() { - if (!GameInteractor::IsSaveLoaded()) { + if (!GameInteractor::IsSaveLoaded(true)) { return GameInteractionEffectQueryResult::TemporarilyNotPossible; } else { return GameInteractionEffectQueryResult::Possible; @@ -359,7 +359,7 @@ void ReverseControls::_Remove() { // MARK: - ForceEquipBoots GameInteractionEffectQueryResult ForceEquipBoots::CanBeApplied() { - if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused()) { + if (!GameInteractor::IsSaveLoaded(true) || GameInteractor::IsGameplayPaused()) { return GameInteractionEffectQueryResult::TemporarilyNotPossible; } else { return GameInteractionEffectQueryResult::Possible; @@ -374,7 +374,7 @@ void ForceEquipBoots::_Remove() { // MARK: - ModifyMovementSpeedMultiplier GameInteractionEffectQueryResult ModifyMovementSpeedMultiplier::CanBeApplied() { - if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused()) { + if (!GameInteractor::IsSaveLoaded(true) || GameInteractor::IsGameplayPaused()) { return GameInteractionEffectQueryResult::TemporarilyNotPossible; } else { return GameInteractionEffectQueryResult::Possible; @@ -393,7 +393,7 @@ void ModifyMovementSpeedMultiplier::_Remove() { // MARK: - OneHitKO GameInteractionEffectQueryResult OneHitKO::CanBeApplied() { - if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused()) { + if (!GameInteractor::IsSaveLoaded(true) || GameInteractor::IsGameplayPaused()) { return GameInteractionEffectQueryResult::TemporarilyNotPossible; } else { return GameInteractionEffectQueryResult::Possible; @@ -408,7 +408,7 @@ void OneHitKO::_Remove() { // MARK: - ModifyDefenseModifier GameInteractionEffectQueryResult ModifyDefenseModifier::CanBeApplied() { - if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused()) { + if (!GameInteractor::IsSaveLoaded(true) || GameInteractor::IsGameplayPaused()) { return GameInteractionEffectQueryResult::TemporarilyNotPossible; } else { return GameInteractionEffectQueryResult::Possible; @@ -423,7 +423,7 @@ void ModifyDefenseModifier::_Remove() { // MARK: - GiveOrTakeShield GameInteractionEffectQueryResult GiveOrTakeShield::CanBeApplied() { - if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused()) { + if (!GameInteractor::IsSaveLoaded(true) || GameInteractor::IsGameplayPaused()) { return GameInteractionEffectQueryResult::TemporarilyNotPossible; } else if ((parameters[0] > 0 && ((gBitFlags[parameters[0] - ITEM_SHIELD_DEKU] << gEquipShifts[EQUIP_TYPE_SHIELD]) & gSaveContext.inventory.equipment)) || @@ -441,7 +441,7 @@ void GiveOrTakeShield::_Apply() { // MARK: - TeleportPlayer GameInteractionEffectQueryResult TeleportPlayer::CanBeApplied() { - if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused()) { + if (!GameInteractor::IsSaveLoaded(true) || GameInteractor::IsGameplayPaused()) { return GameInteractionEffectQueryResult::TemporarilyNotPossible; } else { return GameInteractionEffectQueryResult::Possible; @@ -453,7 +453,7 @@ void TeleportPlayer::_Apply() { // MARK: - ClearAssignedButtons GameInteractionEffectQueryResult ClearAssignedButtons::CanBeApplied() { - if (!GameInteractor::IsSaveLoaded()) { + if (!GameInteractor::IsSaveLoaded(true)) { return GameInteractionEffectQueryResult::TemporarilyNotPossible; } else { return GameInteractionEffectQueryResult::Possible; @@ -465,7 +465,7 @@ void ClearAssignedButtons::_Apply() { // MARK: - SetTimeOfDay GameInteractionEffectQueryResult SetTimeOfDay::CanBeApplied() { - if (!GameInteractor::IsSaveLoaded()) { + if (!GameInteractor::IsSaveLoaded(true)) { return GameInteractionEffectQueryResult::TemporarilyNotPossible; } else { return GameInteractionEffectQueryResult::Possible; @@ -477,7 +477,7 @@ void SetTimeOfDay::_Apply() { // MARK: - SetCollisionViewer GameInteractionEffectQueryResult SetCollisionViewer::CanBeApplied() { - if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused()) { + if (!GameInteractor::IsSaveLoaded(true) || GameInteractor::IsGameplayPaused()) { return GameInteractionEffectQueryResult::TemporarilyNotPossible; } else { return GameInteractionEffectQueryResult::Possible; @@ -492,7 +492,7 @@ void SetCollisionViewer::_Remove() { // MARK: - RandomizeCosmetics GameInteractionEffectQueryResult RandomizeCosmetics::CanBeApplied() { - if (!GameInteractor::IsSaveLoaded()) { + if (!GameInteractor::IsSaveLoaded(true)) { return GameInteractionEffectQueryResult::TemporarilyNotPossible; } else { return GameInteractionEffectQueryResult::Possible; @@ -504,7 +504,7 @@ void RandomizeCosmetics::_Apply() { // MARK: - PressButton GameInteractionEffectQueryResult PressButton::CanBeApplied() { - if (!GameInteractor::IsSaveLoaded()) { + if (!GameInteractor::IsSaveLoaded(true)) { return GameInteractionEffectQueryResult::TemporarilyNotPossible; } else { return GameInteractionEffectQueryResult::Possible; @@ -516,7 +516,7 @@ void PressButton::_Apply() { // MARK: - PressRandomButton GameInteractionEffectQueryResult PressRandomButton::CanBeApplied() { - if (!GameInteractor::IsSaveLoaded()) { + if (!GameInteractor::IsSaveLoaded(true)) { return GameInteractionEffectQueryResult::TemporarilyNotPossible; } else { return GameInteractionEffectQueryResult::Possible; @@ -528,7 +528,7 @@ void PressRandomButton::_Apply() { // MARK: - AddOrTakeAmmo GameInteractionEffectQueryResult AddOrTakeAmmo::CanBeApplied() { - if (!GameInteractor::IsSaveLoaded()) { + if (!GameInteractor::IsSaveLoaded(true)) { return GameInteractionEffectQueryResult::TemporarilyNotPossible; } else if (!GameInteractor::CanAddOrTakeAmmo(parameters[0], parameters[1])) { return GameInteractionEffectQueryResult::NotPossible; @@ -542,7 +542,7 @@ void AddOrTakeAmmo::_Apply() { // MARK: - RandomBombFuseTimer GameInteractionEffectQueryResult RandomBombFuseTimer::CanBeApplied() { - if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused()) { + if (!GameInteractor::IsSaveLoaded(true) || GameInteractor::IsGameplayPaused()) { return GameInteractionEffectQueryResult::TemporarilyNotPossible; } else { return GameInteractionEffectQueryResult::Possible; @@ -557,7 +557,7 @@ void RandomBombFuseTimer::_Remove() { // MARK: - DisableLedgeGrabs GameInteractionEffectQueryResult DisableLedgeGrabs::CanBeApplied() { - if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused()) { + if (!GameInteractor::IsSaveLoaded(true) || GameInteractor::IsGameplayPaused()) { return GameInteractionEffectQueryResult::TemporarilyNotPossible; } else { return GameInteractionEffectQueryResult::Possible; @@ -572,7 +572,7 @@ void DisableLedgeGrabs::_Remove() { // MARK: - RandomWind GameInteractionEffectQueryResult RandomWind::CanBeApplied() { - if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused()) { + if (!GameInteractor::IsSaveLoaded(true) || GameInteractor::IsGameplayPaused()) { return GameInteractionEffectQueryResult::TemporarilyNotPossible; } else { return GameInteractionEffectQueryResult::Possible; @@ -587,7 +587,7 @@ void RandomWind::_Remove() { // MARK: - RandomBonks GameInteractionEffectQueryResult RandomBonks::CanBeApplied() { - if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused()) { + if (!GameInteractor::IsSaveLoaded(true) || GameInteractor::IsGameplayPaused()) { return GameInteractionEffectQueryResult::TemporarilyNotPossible; } else { return GameInteractionEffectQueryResult::Possible; @@ -602,7 +602,7 @@ void RandomBonks::_Remove() { // MARK: - PlayerInvincibility GameInteractionEffectQueryResult PlayerInvincibility::CanBeApplied() { - if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused()) { + if (!GameInteractor::IsSaveLoaded(true) || GameInteractor::IsGameplayPaused()) { return GameInteractionEffectQueryResult::TemporarilyNotPossible; } else { return GameInteractionEffectQueryResult::Possible; @@ -617,7 +617,7 @@ void PlayerInvincibility::_Remove() { // MARK: - SlipperyFloor GameInteractionEffectQueryResult SlipperyFloor::CanBeApplied() { - if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused()) { + if (!GameInteractor::IsSaveLoaded(true) || GameInteractor::IsGameplayPaused()) { return GameInteractionEffectQueryResult::TemporarilyNotPossible; } else { return GameInteractionEffectQueryResult::Possible; @@ -632,7 +632,7 @@ void SlipperyFloor::_Remove() { // MARK: - SpawnEnemyWithOffset GameInteractionEffectQueryResult SpawnEnemyWithOffset::CanBeApplied() { - if (!GameInteractor::IsSaveLoaded()) { + if (!GameInteractor::IsSaveLoaded(true)) { return GameInteractionEffectQueryResult::TemporarilyNotPossible; } return GameInteractor::RawAction::SpawnEnemyWithOffset(parameters[0], parameters[1]); @@ -644,7 +644,7 @@ void SpawnEnemyWithOffset::_Apply() { // MARK: - SpawnActor GameInteractionEffectQueryResult SpawnActor::CanBeApplied() { - if (!GameInteractor::IsSaveLoaded()) { + if (!GameInteractor::IsSaveLoaded(true)) { return GameInteractionEffectQueryResult::TemporarilyNotPossible; } return GameInteractor::RawAction::SpawnActor(parameters[0], parameters[1]); diff --git a/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h b/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h index 99bc57efe..09defd088 100644 --- a/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h +++ b/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h @@ -2239,6 +2239,12 @@ typedef enum { // #### `args` // - `*PlayState` VB_SHOW_GAMEPLAY_TIMER, + // (this->dyna.actor.params >> 5 & 0x7F) == GI_ICE_TRAP && this->actionFunc == EnBox_Open && + // this->skelanime.curFrame > 45 && this->iceSmokeTimer < 100 + // ``` + // #### `args` + // - `*EnBox` + VB_CHEST_USE_ICE_EFFECT, } GIVanillaBehavior; #endif diff --git a/soh/soh/Enhancements/gameplaystats.h b/soh/soh/Enhancements/gameplaystats.h index 1f89cb3a4..1d60b5dfc 100644 --- a/soh/soh/Enhancements/gameplaystats.h +++ b/soh/soh/Enhancements/gameplaystats.h @@ -51,9 +51,48 @@ typedef enum { /* 0xA9 */ TIMESTAMP_DEFEAT_GANON, // z_boss_ganon2.c /* 0xA9 */ TIMESTAMP_BOSSRUSH_FINISH, // z_boss_ganon2.c /* 0xAA */ TIMESTAMP_FOUND_GREG, // z_parameter.c - /* 0xAA */ TIMESTAMP_TRIFORCE_COMPLETED, // z_parameter.c - /* 0xAB */ TIMESTAMP_MAX - + /* 0xAB */ TIMESTAMP_TRIFORCE_COMPLETED, // z_parameter.c + /* 0xAC */ TIMESTAMP_FOUND_GOHMA_SOUL, + /* 0xAD */ TIMESTAMP_FOUND_KING_DODONGO_SOUL, + /* 0xAE */ TIMESTAMP_FOUND_BARINADE_SOUL, + /* 0xAF */ TIMESTAMP_FOUND_PHANTOM_GANON_SOUL, + /* 0xB0 */ TIMESTAMP_FOUND_VOLVAGIA_SOUL, + /* 0xB1 */ TIMESTAMP_FOUND_MORPHA_SOUL, + /* 0xB2 */ TIMESTAMP_FOUND_BONGO_BONGO_SOUL, + /* 0xB3 */ TIMESTAMP_FOUND_TWINROVA_SOUL, + /* 0xB5 */ TIMESTAMP_FOUND_GANON_SOUL, + /* 0xB6 */ TIMESTAMP_FOUND_BRONZE_SCALE, + /* 0xB7 */ TIMESTAMP_FOUND_OCARINA_A_BUTTON, + /* 0xB8 */ TIMESTAMP_FOUND_OCARINA_C_UP_BUTTON, + /* 0xB9 */ TIMESTAMP_FOUND_OCARINA_C_DOWN_BUTTON, + /* 0xBA */ TIMESTAMP_FOUND_OCARINA_C_LEFT_BUTTON, + /* 0xBB */ TIMESTAMP_FOUND_OCARINA_C_RIGHT_BUTTON, + /* 0xBC */ TIMESTAMP_FOUND_FISHING_POLE, + /* 0xBD */ TIMESTAMP_FOUND_GUARD_HOUSE_KEY, + /* 0xBE */ TIMESTAMP_FOUND_MARKET_BAZAAR_KEY, + /* 0xBF */ TIMESTAMP_FOUND_MARKET_POTION_SHOP_KEY, + /* 0xC0 */ TIMESTAMP_FOUND_MASK_SHOP_KEY, + /* 0xC1 */ TIMESTAMP_FOUND_MARKET_SHOOTING_GALLERY_KEY, + /* 0xC2 */ TIMESTAMP_FOUND_BOMBCHU_BOWLING_KEY, + /* 0xC3 */ TIMESTAMP_FOUND_TREASURE_CHEST_GAME_BUILDING_KEY, + /* 0xC4 */ TIMESTAMP_FOUND_BOMBCHU_SHOP_KEY, + /* 0xC5 */ TIMESTAMP_FOUND_RICHARDS_HOUSE_KEY, + /* 0xC6 */ TIMESTAMP_FOUND_ALLEY_HOUSE_KEY, + /* 0xC7 */ TIMESTAMP_FOUND_KAK_BAZAAR_KEY, + /* 0xC8 */ TIMESTAMP_FOUND_KAK_POTION_SHOP_KEY, + /* 0xC9 */ TIMESTAMP_FOUND_BOSS_HOUSE_KEY, + /* 0xCA */ TIMESTAMP_FOUND_GRANNYS_POTION_SHOP_KEY, + /* 0xCB */ TIMESTAMP_FOUND_SKULLTULA_HOUSE_KEY, + /* 0xCC */ TIMESTAMP_FOUND_IMPAS_HOUSE_KEY, + /* 0xCD */ TIMESTAMP_FOUND_WINDMILL_KEY, + /* 0xCE */ TIMESTAMP_FOUND_KAK_SHOOTING_GALLERY_KEY, + /* 0xCF */ TIMESTAMP_FOUND_DAMPES_HUT_KEY, + /* 0xD0 */ TIMESTAMP_FOUND_TALONS_HOUSE_KEY, + /* 0xD1 */ TIMESTAMP_FOUND_STABLES_KEY, + /* 0xD2 */ TIMESTAMP_FOUND_BACK_TOWER_KEY, + /* 0xD3 */ TIMESTAMP_FOUND_HYLIA_LAB_KEY, + /* 0xD4 */ TIMESTAMP_FOUND_FISHING_HOLE_KEY, + /* 0xD5 */ TIMESTAMP_MAX } GameplayStatTimestamp; typedef enum { diff --git a/soh/soh/Enhancements/mods.cpp b/soh/soh/Enhancements/mods.cpp index 44f0bcd57..2f56cadd6 100644 --- a/soh/soh/Enhancements/mods.cpp +++ b/soh/soh/Enhancements/mods.cpp @@ -48,7 +48,6 @@ extern "C" { extern SaveContext gSaveContext; extern PlayState* gPlayState; -extern void Overlay_DisplayText(float duration, const char* text); } // GreyScaleEndDlist @@ -130,10 +129,27 @@ void RegisterOcarinaTimeTravel() { bool notNearAnySource = !nearbyTimeBlockEmpty && !nearbyTimeBlock && !nearbyOcarinaSpot && !nearbyDoorOfTime && !nearbyFrogs && !nearbyGossipStone; bool hasOcarinaOfTime = (INV_CONTENT(ITEM_OCARINA_TIME) == ITEM_OCARINA_TIME); - bool doesntNeedOcarinaOfTime = CVarGetInteger(CVAR_ENHANCEMENT("TimeTravel"), 0) == 2; bool hasMasterSword = CHECK_OWNED_EQUIP(EQUIP_TYPE_SWORD, EQUIP_INV_SWORD_MASTER); - // TODO: Once Swordless Adult is fixed: Remove the Master Sword check - if (justPlayedSoT && notNearAnySource && (hasOcarinaOfTime || doesntNeedOcarinaOfTime) && hasMasterSword) { + int timeTravelSetting = CVarGetInteger(CVAR_ENHANCEMENT("TimeTravel"), 0); + bool meetsTimeTravelRequirements = false; + + switch (timeTravelSetting) { + case TIME_TRAVEL_ANY: + meetsTimeTravelRequirements = true; + break; + case TIME_TRAVEL_ANY_MS: + meetsTimeTravelRequirements = hasMasterSword; + break; + case TIME_TRAVEL_OOT_MS: + meetsTimeTravelRequirements = hasMasterSword && hasOcarinaOfTime; + break; + case TIME_TRAVEL_OOT: + default: + meetsTimeTravelRequirements = hasOcarinaOfTime; + break; + } + + if (justPlayedSoT && notNearAnySource && meetsTimeTravelRequirements) { SwitchAge(); } }); @@ -282,49 +298,6 @@ void UpdateHyperEnemiesState() { } } -void RegisterBonkDamage() { - GameInteractor::Instance->RegisterGameHook([]() { - uint8_t bonkOption = CVarGetInteger(CVAR_ENHANCEMENT("BonkDamageMult"), BONK_DAMAGE_NONE); - if (bonkOption == BONK_DAMAGE_NONE) { - return; - } - - if (bonkOption == BONK_DAMAGE_OHKO) { - gSaveContext.health = 0; - return; - } - - uint16_t bonkDamage = 0; - switch (bonkOption) { - case BONK_DAMAGE_QUARTER_HEART: - bonkDamage = 4; - break; - case BONK_DAMAGE_HALF_HEART: - bonkDamage = 8; - break; - case BONK_DAMAGE_1_HEART: - bonkDamage = 16; - break; - case BONK_DAMAGE_2_HEARTS: - bonkDamage = 32; - break; - case BONK_DAMAGE_4_HEARTS: - bonkDamage = 64; - break; - case BONK_DAMAGE_8_HEARTS: - bonkDamage = 128; - break; - default: - break; - } - - Health_ChangeBy(gPlayState, -bonkDamage); - // Set invincibility to make Link flash red as a visual damage indicator. - Player* player = GET_PLAYER(gPlayState); - player->invincibilityTimer = 28; - }); -} - void UpdateDirtPathFixState(int32_t sceneNum) { switch (sceneNum) { case SCENE_HYRULE_FIELD: @@ -964,7 +937,6 @@ void InitMods() { RegisterDeleteFileOnDeath(); RegisterHyperBosses(); UpdateHyperEnemiesState(); - RegisterBonkDamage(); RegisterMenuPathFix(); RegisterMirrorModeHandler(); RegisterResetNaviTimer(); diff --git a/soh/soh/Enhancements/randomizer/3drando/hints.cpp b/soh/soh/Enhancements/randomizer/3drando/hints.cpp index d59331776..d8a3f67ee 100644 --- a/soh/soh/Enhancements/randomizer/3drando/hints.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/hints.cpp @@ -648,6 +648,9 @@ void CreateStoneHints() { if (ctx->GetOption(RSK_SKIP_CHILD_ZELDA)) { ctx->GetItemLocation(RC_SONG_FROM_IMPA)->SetHintAccesible(); } + if (ctx->GetOption(RSK_SELECTED_STARTING_AGE).Is(RO_AGE_ADULT)) { + ctx->GetItemLocation(RC_TOT_MASTER_SWORD)->SetHintAccesible(); + } // Add 'always' location hints std::vector alwaysHintLocations = {}; diff --git a/soh/soh/Enhancements/randomizer/ShuffleCrates.cpp b/soh/soh/Enhancements/randomizer/ShuffleCrates.cpp index 53a65df22..6962b290d 100644 --- a/soh/soh/Enhancements/randomizer/ShuffleCrates.cpp +++ b/soh/soh/Enhancements/randomizer/ShuffleCrates.cpp @@ -336,7 +336,7 @@ void Rando::StaticData::RegisterCrateLocations() { locationTable[RC_GF_SOUTHMOST_CENTER_CRATE] = Location::Crate(RC_GF_SOUTHMOST_CENTER_CRATE, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_GERUDOS_FORTRESS, TWO_ACTOR_PARAMS(315, -1534), "Southmost Center Crate", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_SOUTHMOST_CENTER_CRATE)); locationTable[RC_GF_MID_SOUTH_CENTER_CRATE] = Location::Crate(RC_GF_MID_SOUTH_CENTER_CRATE, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_GERUDOS_FORTRESS, TWO_ACTOR_PARAMS(315, -1594), "Middle South Center Crate", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_MID_SOUTH_CENTER_CRATE)); locationTable[RC_GF_MID_NORTH_CENTER_CRATE] = Location::Crate(RC_GF_MID_NORTH_CENTER_CRATE, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_GERUDOS_FORTRESS, TWO_ACTOR_PARAMS(310, -1782), "Middle North Center Crate", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_MID_NORTH_CENTER_CRATE)); - locationTable[RR_GF_NORTHMOST_CENTER_CRATE] = Location::Crate(RR_GF_NORTHMOST_CENTER_CRATE, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_GERUDOS_FORTRESS, TWO_ACTOR_PARAMS(310, -1842), "Northmost Center Crate", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_NORTHMOST_CENTER_CRATE)); + locationTable[RC_GF_NORTHMOST_CENTER_CRATE] = Location::Crate(RC_GF_NORTHMOST_CENTER_CRATE, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_GERUDOS_FORTRESS, TWO_ACTOR_PARAMS(310, -1842), "Northmost Center Crate", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_NORTHMOST_CENTER_CRATE)); locationTable[RC_GF_OUTSKIRTS_NE_CRATE] = Location::Crate(RC_GF_OUTSKIRTS_NE_CRATE, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_GERUDOS_FORTRESS, TWO_ACTOR_PARAMS(-60, -2210), "Outskirts Northeast Crate", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_OUTSKIRTS_NE_CRATE)); locationTable[RC_GF_OUTSKIRTS_NW_CRATE] = Location::Crate(RC_GF_OUTSKIRTS_NW_CRATE, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_GERUDOS_FORTRESS, TWO_ACTOR_PARAMS(-120, -2210), "Outskirts Northwest Crate", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_OUTSKIRTS_NW_CRATE)); locationTable[RC_GF_HBA_RANGE_CRATE_2] = Location::Crate(RC_GF_HBA_RANGE_CRATE_2, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_GERUDOS_FORTRESS, TWO_ACTOR_PARAMS(4090, -1780), "Horseback Archery Range Crate 2", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_HBA_RANGE_CRATE_2)); diff --git a/soh/soh/Enhancements/randomizer/hook_handlers.cpp b/soh/soh/Enhancements/randomizer/hook_handlers.cpp index d73cebca7..447125ae1 100644 --- a/soh/soh/Enhancements/randomizer/hook_handlers.cpp +++ b/soh/soh/Enhancements/randomizer/hook_handlers.cpp @@ -1713,6 +1713,7 @@ void RandomizerOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, va_l case VB_GIVE_ITEM_WATER_MEDALLION: case VB_GIVE_ITEM_SPIRIT_MEDALLION: case VB_GIVE_ITEM_SHADOW_MEDALLION: + case VB_CHEST_USE_ICE_EFFECT: *should = false; break; case VB_GIVE_ITEM_SKULL_TOKEN: diff --git a/soh/soh/Enhancements/randomizer/location_access.cpp b/soh/soh/Enhancements/randomizer/location_access.cpp index e261b8d49..cb5668b01 100644 --- a/soh/soh/Enhancements/randomizer/location_access.cpp +++ b/soh/soh/Enhancements/randomizer/location_access.cpp @@ -792,12 +792,14 @@ void RegionTable_Init() { EventAccess(&logic->THCouldFreeDoubleCellCarpenter, []{return ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_CARPENTERS_FREE) || ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_CARPENTERS_FAST);}), EventAccess(&logic->TH_CouldFreeDeadEndCarpenter, []{return ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_CARPENTERS_FREE) || ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_CARPENTERS_FAST);}), EventAccess(&logic->THCouldRescueSlopeCarpenter, []{return ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_CARPENTERS_FREE) || ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_CARPENTERS_FAST);}), - EventAccess(&logic->THRescuedAllCarpenters, []{return ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_CARPENTERS_FREE);}), + EventAccess(&logic->THRescuedAllCarpenters, []{return ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_CARPENTERS_FREE);}),EventAccess(&logic->FreedEpona, []{return (bool)ctx->GetOption(RSK_SKIP_EPONA_RACE);}), }, { //Locations LOCATION(RC_LINKS_POCKET, true), LOCATION(RC_TRIFORCE_COMPLETED, logic->GetSaveContext()->ship.quest.data.randomizer.triforcePiecesCollected >= ctx->GetOption(RSK_TRIFORCE_HUNT_PIECES_REQUIRED).Get() + 1;), LOCATION(RC_SARIA_SONG_HINT, logic->CanUse(RG_SARIAS_SONG)), + LOCATION(RC_SONG_FROM_IMPA, (bool)ctx->GetOption(RSK_SKIP_CHILD_ZELDA)), + LOCATION(RC_TOT_MASTER_SWORD, (bool)ctx->GetOption(RSK_SELECTED_STARTING_AGE).Is(RO_AGE_ADULT)), }, { //Exits Entrance(RR_ROOT_EXITS, []{return true;}), diff --git a/soh/soh/Enhancements/randomizer/location_access/overworld/gerudo_fortress.cpp b/soh/soh/Enhancements/randomizer/location_access/overworld/gerudo_fortress.cpp index 3929faf86..17e28d5eb 100644 --- a/soh/soh/Enhancements/randomizer/location_access/overworld/gerudo_fortress.cpp +++ b/soh/soh/Enhancements/randomizer/location_access/overworld/gerudo_fortress.cpp @@ -30,7 +30,7 @@ void RegionTable_Init_GerudoFortress() { LOCATION(RC_GF_SOUTHMOST_CENTER_CRATE, logic->CanBreakCrates()), LOCATION(RC_GF_MID_SOUTH_CENTER_CRATE, logic->CanBreakCrates()), LOCATION(RC_GF_MID_NORTH_CENTER_CRATE, logic->CanBreakCrates()), - LOCATION(RR_GF_NORTHMOST_CENTER_CRATE, logic->CanBreakCrates()), + LOCATION(RC_GF_NORTHMOST_CENTER_CRATE, logic->CanBreakCrates()), }, { //Exits Entrance(RR_TH_1_TORCH_CELL, []{return true;}), diff --git a/soh/soh/Enhancements/randomizer/logic.cpp b/soh/soh/Enhancements/randomizer/logic.cpp index eea79e92d..3c0c8345e 100644 --- a/soh/soh/Enhancements/randomizer/logic.cpp +++ b/soh/soh/Enhancements/randomizer/logic.cpp @@ -2471,6 +2471,7 @@ void Logic::Reset(bool resetSaveContext /*= true*/) { THCouldFreeDoubleCellCarpenter = false; TH_CouldFreeDeadEndCarpenter = false; THCouldRescueSlopeCarpenter = false; + THRescuedAllCarpenters = false; GF_GateOpen = false; GtG_GateOpen = false; DampesWindmillAccess = false; diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index 2a2acd5c7..b8a4820d8 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -519,6 +519,8 @@ bool Randomizer::SpoilerFileExists(const char* spoilerFileName) { "The spoiler file located at\n" + std::string(spoilerFileName) + "\nwas made by a version that doesn't match the currently running version.\n" + "Loading for this file has been cancelled."); + CVarClear(CVAR_GENERAL("SpoilerLog")); + Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame(); } // Update cache @@ -2330,7 +2332,7 @@ std::map rcToRandomizerInf = { RAND_INF_GF_MID_NORTH_CENTER_CRATE, }, { - RR_GF_NORTHMOST_CENTER_CRATE, + RC_GF_NORTHMOST_CENTER_CRATE, RAND_INF_GF_NORTHMOST_CENTER_CRATE, }, { @@ -5781,6 +5783,53 @@ void RandomizerSettingsWindow::InitElement() { mSettings->UpdateOptionProperties(); } +static std::unordered_map randomizerGetToStatsTimeStamp = { + { RG_GOHMA_SOUL, TIMESTAMP_FOUND_GOHMA_SOUL }, + { RG_KING_DODONGO_SOUL, TIMESTAMP_FOUND_KING_DODONGO_SOUL }, + { RG_BARINADE_SOUL, TIMESTAMP_FOUND_BARINADE_SOUL }, + { RG_PHANTOM_GANON_SOUL, TIMESTAMP_FOUND_PHANTOM_GANON_SOUL }, + { RG_VOLVAGIA_SOUL, TIMESTAMP_FOUND_VOLVAGIA_SOUL }, + { RG_MORPHA_SOUL, TIMESTAMP_FOUND_MORPHA_SOUL }, + { RG_BONGO_BONGO_SOUL, TIMESTAMP_FOUND_BONGO_BONGO_SOUL }, + { RG_TWINROVA_SOUL, TIMESTAMP_FOUND_TWINROVA_SOUL }, + { RG_GANON_SOUL, TIMESTAMP_FOUND_GANON_SOUL }, + + { RG_BRONZE_SCALE, TIMESTAMP_FOUND_BRONZE_SCALE }, + + { RG_OCARINA_A_BUTTON, TIMESTAMP_FOUND_OCARINA_A_BUTTON }, + { RG_OCARINA_C_UP_BUTTON, TIMESTAMP_FOUND_OCARINA_C_UP_BUTTON }, + { RG_OCARINA_C_DOWN_BUTTON, TIMESTAMP_FOUND_OCARINA_C_DOWN_BUTTON }, + { RG_OCARINA_C_LEFT_BUTTON, TIMESTAMP_FOUND_OCARINA_C_LEFT_BUTTON }, + { RG_OCARINA_C_RIGHT_BUTTON, TIMESTAMP_FOUND_OCARINA_C_RIGHT_BUTTON }, + + { RG_FISHING_POLE, TIMESTAMP_FOUND_FISHING_POLE }, + + { RG_GUARD_HOUSE_KEY, TIMESTAMP_FOUND_GUARD_HOUSE_KEY }, + { RG_MARKET_BAZAAR_KEY, TIMESTAMP_FOUND_MARKET_BAZAAR_KEY }, + { RG_MARKET_POTION_SHOP_KEY, TIMESTAMP_FOUND_MARKET_POTION_SHOP_KEY }, + { RG_MASK_SHOP_KEY, TIMESTAMP_FOUND_MASK_SHOP_KEY }, + { RG_MARKET_SHOOTING_GALLERY_KEY, TIMESTAMP_FOUND_MARKET_SHOOTING_GALLERY_KEY }, + { RG_BOMBCHU_BOWLING_KEY, TIMESTAMP_FOUND_BOMBCHU_BOWLING_KEY }, + { RG_TREASURE_CHEST_GAME_BUILDING_KEY, TIMESTAMP_FOUND_TREASURE_CHEST_GAME_BUILDING_KEY }, + { RG_BOMBCHU_SHOP_KEY, TIMESTAMP_FOUND_BOMBCHU_SHOP_KEY }, + { RG_RICHARDS_HOUSE_KEY, TIMESTAMP_FOUND_RICHARDS_HOUSE_KEY }, + { RG_ALLEY_HOUSE_KEY, TIMESTAMP_FOUND_ALLEY_HOUSE_KEY }, + { RG_KAK_BAZAAR_KEY, TIMESTAMP_FOUND_KAK_BAZAAR_KEY }, + { RG_KAK_POTION_SHOP_KEY, TIMESTAMP_FOUND_KAK_POTION_SHOP_KEY }, + { RG_BOSS_HOUSE_KEY, TIMESTAMP_FOUND_BOSS_HOUSE_KEY }, + { RG_GRANNYS_POTION_SHOP_KEY, TIMESTAMP_FOUND_GRANNYS_POTION_SHOP_KEY }, + { RG_SKULLTULA_HOUSE_KEY, TIMESTAMP_FOUND_SKULLTULA_HOUSE_KEY }, + { RG_IMPAS_HOUSE_KEY, TIMESTAMP_FOUND_IMPAS_HOUSE_KEY }, + { RG_WINDMILL_KEY, TIMESTAMP_FOUND_WINDMILL_KEY }, + { RG_KAK_SHOOTING_GALLERY_KEY, TIMESTAMP_FOUND_KAK_SHOOTING_GALLERY_KEY }, + { RG_DAMPES_HUT_KEY, TIMESTAMP_FOUND_DAMPES_HUT_KEY }, + { RG_TALONS_HOUSE_KEY, TIMESTAMP_FOUND_TALONS_HOUSE_KEY }, + { RG_STABLES_KEY, TIMESTAMP_FOUND_STABLES_KEY }, + { RG_BACK_TOWER_KEY, TIMESTAMP_FOUND_BACK_TOWER_KEY }, + { RG_HYLIA_LAB_KEY, TIMESTAMP_FOUND_HYLIA_LAB_KEY }, + { RG_FISHING_HOLE_KEY, TIMESTAMP_FOUND_FISHING_HOLE_KEY }, +}; + // Gameplay stat tracking: Update time the item was acquired // (special cases for rando items) void Randomizer_GameplayStats_SetTimestamp(uint16_t item) { @@ -5795,6 +5844,12 @@ void Randomizer_GameplayStats_SetTimestamp(uint16_t item) { // Use ITEM_KEY_BOSS to timestamp Ganon's boss key if (item == RG_GANONS_CASTLE_BOSS_KEY) { gSaveContext.ship.stats.itemTimestamp[ITEM_KEY_BOSS] = time; + return; + } + + if (randomizerGetToStatsTimeStamp.contains((RandomizerGet)item)) { + gSaveContext.ship.stats.itemTimestamp[randomizerGetToStatsTimeStamp[(RandomizerGet)item]] = time; + return; } // Count any bottled item as a bottle @@ -5804,6 +5859,7 @@ void Randomizer_GameplayStats_SetTimestamp(uint16_t item) { } return; } + // Count any bombchu pack as bombchus if ((item >= RG_BOMBCHU_5 && item <= RG_BOMBCHU_20) || item == RG_PROGRESSIVE_BOMBCHUS) { if (gSaveContext.ship.stats.itemTimestamp[ITEM_BOMBCHU] = 0) { @@ -5811,11 +5867,15 @@ void Randomizer_GameplayStats_SetTimestamp(uint16_t item) { } return; } + if (item == RG_MAGIC_SINGLE) { gSaveContext.ship.stats.itemTimestamp[ITEM_SINGLE_MAGIC] = time; + return; } + if (item == RG_DOUBLE_DEFENSE) { gSaveContext.ship.stats.itemTimestamp[ITEM_DOUBLE_DEFENSE] = time; + return; } } diff --git a/soh/soh/Enhancements/randomizer/randomizerTypes.h b/soh/soh/Enhancements/randomizer/randomizerTypes.h index 15a2fbd37..c2b9cbbdd 100644 --- a/soh/soh/Enhancements/randomizer/randomizerTypes.h +++ b/soh/soh/Enhancements/randomizer/randomizerTypes.h @@ -2396,7 +2396,7 @@ typedef enum { RC_GF_SOUTHMOST_CENTER_CRATE, RC_GF_MID_SOUTH_CENTER_CRATE, RC_GF_MID_NORTH_CENTER_CRATE, - RR_GF_NORTHMOST_CENTER_CRATE, + RC_GF_NORTHMOST_CENTER_CRATE, RC_GF_OUTSKIRTS_NE_CRATE, RC_GF_OUTSKIRTS_NW_CRATE, RC_GF_HBA_RANGE_CRATE_1, diff --git a/soh/soh/Enhancements/randomizer/randomizer_item_tracker.cpp b/soh/soh/Enhancements/randomizer/randomizer_item_tracker.cpp index fcace1017..04bc783d9 100644 --- a/soh/soh/Enhancements/randomizer/randomizer_item_tracker.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer_item_tracker.cpp @@ -449,7 +449,8 @@ ItemTrackerNumbers GetItemCurrentAndMax(ItemTrackerItem item) { result.currentCapacity = IS_RANDO && !Flags_GetRandomizerInf(RAND_INF_HAS_WALLET) ? 0 : CUR_CAPACITY(UPG_WALLET); result.maxCapacity = - OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_INCLUDE_TYCOON_WALLET) ? 999 : 500; + IS_RANDO && OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_INCLUDE_TYCOON_WALLET) ? 999 + : 500; result.currentAmmo = gSaveContext.rupees; break; case ITEM_BOMBCHU: @@ -502,7 +503,28 @@ ItemTrackerNumbers GetItemCurrentAndMax(ItemTrackerItem item) { result.maxCapacity = GERUDO_TRAINING_GROUND_SMALL_KEY_MAX; break; case SCENE_THIEVES_HIDEOUT: - result.maxCapacity = GERUDO_FORTRESS_SMALL_KEY_MAX; + if (IS_RANDO) { + switch (OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_GERUDO_FORTRESS)) { + case RO_GF_CARPENTERS_NORMAL: + result.maxCapacity = GERUDO_FORTRESS_SMALL_KEY_MAX; + break; + case RO_GF_CARPENTERS_FAST: + result.maxCapacity = 1; + break; + case RO_GF_CARPENTERS_FREE: + result.maxCapacity = 0; + break; + default: + result.maxCapacity = 0; + SPDLOG_ERROR( + "Invalid value for RSK_GERUDO_FORTRESS: " + + OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_GERUDO_FORTRESS)); + assert(false); + break; + } + } else { + result.maxCapacity = GERUDO_FORTRESS_SMALL_KEY_MAX; + } break; case SCENE_INSIDE_GANONS_CASTLE: result.maxCapacity = GANONS_CASTLE_SMALL_KEY_MAX; diff --git a/soh/soh/Enhancements/timesplits/TimeSplits.cpp b/soh/soh/Enhancements/timesplits/TimeSplits.cpp index 047a6f502..e6515ed82 100644 --- a/soh/soh/Enhancements/timesplits/TimeSplits.cpp +++ b/soh/soh/Enhancements/timesplits/TimeSplits.cpp @@ -2,6 +2,7 @@ #include #include +#include "Context.h" #include "TimeSplits.h" #include "soh/Enhancements/gameplaystats.h" #include "soh/SaveManager.h" @@ -363,7 +364,7 @@ void TimeSplitsSkipSplit(uint32_t index) { } void TimeSplitsFileManagement(uint32_t action, const char* listEntry, std::vector listData) { - std::string filename = "timesplitdata.json"; + std::string filename = Ship::Context::GetPathRelativeToAppDirectory("timesplitdata.json"); json saveFile; json listArray = nlohmann::json::array(); @@ -948,9 +949,10 @@ void TimeSplitsDrawManageList() { } void InitializeSplitDataFile() { - if (!std::filesystem::exists("timesplitdata.json")) { + std::string filename = Ship::Context::GetPathRelativeToAppDirectory("timesplitdata.json"); + if (!std::filesystem::exists(filename)) { json j; - std::ofstream file("timesplitdata.json"); + std::ofstream file(filename); file << j.dump(4); file.close(); } diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index bc9b3106e..7d2194cca 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -984,7 +984,6 @@ OTRVersion ReadPortVersionFromOTR(std::string otrPath) { version.minor = reader->ReadUInt16(); version.patch = reader->ReadUInt16(); } - archive->Close(); } return version; @@ -1679,7 +1678,9 @@ ImFont* OTRGlobals::CreateFontWithSize(float size, std::string fontPath) { initData->Path = fontPath; std::shared_ptr fontData = std::static_pointer_cast( Ship::Context::GetInstance()->GetResourceManager()->LoadResource(fontPath, false, initData)); - font = mImGuiIo->Fonts->AddFontFromMemoryTTF(fontData->Data, fontData->DataSize, size); + ImFontConfig fontConf; + fontConf.FontDataOwnedByAtlas = false; + font = mImGuiIo->Fonts->AddFontFromMemoryTTF(fontData->Data, fontData->DataSize, size, &fontConf); } // FontAwesome fonts need to have their sizes reduced by 2.0f/3.0f in order to align correctly float iconFontSize = size * 2.0f / 3.0f; @@ -2579,15 +2580,6 @@ extern "C" int CustomMessage_RetrieveIfExists(PlayState* play) { return false; } -extern "C" void Overlay_DisplayText(float duration, const char* text) { - Ship::Context::GetInstance()->GetWindow()->GetGui()->GetGameOverlay()->TextDrawNotification(duration, true, text); -} - -extern "C" void Overlay_DisplayText_Seconds(int seconds, const char* text) { - float duration = seconds * OTRGlobals::Instance->GetInterpolationFPS() * 0.05; - Ship::Context::GetInstance()->GetWindow()->GetGui()->GetGameOverlay()->TextDrawNotification(duration, true, text); -} - extern "C" void EntranceTracker_SetCurrentGrottoID(s16 entranceIndex) { SetCurrentGrottoIDForTracker(entranceIndex); } diff --git a/soh/soh/OTRGlobals.h b/soh/soh/OTRGlobals.h index cab7575cd..032686f8e 100644 --- a/soh/soh/OTRGlobals.h +++ b/soh/soh/OTRGlobals.h @@ -156,8 +156,6 @@ void Randomizer_SetSpoilerLoaded(bool spoilerLoaded); uint8_t Randomizer_GenerateRandomizer(); void Randomizer_ShowRandomizerMenu(); int CustomMessage_RetrieveIfExists(PlayState* play); -void Overlay_DisplayText(float duration, const char* text); -void Overlay_DisplayText_Seconds(int seconds, const char* text); GetItemEntry ItemTable_Retrieve(int16_t getItemID); GetItemEntry ItemTable_RetrieveEntry(s16 modIndex, s16 getItemID); void EntranceTracker_SetCurrentGrottoID(s16 entranceIndex); diff --git a/soh/soh/SaveManager.cpp b/soh/soh/SaveManager.cpp index 4b830f846..05b85e69a 100644 --- a/soh/soh/SaveManager.cpp +++ b/soh/soh/SaveManager.cpp @@ -1125,6 +1125,7 @@ void SaveManager::LoadFile(int fileNum) { std::ifstream input(fileName); try { + bool deleteRando = false; saveBlock = nlohmann::json::object(); input >> saveBlock; if (!saveBlock.contains("version")) { @@ -1134,21 +1135,24 @@ void SaveManager::LoadFile(int fileNum) { switch (saveBlock["version"].get()) { case 1: for (auto& block : saveBlock["sections"].items()) { + bool oldVanilla = + block.value()["data"].empty() || block.value()["data"].contains("aat0") || + block.value()["data"]["entrances"].empty() || + SohUtils::IsStringEmpty(saveBlock["sections"]["sohStats"]["data"]["buildVersion"]); std::string sectionName = block.key(); if (sectionName == "randomizer") { bool hasStats = saveBlock["sections"].contains("sohStats"); - if (block.value()["data"].contains("aat0") || !hasStats) { // Rachael rando data + if (oldVanilla || !hasStats) { // Vanilla "rando" data SohGui::RegisterPopup( "Loading old file", "The file in slot " + std::to_string(fileNum + 1) + - " appears to contain randomizer data, but is a very old format.\n" + + " appears to contain randomizer data, but is a very old format or is empty.\n" + "The randomizer data has been removed, and this file will be treated as a vanilla " - "file.\n" + + "file.\nIf this was a vanilla file, it still is, and you shouldn't see this " + "message again.\n" + "If this was a randomizer file, the file will not work, and should be deleted."); - input.close(); - saveMtx.unlock(); - SaveFile(fileNum); - return; + deleteRando = true; + continue; } s16 major = saveBlock["sections"]["sohStats"]["data"]["buildVersionMajor"]; s16 minor = saveBlock["sections"]["sohStats"]["data"]["buildVersionMinor"]; @@ -1177,7 +1181,6 @@ void SaveManager::LoadFile(int fileNum) { " " + newFileName + "\n" + "If this was not in error, the file should be deleted."); saveMtx.unlock(); - SaveFile(fileNum); return; } } @@ -1216,6 +1219,12 @@ void SaveManager::LoadFile(int fileNum) { assert(false); break; } + input.close(); + if (deleteRando) { + saveBlock["sections"].erase(saveBlock["sections"].find("randomizer")); + SaveFile(fileNum); + deleteRando = false; + } InitMeta(fileNum); GameInteractor::Instance->ExecuteHooks(fileNum); } catch (const std::exception& e) { diff --git a/soh/soh/SohGui/SohGui.cpp b/soh/soh/SohGui/SohGui.cpp index e9b27eda1..8de5478f1 100644 --- a/soh/soh/SohGui/SohGui.cpp +++ b/soh/soh/SohGui/SohGui.cpp @@ -70,7 +70,6 @@ std::shared_ptr mSohMenuBar; std::shared_ptr mConsoleWindow; std::shared_ptr mStatsWindow; std::shared_ptr mGfxDebuggerWindow; -std::shared_ptr mInputEditorWindow; std::shared_ptr mSohMenu; std::shared_ptr mAudioEditorWindow; @@ -130,10 +129,10 @@ void SetupGuiElements() { mStatsWindow = std::make_shared(CVAR_WINDOW("SohStats"), "Stats##Soh", ImVec2(400, 100)); gui->AddGuiWindow(mStatsWindow); - mInputEditorWindow = gui->GetGuiWindow("Controller Configuration"); + /*mInputEditorWindow = gui->GetGuiWindow("Controller Configuration"); if (mInputEditorWindow == nullptr) { SPDLOG_ERROR("Could not find input editor window"); - } + }*/ mAudioEditorWindow = std::make_shared(CVAR_WINDOW("AudioEditor"), "Audio Editor", ImVec2(820, 630)); gui->AddGuiWindow(mAudioEditorWindow); @@ -227,7 +226,6 @@ void Destroy() { mActorViewerWindow = nullptr; mCosmeticsEditorWindow = nullptr; mAudioEditorWindow = nullptr; - mInputEditorWindow = nullptr; mStatsWindow = nullptr; mConsoleWindow = nullptr; mGfxDebuggerWindow = nullptr; diff --git a/soh/soh/SohGui/SohMenuEnhancements.cpp b/soh/soh/SohGui/SohMenuEnhancements.cpp index eda3d85bb..488aeb720 100644 --- a/soh/soh/SohGui/SohMenuEnhancements.cpp +++ b/soh/soh/SohGui/SohMenuEnhancements.cpp @@ -56,7 +56,9 @@ static const std::unordered_map chestStyleMatchesContentsO static const std::unordered_map timeTravelOptions = { { TIME_TRAVEL_DISABLED, "Disabled" }, { TIME_TRAVEL_OOT, "Ocarina of Time" }, + { TIME_TRAVEL_OOT_MS, "Ocarina of Time + Master Sword" }, { TIME_TRAVEL_ANY, "Any Ocarina" }, + { TIME_TRAVEL_ANY_MS, "Any Ocarina + Master Sword" }, }; static const std::unordered_map sleepingWaterfallOptions = { @@ -335,7 +337,7 @@ void SohMenu::AddMenuEnhancements() { info.options->disabled = IS_RANDO && OTRGlobals::Instance->gRandoContext->GetOption(RSK_JABU_OPEN).Is(RO_JABU_OPEN); info.options->disabledTooltip = - "This setting is disabled because a randomizer savefile with \"Jabu-Jaby: Open\" is loaded."; + "This setting is disabled because a randomizer savefile with \"Jabu-Jabu: Open\" is loaded."; }) .Options(CheckboxOptions().Tooltip("Allow Link to enter Jabu-Jabu without feeding him a fish.")); @@ -416,9 +418,12 @@ void SohMenu::AddMenuEnhancements() { "Door Switch CS, Water Temple Dragon Switch CS, and the Box Skip One Point in Jabu.")); AddWidget(path, "Text", WIDGET_SEPARATOR_TEXT); - AddWidget(path, "Skip Pickup Messages", WIDGET_CVAR_CHECKBOX) + AddWidget(path, "Skip Bottle Pickup Messages", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("FastBottles")) + .Options(CheckboxOptions().Tooltip("Skip Pickup Messages for Bottle Swipes.")); + AddWidget(path, "Skip Consumable Item Pickup Messages", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_ENHANCEMENT("FastDrops")) - .Options(CheckboxOptions().Tooltip("Skip Pickup Messages for new Consumable Items and Bottle Swipes.")); + .Options(CheckboxOptions().Tooltip("Skip Pickup Messages for new Consumable Items.")); AddWidget(path, "Skip Forced Dialog", WIDGET_CVAR_COMBOBOX) .CVar(CVAR_ENHANCEMENT("TimeSavers.SkipForcedDialog")) .Options(ComboboxOptions() @@ -780,9 +785,9 @@ void SohMenu::AddMenuEnhancements() { .Tooltip("Allows Link to freely change age by playing the Song of Time.\n" "Time Blocks can still be used properly.\n\n" "Requirements:\n" - " - Obtained the Ocarina of Time (depends on selection)\n" " - Obtained the Song of Time\n" - " - Obtained the Master Sword\n" + " - Obtained the Ocarina of Time (depends on selection)\n" + " - Obtained the Master Sword (depends on selection)\n" " - Not within range of a Time Block\n" " - Not within range of Ocarina Playing spots")); diff --git a/soh/soh/SohGui/SohMenuSettings.cpp b/soh/soh/SohGui/SohMenuSettings.cpp index bb7c82574..2472e325b 100644 --- a/soh/soh/SohGui/SohMenuSettings.cpp +++ b/soh/soh/SohGui/SohMenuSettings.cpp @@ -1,5 +1,7 @@ #include "SohMenu.h" #include "soh/Notification/Notification.h" +#include "soh/Enhancements/controls/SohInputEditorWindow.h" +#include "SohModals.h" #include "soh/OTRGlobals.h" #include #include "soh/ResourceManagerHelpers.h" @@ -14,6 +16,7 @@ extern "C" { namespace SohGui { extern std::shared_ptr mSohMenu; +extern std::shared_ptr mModalWindow; using namespace UIWidgets; static std::unordered_map imguiScaleOptions = { @@ -411,6 +414,20 @@ void SohMenu::AddMenuSettings() { path.sidebarName = "Controls"; path.column = SECTION_COLUMN_1; AddSidebarEntry("Settings", "Controls", 2); + AddWidget(path, "Clear Devices", WIDGET_BUTTON) + .Callback([](WidgetInfo& info) { + SohGui::mModalWindow->RegisterPopup( + "Clear Config", + "This will completely erase the controls config, including registered devices.\nContinue?", "Clear", + "Cancel", + []() { + Ship::Context::GetInstance()->GetConsoleVariables()->ClearBlock(CVAR_PREFIX_SETTING ".Controllers"); + uint8_t bits = 0; + Ship::Context::GetInstance()->GetControlDeck()->Init(&bits); + }, + nullptr); + }) + .Options(ButtonOptions().Size(Sizes::Inline)); AddWidget(path, "Controller Bindings", WIDGET_SEPARATOR_TEXT); AddWidget(path, "Popout Bindings Window", WIDGET_WINDOW_BUTTON) .CVar(CVAR_WINDOW("ControllerConfiguration")) diff --git a/soh/src/code/audio_load.c b/soh/src/code/audio_load.c index 81f67f9c0..52efa4016 100644 --- a/soh/src/code/audio_load.c +++ b/soh/src/code/audio_load.c @@ -640,10 +640,8 @@ s32 AudioLoad_SyncInitSeqPlayerInternal(s32 playerIdx, s32 seqId, s32 arg2) { if (gPlayState != NULL) { previousSceneNum = gPlayState->sceneNum; } - const char* sequenceName = AudioCollection_GetSequenceName(seqId); - if (sequenceName != NULL) { - Overlay_DisplayText_Seconds(CVarGetInteger(CVAR_AUDIO("SeqNameOverlayDuration"), 5), sequenceName); - } + + AudioCollection_EmitSongNameNotification(seqId); } } diff --git a/soh/src/overlays/actors/ovl_En_Box/z_en_box.c b/soh/src/overlays/actors/ovl_En_Box/z_en_box.c index 9a3a8fb77..f52b4a458 100644 --- a/soh/src/overlays/actors/ovl_En_Box/z_en_box.c +++ b/soh/src/overlays/actors/ovl_En_Box/z_en_box.c @@ -567,8 +567,10 @@ void EnBox_Update(Actor* thisx, PlayState* play) { Actor_SetFocus(&this->dyna.actor, 40.0f); } - if ((this->dyna.actor.params >> 5 & 0x7F) == GI_ICE_TRAP && this->actionFunc == EnBox_Open && - this->skelanime.curFrame > 45 && this->iceSmokeTimer < 100) { + if (GameInteractor_Should(VB_CHEST_USE_ICE_EFFECT, + (this->dyna.actor.params >> 5 & 0x7F) == GI_ICE_TRAP && this->actionFunc == EnBox_Open && + this->skelanime.curFrame > 45 && this->iceSmokeTimer < 100, + this)) { EnBox_SpawnIceSmoke(this, play); } } diff --git a/soh/src/overlays/actors/ovl_En_Partner/z_en_partner.c b/soh/src/overlays/actors/ovl_En_Partner/z_en_partner.c index ab8ca1a6f..ab379267e 100644 --- a/soh/src/overlays/actors/ovl_En_Partner/z_en_partner.c +++ b/soh/src/overlays/actors/ovl_En_Partner/z_en_partner.c @@ -654,7 +654,7 @@ void EnPartner_Update(Actor* thisx, PlayState* play) { itemActor->params == ITEM00_ARROWS_MEDIUM || itemActor->params == ITEM00_ARROWS_LARGE || itemActor->params == ITEM00_BOMBCHU || itemActor->params == ITEM00_MAGIC_SMALL || itemActor->params == ITEM00_MAGIC_LARGE || itemActor->params == ITEM00_NUTS || - itemActor->params == ITEM00_STICK) { + itemActor->params == ITEM00_STICK || itemActor->params == ITEM00_SEEDS) { f32 distanceToObject = Actor_WorldDistXYZToActor(&this->actor, itemActor); if (distanceToObject <= 20.0f) { itemActor->world.pos = GET_PLAYER(play)->actor.world.pos; 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 205079576..3571ca135 100644 --- a/soh/src/overlays/actors/ovl_player_actor/z_player.c +++ b/soh/src/overlays/actors/ovl_player_actor/z_player.c @@ -14646,7 +14646,7 @@ void Player_Action_SwingBottle(Player* this, PlayState* play) { if (LinkAnimation_Update(play, &this->skelAnime)) { if (this->av1.bottleCatchType != BOTTLE_CATCH_NONE) { if (!this->av2.startedTextbox) { - if (CVarGetInteger(CVAR_ENHANCEMENT("FastDrops"), 0)) { + if (CVarGetInteger(CVAR_ENHANCEMENT("FastBottles"), 0)) { this->av1.bottleCatchType = BOTTLE_CATCH_NONE; } else { // 1 is subtracted because `sBottleCatchInfo` does not have an entry for `BOTTLE_CATCH_NONE` @@ -14689,13 +14689,13 @@ void Player_Action_SwingBottle(Player* this, PlayState* play) { this->av1.bottleCatchType = i + 1; this->av2.startedTextbox = false; - if (!CVarGetInteger(CVAR_ENHANCEMENT("FastDrops"), 0)) { + if (!CVarGetInteger(CVAR_ENHANCEMENT("FastBottles"), 0)) { this->stateFlags1 |= PLAYER_STATE1_IN_ITEM_CS | PLAYER_STATE1_IN_CUTSCENE; } this->interactRangeActor->parent = &this->actor; Player_UpdateBottleHeld(play, this, catchInfo->itemId, ABS(catchInfo->itemAction)); - if (!CVarGetInteger(CVAR_ENHANCEMENT("FastDrops"), 0)) { + if (!CVarGetInteger(CVAR_ENHANCEMENT("FastBottles"), 0)) { Player_AnimPlayOnceAdjusted(play, this, swingEntry->catchAnimation); func_80835EA4(play, 4); }