Merge branch 'develop' into aManchipelago

This commit is contained in:
aMannus
2025-10-20 20:48:41 +02:00
8 changed files with 253 additions and 119 deletions

View File

@@ -1,17 +1,32 @@
#include "mod_menu.h"
#include <ship/utils/StringHelper.h>
#include <libultraship/classes.h>
#include "soh/SohGui/SohGui.hpp"
#include "soh/OTRGlobals.h"
#include "soh/resource/type/Skeleton.h"
#include <map> #include <map>
#include <ranges> #include <ranges>
#include <vector> #include <vector>
#include <libultraship/classes.h>
#include <ship/utils/StringHelper.h>
#include "mod_menu.h"
#include "soh/OTRGlobals.h"
#include "soh/resource/type/Skeleton.h"
#include "soh/SohGui/MenuTypes.h"
#include "soh/SohGui/SohMenu.h"
#include "soh/SohGui/SohGui.hpp"
std::vector<std::string> enabledModFiles; std::vector<std::string> enabledModFiles;
std::vector<std::string> disabledModFiles; std::vector<std::string> disabledModFiles;
std::vector<std::string> unsupportedFiles;
std::map<std::string, std::filesystem::path> filePaths;
static int dragSourceIndex = -1;
static int dragTargetIndex = -1;
#define CVAR_ENABLED_MODS_NAME CVAR_GENERAL("EnabledMods") namespace SohGui {
extern std::shared_ptr<SohMenu> mSohMenu;
}
static WidgetInfo enableModsWidget;
static WidgetInfo tabHotkeyWidget;
#define CVAR_ENABLED_MODS_NAME CVAR_SETTING("EnabledMods")
#define CVAR_ENABLED_MODS_DEFAULT "" #define CVAR_ENABLED_MODS_DEFAULT ""
#define CVAR_ENABLED_MODS_VALUE CVarGetString(CVAR_ENABLED_MODS_NAME, CVAR_ENABLED_MODS_DEFAULT) #define CVAR_ENABLED_MODS_VALUE CVarGetString(CVAR_ENABLED_MODS_NAME, CVAR_ENABLED_MODS_DEFAULT)
@@ -42,6 +57,42 @@ void SetEnabledModsCVarValue() {
CVarSetString(CVAR_ENABLED_MODS_NAME, s.c_str()); CVarSetString(CVAR_ENABLED_MODS_NAME, s.c_str());
} }
void AfterModChange() {
// disabled mods are always sorted
std::sort(disabledModFiles.begin(), disabledModFiles.end(), [](const std::string& a, const std::string& b) {
return std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end(),
[](char c1, char c2) { return std::tolower(c1) < std::tolower(c2); });
});
}
void ModsPostDragAndDrop() {
if (dragTargetIndex != -1) {
std::string file = enabledModFiles[dragSourceIndex];
enabledModFiles.erase(enabledModFiles.begin() + dragSourceIndex);
enabledModFiles.insert(enabledModFiles.begin() + dragTargetIndex, file);
dragTargetIndex = dragSourceIndex = -1;
AfterModChange();
}
}
void ModsHandleDragAndDrop(std::vector<std::string>& objectList, int targetIndex, const std::string& itemName,
ImGuiDragDropFlags flags = ImGuiDragDropFlags_SourceAllowNullID) {
if (ImGui::BeginDragDropSource(flags)) {
ImGui::SetDragDropPayload("DragMove", &targetIndex, sizeof(uint32_t));
ImGui::Text("Move %s", itemName.c_str());
ImGui::EndDragDropSource();
}
if (ImGui::BeginDragDropTarget()) {
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("DragMove")) {
IM_ASSERT(payload->DataSize == sizeof(uint32_t));
dragSourceIndex = *(const int*)payload->Data;
dragTargetIndex = targetIndex;
}
ImGui::EndDragDropTarget();
}
}
std::vector<std::string> GetEnabledModsFromCVar() { std::vector<std::string> GetEnabledModsFromCVar() {
std::string enabledModsCVarValue = CVAR_ENABLED_MODS_VALUE; std::string enabledModsCVarValue = CVAR_ENABLED_MODS_VALUE;
return StringHelper::Split(enabledModsCVarValue, SEPARATOR); return StringHelper::Split(enabledModsCVarValue, SEPARATOR);
@@ -55,58 +106,71 @@ std::shared_ptr<Ship::ArchiveManager> GetArchiveManager() {
return Ship::Context::GetInstance()->GetResourceManager()->GetArchiveManager(); return Ship::Context::GetInstance()->GetResourceManager()->GetArchiveManager();
} }
void UpdateModFiles(bool init = false) { bool IsValidExtension(std::string extension) {
if (init) { if (
#ifdef INCLUDE_MPQ_SUPPORT
// .mpq doesn't make sense to support because all tools to make such mods output OTR
StringHelper::IEquals(extension, ".otr") /*|| StringHelper::IEquals(extension, ".mpq")*/ ||
#endif
// .zip needs to be excluded because mods are most often distributed in zip archives
// and thus could contain .otr/o2r files
StringHelper::IEquals(extension, ".o2r") /*|| StringHelper::IEquals(extension, ".zip")*/) {
return true;
}
return false;
}
void UpdateModFiles(bool init = false, bool reset = false) {
if (init || reset) {
enabledModFiles.clear(); enabledModFiles.clear();
enabledModFiles = GetEnabledModsFromCVar();
} }
disabledModFiles.clear(); disabledModFiles.clear();
std::vector<std::string> enabledMods = GetEnabledModsFromCVar(); unsupportedFiles.clear();
filePaths.clear();
std::string modsPath = Ship::Context::LocateFileAcrossAppDirs("mods", appShortName); std::string modsPath = Ship::Context::LocateFileAcrossAppDirs("mods", appShortName);
bool changed = false;
if (modsPath.length() > 0 && std::filesystem::exists(modsPath)) { if (modsPath.length() > 0 && std::filesystem::exists(modsPath)) {
std::vector<std::filesystem::path> enabledFiles;
if (std::filesystem::is_directory(modsPath)) { if (std::filesystem::is_directory(modsPath)) {
for (const std::filesystem::directory_entry& p : std::filesystem::recursive_directory_iterator( for (const std::filesystem::directory_entry& p : std::filesystem::recursive_directory_iterator(
modsPath, std::filesystem::directory_options::follow_directory_symlink)) { modsPath, std::filesystem::directory_options::follow_directory_symlink)) {
std::string extension = p.path().extension().string(); if (p.is_directory()) {
if ( continue;
#ifndef EXCLUDE_MPQ_SUPPORT }
StringHelper::IEquals(extension, ".otr") || StringHelper::IEquals(extension, ".mpq") || std::string filename =
#endif p.path().filename().generic_string().substr(0, p.path().filename().generic_string().rfind("."));
StringHelper::IEquals(extension, ".o2r") || StringHelper::IEquals(extension, ".zip")) { std::string extension = p.path().extension().generic_string();
std::string path = p.path().generic_string(); if (!IsValidExtension(extension)) {
bool shouldBeEnabled = std::find(enabledMods.begin(), enabledMods.end(), path) != enabledMods.end(); continue;
}
if (shouldBeEnabled) { bool enabled =
std::find(enabledModFiles.begin(), enabledModFiles.end(), filename) != enabledModFiles.end();
if (!enabled) {
enabledModFiles.push_back(filename);
changed = true;
}
filePaths.emplace(filename, p.path());
}
if (init) { if (init) {
enabledModFiles.push_back(path); std::vector<std::string> enabledTemp(enabledModFiles);
GetArchiveManager()->AddArchive(path); for (std::string mod : enabledTemp) {
} if (filePaths.contains(mod)) {
GetArchiveManager()->AddArchive(filePaths.at(mod).generic_string());
} else { } else {
disabledModFiles.push_back(path); enabledModFiles.erase(std::find(enabledModFiles.begin(), enabledModFiles.end(), mod));
} }
} }
} }
} }
} }
if (changed) {
SetEnabledModsCVarValue();
}
} }
extern "C" void gfx_texture_cache_clear(); extern "C" void gfx_texture_cache_clear();
void AfterModChange() {
SetEnabledModsCVarValue();
// TODO: runtime changes
/*
gfx_texture_cache_clear();
SOH::SkeletonPatcher::ClearSkeletons();
*/
Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame();
// disabled mods are always sorted
std::sort(disabledModFiles.begin(), disabledModFiles.end(), [](const std::string& a, const std::string& b) {
return std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end(),
[](char c1, char c2) { return std::tolower(c1) < std::tolower(c2); });
});
}
void EnableMod(std::string file) { void EnableMod(std::string file) {
disabledModFiles.erase(std::find(disabledModFiles.begin(), disabledModFiles.end(), file)); disabledModFiles.erase(std::find(disabledModFiles.begin(), disabledModFiles.end(), file));
enabledModFiles.insert(enabledModFiles.begin(), file); enabledModFiles.insert(enabledModFiles.begin(), file);
@@ -139,39 +203,30 @@ void DrawMods(bool enabled) {
bool madeAnyChange = false; bool madeAnyChange = false;
int switchFromIndex = -1; int switchFromIndex = -1;
int switchToIndex = -1; int switchToIndex = -1;
uint32_t index = 0;
for (int i = 0; i < selectedModFiles.size(); i += 1) { for (int i = selectedModFiles.size() - 1; i >= 0; i--) {
std::string file = selectedModFiles[i]; std::string file = selectedModFiles[i];
if (UIWidgets::StateButton((file + "_left_right").c_str(), enabled ? ICON_FA_ARROW_LEFT : ICON_FA_ARROW_RIGHT,
ImVec2(25, 25), UIWidgets::ButtonOptions().Color(THEME_COLOR))) {
if (enabled) { if (enabled) {
DisableMod(file); ImGui::BeginGroup();
} else {
EnableMod(file);
}
} }
// if (UIWidgets::StateButton((file + "_left_right").c_str(), enabled ? ICON_FA_ARROW_RIGHT :
// ICON_FA_ARROW_LEFT,
// ImVec2(25, 25), UIWidgets::ButtonOptions().Color(THEME_COLOR))) {
// if (enabled) {
// DisableMod(file);
// } else {
// EnableMod(file);
// }
// }
// it's not relevant to reorder disabled mods // it's not relevant to reorder disabled mods
if (enabled) { if (enabled) {
ImGui::SameLine(); // ImGui::SameLine();
if (i == 0) {
ImGui::BeginDisabled();
}
if (UIWidgets::StateButton((file + "_up").c_str(), ICON_FA_ARROW_UP, ImVec2(25, 25),
UIWidgets::ButtonOptions().Color(THEME_COLOR))) {
madeAnyChange = true;
switchFromIndex = i;
switchToIndex = i - 1;
}
if (i == 0) {
ImGui::EndDisabled();
}
ImGui::SameLine();
if (i == selectedModFiles.size() - 1) { if (i == selectedModFiles.size() - 1) {
ImGui::BeginDisabled(); ImGui::BeginDisabled();
} }
if (UIWidgets::StateButton((file + "_down").c_str(), ICON_FA_ARROW_DOWN, ImVec2(25, 25), if (UIWidgets::StateButton((file + "_up").c_str(), ICON_FA_ARROW_UP, ImVec2(25, 25),
UIWidgets::ButtonOptions().Color(THEME_COLOR))) { UIWidgets::ButtonOptions().Color(THEME_COLOR))) {
madeAnyChange = true; madeAnyChange = true;
switchFromIndex = i; switchFromIndex = i;
@@ -180,9 +235,31 @@ void DrawMods(bool enabled) {
if (i == selectedModFiles.size() - 1) { if (i == selectedModFiles.size() - 1) {
ImGui::EndDisabled(); ImGui::EndDisabled();
} }
ImGui::SameLine();
if (i == 0) {
ImGui::BeginDisabled();
}
if (UIWidgets::StateButton((file + "_down").c_str(), ICON_FA_ARROW_DOWN, ImVec2(25, 25),
UIWidgets::ButtonOptions().Color(THEME_COLOR))) {
madeAnyChange = true;
switchFromIndex = i;
switchToIndex = i - 1;
}
if (i == 0) {
ImGui::EndDisabled();
}
} }
DrawModInfo(file); DrawModInfo(filePaths.at(file).filename().generic_string());
if (enabled) {
ImGui::EndGroup();
ModsHandleDragAndDrop(selectedModFiles, i, file);
}
}
if (enabled) {
ModsPostDragAndDrop();
} }
if (madeAnyChange) { if (madeAnyChange) {
@@ -191,22 +268,61 @@ void DrawMods(bool enabled) {
} }
} }
void ModMenuWindow::DrawElement() { bool editing = false;
ImGui::BeginDisabled(CVarGetInteger(CVAR_SETTING("DisableChanges"), 0));
const ImVec4 yellow = ImVec4(1, 1, 0, 1); void ModMenuWindow::DrawElement() {
SohGui::mSohMenu->MenuDrawItem(enableModsWidget, 200, THEME_COLOR);
ImGui::SameLine();
SohGui::mSohMenu->MenuDrawItem(tabHotkeyWidget, 200, THEME_COLOR);
ImGui::TextColored( ImGui::TextColored(
yellow, "Mods are currently not reloaded at runtime.\nClose and re-open Ship for the changes to take effect."); UIWidgets::ColorValues.at(UIWidgets::Colors::Yellow),
"Mods are currently not reloaded at runtime. Close and re-open Ship for the changes to take effect.\n"
"Drag ordering for the enabled list is available.\nMod priority is top to bottom. They override mods listed "
"below them.");
if (UIWidgets::Button("Update", UIWidgets::ButtonOptions().Size(ImVec2(250.0f, 0.0f)).Color(THEME_COLOR))) { // if (UIWidgets::Button(
UpdateModFiles(); // "Update", UIWidgets::ButtonOptions({ { .disabled = editing, .disabledTooltip = "Currently editing..." }
// })
// .Size(UIWidgets::Sizes::Inline)
// .Color(THEME_COLOR))) {
// UpdateModFiles();
// }
// ImGui::SameLine();
if (UIWidgets::Button("Edit",
UIWidgets::ButtonOptions({ { .disabled = editing, .disabledTooltip = "Already editing..." } })
.Size(UIWidgets::Sizes::Inline)
.Color(THEME_COLOR))) {
editing = true;
} }
UIWidgets::Tooltip("Re-check the mods folder for new files"); if (editing) {
ImGui::SameLine();
if (UIWidgets::Button("Cancel", UIWidgets::ButtonOptions().Size(UIWidgets::Sizes::Inline))) {
editing = false;
UpdateModFiles(false, true);
}
ImGui::SameLine();
if (UIWidgets::Button("Apply & Close",
UIWidgets::ButtonOptions().Size(UIWidgets::Sizes::Inline).Color(THEME_COLOR))) {
SohGui::RegisterPopup("Apply & Close",
"Application currently requires a restart. Save the mod info and close SoH?", "Close",
"Cancel", [&]() {
// TODO: runtime changes
SetEnabledModsCVarValue();
// TODO: runtime changes
/*
gfx_texture_cache_clear();
SOH::SkeletonPatcher::ClearSkeletons();
*/
Ship::Context::GetInstance()->GetConsoleVariables()->Save();
Ship::Context::GetInstance()->GetWindow()->Close();
});
}
}
ImGui::BeginDisabled(!editing);
if (ImGui::BeginTable("tableMods", 2, ImGuiTableFlags_BordersH | ImGuiTableFlags_BordersV)) { if (ImGui::BeginTable("tableMods", 2, ImGuiTableFlags_BordersH | ImGuiTableFlags_BordersV)) {
ImGui::TableSetupColumn("Disabled Mods", ImGuiTableColumnFlags_WidthStretch, 200.0f);
ImGui::TableSetupColumn("Enabled Mods", ImGuiTableColumnFlags_WidthStretch, 200.0f); ImGui::TableSetupColumn("Enabled Mods", ImGuiTableColumnFlags_WidthStretch, 200.0f);
// ImGui::TableSetupColumn("Disabled Mods", ImGuiTableColumnFlags_WidthStretch, 200.0f);
ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true); ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true);
ImGui::TableHeadersRow(); ImGui::TableHeadersRow();
ImGui::PopItemFlag(); ImGui::PopItemFlag();
@@ -214,26 +330,52 @@ void ModMenuWindow::DrawElement() {
ImGui::TableNextColumn(); ImGui::TableNextColumn();
if (ImGui::BeginChild("Disabled Mods", ImVec2(0, -8))) {
DrawMods(false);
ImGui::EndChild();
}
ImGui::TableNextColumn();
if (ImGui::BeginChild("Enabled Mods", ImVec2(0, -8))) { if (ImGui::BeginChild("Enabled Mods", ImVec2(0, -8))) {
DrawMods(true); DrawMods(true);
ImGui::EndChild(); ImGui::EndChild();
} }
/*ImGui::TableNextColumn();
if (ImGui::BeginChild("Disabled Mods", ImVec2(0, -8))) {
DrawMods(false);
ImGui::EndChild();
}*/
ImGui::EndTable(); ImGui::EndTable();
} }
ImGui::EndDisabled(); ImGui::EndDisabled();
} }
void ModMenuWindow::InitElement() { void ModMenuWindow::InitElement() {
UpdateModFiles(true); UpdateModFiles(true);
} }
void RegisterModMenuWidgets() {
enableModsWidget = { .name = "Enable Mods", .type = WidgetType::WIDGET_CVAR_CHECKBOX };
enableModsWidget.CVar(CVAR_SETTING("AltAssets"))
.RaceDisable(false)
.Options(UIWidgets::CheckboxOptions({ { .disabledTooltip = "Temporarily disabled while editing mods list." } })
.Color(THEME_COLOR)
.Tooltip("Toggle mods. For graphics mods, this means toggling between default and mod graphics.")
.DefaultValue(true))
.PreFunc([&](WidgetInfo& info) {
auto options = std::static_pointer_cast<UIWidgets::CheckboxOptions>(info.options);
options->disabled = editing;
});
SohGui::mSohMenu->AddSearchWidget({ enableModsWidget, "Settings", "Mod Menu", "Top", "alternat assets" });
tabHotkeyWidget = { .name = "Mods Tab Hotkey", .type = WidgetType::WIDGET_CVAR_CHECKBOX };
tabHotkeyWidget.CVar(CVAR_SETTING("Mods.AlternateAssetsHotkey"))
.RaceDisable(false)
.Options(UIWidgets::CheckboxOptions()
.Color(THEME_COLOR)
.Tooltip("Allows pressing the Tab key to toggle mods")
.DefaultValue(true));
SohGui::mSohMenu->AddSearchWidget(
{ enableModsWidget, "Settings", "Mod Menu", "Top", "alternat assets tab hotkey" });
}
static RegisterMenuInitFunc menuInitFunc(RegisterModMenuWidgets);

View File

@@ -227,9 +227,10 @@ uint8_t StonesRequiredBySettings() {
} }
if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_LACS_STONES)) { if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_LACS_STONES)) {
stones = std::max<uint8_t>({ stones, ctx->GetOption(RSK_LACS_STONE_COUNT).Get() }); stones = std::max<uint8_t>({ stones, ctx->GetOption(RSK_LACS_STONE_COUNT).Get() });
} else if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_LACS_STONES)) { } else if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_LACS_REWARDS)) {
stones = std::max<uint8_t>({ stones, (uint8_t)(ctx->GetOption(RSK_LACS_REWARD_COUNT).Get() - 6) }); stones = std::max<uint8_t>({ stones, (uint8_t)(ctx->GetOption(RSK_LACS_REWARD_COUNT).Get() - 6) });
} else if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_LACS_DUNGEONS)) { } else if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_LACS_DUNGEONS) &&
ctx->GetOption(RSK_SHUFFLE_DUNGEON_REWARDS).Is(RO_DUNGEON_REWARDS_END_OF_DUNGEON)) {
stones = std::max<uint8_t>({ stones, (uint8_t)(ctx->GetOption(RSK_LACS_DUNGEON_COUNT).Get() - 6) }); stones = std::max<uint8_t>({ stones, (uint8_t)(ctx->GetOption(RSK_LACS_DUNGEON_COUNT).Get() - 6) });
} }
return stones; return stones;
@@ -247,12 +248,12 @@ uint8_t MedallionsRequiredBySettings() {
medallions = ctx->GetOption(RSK_RAINBOW_BRIDGE_DUNGEON_COUNT).Get() - 3; medallions = ctx->GetOption(RSK_RAINBOW_BRIDGE_DUNGEON_COUNT).Get() - 3;
} }
if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_LACS_MEDALLIONS)) { if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_LACS_MEDALLIONS)) {
medallions = std::max({ medallions, ctx->GetOption(RSK_LACS_MEDALLION_COUNT).Get() }); medallions = std::max(medallions, ctx->GetOption(RSK_LACS_MEDALLION_COUNT).Get());
} else if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_LACS_REWARDS)) { } else if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_LACS_REWARDS)) {
medallions = std::max({ medallions, (uint8_t)(ctx->GetOption(RSK_LACS_REWARD_COUNT).Get() - 3) }); medallions = std::max(medallions, (uint8_t)(ctx->GetOption(RSK_LACS_REWARD_COUNT).Get() - 3));
} else if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_LACS_DUNGEONS) && } else if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_LACS_DUNGEONS) &&
ctx->GetOption(RSK_SHUFFLE_DUNGEON_REWARDS).Is(RO_DUNGEON_REWARDS_END_OF_DUNGEON)) { ctx->GetOption(RSK_SHUFFLE_DUNGEON_REWARDS).Is(RO_DUNGEON_REWARDS_END_OF_DUNGEON)) {
medallions = std::max({ medallions, (uint8_t)(ctx->GetOption(RSK_LACS_DUNGEON_COUNT).Get() - 3) }); medallions = std::max(medallions, (uint8_t)(ctx->GetOption(RSK_LACS_DUNGEON_COUNT).Get() - 3));
} }
return medallions; return medallions;
} }
@@ -264,7 +265,7 @@ uint8_t TokensRequiredBySettings() {
tokens = ctx->GetOption(RSK_RAINBOW_BRIDGE_TOKEN_COUNT).Get(); tokens = ctx->GetOption(RSK_RAINBOW_BRIDGE_TOKEN_COUNT).Get();
} }
if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_LACS_TOKENS)) { if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_LACS_TOKENS)) {
tokens = std::max<uint8_t>({ tokens, ctx->GetOption(RSK_LACS_TOKEN_COUNT).Get() }); tokens = std::max<uint8_t>(tokens, ctx->GetOption(RSK_LACS_TOKEN_COUNT).Get());
} }
return tokens; return tokens;
} }

View File

@@ -255,11 +255,14 @@ void RandomizerOnFlagSetHandler(int16_t flagType, int16_t flag) {
return; return;
if (flagType == FLAG_GS_TOKEN && if (flagType == FLAG_GS_TOKEN &&
Rando::Context::GetInstance()->GetOption(RSK_SHUFFLE_TOKENS).Is(RO_TOKENSANITY_OFF)) Rando::Context::GetInstance()->GetOption(RSK_SHUFFLE_TOKENS).Is(RO_TOKENSANITY_OFF)) {
Rando::Context::GetInstance()->GetItemLocation(rc)->SetCheckStatus(RCSHOW_COLLECTED);
return; return;
}
auto loc = Rando::Context::GetInstance()->GetItemLocation(rc); auto loc = Rando::Context::GetInstance()->GetItemLocation(rc);
if (rc != RC_HF_OCARINA_OF_TIME_ITEM) { if (rc != RC_HF_OCARINA_OF_TIME_ITEM) {
if (loc == nullptr || loc->HasObtained() || loc->GetPlacedRandomizerGet() == RG_NONE) if (loc == nullptr || loc->HasObtained() || loc->GetPlacedRandomizerGet() == RG_NONE)
Rando::Context::GetInstance()->GetItemLocation(rc)->SetCheckStatus(RCSHOW_COLLECTED);
return; return;
} }
SPDLOG_INFO("Queuing RC: {}", static_cast<uint32_t>(rc)); SPDLOG_INFO("Queuing RC: {}", static_cast<uint32_t>(rc));

View File

@@ -2116,9 +2116,8 @@ void RegisterItemTrackerWidgets() {
hookshotIdentWidget.CVar(CVAR_SETTING("FreeLook.Enabled")) hookshotIdentWidget.CVar(CVAR_SETTING("FreeLook.Enabled"))
.Options(CheckboxOptions() .Options(CheckboxOptions()
.Color(THEME_COLOR) .Color(THEME_COLOR)
.Tooltip("Shows an 'H' or an 'L' to more easiely distinguish between Hookshot and Longshot.")); .Tooltip("Shows an 'H' or an 'L' to more easily distinguish between Hookshot and Longshot."));
SohGui::mSohMenu->AddSearchWidget( SohGui::mSohMenu->AddSearchWidget({ hookshotIdentWidget, "Randomizer", "Item Tracker", "General Settings" });
{ hookshotIdentWidget, "Settings", "Controls", "Camera Controls", "longshot icon" });
} }
static RegisterMenuInitFunc menuInitFunc(RegisterItemTrackerWidgets); static RegisterMenuInitFunc menuInitFunc(RegisterItemTrackerWidgets);

View File

@@ -300,7 +300,7 @@ void OTRGlobals::Initialize() {
// tell LUS to reserve 3 SoH specific threads (Game, Audio, Save) // tell LUS to reserve 3 SoH specific threads (Game, Audio, Save)
context->InitResourceManager(OTRFiles, {}, 3); context->InitResourceManager(OTRFiles, {}, 3);
prevAltAssets = CVarGetInteger(CVAR_SETTING("AltAssets"), 0); prevAltAssets = CVarGetInteger(CVAR_SETTING("AltAssets"), 1);
context->GetResourceManager()->SetAltAssetsEnabled(prevAltAssets); context->GetResourceManager()->SetAltAssetsEnabled(prevAltAssets);
auto controlDeck = std::make_shared<LUS::ControlDeck>(std::vector<CONTROLLERBUTTONS_T>({ auto controlDeck = std::make_shared<LUS::ControlDeck>(std::vector<CONTROLLERBUTTONS_T>({
@@ -1483,7 +1483,7 @@ extern "C" void Graph_StartFrame() {
#endif #endif
case KbScancode::LUS_KB_TAB: { case KbScancode::LUS_KB_TAB: {
if (CVarGetInteger(CVAR_SETTING("Mods.AlternateAssetsHotkey"), 1)) { if (CVarGetInteger(CVAR_SETTING("Mods.AlternateAssetsHotkey"), 1)) {
CVarSetInteger(CVAR_SETTING("AltAssets"), !CVarGetInteger(CVAR_SETTING("AltAssets"), 0)); CVarSetInteger(CVAR_SETTING("AltAssets"), !CVarGetInteger(CVAR_SETTING("AltAssets"), 1));
} }
break; break;
} }
@@ -1571,7 +1571,7 @@ extern "C" void Graph_ProcessGfxCommands(Gfx* commands) {
} }
} }
bool curAltAssets = CVarGetInteger(CVAR_SETTING("AltAssets"), 0); bool curAltAssets = CVarGetInteger(CVAR_SETTING("AltAssets"), 1);
if (prevAltAssets != curAltAssets) { if (prevAltAssets != curAltAssets) {
prevAltAssets = curAltAssets; prevAltAssets = curAltAssets;
Ship::Context::GetInstance()->GetResourceManager()->SetAltAssetsEnabled(curAltAssets); Ship::Context::GetInstance()->GetResourceManager()->SetAltAssetsEnabled(curAltAssets);

View File

@@ -537,12 +537,6 @@ void SohMenu::AddMenuEnhancements() {
path.column = SECTION_COLUMN_1; path.column = SECTION_COLUMN_1;
AddWidget(path, "Mods", WIDGET_SEPARATOR_TEXT); AddWidget(path, "Mods", WIDGET_SEPARATOR_TEXT);
AddWidget(path, "Use Alternate Assets", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_SETTING("AltAssets"))
.RaceDisable(false)
.Options(CheckboxOptions().Tooltip(
"Toggle between standard assets and alternate assets. Usually mods will indicate if "
"this setting has to be used or not."));
AddWidget(path, "Disable Bomb Billboarding", WIDGET_CVAR_CHECKBOX) AddWidget(path, "Disable Bomb Billboarding", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_ENHANCEMENT("DisableBombBillboarding")) .CVar(CVAR_ENHANCEMENT("DisableBombBillboarding"))
.RaceDisable(false) .RaceDisable(false)
@@ -1908,15 +1902,6 @@ void SohMenu::AddMenuEnhancements() {
.CVar(timer.timeEnable) .CVar(timer.timeEnable)
.Callback([](WidgetInfo& info) { TimeDisplayUpdateDisplayOptions(); }); .Callback([](WidgetInfo& info) { TimeDisplayUpdateDisplayOptions(); });
} }
// Mod Menu
path.sidebarName = "Mod Menu";
AddSidebarEntry("Enhancements", path.sidebarName, 1);
AddWidget(path, "Popout Mod Menu Window", WIDGET_WINDOW_BUTTON)
.CVar(CVAR_WINDOW("ModMenu"))
.WindowName("Mod Menu")
.HideInSearch(true)
.Options(WindowButtonOptions().Tooltip("Enables the separate Mod Menu Window."));
} }
} // namespace SohGui } // namespace SohGui

View File

@@ -178,11 +178,6 @@ void SohMenu::AddMenuSettings() {
.RaceDisable(false) .RaceDisable(false)
.Options(CheckboxOptions().Tooltip( .Options(CheckboxOptions().Tooltip(
"Search input box gets autofocus when visible. Does not affect using other widgets.")); "Search input box gets autofocus when visible. Does not affect using other widgets."));
AddWidget(path, "Alt Assets Tab hotkey", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_SETTING("Mods.AlternateAssetsHotkey"))
.RaceDisable(false)
.Options(
CheckboxOptions().Tooltip("Allows pressing the Tab key to toggle alternate assets").DefaultValue(true));
AddWidget(path, "Open App Files Folder", WIDGET_BUTTON) AddWidget(path, "Open App Files Folder", WIDGET_BUTTON)
.RaceDisable(false) .RaceDisable(false)
.Callback([](WidgetInfo& info) { .Callback([](WidgetInfo& info) {
@@ -505,6 +500,15 @@ void SohMenu::AddMenuSettings() {
}); });
}) })
.Options(ButtonOptions().Tooltip("Displays a test notification.")); .Options(ButtonOptions().Tooltip("Displays a test notification."));
// Mod Menu
path.sidebarName = "Mod Menu";
AddSidebarEntry("Settings", path.sidebarName, 1);
AddWidget(path, "Popout Mod Menu Window", WIDGET_WINDOW_BUTTON)
.CVar(CVAR_WINDOW("ModMenu"))
.WindowName("Mod Menu")
.HideInSearch(true)
.Options(WindowButtonOptions().Tooltip("Enables the separate Mod Menu Window."));
} }
} // namespace SohGui } // namespace SohGui

View File

@@ -1503,7 +1503,7 @@ std::vector<Migration> version3Migrations = {
{ MigrationAction::Rename, "gOpenMenuBar", "gSettings.OpenMenuBar" }, { MigrationAction::Rename, "gOpenMenuBar", "gSettings.OpenMenuBar" },
{ MigrationAction::Rename, "gRandomizeSkipChildStealth", "gRandoSettings.SkipChildStealth" }, { MigrationAction::Rename, "gRandomizeSkipChildStealth", "gRandoSettings.SkipChildStealth" },
{ MigrationAction::Rename, "gRandomizeExcludedLocations", "gRandoSettings.ExcludedLocations" }, { MigrationAction::Rename, "gRandomizeExcludedLocations", "gRandoSettings.ExcludedLocations" },
{ MigrationAction::Rename, "gAltAssets", "gEnhancements.AltAssets" }, { MigrationAction::Rename, "gAltAssets", "gSettings.AltAssets" },
{ MigrationAction::Rename, "gMSAAValue", "gSettings.MSAAValue" }, { MigrationAction::Rename, "gMSAAValue", "gSettings.MSAAValue" },
{ MigrationAction::Rename, "gInternalResolution", "gSettings.InternalResolution" }, { MigrationAction::Rename, "gInternalResolution", "gSettings.InternalResolution" },
{ MigrationAction::Rename, "gTextureFilter", "gSettings.TextureFilter" }, { MigrationAction::Rename, "gTextureFilter", "gSettings.TextureFilter" },