Merge branch 'develop' into mod_menu_2

This commit is contained in:
Pepe20129 2025-08-15 22:22:00 +02:00
commit 0caa33ddee
40 changed files with 688 additions and 475 deletions

View file

@ -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") 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/soh-cvars.cmake)
include(CMake/lus-cvars.cmake) include(CMake/lus-cvars.cmake)
@ -155,6 +155,9 @@ set(GFX_DEBUG_DISASSEMBLER ON)
set(GBI_UCODE F3DEX_GBI_2) set(GBI_UCODE F3DEX_GBI_2)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake") list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake")
# Enable MPQ and OTR support
set(INCLUDE_MPQ_SUPPORT ON)
################################################################################ ################################################################################
# Set CONTROLLERBUTTONS_T # Set CONTROLLERBUTTONS_T
################################################################################ ################################################################################
@ -165,6 +168,7 @@ add_compile_definitions(CONTROLLERBUTTONS_T=uint32_t)
################################################################################ ################################################################################
add_subdirectory(libultraship ${CMAKE_BINARY_DIR}/libultraship) add_subdirectory(libultraship ${CMAKE_BINARY_DIR}/libultraship)
target_compile_options(libultraship PRIVATE "${WARNING_OVERRIDE}") 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(ZAPDTR/ZAPD ${CMAKE_BINARY_DIR}/ZAPD)
add_subdirectory(OTRExporter) add_subdirectory(OTRExporter)
add_subdirectory(soh) add_subdirectory(soh)

@ -1 +1 @@
Subproject commit 6a3f6cd327b99f617b623e5b9a3afeae460aac2b Subproject commit 7f737f8be9580980f5a1fe7784d6e1045f0309da

View file

@ -1522,7 +1522,7 @@ typedef struct {
/* 0x34 */ s32 isEnabled; /* 0x34 */ s32 isEnabled;
} StickDirectionPrompt; } StickDirectionPrompt;
typedef struct { typedef struct FileChooseContext {
/* 0x00000 */ GameState state; /* 0x00000 */ GameState state;
/* 0x000A4 */ Vtx* windowVtx; /* 0x000A4 */ Vtx* windowVtx;
/* 0x000A8 */ u8* staticSegment; /* 0x000A8 */ u8* staticSegment;

View file

@ -7,7 +7,7 @@
#include "soh/Enhancements/randomizer/randomizerTypes.h" #include "soh/Enhancements/randomizer/randomizerTypes.h"
#include "soh/Enhancements/gameplaystats.h" #include "soh/Enhancements/gameplaystats.h"
#include "soh/Enhancements/randomizer/randomizer_entrance.h" #include "soh/Enhancements/randomizer/randomizer_entrance.h"
#include "soh/Enhancements/boss-rush/BossRushTypes.h" #include "soh/Enhancements/boss-rush/BossRush.h"
typedef enum { typedef enum {
/* 0x0 */ MAGIC_STATE_IDLE, // Regular gameplay /* 0x0 */ MAGIC_STATE_IDLE, // Regular gameplay

View file

@ -19,7 +19,7 @@ static std::array<const char*, ACTORCAT_MAX> sCatToStrArray{
"SWITCH", "BG", "PLAYER", "EXPLOSIVE", "NPC", "ENEMY", "PROP", "ITEMACTION", "MISC", "BOSS", "DOOR", "CHEST", "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<const char*, SCENE_ID_MAX> sSceneIdToStrArray{ static std::array<const char*, SCENE_ID_MAX> sSceneIdToStrArray{
#include "tables/scene_table.h" #include "tables/scene_table.h"

View file

@ -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") });

View file

@ -2,6 +2,7 @@
#include "sequence.h" #include "sequence.h"
#include "sfx.h" #include "sfx.h"
#include "soh/cvar_prefixes.h" #include "soh/cvar_prefixes.h"
#include "soh/Notification/Notification.h"
#include <vector> #include <vector>
#include <utils/StringHelper.h> #include <utils/StringHelper.h>
#include <libultraship/bridge.h> #include <libultraship/bridge.h>
@ -458,3 +459,11 @@ extern "C" bool AudioCollection_HasSequenceNum(uint16_t seqId) {
extern "C" size_t AudioCollection_SequenceMapSize() { extern "C" size_t AudioCollection_SequenceMapSize() {
return AudioCollection::Instance->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) });
}
}

View file

@ -73,4 +73,5 @@ void AudioCollection_AddToCollection(char* otrPath, uint16_t seqNum);
const char* AudioCollection_GetSequenceName(uint16_t seqId); const char* AudioCollection_GetSequenceName(uint16_t seqId);
bool AudioCollection_HasSequenceNum(uint16_t seqId); bool AudioCollection_HasSequenceNum(uint16_t seqId);
size_t AudioCollection_SequenceMapSize(); size_t AudioCollection_SequenceMapSize();
void AudioCollection_EmitSongNameNotification(s32 seqId);
#endif #endif

View file

@ -298,9 +298,12 @@ void Draw_SfxTab(const std::string& tabId, SeqType type, const std::string& tabN
ImGui::TableNextRow(); ImGui::TableNextRow();
ImGui::TableNextColumn(); ImGui::TableNextColumn();
ImGui::TextColored( if (isCurrentlyPlaying) {
UIWidgets::ColorValues.at(isCurrentlyPlaying ? UIWidgets::Colors::Yellow : UIWidgets::Colors::White), "%s", ImGui::TextColored(UIWidgets::ColorValues.at(UIWidgets::Colors::Yellow), "%s %s", ICON_FA_PLAY,
seqData.label.c_str()); seqData.label.c_str());
} else {
ImGui::Text("%s", seqData.label.c_str());
}
ImGui::TableNextColumn(); ImGui::TableNextColumn();
ImGui::PushItemWidth(-FLT_MIN); ImGui::PushItemWidth(-FLT_MIN);
const int initialValue = map.contains(currentValue) ? currentValue : defaultValue; const int initialValue = map.contains(currentValue) ? currentValue : defaultValue;

View file

@ -2,6 +2,8 @@
#include "soh/OTRGlobals.h" #include "soh/OTRGlobals.h"
#include "soh/Enhancements/game-interactor/GameInteractor.h" #include "soh/Enhancements/game-interactor/GameInteractor.h"
#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h" #include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
#include "soh_assets.h"
#include "soh/frame_interpolation.h"
#include <array> #include <array>
#include <string> #include <string>
@ -14,14 +16,87 @@ extern "C" {
#include "src/overlays/actors/ovl_Boss_Goma/z_boss_goma.h" #include "src/overlays/actors/ovl_Boss_Goma/z_boss_goma.h"
#include "src/overlays/actors/ovl_Boss_Mo/z_boss_mo.h" #include "src/overlays/actors/ovl_Boss_Mo/z_boss_mo.h"
#include "src/overlays/actors/ovl_Door_Warp1/z_door_warp1.h" #include "src/overlays/actors/ovl_Door_Warp1/z_door_warp1.h"
extern PlayState* gPlayState; #include "src/overlays/gamestates/ovl_file_choose/file_choose.h"
#include "objects/gameplay_keep/gameplay_keep.h"
Gfx* KaleidoScope_QuadTextureIA8(Gfx* gfx, void* texture, s16 width, s16 height, u16 point);
#include "textures/icon_item_nes_static/icon_item_nes_static.h" #include "textures/icon_item_nes_static/icon_item_nes_static.h"
#include "textures/icon_item_ger_static/icon_item_ger_static.h" #include "textures/icon_item_ger_static/icon_item_ger_static.h"
#include "textures/icon_item_fra_static/icon_item_fra_static.h" #include "textures/icon_item_fra_static/icon_item_fra_static.h"
extern PlayState* gPlayState;
Gfx* KaleidoScope_QuadTextureIA8(Gfx* gfx, void* texture, s16 width, s16 height, u16 point);
void FileChoose_UpdateStickDirectionPromptAnim(GameState* thisx);
void FileChoose_DrawTextRec(GraphicsContext* gfxCtx, s32 r, s32 g, s32 b, s32 a, f32 x, f32 y, f32 z, s32 s, s32 t,
f32 dx, f32 dy);
} }
typedef enum {
BR_CHOICE_BOSSES_ALL,
BR_CHOICE_BOSSES_CHILD,
BR_CHOICE_BOSSES_ADULT,
BR_CHOICE_BOSSES_GANONDORF_GANON
} BossRushBossesChoices;
typedef enum {
BR_CHOICE_HEARTS_10,
BR_CHOICE_HEARTS_15,
BR_CHOICE_HEARTS_20,
BR_CHOICE_HEARTS_3,
BR_CHOICE_HEARTS_5,
BR_CHOICE_HEARTS_7
} BossRushHeartsChoices;
typedef enum {
BR_CHOICE_AMMO_LIMITED,
BR_CHOICE_AMMO_FULL,
BR_CHOICE_AMMO_MAXED,
} BossRushAmmoChoices;
typedef enum {
BR_CHOICE_HEAL_GANONDORF,
BR_CHOICE_HEAL_EVERYBOSS,
BR_CHOICE_HEAL_NEVER,
} BossRushHealChoices;
typedef enum {
BR_CHOICE_MAGIC_SINGLE,
BR_CHOICE_MAGIC_DOUBLE,
} BossRushMagicChoices;
typedef enum {
BR_CHOICE_BGS_NO,
BR_CHOICE_BGS_YES,
} BossRushBgsChoices;
typedef enum {
BR_CHOICE_BOTTLE_NO,
BR_CHOICE_BOTTLE_EMPTY,
BR_CHOICE_BOTTLE_FAIRY,
BR_CHOICE_BOTTLE_REDPOTION,
BR_CHOICE_BOTTLE_GREENPOTION,
BR_CHOICE_BOTTLE_BLUEPOTION
} BossRushBottleChoices;
typedef enum {
BR_CHOICE_LONGSHOT_NO,
BR_CHOICE_LONGSHOT_YES,
} BossRushLongshotChoices;
typedef enum {
BR_CHOICE_HOVERBOOTS_NO,
BR_CHOICE_HOVERBOOTS_YES,
} BossRushHoverBootsChoices;
typedef enum {
BR_CHOICE_BUNNYHOOD_NO,
BR_CHOICE_BUNNYHOOD_YES,
} BossRushBunnyHoodChoices;
typedef enum {
BR_CHOICE_TIMER_YES,
BR_CHOICE_TIMER_NO,
} BossRushTimerChoices;
typedef struct BossRushSetting { typedef struct BossRushSetting {
std::array<std::string, LANGUAGE_MAX> name; std::array<std::string, LANGUAGE_MAX> name;
std::vector<std::array<std::string, LANGUAGE_MAX>> choices; std::vector<std::array<std::string, LANGUAGE_MAX>> choices;
@ -114,6 +189,180 @@ u8 BossRush_GetSettingOptionsAmount(u8 optionIndex) {
return static_cast<u8>(BossRushOptions[optionIndex].choices.size()); return static_cast<u8>(BossRushOptions[optionIndex].choices.size());
} }
void FileChoose_UpdateBossRushMenu(GameState* gameState) {
static s8 sLastBossRushOptionIndex = -1;
static s8 sLastBossRushOptionValue = -1;
FileChoose_UpdateStickDirectionPromptAnim(gameState);
FileChooseContext* fileChooseContext = (FileChooseContext*)gameState;
Input* input = &fileChooseContext->state.input[0];
bool dpad = CVarGetInteger(CVAR_SETTING("DpadInText"), 0);
// Fade in elements after opening Boss Rush options menu
fileChooseContext->bossRushUIAlpha += 25;
if (fileChooseContext->bossRushUIAlpha > 255) {
fileChooseContext->bossRushUIAlpha = 255;
}
// Animate up/down arrows.
fileChooseContext->bossRushArrowOffset += 1;
if (fileChooseContext->bossRushArrowOffset >= 30) {
fileChooseContext->bossRushArrowOffset = 0;
}
// Move menu selection up or down.
if (ABS(fileChooseContext->stickRelY) > 30 || (dpad && CHECK_BTN_ANY(input->press.button, BTN_DDOWN | BTN_DUP))) {
// Move down
if (fileChooseContext->stickRelY < -30 || (dpad && CHECK_BTN_ANY(input->press.button, BTN_DDOWN))) {
// When selecting past the last option, cycle back to the first option.
if ((fileChooseContext->bossRushIndex + 1) > BR_OPTIONS_MAX - 1) {
fileChooseContext->bossRushIndex = 0;
fileChooseContext->bossRushOffset = 0;
} else {
fileChooseContext->bossRushIndex++;
// When last visible option is selected when moving down, offset the list down by one.
if (fileChooseContext->bossRushIndex - fileChooseContext->bossRushOffset >
BOSSRUSH_MAX_OPTIONS_ON_SCREEN - 1) {
fileChooseContext->bossRushOffset++;
}
}
} else if (fileChooseContext->stickRelY > 30 || (dpad && CHECK_BTN_ANY(input->press.button, BTN_DUP))) {
// When selecting past the first option, cycle back to the last option and offset the list to view it
// properly.
if ((fileChooseContext->bossRushIndex - 1) < 0) {
fileChooseContext->bossRushIndex = BR_OPTIONS_MAX - 1;
fileChooseContext->bossRushOffset =
fileChooseContext->bossRushIndex - BOSSRUSH_MAX_OPTIONS_ON_SCREEN + 1;
} else {
// When first visible option is selected when moving up, offset the list up by one.
if (fileChooseContext->bossRushIndex - fileChooseContext->bossRushOffset == 0) {
fileChooseContext->bossRushOffset--;
}
fileChooseContext->bossRushIndex--;
}
}
Audio_PlaySoundGeneral(NA_SE_SY_FSEL_CURSOR, &gSfxDefaultPos, 4, &gSfxDefaultFreqAndVolScale,
&gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb);
}
// Cycle through choices for currently selected option.
if (ABS(fileChooseContext->stickRelX) > 30 ||
(dpad && CHECK_BTN_ANY(input->press.button, BTN_DLEFT | BTN_DRIGHT))) {
if (fileChooseContext->stickRelX > 30 || (dpad && CHECK_BTN_ANY(input->press.button, BTN_DRIGHT))) {
// If exceeding the amount of choices for the selected option, cycle back to the first.
if ((gSaveContext.ship.quest.data.bossRush.options[fileChooseContext->bossRushIndex] + 1) ==
BossRush_GetSettingOptionsAmount(fileChooseContext->bossRushIndex)) {
gSaveContext.ship.quest.data.bossRush.options[fileChooseContext->bossRushIndex] = 0;
} else {
gSaveContext.ship.quest.data.bossRush.options[fileChooseContext->bossRushIndex]++;
}
} else if (fileChooseContext->stickRelX < -30 || (dpad && CHECK_BTN_ANY(input->press.button, BTN_DLEFT))) {
// If cycling back when already at the first choice for the selected option, cycle back to the last choice.
if ((gSaveContext.ship.quest.data.bossRush.options[fileChooseContext->bossRushIndex] - 1) < 0) {
gSaveContext.ship.quest.data.bossRush.options[fileChooseContext->bossRushIndex] =
BossRush_GetSettingOptionsAmount(fileChooseContext->bossRushIndex) - 1;
} else {
gSaveContext.ship.quest.data.bossRush.options[fileChooseContext->bossRushIndex]--;
}
}
Audio_PlaySoundGeneral(NA_SE_SY_FSEL_CURSOR, &gSfxDefaultPos, 4, &gSfxDefaultFreqAndVolScale,
&gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb);
}
if (sLastBossRushOptionIndex != fileChooseContext->bossRushIndex ||
sLastBossRushOptionValue != gSaveContext.ship.quest.data.bossRush.options[fileChooseContext->bossRushIndex]) {
GameInteractor_ExecuteOnUpdateFileBossRushOptionSelection(
fileChooseContext->bossRushIndex,
gSaveContext.ship.quest.data.bossRush.options[fileChooseContext->bossRushIndex]);
sLastBossRushOptionIndex = fileChooseContext->bossRushIndex;
sLastBossRushOptionValue = gSaveContext.ship.quest.data.bossRush.options[fileChooseContext->bossRushIndex];
}
if (CHECK_BTN_ALL(input->press.button, BTN_B)) {
fileChooseContext->configMode = CM_BOSS_RUSH_TO_QUEST;
return;
}
// Load into the game.
if (CHECK_BTN_ALL(input->press.button, BTN_START) || CHECK_BTN_ALL(input->press.button, BTN_A)) {
Audio_PlaySoundGeneral(NA_SE_SY_FSEL_DECIDE_L, &gSfxDefaultPos, 4, &gSfxDefaultFreqAndVolScale,
&gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb);
fileChooseContext->buttonIndex = 0xFE;
fileChooseContext->menuMode = FS_MENU_MODE_SELECT;
fileChooseContext->selectMode = SM_FADE_OUT;
fileChooseContext->prevConfigMode = fileChooseContext->configMode;
return;
}
}
void FileChoose_DrawBossRushMenuWindowContents(FileChooseContext* fileChooseContext) {
OPEN_DISPS(fileChooseContext->state.gfxCtx);
uint8_t language = (gSaveContext.language == LANGUAGE_JPN) ? LANGUAGE_ENG : gSaveContext.language;
uint8_t listOffset = fileChooseContext->bossRushOffset;
uint8_t textAlpha = fileChooseContext->bossRushUIAlpha;
// Draw arrows to indicate that the list can scroll up or down.
// Arrow up
if (listOffset > 0) {
uint16_t arrowUpX = 140;
uint16_t arrowUpY = 76 - (fileChooseContext->bossRushArrowOffset / 10);
gDPLoadTextureBlock(POLY_OPA_DISP++, gArrowUpTex, G_IM_FMT_IA, G_IM_SIZ_16b, 16, 16, 0,
G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD,
G_TX_NOLOD);
gSPWideTextureRectangle(POLY_OPA_DISP++, arrowUpX << 2, arrowUpY << 2, (arrowUpX + 8) << 2, (arrowUpY + 8) << 2,
G_TX_RENDERTILE, 0, 0, (1 << 11), (1 << 11));
}
// Arrow down
if (BR_OPTIONS_MAX - listOffset > BOSSRUSH_MAX_OPTIONS_ON_SCREEN) {
uint16_t arrowDownX = 140;
uint16_t arrowDownY = 181 + (fileChooseContext->bossRushArrowOffset / 10);
gDPLoadTextureBlock(POLY_OPA_DISP++, gArrowDownTex, G_IM_FMT_IA, G_IM_SIZ_16b, 16, 16, 0,
G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD,
G_TX_NOLOD);
gSPWideTextureRectangle(POLY_OPA_DISP++, arrowDownX << 2, arrowDownY << 2, (arrowDownX + 8) << 2,
(arrowDownY + 8) << 2, G_TX_RENDERTILE, 0, 0, (1 << 11), (1 << 11));
}
// Draw options. There's more options than what fits on the screen, so the visible options
// depend on the current offset of the list. Currently selected option pulses in
// color and has arrows surrounding the option.
for (uint8_t i = listOffset; i - listOffset < BOSSRUSH_MAX_OPTIONS_ON_SCREEN; i++) {
uint16_t textYOffset = (i - listOffset) * 16;
// Option name.
Interface_DrawTextLine(fileChooseContext->state.gfxCtx, (char*)BossRush_GetSettingName(i, language), 65,
(87 + textYOffset), 255, 255, 80, textAlpha, 0.8f, true);
// Selected choice for option.
uint16_t finalKerning = Interface_DrawTextLine(
fileChooseContext->state.gfxCtx,
(char*)BossRush_GetSettingChoiceName(i, gSaveContext.ship.quest.data.bossRush.options[i], language), 165,
(87 + textYOffset), 255, 255, 255, textAlpha, 0.8f, true);
// Draw arrows around selected option.
if (fileChooseContext->bossRushIndex == i) {
Gfx_SetupDL_39Opa(fileChooseContext->state.gfxCtx);
gDPSetCombineMode(POLY_OPA_DISP++, G_CC_MODULATEIA_PRIM, G_CC_MODULATEIA_PRIM);
gDPLoadTextureBlock(POLY_OPA_DISP++, gArrowCursorTex, G_IM_FMT_IA, G_IM_SIZ_8b, 16, 24, 0,
G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, 4, G_TX_NOMASK, G_TX_NOLOD,
G_TX_NOLOD);
FileChoose_DrawTextRec(fileChooseContext->state.gfxCtx, fileChooseContext->stickLeftPrompt.arrowColorR,
fileChooseContext->stickLeftPrompt.arrowColorG,
fileChooseContext->stickLeftPrompt.arrowColorB, textAlpha, 160, (92 + textYOffset),
0.42f, 0, 0, -1.0f, 1.0f);
FileChoose_DrawTextRec(fileChooseContext->state.gfxCtx, fileChooseContext->stickRightPrompt.arrowColorR,
fileChooseContext->stickRightPrompt.arrowColorG,
fileChooseContext->stickRightPrompt.arrowColorB, textAlpha, (171 + finalKerning),
(92 + textYOffset), 0.42f, 0, 0, 1.0f, 1.0f);
}
}
CLOSE_DISPS(fileChooseContext->state.gfxCtx);
}
void BossRush_SpawnBlueWarps(PlayState* play) { void BossRush_SpawnBlueWarps(PlayState* play) {
// Spawn blue warps in Chamber of Sages based on what bosses have been defeated. // Spawn blue warps in Chamber of Sages based on what bosses have been defeated.
@ -316,7 +565,7 @@ void BossRush_HandleCompleteBoss(PlayState* play) {
} }
} }
void BossRush_InitSave() { extern "C" void BossRush_InitSave() {
// Set player name to Lonk for the few textboxes that show up during Boss Rush. Player can't input their own name. // Set player name to Lonk for the few textboxes that show up during Boss Rush. Player can't input their own name.
std::array<char, 8> brPlayerName = { 21, 50, 49, 46, 62, 62, 62, 62 }; std::array<char, 8> brPlayerName = { 21, 50, 49, 46, 62, 62, 62, 62 };
@ -609,6 +858,17 @@ void BossRush_OnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, va_li
*should = false; *should = false;
break; break;
} }
// Handle the heal on blue warp
case VB_BLUE_WARP_CONSIDER_ADULT_IN_RANGE: {
if (*should) {
BossRush_HandleBlueWarpHeal(gPlayState);
}
break;
}
case VB_SHOW_GAMEPLAY_TIMER: {
*should |= gSaveContext.ship.quest.data.bossRush.options[BR_OPTIONS_TIMER] == BR_CHOICE_TIMER_YES;
break;
}
// Prevent saving // Prevent saving
case VB_BE_ABLE_TO_SAVE: case VB_BE_ABLE_TO_SAVE:
// Disable doors so the player can't leave the boss rooms backwards. // Disable doors so the player can't leave the boss rooms backwards.
@ -629,25 +889,6 @@ void BossRush_OnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, va_li
va_end(args); va_end(args);
} }
void BossRush_OnActorInitHandler(void* actorRef) {
Actor* actor = static_cast<Actor*>(actorRef);
if (actor->id == ACTOR_DEMO_SA && gPlayState->sceneNum == SCENE_CHAMBER_OF_THE_SAGES) {
BossRush_SpawnBlueWarps(gPlayState);
Actor_Kill(actor);
GET_PLAYER(gPlayState)->actor.world.rot.y = GET_PLAYER(gPlayState)->actor.shape.rot.y = 27306;
return;
}
// Remove chests, mainly for the chest in King Dodongo's boss room.
// Remove bushes, used in Gohma's arena.
// Remove pots, used in Barinade's and Ganondorf's arenas.
if (actor->id == ACTOR_EN_KUSA || actor->id == ACTOR_OBJ_TSUBO || actor->id == ACTOR_EN_BOX) {
Actor_Kill(actor);
return;
}
}
void BossRush_OnSceneInitHandler(s16 sceneNum) { void BossRush_OnSceneInitHandler(s16 sceneNum) {
// Unpause the timer when the scene loaded isn't the Chamber of Sages. // Unpause the timer when the scene loaded isn't the Chamber of Sages.
if (sceneNum != SCENE_CHAMBER_OF_THE_SAGES) { if (sceneNum != SCENE_CHAMBER_OF_THE_SAGES) {
@ -667,38 +908,32 @@ void BossRush_OnBlueWarpUpdate(void* actor) {
} }
} }
void BossRush_RegisterHooks() { void RegisterBossRush() {
static u32 onVanillaBehaviorHook = 0; COND_HOOK(OnLoadGame, true, [](int32_t fileNum) {
static u32 onSceneInitHook = 0; COND_ID_HOOK(OnActorInit, ACTOR_DEMO_SA, IS_BOSS_RUSH, [](void* actorPtr) {
static u32 onActorInitHook = 0; BossRush_SpawnBlueWarps(gPlayState);
static u32 onBossDefeatHook = 0; Actor_Kill((Actor*)actorPtr);
static u32 onActorUpdate = 0; GET_PLAYER(gPlayState)->actor.world.rot.y = 27306;
GET_PLAYER(gPlayState)->actor.shape.rot.y = 27306;
});
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnLoadGame>([](int32_t fileNum) { // Remove bushes, used in Gohma's arena
GameInteractor::Instance->UnregisterGameHook<GameInteractor::OnVanillaBehavior>(onVanillaBehaviorHook); COND_ID_HOOK(OnActorInit, ACTOR_EN_KUSA, IS_BOSS_RUSH, [](void* actorPtr) { Actor_Kill((Actor*)actorPtr); });
GameInteractor::Instance->UnregisterGameHook<GameInteractor::OnSceneInit>(onSceneInitHook);
GameInteractor::Instance->UnregisterGameHook<GameInteractor::OnActorInit>(onActorInitHook);
GameInteractor::Instance->UnregisterGameHook<GameInteractor::OnBossDefeat>(onBossDefeatHook);
GameInteractor::Instance->UnregisterGameHookForID<GameInteractor::OnActorUpdate>(onActorUpdate);
onVanillaBehaviorHook = 0; // Remove pots, used in Barinade's and Ganondorf's arenas
onSceneInitHook = 0; COND_ID_HOOK(OnActorInit, ACTOR_OBJ_TSUBO, IS_BOSS_RUSH, [](void* actorPtr) { Actor_Kill((Actor*)actorPtr); });
onActorInitHook = 0;
onBossDefeatHook = 0;
onActorUpdate = 0;
if (!IS_BOSS_RUSH) // Remove chests, mainly for the chest in King Dodongo's boss room
return; COND_ID_HOOK(OnActorInit, ACTOR_EN_BOX, IS_BOSS_RUSH, [](void* actorPtr) { Actor_Kill((Actor*)actorPtr); });
onVanillaBehaviorHook = GameInteractor::Instance->RegisterGameHook<GameInteractor::OnVanillaBehavior>( COND_HOOK(OnVanillaBehavior, IS_BOSS_RUSH, BossRush_OnVanillaBehaviorHandler);
BossRush_OnVanillaBehaviorHandler);
onSceneInitHook = COND_HOOK(OnSceneInit, IS_BOSS_RUSH, BossRush_OnSceneInitHandler);
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnSceneInit>(BossRush_OnSceneInitHandler);
onActorInitHook = COND_HOOK(OnBossDefeat, IS_BOSS_RUSH, BossRush_OnBossDefeatHandler);
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnActorInit>(BossRush_OnActorInitHandler);
onBossDefeatHook = COND_ID_HOOK(OnActorUpdate, ACTOR_DOOR_WARP1, IS_BOSS_RUSH, BossRush_OnBlueWarpUpdate);
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnBossDefeat>(BossRush_OnBossDefeatHandler);
onActorUpdate = GameInteractor::Instance->RegisterGameHookForID<GameInteractor::OnActorUpdate>(
ACTOR_DOOR_WARP1, BossRush_OnBlueWarpUpdate);
}); });
} }
static RegisterShipInitFunc initFunc(RegisterBossRush);

View file

@ -1,16 +1,41 @@
#pragma once #pragma once
#include "z64.h" #include <libultraship/libultra/types.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
void BossRush_HandleBlueWarpHeal(PlayState* play); struct GameState;
void BossRush_InitSave(); struct FileChooseContext;
void FileChoose_UpdateBossRushMenu(struct GameState* gameState);
void FileChoose_DrawBossRushMenuWindowContents(struct FileChooseContext* fileChooseContext);
const char* BossRush_GetSettingName(u8 optionIndex, u8 language); const char* BossRush_GetSettingName(u8 optionIndex, u8 language);
const char* BossRush_GetSettingChoiceName(u8 optionIndex, u8 choiceIndex, u8 language); const char* BossRush_GetSettingChoiceName(u8 optionIndex, u8 choiceIndex, u8 language);
u8 BossRush_GetSettingOptionsAmount(u8 optionIndex); u8 BossRush_GetSettingOptionsAmount(u8 optionIndex);
void BossRush_RegisterHooks();
#ifdef __cplusplus #ifdef __cplusplus
}; };
#endif #endif
#define BOSSRUSH_MAX_OPTIONS_ON_SCREEN 6
typedef enum {
BR_OPTIONS_BOSSES,
BR_OPTIONS_HEARTS,
BR_OPTIONS_AMMO,
BR_OPTIONS_HEAL,
BR_OPTIONS_HYPERBOSSES,
BR_OPTIONS_MAGIC,
BR_OPTIONS_BGS,
BR_OPTIONS_BOTTLE,
BR_OPTIONS_LONGSHOT,
BR_OPTIONS_HOVERBOOTS,
BR_OPTIONS_BUNNYHOOD,
BR_OPTIONS_TIMER,
BR_OPTIONS_MAX,
} BossRushOptionEnums;
typedef enum {
BR_CHOICE_HYPERBOSSES_NO,
BR_CHOICE_HYPERBOSSES_YES,
} BossRushHyperBossesChoices;

View file

@ -1,91 +0,0 @@
#pragma once
#define BOSSRUSH_MAX_OPTIONS_ON_SCREEN 6
typedef enum {
BR_OPTIONS_BOSSES,
BR_OPTIONS_HEARTS,
BR_OPTIONS_AMMO,
BR_OPTIONS_HEAL,
BR_OPTIONS_HYPERBOSSES,
BR_OPTIONS_MAGIC,
BR_OPTIONS_BGS,
BR_OPTIONS_BOTTLE,
BR_OPTIONS_LONGSHOT,
BR_OPTIONS_HOVERBOOTS,
BR_OPTIONS_BUNNYHOOD,
BR_OPTIONS_TIMER,
BR_OPTIONS_MAX,
} BossRushOptionEnums;
typedef enum {
BR_CHOICE_BOSSES_ALL,
BR_CHOICE_BOSSES_CHILD,
BR_CHOICE_BOSSES_ADULT,
BR_CHOICE_BOSSES_GANONDORF_GANON
} BossRushBossesChoices;
typedef enum {
BR_CHOICE_HEARTS_10,
BR_CHOICE_HEARTS_15,
BR_CHOICE_HEARTS_20,
BR_CHOICE_HEARTS_3,
BR_CHOICE_HEARTS_5,
BR_CHOICE_HEARTS_7
} BossRushHeartsChoices;
typedef enum {
BR_CHOICE_AMMO_LIMITED,
BR_CHOICE_AMMO_FULL,
BR_CHOICE_AMMO_MAXED,
} BossRushAmmoChoices;
typedef enum {
BR_CHOICE_HEAL_GANONDORF,
BR_CHOICE_HEAL_EVERYBOSS,
BR_CHOICE_HEAL_NEVER,
} BossRushHealChoices;
typedef enum {
BR_CHOICE_HYPERBOSSES_NO,
BR_CHOICE_HYPERBOSSES_YES,
} BossRushHyperBossesChoices;
typedef enum {
BR_CHOICE_MAGIC_SINGLE,
BR_CHOICE_MAGIC_DOUBLE,
} BossRushMagicChoices;
typedef enum {
BR_CHOICE_BGS_NO,
BR_CHOICE_BGS_YES,
} BossRushBgsChoices;
typedef enum {
BR_CHOICE_BOTTLE_NO,
BR_CHOICE_BOTTLE_EMPTY,
BR_CHOICE_BOTTLE_FAIRY,
BR_CHOICE_BOTTLE_REDPOTION,
BR_CHOICE_BOTTLE_GREENPOTION,
BR_CHOICE_BOTTLE_BLUEPOTION
} BossRushBottleChoices;
typedef enum {
BR_CHOICE_LONGSHOT_NO,
BR_CHOICE_LONGSHOT_YES,
} BossRushLongshotChoices;
typedef enum {
BR_CHOICE_HOVERBOOTS_NO,
BR_CHOICE_HOVERBOOTS_YES,
} BossRushHoverBootsChoices;
typedef enum {
BR_CHOICE_BUNNYHOOD_NO,
BR_CHOICE_BUNNYHOOD_YES,
} BossRushBunnyHoodChoices;
typedef enum {
BR_CHOICE_TIMER_YES,
BR_CHOICE_TIMER_NO,
} BossRushTimerChoices;

View file

@ -112,7 +112,9 @@ typedef enum {
typedef enum { typedef enum {
TIME_TRAVEL_DISABLED, TIME_TRAVEL_DISABLED,
TIME_TRAVEL_OOT, TIME_TRAVEL_OOT,
TIME_TRAVEL_OOT_MS,
TIME_TRAVEL_ANY, TIME_TRAVEL_ANY,
TIME_TRAVEL_ANY_MS
} TimeTravelType; } TimeTravelType;
typedef enum { typedef enum {

View file

@ -50,7 +50,7 @@ namespace GameInteractionEffect {
// MARK: - Flags // MARK: - Flags
GameInteractionEffectQueryResult SetSceneFlag::CanBeApplied() { GameInteractionEffectQueryResult SetSceneFlag::CanBeApplied() {
if (!GameInteractor::IsSaveLoaded()) { if (!GameInteractor::IsSaveLoaded(true)) {
return GameInteractionEffectQueryResult::TemporarilyNotPossible; return GameInteractionEffectQueryResult::TemporarilyNotPossible;
} }
@ -62,7 +62,7 @@ void SetSceneFlag::_Apply() {
} }
GameInteractionEffectQueryResult UnsetSceneFlag::CanBeApplied() { GameInteractionEffectQueryResult UnsetSceneFlag::CanBeApplied() {
if (!GameInteractor::IsSaveLoaded()) { if (!GameInteractor::IsSaveLoaded(true)) {
return GameInteractionEffectQueryResult::TemporarilyNotPossible; return GameInteractionEffectQueryResult::TemporarilyNotPossible;
} }
@ -74,7 +74,7 @@ void UnsetSceneFlag::_Apply() {
} }
GameInteractionEffectQueryResult SetFlag::CanBeApplied() { GameInteractionEffectQueryResult SetFlag::CanBeApplied() {
if (!GameInteractor::IsSaveLoaded()) { if (!GameInteractor::IsSaveLoaded(true)) {
return GameInteractionEffectQueryResult::TemporarilyNotPossible; return GameInteractionEffectQueryResult::TemporarilyNotPossible;
} }
@ -86,7 +86,7 @@ void SetFlag::_Apply() {
} }
GameInteractionEffectQueryResult UnsetFlag::CanBeApplied() { GameInteractionEffectQueryResult UnsetFlag::CanBeApplied() {
if (!GameInteractor::IsSaveLoaded()) { if (!GameInteractor::IsSaveLoaded(true)) {
return GameInteractionEffectQueryResult::TemporarilyNotPossible; return GameInteractionEffectQueryResult::TemporarilyNotPossible;
} }
@ -99,7 +99,7 @@ void UnsetFlag::_Apply() {
// MARK: - ModifyHeartContainers // MARK: - ModifyHeartContainers
GameInteractionEffectQueryResult ModifyHeartContainers::CanBeApplied() { GameInteractionEffectQueryResult ModifyHeartContainers::CanBeApplied() {
if (!GameInteractor::IsSaveLoaded()) { if (!GameInteractor::IsSaveLoaded(true)) {
return GameInteractionEffectQueryResult::TemporarilyNotPossible; return GameInteractionEffectQueryResult::TemporarilyNotPossible;
} else if ((parameters[0] > 0 && (gSaveContext.healthCapacity + (parameters[0] * 0x10) > 0x140)) || } else if ((parameters[0] > 0 && (gSaveContext.healthCapacity + (parameters[0] * 0x10) > 0x140)) ||
(parameters[0] < 0 && (gSaveContext.healthCapacity + (parameters[0] * 0x10) < 0x10))) { (parameters[0] < 0 && (gSaveContext.healthCapacity + (parameters[0] * 0x10) < 0x10))) {
@ -115,7 +115,7 @@ void ModifyHeartContainers::_Apply() {
// MARK: - FillMagic // MARK: - FillMagic
GameInteractionEffectQueryResult FillMagic::CanBeApplied() { GameInteractionEffectQueryResult FillMagic::CanBeApplied() {
if (!GameInteractor::IsSaveLoaded()) { if (!GameInteractor::IsSaveLoaded(true)) {
return GameInteractionEffectQueryResult::TemporarilyNotPossible; return GameInteractionEffectQueryResult::TemporarilyNotPossible;
} else if (!gSaveContext.isMagicAcquired || gSaveContext.magic >= ((gSaveContext.isDoubleMagicAcquired + 1) * 48)) { } else if (!gSaveContext.isMagicAcquired || gSaveContext.magic >= ((gSaveContext.isDoubleMagicAcquired + 1) * 48)) {
return GameInteractionEffectQueryResult::NotPossible; return GameInteractionEffectQueryResult::NotPossible;
@ -129,7 +129,7 @@ void FillMagic::_Apply() {
// MARK: - EmptyMagic // MARK: - EmptyMagic
GameInteractionEffectQueryResult EmptyMagic::CanBeApplied() { GameInteractionEffectQueryResult EmptyMagic::CanBeApplied() {
if (!GameInteractor::IsSaveLoaded()) { if (!GameInteractor::IsSaveLoaded(true)) {
return GameInteractionEffectQueryResult::TemporarilyNotPossible; return GameInteractionEffectQueryResult::TemporarilyNotPossible;
} else if (!gSaveContext.isMagicAcquired || gSaveContext.magic <= 0) { } else if (!gSaveContext.isMagicAcquired || gSaveContext.magic <= 0) {
return GameInteractionEffectQueryResult::NotPossible; return GameInteractionEffectQueryResult::NotPossible;
@ -143,7 +143,7 @@ void EmptyMagic::_Apply() {
// MARK: - ModifyRupees // MARK: - ModifyRupees
GameInteractionEffectQueryResult ModifyRupees::CanBeApplied() { GameInteractionEffectQueryResult ModifyRupees::CanBeApplied() {
if (!GameInteractor::IsSaveLoaded()) { if (!GameInteractor::IsSaveLoaded(true)) {
return GameInteractionEffectQueryResult::TemporarilyNotPossible; return GameInteractionEffectQueryResult::TemporarilyNotPossible;
} else if ((parameters[0] < 0 && gSaveContext.rupees <= 0) || } else if ((parameters[0] < 0 && gSaveContext.rupees <= 0) ||
(parameters[0] > 0 && gSaveContext.rupees >= CUR_CAPACITY(UPG_WALLET))) { (parameters[0] > 0 && gSaveContext.rupees >= CUR_CAPACITY(UPG_WALLET))) {
@ -158,7 +158,7 @@ void ModifyRupees::_Apply() {
// MARK: - NoUI // MARK: - NoUI
GameInteractionEffectQueryResult NoUI::CanBeApplied() { GameInteractionEffectQueryResult NoUI::CanBeApplied() {
if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused()) { if (!GameInteractor::IsSaveLoaded(true) || GameInteractor::IsGameplayPaused()) {
return GameInteractionEffectQueryResult::TemporarilyNotPossible; return GameInteractionEffectQueryResult::TemporarilyNotPossible;
} else { } else {
return GameInteractionEffectQueryResult::Possible; return GameInteractionEffectQueryResult::Possible;
@ -173,7 +173,7 @@ void NoUI::_Remove() {
// MARK: - ModifyGravity // MARK: - ModifyGravity
GameInteractionEffectQueryResult ModifyGravity::CanBeApplied() { GameInteractionEffectQueryResult ModifyGravity::CanBeApplied() {
if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused()) { if (!GameInteractor::IsSaveLoaded(true) || GameInteractor::IsGameplayPaused()) {
return GameInteractionEffectQueryResult::TemporarilyNotPossible; return GameInteractionEffectQueryResult::TemporarilyNotPossible;
} else { } else {
return GameInteractionEffectQueryResult::Possible; return GameInteractionEffectQueryResult::Possible;
@ -188,7 +188,7 @@ void ModifyGravity::_Remove() {
// MARK: - ModifyHealth // MARK: - ModifyHealth
GameInteractionEffectQueryResult ModifyHealth::CanBeApplied() { GameInteractionEffectQueryResult ModifyHealth::CanBeApplied() {
if (!GameInteractor::IsSaveLoaded()) { if (!GameInteractor::IsSaveLoaded(true)) {
return GameInteractionEffectQueryResult::TemporarilyNotPossible; return GameInteractionEffectQueryResult::TemporarilyNotPossible;
} else if ((parameters[0] > 0 && gSaveContext.health == gSaveContext.healthCapacity) || } else if ((parameters[0] > 0 && gSaveContext.health == gSaveContext.healthCapacity) ||
(parameters[0] < 0 && (gSaveContext.health + (16 * parameters[0]) <= 0))) { (parameters[0] < 0 && (gSaveContext.health + (16 * parameters[0]) <= 0))) {
@ -204,7 +204,7 @@ void ModifyHealth::_Apply() {
// MARK: - SetPlayerHealth // MARK: - SetPlayerHealth
GameInteractionEffectQueryResult SetPlayerHealth::CanBeApplied() { GameInteractionEffectQueryResult SetPlayerHealth::CanBeApplied() {
Player* player = GET_PLAYER(gPlayState); Player* player = GET_PLAYER(gPlayState);
if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused()) { if (!GameInteractor::IsSaveLoaded(true) || GameInteractor::IsGameplayPaused()) {
return GameInteractionEffectQueryResult::TemporarilyNotPossible; return GameInteractionEffectQueryResult::TemporarilyNotPossible;
} else { } else {
return GameInteractionEffectQueryResult::Possible; return GameInteractionEffectQueryResult::Possible;
@ -217,7 +217,7 @@ void SetPlayerHealth::_Apply() {
// MARK: - FreezePlayer // MARK: - FreezePlayer
GameInteractionEffectQueryResult FreezePlayer::CanBeApplied() { GameInteractionEffectQueryResult FreezePlayer::CanBeApplied() {
Player* player = GET_PLAYER(gPlayState); Player* player = GET_PLAYER(gPlayState);
if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused() || !PlayerGrounded(player)) { if (!GameInteractor::IsSaveLoaded(true) || GameInteractor::IsGameplayPaused() || !PlayerGrounded(player)) {
return GameInteractionEffectQueryResult::TemporarilyNotPossible; return GameInteractionEffectQueryResult::TemporarilyNotPossible;
} else { } else {
return GameInteractionEffectQueryResult::Possible; return GameInteractionEffectQueryResult::Possible;
@ -230,7 +230,7 @@ void FreezePlayer::_Apply() {
// MARK: - BurnPlayer // MARK: - BurnPlayer
GameInteractionEffectQueryResult BurnPlayer::CanBeApplied() { GameInteractionEffectQueryResult BurnPlayer::CanBeApplied() {
Player* player = GET_PLAYER(gPlayState); Player* player = GET_PLAYER(gPlayState);
if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused() || !PlayerGrounded(player)) { if (!GameInteractor::IsSaveLoaded(true) || GameInteractor::IsGameplayPaused() || !PlayerGrounded(player)) {
return GameInteractionEffectQueryResult::TemporarilyNotPossible; return GameInteractionEffectQueryResult::TemporarilyNotPossible;
} else { } else {
return GameInteractionEffectQueryResult::Possible; return GameInteractionEffectQueryResult::Possible;
@ -243,7 +243,7 @@ void BurnPlayer::_Apply() {
// MARK: - ElectrocutePlayer // MARK: - ElectrocutePlayer
GameInteractionEffectQueryResult ElectrocutePlayer::CanBeApplied() { GameInteractionEffectQueryResult ElectrocutePlayer::CanBeApplied() {
Player* player = GET_PLAYER(gPlayState); Player* player = GET_PLAYER(gPlayState);
if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused() || !PlayerGrounded(player)) { if (!GameInteractor::IsSaveLoaded(true) || GameInteractor::IsGameplayPaused() || !PlayerGrounded(player)) {
return GameInteractionEffectQueryResult::TemporarilyNotPossible; return GameInteractionEffectQueryResult::TemporarilyNotPossible;
} else { } else {
return GameInteractionEffectQueryResult::Possible; return GameInteractionEffectQueryResult::Possible;
@ -256,7 +256,7 @@ void ElectrocutePlayer::_Apply() {
// MARK: - KnockbackPlayer // MARK: - KnockbackPlayer
GameInteractionEffectQueryResult KnockbackPlayer::CanBeApplied() { GameInteractionEffectQueryResult KnockbackPlayer::CanBeApplied() {
Player* player = GET_PLAYER(gPlayState); Player* player = GET_PLAYER(gPlayState);
if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused() || if (!GameInteractor::IsSaveLoaded(true) || GameInteractor::IsGameplayPaused() ||
player->stateFlags2 & PLAYER_STATE2_CRAWLING) { player->stateFlags2 & PLAYER_STATE2_CRAWLING) {
return GameInteractionEffectQueryResult::TemporarilyNotPossible; return GameInteractionEffectQueryResult::TemporarilyNotPossible;
} else { } else {
@ -269,7 +269,7 @@ void KnockbackPlayer::_Apply() {
// MARK: - ModifyLinkSize // MARK: - ModifyLinkSize
GameInteractionEffectQueryResult ModifyLinkSize::CanBeApplied() { GameInteractionEffectQueryResult ModifyLinkSize::CanBeApplied() {
if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused()) { if (!GameInteractor::IsSaveLoaded(true) || GameInteractor::IsGameplayPaused()) {
return GameInteractionEffectQueryResult::TemporarilyNotPossible; return GameInteractionEffectQueryResult::TemporarilyNotPossible;
} else { } else {
return GameInteractionEffectQueryResult::Possible; return GameInteractionEffectQueryResult::Possible;
@ -284,7 +284,7 @@ void ModifyLinkSize::_Remove() {
// MARK: - InvisibleLink // MARK: - InvisibleLink
GameInteractionEffectQueryResult InvisibleLink::CanBeApplied() { GameInteractionEffectQueryResult InvisibleLink::CanBeApplied() {
if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused()) { if (!GameInteractor::IsSaveLoaded(true) || GameInteractor::IsGameplayPaused()) {
return GameInteractionEffectQueryResult::TemporarilyNotPossible; return GameInteractionEffectQueryResult::TemporarilyNotPossible;
} else { } else {
return GameInteractionEffectQueryResult::Possible; return GameInteractionEffectQueryResult::Possible;
@ -299,7 +299,7 @@ void InvisibleLink::_Remove() {
// MARK: - PacifistMode // MARK: - PacifistMode
GameInteractionEffectQueryResult PacifistMode::CanBeApplied() { GameInteractionEffectQueryResult PacifistMode::CanBeApplied() {
if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused()) { if (!GameInteractor::IsSaveLoaded(true) || GameInteractor::IsGameplayPaused()) {
return GameInteractionEffectQueryResult::TemporarilyNotPossible; return GameInteractionEffectQueryResult::TemporarilyNotPossible;
} else { } else {
return GameInteractionEffectQueryResult::Possible; return GameInteractionEffectQueryResult::Possible;
@ -314,7 +314,7 @@ void PacifistMode::_Remove() {
// MARK: - DisableZTargeting // MARK: - DisableZTargeting
GameInteractionEffectQueryResult DisableZTargeting::CanBeApplied() { GameInteractionEffectQueryResult DisableZTargeting::CanBeApplied() {
if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused()) { if (!GameInteractor::IsSaveLoaded(true) || GameInteractor::IsGameplayPaused()) {
return GameInteractionEffectQueryResult::TemporarilyNotPossible; return GameInteractionEffectQueryResult::TemporarilyNotPossible;
} else { } else {
return GameInteractionEffectQueryResult::Possible; return GameInteractionEffectQueryResult::Possible;
@ -329,7 +329,7 @@ void DisableZTargeting::_Remove() {
// MARK: - WeatherRainstorm // MARK: - WeatherRainstorm
GameInteractionEffectQueryResult WeatherRainstorm::CanBeApplied() { GameInteractionEffectQueryResult WeatherRainstorm::CanBeApplied() {
if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused()) { if (!GameInteractor::IsSaveLoaded(true) || GameInteractor::IsGameplayPaused()) {
return GameInteractionEffectQueryResult::TemporarilyNotPossible; return GameInteractionEffectQueryResult::TemporarilyNotPossible;
} else { } else {
return GameInteractionEffectQueryResult::Possible; return GameInteractionEffectQueryResult::Possible;
@ -344,7 +344,7 @@ void WeatherRainstorm::_Remove() {
// MARK: - ReverseControls // MARK: - ReverseControls
GameInteractionEffectQueryResult ReverseControls::CanBeApplied() { GameInteractionEffectQueryResult ReverseControls::CanBeApplied() {
if (!GameInteractor::IsSaveLoaded()) { if (!GameInteractor::IsSaveLoaded(true)) {
return GameInteractionEffectQueryResult::TemporarilyNotPossible; return GameInteractionEffectQueryResult::TemporarilyNotPossible;
} else { } else {
return GameInteractionEffectQueryResult::Possible; return GameInteractionEffectQueryResult::Possible;
@ -359,7 +359,7 @@ void ReverseControls::_Remove() {
// MARK: - ForceEquipBoots // MARK: - ForceEquipBoots
GameInteractionEffectQueryResult ForceEquipBoots::CanBeApplied() { GameInteractionEffectQueryResult ForceEquipBoots::CanBeApplied() {
if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused()) { if (!GameInteractor::IsSaveLoaded(true) || GameInteractor::IsGameplayPaused()) {
return GameInteractionEffectQueryResult::TemporarilyNotPossible; return GameInteractionEffectQueryResult::TemporarilyNotPossible;
} else { } else {
return GameInteractionEffectQueryResult::Possible; return GameInteractionEffectQueryResult::Possible;
@ -374,7 +374,7 @@ void ForceEquipBoots::_Remove() {
// MARK: - ModifyMovementSpeedMultiplier // MARK: - ModifyMovementSpeedMultiplier
GameInteractionEffectQueryResult ModifyMovementSpeedMultiplier::CanBeApplied() { GameInteractionEffectQueryResult ModifyMovementSpeedMultiplier::CanBeApplied() {
if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused()) { if (!GameInteractor::IsSaveLoaded(true) || GameInteractor::IsGameplayPaused()) {
return GameInteractionEffectQueryResult::TemporarilyNotPossible; return GameInteractionEffectQueryResult::TemporarilyNotPossible;
} else { } else {
return GameInteractionEffectQueryResult::Possible; return GameInteractionEffectQueryResult::Possible;
@ -393,7 +393,7 @@ void ModifyMovementSpeedMultiplier::_Remove() {
// MARK: - OneHitKO // MARK: - OneHitKO
GameInteractionEffectQueryResult OneHitKO::CanBeApplied() { GameInteractionEffectQueryResult OneHitKO::CanBeApplied() {
if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused()) { if (!GameInteractor::IsSaveLoaded(true) || GameInteractor::IsGameplayPaused()) {
return GameInteractionEffectQueryResult::TemporarilyNotPossible; return GameInteractionEffectQueryResult::TemporarilyNotPossible;
} else { } else {
return GameInteractionEffectQueryResult::Possible; return GameInteractionEffectQueryResult::Possible;
@ -408,7 +408,7 @@ void OneHitKO::_Remove() {
// MARK: - ModifyDefenseModifier // MARK: - ModifyDefenseModifier
GameInteractionEffectQueryResult ModifyDefenseModifier::CanBeApplied() { GameInteractionEffectQueryResult ModifyDefenseModifier::CanBeApplied() {
if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused()) { if (!GameInteractor::IsSaveLoaded(true) || GameInteractor::IsGameplayPaused()) {
return GameInteractionEffectQueryResult::TemporarilyNotPossible; return GameInteractionEffectQueryResult::TemporarilyNotPossible;
} else { } else {
return GameInteractionEffectQueryResult::Possible; return GameInteractionEffectQueryResult::Possible;
@ -423,7 +423,7 @@ void ModifyDefenseModifier::_Remove() {
// MARK: - GiveOrTakeShield // MARK: - GiveOrTakeShield
GameInteractionEffectQueryResult GiveOrTakeShield::CanBeApplied() { GameInteractionEffectQueryResult GiveOrTakeShield::CanBeApplied() {
if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused()) { if (!GameInteractor::IsSaveLoaded(true) || GameInteractor::IsGameplayPaused()) {
return GameInteractionEffectQueryResult::TemporarilyNotPossible; return GameInteractionEffectQueryResult::TemporarilyNotPossible;
} else if ((parameters[0] > 0 && ((gBitFlags[parameters[0] - ITEM_SHIELD_DEKU] << gEquipShifts[EQUIP_TYPE_SHIELD]) & } else if ((parameters[0] > 0 && ((gBitFlags[parameters[0] - ITEM_SHIELD_DEKU] << gEquipShifts[EQUIP_TYPE_SHIELD]) &
gSaveContext.inventory.equipment)) || gSaveContext.inventory.equipment)) ||
@ -441,7 +441,7 @@ void GiveOrTakeShield::_Apply() {
// MARK: - TeleportPlayer // MARK: - TeleportPlayer
GameInteractionEffectQueryResult TeleportPlayer::CanBeApplied() { GameInteractionEffectQueryResult TeleportPlayer::CanBeApplied() {
if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused()) { if (!GameInteractor::IsSaveLoaded(true) || GameInteractor::IsGameplayPaused()) {
return GameInteractionEffectQueryResult::TemporarilyNotPossible; return GameInteractionEffectQueryResult::TemporarilyNotPossible;
} else { } else {
return GameInteractionEffectQueryResult::Possible; return GameInteractionEffectQueryResult::Possible;
@ -453,7 +453,7 @@ void TeleportPlayer::_Apply() {
// MARK: - ClearAssignedButtons // MARK: - ClearAssignedButtons
GameInteractionEffectQueryResult ClearAssignedButtons::CanBeApplied() { GameInteractionEffectQueryResult ClearAssignedButtons::CanBeApplied() {
if (!GameInteractor::IsSaveLoaded()) { if (!GameInteractor::IsSaveLoaded(true)) {
return GameInteractionEffectQueryResult::TemporarilyNotPossible; return GameInteractionEffectQueryResult::TemporarilyNotPossible;
} else { } else {
return GameInteractionEffectQueryResult::Possible; return GameInteractionEffectQueryResult::Possible;
@ -465,7 +465,7 @@ void ClearAssignedButtons::_Apply() {
// MARK: - SetTimeOfDay // MARK: - SetTimeOfDay
GameInteractionEffectQueryResult SetTimeOfDay::CanBeApplied() { GameInteractionEffectQueryResult SetTimeOfDay::CanBeApplied() {
if (!GameInteractor::IsSaveLoaded()) { if (!GameInteractor::IsSaveLoaded(true)) {
return GameInteractionEffectQueryResult::TemporarilyNotPossible; return GameInteractionEffectQueryResult::TemporarilyNotPossible;
} else { } else {
return GameInteractionEffectQueryResult::Possible; return GameInteractionEffectQueryResult::Possible;
@ -477,7 +477,7 @@ void SetTimeOfDay::_Apply() {
// MARK: - SetCollisionViewer // MARK: - SetCollisionViewer
GameInteractionEffectQueryResult SetCollisionViewer::CanBeApplied() { GameInteractionEffectQueryResult SetCollisionViewer::CanBeApplied() {
if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused()) { if (!GameInteractor::IsSaveLoaded(true) || GameInteractor::IsGameplayPaused()) {
return GameInteractionEffectQueryResult::TemporarilyNotPossible; return GameInteractionEffectQueryResult::TemporarilyNotPossible;
} else { } else {
return GameInteractionEffectQueryResult::Possible; return GameInteractionEffectQueryResult::Possible;
@ -492,7 +492,7 @@ void SetCollisionViewer::_Remove() {
// MARK: - RandomizeCosmetics // MARK: - RandomizeCosmetics
GameInteractionEffectQueryResult RandomizeCosmetics::CanBeApplied() { GameInteractionEffectQueryResult RandomizeCosmetics::CanBeApplied() {
if (!GameInteractor::IsSaveLoaded()) { if (!GameInteractor::IsSaveLoaded(true)) {
return GameInteractionEffectQueryResult::TemporarilyNotPossible; return GameInteractionEffectQueryResult::TemporarilyNotPossible;
} else { } else {
return GameInteractionEffectQueryResult::Possible; return GameInteractionEffectQueryResult::Possible;
@ -504,7 +504,7 @@ void RandomizeCosmetics::_Apply() {
// MARK: - PressButton // MARK: - PressButton
GameInteractionEffectQueryResult PressButton::CanBeApplied() { GameInteractionEffectQueryResult PressButton::CanBeApplied() {
if (!GameInteractor::IsSaveLoaded()) { if (!GameInteractor::IsSaveLoaded(true)) {
return GameInteractionEffectQueryResult::TemporarilyNotPossible; return GameInteractionEffectQueryResult::TemporarilyNotPossible;
} else { } else {
return GameInteractionEffectQueryResult::Possible; return GameInteractionEffectQueryResult::Possible;
@ -516,7 +516,7 @@ void PressButton::_Apply() {
// MARK: - PressRandomButton // MARK: - PressRandomButton
GameInteractionEffectQueryResult PressRandomButton::CanBeApplied() { GameInteractionEffectQueryResult PressRandomButton::CanBeApplied() {
if (!GameInteractor::IsSaveLoaded()) { if (!GameInteractor::IsSaveLoaded(true)) {
return GameInteractionEffectQueryResult::TemporarilyNotPossible; return GameInteractionEffectQueryResult::TemporarilyNotPossible;
} else { } else {
return GameInteractionEffectQueryResult::Possible; return GameInteractionEffectQueryResult::Possible;
@ -528,7 +528,7 @@ void PressRandomButton::_Apply() {
// MARK: - AddOrTakeAmmo // MARK: - AddOrTakeAmmo
GameInteractionEffectQueryResult AddOrTakeAmmo::CanBeApplied() { GameInteractionEffectQueryResult AddOrTakeAmmo::CanBeApplied() {
if (!GameInteractor::IsSaveLoaded()) { if (!GameInteractor::IsSaveLoaded(true)) {
return GameInteractionEffectQueryResult::TemporarilyNotPossible; return GameInteractionEffectQueryResult::TemporarilyNotPossible;
} else if (!GameInteractor::CanAddOrTakeAmmo(parameters[0], parameters[1])) { } else if (!GameInteractor::CanAddOrTakeAmmo(parameters[0], parameters[1])) {
return GameInteractionEffectQueryResult::NotPossible; return GameInteractionEffectQueryResult::NotPossible;
@ -542,7 +542,7 @@ void AddOrTakeAmmo::_Apply() {
// MARK: - RandomBombFuseTimer // MARK: - RandomBombFuseTimer
GameInteractionEffectQueryResult RandomBombFuseTimer::CanBeApplied() { GameInteractionEffectQueryResult RandomBombFuseTimer::CanBeApplied() {
if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused()) { if (!GameInteractor::IsSaveLoaded(true) || GameInteractor::IsGameplayPaused()) {
return GameInteractionEffectQueryResult::TemporarilyNotPossible; return GameInteractionEffectQueryResult::TemporarilyNotPossible;
} else { } else {
return GameInteractionEffectQueryResult::Possible; return GameInteractionEffectQueryResult::Possible;
@ -557,7 +557,7 @@ void RandomBombFuseTimer::_Remove() {
// MARK: - DisableLedgeGrabs // MARK: - DisableLedgeGrabs
GameInteractionEffectQueryResult DisableLedgeGrabs::CanBeApplied() { GameInteractionEffectQueryResult DisableLedgeGrabs::CanBeApplied() {
if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused()) { if (!GameInteractor::IsSaveLoaded(true) || GameInteractor::IsGameplayPaused()) {
return GameInteractionEffectQueryResult::TemporarilyNotPossible; return GameInteractionEffectQueryResult::TemporarilyNotPossible;
} else { } else {
return GameInteractionEffectQueryResult::Possible; return GameInteractionEffectQueryResult::Possible;
@ -572,7 +572,7 @@ void DisableLedgeGrabs::_Remove() {
// MARK: - RandomWind // MARK: - RandomWind
GameInteractionEffectQueryResult RandomWind::CanBeApplied() { GameInteractionEffectQueryResult RandomWind::CanBeApplied() {
if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused()) { if (!GameInteractor::IsSaveLoaded(true) || GameInteractor::IsGameplayPaused()) {
return GameInteractionEffectQueryResult::TemporarilyNotPossible; return GameInteractionEffectQueryResult::TemporarilyNotPossible;
} else { } else {
return GameInteractionEffectQueryResult::Possible; return GameInteractionEffectQueryResult::Possible;
@ -587,7 +587,7 @@ void RandomWind::_Remove() {
// MARK: - RandomBonks // MARK: - RandomBonks
GameInteractionEffectQueryResult RandomBonks::CanBeApplied() { GameInteractionEffectQueryResult RandomBonks::CanBeApplied() {
if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused()) { if (!GameInteractor::IsSaveLoaded(true) || GameInteractor::IsGameplayPaused()) {
return GameInteractionEffectQueryResult::TemporarilyNotPossible; return GameInteractionEffectQueryResult::TemporarilyNotPossible;
} else { } else {
return GameInteractionEffectQueryResult::Possible; return GameInteractionEffectQueryResult::Possible;
@ -602,7 +602,7 @@ void RandomBonks::_Remove() {
// MARK: - PlayerInvincibility // MARK: - PlayerInvincibility
GameInteractionEffectQueryResult PlayerInvincibility::CanBeApplied() { GameInteractionEffectQueryResult PlayerInvincibility::CanBeApplied() {
if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused()) { if (!GameInteractor::IsSaveLoaded(true) || GameInteractor::IsGameplayPaused()) {
return GameInteractionEffectQueryResult::TemporarilyNotPossible; return GameInteractionEffectQueryResult::TemporarilyNotPossible;
} else { } else {
return GameInteractionEffectQueryResult::Possible; return GameInteractionEffectQueryResult::Possible;
@ -617,7 +617,7 @@ void PlayerInvincibility::_Remove() {
// MARK: - SlipperyFloor // MARK: - SlipperyFloor
GameInteractionEffectQueryResult SlipperyFloor::CanBeApplied() { GameInteractionEffectQueryResult SlipperyFloor::CanBeApplied() {
if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused()) { if (!GameInteractor::IsSaveLoaded(true) || GameInteractor::IsGameplayPaused()) {
return GameInteractionEffectQueryResult::TemporarilyNotPossible; return GameInteractionEffectQueryResult::TemporarilyNotPossible;
} else { } else {
return GameInteractionEffectQueryResult::Possible; return GameInteractionEffectQueryResult::Possible;
@ -632,7 +632,7 @@ void SlipperyFloor::_Remove() {
// MARK: - SpawnEnemyWithOffset // MARK: - SpawnEnemyWithOffset
GameInteractionEffectQueryResult SpawnEnemyWithOffset::CanBeApplied() { GameInteractionEffectQueryResult SpawnEnemyWithOffset::CanBeApplied() {
if (!GameInteractor::IsSaveLoaded()) { if (!GameInteractor::IsSaveLoaded(true)) {
return GameInteractionEffectQueryResult::TemporarilyNotPossible; return GameInteractionEffectQueryResult::TemporarilyNotPossible;
} }
return GameInteractor::RawAction::SpawnEnemyWithOffset(parameters[0], parameters[1]); return GameInteractor::RawAction::SpawnEnemyWithOffset(parameters[0], parameters[1]);
@ -644,7 +644,7 @@ void SpawnEnemyWithOffset::_Apply() {
// MARK: - SpawnActor // MARK: - SpawnActor
GameInteractionEffectQueryResult SpawnActor::CanBeApplied() { GameInteractionEffectQueryResult SpawnActor::CanBeApplied() {
if (!GameInteractor::IsSaveLoaded()) { if (!GameInteractor::IsSaveLoaded(true)) {
return GameInteractionEffectQueryResult::TemporarilyNotPossible; return GameInteractionEffectQueryResult::TemporarilyNotPossible;
} }
return GameInteractor::RawAction::SpawnActor(parameters[0], parameters[1]); return GameInteractor::RawAction::SpawnActor(parameters[0], parameters[1]);

View file

@ -2222,6 +2222,29 @@ typedef enum {
// - `s32` limbCount // - `s32` limbCount
// - `*Vec3s` frameTable // - `*Vec3s` frameTable
VB_LOAD_PLAYER_ANIMATION_FRAME, VB_LOAD_PLAYER_ANIMATION_FRAME,
// #### `result`
// ```c
// DoorWarp1_PlayerInRange(this, play)
// ```
// #### `args`
// - `*DoorWarp1`
VB_BLUE_WARP_CONSIDER_ADULT_IN_RANGE,
// #### `result`
// ```c
// (CVarGetInteger(CVAR_GAMEPLAY_STATS("ShowIngameTimer"), 0) && gSaveContext.fileNum >= 0 && gSaveContext.fileNum
// <= 2)
// ```
// #### `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; } GIVanillaBehavior;
#endif #endif

View file

@ -51,9 +51,48 @@ typedef enum {
/* 0xA9 */ TIMESTAMP_DEFEAT_GANON, // z_boss_ganon2.c /* 0xA9 */ TIMESTAMP_DEFEAT_GANON, // z_boss_ganon2.c
/* 0xA9 */ TIMESTAMP_BOSSRUSH_FINISH, // z_boss_ganon2.c /* 0xA9 */ TIMESTAMP_BOSSRUSH_FINISH, // z_boss_ganon2.c
/* 0xAA */ TIMESTAMP_FOUND_GREG, // z_parameter.c /* 0xAA */ TIMESTAMP_FOUND_GREG, // z_parameter.c
/* 0xAA */ TIMESTAMP_TRIFORCE_COMPLETED, // z_parameter.c /* 0xAB */ TIMESTAMP_TRIFORCE_COMPLETED, // z_parameter.c
/* 0xAB */ TIMESTAMP_MAX /* 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; } GameplayStatTimestamp;
typedef enum { typedef enum {

View file

@ -6,7 +6,6 @@
#include "soh/SaveManager.h" #include "soh/SaveManager.h"
#include "soh/ResourceManagerHelpers.h" #include "soh/ResourceManagerHelpers.h"
#include "soh/resource/type/Skeleton.h" #include "soh/resource/type/Skeleton.h"
#include "soh/Enhancements/boss-rush/BossRushTypes.h"
#include "soh/Enhancements/boss-rush/BossRush.h" #include "soh/Enhancements/boss-rush/BossRush.h"
#include "soh/Enhancements/enhancementTypes.h" #include "soh/Enhancements/enhancementTypes.h"
#include "soh/Enhancements/randomizer/3drando/random.hpp" #include "soh/Enhancements/randomizer/3drando/random.hpp"
@ -49,7 +48,6 @@ extern "C" {
extern SaveContext gSaveContext; extern SaveContext gSaveContext;
extern PlayState* gPlayState; extern PlayState* gPlayState;
extern void Overlay_DisplayText(float duration, const char* text);
} }
// GreyScaleEndDlist // GreyScaleEndDlist
@ -131,10 +129,27 @@ void RegisterOcarinaTimeTravel() {
bool notNearAnySource = !nearbyTimeBlockEmpty && !nearbyTimeBlock && !nearbyOcarinaSpot && !nearbyDoorOfTime && bool notNearAnySource = !nearbyTimeBlockEmpty && !nearbyTimeBlock && !nearbyOcarinaSpot && !nearbyDoorOfTime &&
!nearbyFrogs && !nearbyGossipStone; !nearbyFrogs && !nearbyGossipStone;
bool hasOcarinaOfTime = (INV_CONTENT(ITEM_OCARINA_TIME) == ITEM_OCARINA_TIME); 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); bool hasMasterSword = CHECK_OWNED_EQUIP(EQUIP_TYPE_SWORD, EQUIP_INV_SWORD_MASTER);
// TODO: Once Swordless Adult is fixed: Remove the Master Sword check int timeTravelSetting = CVarGetInteger(CVAR_ENHANCEMENT("TimeTravel"), 0);
if (justPlayedSoT && notNearAnySource && (hasOcarinaOfTime || doesntNeedOcarinaOfTime) && hasMasterSword) { 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(); SwitchAge();
} }
}); });
@ -283,49 +298,6 @@ void UpdateHyperEnemiesState() {
} }
} }
void RegisterBonkDamage() {
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnPlayerBonk>([]() {
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) { void UpdateDirtPathFixState(int32_t sceneNum) {
switch (sceneNum) { switch (sceneNum) {
case SCENE_HYRULE_FIELD: case SCENE_HYRULE_FIELD:
@ -957,7 +929,6 @@ void RegisterCustomSkeletons() {
} }
void InitMods() { void InitMods() {
BossRush_RegisterHooks();
RandomizerRegisterHooks(); RandomizerRegisterHooks();
TimeSaverRegisterHooks(); TimeSaverRegisterHooks();
RegisterTTS(); RegisterTTS();
@ -966,7 +937,6 @@ void InitMods() {
RegisterDeleteFileOnDeath(); RegisterDeleteFileOnDeath();
RegisterHyperBosses(); RegisterHyperBosses();
UpdateHyperEnemiesState(); UpdateHyperEnemiesState();
RegisterBonkDamage();
RegisterMenuPathFix(); RegisterMenuPathFix();
RegisterMirrorModeHandler(); RegisterMirrorModeHandler();
RegisterResetNaviTimer(); RegisterResetNaviTimer();

View file

@ -648,6 +648,9 @@ void CreateStoneHints() {
if (ctx->GetOption(RSK_SKIP_CHILD_ZELDA)) { if (ctx->GetOption(RSK_SKIP_CHILD_ZELDA)) {
ctx->GetItemLocation(RC_SONG_FROM_IMPA)->SetHintAccesible(); 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 // Add 'always' location hints
std::vector<RandomizerCheck> alwaysHintLocations = {}; std::vector<RandomizerCheck> alwaysHintLocations = {};

View file

@ -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_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_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[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_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_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)); 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));

View file

@ -1713,6 +1713,7 @@ void RandomizerOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, va_l
case VB_GIVE_ITEM_WATER_MEDALLION: case VB_GIVE_ITEM_WATER_MEDALLION:
case VB_GIVE_ITEM_SPIRIT_MEDALLION: case VB_GIVE_ITEM_SPIRIT_MEDALLION:
case VB_GIVE_ITEM_SHADOW_MEDALLION: case VB_GIVE_ITEM_SHADOW_MEDALLION:
case VB_CHEST_USE_ICE_EFFECT:
*should = false; *should = false;
break; break;
case VB_GIVE_ITEM_SKULL_TOKEN: case VB_GIVE_ITEM_SKULL_TOKEN:

View file

@ -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->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->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->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 //Locations
LOCATION(RC_LINKS_POCKET, true), 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_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_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 //Exits
Entrance(RR_ROOT_EXITS, []{return true;}), Entrance(RR_ROOT_EXITS, []{return true;}),

View file

@ -30,7 +30,7 @@ void RegionTable_Init_GerudoFortress() {
LOCATION(RC_GF_SOUTHMOST_CENTER_CRATE, logic->CanBreakCrates()), LOCATION(RC_GF_SOUTHMOST_CENTER_CRATE, logic->CanBreakCrates()),
LOCATION(RC_GF_MID_SOUTH_CENTER_CRATE, logic->CanBreakCrates()), LOCATION(RC_GF_MID_SOUTH_CENTER_CRATE, logic->CanBreakCrates()),
LOCATION(RC_GF_MID_NORTH_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 //Exits
Entrance(RR_TH_1_TORCH_CELL, []{return true;}), Entrance(RR_TH_1_TORCH_CELL, []{return true;}),

View file

@ -2471,6 +2471,7 @@ void Logic::Reset(bool resetSaveContext /*= true*/) {
THCouldFreeDoubleCellCarpenter = false; THCouldFreeDoubleCellCarpenter = false;
TH_CouldFreeDeadEndCarpenter = false; TH_CouldFreeDeadEndCarpenter = false;
THCouldRescueSlopeCarpenter = false; THCouldRescueSlopeCarpenter = false;
THRescuedAllCarpenters = false;
GF_GateOpen = false; GF_GateOpen = false;
GtG_GateOpen = false; GtG_GateOpen = false;
DampesWindmillAccess = false; DampesWindmillAccess = false;

View file

@ -519,6 +519,8 @@ bool Randomizer::SpoilerFileExists(const char* spoilerFileName) {
"The spoiler file located at\n" + std::string(spoilerFileName) + "The spoiler file located at\n" + std::string(spoilerFileName) +
"\nwas made by a version that doesn't match the currently running version.\n" + "\nwas made by a version that doesn't match the currently running version.\n" +
"Loading for this file has been cancelled."); "Loading for this file has been cancelled.");
CVarClear(CVAR_GENERAL("SpoilerLog"));
Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame();
} }
// Update cache // Update cache
@ -2330,7 +2332,7 @@ std::map<RandomizerCheck, RandomizerInf> rcToRandomizerInf = {
RAND_INF_GF_MID_NORTH_CENTER_CRATE, RAND_INF_GF_MID_NORTH_CENTER_CRATE,
}, },
{ {
RR_GF_NORTHMOST_CENTER_CRATE, RC_GF_NORTHMOST_CENTER_CRATE,
RAND_INF_GF_NORTHMOST_CENTER_CRATE, RAND_INF_GF_NORTHMOST_CENTER_CRATE,
}, },
{ {
@ -5781,6 +5783,53 @@ void RandomizerSettingsWindow::InitElement() {
mSettings->UpdateOptionProperties(); mSettings->UpdateOptionProperties();
} }
static std::unordered_map<RandomizerGet, GameplayStatTimestamp> 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 // Gameplay stat tracking: Update time the item was acquired
// (special cases for rando items) // (special cases for rando items)
void Randomizer_GameplayStats_SetTimestamp(uint16_t item) { 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 // Use ITEM_KEY_BOSS to timestamp Ganon's boss key
if (item == RG_GANONS_CASTLE_BOSS_KEY) { if (item == RG_GANONS_CASTLE_BOSS_KEY) {
gSaveContext.ship.stats.itemTimestamp[ITEM_KEY_BOSS] = time; 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 // Count any bottled item as a bottle
@ -5804,6 +5859,7 @@ void Randomizer_GameplayStats_SetTimestamp(uint16_t item) {
} }
return; return;
} }
// Count any bombchu pack as bombchus // Count any bombchu pack as bombchus
if ((item >= RG_BOMBCHU_5 && item <= RG_BOMBCHU_20) || item == RG_PROGRESSIVE_BOMBCHUS) { if ((item >= RG_BOMBCHU_5 && item <= RG_BOMBCHU_20) || item == RG_PROGRESSIVE_BOMBCHUS) {
if (gSaveContext.ship.stats.itemTimestamp[ITEM_BOMBCHU] = 0) { if (gSaveContext.ship.stats.itemTimestamp[ITEM_BOMBCHU] = 0) {
@ -5811,11 +5867,15 @@ void Randomizer_GameplayStats_SetTimestamp(uint16_t item) {
} }
return; return;
} }
if (item == RG_MAGIC_SINGLE) { if (item == RG_MAGIC_SINGLE) {
gSaveContext.ship.stats.itemTimestamp[ITEM_SINGLE_MAGIC] = time; gSaveContext.ship.stats.itemTimestamp[ITEM_SINGLE_MAGIC] = time;
return;
} }
if (item == RG_DOUBLE_DEFENSE) { if (item == RG_DOUBLE_DEFENSE) {
gSaveContext.ship.stats.itemTimestamp[ITEM_DOUBLE_DEFENSE] = time; gSaveContext.ship.stats.itemTimestamp[ITEM_DOUBLE_DEFENSE] = time;
return;
} }
} }

View file

@ -2396,7 +2396,7 @@ typedef enum {
RC_GF_SOUTHMOST_CENTER_CRATE, RC_GF_SOUTHMOST_CENTER_CRATE,
RC_GF_MID_SOUTH_CENTER_CRATE, RC_GF_MID_SOUTH_CENTER_CRATE,
RC_GF_MID_NORTH_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_NE_CRATE,
RC_GF_OUTSKIRTS_NW_CRATE, RC_GF_OUTSKIRTS_NW_CRATE,
RC_GF_HBA_RANGE_CRATE_1, RC_GF_HBA_RANGE_CRATE_1,

View file

@ -449,7 +449,8 @@ ItemTrackerNumbers GetItemCurrentAndMax(ItemTrackerItem item) {
result.currentCapacity = result.currentCapacity =
IS_RANDO && !Flags_GetRandomizerInf(RAND_INF_HAS_WALLET) ? 0 : CUR_CAPACITY(UPG_WALLET); IS_RANDO && !Flags_GetRandomizerInf(RAND_INF_HAS_WALLET) ? 0 : CUR_CAPACITY(UPG_WALLET);
result.maxCapacity = 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; result.currentAmmo = gSaveContext.rupees;
break; break;
case ITEM_BOMBCHU: case ITEM_BOMBCHU:
@ -502,8 +503,29 @@ ItemTrackerNumbers GetItemCurrentAndMax(ItemTrackerItem item) {
result.maxCapacity = GERUDO_TRAINING_GROUND_SMALL_KEY_MAX; result.maxCapacity = GERUDO_TRAINING_GROUND_SMALL_KEY_MAX;
break; break;
case SCENE_THIEVES_HIDEOUT: case SCENE_THIEVES_HIDEOUT:
if (IS_RANDO) {
switch (OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_GERUDO_FORTRESS)) {
case RO_GF_CARPENTERS_NORMAL:
result.maxCapacity = GERUDO_FORTRESS_SMALL_KEY_MAX; result.maxCapacity = GERUDO_FORTRESS_SMALL_KEY_MAX;
break; 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: case SCENE_INSIDE_GANONS_CASTLE:
result.maxCapacity = GANONS_CASTLE_SMALL_KEY_MAX; result.maxCapacity = GANONS_CASTLE_SMALL_KEY_MAX;
break; break;

View file

@ -2,6 +2,7 @@
#include <fstream> #include <fstream>
#include <filesystem> #include <filesystem>
#include "Context.h"
#include "TimeSplits.h" #include "TimeSplits.h"
#include "soh/Enhancements/gameplaystats.h" #include "soh/Enhancements/gameplaystats.h"
#include "soh/SaveManager.h" #include "soh/SaveManager.h"
@ -363,7 +364,7 @@ void TimeSplitsSkipSplit(uint32_t index) {
} }
void TimeSplitsFileManagement(uint32_t action, const char* listEntry, std::vector<SplitObject> listData) { void TimeSplitsFileManagement(uint32_t action, const char* listEntry, std::vector<SplitObject> listData) {
std::string filename = "timesplitdata.json"; std::string filename = Ship::Context::GetPathRelativeToAppDirectory("timesplitdata.json");
json saveFile; json saveFile;
json listArray = nlohmann::json::array(); json listArray = nlohmann::json::array();
@ -948,9 +949,10 @@ void TimeSplitsDrawManageList() {
} }
void InitializeSplitDataFile() { void InitializeSplitDataFile() {
if (!std::filesystem::exists("timesplitdata.json")) { std::string filename = Ship::Context::GetPathRelativeToAppDirectory("timesplitdata.json");
if (!std::filesystem::exists(filename)) {
json j; json j;
std::ofstream file("timesplitdata.json"); std::ofstream file(filename);
file << j.dump(4); file << j.dump(4);
file.close(); file.close();
} }

View file

@ -965,7 +965,6 @@ OTRVersion ReadPortVersionFromOTR(std::string otrPath) {
version.minor = reader->ReadUInt16(); version.minor = reader->ReadUInt16();
version.patch = reader->ReadUInt16(); version.patch = reader->ReadUInt16();
} }
archive->Close();
} }
return version; return version;
@ -1660,7 +1659,9 @@ ImFont* OTRGlobals::CreateFontWithSize(float size, std::string fontPath) {
initData->Path = fontPath; initData->Path = fontPath;
std::shared_ptr<Ship::Font> fontData = std::static_pointer_cast<Ship::Font>( std::shared_ptr<Ship::Font> fontData = std::static_pointer_cast<Ship::Font>(
Ship::Context::GetInstance()->GetResourceManager()->LoadResource(fontPath, false, initData)); 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 // 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; float iconFontSize = size * 2.0f / 3.0f;
@ -2560,15 +2561,6 @@ extern "C" int CustomMessage_RetrieveIfExists(PlayState* play) {
return false; 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) { extern "C" void EntranceTracker_SetCurrentGrottoID(s16 entranceIndex) {
SetCurrentGrottoIDForTracker(entranceIndex); SetCurrentGrottoIDForTracker(entranceIndex);
} }

View file

@ -156,8 +156,6 @@ void Randomizer_SetSpoilerLoaded(bool spoilerLoaded);
uint8_t Randomizer_GenerateRandomizer(); uint8_t Randomizer_GenerateRandomizer();
void Randomizer_ShowRandomizerMenu(); void Randomizer_ShowRandomizerMenu();
int CustomMessage_RetrieveIfExists(PlayState* play); 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_Retrieve(int16_t getItemID);
GetItemEntry ItemTable_RetrieveEntry(s16 modIndex, s16 getItemID); GetItemEntry ItemTable_RetrieveEntry(s16 modIndex, s16 getItemID);
void EntranceTracker_SetCurrentGrottoID(s16 entranceIndex); void EntranceTracker_SetCurrentGrottoID(s16 entranceIndex);

View file

@ -1125,6 +1125,7 @@ void SaveManager::LoadFile(int fileNum) {
std::ifstream input(fileName); std::ifstream input(fileName);
try { try {
bool deleteRando = false;
saveBlock = nlohmann::json::object(); saveBlock = nlohmann::json::object();
input >> saveBlock; input >> saveBlock;
if (!saveBlock.contains("version")) { if (!saveBlock.contains("version")) {
@ -1134,21 +1135,24 @@ void SaveManager::LoadFile(int fileNum) {
switch (saveBlock["version"].get<int>()) { switch (saveBlock["version"].get<int>()) {
case 1: case 1:
for (auto& block : saveBlock["sections"].items()) { 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(); std::string sectionName = block.key();
if (sectionName == "randomizer") { if (sectionName == "randomizer") {
bool hasStats = saveBlock["sections"].contains("sohStats"); bool hasStats = saveBlock["sections"].contains("sohStats");
if (block.value()["data"].contains("aat0") || !hasStats) { // Rachael rando data if (oldVanilla || !hasStats) { // Vanilla "rando" data
SohGui::RegisterPopup( SohGui::RegisterPopup(
"Loading old file", "Loading old file",
"The file in slot " + std::to_string(fileNum + 1) + "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 " "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."); "If this was a randomizer file, the file will not work, and should be deleted.");
input.close(); deleteRando = true;
saveMtx.unlock(); continue;
SaveFile(fileNum);
return;
} }
s16 major = saveBlock["sections"]["sohStats"]["data"]["buildVersionMajor"]; s16 major = saveBlock["sections"]["sohStats"]["data"]["buildVersionMajor"];
s16 minor = saveBlock["sections"]["sohStats"]["data"]["buildVersionMinor"]; s16 minor = saveBlock["sections"]["sohStats"]["data"]["buildVersionMinor"];
@ -1177,7 +1181,6 @@ void SaveManager::LoadFile(int fileNum) {
" " + newFileName + "\n" + " " + newFileName + "\n" +
"If this was not in error, the file should be deleted."); "If this was not in error, the file should be deleted.");
saveMtx.unlock(); saveMtx.unlock();
SaveFile(fileNum);
return; return;
} }
} }
@ -1216,6 +1219,12 @@ void SaveManager::LoadFile(int fileNum) {
assert(false); assert(false);
break; break;
} }
input.close();
if (deleteRando) {
saveBlock["sections"].erase(saveBlock["sections"].find("randomizer"));
SaveFile(fileNum);
deleteRando = false;
}
InitMeta(fileNum); InitMeta(fileNum);
GameInteractor::Instance->ExecuteHooks<GameInteractor::OnLoadFile>(fileNum); GameInteractor::Instance->ExecuteHooks<GameInteractor::OnLoadFile>(fileNum);
} catch (const std::exception& e) { } catch (const std::exception& e) {

View file

@ -71,7 +71,6 @@ std::shared_ptr<SohMenuBar> mSohMenuBar;
std::shared_ptr<Ship::GuiWindow> mConsoleWindow; std::shared_ptr<Ship::GuiWindow> mConsoleWindow;
std::shared_ptr<SohStatsWindow> mStatsWindow; std::shared_ptr<SohStatsWindow> mStatsWindow;
std::shared_ptr<Ship::GuiWindow> mGfxDebuggerWindow; std::shared_ptr<Ship::GuiWindow> mGfxDebuggerWindow;
std::shared_ptr<Ship::GuiWindow> mInputEditorWindow;
std::shared_ptr<SohMenu> mSohMenu; std::shared_ptr<SohMenu> mSohMenu;
std::shared_ptr<ModMenuWindow> mModMenuWindow; std::shared_ptr<ModMenuWindow> mModMenuWindow;
@ -132,10 +131,10 @@ void SetupGuiElements() {
mStatsWindow = std::make_shared<SohStatsWindow>(CVAR_WINDOW("SohStats"), "Stats##Soh", ImVec2(400, 100)); mStatsWindow = std::make_shared<SohStatsWindow>(CVAR_WINDOW("SohStats"), "Stats##Soh", ImVec2(400, 100));
gui->AddGuiWindow(mStatsWindow); gui->AddGuiWindow(mStatsWindow);
mInputEditorWindow = gui->GetGuiWindow("Controller Configuration"); /*mInputEditorWindow = gui->GetGuiWindow("Controller Configuration");
if (mInputEditorWindow == nullptr) { if (mInputEditorWindow == nullptr) {
SPDLOG_ERROR("Could not find input editor window"); SPDLOG_ERROR("Could not find input editor window");
} }*/
mModMenuWindow = std::make_shared<ModMenuWindow>(CVAR_WINDOW("ModMenu"), "Mod Menu", ImVec2(820, 630)); mModMenuWindow = std::make_shared<ModMenuWindow>(CVAR_WINDOW("ModMenu"), "Mod Menu", ImVec2(820, 630));
gui->AddGuiWindow(mModMenuWindow); gui->AddGuiWindow(mModMenuWindow);
@ -232,7 +231,6 @@ void Destroy() {
mCosmeticsEditorWindow = nullptr; mCosmeticsEditorWindow = nullptr;
mModMenuWindow = nullptr; mModMenuWindow = nullptr;
mAudioEditorWindow = nullptr; mAudioEditorWindow = nullptr;
mInputEditorWindow = nullptr;
mStatsWindow = nullptr; mStatsWindow = nullptr;
mConsoleWindow = nullptr; mConsoleWindow = nullptr;
mGfxDebuggerWindow = nullptr; mGfxDebuggerWindow = nullptr;

View file

@ -56,7 +56,9 @@ static const std::unordered_map<int32_t, const char*> chestStyleMatchesContentsO
static const std::unordered_map<int32_t, const char*> timeTravelOptions = { static const std::unordered_map<int32_t, const char*> timeTravelOptions = {
{ TIME_TRAVEL_DISABLED, "Disabled" }, { TIME_TRAVEL_DISABLED, "Disabled" },
{ TIME_TRAVEL_OOT, "Ocarina of Time" }, { TIME_TRAVEL_OOT, "Ocarina of Time" },
{ TIME_TRAVEL_OOT_MS, "Ocarina of Time + Master Sword" },
{ TIME_TRAVEL_ANY, "Any Ocarina" }, { TIME_TRAVEL_ANY, "Any Ocarina" },
{ TIME_TRAVEL_ANY_MS, "Any Ocarina + Master Sword" },
}; };
static const std::unordered_map<int32_t, const char*> sleepingWaterfallOptions = { static const std::unordered_map<int32_t, const char*> sleepingWaterfallOptions = {
@ -335,7 +337,7 @@ void SohMenu::AddMenuEnhancements() {
info.options->disabled = info.options->disabled =
IS_RANDO && OTRGlobals::Instance->gRandoContext->GetOption(RSK_JABU_OPEN).Is(RO_JABU_OPEN); IS_RANDO && OTRGlobals::Instance->gRandoContext->GetOption(RSK_JABU_OPEN).Is(RO_JABU_OPEN);
info.options->disabledTooltip = 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.")); .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.")); "Door Switch CS, Water Temple Dragon Switch CS, and the Box Skip One Point in Jabu."));
AddWidget(path, "Text", WIDGET_SEPARATOR_TEXT); 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")) .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) AddWidget(path, "Skip Forced Dialog", WIDGET_CVAR_COMBOBOX)
.CVar(CVAR_ENHANCEMENT("TimeSavers.SkipForcedDialog")) .CVar(CVAR_ENHANCEMENT("TimeSavers.SkipForcedDialog"))
.Options(ComboboxOptions() .Options(ComboboxOptions()
@ -780,9 +785,9 @@ void SohMenu::AddMenuEnhancements() {
.Tooltip("Allows Link to freely change age by playing the Song of Time.\n" .Tooltip("Allows Link to freely change age by playing the Song of Time.\n"
"Time Blocks can still be used properly.\n\n" "Time Blocks can still be used properly.\n\n"
"Requirements:\n" "Requirements:\n"
" - Obtained the Ocarina of Time (depends on selection)\n"
" - Obtained the Song of Time\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 a Time Block\n"
" - Not within range of Ocarina Playing spots")); " - Not within range of Ocarina Playing spots"));

View file

@ -1,5 +1,7 @@
#include "SohMenu.h" #include "SohMenu.h"
#include "soh/Notification/Notification.h" #include "soh/Notification/Notification.h"
#include "soh/Enhancements/controls/SohInputEditorWindow.h"
#include "SohModals.h"
#include "soh/OTRGlobals.h" #include "soh/OTRGlobals.h"
#include <soh/GameVersions.h> #include <soh/GameVersions.h>
#include "soh/ResourceManagerHelpers.h" #include "soh/ResourceManagerHelpers.h"
@ -14,6 +16,7 @@ extern "C" {
namespace SohGui { namespace SohGui {
extern std::shared_ptr<SohMenu> mSohMenu; extern std::shared_ptr<SohMenu> mSohMenu;
extern std::shared_ptr<SohModalWindow> mModalWindow;
using namespace UIWidgets; using namespace UIWidgets;
static std::unordered_map<int32_t, const char*> imguiScaleOptions = { static std::unordered_map<int32_t, const char*> imguiScaleOptions = {
@ -411,6 +414,20 @@ void SohMenu::AddMenuSettings() {
path.sidebarName = "Controls"; path.sidebarName = "Controls";
path.column = SECTION_COLUMN_1; path.column = SECTION_COLUMN_1;
AddSidebarEntry("Settings", "Controls", 2); 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, "Controller Bindings", WIDGET_SEPARATOR_TEXT);
AddWidget(path, "Popout Bindings Window", WIDGET_WINDOW_BUTTON) AddWidget(path, "Popout Bindings Window", WIDGET_WINDOW_BUTTON)
.CVar(CVAR_WINDOW("ControllerConfiguration")) .CVar(CVAR_WINDOW("ControllerConfiguration"))

View file

@ -640,10 +640,8 @@ s32 AudioLoad_SyncInitSeqPlayerInternal(s32 playerIdx, s32 seqId, s32 arg2) {
if (gPlayState != NULL) { if (gPlayState != NULL) {
previousSceneNum = gPlayState->sceneNum; previousSceneNum = gPlayState->sceneNum;
} }
const char* sequenceName = AudioCollection_GetSequenceName(seqId);
if (sequenceName != NULL) { AudioCollection_EmitSongNameNotification(seqId);
Overlay_DisplayText_Seconds(CVarGetInteger(CVAR_AUDIO("SeqNameOverlayDuration"), 5), sequenceName);
}
} }
} }

View file

@ -8,7 +8,6 @@
#include "libultraship/bridge.h" #include "libultraship/bridge.h"
#include "soh/Enhancements/gameplaystats.h" #include "soh/Enhancements/gameplaystats.h"
#include "soh/Enhancements/boss-rush/BossRushTypes.h"
#include "soh/Enhancements/custom-message/CustomMessageInterfaceAddon.h" #include "soh/Enhancements/custom-message/CustomMessageInterfaceAddon.h"
#include "soh/Enhancements/cosmetics/cosmeticsTypes.h" #include "soh/Enhancements/cosmetics/cosmeticsTypes.h"
#include "soh/Enhancements/enhancementTypes.h" #include "soh/Enhancements/enhancementTypes.h"
@ -6374,11 +6373,10 @@ void Interface_Draw(PlayState* play) {
void Interface_DrawTotalGameplayTimer(PlayState* play) { void Interface_DrawTotalGameplayTimer(PlayState* play) {
// Draw timer based on the Gameplay Stats total time. // Draw timer based on the Gameplay Stats total time.
if (GameInteractor_Should(VB_SHOW_GAMEPLAY_TIMER,
if ((IS_BOSS_RUSH && gSaveContext.ship.quest.data.bossRush.options[BR_OPTIONS_TIMER] == BR_CHOICE_TIMER_YES) || CVarGetInteger(CVAR_GAMEPLAY_STATS("ShowIngameTimer"), 0) && gSaveContext.fileNum >= 0 &&
(CVarGetInteger(CVAR_GAMEPLAY_STATS("ShowIngameTimer"), 0) && gSaveContext.fileNum >= 0 && gSaveContext.fileNum <= 2,
gSaveContext.fileNum <= 2)) { play)) {
s32 X_Margins_Timer = 0; s32 X_Margins_Timer = 0;
if (CVarGetInteger(CVAR_COSMETIC("HUD.IGT.UseMargins"), 0) != 0) { if (CVarGetInteger(CVAR_COSMETIC("HUD.IGT.UseMargins"), 0) != 0) {
if (CVarGetInteger(CVAR_COSMETIC("HUD.IGT.PosType"), 0) == ORIGINAL_LOCATION) { if (CVarGetInteger(CVAR_COSMETIC("HUD.IGT.PosType"), 0) == ORIGINAL_LOCATION) {

View file

@ -1,7 +1,6 @@
#include "z_door_warp1.h" #include "z_door_warp1.h"
#include "objects/object_warp1/object_warp1.h" #include "objects/object_warp1/object_warp1.h"
#include "soh/Enhancements/randomizer/randomizer_entrance.h" #include "soh/Enhancements/randomizer/randomizer_entrance.h"
#include "soh/Enhancements/boss-rush/BossRush.h"
#include "soh/OTRGlobals.h" #include "soh/OTRGlobals.h"
#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h" #include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
@ -693,12 +692,7 @@ void DoorWarp1_AdultWarpIdle(DoorWarp1* this, PlayState* play) {
Audio_PlayActorSound2(&this->actor, NA_SE_EV_WARP_HOLE - SFX_FLAG); Audio_PlayActorSound2(&this->actor, NA_SE_EV_WARP_HOLE - SFX_FLAG);
if (DoorWarp1_PlayerInRange(this, play)) { if (GameInteractor_Should(VB_BLUE_WARP_CONSIDER_ADULT_IN_RANGE, DoorWarp1_PlayerInRange(this, play), this)) {
// Heal player in Boss Rush
if (IS_BOSS_RUSH) {
BossRush_HandleBlueWarpHeal(play);
}
player = GET_PLAYER(play); player = GET_PLAYER(play);
OnePointCutscene_Init(play, 0x25E8, 999, &this->actor, MAIN_CAM); OnePointCutscene_Init(play, 0x25E8, 999, &this->actor, MAIN_CAM);

View file

@ -567,8 +567,10 @@ void EnBox_Update(Actor* thisx, PlayState* play) {
Actor_SetFocus(&this->dyna.actor, 40.0f); Actor_SetFocus(&this->dyna.actor, 40.0f);
} }
if ((this->dyna.actor.params >> 5 & 0x7F) == GI_ICE_TRAP && this->actionFunc == EnBox_Open && if (GameInteractor_Should(VB_CHEST_USE_ICE_EFFECT,
this->skelanime.curFrame > 45 && this->iceSmokeTimer < 100) { (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); EnBox_SpawnIceSmoke(this, play);
} }
} }

View file

@ -654,7 +654,7 @@ void EnPartner_Update(Actor* thisx, PlayState* play) {
itemActor->params == ITEM00_ARROWS_MEDIUM || itemActor->params == ITEM00_ARROWS_LARGE || itemActor->params == ITEM00_ARROWS_MEDIUM || itemActor->params == ITEM00_ARROWS_LARGE ||
itemActor->params == ITEM00_BOMBCHU || itemActor->params == ITEM00_MAGIC_SMALL || itemActor->params == ITEM00_BOMBCHU || itemActor->params == ITEM00_MAGIC_SMALL ||
itemActor->params == ITEM00_MAGIC_LARGE || itemActor->params == ITEM00_NUTS || 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); f32 distanceToObject = Actor_WorldDistXYZToActor(&this->actor, itemActor);
if (distanceToObject <= 20.0f) { if (distanceToObject <= 20.0f) {
itemActor->world.pos = GET_PLAYER(play)->actor.world.pos; itemActor->world.pos = GET_PLAYER(play)->actor.world.pos;

View file

@ -14646,7 +14646,7 @@ void Player_Action_SwingBottle(Player* this, PlayState* play) {
if (LinkAnimation_Update(play, &this->skelAnime)) { if (LinkAnimation_Update(play, &this->skelAnime)) {
if (this->av1.bottleCatchType != BOTTLE_CATCH_NONE) { if (this->av1.bottleCatchType != BOTTLE_CATCH_NONE) {
if (!this->av2.startedTextbox) { if (!this->av2.startedTextbox) {
if (CVarGetInteger(CVAR_ENHANCEMENT("FastDrops"), 0)) { if (CVarGetInteger(CVAR_ENHANCEMENT("FastBottles"), 0)) {
this->av1.bottleCatchType = BOTTLE_CATCH_NONE; this->av1.bottleCatchType = BOTTLE_CATCH_NONE;
} else { } else {
// 1 is subtracted because `sBottleCatchInfo` does not have an entry for `BOTTLE_CATCH_NONE` // 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->av1.bottleCatchType = i + 1;
this->av2.startedTextbox = false; 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->stateFlags1 |= PLAYER_STATE1_IN_ITEM_CS | PLAYER_STATE1_IN_CUTSCENE;
} }
this->interactRangeActor->parent = &this->actor; this->interactRangeActor->parent = &this->actor;
Player_UpdateBottleHeld(play, this, catchInfo->itemId, ABS(catchInfo->itemAction)); 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); Player_AnimPlayOnceAdjusted(play, this, swingEntry->catchAnimation);
func_80835EA4(play, 4); func_80835EA4(play, 4);
} }

View file

@ -1398,110 +1398,6 @@ void FileChoose_UpdateQuestMenu(GameState* thisx) {
} }
} }
static s8 sLastBossRushOptionIndex = -1;
static s8 sLastBossRushOptionValue = -1;
void FileChoose_UpdateBossRushMenu(GameState* thisx) {
FileChoose_UpdateStickDirectionPromptAnim(thisx);
FileChooseContext* this = (FileChooseContext*)thisx;
Input* input = &this->state.input[0];
bool dpad = CVarGetInteger(CVAR_SETTING("DpadInText"), 0);
// Fade in elements after opening Boss Rush options menu
this->bossRushUIAlpha += 25;
if (this->bossRushUIAlpha > 255) {
this->bossRushUIAlpha = 255;
}
// Animate up/down arrows.
this->bossRushArrowOffset += 1;
if (this->bossRushArrowOffset >= 30) {
this->bossRushArrowOffset = 0;
}
// Move menu selection up or down.
if (ABS(this->stickRelY) > 30 || (dpad && CHECK_BTN_ANY(input->press.button, BTN_DDOWN | BTN_DUP))) {
// Move down
if (this->stickRelY < -30 || (dpad && CHECK_BTN_ANY(input->press.button, BTN_DDOWN))) {
// When selecting past the last option, cycle back to the first option.
if ((this->bossRushIndex + 1) > BR_OPTIONS_MAX - 1) {
this->bossRushIndex = 0;
this->bossRushOffset = 0;
} else {
this->bossRushIndex++;
// When last visible option is selected when moving down, offset the list down by one.
if (this->bossRushIndex - this->bossRushOffset > BOSSRUSH_MAX_OPTIONS_ON_SCREEN - 1) {
this->bossRushOffset++;
}
}
} else if (this->stickRelY > 30 || (dpad && CHECK_BTN_ANY(input->press.button, BTN_DUP))) {
// When selecting past the first option, cycle back to the last option and offset the list to view it
// properly.
if ((this->bossRushIndex - 1) < 0) {
this->bossRushIndex = BR_OPTIONS_MAX - 1;
this->bossRushOffset = this->bossRushIndex - BOSSRUSH_MAX_OPTIONS_ON_SCREEN + 1;
} else {
// When first visible option is selected when moving up, offset the list up by one.
if (this->bossRushIndex - this->bossRushOffset == 0) {
this->bossRushOffset--;
}
this->bossRushIndex--;
}
}
Audio_PlaySoundGeneral(NA_SE_SY_FSEL_CURSOR, &gSfxDefaultPos, 4, &gSfxDefaultFreqAndVolScale,
&gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb);
}
// Cycle through choices for currently selected option.
if (ABS(this->stickRelX) > 30 || (dpad && CHECK_BTN_ANY(input->press.button, BTN_DLEFT | BTN_DRIGHT))) {
if (this->stickRelX > 30 || (dpad && CHECK_BTN_ANY(input->press.button, BTN_DRIGHT))) {
// If exceeding the amount of choices for the selected option, cycle back to the first.
if ((gSaveContext.ship.quest.data.bossRush.options[this->bossRushIndex] + 1) ==
BossRush_GetSettingOptionsAmount(this->bossRushIndex)) {
gSaveContext.ship.quest.data.bossRush.options[this->bossRushIndex] = 0;
} else {
gSaveContext.ship.quest.data.bossRush.options[this->bossRushIndex]++;
}
} else if (this->stickRelX < -30 || (dpad && CHECK_BTN_ANY(input->press.button, BTN_DLEFT))) {
// If cycling back when already at the first choice for the selected option, cycle back to the last choice.
if ((gSaveContext.ship.quest.data.bossRush.options[this->bossRushIndex] - 1) < 0) {
gSaveContext.ship.quest.data.bossRush.options[this->bossRushIndex] =
BossRush_GetSettingOptionsAmount(this->bossRushIndex) - 1;
} else {
gSaveContext.ship.quest.data.bossRush.options[this->bossRushIndex]--;
}
}
Audio_PlaySoundGeneral(NA_SE_SY_FSEL_CURSOR, &gSfxDefaultPos, 4, &gSfxDefaultFreqAndVolScale,
&gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb);
}
if (sLastBossRushOptionIndex != this->bossRushIndex ||
sLastBossRushOptionValue != gSaveContext.ship.quest.data.bossRush.options[this->bossRushIndex]) {
GameInteractor_ExecuteOnUpdateFileBossRushOptionSelection(
this->bossRushIndex, gSaveContext.ship.quest.data.bossRush.options[this->bossRushIndex]);
sLastBossRushOptionIndex = this->bossRushIndex;
sLastBossRushOptionValue = gSaveContext.ship.quest.data.bossRush.options[this->bossRushIndex];
}
if (CHECK_BTN_ALL(input->press.button, BTN_B)) {
this->configMode = CM_BOSS_RUSH_TO_QUEST;
return;
}
// Load into the game.
if (CHECK_BTN_ALL(input->press.button, BTN_START) || CHECK_BTN_ALL(input->press.button, BTN_A)) {
Audio_PlaySoundGeneral(NA_SE_SY_FSEL_DECIDE_L, &gSfxDefaultPos, 4, &gSfxDefaultFreqAndVolScale,
&gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb);
this->buttonIndex = 0xFE;
this->menuMode = FS_MENU_MODE_SELECT;
this->selectMode = SM_FADE_OUT;
this->prevConfigMode = this->configMode;
return;
}
}
void FileChoose_UpdateRandomizerMenu(GameState* thisx) { void FileChoose_UpdateRandomizerMenu(GameState* thisx) {
FileChoose_UpdateStickDirectionPromptAnim(thisx); FileChoose_UpdateStickDirectionPromptAnim(thisx);
FileChooseContext* this = (FileChooseContext*)thisx; FileChooseContext* this = (FileChooseContext*)thisx;
@ -2590,63 +2486,7 @@ void FileChoose_DrawWindowContents(GameState* thisx) {
break; break;
} }
} else if (this->configMode == CM_BOSS_RUSH_MENU) { } else if (this->configMode == CM_BOSS_RUSH_MENU) {
uint8_t language = (gSaveContext.language == LANGUAGE_JPN) ? LANGUAGE_ENG : gSaveContext.language; FileChoose_DrawBossRushMenuWindowContents(this);
uint8_t listOffset = this->bossRushOffset;
uint8_t textAlpha = this->bossRushUIAlpha;
// Draw arrows to indicate that the list can scroll up or down.
// Arrow up
if (listOffset > 0) {
uint16_t arrowUpX = 140;
uint16_t arrowUpY = 76 - (this->bossRushArrowOffset / 10);
gDPLoadTextureBlock(POLY_OPA_DISP++, gArrowUpTex, G_IM_FMT_IA, G_IM_SIZ_16b, 16, 16, 0,
G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK,
G_TX_NOLOD, G_TX_NOLOD);
gSPWideTextureRectangle(POLY_OPA_DISP++, arrowUpX << 2, arrowUpY << 2, (arrowUpX + 8) << 2,
(arrowUpY + 8) << 2, G_TX_RENDERTILE, 0, 0, (1 << 11), (1 << 11));
}
// Arrow down
if (BR_OPTIONS_MAX - listOffset > BOSSRUSH_MAX_OPTIONS_ON_SCREEN) {
uint16_t arrowDownX = 140;
uint16_t arrowDownY = 181 + (this->bossRushArrowOffset / 10);
gDPLoadTextureBlock(POLY_OPA_DISP++, gArrowDownTex, G_IM_FMT_IA, G_IM_SIZ_16b, 16, 16, 0,
G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK,
G_TX_NOLOD, G_TX_NOLOD);
gSPWideTextureRectangle(POLY_OPA_DISP++, arrowDownX << 2, arrowDownY << 2, (arrowDownX + 8) << 2,
(arrowDownY + 8) << 2, G_TX_RENDERTILE, 0, 0, (1 << 11), (1 << 11));
}
// Draw options. There's more options than what fits on the screen, so the visible options
// depend on the current offset of the list. Currently selected option pulses in
// color and has arrows surrounding the option.
for (uint8_t i = listOffset; i - listOffset < BOSSRUSH_MAX_OPTIONS_ON_SCREEN; i++) {
uint16_t textYOffset = (i - listOffset) * 16;
// Option name.
Interface_DrawTextLine(this->state.gfxCtx, BossRush_GetSettingName(i, language), 65, (87 + textYOffset),
255, 255, 80, textAlpha, 0.8f, true);
// Selected choice for option.
uint16_t finalKerning = Interface_DrawTextLine(
this->state.gfxCtx,
BossRush_GetSettingChoiceName(i, gSaveContext.ship.quest.data.bossRush.options[i], language), 165,
(87 + textYOffset), 255, 255, 255, textAlpha, 0.8f, true);
// Draw arrows around selected option.
if (this->bossRushIndex == i) {
Gfx_SetupDL_39Opa(this->state.gfxCtx);
gDPSetCombineMode(POLY_OPA_DISP++, G_CC_MODULATEIA_PRIM, G_CC_MODULATEIA_PRIM);
gDPLoadTextureBlock(POLY_OPA_DISP++, gArrowCursorTex, G_IM_FMT_IA, G_IM_SIZ_8b, 16, 24, 0,
G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, 4, G_TX_NOMASK, G_TX_NOLOD,
G_TX_NOLOD);
FileChoose_DrawTextRec(this->state.gfxCtx, this->stickLeftPrompt.arrowColorR,
this->stickLeftPrompt.arrowColorG, this->stickLeftPrompt.arrowColorB, textAlpha,
160, (92 + textYOffset), 0.42f, 0, 0, -1.0f, 1.0f);
FileChoose_DrawTextRec(this->state.gfxCtx, this->stickRightPrompt.arrowColorR,
this->stickRightPrompt.arrowColorG, this->stickRightPrompt.arrowColorB,
textAlpha, (171 + finalKerning), (92 + textYOffset), 0.42f, 0, 0, 1.0f, 1.0f);
}
}
} else if (this->configMode == CM_RANDOMIZER_SETTINGS_MENU) { } else if (this->configMode == CM_RANDOMIZER_SETTINGS_MENU) {
uint8_t language = (gSaveContext.language == LANGUAGE_JPN) ? LANGUAGE_ENG : gSaveContext.language; uint8_t language = (gSaveContext.language == LANGUAGE_JPN) ? LANGUAGE_ENG : gSaveContext.language;
uint8_t textAlpha = this->randomizerUIAlpha; uint8_t textAlpha = this->randomizerUIAlpha;