diff --git a/soh/soh/Enhancements/debugger/debugSaveEditor.cpp b/soh/soh/Enhancements/debugger/debugSaveEditor.cpp index 342dc34fa..293aebeb2 100644 --- a/soh/soh/Enhancements/debugger/debugSaveEditor.cpp +++ b/soh/soh/Enhancements/debugger/debugSaveEditor.cpp @@ -67,6 +67,7 @@ IntSliderOptions intSliderOptionsBase; ButtonOptions buttonOptionsBase; CheckboxOptions checkboxOptionsBase; ComboboxOptions comboboxOptionsBase; +static std::map flagTableFilters; // Modification of gAmmoItems that replaces ITEM_NONE with the item in inventory slot it represents u8 gAllAmmoItems[] = { @@ -696,9 +697,79 @@ void DrawFlagTableArray16(const FlagTable& flagTable, uint16_t row, uint16_t& fl } ImGui::PopID(); } + ImGui::PopID(); } +static uint16_t& GetFlagTableEntry(const FlagTable& flagTable, size_t row) { + switch (flagTable.flagTableType) { + case EVENT_CHECK_INF: + return gSaveContext.eventChkInf[row]; + case ITEM_GET_INF: + return gSaveContext.itemGetInf[row]; + case INF_TABLE: + return gSaveContext.infTable[row]; + case EVENT_INF: + return gSaveContext.eventInf[row]; + case RANDOMIZER_INF: + return gSaveContext.ship.randomizerInf[row]; + default: // Shouldn't be hit + assert(false); + return gSaveContext.eventChkInf[row]; + } +} + +static void DrawFlagTableSearchResults(const FlagTable& flagTable, ImGuiTextFilter& filter) { + bool hasMatches = false; + + for (size_t row = 0; row < flagTable.size + 1; row++) { + uint16_t& flags = GetFlagTableEntry(flagTable, row); + + for (int32_t flagIndex = 15; flagIndex >= 0; flagIndex--) { + uint16_t index = row * 16 + flagIndex; + auto descIt = flagTable.flagDescriptions.find(index); + const char* desc = descIt != flagTable.flagDescriptions.end() ? descIt->second : ""; + std::string searchable = fmt::format("0x{:02X} {}", index, desc); + if (!filter.PassFilter(searchable.c_str())) { + continue; + } + + hasMatches = true; + + ImGui::PushID(index); + bool hasDescription = descIt != flagTable.flagDescriptions.end(); + uint32_t bitMask = 1 << flagIndex; + ImVec4 themeColor = ColorValues.at(THEME_COLOR); + ImVec4 colorDark = { themeColor.x * 0.4f, themeColor.y * 0.4f, themeColor.z * 0.4f, themeColor.z }; + PushStyleCheckbox(hasDescription ? themeColor : colorDark); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(4.0f, 3.0f)); + bool flag = (flags & bitMask) != 0; + if (ImGui::Checkbox("##check", &flag)) { + if (flag) { + flags |= bitMask; + } else { + flags &= ~bitMask; + } + } + ImGui::PopStyleVar(); + PopStyleCheckbox(); + + ImGui::SameLine(); + if (hasDescription) { + ImGui::TextWrapped("0x%02X: %s", index, desc); + } else { + ImGui::Text("0x%02X", index); + } + + ImGui::PopID(); + } + } + + if (!hasMatches) { + ImGui::Text("No flags match the current search."); + } +} + void DrawFlagsTab() { if (ImGui::TreeNode("Player State")) { if (gPlayState != nullptr) { @@ -1046,37 +1117,47 @@ void DrawFlagsTab() { } if (ImGui::TreeNode(flagTable.name)) { - for (size_t j = 0; j < flagTable.size + 1; j++) { - DrawGroupWithBorder( - [&]() { - if (j == 0) { - for (int k = 0xF; k >= 0; k--) { - ImGui::SameLine(37.5 + ((0xF - k) * 33.8)); - ImGui::Text("%X", k); + ImGui::PushID(flagTable.name); + ImGuiTextFilter& flagFilter = flagTableFilters[flagTable.name]; + ImGui::SetNextItemWidth(ImGui::GetFontSize() * 16); + flagFilter.Draw(); + ImGui::Spacing(); + + if (!flagFilter.IsActive()) { + for (size_t j = 0; j < flagTable.size + 1; j++) { + DrawGroupWithBorder( + [&]() { + if (j == 0) { + for (int k = 0xF; k >= 0; k--) { + ImGui::SameLine(37.5 + ((0xF - k) * 33.8)); + ImGui::Text("%X", k); + } } - } - ImGui::Text("%s", fmt::format("{:<2X}", j).c_str()); + ImGui::Text("%s", fmt::format("{:<2X}", j).c_str()); - switch (flagTable.flagTableType) { - case EVENT_CHECK_INF: - DrawFlagTableArray16(flagTable, j, gSaveContext.eventChkInf[j]); - break; - case ITEM_GET_INF: - DrawFlagTableArray16(flagTable, j, gSaveContext.itemGetInf[j]); - break; - case INF_TABLE: - DrawFlagTableArray16(flagTable, j, gSaveContext.infTable[j]); - break; - case EVENT_INF: - DrawFlagTableArray16(flagTable, j, gSaveContext.eventInf[j]); - break; - case RANDOMIZER_INF: - DrawFlagTableArray16(flagTable, j, gSaveContext.ship.randomizerInf[j]); - break; - } - }, - flagTable.name); + switch (flagTable.flagTableType) { + case EVENT_CHECK_INF: + DrawFlagTableArray16(flagTable, j, gSaveContext.eventChkInf[j]); + break; + case ITEM_GET_INF: + DrawFlagTableArray16(flagTable, j, gSaveContext.itemGetInf[j]); + break; + case INF_TABLE: + DrawFlagTableArray16(flagTable, j, gSaveContext.infTable[j]); + break; + case EVENT_INF: + DrawFlagTableArray16(flagTable, j, gSaveContext.eventInf[j]); + break; + case RANDOMIZER_INF: + DrawFlagTableArray16(flagTable, j, gSaveContext.ship.randomizerInf[j]); + break; + } + }, + flagTable.name); + } + } else { + DrawFlagTableSearchResults(flagTable, flagFilter); } // make some buttons to help with fishsanity debugging @@ -1108,6 +1189,7 @@ void DrawFlagsTab() { } } + ImGui::PopID(); ImGui::TreePop(); } }