diff --git a/libultraship/libultraship/Console.cpp b/libultraship/libultraship/Console.cpp index efc13ca2c..79064838e 100644 --- a/libultraship/libultraship/Console.cpp +++ b/libultraship/libultraship/Console.cpp @@ -1,39 +1,35 @@ #include "Console.h" -#include -#include - #include "Cvar.h" #include "GlobalCtx2.h" #include "ImGuiImpl.h" #include "Lib/ImGui/imgui.h" #include "Utils/StringHelper.h" #include "Lib/ImGui/imgui_internal.h" +#include "Utils.h" namespace Ship { - std::map Bindings; - std::map BindingToggle; + std::string BuildUsage(const CommandEntry& entry) { + std::string usage; + for (const auto& arg : entry.arguments) + usage += StringHelper::Sprintf(arg.optional ? "[%s] " : "<%s> ", arg.info.c_str()); + return usage; + } - static bool HelpCommand(const std::vector&) { - SohImGui::console->SendInfoMessage("SoH Commands:"); - for (const auto& cmd : SohImGui::console->Commands) { - SohImGui::console->SendInfoMessage(" - " + cmd.first); + bool Console::HelpCommand(std::shared_ptr Console, const std::vector& args) { + Console->SendInfoMessage("SoH Commands:"); + for (const auto& cmd : Console->Commands) { + Console->SendInfoMessage(" - " + cmd.first); } return CMD_SUCCESS; } - static bool ClearCommand(const std::vector&) { - SohImGui::console->Log[SohImGui::console->selected_channel].clear(); + bool Console::ClearCommand(std::shared_ptr Console, const std::vector& args) { + Console->ClearLogs(Console->GetCurrentChannel()); return CMD_SUCCESS; } - std::string toLowerCase(std::string in) { - std::string cpy(in); - std::transform(cpy.begin(), cpy.end(), cpy.begin(), ::tolower); - return cpy; - } - - static bool BindCommand(const std::vector& args) { + bool Console::BindCommand(std::shared_ptr Console, const std::vector& args) { if (args.size() > 2) { const ImGuiIO* io = &ImGui::GetIO();; for (size_t k = 0; k < std::size(io->KeysData); k++) { @@ -44,8 +40,8 @@ namespace Ship { const char* const delim = " "; std::ostringstream imploded; std::copy(args.begin() + 2, args.end(), std::ostream_iterator(imploded, delim)); - Bindings[k] = imploded.str(); - SohImGui::console->SendInfoMessage("Binding '%s' to %s", args[1].c_str(), Bindings[k].c_str()); + Console->Bindings[k] = imploded.str(); + Console->SendInfoMessage("Binding '%s' to %s", args[1].c_str(), Console->Bindings[k].c_str()); break; } } @@ -53,15 +49,15 @@ namespace Ship { return CMD_SUCCESS; } - static bool BindToggleCommand(const std::vector& args) { + bool Console::BindToggleCommand(std::shared_ptr Console, const std::vector& args) { if (args.size() > 2) { const ImGuiIO* io = &ImGui::GetIO();; for (size_t k = 0; k < std::size(io->KeysData); k++) { std::string key(ImGui::GetKeyName(k)); if (toLowerCase(args[1]) == toLowerCase(key)) { - BindingToggle[k] = args[2]; - SohImGui::console->SendInfoMessage("Binding toggle '%s' to %s", args[1].c_str(), BindingToggle[k].c_str()); + Console->BindingToggle[k] = args[2]; + Console->SendInfoMessage("Binding toggle '%s' to %s", args[1].c_str(), Console->BindingToggle[k].c_str()); break; } } @@ -69,22 +65,15 @@ namespace Ship { return CMD_SUCCESS; } - std::string BuildUsage(const CommandEntry& entry) { - std::string usage; - for (const auto& arg : entry.arguments) - usage += StringHelper::Sprintf(arg.optional ? "[%s] " : "<%s> ", arg.info.c_str()); - return usage; - } - void Console::Init() { - this->InputBuffer = new char[MAX_BUFFER_SIZE]; - strcpy(this->InputBuffer, ""); - this->FilterBuffer = new char[MAX_BUFFER_SIZE]; - strcpy(this->FilterBuffer, ""); - this->Commands["help"] = { HelpCommand, "Shows all the commands" }; - this->Commands["clear"] = { ClearCommand, "Clear the console history" }; - this->Commands["bind"] = { BindCommand, "Binds key to commands" }; - this->Commands["bind-toggle"] = { BindToggleCommand, "Bind key as a bool toggle" }; + this->inputBuffer = new char[MAX_BUFFER_SIZE]; + strcpy(this->inputBuffer, ""); + this->filterBuffer = new char[MAX_BUFFER_SIZE]; + strcpy(this->filterBuffer, ""); + AddCommand("help", { HelpCommand, "Shows all the commands" }); + AddCommand("clear", { ClearCommand, "Clear the console history" }); + AddCommand("bind", { BindCommand, "Binds key to commands" }); + AddCommand("bind-toggle", { BindToggleCommand, "Bind key as a bool toggle" }); } void Console::Update() { @@ -114,7 +103,7 @@ namespace Ship { // SohImGui::ShowCursor(ImGui::IsWindowHovered(ImGuiHoveredFlags_RootAndChildWindows | ImGuiHoveredFlags_RectOnly), SohImGui::Dialogues::dConsole); // Renders autocomplete window - if (this->OpenAutocomplete) { + if (this->openAutocomplete) { ImGui::SetNextWindowSize(ImVec2(350, std::min(static_cast(this->Autocomplete.size()), 3) * 20.f), ImGuiCond_Once); ImGui::SetNextWindowPos(ImVec2(pos.x + 8, pos.y + size.y - 1)); ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(3, 3)); @@ -129,16 +118,16 @@ namespace Ship { ImGui::TableNextRow(); ImGui::TableSetColumnIndex(0); if (ImGui::Selectable(preview.c_str())) { - memset(this->InputBuffer, 0, MAX_BUFFER_SIZE); - memcpy(this->InputBuffer, autocomplete.c_str(), sizeof(char) * autocomplete.size()); - this->OpenAutocomplete = false; + memset(this->inputBuffer, 0, MAX_BUFFER_SIZE); + memcpy(this->inputBuffer, autocomplete.c_str(), sizeof(char) * autocomplete.size()); + this->openAutocomplete = false; input_focus = true; } } ImGui::EndTable(); } if (ImGui::IsKeyPressed(ImGuiKey_Escape)) { - this->OpenAutocomplete = false; + this->openAutocomplete = false; } ImGui::PopStyleColor(); ImGui::EndChild(); @@ -148,7 +137,7 @@ namespace Ship { if (ImGui::BeginPopupContextWindow("Context Menu")) { if (ImGui::MenuItem("Copy Text")) { - ImGui::SetClipboardText(this->Log[this->selected_channel][this->selectedId].text.c_str()); + ImGui::SetClipboardText(this->Log[this->currentChannel][this->selectedId].text.c_str()); this->selectedId = -1; } ImGui::EndPopup(); @@ -158,44 +147,44 @@ namespace Ship { } // Renders top bar filters - if (ImGui::Button("Clear")) this->Log[this->selected_channel].clear(); + if (ImGui::Button("Clear")) this->Log[this->currentChannel].clear(); if (CVar_GetS32("gSinkEnabled", 0)) { ImGui::SameLine(); ImGui::SetNextItemWidth(150); - if (ImGui::BeginCombo("##channel", this->selected_channel.c_str())) { - for (const auto& channel : log_channels) { - const bool is_selected = (channel == std::string(this->selected_channel)); + if (ImGui::BeginCombo("##channel", this->currentChannel.c_str())) { + for (const auto& channel : LogChannels) { + const bool is_selected = (channel == std::string(this->currentChannel)); if (ImGui::Selectable(channel.c_str(), is_selected)) - this->selected_channel = channel; + this->currentChannel = channel; if (is_selected) ImGui::SetItemDefaultFocus(); } ImGui::EndCombo(); } } else { - this->selected_channel = "Console"; + this->currentChannel = "Console"; } ImGui::SameLine(); ImGui::SetNextItemWidth(150); - if (this->selected_channel != "Console") { - if (ImGui::BeginCombo("##level", spdlog::level::to_string_view(this->level_filter).data())) { - for (const auto& priority_filter : priority_filters) { - const bool is_selected = priority_filter == this->level_filter; + if (this->currentChannel != "Console") { + if (ImGui::BeginCombo("##level", spdlog::level::to_string_view(this->levelFilter).data())) { + for (const auto& priority_filter : PriorityFilters) { + const bool is_selected = priority_filter == this->levelFilter; if (ImGui::Selectable(spdlog::level::to_string_view(priority_filter).data(), is_selected)) { - this->level_filter = priority_filter; + this->levelFilter = priority_filter; if (is_selected) ImGui::SetItemDefaultFocus(); } } ImGui::EndCombo(); } } else { - this->level_filter = spdlog::level::trace; + this->levelFilter = spdlog::level::trace; } ImGui::SameLine(); ImGui::PushItemWidth(-1); - if (ImGui::InputTextWithHint("##input", "Filter", this->FilterBuffer, MAX_BUFFER_SIZE))this->filter = std::string(this->FilterBuffer); + if (ImGui::InputTextWithHint("##input", "Filter", this->filterBuffer, MAX_BUFFER_SIZE))this->filter = std::string(this->filterBuffer); ImGui::PopItemWidth(); // Renders console history @@ -209,16 +198,16 @@ namespace Ship { if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_UpArrow))) if (this->selectedId > 0)--this->selectedId; - const std::vector channel = this->Log[this->selected_channel]; + const std::vector channel = this->Log[this->currentChannel]; for (int i = 0; i < static_cast(channel.size()); i++) { ConsoleLine line = channel[i]; if (!this->filter.empty() && line.text.find(this->filter) == std::string::npos) continue; - if (this->level_filter > line.priority) continue; + if (this->levelFilter > line.priority) continue; std::string id = line.text + "##" + std::to_string(i); ImGui::TableNextRow(); ImGui::TableSetColumnIndex(0); const bool is_selected = (this->selectedId == i) || std::find(this->selectedEntries.begin(), this->selectedEntries.end(), i) != this->selectedEntries.end(); - ImGui::PushStyleColor(ImGuiCol_Text, this->priority_colors[line.priority]); + ImGui::PushStyleColor(ImGuiCol_Text, this->PriorityColours[line.priority]); if (ImGui::Selectable(id.c_str(), is_selected)) { if (ImGui::IsKeyDown(ImGui::GetKeyIndex(ImGuiKey_LeftCtrl)) && !is_selected) this->selectedEntries.push_back(i); @@ -236,25 +225,25 @@ namespace Ship { ImGui::SetScrollHereY(1.0f); ImGui::EndChild(); - if (this->selected_channel == "Console") { + if (this->currentChannel == "Console") { // Renders input textfield constexpr ImGuiInputTextFlags flags = ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_CallbackEdit | ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_CallbackHistory; ImGui::PushItemWidth(-53); - if (ImGui::InputTextWithHint("##CMDInput", ">", this->InputBuffer, MAX_BUFFER_SIZE, flags, &Console::CallbackStub, this)) { + if (ImGui::InputTextWithHint("##CMDInput", ">", this->inputBuffer, MAX_BUFFER_SIZE, flags, &Console::CallbackStub, this)) { input_focus = true; - if (this->InputBuffer[0] != '\0' && this->InputBuffer[0] != ' ') - this->Dispatch(std::string(this->InputBuffer)); - memset(this->InputBuffer, 0, MAX_BUFFER_SIZE); + if (this->inputBuffer[0] != '\0' && this->inputBuffer[0] != ' ') + this->Dispatch(std::string(this->inputBuffer)); + memset(this->inputBuffer, 0, MAX_BUFFER_SIZE); } - if (this->CMDHint != NULLSTR) { + if (this->cmdHint != NULLSTR) { if (ImGui::IsItemFocused()) { ImGui::SetNextWindowPos(ImVec2(pos.x, pos.y + size.y)); ImGui::SameLine(); ImGui::BeginTooltip(); ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); - ImGui::TextUnformatted(this->CMDHint.c_str()); + ImGui::TextUnformatted(this->cmdHint.c_str()); ImGui::PopTextWrapPos(); ImGui::EndTooltip(); } @@ -262,9 +251,9 @@ namespace Ship { ImGui::SameLine(); ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetContentRegionAvail().x - 50); - if (ImGui::Button("Submit") && !input_focus && this->InputBuffer[0] != '\0' && this->InputBuffer[0] != ' ') { - this->Dispatch(std::string(this->InputBuffer)); - memset(this->InputBuffer, 0, MAX_BUFFER_SIZE); + if (ImGui::Button("Submit") && !input_focus && this->inputBuffer[0] != '\0' && this->inputBuffer[0] != ' ') { + this->Dispatch(std::string(this->inputBuffer)); + memset(this->inputBuffer, 0, MAX_BUFFER_SIZE); } ImGui::SetItemDefaultFocus(); @@ -275,14 +264,16 @@ namespace Ship { } void Console::Dispatch(const std::string& line) { - this->CMDHint = NULLSTR; + this->cmdHint = NULLSTR; this->History.push_back(line); SendInfoMessage("> " + line); const std::vector cmd_args = StringHelper::Split(line, " "); if (this->Commands.contains(cmd_args[0])) { const CommandEntry entry = this->Commands[cmd_args[0]]; - if (!entry.handler(cmd_args) && !entry.arguments.empty()) + if (!entry.handler(shared_from_this(), cmd_args) && !entry.arguments.empty()) { SendErrorMessage("[SOH] Usage: " + cmd_args[0] + " " + BuildUsage(entry)); + } + return; } SendErrorMessage("[SOH] Command not found"); @@ -291,7 +282,7 @@ namespace Ship { int Console::CallbackStub(ImGuiInputTextCallbackData* data) { const auto instance = static_cast(data->UserData); const bool empty_history = instance->History.empty(); - const int history_index = instance->HistoryIndex; + const int history_index = instance->historyIndex; std::string history; switch (data->EventKey) { @@ -299,39 +290,39 @@ namespace Ship { instance->Autocomplete.clear(); for (auto& [cmd, entry] : instance->Commands) if (cmd.find(std::string(data->Buf)) != std::string::npos) instance->Autocomplete.push_back(cmd); - instance->OpenAutocomplete = !instance->Autocomplete.empty(); - instance->CMDHint = NULLSTR; + instance->openAutocomplete = !instance->Autocomplete.empty(); + instance->cmdHint = NULLSTR; break; case ImGuiKey_UpArrow: if (empty_history) break; - if (history_index < static_cast(instance->History.size()) - 1) instance->HistoryIndex += 1; + if (history_index < static_cast(instance->History.size()) - 1) instance->historyIndex += 1; data->DeleteChars(0, data->BufTextLen); - data->InsertChars(0, instance->History[instance->HistoryIndex].c_str()); - instance->CMDHint = NULLSTR; + data->InsertChars(0, instance->History[instance->historyIndex].c_str()); + instance->cmdHint = NULLSTR; break; case ImGuiKey_DownArrow: if (empty_history) break; - if (history_index > -1) instance->HistoryIndex -= 1; + if (history_index > -1) instance->historyIndex -= 1; data->DeleteChars(0, data->BufTextLen); if (history_index >= 0) data->InsertChars(0, instance->History[history_index].c_str()); - instance->CMDHint = NULLSTR; + instance->cmdHint = NULLSTR; break; case ImGuiKey_Escape: - instance->HistoryIndex = -1; + instance->historyIndex = -1; data->DeleteChars(0, data->BufTextLen); - instance->OpenAutocomplete = false; - instance->CMDHint = NULLSTR; + instance->openAutocomplete = false; + instance->cmdHint = NULLSTR; break; default: - instance->OpenAutocomplete = false; + instance->openAutocomplete = false; for (auto& [cmd, entry] : instance->Commands) { const std::vector cmd_args = StringHelper::Split(std::string(data->Buf), " "); if (data->BufTextLen > 2 && !cmd_args.empty() && cmd.find(cmd_args[0]) != std::string::npos) { - instance->CMDHint = cmd + " " + BuildUsage(entry); + instance->cmdHint = cmd + " " + BuildUsage(entry); break; } - instance->CMDHint = NULLSTR; + instance->cmdHint = NULLSTR; } } return 0; @@ -372,4 +363,30 @@ namespace Ship { void Console::SendErrorMessage(const std::string& str) { Append("Console", spdlog::level::err, str.c_str()); } + + void Console::ClearLogs(std::string channel) { + Log[channel].clear(); + } + + void Console::ClearLogs() { + for (auto [key, var] : Log) { + var.clear(); + } + } + + bool Console::HasCommand(const std::string& command) { + for (const auto& Command : Commands) { + if (Command.first == command) { + return true; + } + } + + return false; + } + + void Console::AddCommand(const std::string& command, CommandEntry entry) { + if (!HasCommand(command)) { + Commands[command] = entry; + } + } } \ No newline at end of file diff --git a/libultraship/libultraship/Console.h b/libultraship/libultraship/Console.h index 00ca518e2..f0b78aac9 100644 --- a/libultraship/libultraship/Console.h +++ b/libultraship/libultraship/Console.h @@ -16,7 +16,8 @@ namespace Ship { #define MAX_BUFFER_SIZE 255 #define NULLSTR "None" - typedef std::function args)> CommandHandler; + class Console; + typedef std::function Console, std::vector args)> CommandHandler; enum class ArgumentType { TEXT, NUMBER, PLAYER_POS, PLAYER_ROT @@ -40,14 +41,35 @@ namespace Ship { std::string channel = "Console"; }; - class Console { + class Console : public std::enable_shared_from_this { + private: + static int CallbackStub(ImGuiInputTextCallbackData* data); + static bool ClearCommand(std::shared_ptr Console, const std::vector& args); + static bool HelpCommand(std::shared_ptr Console, const std::vector& args); + static bool BindCommand(std::shared_ptr Console, const std::vector& args); + static bool BindToggleCommand(std::shared_ptr Console, const std::vector& args); + + bool opened = false; int selectedId = -1; + int historyIndex = -1; std::vector selectedEntries; std::string filter; - spdlog::level::level_enum level_filter = spdlog::level::trace; - std::vector log_channels = { "Console", "Logs" }; - std::vector priority_filters = { spdlog::level::off, spdlog::level::critical, spdlog::level::err, spdlog::level::warn, spdlog::level::info, spdlog::level::debug, spdlog::level::trace }; - std::vector priority_colors = { + std::string currentChannel = "Console"; + bool openAutocomplete = false; + char* inputBuffer = nullptr; + char* filterBuffer = nullptr; + std::string cmdHint = NULLSTR; + spdlog::level::level_enum levelFilter = spdlog::level::trace; + + std::vector History; + std::vector Autocomplete; + std::map Bindings; + std::map BindingToggle; + std::map Commands; + std::map> Log; + const std::vector LogChannels = { "Console", "Logs" }; + const std::vector PriorityFilters = { spdlog::level::off, spdlog::level::critical, spdlog::level::err, spdlog::level::warn, spdlog::level::info, spdlog::level::debug, spdlog::level::trace }; + const std::vector PriorityColours = { ImVec4(0.8f, 0.8f, 0.8f, 1.0f), // TRACE ImVec4(0.9f, 0.9f, 0.9f, 1.0f), // DEBUG ImVec4(1.0f, 1.0f, 1.0f, 1.0f), // INFO @@ -60,26 +82,23 @@ namespace Ship { void Append(const std::string& channel, spdlog::level::level_enum priority, const char* fmt, va_list args); public: - std::map> Log; - std::map Commands; - std::vector Autocomplete; - std::vector History; - std::string CMDHint = NULLSTR; - char* FilterBuffer = nullptr; - char* InputBuffer = nullptr; - bool OpenAutocomplete = false; - int HistoryIndex = -1; - std::string selected_channel = "Console"; - bool opened = false; + void ClearLogs(std::string channel); + void ClearLogs(); void Init(); void Update(); void Draw(); void Dispatch(const std::string& line); - static int CallbackStub(ImGuiInputTextCallbackData* data); void SendInfoMessage(const char* fmt, ...); void SendErrorMessage(const char* fmt, ...); void SendInfoMessage(const std::string& str); void SendErrorMessage(const std::string& str); void Append(const std::string& channel, spdlog::level::level_enum priority, const char* fmt, ...); + bool HasCommand(const std::string& command); + void AddCommand(const std::string& command, CommandEntry entry); + + std::string GetCurrentChannel() { return currentChannel; } + bool IsOpened() { return opened; } + void Close() { opened = false; } + void Open() { opened = true; } }; } \ No newline at end of file diff --git a/libultraship/libultraship/ControlDeck.cpp b/libultraship/libultraship/ControlDeck.cpp index 7437afeee..59f25b44f 100644 --- a/libultraship/libultraship/ControlDeck.cpp +++ b/libultraship/libultraship/ControlDeck.cpp @@ -9,7 +9,6 @@ #include "Cvar.h" namespace Ship { - uint8_t* controllerBits; void ControlDeck::Init(uint8_t* bits) { ScanPhysicalDevices(); @@ -187,4 +186,9 @@ namespace Ship { std::shared_ptr ControlDeck::GetPhysicalDeviceFromVirtualSlot(int slot) { return GetPhysicalDevice(GetVirtualDevice(slot)); } + + uint8_t* ControlDeck::GetControllerBits() { + return controllerBits; + } + } \ No newline at end of file diff --git a/libultraship/libultraship/ControlDeck.h b/libultraship/libultraship/ControlDeck.h index 15cba08e9..025bfcde4 100644 --- a/libultraship/libultraship/ControlDeck.h +++ b/libultraship/libultraship/ControlDeck.h @@ -18,8 +18,10 @@ namespace Ship { size_t GetNumPhysicalDevices(); int GetVirtualDevice(int slot); size_t GetNumVirtualDevices(); + uint8_t* GetControllerBits(); private: - std::vector virtualDevices; + std::vector virtualDevices = {}; std::vector> physicalDevices = {}; + uint8_t* controllerBits = nullptr; }; } diff --git a/libultraship/libultraship/GameOverlay.cpp b/libultraship/libultraship/GameOverlay.cpp index 8fe028667..051669577 100644 --- a/libultraship/libultraship/GameOverlay.cpp +++ b/libultraship/libultraship/GameOverlay.cpp @@ -9,6 +9,40 @@ #include "Utils/StringHelper.h" namespace Ship { + bool OverlayCommand(std::shared_ptr Console, const std::vector& args) { + if (args.size() < 3) { + return CMD_FAILED; + } + + if (CVar_Get(args[2].c_str()) != nullptr) { + const char* key = args[2].c_str(); + GameOverlay* overlay = SohImGui::overlay; + if (args[1] == "add") { + if (!overlay->RegisteredOverlays.contains(key)) { + overlay->RegisteredOverlays[key] = new Overlay({ OverlayType::TEXT, ImStrdup(key), -1.0f }); + SohImGui::console->SendInfoMessage("Added overlay: %s", key); + } + else { + SohImGui::console->SendErrorMessage("Overlay already exists: %s", key); + } + } + else if (args[1] == "remove") { + if (overlay->RegisteredOverlays.contains(key)) { + overlay->RegisteredOverlays.erase(key); + SohImGui::console->SendInfoMessage("Removed overlay: %s", key); + } + else { + SohImGui::console->SendErrorMessage("Overlay not found: %s", key); + } + } + } + else { + SohImGui::console->SendErrorMessage("CVar {} does not exist", args[2].c_str()); + } + + return CMD_SUCCESS; + } + void GameOverlay::LoadFont(const std::string& name, const std::string& path, float fontSize) { ImGuiIO& io = ImGui::GetIO(); std::shared_ptr base = GlobalCtx2::GetInstance()->GetResourceManager()->GetArchive(); @@ -122,7 +156,8 @@ namespace Ship { this->CurrentFont = DefaultFont; } } - SohImGui::console->Commands["overlay"] = { OverlayCommand, "Draw an overlay using a cvar value" }; + + SohImGui::console->AddCommand("overlay", { OverlayCommand, "Draw an overlay using a cvar value" }); } void GameOverlay::DrawSettings() { @@ -195,40 +230,4 @@ namespace Ship { ImGui::End(); } - - - bool OverlayCommand(const std::vector& args) { - if (args.size() < 3) { - return CMD_FAILED; - } - - if (CVar_Get(args[2].c_str()) != nullptr) { - const char* key = args[2].c_str(); - GameOverlay* overlay = SohImGui::overlay; - if (args[1] == "add") { - if (!overlay->RegisteredOverlays.contains(key)) { - overlay->RegisteredOverlays[key] = new Overlay({ OverlayType::TEXT, ImStrdup(key), -1.0f }); - SPDLOG_INFO("Added overlay: {} ", key); - SohImGui::console->SendInfoMessage("Added overlay: %s", key); - } - else { - SPDLOG_ERROR("Overlay already exists: {}", key); - } - } - else if (args[1] == "remove") { - if (overlay->RegisteredOverlays.contains(key)) { - overlay->RegisteredOverlays.erase(key); - SPDLOG_INFO("Removed overlay: {} ", key); - } - else { - SPDLOG_ERROR("Overlay not found: {}", key); - } - } - } - else { - SPDLOG_ERROR("CVar {} does not exist", args[2].c_str()); - } - - return CMD_SUCCESS; - } } diff --git a/libultraship/libultraship/GameOverlay.h b/libultraship/libultraship/GameOverlay.h index 061d259ba..57bc41864 100644 --- a/libultraship/libultraship/GameOverlay.h +++ b/libultraship/libultraship/GameOverlay.h @@ -37,6 +37,4 @@ namespace Ship { void CleanupNotifications(); void LoadFont(const std::string& name, const std::string& path, float fontSize); }; - - bool OverlayCommand(const std::vector& args); } diff --git a/libultraship/libultraship/ImGuiImpl.cpp b/libultraship/libultraship/ImGuiImpl.cpp index b95073fd1..3b3b534bd 100644 --- a/libultraship/libultraship/ImGuiImpl.cpp +++ b/libultraship/libultraship/ImGuiImpl.cpp @@ -91,7 +91,7 @@ namespace SohImGui { WindowImpl impl; ImGuiIO* io; - Console* console = new Console; + std::shared_ptr console = std::make_shared(); GameOverlay* overlay = new GameOverlay; InputEditor* controller = new InputEditor; static ImVector s_GroupPanelLabelStack; @@ -141,7 +141,11 @@ namespace SohImGui { Ship::RegisterHook(UpdateAudio); Ship::RegisterHook([] { gfx_get_current_rendering_api()->set_texture_filter((FilteringMode)CVar_GetS32("gTextureFilter", FILTER_THREE_POINT)); - SohImGui::console->opened = CVar_GetS32("gConsoleEnabled", 0); + if (CVar_GetS32("gConsoleEnabled", 0)) { + console->Open(); + } else { + console->Close(); + } SohImGui::controller->Opened = CVar_GetS32("gControllerConfigurationEnabled", 0); UpdateAudio(); }); @@ -857,13 +861,13 @@ namespace SohImGui { if ((ImGui::IsKeyDown(ImGuiKey_LeftSuper) || ImGui::IsKeyDown(ImGuiKey_RightSuper)) && ImGui::IsKeyPressed(ImGuiKey_R, false)) { - console->Commands["reset"].handler(emptyArgs); + console->Dispatch("reset"); } #else if ((ImGui::IsKeyDown(ImGuiKey_LeftCtrl) || ImGui::IsKeyDown(ImGuiKey_RightCtrl)) && ImGui::IsKeyPressed(ImGuiKey_R, false)) { - console->Commands["reset"].handler(emptyArgs); + console->Dispatch("reset"); } #endif @@ -891,7 +895,7 @@ namespace SohImGui { "Ctrl+R" #endif )) { - console->Commands["reset"].handler(emptyArgs); + console->Dispatch("reset"); } ImGui::EndMenu(); } @@ -1638,7 +1642,7 @@ namespace SohImGui { CVar_SetS32("gEnableBetaQuest", betaQuestEnabled); CVar_SetS32("gBetaQuestWorld", betaQuestWorld); - console->Commands["reset"].handler(emptyArgs); + console->Dispatch("reset"); needs_save = true; } @@ -1695,7 +1699,11 @@ namespace SohImGui { bool currentValue = CVar_GetS32("gConsoleEnabled", 0); CVar_SetS32("gConsoleEnabled", !currentValue); needs_save = true; - console->opened = CVar_GetS32("gConsoleEnabled", 0); + if(CVar_GetS32("gConsoleEnabled", 0)){ + console->Open(); + } else { + console->Close(); + } } Tooltip("Enables the console window, allowing you to input commands, type help for some examples"); InsertPadding(); @@ -2261,7 +2269,7 @@ namespace SohImGui { } void BindCmd(const std::string& cmd, CommandEntry entry) { - console->Commands[cmd] = std::move(entry); + console->AddCommand(cmd, entry); } void AddWindow(const std::string& category, const std::string& name, WindowDrawFunc drawFunc, bool isEnabled, bool isHidden) { diff --git a/libultraship/libultraship/ImGuiImpl.h b/libultraship/libultraship/ImGuiImpl.h index fd0aced6a..8e20d415c 100644 --- a/libultraship/libultraship/ImGuiImpl.h +++ b/libultraship/libultraship/ImGuiImpl.h @@ -69,7 +69,7 @@ namespace SohImGui { WindowDrawFunc drawFunc; } CustomWindow; - extern Ship::Console* console; + extern std::shared_ptr console; extern Ship::InputEditor* controller; extern Ship::GameOverlay* overlay; extern bool needs_save; diff --git a/libultraship/libultraship/Lib/spdlog/include/spdlog/sinks/sohconsole_sink.h b/libultraship/libultraship/Lib/spdlog/include/spdlog/sinks/sohconsole_sink.h index 65e98610a..8a629aa1a 100644 --- a/libultraship/libultraship/Lib/spdlog/include/spdlog/sinks/sohconsole_sink.h +++ b/libultraship/libultraship/Lib/spdlog/include/spdlog/sinks/sohconsole_sink.h @@ -41,7 +41,7 @@ protected: } formatted.push_back('\0'); const char* msg_output = formatted.data(); - if (CVar_GetS32("gSinkEnabled", 0) && SohImGui::console->opened) { + if (CVar_GetS32("gSinkEnabled", 0) && SohImGui::console->IsOpened()) { SohImGui::console->Append("Logs", msg.level, "%s", msg_output); } } diff --git a/libultraship/libultraship/Model.cpp b/libultraship/libultraship/Model.cpp index 9e37de177..c59f38e8b 100644 --- a/libultraship/libultraship/Model.cpp +++ b/libultraship/libultraship/Model.cpp @@ -2,7 +2,7 @@ namespace Ship { - Vertex::Vertex() + ModelVertex::ModelVertex() { pos = Vec3f(0, 0, 0); normal = Vec3f(0, 0, 0); @@ -10,7 +10,7 @@ namespace Ship uv = Vec2f(0, 0); } - Vertex::Vertex(BinaryReader* reader) + ModelVertex::ModelVertex(BinaryReader* reader) { pos = reader->ReadVec3f(); normal = reader->ReadVec3f(); @@ -36,7 +36,7 @@ namespace Ship uvCoords = reader->ReadUInt32(); boneWeights = reader->ReadUInt32(); - Vertex* vtxData = new Vertex[numVerts]; + ModelVertex* vtxData = new ModelVertex[numVerts]; uint32_t* indicesData = new uint32_t[numPolys]; if (vertices != 0) diff --git a/libultraship/libultraship/Model.h b/libultraship/libultraship/Model.h index f66ca7b84..241a2932a 100644 --- a/libultraship/libultraship/Model.h +++ b/libultraship/libultraship/Model.h @@ -43,15 +43,15 @@ namespace Ship void ParseFileBinary(BinaryReader* reader, Resource* res) override; }; - struct Vertex + struct ModelVertex { Vec3f pos; Vec3f normal; Color3b color; Vec2f uv; - Vertex(); - Vertex(BinaryReader* reader); + ModelVertex(); + ModelVertex(BinaryReader* reader); }; class Model : public Resource @@ -62,7 +62,7 @@ namespace Ship uint32_t numVerts; uint32_t numPolys; - Vertex* vertices; + ModelVertex* vertices; Vec2f* boneWeights; uint32_t* indices; }; diff --git a/libultraship/libultraship/Utils.cpp b/libultraship/libultraship/Utils.cpp index 185c21c24..6d0e50f5c 100644 --- a/libultraship/libultraship/Utils.cpp +++ b/libultraship/libultraship/Utils.cpp @@ -1,5 +1,6 @@ #include "Utils.h" #include +#include #ifdef _MSC_VER #define strdup _strdup @@ -58,4 +59,10 @@ namespace Ship { return args; } + + std::string toLowerCase(std::string in) { + std::string cpy(in); + std::transform(cpy.begin(), cpy.end(), cpy.begin(), ::tolower); + return cpy; + } } diff --git a/libultraship/libultraship/Utils.h b/libultraship/libultraship/Utils.h index 1dc3d3491..256db35e7 100644 --- a/libultraship/libultraship/Utils.h +++ b/libultraship/libultraship/Utils.h @@ -10,4 +10,5 @@ namespace Ship { } std::vector SplitText(const std::string& text, char separator, bool keep_quotes); + std::string toLowerCase(std::string in); } \ No newline at end of file diff --git a/soh/include/functions.h b/soh/include/functions.h index 0bea29da2..18a58994a 100644 --- a/soh/include/functions.h +++ b/soh/include/functions.h @@ -1055,6 +1055,7 @@ s32 Inventory_HasEmptyBottle(void); s32 Inventory_HasSpecificBottle(u8 bottleItem); void Inventory_UpdateBottleItem(GlobalContext* globalCtx, u8 item, u8 cButton); s32 Inventory_ConsumeFairy(GlobalContext* globalCtx); +bool Inventory_HatchPocketCucco(GlobalContext* globalCtx); void Interface_SetDoAction(GlobalContext* globalCtx, u16 action); void Interface_SetNaviCall(GlobalContext* globalCtx, u16 naviCallState); void Interface_LoadActionLabelB(GlobalContext* globalCtx, u16 action); diff --git a/soh/soh/Enhancements/custom-message/CustomMessageTypes.h b/soh/soh/Enhancements/custom-message/CustomMessageTypes.h index d2f30f123..1859e83a5 100644 --- a/soh/soh/Enhancements/custom-message/CustomMessageTypes.h +++ b/soh/soh/Enhancements/custom-message/CustomMessageTypes.h @@ -30,4 +30,7 @@ typedef struct { #define GIMESSAGE_UNTRANSLATED(giid, iid, message) \ { giid, iid, message, message, message } +#define GIMESSAGE_NO_GERMAN(giid, iid, english, french) \ + { giid, iid, english, english, french } + #endif diff --git a/soh/soh/Enhancements/debugconsole.cpp b/soh/soh/Enhancements/debugconsole.cpp index 203e5521a..8e72392ca 100644 --- a/soh/soh/Enhancements/debugconsole.cpp +++ b/soh/soh/Enhancements/debugconsole.cpp @@ -5,6 +5,7 @@ #include "debugconsole.h" #include "../libultraship/ImGuiImpl.h" #include "savestates.h" +#include "Console.h" #include #include @@ -32,7 +33,7 @@ extern GlobalContext* gGlobalCtx; #define CMD_REGISTER SohImGui::BindCmd -static bool ActorSpawnHandler(const std::vector& args) { +static bool ActorSpawnHandler(std::shared_ptr Console, const std::vector& args) { if ((args.size() != 9) && (args.size() != 3) && (args.size() != 6)) { SohImGui::console->SendErrorMessage("Not enough arguments passed to actorspawn"); return CMD_FAILED; @@ -82,13 +83,13 @@ static bool ActorSpawnHandler(const std::vector& args) { } -static bool KillPlayerHandler([[maybe_unused]] const std::vector&) { +static bool KillPlayerHandler(std::shared_ptr Console, const std::vector&) { gSaveContext.health = 0; SohImGui::console->SendInfoMessage("[SOH] You've met with a terrible fate, haven't you?"); return CMD_SUCCESS; } -static bool SetPlayerHealthHandler(const std::vector& args) { +static bool SetPlayerHealthHandler(std::shared_ptr Console, const std::vector& args) { if (args.size() != 2) { SohImGui::console->SendErrorMessage("[SOH] Unexpected arguments passed"); return CMD_FAILED; @@ -115,7 +116,7 @@ static bool SetPlayerHealthHandler(const std::vector& args) { } -static bool LoadSceneHandler(const std::vector&) { +static bool LoadSceneHandler(std::shared_ptr Console, const std::vector&) { gSaveContext.respawnFlag = 0; gSaveContext.seqId = 0xFF; gSaveContext.gameMode = 0; @@ -123,7 +124,7 @@ static bool LoadSceneHandler(const std::vector&) { return CMD_SUCCESS; } -static bool RuppeHandler(const std::vector& args) { +static bool RuppeHandler(std::shared_ptr Console, const std::vector& args) { if (args.size() < 2) return CMD_FAILED; @@ -147,7 +148,7 @@ static bool RuppeHandler(const std::vector& args) { return CMD_SUCCESS; } -static bool SetPosHandler(const std::vector args) { +static bool SetPosHandler(std::shared_ptr Console, const std::vector args) { if (gGlobalCtx == nullptr) { SohImGui::console->SendErrorMessage("GlobalCtx == nullptr"); return CMD_FAILED; @@ -174,7 +175,7 @@ static bool SetPosHandler(const std::vector args) { return CMD_SUCCESS; } -static bool ResetHandler(std::vector args) { +static bool ResetHandler(std::shared_ptr Console, std::vector args) { if (gGlobalCtx == nullptr) { SohImGui::console->SendErrorMessage("GlobalCtx == nullptr"); return CMD_FAILED; @@ -195,7 +196,7 @@ const static std::map ammoItems{ { "magic_beans", ITEM_BEAN }, }; -static bool AmmoHandler(const std::vector& args) { +static bool AmmoHandler(std::shared_ptr Console, const std::vector& args) { if (args.size() != 3) { SohImGui::console->SendErrorMessage("[SOH] Unexpected arguments passed"); return CMD_FAILED; @@ -238,7 +239,7 @@ const static std::map bottleItems{ { "big_poe", ITEM_BIG_POE }, { "blue_fire", ITEM_BLUE_FIRE }, { "rutos_letter", ITEM_LETTER_RUTO }, }; -static bool BottleHandler(const std::vector& args) { +static bool BottleHandler(std::shared_ptr Console, const std::vector& args) { if (args.size() != 3) { SohImGui::console->SendErrorMessage("[SOH] Unexpected arguments passed"); return CMD_FAILED; @@ -270,7 +271,7 @@ static bool BottleHandler(const std::vector& args) { return CMD_SUCCESS; } -static bool BHandler(const std::vector& args) { +static bool BHandler(std::shared_ptr Console, const std::vector& args) { if (args.size() != 2) { SohImGui::console->SendErrorMessage("[SOH] Unexpected arguments passed"); return CMD_FAILED; @@ -280,7 +281,7 @@ static bool BHandler(const std::vector& args) { return CMD_SUCCESS; } -static bool ItemHandler(const std::vector& args) { +static bool ItemHandler(std::shared_ptr Console, const std::vector& args) { if (args.size() != 3) { SohImGui::console->SendErrorMessage("[SOH] Unexpected arguments passed"); return CMD_FAILED; @@ -291,7 +292,7 @@ static bool ItemHandler(const std::vector& args) { return CMD_SUCCESS; } -static bool EntranceHandler(const std::vector& args) { +static bool EntranceHandler(std::shared_ptr Console, const std::vector& args) { if (args.size() != 2) { SohImGui::console->SendErrorMessage("[SOH] Unexpected arguments passed"); return CMD_FAILED; @@ -312,7 +313,7 @@ static bool EntranceHandler(const std::vector& args) { gSaveContext.nextTransition = 11; } -static bool SaveStateHandler(const std::vector& args) { +static bool SaveStateHandler(std::shared_ptr Console, const std::vector& args) { unsigned int slot = OTRGlobals::Instance->gSaveStateMgr->GetCurrentSlot(); const SaveStateReturn rtn = OTRGlobals::Instance->gSaveStateMgr->AddRequest({ slot, RequestType::SAVE }); @@ -323,11 +324,10 @@ static bool SaveStateHandler(const std::vector& args) { case SaveStateReturn::FAIL_WRONG_GAMESTATE: SohImGui::console->SendErrorMessage("[SOH] Can not save a state outside of \"GamePlay\""); return CMD_FAILED; - } } -static bool LoadStateHandler(const std::vector& args) { +static bool LoadStateHandler(std::shared_ptr Console, const std::vector& args) { unsigned int slot = OTRGlobals::Instance->gSaveStateMgr->GetCurrentSlot(); const SaveStateReturn rtn = OTRGlobals::Instance->gSaveStateMgr->AddRequest({ slot, RequestType::LOAD }); @@ -348,7 +348,7 @@ static bool LoadStateHandler(const std::vector& args) { } -static bool StateSlotSelectHandler(const std::vector& args) { +static bool StateSlotSelectHandler(std::shared_ptr Console, const std::vector& args) { if (args.size() != 2) { SohImGui::console->SendErrorMessage("[SOH] Unexpected arguments passed"); return CMD_FAILED; @@ -404,7 +404,7 @@ static int CheckVarType(const std::string& input) return result; } -static bool SetCVarHandler(const std::vector& args) { +static bool SetCVarHandler(std::shared_ptr Console, const std::vector& args) { if (args.size() < 3) return CMD_FAILED; @@ -434,7 +434,7 @@ static bool SetCVarHandler(const std::vector& args) { } -static bool GetCVarHandler(const std::vector& args) { +static bool GetCVarHandler(std::shared_ptr Console, const std::vector& args) { if (args.size() < 2) return CMD_FAILED; diff --git a/soh/soh/Enhancements/debugger/debugSaveEditor.cpp b/soh/soh/Enhancements/debugger/debugSaveEditor.cpp index 90e4ca0ff..c5cad88dd 100644 --- a/soh/soh/Enhancements/debugger/debugSaveEditor.cpp +++ b/soh/soh/Enhancements/debugger/debugSaveEditor.cpp @@ -533,15 +533,18 @@ void DrawBGSItemFlag(uint8_t itemID) { ImGui::SameLine(); int tradeIndex = itemID - ITEM_POCKET_EGG; bool hasItem = (gSaveContext.adultTradeItems & (1 << tradeIndex)) != 0; - ImGui::Checkbox(("##adultTradeFlag" + std::to_string(itemID)).c_str(), &hasItem); - if (hasItem) { - gSaveContext.adultTradeItems |= (1 << tradeIndex); - if (INV_CONTENT(ITEM_TRADE_ADULT) == ITEM_NONE) { - INV_CONTENT(ITEM_TRADE_ADULT) = ITEM_POCKET_EGG + tradeIndex; + bool shouldHaveItem = hasItem; + ImGui::Checkbox(("##adultTradeFlag" + std::to_string(itemID)).c_str(), &shouldHaveItem); + if (hasItem != shouldHaveItem) { + if (shouldHaveItem) { + gSaveContext.adultTradeItems |= (1 << tradeIndex); + if (INV_CONTENT(ITEM_TRADE_ADULT) == ITEM_NONE) { + INV_CONTENT(ITEM_TRADE_ADULT) = ITEM_POCKET_EGG + tradeIndex; + } + } else { + gSaveContext.adultTradeItems &= ~(1 << tradeIndex); + Inventory_ReplaceItem(gGlobalCtx, itemID, Randomizer_GetNextAdultTradeItem()); } - } else { - gSaveContext.adultTradeItems &= ~(1 << tradeIndex); - Inventory_ReplaceItem(gGlobalCtx, INV_CONTENT(ITEM_TRADE_ADULT), Randomizer_GetNextAdultTradeItem()); } } @@ -586,6 +589,9 @@ void DrawInventoryTab() { if (ImGui::BeginPopup(itemPopupPicker)) { if (ImGui::Button("##itemNonePicker", ImVec2(32.0f, 32.0f))) { gSaveContext.inventory.items[selectedIndex] = ITEM_NONE; + if (selectedIndex == SLOT_TRADE_ADULT) { + gSaveContext.adultTradeItems = 0; + } ImGui::CloseCurrentPopup(); } SetLastItemHoverText("None"); @@ -616,17 +622,13 @@ void DrawInventoryTab() { if (ImGui::ImageButton(SohImGui::GetTextureByName(slotEntry.name), ImVec2(32.0f, 32.0f), ImVec2(0, 0), ImVec2(1, 1), 0)) { gSaveContext.inventory.items[selectedIndex] = slotEntry.id; - // Set adult trade item flag if you're playing adult trade shuffle in rando + // Set adult trade item flag if you're playing adult trade shuffle in rando if (gSaveContext.n64ddFlag && - OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_ADULT_TRADE) && - selectedIndex == SLOT_TRADE_ADULT) { - if (slotEntry.id == ITEM_NONE) { - gSaveContext.adultTradeItems = 0; - } else if (slotEntry.id >= ITEM_POCKET_EGG && slotEntry.id <= ITEM_CLAIM_CHECK) { - uint32_t tradeID = slotEntry.id - ITEM_POCKET_EGG; - gSaveContext.adultTradeItems |= tradeID; - } - } + OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_ADULT_TRADE); + selectedIndex == SLOT_TRADE_ADULT && + slotEntry.id >= ITEM_POCKET_EGG && slotEntry.id <= ITEM_CLAIM_CHECK) { + gSaveContext.adultTradeItems |= ADULT_TRADE_FLAG(slotEntry.id); + } ImGui::CloseCurrentPopup(); } SetLastItemHoverText(SohUtils::GetItemName(slotEntry.id)); diff --git a/soh/soh/Enhancements/randomizer/3drando/setting_descriptions.cpp b/soh/soh/Enhancements/randomizer/3drando/setting_descriptions.cpp index 0e11fecbd..328b862bd 100644 --- a/soh/soh/Enhancements/randomizer/3drando/setting_descriptions.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/setting_descriptions.cpp @@ -593,6 +593,13 @@ string_view kingZoraSpeedRandom = "King Zora will move out of the way in 1 string_view completeMaskDesc = "Once the happy mask shop is opened, all masks\n" // "will be available to be borrowed."; // /*------------------------------ // +| ENABLE GLITCH CUTSCENES | // +------------------------------*/ // +string_view glitchCutscenesDesc = "The cutscenes of the Poes in Forest Temple and\n" // + "Darunia in Fire Temple will not be skipped.\n" // + "These cutscenes are only useful for glitched\n" // + "gameplay and can be safely skipped otherwise."; // +/*------------------------------ // | QUICK TEXT | // ------------------------------*/ // string_view quickTextDesc0 = "Quick text will be unchanged, requiring\n" // diff --git a/soh/soh/Enhancements/randomizer/3drando/setting_descriptions.hpp b/soh/soh/Enhancements/randomizer/3drando/setting_descriptions.hpp index 917316ba1..cea8f419d 100644 --- a/soh/soh/Enhancements/randomizer/3drando/setting_descriptions.hpp +++ b/soh/soh/Enhancements/randomizer/3drando/setting_descriptions.hpp @@ -198,6 +198,8 @@ extern string_view kingZoraSpeedRandom; extern string_view completeMaskDesc; +extern string_view glitchCutscenesDesc; + extern string_view quickTextDesc0; extern string_view quickTextDesc1; extern string_view quickTextDesc2; diff --git a/soh/soh/Enhancements/randomizer/3drando/settings.cpp b/soh/soh/Enhancements/randomizer/3drando/settings.cpp index 4a136b9cb..71aa70b32 100644 --- a/soh/soh/Enhancements/randomizer/3drando/settings.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/settings.cpp @@ -191,7 +191,7 @@ namespace Settings { //Shuffle Dungeon Items Option RandomizeDungeon = Option::Bool("Randomize Settings", {"No","Yes"}, {dungeonRandomize}, OptionCategory::Toggle); - Option MapsAndCompasses = Option::U8 ("Start with Maps/Compasses", {"Start With", "Vanilla", "Own Dungeon", "Any Dungeon", "Overworld", "Anywhere"}, + Option MapsAndCompasses = Option::U8 ("Maps/Compasses", {"Start With", "Vanilla", "Own Dungeon", "Any Dungeon", "Overworld", "Anywhere"}, {mapCompassStartWith, mapCompassVanilla, mapCompassOwnDungeon, mapCompassAnyDungeon, mapCompassOverworld, mapCompassAnywhere}, OptionCategory::Setting, MAPSANDCOMPASSES_OWN_DUNGEON); Option Keysanity = Option::U8 ("Small Keys", {"Start With", "Vanilla", "Own Dungeon", "Any Dungeon", "Overworld", "Anywhere"}, {smallKeyStartWith, smallKeyVanilla, smallKeyOwnDungeon, smallKeyAnyDungeon, smallKeyOverworld, smallKeyAnywhere}, OptionCategory::Setting, KEYSANITY_OWN_DUNGEON); @@ -265,6 +265,7 @@ namespace Settings { Option NumRequiredCuccos = Option::U8 ("Cuccos to return", {NumOpts(0, 7)}, {numRequiredCuccosDesc}); Option KingZoraSpeed = Option::U8 ("King Zora Speed", {"Fast", "Vanilla", "Random"}, {kingZoraSpeedFast, kingZoraSpeedVanilla, kingZoraSpeedRandom}); Option CompleteMaskQuest = Option::Bool("Complete Mask Quest", {"Off", "On"}, {completeMaskDesc}); + Option EnableGlitchCutscenes = Option::Bool("Enable Glitch-Useful Cutscenes", {"Off", "On"}, {glitchCutscenesDesc}); Option QuickText = Option::U8 ("Quick Text", {"0: Vanilla", "1: Skippable", "2: Instant", "3: Turbo"}, {quickTextDesc0, quickTextDesc1, quickTextDesc2, quickTextDesc3}, OptionCategory::Setting, QUICKTEXT_INSTANT); Option SkipSongReplays = Option::U8 ("Skip Song Replays", {"Don't Skip", "Skip (No SFX)", "Skip (Keep SFX)"}, {skipSongReplaysDesc}); Option KeepFWWarpPoint = Option::Bool("Keep FW Warp Point", {"Off", "On"}, {keepFWWarpPointDesc}); @@ -281,6 +282,7 @@ namespace Settings { &NumRequiredCuccos, &KingZoraSpeed, &CompleteMaskQuest, + &EnableGlitchCutscenes, &QuickText, &SkipSongReplays, &KeepFWWarpPoint, @@ -1302,6 +1304,7 @@ namespace Settings { ctx.numRequiredCuccos = NumRequiredCuccos.Value(); ctx.kingZoraSpeed = KingZoraSpeed.Value(); ctx.completeMaskQuest = CompleteMaskQuest ? 1 : 0; + ctx.enableGlitchCutscenes = EnableGlitchCutscenes ? 1 : 0; ctx.quickText = QuickText.Value(); ctx.skipSongReplays = SkipSongReplays.Value(); ctx.keepFWWarpPoint = KeepFWWarpPoint ? 1 : 0; @@ -2572,6 +2575,8 @@ namespace Settings { CompleteMaskQuest.SetSelectedIndex(cvarSettings[RSK_COMPLETE_MASK_QUEST]); + EnableGlitchCutscenes.SetSelectedIndex(cvarSettings[RSK_ENABLE_GLITCH_CUTSCENES]); + NightGSExpectSuns.SetSelectedIndex(cvarSettings[RSK_SKULLS_SUNS_SONG]); // RANDOTODO implement chest shuffle with keysanity diff --git a/soh/soh/Enhancements/randomizer/3drando/settings.hpp b/soh/soh/Enhancements/randomizer/3drando/settings.hpp index 1c1476e9e..06ec9da1c 100644 --- a/soh/soh/Enhancements/randomizer/3drando/settings.hpp +++ b/soh/soh/Enhancements/randomizer/3drando/settings.hpp @@ -440,6 +440,7 @@ typedef struct { uint8_t numRequiredCuccos; uint8_t kingZoraSpeed; uint8_t completeMaskQuest; + uint8_t enableGlitchCutscenes; uint8_t quickText; uint8_t skipSongReplays; uint8_t keepFWWarpPoint; @@ -942,6 +943,7 @@ void UpdateSettings(std::unordered_map cvarSettin extern Option NumRequiredCuccos; extern Option KingZoraSpeed; extern Option CompleteMaskQuest; + extern Option EnableGlitchCutscenes; extern Option QuickText; extern Option SkipSongReplays; extern Option KeepFWWarpPoint; diff --git a/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp b/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp index 91271b74b..22d1f196d 100644 --- a/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp @@ -348,7 +348,8 @@ static void WriteSettings(const bool printAll = false) { setting->GetName() == "Skip Epona Race" || setting->GetName() == "Skip Tower Escape" || setting->GetName() == "Skip Child Stealth" || - setting->GetName() == "Complete Mask Quest") { + setting->GetName() == "Complete Mask Quest" || + setting->GetName() == "Enable Glitch-Useful Cutscenes") { std::string settingName = menu->name + ":" + setting->GetName(); jsonData["settings"][settingName] = setting->GetSelectedOptionText(); } diff --git a/soh/soh/Enhancements/randomizer/adult_trade_shuffle.h b/soh/soh/Enhancements/randomizer/adult_trade_shuffle.h index c5199e50a..d30ca2839 100644 --- a/soh/soh/Enhancements/randomizer/adult_trade_shuffle.h +++ b/soh/soh/Enhancements/randomizer/adult_trade_shuffle.h @@ -4,6 +4,7 @@ #include #define ADULT_TRADE_FLAG(itemId) (1 << (itemId - ITEM_POCKET_EGG)) +#define PLAYER_HAS_SHUFFLED_ADULT_TRADE_ITEM(itemID) (gSaveContext.adultTradeItems & ADULT_TRADE_FLAG(itemID)) void Randomizer_ConsumeAdultTradeItem(GlobalContext* globalCtx, u8 itemId); u8 Randomizer_GetNextAdultTradeItem(); diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index 5ffe540ad..770cf1dda 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -1441,13 +1441,14 @@ std::unordered_map SpoilerfileSettingNameToEn { "Open Settings:Token Count", RSK_RAINBOW_BRIDGE_TOKEN_COUNT }, { "Open Settings:Random Ganon's Trials", RSK_RANDOM_TRIALS }, { "Open Settings:Trial Count", RSK_TRIAL_COUNT }, + { "Shuffle Settings:Shuffle Gerudo Card", RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD }, { "Shuffle Settings:Shuffle Cows", RSK_SHUFFLE_COWS }, { "Shuffle Settings:Tokensanity", RSK_SHUFFLE_TOKENS }, { "Shuffle Settings:Shuffle Adult Trade", RSK_SHUFFLE_ADULT_TRADE }, { "Start with Deku Shield", RSK_STARTING_DEKU_SHIELD }, { "Start with Kokiri Sword", RSK_STARTING_KOKIRI_SWORD }, { "Start with Fairy Ocarina", RSK_STARTING_OCARINA }, - { "Shuffle Dungeon Items:Start with Maps/Compasses", RSK_STARTING_MAPS_COMPASSES }, + { "Shuffle Dungeon Items:Maps/Compasses", RSK_STARTING_MAPS_COMPASSES }, { "Shuffle Dungeon Items:Small Keys", RSK_KEYSANITY }, { "Shuffle Dungeon Items:Gerudo Fortress Keys", RSK_GERUDO_KEYS }, { "Shuffle Dungeon Items:Boss Keys", RSK_BOSS_KEYSANITY }, @@ -1464,6 +1465,7 @@ std::unordered_map SpoilerfileSettingNameToEn { "Timesaver Settings:Skip Epona Race", RSK_SKIP_EPONA_RACE }, { "Timesaver Settings:Skip Tower Escape", RSK_SKIP_TOWER_ESCAPE }, { "Timesaver Settings:Complete Mask Quest", RSK_COMPLETE_MASK_QUEST }, + { "Timesaver Settings:Enable Glitch-Useful Cutscenes", RSK_ENABLE_GLITCH_CUTSCENES }, }; s32 Randomizer::GetItemIDFromGetItemID(s32 getItemId) { @@ -1678,12 +1680,14 @@ void Randomizer::ParseRandomizerSettingsFile(const char* spoilerFileName) { numericValueString = it.value(); gSaveContext.randoSettings[index].value = std::stoi(numericValueString); break; + case RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD: case RSK_SHUFFLE_COWS: case RSK_SHUFFLE_ADULT_TRADE: case RSK_RANDOM_TRIALS: case RSK_STARTING_DEKU_SHIELD: case RSK_STARTING_KOKIRI_SWORD: case RSK_COMPLETE_MASK_QUEST: + case RSK_ENABLE_GLITCH_CUTSCENES: if(it.value() == "Off") { gSaveContext.randoSettings[index].value = 0; } else if(it.value() == "On") { @@ -2046,18 +2050,18 @@ GetItemID Randomizer::GetItemFromGet(RandomizerGet randoGet, GetItemID ogItemId) return ogItemId; case RG_KOKIRI_SWORD: - return GI_SWORD_KOKIRI; + return !CHECK_OWNED_EQUIP(EQUIP_SWORD, 0) ? GI_SWORD_KOKIRI : GI_RUPEE_BLUE; case RG_GIANTS_KNIFE: return GI_SWORD_KNIFE; case RG_BIGGORON_SWORD: - return GI_SWORD_BGS; + return !CHECK_OWNED_EQUIP(EQUIP_SWORD, 2) ? GI_SWORD_BGS : GI_RUPEE_BLUE; case RG_DEKU_SHIELD: return GI_SHIELD_DEKU; case RG_HYLIAN_SHIELD: return GI_SHIELD_HYLIAN; case RG_MIRROR_SHIELD: - return GI_SHIELD_MIRROR; + return !CHECK_OWNED_EQUIP(EQUIP_SHIELD, 2) ? GI_SHIELD_MIRROR : GI_RUPEE_BLUE; case RG_GORON_TUNIC: return GI_TUNIC_GORON; @@ -2065,35 +2069,35 @@ GetItemID Randomizer::GetItemFromGet(RandomizerGet randoGet, GetItemID ogItemId) return GI_TUNIC_ZORA; case RG_IRON_BOOTS: - return GI_BOOTS_IRON; + return !CHECK_OWNED_EQUIP(EQUIP_BOOTS, 1) ? GI_BOOTS_IRON : GI_RUPEE_BLUE; case RG_HOVER_BOOTS: - return GI_BOOTS_HOVER; + return !CHECK_OWNED_EQUIP(EQUIP_BOOTS, 2) ? GI_BOOTS_HOVER : GI_RUPEE_BLUE; case RG_BOOMERANG: - return GI_BOOMERANG; + return INV_CONTENT(ITEM_BOOMERANG) == ITEM_NONE ? GI_BOOMERANG : GI_RUPEE_BLUE; case RG_LENS_OF_TRUTH: - return GI_LENS; + return INV_CONTENT(ITEM_LENS) == ITEM_NONE ? GI_LENS : GI_RUPEE_BLUE; case RG_MEGATON_HAMMER: - return GI_HAMMER; + return INV_CONTENT(ITEM_HAMMER) == ITEM_NONE ? GI_HAMMER : GI_RUPEE_BLUE; case RG_STONE_OF_AGONY: return GI_STONE_OF_AGONY; case RG_DINS_FIRE: - return GI_DINS_FIRE; + return INV_CONTENT(ITEM_DINS_FIRE) == ITEM_NONE ? GI_DINS_FIRE : GI_RUPEE_BLUE; case RG_FARORES_WIND: - return GI_FARORES_WIND; + return INV_CONTENT(ITEM_FARORES_WIND) == ITEM_NONE ? GI_FARORES_WIND : GI_RUPEE_BLUE; case RG_NAYRUS_LOVE: - return GI_NAYRUS_LOVE; + return INV_CONTENT(ITEM_NAYRUS_LOVE) == ITEM_NONE ? GI_NAYRUS_LOVE : GI_RUPEE_BLUE; case RG_FIRE_ARROWS: - return GI_ARROW_FIRE; + return INV_CONTENT(ITEM_ARROW_FIRE) == ITEM_NONE ? GI_ARROW_FIRE : GI_RUPEE_BLUE; case RG_ICE_ARROWS: - return GI_ARROW_ICE; + return INV_CONTENT(ITEM_ARROW_ICE) == ITEM_NONE ? GI_ARROW_ICE : GI_RUPEE_BLUE; case RG_LIGHT_ARROWS: - return GI_ARROW_LIGHT; + return INV_CONTENT(ITEM_ARROW_LIGHT) == ITEM_NONE ? GI_ARROW_LIGHT : GI_RUPEE_BLUE; case RG_GERUDO_MEMBERSHIP_CARD: return GI_GERUDO_CARD; @@ -2104,7 +2108,7 @@ GetItemID Randomizer::GetItemFromGet(RandomizerGet randoGet, GetItemID ogItemId) return GI_BEAN; //todo make it 10 of them case RG_DOUBLE_DEFENSE: - return GI_DOUBLE_DEFENSE; + return !gSaveContext.doubleDefense ? GI_DOUBLE_DEFENSE : GI_RUPEE_BLUE; case RG_WEIRD_EGG: return GI_WEIRD_EGG; @@ -3582,6 +3586,7 @@ void GenerateRandomizerImgui() { cvarSettings[RSK_SKIP_EPONA_RACE] = CVar_GetS32("gRandomizeSkipEponaRace", 0); cvarSettings[RSK_SKIP_TOWER_ESCAPE] = CVar_GetS32("gRandomizeSkipTowerEscape", 0); cvarSettings[RSK_COMPLETE_MASK_QUEST] = CVar_GetS32("gRandomizeCompleteMaskQuest", 0); + cvarSettings[RSK_ENABLE_GLITCH_CUTSCENES] = CVar_GetS32("gRandomizeEnableGlitchCutscenes", 0); cvarSettings[RSK_SKULLS_SUNS_SONG] = CVar_GetS32("gRandomizeGsExpectSunsSong", 0); @@ -4176,6 +4181,24 @@ void DrawRandoEditor(bool& open) { SohImGui::EnhancementCombobox("gRandomizeShuffleDungeonReward", randoShuffleDungeonRewards, 4, 0); PaddedSeparator(); + // Maps & Compasses + ImGui::Text(Settings::MapsAndCompasses.GetName().c_str()); + InsertHelpHoverText( + "Start with - You will start with Maps & Compasses from all dungeons.\n" + "\n" + "Vanilla - Maps & Compasses will appear in their vanilla locations.\n" + "\n" + "Own dungeon - Maps & Compasses can only appear in their respective dungeon.\n" + "\n" + "Any dungeon - Maps & Compasses can only appear inside of any dungon.\n" + "\n" + "Overworld - Maps & Compasses can only appear outside of dungeons.\n" + "\n" + "Anywhere - Maps & Compasses can appear anywhere in the world." + ); + SohImGui::EnhancementCombobox("gRandomizeStartingMapsCompasses", randoShuffleMapsAndCompasses, 6, 2); + PaddedSeparator(); + // Keysanity ImGui::Text(Settings::Keysanity.GetName().c_str()); InsertHelpHoverText( @@ -4242,24 +4265,6 @@ void DrawRandoEditor(bool& open) { "Anywhere - Ganon's Boss Key Key can appear anywhere in the world." ); SohImGui::EnhancementCombobox("gRandomizeShuffleGanonBossKey", randoShuffleGanonsBossKey, 6, 1); - PaddedSeparator(); - - // Start with Maps & Compasses - ImGui::Text(Settings::MapsAndCompasses.GetName().c_str()); - InsertHelpHoverText( - "Start with - You will start with Maps & Compasses from all dungeons.\n" - "\n" - "Vanilla - Maps & Compasses will appear in their vanilla locations.\n" - "\n" - "Own dungeon - Maps & Compasses can only appear in their respective dungeon.\n" - "\n" - "Any dungeon - Maps & Compasses can only appear inside of any dungon.\n" - "\n" - "Overworld - Maps & Compasses can only appear outside of dungeons.\n" - "\n" - "Anywhere - Maps & Compasses can appear anywhere in the world." - ); - SohImGui::EnhancementCombobox("gRandomizeStartingMapsCompasses", randoShuffleMapsAndCompasses, 6, 2); ImGui::PopItemWidth(); ImGui::EndTable(); @@ -4347,6 +4352,14 @@ void DrawRandoEditor(bool& open) { InsertHelpHoverText( "Once the happy mask shop is opened, all masks will be available to be borrowed." ); + PaddedSeparator(); + + // Enable Glitch-Useful Cutscenes + SohImGui::EnhancementCheckbox(Settings::EnableGlitchCutscenes.GetName().c_str(), "gRandomizeEnableGlitchCutscenes"); + InsertHelpHoverText( + "The cutscenes of the Poes in Forest Temple and Darunia in Fire Temple will not be skipped. " + "These cutscenes are only useful for glitched gameplay and can be safely skipped otherwise." + ); // COLUMN 2 - HINT SETTINGS ImGui::TableNextColumn(); @@ -4629,64 +4642,72 @@ void Randomizer::CreateCustomMessages() { const std::vector getItemMessages = { GIMESSAGE(GI_ICE_TRAP, ITEM_NONE, "\x08\x06\x30You are a %bFOWL%w!\x0E\x20", "\x08\x06\x15 Du bist ein %bDUMMKOPF%w!\x0E\x20", "\x08\x06\x50%bIDIOT%w\x0E\x20"), - GIMESSAGE_UNTRANSLATED(GI_BOTTLE_WITH_BLUE_FIRE, ITEM_BLUE_FIRE, - "You got a %rBottle with Blue &Fire%w! Use it to melt Red Ice!"), - GIMESSAGE_UNTRANSLATED(GI_BOTTLE_WITH_BIG_POE, ITEM_BIG_POE, - "You got a %rBig Poe in a Bottle%w!&Sell it to the Ghost Shop!"), - GIMESSAGE_UNTRANSLATED( - GI_BOTTLE_WITH_BLUE_POTION, ITEM_POTION_BLUE, - "You got a %rBottle of Blue Potion%w!&Drink it to replenish your&%ghealth%w and %bmagic%w!"), - GIMESSAGE_UNTRANSLATED( - GI_BOTTLE_WITH_FISH, ITEM_FISH, - "You got a %rFish in a Bottle%w!&It looks fresh and delicious!&They say Jabu-Jabu loves them!"), - GIMESSAGE_UNTRANSLATED(GI_BOTTLE_WITH_BUGS, ITEM_BUG, - "You got a %rBug in a Bottle%w!&They love to burrow in&dirt holes!"), - GIMESSAGE_UNTRANSLATED(GI_BOTTLE_WITH_FAIRY, ITEM_FAIRY, "You got a %rFairy in a Bottle%w!&Use it wisely!"), - GIMESSAGE_UNTRANSLATED(GI_BOTTLE_WITH_RED_POTION, ITEM_POTION_RED, - "You got a %rBottle of Red Potion%w!&Drink it to replenish your&%ghealth%w!"), - GIMESSAGE_UNTRANSLATED(GI_BOTTLE_WITH_GREEN_POTION, ITEM_POTION_GREEN, - "You got a %rBottle of Green Potion%w!&Drink it to replenish your&%bmagic%w!"), - GIMESSAGE_UNTRANSLATED(GI_BOTTLE_WITH_POE, ITEM_POE, - "You got a %rPoe in a Bottle%w!&That creepy Ghost Shop might&be interested in this..."), + GIMESSAGE_NO_GERMAN(GI_BOTTLE_WITH_BLUE_FIRE, ITEM_BLUE_FIRE, + "You got a %rBottle with Blue &Fire%w! Use it to melt Red Ice!", + "Vous obtenez une %rBouteille avec&une Flamme Bleue%w! Utilisez-la&pour faire fondre la %rGlace&Rouge%w!"), + GIMESSAGE_NO_GERMAN(GI_BOTTLE_WITH_BIG_POE, ITEM_BIG_POE, + "You got a %rBig Poe in a Bottle%w!&Sell it to the Ghost Shop!", + "Vous obtenez une %rBouteille avec&une Âme%w! Vendez-la au Marchand&d'Âme"), + GIMESSAGE_NO_GERMAN(GI_BOTTLE_WITH_BLUE_POTION, ITEM_POTION_BLUE, + "You got a %rBottle of Blue Potion%w!&Drink it to replenish your&%ghealth%w and %bmagic%w!", + "Vous obtenez une %rBouteille avec&une Potion Bleue%w! Buvez-la pour&restaurer votre %rénergie vitale%w&ainsi que votre %gmagie%w!"), + GIMESSAGE_NO_GERMAN(GI_BOTTLE_WITH_FISH, ITEM_FISH, + "You got a %rFish in a Bottle%w!&It looks fresh and delicious!&They say Jabu-Jabu loves them!", + "Vous obtenez une %rBouteille avec&un Poisson%w! Il a l'air délicieux!&Il paraîtrait que %bJabu-Jabu %wen&serait friand!"), + GIMESSAGE_NO_GERMAN(GI_BOTTLE_WITH_BUGS, ITEM_BUG, + "You got a %rBug in a Bottle%w!&They love to burrow in&dirt holes!", + "Vous obtenez une %rBouteille avec&des Insectes%w! Ils adorent creuser&dans la terre meuble!"), + GIMESSAGE_NO_GERMAN(GI_BOTTLE_WITH_FAIRY, ITEM_FAIRY, + "You got a %rFairy in a Bottle%w!&Use it wisely!", + "Vous obtenez une %rBouteille avec&une Fée%w! Faites-en bon usage!"), + GIMESSAGE_NO_GERMAN(GI_BOTTLE_WITH_RED_POTION, ITEM_POTION_RED, + "You got a %rBottle of Red Potion%w!&Drink it to replenish your&%ghealth%w!", + "Vous obtenez une %rBouteille avec&une Potion Rouge%w! Buvez-la pour&restaurer votre %rénergie vitale%w!"), + GIMESSAGE_NO_GERMAN(GI_BOTTLE_WITH_GREEN_POTION, ITEM_POTION_GREEN, + "You got a %rBottle of Green Potion%w!&Drink it to replenish your&%bmagic%w!", + "Vous obtenez une %rBouteille avec&une Potion Verte%w! Buvez-la pour&restaurer votre %gmagie%w!"), + GIMESSAGE_NO_GERMAN(GI_BOTTLE_WITH_POE, ITEM_POE, + "You got a %rPoe in a Bottle%w!&That creepy Ghost Shop might&be interested in this...", + "Vous obtenez une %rBouteille avec&un Esprit%w! Ça intéresserait&peut-être le vendeur d'Âme "), - GIMESSAGE_UNTRANSLATED(GI_GERUDO_FORTRESS_SMALL_KEY, ITEM_KEY_SMALL, "You found a %yThieves Hideout &%wSmall Key!"), - GIMESSAGE_UNTRANSLATED(GI_FOREST_TEMPLE_SMALL_KEY, ITEM_KEY_SMALL, "You found a %gForest Temple &%wSmall Key!"), - GIMESSAGE_UNTRANSLATED(GI_FIRE_TEMPLE_SMALL_KEY, ITEM_KEY_SMALL, "You found a %rFire Temple &%wSmall Key!"), - GIMESSAGE_UNTRANSLATED(GI_WATER_TEMPLE_SMALL_KEY, ITEM_KEY_SMALL, "You found a %bWater Temple &%wSmall Key!"), - GIMESSAGE_UNTRANSLATED(GI_SPIRIT_TEMPLE_SMALL_KEY, ITEM_KEY_SMALL, "You found a %ySpirit Temple &%wSmall Key!"), - GIMESSAGE_UNTRANSLATED(GI_SHADOW_TEMPLE_SMALL_KEY, ITEM_KEY_SMALL, "You found a %pShadow Temple &%wSmall Key!"), - GIMESSAGE_UNTRANSLATED(GI_BOTTOM_OF_THE_WELL_SMALL_KEY, ITEM_KEY_SMALL, "You found a %pBottom of the &Well %wSmall Key!"), - GIMESSAGE_UNTRANSLATED(GI_GERUDO_TRAINING_GROUNDS_SMALL_KEY, ITEM_KEY_SMALL, "You found a %yGerudo Training Grounds &%wSmall Key!"), - GIMESSAGE_UNTRANSLATED(GI_GANONS_CASTLE_SMALL_KEY, ITEM_KEY_SMALL, "You found a %rGanon's Castle &%wSmall Key!"), + GIMESSAGE_NO_GERMAN(GI_GERUDO_FORTRESS_SMALL_KEY, ITEM_KEY_SMALL, "You found a %yThieves Hideout &%wSmall Key!", "Vous obtenez une %rPetite Clé %w&du %yRepaire des Voleurs%w!"), + GIMESSAGE_NO_GERMAN(GI_FOREST_TEMPLE_SMALL_KEY, ITEM_KEY_SMALL, "You found a %gForest Temple &%wSmall Key!", "Vous obtenez une %rPetite Clé %w&du %gTemple de la Forêt%w!"), + GIMESSAGE_NO_GERMAN(GI_FIRE_TEMPLE_SMALL_KEY, ITEM_KEY_SMALL, "You found a %rFire Temple &%wSmall Key!", "Vous obtenez une %rPetite Clé %w&du %rTemple du Feu%w!"), + GIMESSAGE_NO_GERMAN(GI_WATER_TEMPLE_SMALL_KEY, ITEM_KEY_SMALL, "You found a %bWater Temple &%wSmall Key!", "Vous obtenez une %rPetite Clé %w&du %bTemple de l'Eau%w!"), + GIMESSAGE_NO_GERMAN(GI_SPIRIT_TEMPLE_SMALL_KEY, ITEM_KEY_SMALL, "You found a %ySpirit Temple &%wSmall Key!", "Vous obtenez une %rPetite Clé %w&du %yTemple de l'Esprit%w!"), + GIMESSAGE_NO_GERMAN(GI_SHADOW_TEMPLE_SMALL_KEY, ITEM_KEY_SMALL, "You found a %pShadow Temple &%wSmall Key!", "Vous obtenez une %rPetite Clé %w&du %pTemple de l'Ombre%w!"), + GIMESSAGE_NO_GERMAN(GI_BOTTOM_OF_THE_WELL_SMALL_KEY, ITEM_KEY_SMALL, "You found a %pBottom of the &Well %wSmall Key!", "Vous obtenez une %rPetite Clé %w&du %Puits%w!"), + GIMESSAGE_NO_GERMAN(GI_GERUDO_TRAINING_GROUNDS_SMALL_KEY, ITEM_KEY_SMALL, "You found a %yGerudo Training &Grounds %wSmall Key!", "Vous obtenez une %rPetite Clé %w&du %yGymnase Gerudo%w!"), + GIMESSAGE_NO_GERMAN(GI_GANONS_CASTLE_SMALL_KEY, ITEM_KEY_SMALL, "You found a %rGanon's Castle &%wSmall Key!", "Vous obtenez une %rPetite Clé %w&du %Château de Ganon%w!"), - GIMESSAGE_UNTRANSLATED(GI_FOREST_TEMPLE_BOSS_KEY, ITEM_KEY_BOSS, "You found the %gForest Temple &%wBoss Key!"), - GIMESSAGE_UNTRANSLATED(GI_FIRE_TEMPLE_BOSS_KEY, ITEM_KEY_BOSS, "You found the %rFire Temple &%wBoss Key!"), - GIMESSAGE_UNTRANSLATED(GI_WATER_TEMPLE_BOSS_KEY, ITEM_KEY_BOSS, "You found the %bWater Temple &%wBoss Key!"), - GIMESSAGE_UNTRANSLATED(GI_SPIRIT_TEMPLE_BOSS_KEY, ITEM_KEY_BOSS, "You found the %ySpirit Temple &%wBoss Key!"), - GIMESSAGE_UNTRANSLATED(GI_SHADOW_TEMPLE_BOSS_KEY, ITEM_KEY_BOSS, "You found the %pShadow Temple &%wBoss Key!"), - GIMESSAGE_UNTRANSLATED(GI_GANONS_CASTLE_BOSS_KEY, ITEM_KEY_BOSS, "You found the %rGanon's Castle &%wBoss Key!"), + GIMESSAGE_NO_GERMAN(GI_FOREST_TEMPLE_BOSS_KEY, ITEM_KEY_BOSS, "You found the %gForest Temple &%wBoss Key!", "Vous obtenez la %rClé d'or %wdu&%gTemple de la Forêt%w!"), + GIMESSAGE_NO_GERMAN(GI_FIRE_TEMPLE_BOSS_KEY, ITEM_KEY_BOSS, "You found the %rFire Temple &%wBoss Key!", "Vous obtenez la %rClé d'or %wdu&%rTemple du Feu%w!"), + GIMESSAGE_NO_GERMAN(GI_WATER_TEMPLE_BOSS_KEY, ITEM_KEY_BOSS, "You found the %bWater Temple &%wBoss Key!", "Vous obtenez la %rClé d'or %wdu&%bTemple de l'Eau%w!"), + GIMESSAGE_NO_GERMAN(GI_SPIRIT_TEMPLE_BOSS_KEY, ITEM_KEY_BOSS, "You found the %ySpirit Temple &%wBoss Key!", "Vous obtenez la %rClé d'or %wdu&%yTemple de l'Esprit%w!"), + GIMESSAGE_NO_GERMAN(GI_SHADOW_TEMPLE_BOSS_KEY, ITEM_KEY_BOSS, "You found the %pShadow Temple &%wBoss Key!", "Vous obtenez la %rClé d'or %wdu&%pTemple de l'Ombre%w!"), + GIMESSAGE_NO_GERMAN(GI_GANONS_CASTLE_BOSS_KEY, ITEM_KEY_BOSS, "You found the %rGanon's Castle &%wBoss Key!", "Vous obtenez la %rClé d'or %wdu&%rChâteau de Ganon%w!"), + + GIMESSAGE_NO_GERMAN(GI_DEKU_TREE_MAP, ITEM_DUNGEON_MAP, "You found the %gDeku Tree &%wMap!", "Vous obtenez la %rCarte %wde&l'%gArbre Mojo%w!"), + GIMESSAGE_NO_GERMAN(GI_DODONGOS_CAVERN_MAP, ITEM_DUNGEON_MAP, "You found the %rDodongo's Cavern &%wMap!", "Vous obtenez la %rCarte %wde la&%rCaverne Dodongo%w!"), + GIMESSAGE_NO_GERMAN(GI_JABU_JABUS_BELLY_MAP, ITEM_DUNGEON_MAP, "You found the %bJabu Jabu's Belly &%wMap!", "Vous obtenez la %rCarte %wdu &%bVentre de Jabu-Jabu%w!"), + GIMESSAGE_NO_GERMAN(GI_FOREST_TEMPLE_MAP, ITEM_DUNGEON_MAP, "You found the %gForest Temple &%wMap!", "Vous obtenez la %rCarte %wdu &%gTemple de la Forêt%w!"), + GIMESSAGE_NO_GERMAN(GI_FIRE_TEMPLE_MAP, ITEM_DUNGEON_MAP, "You found the %rFire Temple &%wMap!", "Vous obtenez la %rCarte %wdu &%rTemple du Feu%w!"), + GIMESSAGE_NO_GERMAN(GI_WATER_TEMPLE_MAP, ITEM_DUNGEON_MAP, "You found the %bWater Temple &%wMap!", "Vous obtenez la %rCarte %wdu &%bTemple de l'Eau%w!"), + GIMESSAGE_NO_GERMAN(GI_SPIRIT_TEMPLE_MAP, ITEM_DUNGEON_MAP, "You found the %ySpirit Temple &%wMap!", "Vous obtenez la %rCarte %wdu &%yTemple de l'Esprit%w!"), + GIMESSAGE_NO_GERMAN(GI_SHADOW_TEMPLE_MAP, ITEM_DUNGEON_MAP, "You found the %pShadow Temple &%wMap!", "Vous obtenez la %rCarte %wdu &%pTemple de l'Ombre%w!"), + GIMESSAGE_NO_GERMAN(GI_BOTTOM_OF_THE_WELL_MAP, ITEM_DUNGEON_MAP, "You found the %pBottom of the &Well %wMap!", "Vous obtenez la %rCarte %wdu &%pPuits%w!"), + GIMESSAGE_NO_GERMAN(GI_ICE_CAVERN_MAP, ITEM_DUNGEON_MAP, "You found the %cIce Cavern &%wMap!", "Vous obtenez la %rCarte %wde &la %cCaverne Polaire%w!"), - GIMESSAGE_UNTRANSLATED(GI_DEKU_TREE_MAP, ITEM_DUNGEON_MAP, "You found the %gDeku Tree &%wMap!"), - GIMESSAGE_UNTRANSLATED(GI_DODONGOS_CAVERN_MAP, ITEM_DUNGEON_MAP, "You found the %rDodongo's Cavern &%wMap!"), - GIMESSAGE_UNTRANSLATED(GI_JABU_JABUS_BELLY_MAP, ITEM_DUNGEON_MAP, "You found the %bJabu Jabu's Belly &%wMap!"), - GIMESSAGE_UNTRANSLATED(GI_FOREST_TEMPLE_MAP, ITEM_DUNGEON_MAP, "You found the %gForest Temple &%wMap!"), - GIMESSAGE_UNTRANSLATED(GI_FIRE_TEMPLE_MAP, ITEM_DUNGEON_MAP, "You found the %rFire Temple &%wMap!"), - GIMESSAGE_UNTRANSLATED(GI_WATER_TEMPLE_MAP, ITEM_DUNGEON_MAP, "You found the %bWater Temple &%wMap!"), - GIMESSAGE_UNTRANSLATED(GI_SPIRIT_TEMPLE_MAP, ITEM_DUNGEON_MAP, "You found the %ySpirit Temple &%wMap!"), - GIMESSAGE_UNTRANSLATED(GI_SHADOW_TEMPLE_MAP, ITEM_DUNGEON_MAP, "You found the %pShadow Temple &%wMap!"), - GIMESSAGE_UNTRANSLATED(GI_BOTTOM_OF_THE_WELL_MAP, ITEM_DUNGEON_MAP, "You found the %pBottom of the &Well %wMap!"), - GIMESSAGE_UNTRANSLATED(GI_ICE_CAVERN_MAP, ITEM_DUNGEON_MAP, "You found the %cIce Cavern &%wMap!"), - - GIMESSAGE_UNTRANSLATED(GI_DEKU_TREE_COMPASS, ITEM_COMPASS, "You found the %gDeku Tree &%wCompass!"), - GIMESSAGE_UNTRANSLATED(GI_DODONGOS_CAVERN_COMPASS, ITEM_COMPASS, "You found the %rDodongo's Cavern &%wCompass!"), - GIMESSAGE_UNTRANSLATED(GI_JABU_JABUS_BELLY_COMPASS, ITEM_COMPASS, "You found the %bJabu Jabu's Belly &%wCompass!"), - GIMESSAGE_UNTRANSLATED(GI_FOREST_TEMPLE_COMPASS, ITEM_COMPASS, "You found the %gForest Temple &%wCompass!"), - GIMESSAGE_UNTRANSLATED(GI_FIRE_TEMPLE_COMPASS, ITEM_COMPASS, "You found the %rFire Temple &%wCompass!"), - GIMESSAGE_UNTRANSLATED(GI_WATER_TEMPLE_COMPASS, ITEM_COMPASS, "You found the %bWater Temple &%wCompass!"), - GIMESSAGE_UNTRANSLATED(GI_SPIRIT_TEMPLE_COMPASS, ITEM_COMPASS, "You found the %ySpirit Temple &%wCompass!"), - GIMESSAGE_UNTRANSLATED(GI_SHADOW_TEMPLE_COMPASS, ITEM_COMPASS, "You found the %pShadow Temple &%wCompass!"), - GIMESSAGE_UNTRANSLATED(GI_BOTTOM_OF_THE_WELL_COMPASS, ITEM_COMPASS, "You found the %pBottom of the &Well %wCompass!"), - GIMESSAGE_UNTRANSLATED(GI_ICE_CAVERN_COMPASS, ITEM_COMPASS, "You found the %cIce Cavern &%wCompass!"), + GIMESSAGE_NO_GERMAN(GI_DEKU_TREE_COMPASS, ITEM_COMPASS, "You found the %gDeku Tree &%wCompass!", "Vous obtenez la %rBoussole %wde&l'%gArbre Mojo%w!"), + GIMESSAGE_NO_GERMAN(GI_DODONGOS_CAVERN_COMPASS, ITEM_COMPASS, "You found the %rDodongo's Cavern &%wCompass!", "Vous obtenez la %rBoussole %wde la&%rCaverne Dodongo%w!"), + GIMESSAGE_NO_GERMAN(GI_JABU_JABUS_BELLY_COMPASS, ITEM_COMPASS, "You found the %bJabu Jabu's Belly &%wCompass!", "Vous obtenez la %rBoussole %wdu &%bVentre de Jabu-Jabu%w!"), + GIMESSAGE_NO_GERMAN(GI_FOREST_TEMPLE_COMPASS, ITEM_COMPASS, "You found the %gForest Temple &%wCompass!", "Vous obtenez la %rBoussole %wdu &%gTemple de la Forêt%w!"), + GIMESSAGE_NO_GERMAN(GI_FIRE_TEMPLE_COMPASS, ITEM_COMPASS, "You found the %rFire Temple &%wCompass!", "Vous obtenez la %rBoussole %wdu &%rTemple du Feu%w!"), + GIMESSAGE_NO_GERMAN(GI_WATER_TEMPLE_COMPASS, ITEM_COMPASS, "You found the %bWater Temple &%wCompass!", "Vous obtenez la %rBoussole %wdu &%bTemple de l'Eau%w!"), + GIMESSAGE_NO_GERMAN(GI_SPIRIT_TEMPLE_COMPASS, ITEM_COMPASS, "You found the %ySpirit Temple &%wCompass!", "Vous obtenez la %rBoussole %wdu &%yTemple de l'Esprit%w!"), + GIMESSAGE_NO_GERMAN(GI_SHADOW_TEMPLE_COMPASS, ITEM_COMPASS, "You found the %pShadow Temple &%wCompass!", "Vous obtenez la %rBoussole %wdu &%pTemple de l'Ombre%w!"), + GIMESSAGE_NO_GERMAN(GI_BOTTOM_OF_THE_WELL_COMPASS, ITEM_COMPASS, "You found the %pBottom of the &Well %wCompass!", "Vous obtenez la %rBoussole %wdu &%pPuits%w!"), + GIMESSAGE_NO_GERMAN(GI_ICE_CAVERN_COMPASS, ITEM_COMPASS, "You found the %cIce Cavern &%wCompass!", "Vous obtenez la %rBoussole %wde &la %cCaverne Polaire%w!"), }; CreateGetItemMessages(getItemMessages); CreateScrubMessages(); diff --git a/soh/soh/Enhancements/randomizer/randomizerTypes.h b/soh/soh/Enhancements/randomizer/randomizerTypes.h index 3f0da52b7..b09b9dab2 100644 --- a/soh/soh/Enhancements/randomizer/randomizerTypes.h +++ b/soh/soh/Enhancements/randomizer/randomizerTypes.h @@ -1006,6 +1006,7 @@ typedef enum { RSK_SKIP_EPONA_RACE, RSK_SKIP_TOWER_ESCAPE, RSK_COMPLETE_MASK_QUEST, + RSK_ENABLE_GLITCH_CUTSCENES, RSK_SKULLS_SUNS_SONG, RSK_SHUFFLE_ADULT_TRADE } RandomizerSettingKey; diff --git a/soh/soh/Enhancements/randomizer/randomizer_item_tracker.cpp b/soh/soh/Enhancements/randomizer/randomizer_item_tracker.cpp index 70c16fd80..ed26e9078 100644 --- a/soh/soh/Enhancements/randomizer/randomizer_item_tracker.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer_item_tracker.cpp @@ -239,12 +239,17 @@ std::unordered_map equipTrackerMap = { ITEM_TRACKER_MAP_ENTRY(ITEM_BOOTS_HOVER, 14), }; +bool IsValidSaveFile() { + bool validSave = gSaveContext.fileNum >= 0 && gSaveContext.fileNum <= 2; + return validSave; +} + void DrawEquip(uint32_t itemId) { const ItemTrackerMapEntry& entry = equipTrackerMap[itemId]; bool hasEquip = (entry.bitMask & gSaveContext.inventory.equipment) != 0; int iconSize = CVar_GetS32("gRandoTrackIconSize", 0); - ImGui::Image(SohImGui::GetTextureByName(hasEquip ? entry.name : entry.nameFaded), ImVec2(iconSize, iconSize), - ImVec2(0, 0), ImVec2(1, 1)); + ImGui::Image(SohImGui::GetTextureByName(hasEquip && IsValidSaveFile() ? entry.name : entry.nameFaded), + ImVec2(iconSize, iconSize), ImVec2(0, 0), ImVec2(1, 1)); SetLastItemHoverText(SohUtils::GetItemName(entry.id)); } @@ -264,8 +269,8 @@ void DrawQuest(uint32_t itemId) { bool hasQuestItem = (entry.bitMask & gSaveContext.inventory.questItems) != 0; int iconSize = CVar_GetS32("gRandoTrackIconSize", 0); ImGui::BeginGroup(); - ImGui::Image(SohImGui::GetTextureByName(hasQuestItem ? entry.name : entry.nameFaded), ImVec2(iconSize, iconSize), - ImVec2(0, 0), ImVec2(1, 1)); + ImGui::Image(SohImGui::GetTextureByName(hasQuestItem && IsValidSaveFile() ? entry.name : entry.nameFaded), + ImVec2(iconSize, iconSize), ImVec2(0, 0), ImVec2(1, 1)); ImVec2 p = ImGui::GetCursorScreenPos(); int estimatedTextWidth = 10; @@ -447,18 +452,29 @@ void DrawItem(uint32_t itemId) { } } - const ItemTrackerMapEntry& entry = itemTrackerMap[hasItem ? actualItemId : itemId]; + const ItemTrackerMapEntry& entry = itemTrackerMap[hasItem && IsValidSaveFile() ? actualItemId : itemId]; int iconSize = CVar_GetS32("gRandoTrackIconSize", 0); ImGui::BeginGroup(); - ImGui::Image(SohImGui::GetTextureByName(hasItem ? entry.name : entry.nameFaded), ImVec2(iconSize, iconSize), - ImVec2(0, 0), ImVec2(1, 1)); + ImGui::Image(SohImGui::GetTextureByName(hasItem && IsValidSaveFile() ? entry.name : entry.nameFaded), + ImVec2(iconSize, iconSize), ImVec2(0, 0), ImVec2(1, 1)); ImVec2 p = ImGui::GetCursorScreenPos(); int estimatedTextWidth = 10; int estimatedTextHeight = 10; ImGui::SetCursorScreenPos(ImVec2(p.x - 5 + (iconSize / 2) - estimatedTextWidth, p.y - estimatedTextHeight)); - switch (actualItemId) { + if (IsValidSaveFile()) { + DrawItemAmmo(actualItemId); + } else { + ImGui::Text(" "); + } + ImGui::EndGroup(); + + SetLastItemHoverText(SohUtils::GetItemName(entry.id)); +} + +void DrawItemAmmo(int itemId) { + switch (itemId) { case ITEM_STICK: if (CVar_GetS32("gItemTrackerAmmoDisplay", 0) == 1) { if (AMMO(ITEM_STICK) == CUR_CAPACITY(UPG_STICKS)) { @@ -667,18 +683,15 @@ void DrawItem(uint32_t itemId) { ImGui::Text(" "); break; } - ImGui::EndGroup(); - - SetLastItemHoverText(SohUtils::GetItemName(entry.id)); } void DrawBottle(uint32_t itemId, uint32_t bottleSlot) { uint32_t actualItemId = gSaveContext.inventory.items[SLOT(itemId) + bottleSlot]; bool hasItem = actualItemId != ITEM_NONE; - const ItemTrackerMapEntry& entry = itemTrackerMap[hasItem ? actualItemId : itemId]; + const ItemTrackerMapEntry& entry = itemTrackerMap[hasItem && IsValidSaveFile() ? actualItemId : itemId]; int iconSize = CVar_GetS32("gRandoTrackIconSize", 0); - ImGui::Image(SohImGui::GetTextureByName(hasItem ? entry.name : entry.nameFaded), ImVec2(iconSize, iconSize), - ImVec2(0, 0), ImVec2(1, 1)); + ImGui::Image(SohImGui::GetTextureByName(hasItem && IsValidSaveFile() ? entry.name : entry.nameFaded), + ImVec2(iconSize, iconSize), ImVec2(0, 0), ImVec2(1, 1)); SetLastItemHoverText(SohUtils::GetItemName(entry.id)); }; @@ -688,19 +701,26 @@ void DrawDungeonItem(uint32_t itemId, uint32_t scene) { uint32_t bitMask = 1 << (entry.id - ITEM_KEY_BOSS); // Bitset starts at ITEM_KEY_BOSS == 0. the rest are sequential int iconSize = CVar_GetS32("gRandoTrackIconSize", 0); bool hasItem = (bitMask & gSaveContext.inventory.dungeonItems[scene]) != 0; + bool hasSmallKey = (gSaveContext.inventory.dungeonKeys[scene]) >= 0; ImGui::BeginGroup(); - ImGui::Image(SohImGui::GetTextureByName(hasItem ? entry.name : entry.nameFaded), ImVec2(iconSize, iconSize), - ImVec2(0, 0), ImVec2(1, 1)); + if (itemId == ITEM_KEY_SMALL) { + ImGui::Image(SohImGui::GetTextureByName(hasSmallKey && IsValidSaveFile() ? entry.name : entry.nameFaded), + ImVec2(iconSize, iconSize), ImVec2(0, 0), ImVec2(1, 1)); + } + else { + ImGui::Image(SohImGui::GetTextureByName(hasItem && IsValidSaveFile() ? entry.name : entry.nameFaded), + ImVec2(iconSize, iconSize), ImVec2(0, 0), ImVec2(1, 1)); + } ImVec2 p = ImGui::GetCursorScreenPos(); int estimatedTextWidth = 10; int estimatedTextHeight = 10; ImGui::SetCursorScreenPos(ImVec2(p.x - 5 + (iconSize / 2) - estimatedTextWidth, p.y - estimatedTextHeight)); - if (itemId == ITEM_KEY_SMALL) { - if (gSaveContext.inventory.dungeonKeys[scene] == 0) { + if (itemId == ITEM_KEY_SMALL) { // This check there for small key is necessary to get the text position properly and can't be on the same ITEM_KEY chack from the top + if (gSaveContext.inventory.dungeonKeys[scene] <= 0 || !IsValidSaveFile()) { ImGui::PushStyleColor(ImGuiCol_Text, IM_COL32(155, 155, 155, 255)); - ImGui::Text("%i", gSaveContext.inventory.dungeonKeys[scene]); + ImGui::Text("0"); ImGui::PopStyleColor(); } else { @@ -756,7 +776,7 @@ std::unordered_map> upgradeTracker void DrawUpgrade(int32_t categoryId) { int iconSize = CVar_GetS32("gRandoTrackIconSize", 0); - if (CUR_UPG_VALUE(categoryId) == 0) { + if (CUR_UPG_VALUE(categoryId) == 0 || !IsValidSaveFile()) { const ItemTrackerUpgradeEntry& entry = upgradeTrackerMap[categoryId][0]; ImGui::Image(SohImGui::GetTextureByName(entry.nameFaded), ImVec2(iconSize, iconSize), ImVec2(0, 0), ImVec2(1, 1)); @@ -815,8 +835,8 @@ void DrawSong(int32_t songId) { CVar_GetS32("gItemTrackeSongColor", 0) ? songTrackerMap[songId] : vanillaSongTrackerMap[songId]; uint32_t bitMask = 1 << entry.id; bool hasSong = (bitMask & gSaveContext.inventory.questItems) != 0; - ImGui::Image(SohImGui::GetTextureByName(hasSong ? entry.name : entry.nameFaded), ImVec2(iconSize / 1.5, iconSize), - ImVec2(0, 0), ImVec2(1, 1)); + ImGui::Image(SohImGui::GetTextureByName(hasSong && IsValidSaveFile() ? entry.name : entry.nameFaded), + ImVec2(iconSize / 1.5, iconSize), ImVec2(0, 0), ImVec2(1, 1)); SetLastItemHoverText(SohUtils::GetQuestItemName(entry.id)); } @@ -1273,7 +1293,7 @@ void DrawFloatingDungeons(int Icon_Cells_Size, int Icon_Spacing) { DrawDungeonItem(ITEM_KEY_SMALL, SCENE_HAKADAN); ImGui::SameLine(Icon_Cells_Size * 5); ImGui::SetCursorPosX(ImGui::GetCursorPosX() + Icon_Spacing * 5); - DrawDungeonItem(ITEM_KEY_SMALL, SCENE_GANON); + DrawDungeonItem(ITEM_KEY_SMALL, SCENE_GANONTIKA); ImGui::EndGroup(); // BOSS KEYS FOR FOREST TO GANON ImGui::BeginGroup(); @@ -1340,7 +1360,7 @@ void DrawFloatingDungeons(int Icon_Cells_Size, int Icon_Spacing) { DrawDungeonItem(ITEM_KEY_SMALL, SCENE_MEN); ImGui::SameLine(Icon_Cells_Size * 5); ImGui::SetCursorPosX(ImGui::GetCursorPosX() + Icon_Spacing * 5); - DrawDungeonItem(ITEM_KEY_SMALL, SCENE_GANON); + DrawDungeonItem(ITEM_KEY_SMALL, SCENE_GANONTIKA); ImGui::EndGroup(); ImGui::BeginGroup(); DrawDungeonItem(ITEM_COMPASS, SCENE_JYASINZOU); @@ -1355,7 +1375,7 @@ void DrawFloatingDungeons(int Icon_Cells_Size, int Icon_Spacing) { DrawDungeonItem(ITEM_COMPASS, SCENE_ICE_DOUKUTO); ImGui::SameLine(Icon_Cells_Size * 5); ImGui::SetCursorPosX(ImGui::GetCursorPosX() + Icon_Spacing * 5); - DrawDungeonItem(ITEM_KEY_BOSS, SCENE_GANONTIKA); + DrawDungeonItem(ITEM_KEY_BOSS, SCENE_GANON); ImGui::EndGroup(); } ImGui::BeginGroup(); @@ -1463,12 +1483,12 @@ void DrawItemTracker(bool& open) { DrawFloatingDungeons(Icon_Cells_Size, Icon_Spacing); EndFloatingWindows(); } - + /* if (CVar_GetS32("gItemTrackerNotes", 0)) { BeginFloatingWindows("ItemTracker_Theme_0_Notes"); DrawFloatingNotes(Icon_Cells_Size, Icon_Spacing); EndFloatingWindows(); - } + }*/ } else if (CVar_GetS32("gItemTrackerTheme", 0) == 1) { // Per groups elements N.1 BeginFloatingWindows("ItemTracker_Theme_1_Inventory"); DrawFloatingInventory(Icon_Cells_Size, Icon_Spacing); @@ -1491,12 +1511,12 @@ void DrawItemTracker(bool& open) { DrawFloatingDungeons(Icon_Cells_Size, Icon_Spacing); EndFloatingWindows(); } - + /* if (CVar_GetS32("gItemTrackerNotes", 0)) { BeginFloatingWindows("ItemTracker_Theme_1_Notes"); DrawFloatingNotes(Icon_Cells_Size, Icon_Spacing); EndFloatingWindows(); - } + }*/ } else if (CVar_GetS32("gItemTrackerTheme", 0) == 2) { // Per groups elements N.2 BeginFloatingWindows("ItemTracker_Theme_2_Inventory"); DrawFloatingInventory(Icon_Cells_Size, Icon_Spacing); @@ -1531,12 +1551,12 @@ void DrawItemTracker(bool& open) { DrawFloatingDungeons(Icon_Cells_Size, Icon_Spacing); EndFloatingWindows(); } - + /* if (CVar_GetS32("gItemTrackerNotes", 0)) { BeginFloatingWindows("ItemTracker_Theme_2_Notes"); DrawFloatingNotes(Icon_Cells_Size, Icon_Spacing); EndFloatingWindows(); - } + }*/ } } } @@ -1570,6 +1590,10 @@ void DrawItemTrackerOptions(bool& open) { ImGui::Text("Chroma Key"); auto flags = ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaBar | ImGuiColorEditFlags_NoLabel; ImGui::ColorEdit4("Chroma Key Selection", (float*)&ChromaKeyBackground, flags); + CVar_SetFloat("gItemTrackerBgColorR", ChromaKeyBackground.x); + CVar_SetFloat("gItemTrackerBgColorG", ChromaKeyBackground.y); + CVar_SetFloat("gItemTrackerBgColorB", ChromaKeyBackground.z); + CVar_SetFloat("gItemTrackerBgColorA", ChromaKeyBackground.w); const char* ItemsTrackerTheme[3] = { "One Block", "Grouped style n.1", "Grouped style n.2" }; ImGui::Text("Using theme :"); @@ -1590,8 +1614,8 @@ void DrawItemTrackerOptions(bool& open) { ImGui::SetWindowPos("ItemTracker_Theme_0_Grouped", Default_Pos_Wnd_0); ImVec2 Default_Pos_Wnd_1 = { OriginPosition.x, OriginPosition.y + 175}; ImGui::SetWindowPos("ItemTracker_Theme_0_Dungeons", Default_Pos_Wnd_1); - ImVec2 Default_Pos_Wnd_2 = { OriginPosition.x + 100, OriginPosition.y}; - ImGui::SetWindowPos("ItemTracker_Theme_0_Notes", Default_Pos_Wnd_2); + //ImVec2 Default_Pos_Wnd_2 = { OriginPosition.x + 100, OriginPosition.y}; + //ImGui::SetWindowPos("ItemTracker_Theme_0_Notes", Default_Pos_Wnd_2); } else if (CVar_GetS32("gItemTrackerTheme", 0) == 1) { // Per groups elements N.1 ImVec2 Default_Pos_Wnd_0 = { OriginPosition.x, OriginPosition.y }; ImGui::SetWindowPos("ItemTracker_Theme_1_Inventory", Default_Pos_Wnd_0); @@ -1603,8 +1627,8 @@ void DrawItemTrackerOptions(bool& open) { ImGui::SetWindowPos("ItemTracker_Theme_1_Songs", Default_Pos_Wnd_3); ImVec2 Default_Pos_Wnd_4 = { OriginPosition.x + 100, OriginPosition.y + 175}; ImGui::SetWindowPos("ItemTracker_Theme_1_Dungeons", Default_Pos_Wnd_4); - ImVec2 Default_Pos_Wnd_5 = { OriginPosition.x - 100, OriginPosition.y}; - ImGui::SetWindowPos("ItemTracker_Theme_1_Notes", Default_Pos_Wnd_5); + //ImVec2 Default_Pos_Wnd_5 = { OriginPosition.x - 100, OriginPosition.y}; + //ImGui::SetWindowPos("ItemTracker_Theme_1_Notes", Default_Pos_Wnd_5); } else if (CVar_GetS32("gItemTrackerTheme", 0) == 2) { // Per groups elements N.2 ImVec2 Default_Pos_Wnd_0 = { OriginPosition.x, OriginPosition.y }; ImGui::SetWindowPos("ItemTracker_Theme_2_Inventory", Default_Pos_Wnd_0); @@ -1622,8 +1646,8 @@ void DrawItemTrackerOptions(bool& open) { ImGui::SetWindowPos("ItemTracker_Theme_2_Song", Default_Pos_Wnd_6); ImVec2 Default_Pos_Wnd_7 = { OriginPosition.x - 100, OriginPosition.y}; ImGui::SetWindowPos("ItemTracker_Theme_2_Dungeons", Default_Pos_Wnd_7); - ImVec2 Default_Pos_Wnd_8 = { OriginPosition.x - 100, OriginPosition.y + 170}; - ImGui::SetWindowPos("ItemTracker_Theme_2_Notes", Default_Pos_Wnd_8); + //ImVec2 Default_Pos_Wnd_8 = { OriginPosition.x - 100, OriginPosition.y + 170}; + //ImGui::SetWindowPos("ItemTracker_Theme_2_Notes", Default_Pos_Wnd_8); } } SohImGui::EnhancementCheckbox("Alternative medallions display", "gItemTrackerMedallionsPlacement"); @@ -1646,4 +1670,14 @@ void InitItemTracker() { CVar_RegisterS32("gRandoTrackIconSize", 32); SohImGui::AddWindow("Randomizer", "Item Tracker", DrawItemTracker); SohImGui::AddWindow("Randomizer", "Item Tracker Settings", DrawItemTrackerOptions); + float trackerBgR = CVar_GetFloat("gItemTrackerBgColorR", 0); + float trackerBgG = CVar_GetFloat("gItemTrackerBgColorG", 0); + float trackerBgB = CVar_GetFloat("gItemTrackerBgColorB", 0); + float trackerBgA = CVar_GetFloat("gItemTrackerBgColorA", 1); + ChromaKeyBackground = { + trackerBgR, + trackerBgG, + trackerBgB, + trackerBgA + }; // Float value, 1 = 255 in rgb value. } diff --git a/soh/soh/Enhancements/randomizer/randomizer_item_tracker.h b/soh/soh/Enhancements/randomizer/randomizer_item_tracker.h index b67a939fb..1397c3d58 100644 --- a/soh/soh/Enhancements/randomizer/randomizer_item_tracker.h +++ b/soh/soh/Enhancements/randomizer/randomizer_item_tracker.h @@ -1,4 +1,5 @@ #pragma once void InitItemTracker(); -void DrawItemTracker(bool& open); \ No newline at end of file +void DrawItemTracker(bool& open); +void DrawItemAmmo(int itemId); diff --git a/soh/src/code/z_kankyo.c b/soh/src/code/z_kankyo.c index 140f5f832..1c3037801 100644 --- a/soh/src/code/z_kankyo.c +++ b/soh/src/code/z_kankyo.c @@ -4,7 +4,6 @@ #include "objects/gameplay_keep/gameplay_keep.h" #include "objects/gameplay_field_keep/gameplay_field_keep.h" #include "soh/frame_interpolation.h" -#include "soh/Enhancements/randomizer/adult_trade_shuffle.h" typedef enum { /* 0 */ LENS_FLARE_CIRCLE0, @@ -2049,21 +2048,6 @@ void Environment_PlaySceneSequence(GlobalContext* globalCtx) { Audio_SetEnvReverb(globalCtx->roomCtx.curRoom.echo); } -bool HatchPocketEgg(GlobalContext* globalCtx) { - if (!gSaveContext.n64ddFlag) { - return Inventory_ReplaceItem(globalCtx, ITEM_POCKET_EGG, ITEM_POCKET_CUCCO); - } - - if (!(gSaveContext.adultTradeItems & ADULT_TRADE_FLAG(ITEM_POCKET_EGG))) { - return 0; - } - - gSaveContext.adultTradeItems &= ~ADULT_TRADE_FLAG(ITEM_POCKET_EGG); - gSaveContext.adultTradeItems |= ADULT_TRADE_FLAG(ITEM_POCKET_CUCCO); - Inventory_ReplaceItem(globalCtx, ITEM_POCKET_EGG, ITEM_POCKET_CUCCO); - return 1; -} - // updates bgm/sfx and other things as the day progresses void func_80075B44(GlobalContext* globalCtx) { switch (globalCtx->envCtx.unk_E0) { @@ -2117,7 +2101,7 @@ void func_80075B44(GlobalContext* globalCtx) { gSaveContext.dogIsLost = true; func_80078884(NA_SE_EV_CHICKEN_CRY_M); if ((Inventory_ReplaceItem(globalCtx, ITEM_WEIRD_EGG, ITEM_CHICKEN) || - HatchPocketEgg(globalCtx)) && + Inventory_HatchPocketCucco(globalCtx)) && globalCtx->csCtx.state == 0 && !Player_InCsMode(globalCtx)) { Message_StartTextbox(globalCtx, 0x3066, NULL); } diff --git a/soh/src/code/z_parameter.c b/soh/src/code/z_parameter.c index a7f1a6c78..e844a9267 100644 --- a/soh/src/code/z_parameter.c +++ b/soh/src/code/z_parameter.c @@ -2573,6 +2573,21 @@ s32 Inventory_ConsumeFairy(GlobalContext* globalCtx) { return 0; } +bool Inventory_HatchPocketCucco(GlobalContext* globalCtx) { + if (!gSaveContext.n64ddFlag) { + return Inventory_ReplaceItem(globalCtx, ITEM_POCKET_EGG, ITEM_POCKET_CUCCO); + } + + if (!PLAYER_HAS_SHUFFLED_ADULT_TRADE_ITEM(ITEM_POCKET_EGG)) { + return 0; + } + + gSaveContext.adultTradeItems &= ~ADULT_TRADE_FLAG(ITEM_POCKET_EGG); + gSaveContext.adultTradeItems |= ADULT_TRADE_FLAG(ITEM_POCKET_CUCCO); + Inventory_ReplaceItem(globalCtx, ITEM_POCKET_EGG, ITEM_POCKET_CUCCO); + return 1; +} + void func_80086D5C(s32* buf, u16 size) { u16 i; diff --git a/soh/src/code/z_play.c b/soh/src/code/z_play.c index 104b7f1e4..bd0166408 100644 --- a/soh/src/code/z_play.c +++ b/soh/src/code/z_play.c @@ -398,7 +398,7 @@ void Gameplay_Init(GameState* thisx) { gSaveContext.bgsDayCount++; gSaveContext.dogIsLost = true; if (Inventory_ReplaceItem(globalCtx, ITEM_WEIRD_EGG, ITEM_CHICKEN) || - Inventory_ReplaceItem(globalCtx, ITEM_POCKET_EGG, ITEM_POCKET_CUCCO)) { + Inventory_HatchPocketCucco(globalCtx)) { Message_StartTextbox(globalCtx, 0x3066, NULL); } gSaveContext.nextDayTime = 0xFFFE; diff --git a/soh/src/code/z_scene_table.c b/soh/src/code/z_scene_table.c index ea1f45863..0916557b4 100644 --- a/soh/src/code/z_scene_table.c +++ b/soh/src/code/z_scene_table.c @@ -23,6 +23,8 @@ #include "overlays/actors/ovl_Bg_Dodoago/z_bg_dodoago.h" +#include "soh/Enhancements/randomizer/adult_trade_shuffle.h" + #define ENTRANCE(scene, spawn, continueBgm, displayTitleCard, fadeIn, fadeOut) \ { \ scene, spawn, \ @@ -2136,7 +2138,11 @@ void func_8009EE44(GlobalContext* globalCtx) { gDPPipeSync(POLY_OPA_DISP++); gDPSetEnvColor(POLY_OPA_DISP++, 128, 128, 128, 128); - if ((globalCtx->roomCtx.unk_74[0] == 0) && (INV_CONTENT(ITEM_COJIRO) == ITEM_COJIRO)) { + bool playerHasCojiro = INV_CONTENT(ITEM_COJIRO) == ITEM_COJIRO; + if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_ADULT_TRADE)) { + playerHasCojiro = PLAYER_HAS_SHUFFLED_ADULT_TRADE_ITEM(ITEM_COJIRO); + } + if ((globalCtx->roomCtx.unk_74[0] == 0) && playerHasCojiro) { if (globalCtx->roomCtx.unk_74[1] == 50) { func_8002F7DC(&GET_PLAYER(globalCtx)->actor, NA_SE_EV_CHICKEN_CRY_M); globalCtx->roomCtx.unk_74[0] = 1; diff --git a/soh/src/code/z_sram.c b/soh/src/code/z_sram.c index 65eb58812..5e6677ff2 100644 --- a/soh/src/code/z_sram.c +++ b/soh/src/code/z_sram.c @@ -722,8 +722,9 @@ void Sram_InitSave(FileChooseContext* fileChooseCtx) { gSaveContext.eventChkInf[4] |= 0x20; // master sword pulled gSaveContext.eventChkInf[4] |= 0x8000; // entered master sword chamber gSaveContext.infTable[0] |= 1; - // RANDTODO: Don't skip this scene if Don't Skip Glitch Useful Cutscenes is enabled. - gSaveContext.infTable[17] |= 0x400; // Darunia in Fire Temple + if (!Randomizer_GetSettingValue(RSK_ENABLE_GLITCH_CUTSCENES)) { + gSaveContext.infTable[17] |= 0x400; // Darunia in Fire Temple + } gSaveContext.cutsceneIndex = 0; Flags_SetEventChkInf(5); diff --git a/soh/src/overlays/actors/ovl_En_Hs/z_en_hs.c b/soh/src/overlays/actors/ovl_En_Hs/z_en_hs.c index 3fe2c9851..b3c008a50 100644 --- a/soh/src/overlays/actors/ovl_En_Hs/z_en_hs.c +++ b/soh/src/overlays/actors/ovl_En_Hs/z_en_hs.c @@ -79,14 +79,25 @@ void EnHs_Init(Actor* thisx, GlobalContext* globalCtx) { // "chicken shop (adult era)" osSyncPrintf(VT_FGCOL(CYAN) " ヒヨコの店(大人の時) \n" VT_RST); func_80A6E3A0(this, func_80A6E9AC); - bool shouldDespawn; + bool shouldSpawn; bool tradedMushroom = gSaveContext.itemGetInf[3] & 1; - if (gSaveContext.n64ddFlag) { - shouldDespawn = tradedMushroom && !(gSaveContext.adultTradeItems & ADULT_TRADE_FLAG(ITEM_COJIRO)); + if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_ADULT_TRADE)) { + // To explain the logic because Fado and Grog are linked: + // - If you have Cojiro, then spawn Grog and not Fado. + // - If you don't have Cojiro but do have Odd Potion, spawn Fado and not Grog. + // - If you don't have either, spawn Grog if you haven't traded the Odd Mushroom. + // - If you don't have either but have traded the mushroom, don't spawn either. + if (PLAYER_HAS_SHUFFLED_ADULT_TRADE_ITEM(ITEM_COJIRO)) { + shouldSpawn = true; + } else if (PLAYER_HAS_SHUFFLED_ADULT_TRADE_ITEM(ITEM_ODD_POTION)) { + shouldSpawn = false; + } else { + shouldSpawn = !tradedMushroom; + } } else { - shouldDespawn = tradedMushroom; + shouldSpawn = !tradedMushroom; } - if (shouldDespawn) { + if (!shouldSpawn) { // "chicken shop closed" osSyncPrintf(VT_FGCOL(CYAN) " ヒヨコ屋閉店 \n" VT_RST); Actor_Kill(&this->actor); diff --git a/soh/src/overlays/actors/ovl_En_Ko/z_en_ko.c b/soh/src/overlays/actors/ovl_En_Ko/z_en_ko.c index 4b9bc1f2b..2763be734 100644 --- a/soh/src/overlays/actors/ovl_En_Ko/z_en_ko.c +++ b/soh/src/overlays/actors/ovl_En_Ko/z_en_ko.c @@ -1026,7 +1026,20 @@ s32 EnKo_CanSpawn(EnKo* this, GlobalContext* globalCtx) { } case SCENE_SPOT10: - return (INV_CONTENT(ITEM_TRADE_ADULT) == ITEM_ODD_POTION) ? true : false; + if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_ADULT_TRADE)) { + // To explain the logic because Fado and Grog are linked: + // - If you have Cojiro, then spawn Grog and not Fado. + // - If you don't have Cojiro but do have Odd Potion, spawn Fado and not Grog. + // - If you don't have either, spawn Grog if you haven't traded the Odd Mushroom. + // - If you don't have either but have traded the mushroom, don't spawn either. + if (PLAYER_HAS_SHUFFLED_ADULT_TRADE_ITEM(ITEM_COJIRO)) { + return false; + } else { + return PLAYER_HAS_SHUFFLED_ADULT_TRADE_ITEM(ITEM_ODD_POTION); + } + } else { + return (INV_CONTENT(ITEM_TRADE_ADULT) == ITEM_ODD_POTION) ? true : false; + } default: return false; } diff --git a/soh/src/overlays/actors/ovl_En_Po_Sisters/z_en_po_sisters.c b/soh/src/overlays/actors/ovl_En_Po_Sisters/z_en_po_sisters.c index d66cdae6c..473d426d0 100644 --- a/soh/src/overlays/actors/ovl_En_Po_Sisters/z_en_po_sisters.c +++ b/soh/src/overlays/actors/ovl_En_Po_Sisters/z_en_po_sisters.c @@ -183,7 +183,7 @@ void EnPoSisters_Init(Actor* thisx, GlobalContext* globalCtx) { this->epoch++; // Skip Poe Intro Cutscene - if (gSaveContext.n64ddFlag && thisx->params == 4124) { + if (gSaveContext.n64ddFlag && thisx->params == 4124 && !Randomizer_GetSettingValue(RSK_ENABLE_GLITCH_CUTSCENES)) { Flags_SetSwitch(globalCtx, 0x1B); Actor_Kill(thisx); } diff --git a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_item.c b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_item.c index fe57289fa..b8aff2d22 100644 --- a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_item.c +++ b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_item.c @@ -354,8 +354,16 @@ void KaleidoScope_DrawItemSelect(GlobalContext* globalCtx) { KaleidoScope_SetCursorVtx(pauseCtx, index, pauseCtx->itemVtx); if ((pauseCtx->debugState == 0) && (pauseCtx->state == 6) && (pauseCtx->unk_1E4 == 0)) { - if (CVar_GetS32("gMaskSelect", 0) && (gSaveContext.eventChkInf[8] & 0x8000) && - cursorSlot == SLOT_TRADE_CHILD && CHECK_BTN_ALL(input->press.button, BTN_A)) { + // only allow mask select when: + // the shop is open: + // * zelda's letter check: gSaveContext.eventChkInf[4] & 1 + // * kak gate check: gSaveContext.infTable[7] & 0x40 + // and the mask quest is complete: gSaveContext.eventChkInf[8] & 0x8000 + if (CVar_GetS32("gMaskSelect", 0) && + (gSaveContext.eventChkInf[8] & 0x8000) && + cursorSlot == SLOT_TRADE_CHILD && CHECK_BTN_ALL(input->press.button, BTN_A) && + (gSaveContext.eventChkInf[4] & 1) && + (gSaveContext.infTable[7] & 0x40)) { Audio_PlaySoundGeneral(NA_SE_SY_DECIDE, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8); gSelectingMask = !gSelectingMask; }