Merge pull request #5961 from Malkierian/develop-copper

Copper -> Develop 11/14
This commit is contained in:
Malkierian
2025-11-14 12:29:38 -07:00
committed by GitHub
27 changed files with 269 additions and 215 deletions

View File

@@ -1,20 +0,0 @@
set(SPDLOG_LEVEL_TRACE 0)
set(SPDLOG_LEVEL_DEBUG 1)
set(SPDLOG_LEVEL_INFO 2)
set(SPDLOG_LEVEL_WARN 3)
set(SPDLOG_LEVEL_ERROR 4)
set(SPDLOG_LEVEL_CRITICAL 5)
set(SPDLOG_LEVEL_OFF 6)
set(LOG_LEVELS "SPDLOG_LEVEL_TRACE;SPDLOG_LEVEL_DEBUG;SPDLOG_LEVEL_INFO;SPDLOG_LEVEL_WARN;SPDLOG_LEVEL_ERROR;SPDLOG_LEVEL_CRITICAL;SPDLOG_LEVEL_OFF")
set(LOG_LEVEL SPDLOG_LEVEL_TRACE CACHE STRING "The spdlog level that prints will be logged out. Overridden to SPDLOG_LEVEL_ERROR on Release builds.")
set_property(CACHE LOG_LEVEL PROPERTY STRINGS ${LOG_LEVELS})
if(NOT LOG_LEVEL IN_LIST LOG_LEVELS)
message(FATAL_ERROR "LOG_LEVEL must be one of ${LOG_LEVELS}")
endif()
set(SPDLOG_ACTIVE_LEVEL ${${LOG_LEVEL}})
set(LOG_LEVEL_GAME_PRINTS ${SPDLOG_LEVEL_OFF})
add_compile_definitions(
LOG_LEVEL_GAME_PRINTS=${LOG_LEVEL_GAME_PRINTS}
SPDLOG_ACTIVE_LEVEL=${SPDLOG_ACTIVE_LEVEL}
)

View File

@@ -9,7 +9,9 @@ set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15" CACHE STRING "Minimum OS X deployment ve
project(Ship VERSION 9.1.1 LANGUAGES C CXX)
include(CMake/soh-cvars.cmake)
include(CMake/lus-cvars.cmake)
include(CMake/logging.cmake)
set(SPDLOG_LEVEL_TRACE 0)
set(SPDLOG_LEVEL_OFF 6)
set(SPDLOG_MIN_CUTOFF SPDLOG_LEVEL_TRACE CACHE STRING "cutoff at trace")
option(SUPPRESS_WARNINGS "Suppress warnings in LUS and src (decomp)" ON)
if(SUPPRESS_WARNINGS)

View File

@@ -337,13 +337,15 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
"ENABLE_DX11;"
">"
"$<$<CONFIG:Release>:"
"NDEBUG"
"NDEBUG;"
">"
"$<$<BOOL:${BUILD_REMOTE_CONTROL}>:ENABLE_REMOTE_CONTROL>"
"INCLUDE_GAME_PRINTF;"
"F3DEX_GBI_2"
"UNICODE;"
"_UNICODE"
SPDLOG_ACTIVE_LEVEL=${SPDLOG_MIN_CUTOFF}
LOG_LEVEL_GAME_PRINTS=${SPDLOG_LEVEL_OFF}
STORMLIB_NO_AUTO_LINK
"_CRT_SECURE_NO_WARNINGS;"
NOMINMAX
@@ -354,7 +356,7 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
"NOINCLUDE_GAME_PRINTF;"
"_DEBUG;"
"_CRT_SECURE_NO_WARNINGS;"
"ENABLE_OPENGL"
"ENABLE_OPENGL;"
">"
"$<$<CONFIG:Release>:"
"NDEBUG;"
@@ -363,7 +365,9 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
"F3DEX_GBI_2"
"WIN32;"
"UNICODE;"
"_UNICODE"
"_UNICODE;"
SPDLOG_ACTIVE_LEVEL=${SPDLOG_MIN_CUTOFF}
LOG_LEVEL_GAME_PRINTS=${SPDLOG_LEVEL_OFF}
STORMLIB_NO_AUTO_LINK
NOMINMAX
)
@@ -371,33 +375,35 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
elseif (CMAKE_SYSTEM_NAME STREQUAL "CafeOS")
target_compile_definitions(${PROJECT_NAME} PRIVATE
"$<$<CONFIG:Debug>:"
"_DEBUG"
"_DEBUG;"
">"
"$<$<CONFIG:Release>:"
"NDEBUG"
"NDEBUG;"
">"
"F3DEX_GBI_2"
"SPDLOG_ACTIVE_LEVEL=3;"
"F3DEX_GBI_2;"
"SPDLOG_NO_THREAD_ID;"
"SPDLOG_NO_TLS;"
"STBI_NO_THREAD_LOCALS;"
SPDLOG_ACTIVE_LEVEL=${SPDLOG_MIN_CUTOFF}
LOG_LEVEL_GAME_PRINTS=${SPDLOG_LEVEL_OFF}
)
elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU|Clang|AppleClang")
target_compile_definitions(${PROJECT_NAME} PRIVATE
"$<$<CONFIG:Debug>:"
"_DEBUG"
"_DEBUG;"
">"
"$<$<CONFIG:Release>:"
"NDEBUG"
"NDEBUG;"
">"
"F3DEX_GBI_2"
"$<$<BOOL:${BUILD_REMOTE_CONTROL}>:ENABLE_REMOTE_CONTROL>"
"SPDLOG_ACTIVE_LEVEL=0;"
"F3DEX_GBI_2;"
"$<$<BOOL:${BUILD_REMOTE_CONTROL}>:ENABLE_REMOTE_CONTROL>;"
"_CONSOLE;"
"_CRT_SECURE_NO_WARNINGS;"
"ENABLE_OPENGL;"
"UNICODE;"
"_UNICODE"
"_UNICODE;"
SPDLOG_ACTIVE_LEVEL=${SPDLOG_MIN_CUTOFF}
LOG_LEVEL_GAME_PRINTS=${SPDLOG_LEVEL_OFF}
)
endif()
################################################################################

View File

@@ -146,6 +146,9 @@ typedef enum {
/* 0x1B */ SLOT_BOOTS_KOKIRI,
/* 0x1C */ SLOT_BOOTS_IRON,
/* 0x1D */ SLOT_BOOTS_HOVER,
/* 0x1E */ SLOT_SHIELD_DEKU,
/* 0x1F */ SLOT_SHIELD_HYLIAN,
/* 0x20 */ SLOT_SHIELD_MIRROR,
/* 0xFF */ SLOT_NONE = 0xFF
} InventorySlot;

View File

@@ -14,7 +14,7 @@ extern PlayState* gPlayState;
static u16 sItemButtons[] = { BTN_B, BTN_CLEFT, BTN_CDOWN, BTN_CRIGHT, BTN_DUP, BTN_DDOWN, BTN_DLEFT, BTN_DRIGHT };
void UseTunicBoots(Player* player, PlayState* play, Input* input) {
static void UseTunicBoots(Player* player, PlayState* play, Input* input) {
// Boots and tunics equip despite state
if (player->stateFlags1 & (PLAYER_STATE1_INPUT_DISABLED | PLAYER_STATE1_IN_ITEM_CS | PLAYER_STATE1_IN_CUTSCENE |
PLAYER_STATE1_TALKING | PLAYER_STATE1_DEAD) ||
@@ -30,7 +30,7 @@ void UseTunicBoots(Player* player, PlayState* play, Input* input) {
}
}
if (item >= ITEM_TUNIC_KOKIRI && item <= ITEM_BOOTS_HOVER) {
if (item >= ITEM_SHIELD_DEKU && item <= ITEM_BOOTS_HOVER) {
if (item >= ITEM_BOOTS_KOKIRI) {
u16 bootsValue = item - ITEM_BOOTS_KOKIRI + 1;
if (CUR_EQUIP_VALUE(EQUIP_TYPE_BOOTS) == bootsValue) {
@@ -41,7 +41,7 @@ void UseTunicBoots(Player* player, PlayState* play, Input* input) {
Player_SetEquipmentData(play, player);
func_808328EC(player, CUR_EQUIP_VALUE(EQUIP_TYPE_BOOTS) == EQUIP_VALUE_BOOTS_IRON ? NA_SE_PL_WALK_HEAVYBOOTS
: NA_SE_PL_CHANGE_ARMS);
} else {
} else if (item >= ITEM_TUNIC_KOKIRI) {
u16 tunicValue = item - ITEM_TUNIC_KOKIRI + 1;
if (CUR_EQUIP_VALUE(EQUIP_TYPE_TUNIC) == tunicValue) {
Inventory_ChangeEquipment(EQUIP_TYPE_TUNIC, EQUIP_VALUE_TUNIC_KOKIRI);
@@ -50,45 +50,93 @@ void UseTunicBoots(Player* player, PlayState* play, Input* input) {
}
Player_SetEquipmentData(play, player);
func_808328EC(player, NA_SE_PL_CHANGE_ARMS);
} else {
u16 shieldValue = item - ITEM_SHIELD_DEKU + 1;
if (CUR_EQUIP_VALUE(EQUIP_TYPE_SHIELD) != shieldValue) {
Inventory_ChangeEquipment(EQUIP_TYPE_SHIELD, shieldValue);
Player_SetEquipmentData(play, player);
func_808328EC(player, NA_SE_PL_CHANGE_ARMS);
}
}
}
}
void ClearAssignedTunicsBoots(int32_t unused = 0) {
static void ClearAssignedTunicsBoots(int32_t unused = 0) {
for (int32_t buttonIndex = 0; buttonIndex < 8; buttonIndex++) {
int32_t item = gSaveContext.equips.buttonItems[buttonIndex];
if (item >= ITEM_TUNIC_KOKIRI && item <= ITEM_BOOTS_HOVER) {
if (item >= ITEM_SHIELD_DEKU && item <= ITEM_BOOTS_HOVER) {
gSaveContext.equips.buttonItems[buttonIndex] = ITEM_NONE;
}
}
}
static void ClearDeletedAssignedEquipment(int16_t equipmentType, uint16_t equipValue) {
ItemID itemToRemove = ITEM_NONE;
if (equipmentType == EQUIP_TYPE_TUNIC) {
switch (equipValue) {
case EQUIP_VALUE_TUNIC_KOKIRI:
break;
case EQUIP_VALUE_TUNIC_GORON:
itemToRemove = ITEM_TUNIC_GORON;
break;
case EQUIP_VALUE_TUNIC_ZORA:
itemToRemove = ITEM_TUNIC_ZORA;
break;
}
} else if (equipmentType == EQUIP_TYPE_SHIELD) {
switch (equipValue) {
case EQUIP_VALUE_SHIELD_DEKU:
itemToRemove = ITEM_SHIELD_DEKU;
break;
case EQUIP_VALUE_SHIELD_HYLIAN:
itemToRemove = ITEM_SHIELD_HYLIAN;
break;
case EQUIP_VALUE_SHIELD_MIRROR:
itemToRemove = ITEM_SHIELD_MIRROR;
break;
}
}
if (itemToRemove == ITEM_NONE) {
return;
}
for (int i = 1; i < ARRAY_COUNT(gSaveContext.equips.buttonItems); i++) {
if (gSaveContext.equips.buttonItems[i] == itemToRemove) {
gSaveContext.equips.buttonItems[i] = ITEM_NONE;
gSaveContext.equips.cButtonSlots[i - 1] = SLOT_NONE;
}
}
}
#define CVAR_TUNICBOOTS_NAME CVAR_ENHANCEMENT("AssignableTunicsAndBoots")
#define CVAR_TUNICBOOTS_DEFAULT 0
#define CVAR_TUNICBOOTS_VALUE CVarGetInteger(CVAR_TUNICBOOTS_NAME, CVAR_TUNICBOOTS_DEFAULT)
#define CVAR_TUNICBOOTS_SET (CVAR_TUNICBOOTS_VALUE != CVAR_TUNICBOOTS_DEFAULT)
void RegisterAssignableTunicsBoots() {
// make sure we don't change our held/equipped item when changing tunics/boots
COND_VB_SHOULD(VB_CHANGE_HELD_ITEM_AND_USE_ITEM, CVAR_TUNICBOOTS_VALUE != CVAR_TUNICBOOTS_DEFAULT, {
static void RegisterAssignableTunicsBoots() {
// make sure we don't change our held/equipped item when changing shield/tunic/boots
COND_VB_SHOULD(VB_CHANGE_HELD_ITEM_AND_USE_ITEM, CVAR_TUNICBOOTS_SET, {
int32_t item = va_arg(args, int32_t);
if (item >= ITEM_TUNIC_KOKIRI && item <= ITEM_BOOTS_HOVER) {
if (item >= ITEM_SHIELD_DEKU && item <= ITEM_BOOTS_HOVER) {
*should = false;
}
});
// make sure we don't crash because tunics/boots don't have assoicated item actions
COND_VB_SHOULD(VB_ITEM_ACTION_BE_NONE, CVAR_TUNICBOOTS_VALUE != CVAR_TUNICBOOTS_DEFAULT, {
COND_VB_SHOULD(VB_ITEM_ACTION_BE_NONE, CVAR_TUNICBOOTS_SET, {
int32_t item = va_arg(args, int32_t);
if (item >= ITEM_TUNIC_KOKIRI && item <= ITEM_BOOTS_HOVER) {
if (item >= ITEM_SHIELD_DEKU && item <= ITEM_BOOTS_HOVER) {
*should = true;
}
});
// don't throw items when the pressed button is a tunic or boots
COND_VB_SHOULD(VB_THROW_OR_PUT_DOWN_HELD_ITEM, CVAR_TUNICBOOTS_VALUE != CVAR_TUNICBOOTS_DEFAULT, {
// don't throw items when the pressed button is a shield, tunic or boots
COND_VB_SHOULD(VB_THROW_OR_PUT_DOWN_HELD_ITEM, CVAR_TUNICBOOTS_SET, {
// if the vanilla condition doesn't want us to throw/put down the item, early return
if (!*should) {
return;
@@ -104,13 +152,13 @@ void RegisterAssignableTunicsBoots() {
}
}
if (item >= ITEM_TUNIC_KOKIRI && item <= ITEM_BOOTS_HOVER) {
if (item >= ITEM_SHIELD_DEKU && item <= ITEM_BOOTS_HOVER) {
*should = false;
}
});
// do something when the player presses a button to use the tunics/boots
COND_VB_SHOULD(VB_EXECUTE_PLAYER_ACTION_FUNC, CVAR_TUNICBOOTS_VALUE != CVAR_TUNICBOOTS_DEFAULT, {
COND_VB_SHOULD(VB_EXECUTE_PLAYER_ACTION_FUNC, CVAR_TUNICBOOTS_SET, {
// if the vanilla condition doesn't want us to run the actionFunc, don't do any of this
if (!*should) {
return;
@@ -133,13 +181,16 @@ void RegisterAssignableTunicsBoots() {
UseTunicBoots(player, gPlayState, input);
});
// remove assigned equipment when it gets deleted
COND_HOOK(OnEquipmentDelete, CVAR_TUNICBOOTS_SET, ClearDeletedAssignedEquipment);
// clear out assigned tunics/boots when the enhancement is toggled off
if (GameInteractor::IsSaveLoaded(true) && CVAR_TUNICBOOTS_VALUE == CVAR_TUNICBOOTS_DEFAULT) {
if (GameInteractor::IsSaveLoaded(true) && !CVAR_TUNICBOOTS_SET) {
ClearAssignedTunicsBoots();
}
// clear out assigned tunics/boots when loading a save with enhancement turned off
COND_HOOK(OnLoadGame, CVAR_TUNICBOOTS_VALUE == CVAR_TUNICBOOTS_DEFAULT, ClearAssignedTunicsBoots);
COND_HOOK(OnLoadGame, !CVAR_TUNICBOOTS_SET, ClearAssignedTunicsBoots);
}
static RegisterShipInitFunc initFunc(RegisterAssignableTunicsBoots, { CVAR_TUNICBOOTS_NAME });

View File

@@ -13,7 +13,7 @@ extern PlayState* gPlayState;
#define CVAR_NAME CVAR_ENHANCEMENT("3DSceneRender")
#define CVAR_VALUE CVarGetInteger(CVAR_NAME, 0)
std::vector<SceneID> fogControlList = {
std::set<SceneID> fogControlList = {
SCENE_MARKET_ENTRANCE_DAY,
SCENE_MARKET_ENTRANCE_NIGHT,
SCENE_MARKET_ENTRANCE_RUINS,
@@ -46,7 +46,7 @@ std::vector<SceneID> fogControlList = {
SCENE_GRAVEKEEPERS_HUT,
};
std::vector<SceneID> skyboxSceneControlList = {
std::set<SceneID> skyboxSceneControlList = {
SCENE_MARKET_ENTRANCE_DAY,
SCENE_MARKET_ENTRANCE_NIGHT,
SCENE_MARKET_ENTRANCE_RUINS,
@@ -62,7 +62,7 @@ std::vector<SceneID> skyboxSceneControlList = {
SCENE_FOREST_TEMPLE,
};
std::vector<SkyboxId> skyboxIdControlList = {
std::set<SkyboxId> skyboxIdControlList = {
SKYBOX_BAZAAR,
SKYBOX_HOUSE_LINK,
SKYBOX_MARKET_ADULT,
@@ -88,74 +88,49 @@ std::vector<SkyboxId> skyboxIdControlList = {
void Register3DPreRenderedScenes() {
COND_HOOK(AfterSceneCommands, CVAR_VALUE, [](int16_t sceneNum) {
// Check if this scene is in the skyboxControlList
bool shouldControlSkybox = false;
for (const auto& scene : skyboxSceneControlList) {
if (sceneNum == scene) {
shouldControlSkybox = true;
break;
}
if (!skyboxSceneControlList.contains(static_cast<SceneID>(sceneNum))) {
return;
}
if (shouldControlSkybox) {
// Add a skybox on scenes from skyboxSceneControlList
gPlayState->envCtx.skyboxDisabled = false;
// Add a skybox on scenes from skyboxSceneControlList
gPlayState->envCtx.skyboxDisabled = false;
// Replace skybox with normal sky
gPlayState->skyboxId = SKYBOX_NORMAL_SKY;
// Apply the always cloudy skybox as an adult for Temple of Time and the Market
if (sceneNum == SCENE_TEMPLE_OF_TIME_EXTERIOR_RUINS || sceneNum == SCENE_MARKET_RUINS ||
sceneNum == SCENE_MARKET_ENTRANCE_RUINS) {
gWeatherMode = 3;
}
// Replace skybox with normal sky
gPlayState->skyboxId = SKYBOX_NORMAL_SKY;
// Apply the always cloudy skybox as an adult for Temple of Time and the Market
if (sceneNum == SCENE_TEMPLE_OF_TIME_EXTERIOR_RUINS || sceneNum == SCENE_MARKET_RUINS ||
sceneNum == SCENE_MARKET_ENTRANCE_RUINS) {
gWeatherMode = 3;
}
});
COND_HOOK(OnPlayDrawBegin, CVAR_VALUE, []() {
if (!CVarGetInteger(CVAR_ENHANCEMENT("3DSceneRender"), 0)) {
if (!fogControlList.contains(static_cast<SceneID>(gPlayState->sceneNum))) {
return;
}
for (auto& scene : fogControlList) {
if (scene == gPlayState->sceneNum) {
if ((HREG(80) != 10) || (HREG(82) != 0)) {
// Furthest possible fog and zFar
gPlayState->view.zFar = 12800;
gPlayState->lightCtx.fogNear = 996; // Set to 1000 to complete disable fog entirely
gPlayState->lightCtx.fogFar = 12800;
// General gray fog color
gPlayState->lightCtx.fogColor[0] = 100;
gPlayState->lightCtx.fogColor[1] = 100;
gPlayState->lightCtx.fogColor[2] = 100;
}
break;
}
}
});
REGISTER_VB_SHOULD(VB_DRAW_2D_BACKGROUND, {
if (CVAR_VALUE) {
*should = false;
return;
if ((HREG(80) != 10) || (HREG(82) != 0)) {
// Furthest possible fog and zFar
gPlayState->view.zFar = 12800;
gPlayState->lightCtx.fogNear = 996; // Set to 1000 to complete disable fog entirely
gPlayState->lightCtx.fogFar = 12800;
// General gray fog color
gPlayState->lightCtx.fogColor[0] = 100;
gPlayState->lightCtx.fogColor[1] = 100;
gPlayState->lightCtx.fogColor[2] = 100;
}
});
REGISTER_VB_SHOULD(VB_LOAD_SKYBOX, {
if (!gPlayState) {
COND_VB_SHOULD(VB_DRAW_2D_BACKGROUND, CVAR_VALUE, { *should = false; });
COND_VB_SHOULD(VB_LOAD_SKYBOX, CVAR_VALUE, {
if (!gPlayState || !skyboxIdControlList.contains(static_cast<SkyboxId>(gPlayState->skyboxCtx.skyboxId))) {
return;
}
if (!CVAR_VALUE) {
return;
}
for (auto& skybox : skyboxIdControlList) {
if (gPlayState->skyboxCtx.skyboxId == skybox) {
gPlayState->skyboxCtx.unk_140 = 0;
*should = false;
return;
}
}
gPlayState->skyboxCtx.unk_140 = 0;
*should = false;
});
}
static RegisterShipInitFunc initFunc(Register3DPreRenderedScenes, { CVAR_NAME });
static RegisterShipInitFunc initFunc(Register3DPreRenderedScenes, { CVAR_NAME });

View File

@@ -7,6 +7,7 @@
extern "C" {
extern PlayState* gPlayState;
#include "functions.h"
#include "macros.h"
#include "variables.h"
}
@@ -15,27 +16,31 @@ static uint64_t lastSaveTimestamp = GetUnixTimestamp();
#define CVAR_AUTOSAVE_NAME CVAR_ENHANCEMENT("Autosave")
#define CVAR_AUTOSAVE_DEFAULT AUTOSAVE_OFF
#define CVAR_AUTOSAVE_VALUE CVarGetInteger(CVAR_AUTOSAVE_NAME, CVAR_AUTOSAVE_DEFAULT)
#define THREE_MINUTES_IN_UNIX 3 * 60000
static constexpr uint64_t THREE_MINUTES_IN_UNIX = 3 * 60000;
typedef enum {
AUTOSAVE_OFF,
AUTOSAVE_ON,
} AutosaveOptions;
bool Autosave_CanSave() {
static bool Autosave_CanSave() {
// Don't save when in title screen or debug file
// Don't save a file that doesn't exist (e.g. it was deleted on death by user option)
// Don't save the first 60 frames to not save the magic meter when it's still in the animation of filling it.
// Don't save in Chamber of Sages and the Cutscene map because of remember save location and cutscene item gives.
if (!GameInteractor::IsSaveLoaded(false) || gPlayState->gameplayFrames < 60 ||
gPlayState->sceneNum == SCENE_CHAMBER_OF_THE_SAGES || gPlayState->sceneNum == SCENE_CUTSCENE_MAP) {
// Don't save between obtaining Ocarina of Time and Song of Time because the latter would become unobtainable.
if (!SaveManager::Instance->SaveFile_Exist(gSaveContext.fileNum) || !GameInteractor::IsSaveLoaded(false) ||
gPlayState->gameplayFrames < 60 || gPlayState->sceneNum == SCENE_CHAMBER_OF_THE_SAGES ||
gPlayState->sceneNum == SCENE_CUTSCENE_MAP ||
(!CHECK_QUEST_ITEM(QUEST_SONG_TIME) && (INV_CONTENT(ITEM_OCARINA_TIME) == ITEM_OCARINA_TIME))) {
return false;
}
return true;
}
void Autosave_PerformSave() {
static void Autosave_PerformSave() {
Play_PerformSave(gPlayState);
// Send notification
@@ -44,7 +49,7 @@ void Autosave_PerformSave() {
});
}
void Autosave_IntervalSave() {
static void Autosave_IntervalSave() {
// Check if the interval has passed in minutes.
uint64_t currentTimestamp = GetUnixTimestamp();
if ((currentTimestamp - lastSaveTimestamp) < THREE_MINUTES_IN_UNIX) {
@@ -64,13 +69,13 @@ void Autosave_IntervalSave() {
}
}
void Autosave_SoftResetSave() {
static void Autosave_SoftResetSave() {
if (Autosave_CanSave()) {
Autosave_PerformSave();
}
}
void RegisterAutosave() {
static void RegisterAutosave() {
COND_HOOK(GameInteractor::OnGameFrameUpdate, CVAR_AUTOSAVE_VALUE, Autosave_IntervalSave);
COND_HOOK(GameInteractor::OnExitGame, CVAR_AUTOSAVE_VALUE, [](int32_t fileNum) { Autosave_SoftResetSave(); });
}

View File

@@ -0,0 +1,37 @@
#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
#include "soh/OTRGlobals.h"
#include "soh/ShipInit.hpp"
extern "C" {
#include "src/overlays/actors/ovl_En_Door/z_en_door.h"
extern SaveContext gSaveContext;
extern PlayState* gPlayState;
}
static constexpr int32_t CVAR_DAMPE_ALL_NIGHT_DEFAULT = 0;
#define CVAR_DAMPE_ALL_NIGHT_NAME CVAR_ENHANCEMENT("DampeAllNight")
#define CVAR_DAMPE_ALL_NIGHT_VALUE CVarGetInteger(CVAR_DAMPE_ALL_NIGHT_NAME, CVAR_DAMPE_ALL_NIGHT_DEFAULT)
static constexpr s16 DAMPE_HUT_DOOR_OPEN = 447;
static constexpr s16 DAMPE_HUT_DOOR_CLOSED = 774;
static bool DampeIsResting() {
return LINK_IS_ADULT || gPlayState->sceneNum != SCENE_GRAVEYARD;
}
static void OpenDampeHutDoor(void* refActor) {
EnDoor* enDoor = static_cast<EnDoor*>(refActor);
s16* params = &enDoor->actor.params;
if (*params == DAMPE_HUT_DOOR_CLOSED && !DampeIsResting()) {
*params = DAMPE_HUT_DOOR_OPEN;
EnDoor_SetupType(enDoor, gPlayState);
}
}
static void RegisterDampeAllNight() {
COND_VB_SHOULD(VB_DAMPE_IN_GRAVEYARD_DESPAWN, CVAR_DAMPE_ALL_NIGHT_VALUE, { *should = DampeIsResting(); });
COND_ID_HOOK(OnActorInit, ACTOR_EN_DOOR, CVAR_DAMPE_ALL_NIGHT_VALUE, OpenDampeHutDoor);
}
static RegisterShipInitFunc initFunc(RegisterDampeAllNight, { CVAR_DAMPE_ALL_NIGHT_NAME });

View File

@@ -12,6 +12,7 @@ DEFINE_HOOK(OnExitGame, (int32_t fileNum));
DEFINE_HOOK(OnGameStateMainStart, ());
DEFINE_HOOK(OnGameFrameUpdate, ());
DEFINE_HOOK(OnItemReceive, (GetItemEntry itemEntry));
DEFINE_HOOK(OnEquipmentDelete, (int16_t equipmentType, uint16_t equipValue));
DEFINE_HOOK(OnSaleEnd, (GetItemEntry itemEntry));
DEFINE_HOOK(OnTransitionEnd, (int16_t sceneNum));
DEFINE_HOOK(OnSceneInit, (int16_t sceneNum));

View File

@@ -34,6 +34,11 @@ void GameInteractor_ExecuteOnItemReceiveHooks(GetItemEntry itemEntry) {
GameInteractor::Instance->ExecuteHooksForFilter<GameInteractor::OnItemReceive>(itemEntry);
}
void GameInteractor_ExecuteOnEquipmentDelete(int16_t equipmentType, uint16_t equipValue) {
GameInteractor::Instance->ExecuteHooks<GameInteractor::OnEquipmentDelete>(equipmentType, equipValue);
GameInteractor::Instance->ExecuteHooksForFilter<GameInteractor::OnEquipmentDelete>(equipmentType, equipValue);
}
void GameInteractor_ExecuteOnSaleEndHooks(GetItemEntry itemEntry) {
GameInteractor::Instance->ExecuteHooks<GameInteractor::OnSaleEnd>(itemEntry);
GameInteractor::Instance->ExecuteHooksForFilter<GameInteractor::OnSaleEnd>(itemEntry);

View File

@@ -15,6 +15,7 @@ void GameInteractor_ExecuteOnExitGame(int32_t fileNum);
void GameInteractor_ExecuteOnGameStateMainStart();
void GameInteractor_ExecuteOnGameFrameUpdate();
void GameInteractor_ExecuteOnItemReceiveHooks(GetItemEntry itemEntry);
void GameInteractor_ExecuteOnEquipmentDelete(int16_t equipmentType, uint16_t equipValue);
void GameInteractor_ExecuteOnSaleEndHooks(GetItemEntry itemEntry);
void GameInteractor_ExecuteOnTransitionEndHooks(int16_t sceneNum);
void GameInteractor_ExecuteOnSceneInit(int16_t sceneNum);

View File

@@ -1018,7 +1018,7 @@ static void FillExcludedLocations() {
FilterFromPool(ctx->allLocations, [ctx](const auto loc) { return ctx->GetItemLocation(loc)->IsExcluded(); });
for (RandomizerCheck loc : excludedLocations) {
PlaceJunkInExcludedLocation(loc);
ctx->PlaceItemInLocation(loc, GetJunkItem());
}
}

View File

@@ -350,19 +350,6 @@ static void ReplaceMaxItem(const RandomizerGet itemToReplace, int max) {
}
}
void PlaceJunkInExcludedLocation(const RandomizerCheck il) {
// place a non-advancement item in this location
auto ctx = Rando::Context::GetInstance();
for (size_t i = 0; i < ItemPool.size(); i++) {
if (Rando::StaticData::RetrieveItem(ItemPool[i]).GetCategory() == ITEM_CATEGORY_JUNK) {
ctx->PlaceItemInLocation(il, ItemPool[i]);
ItemPool.erase(ItemPool.begin() + i);
return;
}
}
SPDLOG_ERROR("ERROR: No Junk to Place!!!");
}
static void PlaceVanillaMapsAndCompasses() {
auto ctx = Rando::Context::GetInstance();
for (auto dungeon : ctx->GetDungeons()->GetDungeonList()) {

View File

@@ -9,7 +9,6 @@ class ItemLocation;
void AddItemToPool(std::vector<RandomizerGet>& pool, const RandomizerGet item, size_t count = 1);
RandomizerGet GetJunkItem();
void PlaceJunkInExcludedLocation(const RandomizerCheck il);
void GenerateItemPool();
extern std::vector<RandomizerGet> ItemPool;

View File

@@ -670,8 +670,7 @@ std::vector<Entrance*> EntranceShuffler::AssumeEntrancePool(std::vector<Entrance
(ctx->GetOption(RSK_SHUFFLE_OVERWORLD_ENTRANCES) ||
ctx->GetOption(RSK_SHUFFLE_INTERIOR_ENTRANCES).Is(RO_INTERIOR_ENTRANCE_SHUFFLE_ALL)))) {
auto type = entrance->GetType();
if (((type == EntranceType::Dungeon || type == EntranceType::ThievesHideout ||
type == EntranceType::GrottoGrave) &&
if (((type == EntranceType::Dungeon || type == EntranceType::GrottoGrave) &&
entrance->GetReverse()->GetName() !=
"Spirit Temple Entryway -> Desert Colossus From Spirit Entryway") ||
(type == EntranceType::Interior &&
@@ -796,10 +795,11 @@ static bool ValidateWorld(Entrance* entrancePlaced) {
bool checkOtherEntranceAccess =
(ctx->GetOption(RSK_SHUFFLE_OVERWORLD_ENTRANCES) ||
ctx->GetOption(RSK_SHUFFLE_INTERIOR_ENTRANCES).Is(RO_INTERIOR_ENTRANCE_SHUFFLE_ALL) ||
ctx->GetOption(RSK_SHUFFLE_OVERWORLD_SPAWNS)) &&
ctx->GetOption(RSK_SHUFFLE_THIEVES_HIDEOUT_ENTRANCES) || ctx->GetOption(RSK_SHUFFLE_OVERWORLD_SPAWNS)) &&
(entrancePlaced == nullptr || ctx->GetOption(RSK_MIXED_ENTRANCE_POOLS) ||
type == EntranceType::SpecialInterior || type == EntranceType::Overworld || type == EntranceType::Spawn ||
type == EntranceType::WarpSong || type == EntranceType::OwlDrop);
type == EntranceType::SpecialInterior || type == EntranceType::Overworld ||
type == EntranceType::ThievesHideout || type == EntranceType::Spawn || type == EntranceType::WarpSong ||
type == EntranceType::OwlDrop);
// Search the world to verify that all necessary conditions are still being held
// Conditions will be checked during the search and any that fail will be figured out
@@ -1333,6 +1333,7 @@ int EntranceShuffler::ShuffleAllEntrances() {
int totalMixedPools =
(ctx->GetOption(RSK_MIX_DUNGEON_ENTRANCES) ? 1 : 0) + (ctx->GetOption(RSK_MIX_BOSS_ENTRANCES) ? 1 : 0) +
(ctx->GetOption(RSK_MIX_OVERWORLD_ENTRANCES) ? 1 : 0) + (ctx->GetOption(RSK_MIX_INTERIOR_ENTRANCES) ? 1 : 0) +
(ctx->GetOption(RSK_MIX_THIEVES_HIDEOUT_ENTRANCES) ? 1 : 0) +
(ctx->GetOption(RSK_MIX_GROTTO_ENTRANCES) ? 1 : 0);
if (totalMixedPools < 2) {
ctx->GetOption(RSK_MIXED_ENTRANCE_POOLS).Set(RO_GENERIC_OFF);
@@ -1340,6 +1341,7 @@ int EntranceShuffler::ShuffleAllEntrances() {
ctx->GetOption(RSK_MIX_BOSS_ENTRANCES).Set(RO_GENERIC_OFF);
ctx->GetOption(RSK_MIX_OVERWORLD_ENTRANCES).Set(RO_GENERIC_OFF);
ctx->GetOption(RSK_MIX_INTERIOR_ENTRANCES).Set(RO_GENERIC_OFF);
ctx->GetOption(RSK_MIX_THIEVES_HIDEOUT_ENTRANCES).Set(RO_GENERIC_OFF);
ctx->GetOption(RSK_MIX_GROTTO_ENTRANCES).Set(RO_GENERIC_OFF);
}
if (ctx->GetOption(RSK_MIXED_ENTRANCE_POOLS)) {

View File

@@ -24,7 +24,7 @@ void RegionTable_Init_HauntedWasteland() {
//Locations
LOCATION(RC_WASTELAND_CHEST, logic->HasFireSource()),
LOCATION(RC_WASTELAND_BOMBCHU_SALESMAN, logic->CanJumpslash() || logic->CanUse(RG_HOVER_BOOTS)),
LOCATION(RC_WASTELAND_GS, logic->HookshotOrBoomerang() || (logic->IsAdult && logic->CanGroundJump() && logic->CanJumpslash())),
LOCATION(RC_WASTELAND_GS, logic->HookshotOrBoomerang() || (logic->IsAdult && ctx->GetTrickOption(RT_GROUND_JUMP_HARD) && logic->CanGroundJump() && logic->CanJumpslash())), // need to jumpslash immediately with two handed weapons
LOCATION(RC_WASTELAND_NEAR_GS_POT_1, logic->CanBreakPots()),
LOCATION(RC_WASTELAND_NEAR_GS_POT_2, logic->CanBreakPots()),
LOCATION(RC_WASTELAND_NEAR_GS_POT_3, logic->CanBreakPots()),

View File

@@ -4,7 +4,7 @@
using namespace Rando;
// clang-format off
// When Thieve's hideout entrances are shuffled, getting caught by guards should behave like void outs to avoid logic headaches.
// When Thieves' Hideout entrances are shuffled, getting caught by guards should behave like void outs to avoid logic headaches.
void RegionTable_Init_ThievesHideout() {
areaTable[RR_TH_1_TORCH_CELL] = Region("Thieves Hideout 1 Torch Cell", SCENE_THIEVES_HIDEOUT, {
//Events

View File

@@ -3,7 +3,6 @@
#include "soh/cvar_prefixes.h"
#include "soh/SohGui/SohGui.hpp"
#include <map>
#include <string>
#include <vector>
#include <libultraship/libultraship.h>
@@ -68,7 +67,7 @@ static std::string spoilerEntranceGroupNames[] = {
};
static std::string groupTypeNames[] = {
"One Way", "Overworld", "Interior", "Grotto", "Dungeon",
"One Way", "Overworld", "Interior", "Fortress", "Grotto", "Dungeon",
};
// Entrance data for the tracker taken from the 3ds rando entrance tracker, and supplemented with scene/spawn info and
@@ -328,32 +327,32 @@ const EntranceData entranceData[] = {
{ ENTR_GERUDO_TRAINING_GROUND_ENTRANCE, ENTR_GERUDOS_FORTRESS_OUTSIDE_GERUDO_TRAINING_GROUND, SINGLE_SCENE_INFO(SCENE_GERUDOS_FORTRESS), "GF Outside Training Ground", "Gerudo Training Ground Entrance", ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_TYPE_DUNGEON, "gtg", 1},
{ ENTRANCE_GROTTO_EXIT(GROTTO_GF_STORMS_OFFSET), ENTRANCE_GROTTO_LOAD(GROTTO_GF_STORMS_OFFSET), {{ SCENE_FAIRYS_FOUNTAIN, 0x00 }}, "GF Fairy Grotto", "GF Storms Grotto Entry", ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_TYPE_GROTTO, ""},
{ ENTR_GERUDOS_FORTRESS_OUTSIDE_GERUDO_TRAINING_GROUND, ENTR_GERUDO_TRAINING_GROUND_ENTRANCE, SINGLE_SCENE_INFO(SCENE_GERUDO_TRAINING_GROUND), "Gerudo Training Ground Entrance", "GF Outside Training Ground", ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_TYPE_DUNGEON, "gtg"},
{ ENTR_GERUDOS_FORTRESS_1, ENTR_THIEVES_HIDEOUT_0, SINGLE_SCENE_INFO(SCENE_THIEVES_HIDEOUT), "GF Outskirts", "TH 1 Torch Cell", ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_TYPE_DUNGEON},
{ ENTR_GERUDOS_FORTRESS_2, ENTR_THIEVES_HIDEOUT_1, SINGLE_SCENE_INFO(SCENE_THIEVES_HIDEOUT), "GF Near Grotto", "TH 1 Torch Cell", ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_TYPE_DUNGEON},
{ ENTR_GERUDOS_FORTRESS_3, ENTR_THIEVES_HIDEOUT_2, SINGLE_SCENE_INFO(SCENE_THIEVES_HIDEOUT), "GF Near Grotto", "TH Kitchen Corridor", ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_TYPE_DUNGEON},
{ ENTR_GERUDOS_FORTRESS_4, ENTR_THIEVES_HIDEOUT_3, SINGLE_SCENE_INFO(SCENE_THIEVES_HIDEOUT), "GF Above GTG", "TH Kitchen Corridor", ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_TYPE_DUNGEON},
{ ENTR_GERUDOS_FORTRESS_5, ENTR_THIEVES_HIDEOUT_4, SINGLE_SCENE_INFO(SCENE_THIEVES_HIDEOUT), "GF Near Grotto", "TH Steep Slope Cell", ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_TYPE_DUNGEON},
{ ENTR_GERUDOS_FORTRESS_6, ENTR_THIEVES_HIDEOUT_5, SINGLE_SCENE_INFO(SCENE_THIEVES_HIDEOUT), "GF Bottom of Lower Vines", "TH Steep Slope Cell", ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_TYPE_DUNGEON},
{ ENTR_GERUDOS_FORTRESS_7, ENTR_THIEVES_HIDEOUT_6, SINGLE_SCENE_INFO(SCENE_THIEVES_HIDEOUT), "GF Above GTG", "TH Double Cell", ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_TYPE_DUNGEON},
{ ENTR_GERUDOS_FORTRESS_8, ENTR_THIEVES_HIDEOUT_7, SINGLE_SCENE_INFO(SCENE_THIEVES_HIDEOUT), "GF Top of Lower Vines", "TH Double Cell", ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_TYPE_DUNGEON},
{ ENTR_GERUDOS_FORTRESS_9, ENTR_THIEVES_HIDEOUT_8, SINGLE_SCENE_INFO(SCENE_THIEVES_HIDEOUT), "GF Top of Lower Vines", "TH Kitchen By Corridor", ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_TYPE_DUNGEON},
{ ENTR_GERUDOS_FORTRESS_10, ENTR_THIEVES_HIDEOUT_9, SINGLE_SCENE_INFO(SCENE_THIEVES_HIDEOUT), "GF Near GS", "TH Kitchen Opposite Corridor", ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_TYPE_DUNGEON},
{ ENTR_GERUDOS_FORTRESS_11, ENTR_THIEVES_HIDEOUT_10, SINGLE_SCENE_INFO(SCENE_THIEVES_HIDEOUT), "GF Below Chest", "TH Break Room", ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_TYPE_DUNGEON},
{ ENTR_GERUDOS_FORTRESS_12, ENTR_THIEVES_HIDEOUT_11, SINGLE_SCENE_INFO(SCENE_THIEVES_HIDEOUT), "GF Above Jail", "TH Break Room Corridor", ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_TYPE_DUNGEON},
{ ENTR_GERUDOS_FORTRESS_13, ENTR_THIEVES_HIDEOUT_12, SINGLE_SCENE_INFO(SCENE_THIEVES_HIDEOUT), "GF Below GS", "TH Dead End Cell", ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_TYPE_DUNGEON},
{ ENTR_THIEVES_HIDEOUT_0, ENTR_GERUDOS_FORTRESS_1, SINGLE_SCENE_INFO(SCENE_GERUDOS_FORTRESS), "TH 1 Torch Cell", "GF Outskirts", ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_TYPE_DUNGEON},
{ ENTR_THIEVES_HIDEOUT_1, ENTR_GERUDOS_FORTRESS_2, SINGLE_SCENE_INFO(SCENE_GERUDOS_FORTRESS), "TH 1 Torch Cell", "GF Near Grotto", ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_TYPE_DUNGEON},
{ ENTR_THIEVES_HIDEOUT_2, ENTR_GERUDOS_FORTRESS_3, SINGLE_SCENE_INFO(SCENE_GERUDOS_FORTRESS), "TH Kitchen Corridor", "GF Near Grotto", ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_TYPE_DUNGEON},
{ ENTR_THIEVES_HIDEOUT_3, ENTR_GERUDOS_FORTRESS_4, SINGLE_SCENE_INFO(SCENE_GERUDOS_FORTRESS), "TH Kitchen Corridor", "GF Above GTG", ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_TYPE_DUNGEON},
{ ENTR_THIEVES_HIDEOUT_4, ENTR_GERUDOS_FORTRESS_5, SINGLE_SCENE_INFO(SCENE_GERUDOS_FORTRESS), "TH Steep Slope Cell", "GF Near Grotto", ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_TYPE_DUNGEON},
{ ENTR_THIEVES_HIDEOUT_5, ENTR_GERUDOS_FORTRESS_6, SINGLE_SCENE_INFO(SCENE_GERUDOS_FORTRESS), "TH Steep Slope Cell", "GF Bottom of Lower Vines", ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_TYPE_DUNGEON},
{ ENTR_THIEVES_HIDEOUT_6, ENTR_GERUDOS_FORTRESS_7, SINGLE_SCENE_INFO(SCENE_GERUDOS_FORTRESS), "TH Double Cell", "GF Above GTG", ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_TYPE_DUNGEON},
{ ENTR_THIEVES_HIDEOUT_7, ENTR_GERUDOS_FORTRESS_8, SINGLE_SCENE_INFO(SCENE_GERUDOS_FORTRESS), "TH Double Cell", "GF Top of Lower Vines", ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_TYPE_DUNGEON},
{ ENTR_THIEVES_HIDEOUT_8, ENTR_GERUDOS_FORTRESS_9, SINGLE_SCENE_INFO(SCENE_GERUDOS_FORTRESS), "TH Kitchen By Corridor", "GF Top of Lower Vines", ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_TYPE_DUNGEON},
{ ENTR_THIEVES_HIDEOUT_9, ENTR_GERUDOS_FORTRESS_10, SINGLE_SCENE_INFO(SCENE_GERUDOS_FORTRESS), "TH Kitchen Opposite Corridor", "GF Near GS", ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_TYPE_DUNGEON},
{ ENTR_THIEVES_HIDEOUT_10, ENTR_GERUDOS_FORTRESS_11, SINGLE_SCENE_INFO(SCENE_GERUDOS_FORTRESS), "TH Break Room", "GF Below Chest", ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_TYPE_DUNGEON},
{ ENTR_THIEVES_HIDEOUT_11, ENTR_GERUDOS_FORTRESS_12, SINGLE_SCENE_INFO(SCENE_GERUDOS_FORTRESS), "TH Break Room Corridor", "GF Above Jail", ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_TYPE_DUNGEON},
{ ENTR_THIEVES_HIDEOUT_12, ENTR_GERUDOS_FORTRESS_13, SINGLE_SCENE_INFO(SCENE_GERUDOS_FORTRESS), "TH Dead End Cell", "GF Below GS", ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_TYPE_DUNGEON},
{ ENTR_GERUDOS_FORTRESS_1, ENTR_THIEVES_HIDEOUT_0, {{ SCENE_THIEVES_HIDEOUT, 2 }}, "TH 1 Torch Cell Turn", "GF Outskirts", ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_TYPE_FORTRESS},
{ ENTR_GERUDOS_FORTRESS_2, ENTR_THIEVES_HIDEOUT_1, {{ SCENE_THIEVES_HIDEOUT, 2 }}, "TH 1 Torch Cell", "GF Near Grotto East", ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_TYPE_FORTRESS},
{ ENTR_GERUDOS_FORTRESS_3, ENTR_THIEVES_HIDEOUT_2, {{ SCENE_THIEVES_HIDEOUT, 3 }}, "TH Kitchen Corridor Lower", "GF Near Grotto North", ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_TYPE_FORTRESS},
{ ENTR_GERUDOS_FORTRESS_4, ENTR_THIEVES_HIDEOUT_3, {{ SCENE_THIEVES_HIDEOUT, 3 }}, "TH Kitchen Corridor Upper", "GF Above GTG", ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_TYPE_FORTRESS},
{ ENTR_GERUDOS_FORTRESS_5, ENTR_THIEVES_HIDEOUT_4, {{ SCENE_THIEVES_HIDEOUT, 4 }}, "TH Steep Slope Cell", "GF Near Grotto", ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_TYPE_FORTRESS},
{ ENTR_GERUDOS_FORTRESS_6, ENTR_THIEVES_HIDEOUT_5, {{ SCENE_THIEVES_HIDEOUT, 4 }}, "TH Steep Slope Cell Two Ramps", "GF Bottom of Lower Vines", ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_TYPE_FORTRESS},
{ ENTR_GERUDOS_FORTRESS_7, ENTR_THIEVES_HIDEOUT_6, {{ SCENE_THIEVES_HIDEOUT, 5 }}, "TH Double Cell Lower", "GF Above GTG Directly", ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_TYPE_FORTRESS},
{ ENTR_GERUDOS_FORTRESS_8, ENTR_THIEVES_HIDEOUT_7, {{ SCENE_THIEVES_HIDEOUT, 5 }}, "TH Double Cell Upper", "GF Top of Lower Vines Across", ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_TYPE_FORTRESS},
{ ENTR_GERUDOS_FORTRESS_9, ENTR_THIEVES_HIDEOUT_8, {{ SCENE_THIEVES_HIDEOUT, 3 }}, "TH Kitchen By Corridor", "GF Top of Lower Vines Near", ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_TYPE_FORTRESS},
{ ENTR_GERUDOS_FORTRESS_10, ENTR_THIEVES_HIDEOUT_9, {{ SCENE_THIEVES_HIDEOUT, 3 }}, "TH Kitchen Opposite Corridor", "GF Near GS", ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_TYPE_FORTRESS},
{ ENTR_GERUDOS_FORTRESS_11, ENTR_THIEVES_HIDEOUT_10, {{ SCENE_THIEVES_HIDEOUT, 0 }}, "TH Break Room", "GF Below Chest", ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_TYPE_FORTRESS},
{ ENTR_GERUDOS_FORTRESS_12, ENTR_THIEVES_HIDEOUT_11, {{ SCENE_THIEVES_HIDEOUT, 0 }}, "TH Break Room Corridor", "GF Above Jail", ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_TYPE_FORTRESS},
{ ENTR_GERUDOS_FORTRESS_13, ENTR_THIEVES_HIDEOUT_12, {{ SCENE_THIEVES_HIDEOUT, 1 }}, "TH Dead End Cell", "GF Below GS", ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_TYPE_FORTRESS},
{ ENTR_THIEVES_HIDEOUT_0, ENTR_GERUDOS_FORTRESS_1, SINGLE_SCENE_INFO(SCENE_GERUDOS_FORTRESS), "GF Outskirts", "TH 1 Torch Cell Turn", ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_TYPE_FORTRESS},
{ ENTR_THIEVES_HIDEOUT_1, ENTR_GERUDOS_FORTRESS_2, SINGLE_SCENE_INFO(SCENE_GERUDOS_FORTRESS), "GF Near Grotto East", "TH 1 Torch Cell", ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_TYPE_FORTRESS},
{ ENTR_THIEVES_HIDEOUT_2, ENTR_GERUDOS_FORTRESS_3, SINGLE_SCENE_INFO(SCENE_GERUDOS_FORTRESS), "GF Near Grotto North", "TH Kitchen Corridor Lower", ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_TYPE_FORTRESS},
{ ENTR_THIEVES_HIDEOUT_3, ENTR_GERUDOS_FORTRESS_4, SINGLE_SCENE_INFO(SCENE_GERUDOS_FORTRESS), "GF Above GTG", "TH Kitchen Corridor Upper", ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_TYPE_FORTRESS},
{ ENTR_THIEVES_HIDEOUT_4, ENTR_GERUDOS_FORTRESS_5, SINGLE_SCENE_INFO(SCENE_GERUDOS_FORTRESS), "GF Near Grotto", "TH Steep Slope Cell", ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_TYPE_FORTRESS},
{ ENTR_THIEVES_HIDEOUT_5, ENTR_GERUDOS_FORTRESS_6, SINGLE_SCENE_INFO(SCENE_GERUDOS_FORTRESS), "GF Bottom of Lower Vines", "TH Steep Slope Cell Two Ramps", ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_TYPE_FORTRESS},
{ ENTR_THIEVES_HIDEOUT_6, ENTR_GERUDOS_FORTRESS_7, SINGLE_SCENE_INFO(SCENE_GERUDOS_FORTRESS), "GF Above GTG Directly", "TH Double Cell Lower", ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_TYPE_FORTRESS},
{ ENTR_THIEVES_HIDEOUT_7, ENTR_GERUDOS_FORTRESS_8, SINGLE_SCENE_INFO(SCENE_GERUDOS_FORTRESS), "GF Top of Lower Vines Across", "TH Double Cell Upper", ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_TYPE_FORTRESS},
{ ENTR_THIEVES_HIDEOUT_8, ENTR_GERUDOS_FORTRESS_9, SINGLE_SCENE_INFO(SCENE_GERUDOS_FORTRESS), "GF Top of Lower Vines Near", "TH Kitchen By Corridor", ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_TYPE_FORTRESS},
{ ENTR_THIEVES_HIDEOUT_9, ENTR_GERUDOS_FORTRESS_10, SINGLE_SCENE_INFO(SCENE_GERUDOS_FORTRESS), "GF Near GS", "TH Kitchen Opposite Corridor", ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_TYPE_FORTRESS},
{ ENTR_THIEVES_HIDEOUT_10, ENTR_GERUDOS_FORTRESS_11, SINGLE_SCENE_INFO(SCENE_GERUDOS_FORTRESS), "GF Below Chest", "TH Break Room", ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_TYPE_FORTRESS},
{ ENTR_THIEVES_HIDEOUT_11, ENTR_GERUDOS_FORTRESS_12, SINGLE_SCENE_INFO(SCENE_GERUDOS_FORTRESS), "GF Above Jail", "TH Break Room Corridor", ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_TYPE_FORTRESS},
{ ENTR_THIEVES_HIDEOUT_12, ENTR_GERUDOS_FORTRESS_13, SINGLE_SCENE_INFO(SCENE_GERUDOS_FORTRESS), "GF Below GS", "TH Dead End Cell", ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_TYPE_FORTRESS},
// The Wasteland
{ ENTR_GERUDOS_FORTRESS_GATE_EXIT, ENTR_HAUNTED_WASTELAND_EAST_EXIT, SINGLE_SCENE_INFO(SCENE_HAUNTED_WASTELAND), "Haunted Wasteland East Exit", "Gerudo Fortress Gate Exit", ENTRANCE_GROUP_HAUNTED_WASTELAND, ENTRANCE_GROUP_GERUDO_FORTRESS, ENTRANCE_TYPE_OVERWORLD, "hw,gf"},
@@ -433,11 +432,13 @@ int16_t LinkIsInArea(const EntranceData* entrance) {
// Otherwise check all scenes/spawns
// Not all areas require a spawn position to differeniate between another area
for (auto info : entrance->scenes) {
// When a spawn position is specified, check that combination
if (info.spawn != -1) {
result = Entrance_SceneAndSpawnAre(info.scene, info.spawn);
} else { // Otherwise just check the current scene
// only check current scene when spawn info missing
if (info.spawn == -1) {
result = gPlayState->sceneNum == info.scene;
} else if (gPlayState->sceneNum == SCENE_THIEVES_HIDEOUT) { // group by rooms, not spawn
result = info.scene == SCENE_THIEVES_HIDEOUT && gPlayState->roomCtx.curRoom.num == info.spawn;
} else { // Otherwise just check scene & spawn
result = Entrance_SceneAndSpawnAre(info.scene, info.spawn);
}
// Return the scene for tracking
@@ -514,7 +515,7 @@ void SortEntranceListByType(EntranceOverride* entranceList, u8 byDest) {
break;
}
size_t entranceIndex = byDest ? tempList[j].override : tempList[j].index;
int16_t entranceIndex = byDest ? tempList[j].override : tempList[j].index;
if (entranceData[i].type == k && entranceIndex == entranceData[i].index) {
entranceList[idx] = tempList[j];
@@ -838,7 +839,7 @@ void EntranceTrackerWindow::DrawElement() {
// Combine destToggle and groupToggle to get a range of 0-3
uint8_t groupType = destToggle + (groupToggle * 2);
size_t groupCount = groupToggle ? ENTRANCE_TYPE_COUNT : SPOILER_ENTRANCE_GROUP_COUNT;
size_t groupCount = groupToggle ? (size_t)ENTRANCE_TYPE_COUNT : (size_t)SPOILER_ENTRANCE_GROUP_COUNT;
auto groupNames = groupToggle ? groupTypeNames : spoilerEntranceGroupNames;
EntranceOverride* entranceList;
@@ -874,7 +875,7 @@ void EntranceTrackerWindow::DrawElement() {
uint16_t startIndex = gEntranceTrackingData.GroupOffsets[groupType][i];
bool doAreaScroll = false;
size_t undiscovered = 0;
int undiscovered = 0;
std::vector<EntranceOverride> displayEntrances = {};
// Loop over entrances first for filtering
@@ -934,10 +935,8 @@ void EntranceTrackerWindow::DrawElement() {
}
displayEntrances.push_back(entrance);
} else {
if (!isDiscovered) {
undiscovered++;
}
} else if (!isDiscovered) {
undiscovered++;
}
}
@@ -990,8 +989,7 @@ void EntranceTrackerWindow::DrawElement() {
ImGui::PushStyleColor(ImGuiCol_Text, color);
// Use a non-breaking space to keep the arrow from wrapping to a newline by itself
auto nbsp = u8"\u00A0";
ImGui::TextWrapped("%s%s-> %s", origSrcName, nbsp, rplcDstName);
ImGui::TextWrapped("%s\u00A0-> %s", origSrcName, rplcDstName);
ImGui::PopStyleColor();
}

View File

@@ -37,6 +37,7 @@ typedef enum {
ENTRANCE_TYPE_ONE_WAY,
ENTRANCE_TYPE_OVERWORLD,
ENTRANCE_TYPE_INTERIOR,
ENTRANCE_TYPE_FORTRESS,
ENTRANCE_TYPE_GROTTO,
ENTRANCE_TYPE_DUNGEON,
ENTRANCE_TYPE_COUNT,

View File

@@ -709,11 +709,6 @@ void TimeSaverOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, va_li
*should = false;
}
break;
case VB_DAMPE_IN_GRAVEYARD_DESPAWN:
if (CVarGetInteger(CVAR_ENHANCEMENT("DampeAllNight"), 0)) {
*should = LINK_IS_ADULT || gPlayState->sceneNum != SCENE_GRAVEYARD;
}
break;
case VB_BE_VALID_GRAVEDIGGING_SPOT:
if (CVarGetInteger(CVAR_ENHANCEMENT("DampeWin"), IS_RANDO)) {
EnTk* enTk = va_arg(args, EnTk*);

View File

@@ -290,10 +290,19 @@ void OTRGlobals::Initialize() {
OOT_NTSC_JP_GC, OOT_NTSC_US_GC, OOT_PAL_GC, OOT_PAL_GC_DBG1, OOT_PAL_GC_DBG2,
};
context->InitLogging();
context->InitGfxDebugger();
#if (_DEBUG)
auto defaultLogLevel = spdlog::level::trace;
#else
auto defaultLogLevel = spdlog::level::info;
#endif
auto logLevel =
static_cast<spdlog::level::level_enum>(CVarGetInteger(CVAR_DEVELOPER_TOOLS("LogLevel"), defaultLogLevel));
context->InitLogging(logLevel, logLevel);
Ship::Context::GetInstance()->GetLogger()->set_pattern("[%H:%M:%S.%e] [%s:%#] [%l] %v");
context->InitConfiguration();
context->InitConsoleVariables();
context->InitGfxDebugger();
context->InitFileDropMgr();
// tell LUS to reserve 3 SoH specific threads (Game, Audio, Save)
@@ -318,15 +327,6 @@ void OTRGlobals::Initialize() {
context->InitCrashHandler();
context->InitConsole();
#if (_DEBUG)
int defaultLogLevel = 0;
#else
int defaultLogLevel = 2;
#endif
Ship::Context::GetInstance()->GetLogger()->set_level(
(spdlog::level::level_enum)CVarGetInteger(CVAR_DEVELOPER_TOOLS("LogLevel"), defaultLogLevel));
Ship::Context::GetInstance()->GetLogger()->set_pattern("[%H:%M:%S.%e] [%s:%#] [%l] %v");
auto sohInputEditorWindow =
std::make_shared<SohInputEditorWindow>(CVAR_WINDOW("ControllerConfiguration"), "Configure Controller");
auto sohFast3dWindow =

View File

@@ -11,6 +11,12 @@ static const std::unordered_map<int32_t, const char*> logLevels = {
{ DEBUG_LOG_OFF, "Off" },
};
#ifdef _DEBUG
DebugLogOption defaultLogLevel = DEBUG_LOG_TRACE;
#else
DebugLogOption defaultLogLevel = DEBUG_LOG_INFO;
#endif
static const std::unordered_map<int32_t, const char*> debugSaveFileModes = {
{ 0, "Off" },
{ 1, "Vanilla" },
@@ -110,10 +116,11 @@ void SohMenu::AddMenuDevTools() {
.Options(ComboboxOptions()
.Tooltip("The log level determines which messages are printed to the console."
" This does not affect the log file output")
.ComboMap(logLevels))
.ComboMap(logLevels)
.DefaultIndex(defaultLogLevel))
.Callback([](WidgetInfo& info) {
Ship::Context::GetInstance()->GetLogger()->set_level(
(spdlog::level::level_enum)CVarGetInteger(CVAR_DEVELOPER_TOOLS("LogLevel"), DEBUG_LOG_DEBUG));
(spdlog::level::level_enum)CVarGetInteger(CVAR_DEVELOPER_TOOLS("LogLevel"), defaultLogLevel));
})
.PreFunc([](WidgetInfo& info) { info.isHidden = mSohMenu->disabledMap.at(DISABLE_FOR_DEBUG_MODE_OFF).active; });

View File

@@ -732,9 +732,9 @@ void SohMenu::AddMenuEnhancements() {
.Options(CheckboxOptions().Tooltip(
"Equip items and equipment on the D-pad. If used with \"D-pad on Pause Screen\", you must "
"hold C-Up to equip instead of navigate."));
AddWidget(path, "Assignable Tunics and Boots", WIDGET_CVAR_CHECKBOX)
AddWidget(path, "Assignable Shields, Tunics and Boots", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_ENHANCEMENT("AssignableTunicsAndBoots"))
.Options(CheckboxOptions().Tooltip("Allows equipping the Tunics and Boots to C-Buttons/D-pad."));
.Options(CheckboxOptions().Tooltip("Allows equipping Shields, Tunics and Boots to C-Buttons/D-pad."));
// TODO: Revist strength toggle, it's currently separate but should probably be locked behind the
// Equipment toggle settings or be absorbed by it completely.
AddWidget(path, "Equipment Toggle", WIDGET_CVAR_CHECKBOX)

View File

@@ -472,13 +472,12 @@ extern "C" s32 OTRfunc_800973FC(PlayState* play, RoomContext* roomCtx) {
gSegments[3] = VIRTUAL_TO_PHYSICAL(roomCtx->unk_34);
OTRScene_ExecuteCommands(play, (SOH::Scene*)roomCtx->roomToLoad);
if (!GameInteractor_Should(VB_DRAW_2D_BACKGROUND, true)) {
play->envCtx.skyboxDisabled = false;
}
Player_SetBootData(play, GET_PLAYER(play));
Actor_SpawnTransitionActors(play, &play->actorCtx);
GameInteractor_ExecuteAfterSceneCommands(play->sceneNum);
return 1;
}

View File

@@ -1,4 +1,5 @@
#include "global.h"
#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
#include "textures/icon_item_static/icon_item_static.h"
#include "textures/icon_item_24_static/icon_item_24_static.h"
#include "textures/parameter_static/parameter_static.h"
@@ -204,20 +205,10 @@ u8 Inventory_DeleteEquipment(PlayState* play, s16 equipment) {
if (equipment == EQUIP_TYPE_TUNIC) {
gSaveContext.equips.equipment |= EQUIP_VALUE_TUNIC_KOKIRI << (EQUIP_TYPE_TUNIC * 4);
// non-vanilla: remove goron and zora tunics from item buttons if assignable tunics is on
if (CVarGetInteger(CVAR_ENHANCEMENT("AssignableTunicsAndBoots"), 0) &&
equipValue != EQUIP_VALUE_TUNIC_KOKIRI) {
ItemID item = (equipValue == EQUIP_VALUE_TUNIC_GORON ? ITEM_TUNIC_GORON : ITEM_TUNIC_ZORA);
for (int i = 1; i < ARRAY_COUNT(gSaveContext.equips.buttonItems); i++) {
if (gSaveContext.equips.buttonItems[i] == item) {
gSaveContext.equips.buttonItems[i] = ITEM_NONE;
gSaveContext.equips.cButtonSlots[i - 1] = SLOT_NONE;
}
}
}
// end non-vanilla
}
GameInteractor_ExecuteOnEquipmentDelete(equipment, equipValue);
if (equipment == EQUIP_TYPE_SWORD) {
gSaveContext.equips.buttonItems[0] = ITEM_NONE;
gSaveContext.infTable[29] = 1;

View File

@@ -642,8 +642,8 @@ void KaleidoScope_DrawEquipment(PlayState* play) {
pauseCtx->unk_1E4 = 7;
sEquipTimer = 10;
} else if (CVarGetInteger(CVAR_ENHANCEMENT("AssignableTunicsAndBoots"), 0) != 0) {
// Only allow assigning tunic and boots to c-buttons
if (pauseCtx->cursorY[PAUSE_EQUIP] > 1) {
// Only allow assigning shield, tunic and boots to c-buttons
if (pauseCtx->cursorY[PAUSE_EQUIP] > 0) {
if (CHECK_OWNED_EQUIP(pauseCtx->cursorY[PAUSE_EQUIP], pauseCtx->cursorX[PAUSE_EQUIP] - 1)) {
u16 slot = 0;
switch (cursorItem) {
@@ -665,6 +665,15 @@ void KaleidoScope_DrawEquipment(PlayState* play) {
case ITEM_BOOTS_HOVER:
slot = SLOT_BOOTS_HOVER;
break;
case ITEM_SHIELD_DEKU:
slot = SLOT_SHIELD_DEKU;
break;
case ITEM_SHIELD_HYLIAN:
slot = SLOT_SHIELD_HYLIAN;
break;
case ITEM_SHIELD_MIRROR:
slot = SLOT_SHIELD_MIRROR;
break;
default:
break;
}