From 68df2391978f808b4ce191b4493ef5c99ec4f8f8 Mon Sep 17 00:00:00 2001 From: TakaRikka Date: Sun, 22 Mar 2026 00:20:37 -0700 Subject: [PATCH 1/7] enable cs fades again --- src/m_Do/m_Do_graphic.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/m_Do/m_Do_graphic.cpp b/src/m_Do/m_Do_graphic.cpp index 72180b3c40..1264e54dd8 100644 --- a/src/m_Do/m_Do_graphic.cpp +++ b/src/m_Do/m_Do_graphic.cpp @@ -442,6 +442,14 @@ void darwFilter(GXColor matColor) { GXLoadPosMtxImm(cMtx_getIdentity(), GX_PNMTX0); GXSetChanMatColor(GX_COLOR0A0, matColor); GXSetCurrentMtx(0); + +#if TARGET_PC + f32 width = mDoGph_gInf_c::getWidth(); + f32 height = mDoGph_gInf_c::getHeight(); + GXSetViewport(0.0f, 0.0f, width, height, 0.0f, 1.0f); + GXSetScissor(0, 0, width, height); +#endif + GXClearVtxDesc(); GXSetVtxDesc(GX_VA_POS, GX_DIRECT); GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_CLR_RGBA, GX_RGB8, 0); @@ -478,7 +486,7 @@ void mDoGph_gInf_c::calcFade() { } if (mFadeColor.a != 0) { - //darwFilter(mFadeColor); + darwFilter(mFadeColor); } } From 364400d56f68f7029a572cdbeb930e3d8721732d Mon Sep 17 00:00:00 2001 From: TakaRikka Date: Mon, 23 Mar 2026 05:01:42 -0700 Subject: [PATCH 2/7] save editor wip --- files.cmake | 1 + include/d/d_save.h | 30 -- src/dusk/imgui/ImGuiConsole.cpp | 86 +++ src/dusk/imgui/ImGuiConsole.hpp | 2 + src/dusk/imgui/ImGuiMenuGame.cpp | 85 --- src/dusk/imgui/ImGuiMenuTools.cpp | 5 + src/dusk/imgui/ImGuiMenuTools.hpp | 4 + src/dusk/imgui/ImGuiSaveEditor.cpp | 816 +++++++++++++++++++++++++++++ src/dusk/imgui/ImGuiSaveEditor.hpp | 26 + 9 files changed, 940 insertions(+), 115 deletions(-) create mode 100644 src/dusk/imgui/ImGuiSaveEditor.cpp create mode 100644 src/dusk/imgui/ImGuiSaveEditor.hpp diff --git a/files.cmake b/files.cmake index cae7f66aed..d57eaec490 100644 --- a/files.cmake +++ b/files.cmake @@ -1348,6 +1348,7 @@ set(DUSK_FILES src/dusk/imgui/ImGuiControllerOverlay.cpp src/dusk/imgui/ImGuiStubLog.cpp src/dusk/imgui/ImGuiMapLoader.cpp + src/dusk/imgui/ImGuiSaveEditor.cpp src/dusk/offset_ptr.cpp src/dusk/OSContext.cpp src/dusk/OSThread.cpp diff --git a/include/d/d_save.h b/include/d/d_save.h index 4511bc47e8..b0682e7ed6 100644 --- a/include/d/d_save.h +++ b/include/d/d_save.h @@ -163,7 +163,6 @@ public: u8 getTransformStatus() const { return mTransformStatus; } void setTransformStatus(u8 i_status) { mTransformStatus = i_status; } -private: /* 0x00 */ BE(u16) mMaxLife; /* 0x02 */ BE(u16) mLife; /* 0x04 */ BE(u16) mRupee; @@ -201,7 +200,6 @@ public: u16 getDate() const { return mDate; } void setDate(u16 i_date) { mDate = i_date; } -private: /* 0x00 */ BE(OSTime) mDateIpl; /* 0x08 */ u8 mTransformLevelFlag; /* 0x09 */ u8 mDarkClearLevelFlag; @@ -228,7 +226,6 @@ public: const char* getStageName() const { return mName; } s8 getRoomNo() const { return mRoomNo; } -private: #if TARGET_PC /* 0x00 */ BE(Vec) mPos; #else @@ -248,7 +245,6 @@ public: u8 getPlayerStatus() const { return mPlayerStatus; } s8 getRoomNo() const { return mRoomNo; } -private: /* 0x00 */ char mName[8]; /* 0x08 */ u8 mPlayerStatus; /* 0x09 */ s8 mRoomNo; @@ -277,8 +273,6 @@ public: void offFieldDataExistFlag() { mFieldDataExistFlag = false; } void onFieldDataExistFlag() { mFieldDataExistFlag = true; } - -private: #if TARGET_PC /* 0x00 */ BE(Vec) mPos; #else @@ -312,7 +306,6 @@ public: void setWarpAcceptStage(s8 accept) { mWarpAcceptStage = accept; } void resetWarpAcceptStage() { mWarpAcceptStage = -1; } -private: #if TARGET_PC /* 0x00 */ BE(Vec) mPos; #else @@ -356,7 +349,6 @@ public: static const int BOMB_BAG_MAX = 3; static const int BOTTLE_MAX = 4; -private: /* 0x00 */ u8 mItems[24]; /* 0x18 */ u8 mItemSlots[24]; }; // Size: 0x30 @@ -368,7 +360,6 @@ public: void offFirstBit(u8 i_itemNo); int isFirstBit(u8 i_itemNo) const; -private: /* 0x0 */ BE(u32) mItemFlags[8]; }; // Size: 0x20 @@ -386,7 +377,6 @@ public: u8 getPachinkoNum() const { return mPachinkoNum; } void setPachinkoNum(u8 i_num) { mPachinkoNum = i_num; } -private: /* 0x0 */ u8 mArrowNum; /* 0x1 */ u8 mBombNum[3]; /* 0x4 */ u8 mBottleNum[4]; @@ -403,7 +393,6 @@ public: u8 getArrowNum() const { return mItemMax[ARROW_MAX]; } void setArrowNum(u8 i_maxNum) { mItemMax[ARROW_MAX] = i_maxNum; } -private: /* 0x0 */ u8 mItemMax[8]; }; // Size: 0x8 @@ -429,7 +418,6 @@ public: } } -private: /* 0x0 */ u8 mItem[8]; /* 0x8 */ u8 unk8; /* 0x9 */ u8 mCrystal; @@ -443,7 +431,6 @@ class dSv_player_wolf_c { public: void init(); -private: /* 0x0 */ u8 unk0[3]; /* 0x3 */ u8 unk3; }; // Size: 0x4 @@ -457,7 +444,6 @@ public: void offLightDropGetFlag(u8 i_nowLevel); BOOL isLightDropGetFlag(u8 i_nowLevel) const; -private: /* 0x0 */ u8 mLightDropNum[4]; /* 0x4 */ u8 mLightDropGetFlag; /* 0x5 */ u8 unk5[3]; @@ -473,7 +459,6 @@ public: u8 getGetNumber(int i_no) { return mGetNumber[i_no]; } void setGetNumber(int i_no, u8 i_value) { mGetNumber[i_no] = i_value; } -private: /* 0x00 */ BE(u32) mLetterGetFlags[2]; /* 0x08 */ BE(u32) mLetterReadFlags[2]; /* 0x10 */ u8 mGetNumber[64]; @@ -487,7 +472,6 @@ public: u8 getMaxSize(int i_sizeIndex) const { return mMaxSize[i_sizeIndex]; } void setMaxSize(int i_sizeIndex, u8 i_size) { mMaxSize[i_sizeIndex] = i_size; } -private: /* 0x00 */ BE(u16) mFishCount[16]; /* 0x20 */ u8 mMaxSize[16]; }; // Size: 0x34 @@ -508,7 +492,6 @@ public: void setHorseName(const char* i_name) { strcpy(mHorseName, i_name); } u8 getClearCount() const { return mClearCount; } -private: /* 0x00 */ BE(u64) unk0; /* 0x08 */ BE(s64) mTotalTime; /* 0x10 */ BE(u16) unk16; @@ -555,7 +538,6 @@ public: LANGUAGE_ITALIAN, }; -private: /* 0x0 */ u8 mRuby; /* 0x1 */ u8 mSoundMode; /* 0x2 */ u8 mAttentionType; // Lock-On Type; 0 : hold, 1 : switch @@ -682,7 +664,6 @@ public: void offStageBossEnemy2() { offDungeonItem(STAGE_BOSS_ENEMY_2); } s32 isStageBossEnemy2() const { return isDungeonItem(STAGE_BOSS_ENEMY_2); } -private: /* 0x00 */ BE(u32) mTbox[2]; /* 0x08 */ BE(u32) mSwitch[4]; /* 0x18 */ BE(u32) mItem[1]; @@ -701,7 +682,6 @@ public: void* getPEventBit() { return (void*)mEvent; } -private: /* 0x0 */ u8 mEvent[256]; }; // Size: 0x100 @@ -716,7 +696,6 @@ public: u32 getRaceGameTime() const { return mRaceGameTime; } void setRaceGameTime(u32 i_time) { mRaceGameTime = i_time; } -private: /* 0x00 */ u8 unk0[1][4]; /* 0x04 */ BE(u32) mHookGameTime; /* 0x08 */ BE(u32) mBalloonScore; @@ -732,7 +711,6 @@ public: dSv_memBit_c& getBit() { return mBit; } const dSv_memBit_c& getBit() const { return mBit; } -private: /* 0x0 */ dSv_memBit_c mBit; }; // Size: 0x20 @@ -746,7 +724,6 @@ public: void offVisitedRoom(int i_no); BOOL isVisitedRoom(int i_no); -private: /* 0x0 */ BE(u32) mVisitedRoom[2]; }; // Size: 0x8 @@ -765,7 +742,6 @@ public: void reset() { mStageNo = -1; } -private: /* 0x00 */ s8 mStageNo; /* 0x01 */ u8 unk1; /* 0x04 */ u32 mSwitch[2]; @@ -793,7 +769,6 @@ public: void offOneItem(int i_no); BOOL isOneItem(int i_no) const; -private: /* 0x00 */ BE(u16) mSwitch[2]; /* 0x04 */ BE(u16) mRoomSwitch; /* 0x06 */ BE(u16) mItem[2]; @@ -810,7 +785,6 @@ public: static const int ACTOR_MAX = 0x80; -private: /* 0x00 */ u32 mActorFlags[4]; }; // Size: 0x10 @@ -826,7 +800,6 @@ public: dSv_zoneActor_c& getActor() { return mActor; } const dSv_zoneActor_c& getActor() const { return mActor; } -private: /* 0x00 */ s8 mRoomNo; /* 0x01 */ u8 unk1; /* 0x02 */ dSv_zoneBit_c mBit; @@ -855,7 +828,6 @@ public: mLastAngleY = angle; } -private: /* 0x00 */ s8 mRoomNo; /* 0x01 */ u8 field_0x01[3]; /* 0x04 */ s16 mStartPoint; @@ -891,7 +863,6 @@ public: f32 getCameraFvy() const { return mCameraFvy; } void setCameraFvy(f32 i_fvy) { mCameraFvy = i_fvy; } -private: /* 0x00 */ cXyz mPosition; /* 0x0C */ u32 mParam; /* 0x10 */ s16 mAngleY; @@ -928,7 +899,6 @@ public: static const int STAGE_MAX = 32; static const int STAGE2_MAX = 64; - // private: /* 0x000 */ dSv_player_c mPlayer; /* 0x1F0 */ dSv_memory_c mSave[STAGE_MAX]; /* 0x5F0 */ dSv_memory2_c mSave2[STAGE2_MAX]; diff --git a/src/dusk/imgui/ImGuiConsole.cpp b/src/dusk/imgui/ImGuiConsole.cpp index 003d5e5f62..cc8b758cb7 100644 --- a/src/dusk/imgui/ImGuiConsole.cpp +++ b/src/dusk/imgui/ImGuiConsole.cpp @@ -7,6 +7,7 @@ #include "fmt/format.h" #include "imgui.h" #include "aurora/gfx.h" +#include #include "ImGuiConsole.hpp" @@ -82,6 +83,91 @@ namespace dusk { return result; } + // from https://github.com/ocornut/imgui/issues/1496#issuecomment-569892444 + void ImGuiBeginGroupPanel(const char* name, const ImVec2& size) { + ImGui::BeginGroup(); + + auto cursorPos = ImGui::GetCursorScreenPos(); + auto itemSpacing = ImGui::GetStyle().ItemSpacing; + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.0f, 0.0f)); + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 0.0f)); + + auto frameHeight = ImGui::GetFrameHeight(); + ImGui::BeginGroup(); + + ImVec2 effectiveSize = size; + if (size.x < 0.0f) + effectiveSize.x = ImGui::GetContentRegionAvail().x; + else + effectiveSize.x = size.x; + ImGui::Dummy(ImVec2(effectiveSize.x, 0.0f)); + + ImGui::Dummy(ImVec2(frameHeight * 0.5f, 0.0f)); + ImGui::SameLine(0.0f, 0.0f); + ImGui::BeginGroup(); + ImGui::Dummy(ImVec2(frameHeight * 0.5f, 0.0f)); + ImGui::SameLine(0.0f, 0.0f); + ImGui::TextUnformatted(name); + ImGui::SameLine(0.0f, 0.0f); + ImGui::Dummy(ImVec2(0.0, frameHeight + itemSpacing.y)); + ImGui::BeginGroup(); + + ImGui::PopStyleVar(2); + + ImGui::GetCurrentWindow()->ContentRegionRect.Max.x -= frameHeight * 0.5f; + ImGui::GetCurrentWindow()->WorkRect.Max.x -= frameHeight * 0.5f; + ImGui::GetCurrentWindow()->Size.x -= frameHeight; + + ImGui::PushItemWidth(effectiveSize.x - frameHeight); + } + + // from https://github.com/ocornut/imgui/issues/1496#issuecomment-569892444 + void ImGuiEndGroupPanel() { + ImGui::PopItemWidth(); + + auto itemSpacing = ImGui::GetStyle().ItemSpacing; + + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.0f, 0.0f)); + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 0.0f)); + + auto frameHeight = ImGui::GetFrameHeight(); + + // workaround for incorrect capture of columns/table width by placing + // zero-sized dummy element in the same group, this ensure + // max X cursor position is updated correctly + ImGui::SameLine(0.0f, 0.0f); + ImGui::Dummy(ImVec2(0.0f, 0.0f)); + + ImGui::EndGroup(); + ImGui::EndGroup(); + + ImGui::SameLine(0.0f, 0.0f); + ImGui::Dummy(ImVec2(frameHeight * 0.5f, 0.0f)); + ImGui::Dummy(ImVec2(0.0, frameHeight - frameHeight * 0.5f - itemSpacing.y)); + + ImGui::EndGroup(); + + auto itemMin = ImGui::GetItemRectMin(); + auto itemMax = ImGui::GetItemRectMax(); + + ImVec2 halfFrame = ImVec2((frameHeight * 0.25f) * 0.5f, frameHeight * 0.5f); + ImGui::GetWindowDrawList()->AddRect( + ImVec2(itemMin.x + halfFrame.x, itemMin.y + halfFrame.y), + ImVec2(itemMax.x - halfFrame.x, itemMax.y), + ImColor(ImGui::GetStyleColorVec4(ImGuiCol_Border)), + halfFrame.x); + + ImGui::PopStyleVar(2); + + ImGui::GetCurrentWindow()->ContentRegionRect.Max.x += frameHeight * 0.5f; + ImGui::GetCurrentWindow()->WorkRect.Max.x += frameHeight * 0.5f; + ImGui::GetCurrentWindow()->Size.x += frameHeight; + + ImGui::Dummy(ImVec2(0.0f, 0.0f)); + + ImGui::EndGroup(); + } + ImGuiConsole g_imguiConsole; ImGuiConsole::ImGuiConsole() {} diff --git a/src/dusk/imgui/ImGuiConsole.hpp b/src/dusk/imgui/ImGuiConsole.hpp index 47fa435626..82f0658e7a 100644 --- a/src/dusk/imgui/ImGuiConsole.hpp +++ b/src/dusk/imgui/ImGuiConsole.hpp @@ -33,6 +33,8 @@ namespace dusk { void SetOverlayWindowLocation(int corner); bool ShowCornerContextMenu(int& corner, int avoidCorner); void ImGuiStringViewText(std::string_view text); + void ImGuiBeginGroupPanel(const char* name, const ImVec2& size); + void ImGuiEndGroupPanel(); } void DuskDebugPad(); diff --git a/src/dusk/imgui/ImGuiMenuGame.cpp b/src/dusk/imgui/ImGuiMenuGame.cpp index 3d9af4fdc5..2366fb6a42 100644 --- a/src/dusk/imgui/ImGuiMenuGame.cpp +++ b/src/dusk/imgui/ImGuiMenuGame.cpp @@ -68,91 +68,6 @@ namespace dusk { } } - // from https://github.com/ocornut/imgui/issues/1496#issuecomment-569892444 - void ImGuiBeginGroupPanel(const char* name, const ImVec2& size) { - ImGui::BeginGroup(); - - auto cursorPos = ImGui::GetCursorScreenPos(); - auto itemSpacing = ImGui::GetStyle().ItemSpacing; - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.0f, 0.0f)); - ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 0.0f)); - - auto frameHeight = ImGui::GetFrameHeight(); - ImGui::BeginGroup(); - - ImVec2 effectiveSize = size; - if (size.x < 0.0f) - effectiveSize.x = ImGui::GetContentRegionAvail().x; - else - effectiveSize.x = size.x; - ImGui::Dummy(ImVec2(effectiveSize.x, 0.0f)); - - ImGui::Dummy(ImVec2(frameHeight * 0.5f, 0.0f)); - ImGui::SameLine(0.0f, 0.0f); - ImGui::BeginGroup(); - ImGui::Dummy(ImVec2(frameHeight * 0.5f, 0.0f)); - ImGui::SameLine(0.0f, 0.0f); - ImGui::TextUnformatted(name); - ImGui::SameLine(0.0f, 0.0f); - ImGui::Dummy(ImVec2(0.0, frameHeight + itemSpacing.y)); - ImGui::BeginGroup(); - - ImGui::PopStyleVar(2); - - ImGui::GetCurrentWindow()->ContentRegionRect.Max.x -= frameHeight * 0.5f; - ImGui::GetCurrentWindow()->WorkRect.Max.x -= frameHeight * 0.5f; - ImGui::GetCurrentWindow()->Size.x -= frameHeight; - - ImGui::PushItemWidth(effectiveSize.x - frameHeight); - } - - // from https://github.com/ocornut/imgui/issues/1496#issuecomment-569892444 - void ImGuiEndGroupPanel() { - ImGui::PopItemWidth(); - - auto itemSpacing = ImGui::GetStyle().ItemSpacing; - - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.0f, 0.0f)); - ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 0.0f)); - - auto frameHeight = ImGui::GetFrameHeight(); - - // workaround for incorrect capture of columns/table width by placing - // zero-sized dummy element in the same group, this ensure - // max X cursor position is updated correctly - ImGui::SameLine(0.0f, 0.0f); - ImGui::Dummy(ImVec2(0.0f, 0.0f)); - - ImGui::EndGroup(); - ImGui::EndGroup(); - - ImGui::SameLine(0.0f, 0.0f); - ImGui::Dummy(ImVec2(frameHeight * 0.5f, 0.0f)); - ImGui::Dummy(ImVec2(0.0, frameHeight - frameHeight * 0.5f - itemSpacing.y)); - - ImGui::EndGroup(); - - auto itemMin = ImGui::GetItemRectMin(); - auto itemMax = ImGui::GetItemRectMax(); - - ImVec2 halfFrame = ImVec2((frameHeight * 0.25f) * 0.5f, frameHeight * 0.5f); - ImGui::GetWindowDrawList()->AddRect( - ImVec2(itemMin.x + halfFrame.x, itemMin.y + halfFrame.y), - ImVec2(itemMax.x - halfFrame.x, itemMax.y), - ImColor(ImGui::GetStyleColorVec4(ImGuiCol_Border)), - halfFrame.x); - - ImGui::PopStyleVar(2); - - ImGui::GetCurrentWindow()->ContentRegionRect.Max.x += frameHeight * 0.5f; - ImGui::GetCurrentWindow()->WorkRect.Max.x += frameHeight * 0.5f; - ImGui::GetCurrentWindow()->Size.x += frameHeight; - - ImGui::Dummy(ImVec2(0.0f, 0.0f)); - - ImGui::EndGroup(); - } - static void drawVirtualStick(const char* id, const ImVec2& stick) { ImGui::SetCursorPos(ImVec2(ImGui::GetCursorPos().x + 5, ImGui::GetCursorPos().y)); diff --git a/src/dusk/imgui/ImGuiMenuTools.cpp b/src/dusk/imgui/ImGuiMenuTools.cpp index 9f68e11b40..d848690063 100644 --- a/src/dusk/imgui/ImGuiMenuTools.cpp +++ b/src/dusk/imgui/ImGuiMenuTools.cpp @@ -44,6 +44,7 @@ namespace dusk { ImGui::MenuItem("Debug Camera", "F6", &m_showCameraOverlay); ImGui::MenuItem("Map Loader", nullptr, &m_showMapLoader); ImGui::MenuItem("Player Info", nullptr, &m_showPlayerInfo); + ImGui::MenuItem("Save Editor", nullptr, &m_showSaveEditor); ImGui::EndMenu(); } @@ -59,6 +60,10 @@ namespace dusk { ShowMapLoader(); ShowPlayerInfo(); + if (m_showSaveEditor) { + m_saveEditor.draw(); + } + DuskDebugPad(); // temporary, remove later } diff --git a/src/dusk/imgui/ImGuiMenuTools.hpp b/src/dusk/imgui/ImGuiMenuTools.hpp index 5650e49c8e..325181268a 100644 --- a/src/dusk/imgui/ImGuiMenuTools.hpp +++ b/src/dusk/imgui/ImGuiMenuTools.hpp @@ -5,6 +5,7 @@ #include #include "imgui.h" +#include "ImGuiSaveEditor.hpp" namespace dusk { class ImGuiMenuTools { @@ -63,6 +64,9 @@ namespace dusk { bool m_showPlayerInfo = false; CollisionViewSettings m_collisionViewSettings; + + bool m_showSaveEditor = false; + ImGuiSaveEditor m_saveEditor; }; } diff --git a/src/dusk/imgui/ImGuiSaveEditor.cpp b/src/dusk/imgui/ImGuiSaveEditor.cpp new file mode 100644 index 0000000000..b21196fa54 --- /dev/null +++ b/src/dusk/imgui/ImGuiSaveEditor.cpp @@ -0,0 +1,816 @@ +#include "fmt/format.h" +#include "imgui.h" +#include "aurora/gfx.h" + +#include "ImGuiConsole.hpp" +#include "ImGuiSaveEditor.hpp" + +#include "d/d_com_inf_game.h" +#include "d/d_item_data.h" + +#include + +namespace dusk { + std::map itemMap = { + {dItemNo_HEART_e, "Heart"}, + {dItemNo_GREEN_RUPEE_e, "Green Rupee"}, + {dItemNo_BLUE_RUPEE_e, "Blue Rupee"}, + {dItemNo_YELLOW_RUPEE_e, "Yellow Rupee"}, + {dItemNo_RED_RUPEE_e, "Red Rupee"}, + {dItemNo_PURPLE_RUPEE_e, "Purple Rupee"}, + {dItemNo_ORANGE_RUPEE_e, "Orange Rupee"}, + {dItemNo_SILVER_RUPEE_e, "Silver Rupee"}, + {dItemNo_S_MAGIC_e, "Small Magic"}, + {dItemNo_L_MAGIC_e, "Large Magic"}, + {dItemNo_BOMB_5_e, "Bombs (5)"}, + {dItemNo_BOMB_10_e, "Bombs (10)"}, + {dItemNo_BOMB_20_e, "Bombs (20)"}, + {dItemNo_BOMB_30_e, "Bombs (30)"}, + {dItemNo_ARROW_10_e, "Arrows (10)"}, + {dItemNo_ARROW_20_e, "Arrows (20)"}, + {dItemNo_ARROW_30_e, "Arrows (30)"}, + {dItemNo_ARROW_1_e, "Arrows (1)"}, + {dItemNo_PACHINKO_SHOT_e, "Pumpkin Seeds"}, + {dItemNo_NOENTRY_19_e, "Unknown"}, + {dItemNo_NOENTRY_20_e, "Unknown"}, + {dItemNo_NOENTRY_21_e, "Unknown"}, + {dItemNo_WATER_BOMB_5_e, "Water Bombs (5)"}, + {dItemNo_WATER_BOMB_10_e, "Water Bombs (10)"}, + {dItemNo_WATER_BOMB_20_e, "Water Bombs (20)"}, + {dItemNo_WATER_BOMB_30_e, "Water Bombs (30)"}, + {dItemNo_BOMB_INSECT_5_e, "Bomblings (5)"}, + {dItemNo_BOMB_INSECT_10_e, "Bomblings (10)"}, + {dItemNo_BOMB_INSECT_20_e, "Bomblings (20)"}, + {dItemNo_BOMB_INSECT_30_e, "Bomblings (30)"}, + {dItemNo_RECOVERY_FAILY_e, "Fairy"}, + {dItemNo_TRIPLE_HEART_e, "Triple Hearts"}, + {dItemNo_SMALL_KEY_e, "Small Key"}, + {dItemNo_KAKERA_HEART_e, "Piece of Heart"}, + {dItemNo_UTAWA_HEART_e, "Heart Container"}, + {dItemNo_MAP_e, "Map"}, + {dItemNo_COMPUS_e, "Compass"}, + {dItemNo_DUNGEON_EXIT_e, "Ooccoo Sr."}, + {dItemNo_BOSS_KEY_e, "Boss Key"}, + {dItemNo_DUNGEON_BACK_e, "Ooccoo Jr."}, + {dItemNo_SWORD_e, "Ordon Sword"}, + {dItemNo_MASTER_SWORD_e, "Master Sword"}, + {dItemNo_WOOD_SHIELD_e, "Wooden Shield"}, + {dItemNo_SHIELD_e, "Ordon Shield"}, + {dItemNo_HYLIA_SHIELD_e, "Hylian Shield"}, + {dItemNo_TKS_LETTER_e, "Ooccoo's Letter"}, + {dItemNo_WEAR_CASUAL_e, "Ordon Clothes"}, + {dItemNo_WEAR_KOKIRI_e, "Hero's Clothes"}, + {dItemNo_ARMOR_e, "Magic Armor"}, + {dItemNo_WEAR_ZORA_e, "Zora Armor"}, + {dItemNo_MAGIC_LV1_e, "Magic Level 1"}, + {dItemNo_DUNGEON_EXIT_2_e, "Ooccoo Sr."}, + {dItemNo_WALLET_LV1_e, "Wallet"}, + {dItemNo_WALLET_LV2_e, "Big Wallet"}, + {dItemNo_WALLET_LV3_e, "Giant Wallet"}, + {dItemNo_NOENTRY_55_e, "Unknown"}, + {dItemNo_NOENTRY_56_e, "Unknown"}, + {dItemNo_NOENTRY_57_e, "Unknown"}, + {dItemNo_NOENTRY_58_e, "Unknown"}, + {dItemNo_NOENTRY_59_e, "Unknown"}, + {dItemNo_NOENTRY_60_e, "Unknown"}, + {dItemNo_ZORAS_JEWEL_e, "Coral Earring"}, + {dItemNo_HAWK_EYE_e, "Hawkeye"}, + {dItemNo_WOOD_STICK_e, "Wooden Sword"}, + {dItemNo_BOOMERANG_e, "Gale Boomerang"}, + {dItemNo_SPINNER_e, "Spinner"}, + {dItemNo_IRONBALL_e, "Ball and Chain"}, + {dItemNo_BOW_e, "Hero's Bow"}, + {dItemNo_HOOKSHOT_e, "Clawshot"}, + {dItemNo_HVY_BOOTS_e, "Iron Boots"}, + {dItemNo_COPY_ROD_e, "Dominion Rod"}, + {dItemNo_W_HOOKSHOT_e, "Double Clawshots"}, + {dItemNo_KANTERA_e, "Lantern"}, + {dItemNo_LIGHT_SWORD_e, "Light Sword"}, + {dItemNo_FISHING_ROD_1_e, "Fishing Rod"}, + {dItemNo_PACHINKO_e, "Slingshot"}, + {dItemNo_COPY_ROD_2_e, "Dominion Rod"}, + {dItemNo_NOENTRY_77_e, "Unknown"}, + {dItemNo_NOENTRY_78_e, "Unknown"}, + {dItemNo_BOMB_BAG_LV2_e, "Giant Bomb Bag"}, + {dItemNo_BOMB_BAG_LV1_e, "Bomb Bag"}, + {dItemNo_BOMB_IN_BAG_e, "Bomb Bag"}, + {dItemNo_NOENTRY_82_e, "Unknown"}, + {dItemNo_LIGHT_ARROW_e, "Light Arrow"}, + {dItemNo_ARROW_LV1_e, "Quiver"}, + {dItemNo_ARROW_LV2_e, "Big Quiver"}, + {dItemNo_ARROW_LV3_e, "Giant Quiver"}, + {dItemNo_NOENTRY_87_e, "Unknown"}, + {dItemNo_LURE_ROD_e, "Fishing Rod (Lure)"}, + {dItemNo_BOMB_ARROW_e, "Bomb Arrow"}, + {dItemNo_HAWK_ARROW_e, "Hawk Arrow"}, + {dItemNo_BEE_ROD_e, "Fishing Rod (Bee Larva)"}, + {dItemNo_JEWEL_ROD_e, "Fishing Rod (Earring)"}, + {dItemNo_WORM_ROD_e, "Fishing Rod (Worm)"}, + {dItemNo_JEWEL_BEE_ROD_e, "Fishing Rod (Earring + Bee Larva)"}, + {dItemNo_JEWEL_WORM_ROD_e, "Fishing Rod (Earring + Worm)"}, + {dItemNo_EMPTY_BOTTLE_e, "Empty Bottle"}, + {dItemNo_RED_BOTTLE_e, "Red Potion"}, + {dItemNo_GREEN_BOTTLE_e, "Green Potion"}, + {dItemNo_BLUE_BOTTLE_e, "Blue Potion"}, + {dItemNo_MILK_BOTTLE_e, "Milk Bottle"}, + {dItemNo_HALF_MILK_BOTTLE_e, "Half Milk Bottle"}, + {dItemNo_OIL_BOTTLE_e, "Lantern Oil"}, + {dItemNo_WATER_BOTTLE_e, "Water Bottle"}, + {dItemNo_OIL_BOTTLE_2_e, "Oil Bottle"}, + {dItemNo_RED_BOTTLE_2_e, "Red Potion"}, + {dItemNo_UGLY_SOUP_e, "Nasty Soup"}, + {dItemNo_HOT_SPRING_e, "Hotspring Water"}, + {dItemNo_FAIRY_e, "Fairy"}, + {dItemNo_HOT_SPRING_2_e, "Hotspring Water"}, + {dItemNo_OIL2_e, "Lantern Oil"}, + {dItemNo_OIL_e, "Lantern Oil"}, + {dItemNo_NORMAL_BOMB_e, "Bombs"}, + {dItemNo_WATER_BOMB_e, "Water Bombs"}, + {dItemNo_POKE_BOMB_e, "Bomblings"}, + {dItemNo_FAIRY_DROP_e, "Great Fairy's Tears"}, + {dItemNo_WORM_e, "Worm"}, + {dItemNo_DROP_BOTTLE_e, ""}, + {dItemNo_BEE_CHILD_e, ""}, + {dItemNo_CHUCHU_RARE_e, "Rare Chu Jelly"}, + {dItemNo_CHUCHU_RED_e, "Red Chu Jelly"}, + {dItemNo_CHUCHU_BLUE_e, "Blue Chu Jelly"}, + {dItemNo_CHUCHU_GREEN_e, "Green Chu Jelly"}, + {dItemNo_CHUCHU_YELLOW_e, "Yellow Chu Jelly"}, + {dItemNo_CHUCHU_PURPLE_e, "Purple Chu Jelly"}, + {dItemNo_LV1_SOUP_e, "Simple Soup"}, + {dItemNo_LV2_SOUP_e, "Good Soup"}, + {dItemNo_LV3_SOUP_e, "Superb Soup"}, + {dItemNo_LETTER_e, "Renado's Letter"}, + {dItemNo_BILL_e, "Invoice"}, + {dItemNo_WOOD_STATUE_e, "Wooden Statue"}, + {dItemNo_IRIAS_PENDANT_e, "Ilia's Charm"}, + {dItemNo_HORSE_FLUTE_e, "Horse Call"}, + {dItemNo_NOENTRY_133_e, "Unknown"}, + {dItemNo_NOENTRY_134_e, "Unknown"}, + {dItemNo_NOENTRY_135_e, "Unknown"}, + {dItemNo_NOENTRY_136_e, "Unknown"}, + {dItemNo_NOENTRY_137_e, "Unknown"}, + {dItemNo_NOENTRY_138_e, "Unknown"}, + {dItemNo_NOENTRY_139_e, "Unknown"}, + {dItemNo_NOENTRY_140_e, "Unknown"}, + {dItemNo_NOENTRY_141_e, "Unknown"}, + {dItemNo_NOENTRY_142_e, "Unknown"}, + {dItemNo_NOENTRY_143_e, "Unknown"}, + {dItemNo_RAFRELS_MEMO_e, "Auru's Memo"}, + {dItemNo_ASHS_SCRIBBLING_e, "Ashei's Sketch"}, + {dItemNo_NOENTRY_146_e, "Unknown"}, + {dItemNo_NOENTRY_147_e, "Unknown"}, + {dItemNo_NOENTRY_148_e, "Unknown"}, + {dItemNo_NOENTRY_149_e, "Unknown"}, + {dItemNo_NOENTRY_150_e, "Unknown"}, + {dItemNo_NOENTRY_151_e, "Unknown"}, + {dItemNo_NOENTRY_152_e, "Unknown"}, + {dItemNo_NOENTRY_153_e, "Unknown"}, + {dItemNo_NOENTRY_154_e, "Unknown"}, + {dItemNo_NOENTRY_155_e, "Unknown"}, + {dItemNo_CHUCHU_YELLOW2_e, "Yellow Chu Jelly"}, + {dItemNo_OIL_BOTTLE3_e, "Lantern Oil"}, + {dItemNo_SHOP_BEE_CHILD_e, ""}, + {dItemNo_CHUCHU_BLACK_e, "Black Chu Jelly"}, + {dItemNo_LIGHT_DROP_e, "Tear of Light"}, + {dItemNo_DROP_CONTAINER_e, "Vessel of Light (Faron)"}, + {dItemNo_DROP_CONTAINER02_e, "Vessel of Light (Eldin)"}, + {dItemNo_DROP_CONTAINER03_e, "Vessel of Light (Lanayru)"}, + {dItemNo_FILLED_CONTAINER_e, "Vessel of Light (Filled)"}, + {dItemNo_MIRROR_PIECE_2_e, "Mirror Shard (Snowpeak Ruins)"}, + {dItemNo_MIRROR_PIECE_3_e, "Mirror Shard (Temple of Time)"}, + {dItemNo_MIRROR_PIECE_4_e, "Mirror Shard (City in the Sky)"}, + {dItemNo_NOENTRY_168_e, "Unknown"}, + {dItemNo_NOENTRY_169_e, "Unknown"}, + {dItemNo_NOENTRY_170_e, "Unknown"}, + {dItemNo_NOENTRY_171_e, "Unknown"}, + {dItemNo_NOENTRY_172_e, "Unknown"}, + {dItemNo_NOENTRY_173_e, "Unknown"}, + {dItemNo_NOENTRY_174_e, "Unknown"}, + {dItemNo_NOENTRY_175_e, "Unknown"}, + {dItemNo_SMELL_YELIA_POUCH_e, "Scent of Ilia"}, + {dItemNo_SMELL_PUMPKIN_e, "Pumpkin Scent"}, + {dItemNo_SMELL_POH_e, "Poe Scent"}, + {dItemNo_SMELL_FISH_e, "Reekfish Scent"}, + {dItemNo_SMELL_CHILDREN_e, "Youth's Scent"}, + {dItemNo_SMELL_MEDICINE_e, "Medicine Scent"}, + {dItemNo_NOENTRY_182_e, "Unknown"}, + {dItemNo_NOENTRY_183_e, "Unknown"}, + {dItemNo_NOENTRY_184_e, "Unknown"}, + {dItemNo_NOENTRY_185_e, "Unknown"}, + {dItemNo_NOENTRY_186_e, "Unknown"}, + {dItemNo_NOENTRY_187_e, "Unknown"}, + {dItemNo_NOENTRY_188_e, "Unknown"}, + {dItemNo_NOENTRY_189_e, "Unknown"}, + {dItemNo_NOENTRY_190_e, "Unknown"}, + {dItemNo_NOENTRY_191_e, "Unknown"}, + {dItemNo_M_BEETLE_e, "Beetle ♂"}, + {dItemNo_F_BEETLE_e, "Beetle ♀"}, + {dItemNo_M_BUTTERFLY_e, "Butterfly ♂"}, + {dItemNo_F_BUTTERFLY_e, "Butterfly ♀"}, + {dItemNo_M_STAG_BEETLE_e, "Stag Beetle ♂"}, + {dItemNo_F_STAG_BEETLE_e, "Stag Beetle ♀"}, + {dItemNo_M_GRASSHOPPER_e, "Grasshopper ♂"}, + {dItemNo_F_GRASSHOPPER_e, "Grasshopper ♀"}, + {dItemNo_M_NANAFUSHI_e, "Phasmid ♂"}, + {dItemNo_F_NANAFUSHI_e, "Phasmid ♀"}, + {dItemNo_M_DANGOMUSHI_e, "Pill Bug ♂"}, + {dItemNo_F_DANGOMUSHI_e, "Pill Bug ♀"}, + {dItemNo_M_MANTIS_e, "Mantis ♂"}, + {dItemNo_F_MANTIS_e, "Mantis ♀"}, + {dItemNo_M_LADYBUG_e, "Ladybug ♂"}, + {dItemNo_F_LADYBUG_e, "Ladybug ♀"}, + {dItemNo_M_SNAIL_e, "Snail ♂"}, + {dItemNo_F_SNAIL_e, "Snail ♀"}, + {dItemNo_M_DRAGONFLY_e, "Dragonfly ♂"}, + {dItemNo_F_DRAGONFLY_e, "Dragonfly ♀"}, + {dItemNo_M_ANT_e, "Ant ♂"}, + {dItemNo_F_ANT_e, "Ant ♀"}, + {dItemNo_M_MAYFLY_e, "Mayfly ♂"}, + {dItemNo_F_MAYFLY_e, "Mayfly ♀"}, + {dItemNo_NOENTRY_216_e, "Unknown"}, + {dItemNo_NOENTRY_217_e, "Unknown"}, + {dItemNo_NOENTRY_218_e, "Unknown"}, + {dItemNo_NOENTRY_219_e, "Unknown"}, + {dItemNo_NOENTRY_220_e, "Unknown"}, + {dItemNo_NOENTRY_221_e, "Unknown"}, + {dItemNo_NOENTRY_222_e, "Unknown"}, + {dItemNo_NOENTRY_223_e, "Unknown"}, + {dItemNo_POU_SPIRIT_e, ""}, + {dItemNo_NOENTRY_225_e, "Unknown"}, + {dItemNo_NOENTRY_226_e, "Unknown"}, + {dItemNo_NOENTRY_227_e, "Unknown"}, + {dItemNo_NOENTRY_228_e, "Unknown"}, + {dItemNo_NOENTRY_229_e, "Unknown"}, + {dItemNo_NOENTRY_230_e, "Unknown"}, + {dItemNo_NOENTRY_231_e, "Unknown"}, + {dItemNo_NOENTRY_232_e, "Unknown"}, + {dItemNo_ANCIENT_DOCUMENT_e, "Ancient Sky Book"}, + {dItemNo_AIR_LETTER_e, "Sky Character"}, + {dItemNo_ANCIENT_DOCUMENT2_e, "Ancient Sky Book (Filled)"}, + {dItemNo_LV7_DUNGEON_EXIT_e, "Ooccoo Sr. (City in the Sky)"}, + {dItemNo_LINKS_SAVINGS_e, "Link's Savings"}, + {dItemNo_SMALL_KEY2_e, ""}, + {dItemNo_POU_FIRE1_e, ""}, + {dItemNo_POU_FIRE2_e, ""}, + {dItemNo_POU_FIRE3_e, ""}, + {dItemNo_POU_FIRE4_e, ""}, + {dItemNo_BOSSRIDER_KEY_e, ""}, + {dItemNo_TOMATO_PUREE_e, ""}, + {dItemNo_TASTE_e, ""}, + {dItemNo_LV5_BOSS_KEY_e, "Bedroom Key"}, + {dItemNo_SURFBOARD_e, ""}, + {dItemNo_KANTERA2_e, ""}, + {dItemNo_L2_KEY_PIECES1_e, "Key Shard (1)"}, + {dItemNo_L2_KEY_PIECES2_e, "Key Shard (2)"}, + {dItemNo_L2_KEY_PIECES3_e, "Key Shard (3)"}, + {dItemNo_KEY_OF_CARAVAN_e, "Bulblin Camp Key"}, + {dItemNo_LV2_BOSS_KEY_e, "Key Shard (Completed)"}, + {dItemNo_KEY_OF_FILONE_e, "Faron Gate Key"}, + {dItemNo_NONE_e, "None"}, + }; + + ImGuiSaveEditor::ImGuiSaveEditor() {} + + void ImGuiSaveEditor::draw() { + ImGuiIO& io = ImGui::GetIO(); + ImGuiWindowFlags windowFlags = ImGuiWindowFlags_NoResize; + + ImGui::SetNextWindowBgAlpha(0.65f); + ImGui::SetNextWindowSizeConstraints(ImVec2(600, 700), ImVec2(600, 700)); + + if (ImGui::Begin("Save Editor", nullptr, windowFlags)) { + if (ImGui::BeginTabBar("SaveEditorTabBar", ImGuiTabBarFlags_NoCloseWithMiddleMouseButton)) { + if (ImGui::BeginTabItem("Player Status")) { + drawPlayerStatusTab(); + ImGui::EndTabItem(); + } + + if (ImGui::BeginTabItem("Location")) { + drawLocationTab(); + ImGui::EndTabItem(); + } + + if (ImGui::BeginTabItem("Inventory")) { + //DrawInventoryTab(); + ImGui::EndTabItem(); + } + + if (ImGui::BeginTabItem("Collection")) { + //DrawFlagsTab(); + ImGui::EndTabItem(); + } + + if (ImGui::BeginTabItem("Flags")) { + drawFlagsTab(); + ImGui::EndTabItem(); + } + + if (ImGui::BeginTabItem("Minigame")) { + //DrawFlagsTab(); + ImGui::EndTabItem(); + } + + if (ImGui::BeginTabItem("Config")) { + drawConfigTab(); + ImGui::EndTabItem(); + } + + ImGui::EndTabBar(); + } + } + + ImGui::End(); + } + + void InputScalarBE(const char* label, ImGuiDataType dataType, void* pData) { + switch (dataType) { + case ImGuiDataType_U16: { + u16 temp = *(BE(u16)*)pData; + if (ImGui::InputScalar(label, dataType, &temp)) { + *(BE(u16)*)pData = temp; + } + break; + } + case ImGuiDataType_S16: { + s16 temp = *(BE(s16)*)pData; + if (ImGui::InputScalar(label, dataType, &temp)) { + *(BE(s16)*)pData = temp; + } + break; + } + case ImGuiDataType_U32: { + u32 temp = *(BE(u32)*)pData; + if (ImGui::InputScalar(label, dataType, &temp)) { + *(BE(u32)*)pData = temp; + } + break; + } + case ImGuiDataType_S32: { + s32 temp = *(BE(s32)*)pData; + if (ImGui::InputScalar(label, dataType, &temp)) { + *(BE(s32)*)pData = temp; + } + break; + } + case ImGuiDataType_U64: { + u64 temp = *(BE(u64)*)pData; + if (ImGui::InputScalar(label, dataType, &temp)) { + *(BE(u64)*)pData = temp; + } + break; + } + case ImGuiDataType_S64: { + s64 temp = *(BE(s64)*)pData; + if (ImGui::InputScalar(label, dataType, &temp)) { + *(BE(s64)*)pData = temp; + } + break; + } + case ImGuiDataType_Float: { + f32 temp = *(BE(f32)*)pData; + if (ImGui::InputScalar(label, dataType, &temp)) { + *(BE(f32)*)pData = temp; + } + break; + } + } + } + + void genSelectItemComboBox(const char* label, u8& selectItemData) { + dSv_player_status_a_c& statusA = dComIfGs_getSaveData()->getPlayer().getPlayerStatusA(); + dSv_player_item_c& item = dComIfGs_getSaveData()->getPlayer().getItem(); + + int currentSlotNo = selectItemData; + std::string defaultLabel = + currentSlotNo != 0xFF + ? fmt::format("Slot {0} ({1})", currentSlotNo, itemMap.find(item.mItems[currentSlotNo])->second) + : "None"; + + // TODO: live update equips + if (ImGui::BeginCombo(label, defaultLabel.c_str())) { + if (ImGui::Selectable("None")) { + selectItemData = 0xFF; + } + + for (int i = 0; i < 24; i++) { + u8 itemNo = item.mItems[i]; + if (ImGui::Selectable(fmt::format("Slot {0} ({1})", i, itemMap.find(itemNo)->second).c_str())) { + selectItemData = i; + } + } + ImGui::EndCombo(); + } + } + + void ImGuiSaveEditor::drawPlayerStatusTab() { + const char* playerName = dComIfGs_getPlayerName(); + ImGui::Text("Player Name: "); + ImGui::SameLine(); + char nameBuffer[8]; + snprintf(nameBuffer, sizeof(nameBuffer), "%s", playerName); + if (ImGui::InputText("##PlayerNameInput", nameBuffer, 8)) { + strcpy(dComIfGs_getPlayerName(), nameBuffer); + } + + const char* horseName = dComIfGs_getHorseName(); + ImGui::Text("Horse Name: "); + ImGui::SameLine(); + char horseNameBuffer[8]; + snprintf(horseNameBuffer, sizeof(horseNameBuffer), "%s", horseName); + if (ImGui::InputText("##HorseNameInput", horseNameBuffer, 8)) { + strcpy(dComIfGs_getHorseName(), horseNameBuffer); + } + + ImGui::Separator(); + + dSv_player_status_a_c& statusA = dComIfGs_getSaveData()->getPlayer().getPlayerStatusA(); + dSv_player_status_b_c& statusB = dComIfGs_getSaveData()->getPlayer().getPlayerStatusB(); + + InputScalarBE("Max Health", ImGuiDataType_U16, &statusA.mMaxLife); + InputScalarBE("Health", ImGuiDataType_U16, &statusA.mLife); + InputScalarBE("Rupees", ImGuiDataType_U16, &statusA.mRupee); + InputScalarBE("Max Oil", ImGuiDataType_U16, &statusA.mMaxOil); + InputScalarBE("Oil", ImGuiDataType_U16, &statusA.mOil); + + genSelectItemComboBox("Equip X", statusA.mSelectItem[0]); + genSelectItemComboBox("Equip Y", statusA.mSelectItem[1]); + genSelectItemComboBox("Combo Equip X", statusA.mMixItem[0]); + genSelectItemComboBox("Combo Equip Y", statusA.mMixItem[1]); + + + if (ImGui::BeginCombo("Clothes", itemMap.find(statusA.mSelectEquip[0])->second.c_str())) { + if (ImGui::Selectable("None")) { + statusA.mSelectEquip[0] = dItemNo_NONE_e; + } + if (ImGui::Selectable("Ordon Clothes")) { + statusA.mSelectEquip[0] = dItemNo_WEAR_CASUAL_e; + } + if (ImGui::Selectable("Hero's Clothes")) { + statusA.mSelectEquip[0] = dItemNo_WEAR_KOKIRI_e; + } + if (ImGui::Selectable("Zora Armor")) { + statusA.mSelectEquip[0] = dItemNo_WEAR_ZORA_e; + } + if (ImGui::Selectable("Magic Armor")) { + statusA.mSelectEquip[0] = dItemNo_ARMOR_e; + } + ImGui::EndCombo(); + } + + if (ImGui::BeginCombo("Sword", itemMap.find(statusA.mSelectEquip[1])->second.c_str())) { + if (ImGui::Selectable("None")) { + statusA.mSelectEquip[1] = dItemNo_NONE_e; + } + if (ImGui::Selectable("Wooden Sword")) { + statusA.mSelectEquip[1] = dItemNo_WOOD_STICK_e; + } + if (ImGui::Selectable("Ordon Sword")) { + statusA.mSelectEquip[1] = dItemNo_SWORD_e; + } + if (ImGui::Selectable("Master Sword")) { + statusA.mSelectEquip[1] = dItemNo_MASTER_SWORD_e; + } + if (ImGui::Selectable("Light Sword")) { + statusA.mSelectEquip[1] = dItemNo_LIGHT_SWORD_e; + } + ImGui::EndCombo(); + } + + if (ImGui::BeginCombo("Shield", itemMap.find(statusA.mSelectEquip[2])->second.c_str())) { + if (ImGui::Selectable("None")) { + statusA.mSelectEquip[2] = dItemNo_NONE_e; + } + if (ImGui::Selectable("Wooden Shield")) { + statusA.mSelectEquip[2] = dItemNo_SHIELD_e; + } + if (ImGui::Selectable("Ordon Shield")) { + statusA.mSelectEquip[2] = dItemNo_WOOD_SHIELD_e; + } + if (ImGui::Selectable("Hylian Shield")) { + statusA.mSelectEquip[2] = dItemNo_HYLIA_SHIELD_e; + } + ImGui::EndCombo(); + } + + if (ImGui::BeginCombo("Scent", itemMap.find(statusA.mSelectEquip[3])->second.c_str())) { + if (ImGui::Selectable("None")) { + statusA.mSelectEquip[3] = dItemNo_NONE_e; + } + if (ImGui::Selectable("Youth's Scent")) { + statusA.mSelectEquip[3] = dItemNo_SMELL_CHILDREN_e; + } + if (ImGui::Selectable("Scent of Ilia")) { + statusA.mSelectEquip[3] = dItemNo_SMELL_YELIA_POUCH_e; + } + if (ImGui::Selectable("Poe Scent")) { + statusA.mSelectEquip[3] = dItemNo_SMELL_POH_e; + } + if (ImGui::Selectable("Reekfish Scent")) { + statusA.mSelectEquip[3] = dItemNo_SMELL_FISH_e; + } + if (ImGui::Selectable("Medicine Scent")) { + statusA.mSelectEquip[3] = dItemNo_SMELL_MEDICINE_e; + } + ImGui::EndCombo(); + } + + const char* walletSizeNames[] = { + "Normal", + "Big", + "Giant", + }; + int walletSize = statusA.getWalletSize(); + if (ImGui::BeginCombo("Wallet Size", walletSizeNames[walletSize])) { + if (ImGui::Selectable(walletSizeNames[WALLET])) { + statusA.setWalletSize(WALLET); + } + if (ImGui::Selectable(walletSizeNames[BIG_WALLET])) { + statusA.setWalletSize(BIG_WALLET); + } + if (ImGui::Selectable(walletSizeNames[GIANT_WALLET])) { + statusA.setWalletSize(GIANT_WALLET); + } + ImGui::EndCombo(); + } + + if (ImGui::BeginCombo("Form", statusA.mTransformStatus == 0 ? "Human" : "Wolf")) { + if (ImGui::Selectable("Human")) { + statusA.mTransformStatus = TF_STATUS_HUMAN; + } + if (ImGui::Selectable("Wolf")) { + statusA.mTransformStatus = TF_STATUS_WOLF; + } + ImGui::EndCombo(); + } + + ImGui::Separator(); + + s32 hours = dKy_getdaytime_hour(); + s32 min = dKy_getdaytime_minute(); + ImGui::SetNextItemWidth(ImGui::GetFontSize() * 2); + if (ImGui::InputScalar("##TimeHours", ImGuiDataType_S32, &hours)) { + hours = std::clamp(hours, 0, 23); + statusB.setTime((hours * 15.0f) + (min / 60.0f * 15.0f)); + } + + ImGui::SameLine(); + ImGui::Text(":"); + ImGui::SameLine(); + + ImGui::SetNextItemWidth(ImGui::GetFontSize() * 2); + if (ImGui::InputScalar("Time##TimeMinutes", ImGuiDataType_S32, &min)) { + min = std::clamp(min, 0, 59); + statusB.setTime((hours * 15.0f) + (min / 60.0f * 15.0f)); + } + + InputScalarBE("Date", ImGuiDataType_U16, &statusB.mDate); + + int transformLevel = 0; + for (int i = 0; i < 4; i++) { + if (statusB.mTransformLevelFlag & (1 << i)) { + transformLevel++; + } + } + if (ImGui::SliderInt("Transform Level", &transformLevel, 0, 3)) { + u8 newFlags = 0; + for (int i = 0; i < transformLevel; i++) { + newFlags |= (1 << i); + } + statusB.mTransformLevelFlag = newFlags; + } + + int darkClearLevel = 0; + for (int i = 0; i < 4; i++) { + if (statusB.mDarkClearLevelFlag & (1 << i)) { + darkClearLevel++; + } + } + if (ImGui::SliderInt("Twilight Clear Level", &darkClearLevel, 0, 3)) { + u8 newFlags = 0; + for (int i = 0; i < darkClearLevel; i++) { + newFlags |= (1 << i); + } + statusB.mDarkClearLevelFlag = newFlags; + } + } + + void ImGuiSaveEditor::drawLocationTab() { + dSv_player_return_place_c& returnPlace = dComIfGs_getSaveData()->getPlayer().getPlayerReturnPlace(); + dSv_horse_place_c& horsePlace = dComIfGs_getSaveData()->getPlayer().getHorsePlace(); + ImGui::Text("Save Location"); + + ImGui::Text("Stage: "); + ImGui::SameLine(); + char nameBuffer[8]; + snprintf(nameBuffer, sizeof(nameBuffer), "%s", returnPlace.mName); + if (ImGui::InputText("##SaveStageNameInput", nameBuffer, 8)) { + strcpy(returnPlace.mName, nameBuffer); + } + + ImGui::Text("Room: "); + ImGui::SameLine(); + int tempRoom = returnPlace.mRoomNo; + if (ImGui::InputInt("##SaveRoomInput", &tempRoom)) { + returnPlace.mRoomNo = tempRoom; + } + + ImGui::Text("Spawn ID: "); + ImGui::SameLine(); + int tempSpawn = returnPlace.mPlayerStatus; + if (ImGui::InputInt("##SaveSpawnInput", &tempSpawn)) { + returnPlace.mPlayerStatus = tempSpawn; + } + + ImGui::Separator(); + + ImGui::Text("Horse Location"); + + ImGui::Text("Position: "); + ImGui::SameLine(); + Vec tempPos = horsePlace.mPos; + if (ImGui::InputFloat3("##HorsePosition", &tempPos.x)) { + horsePlace.mPos.x = tempPos.x; + horsePlace.mPos.y = tempPos.y; + horsePlace.mPos.z = tempPos.z; + } + + ImGui::Text("Angle: "); + ImGui::SameLine(); + int tempAngle = horsePlace.mAngleY; + if (ImGui::InputInt("##HorsePosition", &tempAngle)) { + horsePlace.mAngleY = tempAngle; + } + + ImGui::Text("Stage: "); + ImGui::SameLine(); + char horseStageBuffer[8]; + snprintf(horseStageBuffer, sizeof(horseStageBuffer), "%s", horsePlace.mName); + if (ImGui::InputText("##HorseStageNameInput", horseStageBuffer, 8)) { + strcpy(horsePlace.mName, horseStageBuffer); + } + + ImGui::Text("Room: "); + ImGui::SameLine(); + int tempHorseRoom = horsePlace.mRoomNo; + if (ImGui::InputInt("##HorseRoomInput", &tempHorseRoom)) { + horsePlace.mRoomNo = tempHorseRoom; + } + + ImGui::Text("Spawn ID: "); + ImGui::SameLine(); + int tempHorseSpawn = horsePlace.mSpawnId; + if (ImGui::InputInt("##HorseSpawnInput", &tempHorseSpawn)) { + horsePlace.mSpawnId = tempHorseSpawn; + } + } + + void ImGuiSaveEditor::drawInventoryTab() { + + } + + void drawFlagList(const char* id, BE(u32)& flags) { + u32 tempFlagField = flags; + + for (int i = 31; i >= 0; i--) { + if ((31 - i) % 8) { + ImGui::SameLine(); + } + + bool flag = tempFlagField & (1 << i); + if (ImGui::Checkbox(fmt::format("{0}{1}", id, i).c_str(), &flag)) { + if (flag) + tempFlagField |= (1 << i); + else + tempFlagField &= ~(1 << i); + + flags = tempFlagField; + } + } + } + + void genMembitFlags(const char* id, dSv_memBit_c& membit) { + ImGuiBeginGroupPanel("Chest", { 100, 100 }); + for (int j = 0; j < 2; j++) { + drawFlagList(fmt::format("##_tbox{}", j).c_str(), membit.mTbox[j]); + } + ImGuiEndGroupPanel(); + + ImVec2 cursor = ImGui::GetCursorPos(); + + ImGui::SameLine(); + + ImGuiBeginGroupPanel("Switch", { 100, 100 }); + for (int j = 0; j < 4; j++) { + drawFlagList(fmt::format("##_switch{}", j).c_str(), membit.mSwitch[j]); + } + ImGuiEndGroupPanel(); + + ImGui::SetCursorPos(cursor); + + ImGuiBeginGroupPanel("Item", { 100, 100 }); + for (int j = 0; j < 1; j++) { + drawFlagList(fmt::format("##_item{}", j).c_str(), membit.mItem[j]); + } + ImGuiEndGroupPanel(); + } + + void ImGuiSaveEditor::drawFlagsTab() { + if (ImGui::TreeNode("Current Region Flags")) { + dSv_memBit_c& membit = g_dComIfG_gameInfo.info.mMemory.mBit; + genMembitFlags("##TempSceneFlags", membit); + + int stageNo = dStage_stagInfo_GetSaveTbl(dComIfGp_getStageStagInfo()); + if (ImGui::Button("Save##SaveTempFlags")) { + dComIfGs_putSave(stageNo); + } + + ImGui::SameLine(); + + if (ImGui::Button("Load##LoadSaveFlags")) { + dComIfGs_getSave(stageNo); + } + + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Region Saved Flags")) { + static std::array regionNames = { + "Ordon", + "Hyrule Sewers", + "Faron", + "Eldin", + "Lanayru", + "Unknown", + "Hyrule Field", + "Sacred Grove", + "Snowpeak", + "Castle Town", + "Gerudo Desert", + "Fishing Pond", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Forest Temple", + "Goron Mines", + "Lakebed Temple", + "Arbiter's Grounds", + "Snowpeak Ruins", + "Temple of Time", + "City in the Sky", + "Palace of Twilight", + "Hyrule Castle", + "Caves", + "Grottos", + }; + + if (ImGui::BeginCombo("Region", regionNames[m_selectedRegion])) { + for (int i = 0; i < regionNames.size(); i++) { + if (strcmp(regionNames[i], "Reserved") == 0) continue; + + if (ImGui::Selectable(regionNames[i])) { + m_selectedRegion = i; + } + } + + ImGui::EndCombo(); + } + + dSv_memBit_c* membit = &dComIfGs_getSaveData()->mSave[m_selectedRegion].mBit; + if (membit != nullptr) { + genMembitFlags("##SaveSceneFlags", *membit); + } + + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Event Flags")) { + dSv_event_c& event = dComIfGs_getSaveData()->mEvent; + for (int e = 0; e < 255; e++) { + ImGui::Text("%03d ", e); + ImGui::SameLine(); + for (int i = 8; i >= 0; i--) { + bool flag = event.mEvent[e] & (1 << i); + if (ImGui::Checkbox(fmt::format("##event{0}{1}", e, i).c_str(), &flag)) { + if (flag) + event.mEvent[e] |= (1 << i); + else + event.mEvent[e] &= ~(1 << i); + } + ImGui::SameLine(); + } + ImGui::NewLine(); + } + ImGui::TreePop(); + } + } + + void ImGuiSaveEditor::drawConfigTab() { + dSv_player_config_c& config = dComIfGs_getSaveData()->getPlayer().getConfig(); + ImGui::Checkbox("Enable Vibration", (bool*)&config.mVibration); + if (ImGui::BeginCombo("Target Type", "Hold")) { + ImGui::EndCombo(); + } + } +} \ No newline at end of file diff --git a/src/dusk/imgui/ImGuiSaveEditor.hpp b/src/dusk/imgui/ImGuiSaveEditor.hpp new file mode 100644 index 0000000000..f6668a75db --- /dev/null +++ b/src/dusk/imgui/ImGuiSaveEditor.hpp @@ -0,0 +1,26 @@ +#ifndef DUSK_IMGUI_SAVEEDITOR_HPP +#define DUSK_IMGUI_SAVEEDITOR_HPP + +#include +#include + +#include "imgui.h" + +namespace dusk { + class ImGuiSaveEditor { + public: + ImGuiSaveEditor(); + + void draw(); + void drawPlayerStatusTab(); + void drawLocationTab(); + void drawInventoryTab(); + void drawFlagsTab(); + void drawConfigTab(); + + private: + int m_selectedRegion = 0; + }; +} + +#endif // DUSK_IMGUI_SAVEEDITOR_HPP From 946d1ae9b7027dc88c2f2824d946cc882f2fc92c Mon Sep 17 00:00:00 2001 From: PJB3005 Date: Mon, 23 Mar 2026 13:34:08 +0100 Subject: [PATCH 3/7] Threading cleanup: remove MallocAllocator stuff Not necessary anymore now that JKRHeap is isolated --- src/dusk/OSMutex.cpp | 53 +++++-------------------------------------- src/dusk/OSThread.cpp | 51 +++++------------------------------------ src/dusk/stubs.cpp | 43 ++++------------------------------- 3 files changed, 16 insertions(+), 131 deletions(-) diff --git a/src/dusk/OSMutex.cpp b/src/dusk/OSMutex.cpp index 55d8ccb52f..8e26402e0d 100644 --- a/src/dusk/OSMutex.cpp +++ b/src/dusk/OSMutex.cpp @@ -14,43 +14,6 @@ #include "JSystem/JKernel/JKRHeap.h" -// ============================================================================ -// Malloc-based allocator to bypass JKRHeap operator new/delete -// Without this, side-table allocations call operator new -> JKRHeap::alloc -// -> OSLockMutex -> GetMutexData -> operator new ... infinite recursion. -// ============================================================================ - -template -struct MallocAllocator { - using value_type = T; - MallocAllocator() = default; - template MallocAllocator(const MallocAllocator&) noexcept {} - T* allocate(std::size_t n) { - void* p = std::malloc(n * sizeof(T)); - if (!p) throw std::bad_alloc(); - return static_cast(p); - } - void deallocate(T* p, std::size_t) noexcept { std::free(p); } - template bool operator==(const MallocAllocator&) const noexcept { return true; } - template bool operator!=(const MallocAllocator&) const noexcept { return false; } -}; - -template -struct MallocDeleter { - void operator()(T* p) const { - p->~T(); - std::free(p); - } -}; - -template -std::unique_ptr> make_malloc_unique(Args&&... args) { - void* mem = std::malloc(sizeof(T)); - if (!mem) throw std::bad_alloc(); - T* obj = JKR_NEW_ARGS (mem) T(std::forward(args)...); - return std::unique_ptr>(obj); -} - // ============================================================================ // Side-table: native mutex per OSMutex // ============================================================================ @@ -59,17 +22,13 @@ struct PCMutexData { std::recursive_mutex nativeMutex; }; -template -using MallocMap = std::unordered_map, std::equal_to, - MallocAllocator>>; - // Lazy-initialized to avoid DLL static init crashes static std::mutex& GetMutexMapMutex() { static std::mutex mtx; return mtx; } -static MallocMap>>& GetMutexMap() { - static MallocMap>> map; +static std::unordered_map>& GetMutexMap() { + static std::unordered_map> map; return map; } @@ -78,7 +37,7 @@ static PCMutexData& GetMutexData(OSMutex* mutex) { auto& map = GetMutexMap(); auto it = map.find(mutex); if (it == map.end()) { - auto result = map.emplace(mutex, make_malloc_unique()); + auto result = map.emplace(mutex, std::make_unique()); return *result.first->second; } return *it->second; @@ -97,8 +56,8 @@ static std::mutex& GetCondMapMutex() { static std::mutex mtx; return mtx; } -static MallocMap>>& GetCondMap() { - static MallocMap>> map; +static std::unordered_map>& GetCondMap() { + static std::unordered_map> map; return map; } @@ -107,7 +66,7 @@ static PCCondData& GetCondData(OSCond* cond) { auto& map = GetCondMap(); auto it = map.find(cond); if (it == map.end()) { - auto result = map.emplace(cond, make_malloc_unique()); + auto result = map.emplace(cond, std::make_unique()); return *result.first->second; } return *it->second; diff --git a/src/dusk/OSThread.cpp b/src/dusk/OSThread.cpp index 2d19139272..0be30f4aaf 100644 --- a/src/dusk/OSThread.cpp +++ b/src/dusk/OSThread.cpp @@ -18,45 +18,6 @@ #include "JSystem/JKernel/JKRHeap.h" -// ============================================================================ -// Malloc-based allocator to bypass JKRHeap operator new/delete -// ============================================================================ - -template -struct MallocAllocator { - using value_type = T; - MallocAllocator() = default; - template MallocAllocator(const MallocAllocator&) noexcept {} - T* allocate(std::size_t n) { - void* p = std::malloc(n * sizeof(T)); - if (!p) throw std::bad_alloc(); - return static_cast(p); - } - void deallocate(T* p, std::size_t) noexcept { std::free(p); } - template bool operator==(const MallocAllocator&) const noexcept { return true; } - template bool operator!=(const MallocAllocator&) const noexcept { return false; } -}; - -template -struct MallocDeleter { - void operator()(T* p) const { - p->~T(); - std::free(p); - } -}; - -template -std::unique_ptr> make_malloc_unique(Args&&... args) { - void* mem = std::malloc(sizeof(T)); - if (!mem) throw std::bad_alloc(); - T* obj = JKR_NEW_ARGS (mem) T(std::forward(args)...); - return std::unique_ptr>(obj); -} - -template -using MallocMap = std::unordered_map, std::equal_to, - MallocAllocator>>; - // ============================================================================ // Side-table: native thread data per OSThread // ============================================================================ @@ -76,8 +37,8 @@ static std::mutex& GetThreadDataMutex() { static std::mutex mtx; return mtx; } -static MallocMap>>& GetThreadDataMap() { - static MallocMap>> map; +static std::unordered_map>& GetThreadDataMap() { + static std::unordered_map> map; return map; } @@ -86,8 +47,8 @@ static std::mutex& GetQueueCvMutex() { static std::mutex mtx; return mtx; } -static MallocMap>>& GetQueueCvMap() { - static MallocMap>> map; +static std::unordered_map>& GetQueueCvMap() { + static std::unordered_map> map; return map; } @@ -96,7 +57,7 @@ static std::condition_variable& GetQueueCV(OSThreadQueue* queue) { auto& map = GetQueueCvMap(); auto it = map.find(queue); if (it == map.end()) { - auto result = map.emplace(queue, make_malloc_unique()); + auto result = map.emplace(queue, std::make_unique()); return *result.first->second; } return *it->second; @@ -295,7 +256,7 @@ int OSCreateThread(OSThread* thread, void* (*func)(void*), void* param, // Create side-table entry (but don't start the thread yet) { - auto data = make_malloc_unique(); + auto data = std::make_unique(); data->func = func; data->param = param; diff --git a/src/dusk/stubs.cpp b/src/dusk/stubs.cpp index 73f4e93d80..f4d1b2688b 100644 --- a/src/dusk/stubs.cpp +++ b/src/dusk/stubs.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -55,42 +56,6 @@ u32 OSGetSoundMode() { // Message Queue (thread-safe implementation) // ========================================================================== -// Malloc-based allocator to bypass JKRHeap operator new/delete -template -struct MallocAllocator { - using value_type = T; - MallocAllocator() = default; - template MallocAllocator(const MallocAllocator&) noexcept {} - T* allocate(std::size_t n) { - void* p = std::malloc(n * sizeof(T)); - if (!p) throw std::bad_alloc(); - return static_cast(p); - } - void deallocate(T* p, std::size_t) noexcept { std::free(p); } - template bool operator==(const MallocAllocator&) const noexcept { return true; } - template bool operator!=(const MallocAllocator&) const noexcept { return false; } -}; - -template -struct MallocDeleter { - void operator()(T* p) const { - p->~T(); - std::free(p); - } -}; - -template -std::unique_ptr> make_malloc_unique(Args&&... args) { - void* mem = std::malloc(sizeof(T)); - if (!mem) throw std::bad_alloc(); - T* obj = new (mem) T(std::forward(args)...); - return std::unique_ptr>(obj); -} - -template -using MallocMap = std::unordered_map, std::equal_to, - MallocAllocator>>; - // Side-table for native synchronization per OSMessageQueue struct PCMessageQueueData { std::mutex mtx; @@ -103,8 +68,8 @@ static std::mutex& GetMsgQueueMapMutex() { static std::mutex mtx; return mtx; } -static MallocMap>>& GetMsgQueueMap() { - static MallocMap>> map; +static std::unordered_map>& GetMsgQueueMap() { + static std::unordered_map> map; return map; } @@ -113,7 +78,7 @@ static PCMessageQueueData& GetMsgQueueData(OSMessageQueue* mq) { auto& map = GetMsgQueueMap(); auto it = map.find(mq); if (it == map.end()) { - auto result = map.emplace(mq, make_malloc_unique()); + auto result = map.emplace(mq, std::make_unique()); return *result.first->second; } return *it->second; From 0148d913e152cc37a9eec688c8426be5730b4283 Mon Sep 17 00:00:00 2001 From: PJB3005 Date: Mon, 23 Mar 2026 13:46:46 +0100 Subject: [PATCH 4/7] Add a bunch of missing imgui close buttons --- src/dusk/imgui/ImGuiMapLoader.cpp | 6 ++---- src/dusk/imgui/ImGuiMenuGame.cpp | 2 +- src/dusk/imgui/ImGuiMenuTools.cpp | 4 ++-- src/dusk/imgui/ImGuiProcessOverlay.cpp | 2 +- src/dusk/imgui/ImGuiSaveEditor.cpp | 4 ++-- src/dusk/imgui/ImGuiSaveEditor.hpp | 2 +- 6 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/dusk/imgui/ImGuiMapLoader.cpp b/src/dusk/imgui/ImGuiMapLoader.cpp index 4b52fd1b04..74e60e4974 100644 --- a/src/dusk/imgui/ImGuiMapLoader.cpp +++ b/src/dusk/imgui/ImGuiMapLoader.cpp @@ -12,19 +12,17 @@ namespace dusk { return; } - ImGuiWindowFlags windowFlags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_AlwaysAutoResize | + ImGuiWindowFlags windowFlags = ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav; ImGui::SetNextWindowBgAlpha(0.65f); ImGui::SetNextWindowSizeConstraints(ImVec2(300, 0), ImVec2(FLT_MAX, FLT_MAX)); - if (!ImGui::Begin("Map Loader", nullptr, windowFlags)) { + if (!ImGui::Begin("Map Loader", &m_showMapLoader, windowFlags)) { ImGui::End(); return; } - ImGui::SeparatorText("Map Loader"); - ImGui::Checkbox("Show Internal Names", &m_mapLoaderInfo.showInternalNames); const char* previewRegion = "None"; diff --git a/src/dusk/imgui/ImGuiMenuGame.cpp b/src/dusk/imgui/ImGuiMenuGame.cpp index 2366fb6a42..a0b79579eb 100644 --- a/src/dusk/imgui/ImGuiMenuGame.cpp +++ b/src/dusk/imgui/ImGuiMenuGame.cpp @@ -110,7 +110,7 @@ namespace dusk { ImGui::SetNextWindowBgAlpha(0.65f); ImGui::SetNextWindowSizeConstraints(ImVec2(850, 400), ImVec2(850, 400)); - if (!ImGui::Begin("Controller Config", nullptr, windowFlags)) { + if (!ImGui::Begin("Controller Config", &m_showControllerConfig, windowFlags)) { ImGui::End(); return; } diff --git a/src/dusk/imgui/ImGuiMenuTools.cpp b/src/dusk/imgui/ImGuiMenuTools.cpp index d848690063..e84dbc1f08 100644 --- a/src/dusk/imgui/ImGuiMenuTools.cpp +++ b/src/dusk/imgui/ImGuiMenuTools.cpp @@ -61,7 +61,7 @@ namespace dusk { ShowPlayerInfo(); if (m_showSaveEditor) { - m_saveEditor.draw(); + m_saveEditor.draw(m_showSaveEditor); } DuskDebugPad(); // temporary, remove later @@ -141,7 +141,7 @@ namespace dusk { ImGui::SetNextWindowBgAlpha(0.65f); ImGui::SetNextWindowSizeConstraints(ImVec2(300, 200), ImVec2(300, 200)); - if (ImGui::Begin("Player Info", nullptr, windowFlags)) { + if (ImGui::Begin("Player Info", &m_showPlayerInfo, windowFlags)) { daAlink_c* player = (daAlink_c*)dComIfGp_getPlayer(0); daHorse_c* horse = dComIfGp_getHorseActor(); diff --git a/src/dusk/imgui/ImGuiProcessOverlay.cpp b/src/dusk/imgui/ImGuiProcessOverlay.cpp index cf2d22402e..04a87f00b6 100644 --- a/src/dusk/imgui/ImGuiProcessOverlay.cpp +++ b/src/dusk/imgui/ImGuiProcessOverlay.cpp @@ -74,7 +74,7 @@ namespace dusk { return; } - if (ImGui::Begin("Processes")) { + if (ImGui::Begin("Processes", &m_showProcessManagement)) { if (ImGui::BeginTabBar("Tabs")) { showTreeRecursive = true; if (ImGui::BeginTabItem("Tree")) { diff --git a/src/dusk/imgui/ImGuiSaveEditor.cpp b/src/dusk/imgui/ImGuiSaveEditor.cpp index b21196fa54..00cadfaa4a 100644 --- a/src/dusk/imgui/ImGuiSaveEditor.cpp +++ b/src/dusk/imgui/ImGuiSaveEditor.cpp @@ -272,14 +272,14 @@ namespace dusk { ImGuiSaveEditor::ImGuiSaveEditor() {} - void ImGuiSaveEditor::draw() { + void ImGuiSaveEditor::draw(bool& open) { ImGuiIO& io = ImGui::GetIO(); ImGuiWindowFlags windowFlags = ImGuiWindowFlags_NoResize; ImGui::SetNextWindowBgAlpha(0.65f); ImGui::SetNextWindowSizeConstraints(ImVec2(600, 700), ImVec2(600, 700)); - if (ImGui::Begin("Save Editor", nullptr, windowFlags)) { + if (ImGui::Begin("Save Editor", &open, windowFlags)) { if (ImGui::BeginTabBar("SaveEditorTabBar", ImGuiTabBarFlags_NoCloseWithMiddleMouseButton)) { if (ImGui::BeginTabItem("Player Status")) { drawPlayerStatusTab(); diff --git a/src/dusk/imgui/ImGuiSaveEditor.hpp b/src/dusk/imgui/ImGuiSaveEditor.hpp index f6668a75db..3afc1b8145 100644 --- a/src/dusk/imgui/ImGuiSaveEditor.hpp +++ b/src/dusk/imgui/ImGuiSaveEditor.hpp @@ -11,7 +11,7 @@ namespace dusk { public: ImGuiSaveEditor(); - void draw(); + void draw(bool& open); void drawPlayerStatusTab(); void drawLocationTab(); void drawInventoryTab(); From a7fbdd6ece979d6e5cc1b8cc272a9e82cae1db51 Mon Sep 17 00:00:00 2001 From: PJB3005 Date: Mon, 23 Mar 2026 13:53:23 +0100 Subject: [PATCH 5/7] Add note about `DUSK_SELECTED_OPT` to README --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 53a726fac7..200913770a 100644 --- a/README.md +++ b/README.md @@ -68,3 +68,6 @@ Pass the disc image as a positional argument. Supported formats: ISO (GCM), RVZ, build/dusk/dusk /path/to/game.rvz ``` If no path is specified, Dusk defaults to `game.iso` in the current working directory. + +#### 30 FPS on Debug +When compiled fully in a Debug the game runs too slowly to hit playable 30 FPS. To avoid this, you can set a CMake cache variable to optimize specific critical files without hampering debuggability in the rest of the program: `-DDUSK_SELECTED_OPT=ON`. When building for MSVC (Windows) you must also modify `CMAKE_CXX_FLAGS_DEBUG` and `CMAKE_C_FLAGS_DEBUG` to remove `/RTC1` from the flags, like so: `-DCMAKE_CXX_FLAGS_DEBUG="/MDd /Zi /Ob0 /Od" -DCMAKE_C_FLAGS_DEBUG="/MDd /Zi /Ob0 /Od"` From 2a02ab7f099915297c4c5756e23aa95ae1c4b5a9 Mon Sep 17 00:00:00 2001 From: madeline Date: Mon, 23 Mar 2026 22:16:57 -0700 Subject: [PATCH 6/7] fuck interrupts --- src/dusk/OSThread.cpp | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/src/dusk/OSThread.cpp b/src/dusk/OSThread.cpp index 0be30f4aaf..c88126bd52 100644 --- a/src/dusk/OSThread.cpp +++ b/src/dusk/OSThread.cpp @@ -610,24 +610,14 @@ s32 OSEnableScheduler(void) { // ============================================================================ BOOL OSDisableInterrupts(void) { - GetInterruptMutex().lock(); - sInterruptLockCount++; - return (BOOL)(sInterruptLockCount > 1); // TRUE if was already locked + return FALSE; } BOOL OSRestoreInterrupts(BOOL level) { - if (sInterruptLockCount > 0) { - sInterruptLockCount--; - GetInterruptMutex().unlock(); - } - return level; + return FALSE; } BOOL OSEnableInterrupts(void) { - if (sInterruptLockCount > 0) { - sInterruptLockCount--; - GetInterruptMutex().unlock(); - } return FALSE; } From a1f78609d843abc4760bac0180ff012edcc34322 Mon Sep 17 00:00:00 2001 From: madeline Date: Mon, 23 Mar 2026 23:17:26 -0700 Subject: [PATCH 7/7] turn on background input --- src/m_Do/m_Do_main.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/m_Do/m_Do_main.cpp b/src/m_Do/m_Do_main.cpp index 20fc2a8aee..a2fe24771d 100644 --- a/src/m_Do/m_Do_main.cpp +++ b/src/m_Do/m_Do_main.cpp @@ -272,6 +272,7 @@ int game_main(int argc, char* argv[]) { config.logLevel = (AuroraLogLevel)parsed_arg_options["log-level"].as(); config.mem1Size = 256 * 1024 * 1024; config.mem2Size = 24 * 1024 * 1024; + config.allowJoystickBackgroundEvents = true; auroraInfo = aurora_initialize(argc, argv, &config);