mirror of
https://github.com/HarbourMasters/Shipwright.git
synced 2024-11-25 19:02:19 -05:00
Add flag, equipment, and quest status editors (#164)
This commit is contained in:
parent
1dcd24e7e2
commit
a11038f515
@ -179,21 +179,46 @@ namespace SohImGui {
|
|||||||
stbi_image_free(img_data);
|
stbi_image_free(img_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoadResource(const std::string& name, const std::string& path) {
|
void LoadResource(const std::string& name, const std::string& path, const ImVec4& tint) {
|
||||||
GfxRenderingAPI* api = gfx_get_current_rendering_api();
|
GfxRenderingAPI* api = gfx_get_current_rendering_api();
|
||||||
const auto res = static_cast<Ship::Texture*>(GlobalCtx2::GetInstance()->GetResourceManager()->LoadResource(normalize(path)).get());
|
const auto res = static_cast<Ship::Texture*>(GlobalCtx2::GetInstance()->GetResourceManager()->LoadResource(normalize(path)).get());
|
||||||
|
|
||||||
if (res->texType != Ship::TextureType::RGBA32bpp) {
|
std::vector<uint8_t> texBuffer;
|
||||||
|
texBuffer.reserve(res->width * res->height * 4);
|
||||||
|
|
||||||
|
switch (res->texType) {
|
||||||
|
case Ship::TextureType::RGBA32bpp:
|
||||||
|
texBuffer.assign(res->imageData, res->imageData + (res->width * res->height * 4));
|
||||||
|
break;
|
||||||
|
case Ship::TextureType::GrayscaleAlpha8bpp:
|
||||||
|
for (int32_t i = 0; i < res->width * res->height; i++) {
|
||||||
|
uint8_t ia = res->imageData[i];
|
||||||
|
uint8_t color = ((ia >> 4) & 0xF) * 255 / 15;
|
||||||
|
uint8_t alpha = (ia & 0xF) * 255 / 15;
|
||||||
|
texBuffer.push_back(color);
|
||||||
|
texBuffer.push_back(color);
|
||||||
|
texBuffer.push_back(color);
|
||||||
|
texBuffer.push_back(alpha);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
// TODO convert other image types
|
// TODO convert other image types
|
||||||
SPDLOG_WARN("SohImGui::LoadResource: Attempting to load unsupporting image type %s", path.c_str());
|
SPDLOG_WARN("SohImGui::LoadResource: Attempting to load unsupporting image type %s", path.c_str());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (size_t pixel = 0; pixel < texBuffer.size() / 4; pixel++) {
|
||||||
|
texBuffer[pixel * 4 + 0] *= tint.x;
|
||||||
|
texBuffer[pixel * 4 + 1] *= tint.y;
|
||||||
|
texBuffer[pixel * 4 + 2] *= tint.z;
|
||||||
|
texBuffer[pixel * 4 + 3] *= tint.w;
|
||||||
|
}
|
||||||
|
|
||||||
const auto asset = new GameAsset{ api->new_texture() };
|
const auto asset = new GameAsset{ api->new_texture() };
|
||||||
|
|
||||||
api->select_texture(0, asset->textureId);
|
api->select_texture(0, asset->textureId);
|
||||||
api->set_sampler_parameters(0, false, 0, 0);
|
api->set_sampler_parameters(0, false, 0, 0);
|
||||||
api->upload_texture(res->imageData, res->width, res->height);
|
api->upload_texture(texBuffer.data(), res->width, res->height);
|
||||||
|
|
||||||
DefaultAssets[name] = asset;
|
DefaultAssets[name] = asset;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "Lib/ImGui/imgui.h"
|
||||||
#include "SohConsole.h"
|
#include "SohConsole.h"
|
||||||
|
|
||||||
struct GameAsset {
|
struct GameAsset {
|
||||||
@ -63,7 +64,7 @@ namespace SohImGui {
|
|||||||
void ShowCursor(bool hide, Dialogues w);
|
void ShowCursor(bool hide, Dialogues w);
|
||||||
void BindCmd(const std::string& cmd, CommandEntry entry);
|
void BindCmd(const std::string& cmd, CommandEntry entry);
|
||||||
void AddWindow(const std::string& category, const std::string& name, WindowDrawFunc drawFunc);
|
void AddWindow(const std::string& category, const std::string& name, WindowDrawFunc drawFunc);
|
||||||
void LoadResource(const std::string& name, const std::string& path);
|
void LoadResource(const std::string& name, const std::string& path, const ImVec4& tint = ImVec4(1, 1, 1, 1));
|
||||||
ImTextureID GetTextureByID(int id);
|
ImTextureID GetTextureByID(int id);
|
||||||
ImTextureID GetTextureByName(const std::string& name);
|
ImTextureID GetTextureByName(const std::string& name);
|
||||||
}
|
}
|
||||||
|
@ -185,6 +185,7 @@
|
|||||||
<ClCompile Include="soh\gu_pc.c" />
|
<ClCompile Include="soh\gu_pc.c" />
|
||||||
<ClCompile Include="soh\OTRGlobals.cpp" />
|
<ClCompile Include="soh\OTRGlobals.cpp" />
|
||||||
<ClCompile Include="soh\stubs.c" />
|
<ClCompile Include="soh\stubs.c" />
|
||||||
|
<ClCompile Include="soh\util.cpp" />
|
||||||
<ClCompile Include="soh\z_message_OTR.cpp" />
|
<ClCompile Include="soh\z_message_OTR.cpp" />
|
||||||
<ClCompile Include="soh\z_play_otr.cpp" />
|
<ClCompile Include="soh\z_play_otr.cpp" />
|
||||||
<ClCompile Include="soh\z_scene_otr.cpp" />
|
<ClCompile Include="soh\z_scene_otr.cpp" />
|
||||||
@ -928,6 +929,7 @@
|
|||||||
<ClInclude Include="soh\Enhancements\debugger\debugSaveEditor.h" />
|
<ClInclude Include="soh\Enhancements\debugger\debugSaveEditor.h" />
|
||||||
<ClInclude Include="soh\gameconsole.h" />
|
<ClInclude Include="soh\gameconsole.h" />
|
||||||
<ClInclude Include="soh\OTRGlobals.h" />
|
<ClInclude Include="soh\OTRGlobals.h" />
|
||||||
|
<ClInclude Include="soh\util.h" />
|
||||||
<ClInclude Include="src\overlays\actors\ovl_Arms_Hook\z_arms_hook.h" />
|
<ClInclude Include="src\overlays\actors\ovl_Arms_Hook\z_arms_hook.h" />
|
||||||
<ClInclude Include="src\overlays\actors\ovl_Arrow_Fire\z_arrow_fire.h" />
|
<ClInclude Include="src\overlays\actors\ovl_Arrow_Fire\z_arrow_fire.h" />
|
||||||
<ClInclude Include="src\overlays\actors\ovl_Arrow_Ice\z_arrow_ice.h" />
|
<ClInclude Include="src\overlays\actors\ovl_Arrow_Ice\z_arrow_ice.h" />
|
||||||
|
@ -2181,6 +2181,9 @@
|
|||||||
<ClCompile Include="soh\Enhancements\debugger\debugSaveEditor.cpp">
|
<ClCompile Include="soh\Enhancements\debugger\debugSaveEditor.cpp">
|
||||||
<Filter>Source Files\soh\Enhancements\debugger</Filter>
|
<Filter>Source Files\soh\Enhancements\debugger</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="soh\util.cpp">
|
||||||
|
<Filter>Source Files\soh</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="src\overlays\actors\ovl_kaleido_scope\z_kaleido_scope.h">
|
<ClInclude Include="src\overlays\actors\ovl_kaleido_scope\z_kaleido_scope.h">
|
||||||
@ -3728,6 +3731,9 @@
|
|||||||
<ClInclude Include="soh\Enhancements\debugger\debugSaveEditor.h">
|
<ClInclude Include="soh\Enhancements\debugger\debugSaveEditor.h">
|
||||||
<Filter>Header Files\soh\Enhancements\debugger</Filter>
|
<Filter>Header Files\soh\Enhancements\debugger</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="soh\util.h">
|
||||||
|
<Filter>Header Files\soh</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="include\macro.inc">
|
<None Include="include\macro.inc">
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
#include "debugSaveEditor.h"
|
#include "debugSaveEditor.h"
|
||||||
|
#include "../../util.h"
|
||||||
#include "../libultraship/SohImGuiImpl.h"
|
#include "../libultraship/SohImGuiImpl.h"
|
||||||
|
|
||||||
|
#include <array>
|
||||||
#include <bit>
|
#include <bit>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
@ -13,18 +15,20 @@ extern "C" {
|
|||||||
extern GlobalContext* gGlobalCtx;
|
extern GlobalContext* gGlobalCtx;
|
||||||
|
|
||||||
#include "textures/icon_item_static/icon_item_static.h"
|
#include "textures/icon_item_static/icon_item_static.h"
|
||||||
|
#include "textures/icon_item_24_static/icon_item_24_static.h"
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint32_t id;
|
uint32_t id;
|
||||||
std::string name;
|
std::string name;
|
||||||
|
std::string nameFaded;
|
||||||
std::string texturePath;
|
std::string texturePath;
|
||||||
} ItemMapEntry;
|
} ItemMapEntry;
|
||||||
|
|
||||||
#define ITEM_MAP_ENTRY(id) \
|
#define ITEM_MAP_ENTRY(id) \
|
||||||
{ \
|
{ \
|
||||||
id, { \
|
id, { \
|
||||||
id, #id, static_cast<char*>(gItemIcons[id]) \
|
id, #id, #id "_Faded", static_cast<char*>(gItemIcons[id]) \
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,6 +124,10 @@ std::map<uint32_t, ItemMapEntry> itemMapping = {
|
|||||||
ITEM_MAP_ENTRY(ITEM_WALLET_GIANT),
|
ITEM_MAP_ENTRY(ITEM_WALLET_GIANT),
|
||||||
ITEM_MAP_ENTRY(ITEM_SEEDS),
|
ITEM_MAP_ENTRY(ITEM_SEEDS),
|
||||||
ITEM_MAP_ENTRY(ITEM_FISHING_POLE),
|
ITEM_MAP_ENTRY(ITEM_FISHING_POLE),
|
||||||
|
ITEM_MAP_ENTRY(ITEM_KEY_BOSS),
|
||||||
|
ITEM_MAP_ENTRY(ITEM_COMPASS),
|
||||||
|
ITEM_MAP_ENTRY(ITEM_DUNGEON_MAP),
|
||||||
|
ITEM_MAP_ENTRY(ITEM_KEY_SMALL),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Maps entries in the GS flag array to the area name it represents
|
// Maps entries in the GS flag array to the area name it represents
|
||||||
@ -147,6 +155,7 @@ std::vector<std::string> gsMapping = {
|
|||||||
"Gerudo Fortress",
|
"Gerudo Fortress",
|
||||||
"Desert Colossus, Haunted Wasteland",
|
"Desert Colossus, Haunted Wasteland",
|
||||||
};
|
};
|
||||||
|
|
||||||
extern "C" u8 gAreaGsFlags[];
|
extern "C" u8 gAreaGsFlags[];
|
||||||
|
|
||||||
extern "C" u8 gAmmoItems[];
|
extern "C" u8 gAmmoItems[];
|
||||||
@ -158,6 +167,63 @@ u8 gAllAmmoItems[] = {
|
|||||||
ITEM_BOOMERANG, ITEM_LENS, ITEM_BEAN, ITEM_HAMMER,
|
ITEM_BOOMERANG, ITEM_LENS, ITEM_BEAN, ITEM_HAMMER,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t id;
|
||||||
|
std::string name;
|
||||||
|
std::string nameFaded;
|
||||||
|
std::string texturePath;
|
||||||
|
} QuestMapEntry;
|
||||||
|
|
||||||
|
#define QUEST_MAP_ENTRY(id, tex) \
|
||||||
|
{ \
|
||||||
|
id, { \
|
||||||
|
id, #id, #id "_Faded", tex \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
// Maps quest items ids to info for use in ImGui
|
||||||
|
std::map<uint32_t, QuestMapEntry> questMapping = {
|
||||||
|
QUEST_MAP_ENTRY(QUEST_MEDALLION_FOREST, gForestMedallionIconTex),
|
||||||
|
QUEST_MAP_ENTRY(QUEST_MEDALLION_FIRE, gFireMedallionIconTex),
|
||||||
|
QUEST_MAP_ENTRY(QUEST_MEDALLION_WATER, gWaterMedallionIconTex),
|
||||||
|
QUEST_MAP_ENTRY(QUEST_MEDALLION_SPIRIT, gSpiritMedallionIconTex),
|
||||||
|
QUEST_MAP_ENTRY(QUEST_MEDALLION_SHADOW, gShadowMedallionIconTex),
|
||||||
|
QUEST_MAP_ENTRY(QUEST_MEDALLION_LIGHT, gLightMedallionIconTex),
|
||||||
|
QUEST_MAP_ENTRY(QUEST_KOKIRI_EMERALD, gKokiriEmeraldIconTex),
|
||||||
|
QUEST_MAP_ENTRY(QUEST_GORON_RUBY, gGoronRubyIconTex),
|
||||||
|
QUEST_MAP_ENTRY(QUEST_ZORA_SAPPHIRE, gZoraSapphireIconTex),
|
||||||
|
QUEST_MAP_ENTRY(QUEST_STONE_OF_AGONY, gStoneOfAgonyIconTex),
|
||||||
|
QUEST_MAP_ENTRY(QUEST_GERUDO_CARD, gGerudosCardIconTex),
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t id;
|
||||||
|
std::string name;
|
||||||
|
std::string nameFaded;
|
||||||
|
ImVec4 color;
|
||||||
|
} SongMapEntry;
|
||||||
|
|
||||||
|
#define SONG_MAP_ENTRY(id, r, g, b) \
|
||||||
|
{ \
|
||||||
|
id, #id, #id "_Faded", ImVec4(r / 255.0f, g / 255.0f, b / 255.0f, 1.0f) \
|
||||||
|
}
|
||||||
|
|
||||||
|
// Maps song ids to info for use in ImGui
|
||||||
|
std::array<SongMapEntry, 12> songMapping = { {
|
||||||
|
SONG_MAP_ENTRY(QUEST_SONG_LULLABY, 255, 255, 255),
|
||||||
|
SONG_MAP_ENTRY(QUEST_SONG_EPONA, 255, 255, 255),
|
||||||
|
SONG_MAP_ENTRY(QUEST_SONG_SARIA, 255, 255, 255),
|
||||||
|
SONG_MAP_ENTRY(QUEST_SONG_SUN, 255, 255, 255),
|
||||||
|
SONG_MAP_ENTRY(QUEST_SONG_TIME, 255, 255, 255),
|
||||||
|
SONG_MAP_ENTRY(QUEST_SONG_STORMS, 255, 255, 255),
|
||||||
|
SONG_MAP_ENTRY(QUEST_SONG_MINUET, 150, 255, 100),
|
||||||
|
SONG_MAP_ENTRY(QUEST_SONG_BOLERO, 255, 80, 40),
|
||||||
|
SONG_MAP_ENTRY(QUEST_SONG_SERENADE, 100, 150, 255),
|
||||||
|
SONG_MAP_ENTRY(QUEST_SONG_REQUIEM, 255, 160, 0),
|
||||||
|
SONG_MAP_ENTRY(QUEST_SONG_NOCTURNE, 255, 100, 255),
|
||||||
|
SONG_MAP_ENTRY(QUEST_SONG_PRELUDE, 255, 240, 100),
|
||||||
|
} };
|
||||||
|
|
||||||
// Adds a text tooltip for the previous ImGui item
|
// Adds a text tooltip for the previous ImGui item
|
||||||
void SetLastItemHoverText(const std::string& text) {
|
void SetLastItemHoverText(const std::string& text) {
|
||||||
if (ImGui::IsItemHovered()) {
|
if (ImGui::IsItemHovered()) {
|
||||||
@ -178,17 +244,33 @@ void InsertHelpHoverText(const std::string& text) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DrawSaveEditor(bool& open) {
|
// Encapsulates what is drawn by the passed-in function within a border
|
||||||
if (!open) {
|
template<typename T>
|
||||||
return;
|
void DrawGroupWithBorder(T&& drawFunc) {
|
||||||
}
|
// First group encapsulates the inner portion and border
|
||||||
|
ImGui::BeginGroup();
|
||||||
ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver);
|
|
||||||
if (!ImGui::Begin("Save Editor", &open)) {
|
ImVec2 padding = ImGui::GetStyle().FramePadding;
|
||||||
ImGui::End();
|
ImVec2 p0 = ImGui::GetCursorScreenPos();
|
||||||
return;
|
ImGui::SetCursorScreenPos(ImVec2(p0.x + padding.x, p0.y + padding.y));
|
||||||
|
|
||||||
|
// Second group encapsulates just the inner portion
|
||||||
|
ImGui::BeginGroup();
|
||||||
|
|
||||||
|
drawFunc();
|
||||||
|
|
||||||
|
ImGui::Dummy(padding);
|
||||||
|
ImGui::EndGroup();
|
||||||
|
|
||||||
|
ImVec2 p1 = ImGui::GetItemRectMax();
|
||||||
|
p1.x += padding.x;
|
||||||
|
ImVec4 borderCol = ImGui::GetStyle().Colors[ImGuiCol_Border];
|
||||||
|
ImGui::GetWindowDrawList()->AddRect(p0, p1, IM_COL32(borderCol.x * 255, borderCol.y * 255, borderCol.z * 255, borderCol.w * 255));
|
||||||
|
|
||||||
|
ImGui::EndGroup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DrawInfoTab() {
|
||||||
// TODO This is the bare minimum to get the player name showing
|
// TODO This is the bare minimum to get the player name showing
|
||||||
// There will need to be more effort to get it robust and editable
|
// There will need to be more effort to get it robust and editable
|
||||||
std::string name;
|
std::string name;
|
||||||
@ -201,8 +283,6 @@ void DrawSaveEditor(bool& open) {
|
|||||||
}
|
}
|
||||||
name += '\0';
|
name += '\0';
|
||||||
|
|
||||||
if (ImGui::BeginTabBar("SaveContextTabBar", ImGuiTabBarFlags_NoCloseWithMiddleMouseButton)) {
|
|
||||||
if (ImGui::BeginTabItem("Info")) {
|
|
||||||
ImGui::PushItemWidth(ImGui::GetFontSize() * 6);
|
ImGui::PushItemWidth(ImGui::GetFontSize() * 6);
|
||||||
|
|
||||||
ImGui::Text("Name: %s", name.c_str());
|
ImGui::Text("Name: %s", name.c_str());
|
||||||
@ -304,10 +384,6 @@ void DrawSaveEditor(bool& open) {
|
|||||||
ImGui::InputScalar("Deaths", ImGuiDataType_U16, &gSaveContext.deaths);
|
ImGui::InputScalar("Deaths", ImGuiDataType_U16, &gSaveContext.deaths);
|
||||||
InsertHelpHoverText("Total number of deaths");
|
InsertHelpHoverText("Total number of deaths");
|
||||||
|
|
||||||
// TODO Move to quest status screen once the page is created
|
|
||||||
ImGui::InputScalar("GS Count", ImGuiDataType_S16, &gSaveContext.inventory.gsTokens);
|
|
||||||
InsertHelpHoverText("Number of gold skulltula tokens aquired");
|
|
||||||
|
|
||||||
bool bgsFlag = gSaveContext.bgsFlag != 0;
|
bool bgsFlag = gSaveContext.bgsFlag != 0;
|
||||||
if (ImGui::Checkbox("Has BGS", &bgsFlag)) {
|
if (ImGui::Checkbox("Has BGS", &bgsFlag)) {
|
||||||
gSaveContext.bgsFlag = bgsFlag;
|
gSaveContext.bgsFlag = bgsFlag;
|
||||||
@ -336,10 +412,9 @@ void DrawSaveEditor(bool& open) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
ImGui::PopItemWidth();
|
ImGui::PopItemWidth();
|
||||||
ImGui::EndTabItem();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ImGui::BeginTabItem("Inventory")) {
|
void DrawInventoryTab() {
|
||||||
static bool restrictToValid = true;
|
static bool restrictToValid = true;
|
||||||
|
|
||||||
ImGui::Checkbox("Restrict to valid items", &restrictToValid);
|
ImGui::Checkbox("Restrict to valid items", &restrictToValid);
|
||||||
@ -362,8 +437,8 @@ void DrawSaveEditor(bool& open) {
|
|||||||
uint8_t item = gSaveContext.inventory.items[index];
|
uint8_t item = gSaveContext.inventory.items[index];
|
||||||
if (item != ITEM_NONE) {
|
if (item != ITEM_NONE) {
|
||||||
const ItemMapEntry& slotEntry = itemMapping.find(item)->second;
|
const ItemMapEntry& slotEntry = itemMapping.find(item)->second;
|
||||||
if (ImGui::ImageButton(SohImGui::GetTextureByName(slotEntry.name), ImVec2(32.0f, 32.0f),
|
if (ImGui::ImageButton(SohImGui::GetTextureByName(slotEntry.name), ImVec2(32.0f, 32.0f), ImVec2(0, 0),
|
||||||
ImVec2(0, 0), ImVec2(1, 1), 0)) {
|
ImVec2(1, 1), 0)) {
|
||||||
selectedIndex = index;
|
selectedIndex = index;
|
||||||
ImGui::OpenPopup(itemPopupPicker);
|
ImGui::OpenPopup(itemPopupPicker);
|
||||||
}
|
}
|
||||||
@ -382,7 +457,7 @@ void DrawSaveEditor(bool& open) {
|
|||||||
gSaveContext.inventory.items[selectedIndex] = ITEM_NONE;
|
gSaveContext.inventory.items[selectedIndex] = ITEM_NONE;
|
||||||
ImGui::CloseCurrentPopup();
|
ImGui::CloseCurrentPopup();
|
||||||
}
|
}
|
||||||
SetLastItemHoverText("ITEM_NONE");
|
SetLastItemHoverText("None");
|
||||||
|
|
||||||
std::vector<ItemMapEntry> possibleItems;
|
std::vector<ItemMapEntry> possibleItems;
|
||||||
if (restrictToValid) {
|
if (restrictToValid) {
|
||||||
@ -412,7 +487,7 @@ void DrawSaveEditor(bool& open) {
|
|||||||
gSaveContext.inventory.items[selectedIndex] = slotEntry.id;
|
gSaveContext.inventory.items[selectedIndex] = slotEntry.id;
|
||||||
ImGui::CloseCurrentPopup();
|
ImGui::CloseCurrentPopup();
|
||||||
}
|
}
|
||||||
SetLastItemHoverText(slotEntry.name);
|
SetLastItemHoverText(SohUtils::GetItemName(slotEntry.id));
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::EndPopup();
|
ImGui::EndPopup();
|
||||||
@ -446,11 +521,180 @@ void DrawSaveEditor(bool& open) {
|
|||||||
ImGui::PopID();
|
ImGui::PopID();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::EndTabItem();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ImGui::BeginTabItem("Flags")) {
|
// Draw a flag bitfield as an grid of checkboxes
|
||||||
|
void DrawFlagArray(const std::string& name, uint32_t& flags) {
|
||||||
|
ImGui::PushID(name.c_str());
|
||||||
|
for (int32_t flagIndex = 0; flagIndex < 32; flagIndex++) {
|
||||||
|
if ((flagIndex % 8) != 0) {
|
||||||
|
ImGui::SameLine();
|
||||||
|
}
|
||||||
|
ImGui::PushID(flagIndex);
|
||||||
|
uint32_t bitMask = 1 << flagIndex;
|
||||||
|
bool flag = (flags & bitMask) != 0;
|
||||||
|
if (ImGui::Checkbox("##check", &flag)) {
|
||||||
|
if (flag) {
|
||||||
|
flags |= bitMask;
|
||||||
|
} else {
|
||||||
|
flags &= ~bitMask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::PopID();
|
||||||
|
}
|
||||||
|
ImGui::PopID();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawFlagsTab() {
|
||||||
|
if (ImGui::TreeNode("Current Scene")) {
|
||||||
|
if (gGlobalCtx != nullptr) {
|
||||||
|
ActorContext* act = &gGlobalCtx->actorCtx;
|
||||||
|
|
||||||
|
DrawGroupWithBorder([&]() {
|
||||||
|
ImGui::Text("Switch");
|
||||||
|
InsertHelpHoverText("Permanently-saved switch flags");
|
||||||
|
DrawFlagArray("Switch", act->flags.swch);
|
||||||
|
});
|
||||||
|
|
||||||
|
ImGui::SameLine();
|
||||||
|
|
||||||
|
DrawGroupWithBorder([&]() {
|
||||||
|
ImGui::Text("Temp Switch");
|
||||||
|
InsertHelpHoverText("Temporary switch flags. Unset on scene transitions");
|
||||||
|
DrawFlagArray("Temp Switch", act->flags.tempSwch);
|
||||||
|
});
|
||||||
|
|
||||||
|
DrawGroupWithBorder([&]() {
|
||||||
|
ImGui::Text("Clear");
|
||||||
|
InsertHelpHoverText("Permanently-saved room-clear flags");
|
||||||
|
DrawFlagArray("Clear", act->flags.clear);
|
||||||
|
});
|
||||||
|
|
||||||
|
ImGui::SameLine();
|
||||||
|
|
||||||
|
DrawGroupWithBorder([&]() {
|
||||||
|
ImGui::Text("Temp Clear");
|
||||||
|
InsertHelpHoverText("Temporary room-clear flags. Unset on scene transitions");
|
||||||
|
DrawFlagArray("Temp Clear", act->flags.tempClear);
|
||||||
|
});
|
||||||
|
|
||||||
|
DrawGroupWithBorder([&]() {
|
||||||
|
ImGui::Text("Collect");
|
||||||
|
InsertHelpHoverText("Permanently-saved collect flags");
|
||||||
|
DrawFlagArray("Collect", act->flags.collect);
|
||||||
|
});
|
||||||
|
|
||||||
|
ImGui::SameLine();
|
||||||
|
|
||||||
|
DrawGroupWithBorder([&]() {
|
||||||
|
ImGui::Text("Temp Collect");
|
||||||
|
InsertHelpHoverText("Temporary collect flags. Unset on scene transitions");
|
||||||
|
DrawFlagArray("Temp Collect", act->flags.tempCollect);
|
||||||
|
});
|
||||||
|
|
||||||
|
DrawGroupWithBorder([&]() {
|
||||||
|
ImGui::Text("Chest");
|
||||||
|
InsertHelpHoverText("Permanently-saved chest flags");
|
||||||
|
DrawFlagArray("Chest", act->flags.chest);
|
||||||
|
});
|
||||||
|
|
||||||
|
ImGui::SameLine();
|
||||||
|
|
||||||
|
ImGui::BeginGroup();
|
||||||
|
|
||||||
|
if (ImGui::Button("Reload Flags")) {
|
||||||
|
act->flags.swch = gSaveContext.sceneFlags[gGlobalCtx->sceneNum].swch;
|
||||||
|
act->flags.clear = gSaveContext.sceneFlags[gGlobalCtx->sceneNum].clear;
|
||||||
|
act->flags.collect = gSaveContext.sceneFlags[gGlobalCtx->sceneNum].collect;
|
||||||
|
act->flags.chest = gSaveContext.sceneFlags[gGlobalCtx->sceneNum].chest;
|
||||||
|
}
|
||||||
|
SetLastItemHoverText("Load flags from saved scene flags. Normally happens on scene load");
|
||||||
|
|
||||||
|
if (ImGui::Button("Save Flags")) {
|
||||||
|
gSaveContext.sceneFlags[gGlobalCtx->sceneNum].swch = act->flags.swch;
|
||||||
|
gSaveContext.sceneFlags[gGlobalCtx->sceneNum].clear = act->flags.clear;
|
||||||
|
gSaveContext.sceneFlags[gGlobalCtx->sceneNum].collect = act->flags.collect;
|
||||||
|
gSaveContext.sceneFlags[gGlobalCtx->sceneNum].chest = act->flags.chest;
|
||||||
|
}
|
||||||
|
SetLastItemHoverText("Save current scene flags. Normally happens on scene exit");
|
||||||
|
|
||||||
|
ImGui::EndGroup();
|
||||||
|
} else {
|
||||||
|
ImGui::Text("Current game state does not have an active scene");
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::TreePop();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::TreeNode("Saved Scene Flags")) {
|
||||||
|
static uint32_t selectedSceneFlagMap = 0;
|
||||||
|
ImGui::Text("Map");
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::BeginCombo("##Map", SohUtils::GetSceneName(selectedSceneFlagMap).c_str())) {
|
||||||
|
for (int32_t sceneIndex = 0; sceneIndex < SCENE_ID_MAX; sceneIndex++) {
|
||||||
|
if (ImGui::Selectable(SohUtils::GetSceneName(sceneIndex).c_str())) {
|
||||||
|
selectedSceneFlagMap = sceneIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndCombo();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't show current scene button if there is no current scene
|
||||||
|
if (gGlobalCtx != nullptr) {
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button("Current")) {
|
||||||
|
selectedSceneFlagMap = gGlobalCtx->sceneNum;
|
||||||
|
}
|
||||||
|
SetLastItemHoverText("Open flags for current scene");
|
||||||
|
}
|
||||||
|
|
||||||
|
DrawGroupWithBorder([&]() {
|
||||||
|
ImGui::Text("Switch");
|
||||||
|
InsertHelpHoverText("Switch flags");
|
||||||
|
DrawFlagArray("Switch", gSaveContext.sceneFlags[selectedSceneFlagMap].swch);
|
||||||
|
});
|
||||||
|
|
||||||
|
ImGui::SameLine();
|
||||||
|
|
||||||
|
DrawGroupWithBorder([&]() {
|
||||||
|
ImGui::Text("Clear");
|
||||||
|
InsertHelpHoverText("Room-clear flags");
|
||||||
|
DrawFlagArray("Clear", gSaveContext.sceneFlags[selectedSceneFlagMap].clear);
|
||||||
|
});
|
||||||
|
|
||||||
|
DrawGroupWithBorder([&]() {
|
||||||
|
ImGui::Text("Collect");
|
||||||
|
InsertHelpHoverText("Collect flags");
|
||||||
|
DrawFlagArray("Collect", gSaveContext.sceneFlags[selectedSceneFlagMap].collect);
|
||||||
|
});
|
||||||
|
|
||||||
|
ImGui::SameLine();
|
||||||
|
|
||||||
|
DrawGroupWithBorder([&]() {
|
||||||
|
ImGui::Text("Chest");
|
||||||
|
InsertHelpHoverText("Chest flags");
|
||||||
|
DrawFlagArray("Chest", gSaveContext.sceneFlags[selectedSceneFlagMap].chest);
|
||||||
|
});
|
||||||
|
|
||||||
|
DrawGroupWithBorder([&]() {
|
||||||
|
ImGui::Text("Rooms");
|
||||||
|
InsertHelpHoverText("Flags for visted rooms");
|
||||||
|
DrawFlagArray("Rooms", gSaveContext.sceneFlags[selectedSceneFlagMap].rooms);
|
||||||
|
});
|
||||||
|
|
||||||
|
ImGui::SameLine();
|
||||||
|
|
||||||
|
DrawGroupWithBorder([&]() {
|
||||||
|
ImGui::Text("Floors");
|
||||||
|
InsertHelpHoverText("Flags for visted floors");
|
||||||
|
DrawFlagArray("Floors", gSaveContext.sceneFlags[selectedSceneFlagMap].floors);
|
||||||
|
});
|
||||||
|
|
||||||
|
ImGui::TreePop();
|
||||||
|
}
|
||||||
|
|
||||||
|
DrawGroupWithBorder([&]() {
|
||||||
static uint32_t selectedGsMap = 0;
|
static uint32_t selectedGsMap = 0;
|
||||||
ImGui::Text("Gold Skulltulas");
|
ImGui::Text("Gold Skulltulas");
|
||||||
ImGui::Text("Map");
|
ImGui::Text("Map");
|
||||||
@ -504,10 +748,368 @@ void DrawSaveEditor(bool& open) {
|
|||||||
}
|
}
|
||||||
gSaveContext.inventory.gsTokens = gsCount;
|
gSaveContext.inventory.gsTokens = gsCount;
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// TODO other flag types, like switch, clear, etc.
|
// Draws a combo that lets you choose and upgrade value from a drop-down of text values
|
||||||
// These flags interact with the actor context, so it's a bit more complicated
|
void DrawUpgrade(const std::string& categoryName, int32_t categoryId, const std::vector<std::string>& names) {
|
||||||
|
ImGui::Text(categoryName.c_str());
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::PushID(categoryName.c_str());
|
||||||
|
if (ImGui::BeginCombo("##upgrade", names[CUR_UPG_VALUE(categoryId)].c_str())) {
|
||||||
|
for (int32_t i = 0; i < names.size(); i++) {
|
||||||
|
if (ImGui::Selectable(names[i].c_str())) {
|
||||||
|
Inventory_ChangeUpgrade(categoryId, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndCombo();
|
||||||
|
}
|
||||||
|
ImGui::PopID();
|
||||||
|
SetLastItemHoverText(categoryName.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draws a combo that lets you choose and upgrade value from a popup grid of icons
|
||||||
|
void DrawUpgradeIcon(const std::string& categoryName, int32_t categoryId, const std::vector<uint8_t>& items) {
|
||||||
|
static const char* upgradePopupPicker = "upgradePopupPicker";
|
||||||
|
|
||||||
|
ImGui::PushID(categoryName.c_str());
|
||||||
|
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0));
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f);
|
||||||
|
uint8_t item = items[CUR_UPG_VALUE(categoryId)];
|
||||||
|
if (item != ITEM_NONE) {
|
||||||
|
const ItemMapEntry& slotEntry = itemMapping[item];
|
||||||
|
if (ImGui::ImageButton(SohImGui::GetTextureByName(slotEntry.name), ImVec2(32.0f, 32.0f), ImVec2(0, 0),
|
||||||
|
ImVec2(1, 1), 0)) {
|
||||||
|
ImGui::OpenPopup(upgradePopupPicker);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (ImGui::Button("##itemNone", ImVec2(32.0f, 32.0f))) {
|
||||||
|
ImGui::OpenPopup(upgradePopupPicker);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::PopStyleVar();
|
||||||
|
ImGui::PopStyleColor();
|
||||||
|
SetLastItemHoverText(categoryName.c_str());
|
||||||
|
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
|
||||||
|
if (ImGui::BeginPopup(upgradePopupPicker)) {
|
||||||
|
for (int32_t pickerIndex = 0; pickerIndex < items.size(); pickerIndex++) {
|
||||||
|
if ((pickerIndex % 8) != 0) {
|
||||||
|
ImGui::SameLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (items[pickerIndex] == ITEM_NONE) {
|
||||||
|
if (ImGui::Button("##upgradePopupPicker", ImVec2(32.0f, 32.0f))) {
|
||||||
|
Inventory_ChangeUpgrade(categoryId, pickerIndex);
|
||||||
|
ImGui::CloseCurrentPopup();
|
||||||
|
}
|
||||||
|
SetLastItemHoverText("None");
|
||||||
|
} else {
|
||||||
|
const ItemMapEntry& slotEntry = itemMapping[items[pickerIndex]];
|
||||||
|
if (ImGui::ImageButton(SohImGui::GetTextureByName(slotEntry.name), ImVec2(32.0f, 32.0f), ImVec2(0, 0),
|
||||||
|
ImVec2(1, 1), 0)) {
|
||||||
|
Inventory_ChangeUpgrade(categoryId, pickerIndex);
|
||||||
|
ImGui::CloseCurrentPopup();
|
||||||
|
}
|
||||||
|
SetLastItemHoverText(SohUtils::GetItemName(slotEntry.id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndPopup();
|
||||||
|
}
|
||||||
|
ImGui::PopStyleVar();
|
||||||
|
|
||||||
|
ImGui::PopID();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawEquipmentTab() {
|
||||||
|
const std::vector<uint8_t> equipmentValues = {
|
||||||
|
ITEM_SWORD_KOKIRI, ITEM_SWORD_MASTER, ITEM_SWORD_BGS, ITEM_SWORD_BROKEN,
|
||||||
|
ITEM_SHIELD_DEKU, ITEM_SHIELD_HYLIAN, ITEM_SHIELD_MIRROR, ITEM_NONE,
|
||||||
|
ITEM_TUNIC_KOKIRI, ITEM_TUNIC_GORON, ITEM_TUNIC_ZORA, ITEM_NONE,
|
||||||
|
ITEM_BOOTS_KOKIRI, ITEM_BOOTS_IRON, ITEM_BOOTS_HOVER, ITEM_NONE,
|
||||||
|
};
|
||||||
|
for (int32_t i = 0; i < equipmentValues.size(); i++) {
|
||||||
|
// Skip over unused 4th slots for shields, boots, and tunics
|
||||||
|
if (equipmentValues[i] == ITEM_NONE) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ((i % 4) != 0) {
|
||||||
|
ImGui::SameLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::PushID(i);
|
||||||
|
uint32_t bitMask = 1 << i;
|
||||||
|
bool hasEquip = (bitMask & gSaveContext.inventory.equipment) != 0;
|
||||||
|
const ItemMapEntry& entry = itemMapping[equipmentValues[i]];
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0));
|
||||||
|
if (ImGui::ImageButton(SohImGui::GetTextureByName(hasEquip ? entry.name : entry.nameFaded),
|
||||||
|
ImVec2(32.0f, 32.0f), ImVec2(0, 0), ImVec2(1, 1), 0)) {
|
||||||
|
if (hasEquip) {
|
||||||
|
gSaveContext.inventory.equipment &= ~bitMask;
|
||||||
|
} else {
|
||||||
|
gSaveContext.inventory.equipment |= bitMask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::PopStyleColor();
|
||||||
|
ImGui::PopID();
|
||||||
|
SetLastItemHoverText(SohUtils::GetItemName(entry.id));
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<uint8_t> bulletBagValues = {
|
||||||
|
ITEM_NONE,
|
||||||
|
ITEM_BULLET_BAG_30,
|
||||||
|
ITEM_BULLET_BAG_40,
|
||||||
|
ITEM_BULLET_BAG_50,
|
||||||
|
};
|
||||||
|
DrawUpgradeIcon("Bullet Bag", UPG_BULLET_BAG, bulletBagValues);
|
||||||
|
|
||||||
|
ImGui::SameLine();
|
||||||
|
|
||||||
|
const std::vector<uint8_t> quiverValues = {
|
||||||
|
ITEM_NONE,
|
||||||
|
ITEM_QUIVER_30,
|
||||||
|
ITEM_QUIVER_40,
|
||||||
|
ITEM_QUIVER_50,
|
||||||
|
};
|
||||||
|
DrawUpgradeIcon("Quiver", UPG_QUIVER, quiverValues);
|
||||||
|
|
||||||
|
ImGui::SameLine();
|
||||||
|
|
||||||
|
const std::vector<uint8_t> bombBagValues = {
|
||||||
|
ITEM_NONE,
|
||||||
|
ITEM_BOMB_BAG_20,
|
||||||
|
ITEM_BOMB_BAG_30,
|
||||||
|
ITEM_BOMB_BAG_40,
|
||||||
|
};
|
||||||
|
DrawUpgradeIcon("Bomb Bag", UPG_BOMB_BAG, bombBagValues);
|
||||||
|
|
||||||
|
ImGui::SameLine();
|
||||||
|
|
||||||
|
const std::vector<uint8_t> scaleValues = {
|
||||||
|
ITEM_NONE,
|
||||||
|
ITEM_SCALE_SILVER,
|
||||||
|
ITEM_SCALE_GOLDEN,
|
||||||
|
};
|
||||||
|
DrawUpgradeIcon("Scale", UPG_SCALE, scaleValues);
|
||||||
|
|
||||||
|
ImGui::SameLine();
|
||||||
|
|
||||||
|
const std::vector<uint8_t> strengthValues = {
|
||||||
|
ITEM_NONE,
|
||||||
|
ITEM_BRACELET,
|
||||||
|
ITEM_GAUNTLETS_SILVER,
|
||||||
|
ITEM_GAUNTLETS_GOLD,
|
||||||
|
};
|
||||||
|
DrawUpgradeIcon("Strength", UPG_STRENGTH, strengthValues);
|
||||||
|
|
||||||
|
// There is no icon for child wallet, so default to a text list
|
||||||
|
const std::vector<std::string> walletNames = {
|
||||||
|
"Child (99)",
|
||||||
|
"Adult (200)",
|
||||||
|
"Giant (500)",
|
||||||
|
};
|
||||||
|
DrawUpgrade("Wallet", UPG_WALLET, walletNames);
|
||||||
|
|
||||||
|
const std::vector<std::string> stickNames = {
|
||||||
|
"None",
|
||||||
|
"10",
|
||||||
|
"20",
|
||||||
|
"30",
|
||||||
|
};
|
||||||
|
DrawUpgrade("Sticks", UPG_STICKS, stickNames);
|
||||||
|
|
||||||
|
const std::vector<std::string> nutNames = {
|
||||||
|
"None",
|
||||||
|
"20",
|
||||||
|
"30",
|
||||||
|
"40",
|
||||||
|
};
|
||||||
|
DrawUpgrade("Deku Nuts", UPG_NUTS, nutNames);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draws a toggleable icon for a quest item that is faded when disabled
|
||||||
|
void DrawQuestItemButton(uint32_t item) {
|
||||||
|
const QuestMapEntry& entry = questMapping[item];
|
||||||
|
uint32_t bitMask = 1 << entry.id;
|
||||||
|
bool hasQuestItem = (bitMask & gSaveContext.inventory.questItems) != 0;
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0));
|
||||||
|
if (ImGui::ImageButton(SohImGui::GetTextureByName(hasQuestItem ? entry.name : entry.nameFaded),
|
||||||
|
ImVec2(32.0f, 32.0f), ImVec2(0, 0), ImVec2(1, 1), 0)) {
|
||||||
|
if (hasQuestItem) {
|
||||||
|
gSaveContext.inventory.questItems &= ~bitMask;
|
||||||
|
} else {
|
||||||
|
gSaveContext.inventory.questItems |= bitMask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::PopStyleColor();
|
||||||
|
SetLastItemHoverText(SohUtils::GetQuestItemName(entry.id));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draws a toggleable icon for a dungeon item that is faded when disabled
|
||||||
|
void DrawDungeonItemButton(uint32_t item, uint32_t scene) {
|
||||||
|
const ItemMapEntry& entry = itemMapping[item];
|
||||||
|
uint32_t bitMask = 1 << (entry.id - ITEM_KEY_BOSS); // Bitset starts at ITEM_KEY_BOSS == 0. the rest are sequential
|
||||||
|
bool hasItem = (bitMask & gSaveContext.inventory.dungeonItems[scene]) != 0;
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0));
|
||||||
|
if (ImGui::ImageButton(SohImGui::GetTextureByName(hasItem ? entry.name : entry.nameFaded),
|
||||||
|
ImVec2(32.0f, 32.0f), ImVec2(0, 0), ImVec2(1, 1), 0)) {
|
||||||
|
if (hasItem) {
|
||||||
|
gSaveContext.inventory.dungeonItems[scene] &= ~bitMask;
|
||||||
|
} else {
|
||||||
|
gSaveContext.inventory.dungeonItems[scene] |= bitMask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::PopStyleColor();
|
||||||
|
SetLastItemHoverText(SohUtils::GetItemName(entry.id));
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawQuestStatusTab() {
|
||||||
|
ImGui::PushItemWidth(ImGui::GetFontSize() * 6);
|
||||||
|
|
||||||
|
for (int32_t i = QUEST_MEDALLION_FOREST; i < QUEST_MEDALLION_LIGHT + 1; i++) {
|
||||||
|
if (i != QUEST_MEDALLION_FOREST) {
|
||||||
|
ImGui::SameLine();
|
||||||
|
}
|
||||||
|
DrawQuestItemButton(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int32_t i = QUEST_KOKIRI_EMERALD; i < QUEST_ZORA_SAPPHIRE + 1; i++) {
|
||||||
|
if (i != QUEST_KOKIRI_EMERALD) {
|
||||||
|
ImGui::SameLine();
|
||||||
|
}
|
||||||
|
DrawQuestItemButton(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Put Stone of Agony and Gerudo Card on the same line with a little space between them
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::Dummy(ImVec2(20, 0));
|
||||||
|
|
||||||
|
ImGui::SameLine();
|
||||||
|
DrawQuestItemButton(QUEST_STONE_OF_AGONY);
|
||||||
|
|
||||||
|
ImGui::SameLine();
|
||||||
|
DrawQuestItemButton(QUEST_GERUDO_CARD);
|
||||||
|
|
||||||
|
for (const SongMapEntry& entry : songMapping) {
|
||||||
|
if ((entry.id != QUEST_SONG_MINUET) && (entry.id != QUEST_SONG_LULLABY)) {
|
||||||
|
ImGui::SameLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t bitMask = 1 << entry.id;
|
||||||
|
bool hasQuestItem = (bitMask & gSaveContext.inventory.questItems) != 0;
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0));
|
||||||
|
if (ImGui::ImageButton(SohImGui::GetTextureByName(hasQuestItem ? entry.name : entry.nameFaded),
|
||||||
|
ImVec2(16.0f, 24.0f), ImVec2(0, 0), ImVec2(1, 1), 0)) {
|
||||||
|
if (hasQuestItem) {
|
||||||
|
gSaveContext.inventory.questItems &= ~bitMask;
|
||||||
|
} else {
|
||||||
|
gSaveContext.inventory.questItems |= bitMask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::PopStyleColor();
|
||||||
|
SetLastItemHoverText(SohUtils::GetQuestItemName(entry.id));
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::InputScalar("GS Count", ImGuiDataType_S16, &gSaveContext.inventory.gsTokens);
|
||||||
|
InsertHelpHoverText("Number of gold skulltula tokens aquired");
|
||||||
|
|
||||||
|
uint32_t bitMask = 1 << QUEST_SKULL_TOKEN;
|
||||||
|
bool gsUnlocked = (bitMask & gSaveContext.inventory.questItems) != 0;
|
||||||
|
if (ImGui::Checkbox("GS unlocked", &gsUnlocked)) {
|
||||||
|
if (gsUnlocked) {
|
||||||
|
gSaveContext.inventory.questItems |= bitMask;
|
||||||
|
} else {
|
||||||
|
gSaveContext.inventory.questItems &= ~bitMask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
InsertHelpHoverText("If unlocked, enables showing the gold skulltula count in the quest status menu");
|
||||||
|
|
||||||
|
int32_t pohCount = (gSaveContext.inventory.questItems & 0xF0000000) >> 28;
|
||||||
|
if (ImGui::BeginCombo("PoH count", std::to_string(pohCount).c_str())) {
|
||||||
|
for (int32_t i = 0; i < 4; i++) {
|
||||||
|
if (ImGui::Selectable(std::to_string(i).c_str(), pohCount == i)) {
|
||||||
|
gSaveContext.inventory.questItems &= ~0xF0000000;
|
||||||
|
gSaveContext.inventory.questItems |= (i << 28);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::EndCombo();
|
||||||
|
}
|
||||||
|
InsertHelpHoverText("The number of pieces of heart acquired towards the next heart container");
|
||||||
|
|
||||||
|
DrawGroupWithBorder([&]() {
|
||||||
|
ImGui::Text("Dungeon Items");
|
||||||
|
|
||||||
|
static int32_t dungeonItemsScene = SCENE_YDAN;
|
||||||
|
ImGui::PushItemWidth(-ImGui::GetWindowWidth() * 0.35f);
|
||||||
|
if (ImGui::BeginCombo("##DungeonSelect", SohUtils::GetSceneName(dungeonItemsScene).c_str())) {
|
||||||
|
for (int32_t dungeonIndex = SCENE_YDAN; dungeonIndex < SCENE_BDAN_BOSS + 1; dungeonIndex++) {
|
||||||
|
if (ImGui::Selectable(SohUtils::GetSceneName(dungeonIndex).c_str(),
|
||||||
|
dungeonIndex == dungeonItemsScene)) {
|
||||||
|
dungeonItemsScene = dungeonIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndCombo();
|
||||||
|
}
|
||||||
|
ImGui::PopItemWidth();
|
||||||
|
|
||||||
|
DrawDungeonItemButton(ITEM_KEY_BOSS, dungeonItemsScene);
|
||||||
|
ImGui::SameLine();
|
||||||
|
DrawDungeonItemButton(ITEM_COMPASS, dungeonItemsScene);
|
||||||
|
ImGui::SameLine();
|
||||||
|
DrawDungeonItemButton(ITEM_DUNGEON_MAP, dungeonItemsScene);
|
||||||
|
|
||||||
|
if (dungeonItemsScene != SCENE_BDAN_BOSS) {
|
||||||
|
float lineHeight = ImGui::GetTextLineHeightWithSpacing();
|
||||||
|
ImGui::Image(SohImGui::GetTextureByName(itemMapping[ITEM_KEY_SMALL].name), ImVec2(lineHeight, lineHeight));
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::InputScalar("##Keys", ImGuiDataType_S8, gSaveContext.inventory.dungeonKeys + dungeonItemsScene);
|
||||||
|
} else {
|
||||||
|
// dungeonItems is size 20 but dungeonKeys is size 19, so there are no keys for the last scene (Barinade's Lair)
|
||||||
|
ImGui::Text("Barinade's Lair does not have small keys");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ImGui::PopItemWidth();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawSaveEditor(bool& open) {
|
||||||
|
if (!open) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver);
|
||||||
|
if (!ImGui::Begin("Save Editor", &open)) {
|
||||||
|
ImGui::End();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::BeginTabBar("SaveContextTabBar", ImGuiTabBarFlags_NoCloseWithMiddleMouseButton)) {
|
||||||
|
if (ImGui::BeginTabItem("Info")) {
|
||||||
|
DrawInfoTab();
|
||||||
|
ImGui::EndTabItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::BeginTabItem("Inventory")) {
|
||||||
|
DrawInventoryTab();
|
||||||
|
ImGui::EndTabItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::BeginTabItem("Flags")) {
|
||||||
|
DrawFlagsTab();
|
||||||
|
ImGui::EndTabItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::BeginTabItem("Equipment")) {
|
||||||
|
DrawEquipmentTab();
|
||||||
|
ImGui::EndTabItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::BeginTabItem("Quest Status")) {
|
||||||
|
DrawQuestStatusTab();
|
||||||
ImGui::EndTabItem();
|
ImGui::EndTabItem();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -523,5 +1125,16 @@ void InitSaveEditor() {
|
|||||||
// Load item icons into ImGui
|
// Load item icons into ImGui
|
||||||
for (const auto& entry : itemMapping) {
|
for (const auto& entry : itemMapping) {
|
||||||
SohImGui::LoadResource(entry.second.name, entry.second.texturePath);
|
SohImGui::LoadResource(entry.second.name, entry.second.texturePath);
|
||||||
|
SohImGui::LoadResource(entry.second.nameFaded, entry.second.texturePath, ImVec4(1, 1, 1, 0.3f));
|
||||||
|
}
|
||||||
|
for (const auto& entry : questMapping) {
|
||||||
|
SohImGui::LoadResource(entry.second.name, entry.second.texturePath);
|
||||||
|
SohImGui::LoadResource(entry.second.nameFaded, entry.second.texturePath, ImVec4(1, 1, 1, 0.3f));
|
||||||
|
}
|
||||||
|
for (const auto& entry : songMapping) {
|
||||||
|
SohImGui::LoadResource(entry.name, gSongNoteTex, entry.color);
|
||||||
|
ImVec4 fadedCol = entry.color;
|
||||||
|
fadedCol.w = 0.3f;
|
||||||
|
SohImGui::LoadResource(entry.nameFaded, gSongNoteTex, fadedCol);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
314
soh/soh/util.cpp
Normal file
314
soh/soh/util.cpp
Normal file
@ -0,0 +1,314 @@
|
|||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
std::vector<std::string> sceneNames = {
|
||||||
|
"Inside the Deku Tree",
|
||||||
|
"Dodongo's Cavern",
|
||||||
|
"Inside Jabu-Jabu's Belly",
|
||||||
|
"Forest Temple",
|
||||||
|
"Fire Temple",
|
||||||
|
"Water Temple",
|
||||||
|
"Spirit Temple",
|
||||||
|
"Shadow Temple",
|
||||||
|
"Bottom of the Well",
|
||||||
|
"Ice Cavern",
|
||||||
|
"Ganon's Tower",
|
||||||
|
"Gerudo Training Ground",
|
||||||
|
"Thieves' Hideout",
|
||||||
|
"Inside Ganon's Castle",
|
||||||
|
"Ganon's Tower (Collapsing)",
|
||||||
|
"Inside Ganon's Castle (Collapsing)",
|
||||||
|
"Treasure Box Shop",
|
||||||
|
"Gohma's Lair",
|
||||||
|
"King Dodongo's Lair",
|
||||||
|
"Barinade's Lair",
|
||||||
|
"Phantom Ganon's Lair",
|
||||||
|
"Volvagia's Lair",
|
||||||
|
"Morpha's Lair",
|
||||||
|
"Twinrova's Lair & Nabooru's Mini-Boss Room",
|
||||||
|
"Bongo Bongo's Lair",
|
||||||
|
"Ganondorf's Lair",
|
||||||
|
"Tower Collapse Exterior",
|
||||||
|
"Market Entrance (Child - Day)",
|
||||||
|
"Market Entrance (Child - Night)",
|
||||||
|
"Market Entrance (Ruins)",
|
||||||
|
"Back Alley (Child - Day)",
|
||||||
|
"Back Alley (Child - Night)",
|
||||||
|
"Market (Child - Day)",
|
||||||
|
"Market (Child - Night)",
|
||||||
|
"Market (Ruins)",
|
||||||
|
"Temple of Time Exterior (Child - Day)",
|
||||||
|
"Temple of Time Exterior (Child - Night)",
|
||||||
|
"Temple of Time Exterior (Ruins)",
|
||||||
|
"Know-It-All Brothers' House",
|
||||||
|
"House of Twins",
|
||||||
|
"Mido's House",
|
||||||
|
"Saria's House",
|
||||||
|
"Carpenter Boss's House",
|
||||||
|
"Back Alley House (Man in Green)",
|
||||||
|
"Bazaar",
|
||||||
|
"Kokiri Shop",
|
||||||
|
"Goron Shop",
|
||||||
|
"Zora Shop",
|
||||||
|
"Kakariko Potion Shop",
|
||||||
|
"Market Potion Shop",
|
||||||
|
"Bombchu Shop",
|
||||||
|
"Happy Mask Shop",
|
||||||
|
"Link's House",
|
||||||
|
"Back Alley House (Dog Lady)",
|
||||||
|
"Stable",
|
||||||
|
"Impa's House",
|
||||||
|
"Lakeside Laboratory",
|
||||||
|
"Carpenters' Tent",
|
||||||
|
"Gravekeeper's Hut",
|
||||||
|
"Great Fairy's Fountain (Upgrades)",
|
||||||
|
"Fairy's Fountain",
|
||||||
|
"Great Fairy's Fountain (Spells)",
|
||||||
|
"Grottos",
|
||||||
|
"Grave (Redead)",
|
||||||
|
"Grave (Fairy's Fountain)",
|
||||||
|
"Royal Family's Tomb",
|
||||||
|
"Shooting Gallery",
|
||||||
|
"Temple of Time",
|
||||||
|
"Chamber of the Sages",
|
||||||
|
"Castle Hedge Maze (Day)",
|
||||||
|
"Castle Hedge Maze (Night)",
|
||||||
|
"Cutscene Map",
|
||||||
|
"Dampé's Grave & Windmill",
|
||||||
|
"Fishing Pond",
|
||||||
|
"Castle Courtyard",
|
||||||
|
"Bombchu Bowling Alley",
|
||||||
|
"Ranch House & Silo",
|
||||||
|
"Guard House",
|
||||||
|
"Granny's Potion Shop",
|
||||||
|
"Ganon's Tower Collapse & Battle Arena",
|
||||||
|
"House of Skulltula",
|
||||||
|
"Spot 00 - Hyrule Field",
|
||||||
|
"Spot 01 - Kakariko Village",
|
||||||
|
"Spot 02 - Graveyard",
|
||||||
|
"Spot 03 - Zora's River",
|
||||||
|
"Spot 04 - Kokiri Forest",
|
||||||
|
"Spot 05 - Sacred Forest Meadow",
|
||||||
|
"Spot 06 - Lake Hylia",
|
||||||
|
"Spot 07 - Zora's Domain",
|
||||||
|
"Spot 08 - Zora's Fountain",
|
||||||
|
"Spot 09 - Gerudo Valley",
|
||||||
|
"Spot 10 - Lost Woods",
|
||||||
|
"Spot 11 - Desert Colossus",
|
||||||
|
"Spot 12 - Gerudo's Fortress",
|
||||||
|
"Spot 13 - Haunted Wasteland",
|
||||||
|
"Spot 15 - Hyrule Castle",
|
||||||
|
"Spot 16 - Death Mountain Trail",
|
||||||
|
"Spot 17 - Death Mountain Crater",
|
||||||
|
"Spot 18 - Goron City",
|
||||||
|
"Spot 20 - Lon Lon Ranch",
|
||||||
|
"Ganon's Castle Exterior",
|
||||||
|
"Jungle Gym",
|
||||||
|
"Ganondorf Test Room",
|
||||||
|
"Depth Test",
|
||||||
|
"Stalfos Mini-Boss Room",
|
||||||
|
"Stalfos Boss Room",
|
||||||
|
"Sutaru",
|
||||||
|
"Castle Hedge Maze (Early)",
|
||||||
|
"Sasa Test",
|
||||||
|
"Treasure Chest Room",
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<std::string> itemNames = {
|
||||||
|
"Deku Stick",
|
||||||
|
"Deku Nut",
|
||||||
|
"Bomb",
|
||||||
|
"Fairy Bow",
|
||||||
|
"Fire Arrow",
|
||||||
|
"Din's Fire",
|
||||||
|
"Fairy Slingshot",
|
||||||
|
"Fairy Ocarina",
|
||||||
|
"Ocarina of Time",
|
||||||
|
"Bombchu",
|
||||||
|
"Hookshot",
|
||||||
|
"Longshot",
|
||||||
|
"Ice Arrow",
|
||||||
|
"Farore's Wind",
|
||||||
|
"Boomerang",
|
||||||
|
"Lens of Truth",
|
||||||
|
"Magic Bean",
|
||||||
|
"Megaton Hammer",
|
||||||
|
"Light Arrow",
|
||||||
|
"Nayru's Love",
|
||||||
|
"Empty Bottle",
|
||||||
|
"Red Potion",
|
||||||
|
"Green Potion",
|
||||||
|
"Blue Potion",
|
||||||
|
"Bottled Fairy",
|
||||||
|
"Fish",
|
||||||
|
"Lon Lon Milk & Bottle",
|
||||||
|
"Ruto's Letter",
|
||||||
|
"Blue Fire",
|
||||||
|
"Bug",
|
||||||
|
"Big Poe",
|
||||||
|
"Lon Lon Milk (Half)",
|
||||||
|
"Poe",
|
||||||
|
"Weird Egg",
|
||||||
|
"Chicken",
|
||||||
|
"Zelda's Letter",
|
||||||
|
"Keaton Mask",
|
||||||
|
"Skull Mask",
|
||||||
|
"Spooky Mask",
|
||||||
|
"Bunny Hood",
|
||||||
|
"Goron Mask",
|
||||||
|
"Zora Mask",
|
||||||
|
"Gerudo Mask",
|
||||||
|
"Mask of Truth",
|
||||||
|
"SOLD OUT",
|
||||||
|
"Pocket Egg",
|
||||||
|
"Pocket Cucco",
|
||||||
|
"Cojiro",
|
||||||
|
"Odd Mushroom",
|
||||||
|
"Odd Potion",
|
||||||
|
"Poacher's Saw",
|
||||||
|
"Goron's Sword (Broken)",
|
||||||
|
"Prescription",
|
||||||
|
"Eyeball Frog",
|
||||||
|
"Eye Drops",
|
||||||
|
"Claim Check",
|
||||||
|
"Fairy Bow & Fire Arrow",
|
||||||
|
"Fairy Bow & Ice Arrow",
|
||||||
|
"Fairy Bow & Light Arrow",
|
||||||
|
"Kokiri Sword",
|
||||||
|
"Master Sword",
|
||||||
|
"Giant's Knife & Biggoron's Sword",
|
||||||
|
"Deku Shield",
|
||||||
|
"Hylian Shield",
|
||||||
|
"Mirror Shield",
|
||||||
|
"Kokiri Tunic",
|
||||||
|
"Goron Tunic",
|
||||||
|
"Zora Tunic",
|
||||||
|
"Kokiri Boots",
|
||||||
|
"Iron Boots",
|
||||||
|
"Hover Boots",
|
||||||
|
"Bullet Bag (30)",
|
||||||
|
"Bullet Bag (40)",
|
||||||
|
"Bullet Bag (50)",
|
||||||
|
"Quiver (30)",
|
||||||
|
"Big Quiver (40)",
|
||||||
|
"Biggest Quiver (50)",
|
||||||
|
"Bomb Bag (20)",
|
||||||
|
"Big Bomb Bag (30)",
|
||||||
|
"Biggest Bomb Bag (40)",
|
||||||
|
"Goron's Bracelet",
|
||||||
|
"Silver Gauntlets",
|
||||||
|
"Golden Gauntlets",
|
||||||
|
"Silver Scale",
|
||||||
|
"Golden Scale",
|
||||||
|
"Giant's Knife (Broken)",
|
||||||
|
"Adult's Wallet",
|
||||||
|
"Giant's Wallet",
|
||||||
|
"Deku Seeds (5)",
|
||||||
|
"Fishing Pole",
|
||||||
|
"Minuet of Forest",
|
||||||
|
"Bolero of Fire",
|
||||||
|
"Serenade of Water",
|
||||||
|
"Requiem of Spirit",
|
||||||
|
"Nocturne of Shadow",
|
||||||
|
"Prelude of Light",
|
||||||
|
"Zelda's Lullaby",
|
||||||
|
"Epona's Song",
|
||||||
|
"Saria's Song",
|
||||||
|
"Sun's Song",
|
||||||
|
"Song of Time",
|
||||||
|
"Song of Storms",
|
||||||
|
"Forest Medallion",
|
||||||
|
"Fire Medallion",
|
||||||
|
"Water Medallion",
|
||||||
|
"Spirit Medallion",
|
||||||
|
"Shadow Medallion",
|
||||||
|
"Light Medallion",
|
||||||
|
"Kokiri's Emerald",
|
||||||
|
"Goron's Ruby",
|
||||||
|
"Zora's Sapphire",
|
||||||
|
"Stone of Agony",
|
||||||
|
"Gerudo's Card",
|
||||||
|
"Gold Skulltula Token",
|
||||||
|
"Heart Container",
|
||||||
|
"Piece of Heart [?]",
|
||||||
|
"Big Key",
|
||||||
|
"Compass",
|
||||||
|
"Dungeon Map",
|
||||||
|
"Small Key",
|
||||||
|
"Small Magic Jar",
|
||||||
|
"Large Magic Jar",
|
||||||
|
"Piece of Heart",
|
||||||
|
"[Removed]",
|
||||||
|
"[Removed]",
|
||||||
|
"[Removed]",
|
||||||
|
"[Removed]",
|
||||||
|
"[Removed]",
|
||||||
|
"[Removed]",
|
||||||
|
"[Removed]",
|
||||||
|
"Lon Lon Milk",
|
||||||
|
"Recovery Heart",
|
||||||
|
"Green Rupee",
|
||||||
|
"Blue Rupee",
|
||||||
|
"Red Rupee",
|
||||||
|
"Purple Rupee",
|
||||||
|
"Huge Rupee",
|
||||||
|
"[Removed]",
|
||||||
|
"Deku Sticks (5)",
|
||||||
|
"Deku Sticks (10)",
|
||||||
|
"Deku Nuts (5)",
|
||||||
|
"Deku Nuts (10)",
|
||||||
|
"Bombs (5)",
|
||||||
|
"Bombs (10)",
|
||||||
|
"Bombs (20)",
|
||||||
|
"Bombs (30)",
|
||||||
|
"Arrows (Small)",
|
||||||
|
"Arrows (Medium)",
|
||||||
|
"Arrows (Large)",
|
||||||
|
"Deku Seeds (30)",
|
||||||
|
"Bombchu (5)",
|
||||||
|
"Bombchu (20)",
|
||||||
|
"Deku Stick Upgrade (20)",
|
||||||
|
"Deku Stick Upgrade (30)",
|
||||||
|
"Deku Nut Upgrade (30)",
|
||||||
|
"Deku Nut Upgrade (40)",
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<std::string> questItemNames = {
|
||||||
|
"Forest Medallion",
|
||||||
|
"Fire Medallion",
|
||||||
|
"Water Medallion",
|
||||||
|
"Spirit Medallion",
|
||||||
|
"Shadow Medallion",
|
||||||
|
"Light Medallion",
|
||||||
|
"Minuet of Forest",
|
||||||
|
"Bolero of Fire",
|
||||||
|
"Serenade of Water",
|
||||||
|
"Requiem of Spirit",
|
||||||
|
"Nocturne of Shadow",
|
||||||
|
"Prelude of Light",
|
||||||
|
"Zelda's Lullaby",
|
||||||
|
"Epona's Song",
|
||||||
|
"Saria's Song",
|
||||||
|
"Sun's Song",
|
||||||
|
"Song of Time",
|
||||||
|
"Song of Storms",
|
||||||
|
"Kokiri's Emerald",
|
||||||
|
"Goron's Ruby",
|
||||||
|
"Zora's Sapphire",
|
||||||
|
"Stone of Agony",
|
||||||
|
"Gerudo's Card",
|
||||||
|
"Gold Skulltula Token",
|
||||||
|
};
|
||||||
|
|
||||||
|
const std::string& SohUtils::GetSceneName(int32_t scene) {
|
||||||
|
return sceneNames[scene];
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& SohUtils::GetItemName(int32_t item) {
|
||||||
|
return itemNames[item];
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& SohUtils::GetQuestItemName(int32_t item) {
|
||||||
|
return questItemNames[item];
|
||||||
|
}
|
11
soh/soh/util.h
Normal file
11
soh/soh/util.h
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <string>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
namespace SohUtils {
|
||||||
|
const std::string& GetSceneName(int32_t scene);
|
||||||
|
|
||||||
|
const std::string& GetItemName(int32_t item);
|
||||||
|
|
||||||
|
const std::string& GetQuestItemName(int32_t item);
|
||||||
|
} // namespace SohUtils
|
Loading…
Reference in New Issue
Block a user