diff --git a/Source/Contents/Configuration/ServiceOptions.cpp b/Source/Contents/Configuration/ServiceOptions.cpp index acef270..e5b9780 100644 --- a/Source/Contents/Configuration/ServiceOptions.cpp +++ b/Source/Contents/Configuration/ServiceOptions.cpp @@ -1,5 +1,8 @@ #include "Contents/Configuration/ServiceOptions.h" +// GLOBAL: gl_24579 +ServiceOptions g_serviceOptions; + // OFFSET: 0x006C17A0 // FUNCTION: fn_06318 unsigned char ServiceOptions::Get(int id) const { diff --git a/Source/Contents/Configuration/ServiceOptions.h b/Source/Contents/Configuration/ServiceOptions.h index fa2a9e9..d846d48 100644 --- a/Source/Contents/Configuration/ServiceOptions.h +++ b/Source/Contents/Configuration/ServiceOptions.h @@ -10,10 +10,16 @@ enum ServiceOption : int { ConfineCursor = 271 }; bool IsServiceOption(int id); struct ServiceOptions { - std::unordered_map& values; + /* 0000 */ std::unordered_map values; unsigned char Get(int id) const; bool Set(int id, unsigned char value); }; +extern ServiceOptions g_serviceOptions; + +#if defined(_WIN32) && !defined(_WIN64) +static_assert(sizeof(ServiceOptions) == 0x20); +#endif + #endif diff --git a/Source/UI/Layout/SnapMgr.cpp b/Source/UI/Layout/SnapMgr.cpp index c96cc49..9492968 100644 --- a/Source/UI/Layout/SnapMgr.cpp +++ b/Source/UI/Layout/SnapMgr.cpp @@ -12,9 +12,8 @@ bool g_snapEnabled = true; // STATIC: 0x013346A4 // GLOBAL: gl_21917 int g_snapDirection = 1; -// STATIC: 0x013346B0 -// GLOBAL: gl_21919 -SnapObject* g_snapBoundary = nullptr; +// GLOBAL: gl_24655 +CSnapMgr g_snapMgr; namespace { // INLINED @@ -264,12 +263,12 @@ void CSnapMgr::MoveEdge(UIWindow* window, int dx, int dy, int side, WindowSnappi const int candidateBottom = ((object->window->geometry.y - dy) + down); const int screenHeight = snapping.screenHeight; - if (((y + height) - up) != 0 && (!g_snapBoundary || g_snapBoundary != object || candidateBottom == screenHeight)) { + if (((y + height) - up) != 0 && (!g_snapMgr.root || g_snapMgr.root != object || candidateBottom == screenHeight)) { bool moveSelf = side != 3; if (side == 3) { - bool boundaryAncestor = g_snapBoundary == object; + bool boundaryAncestor = g_snapMgr.root == object; if (!boundaryAncestor) { - for (SnapObject* next : g_snapBoundary->edges[1]) { + for (SnapObject* next : g_snapMgr.root->edges[1]) { if (next == object) { boundaryAncestor = true; break; diff --git a/Source/UI/Layout/SnapMgr.h b/Source/UI/Layout/SnapMgr.h index e03d8a0..d941072 100644 --- a/Source/UI/Layout/SnapMgr.h +++ b/Source/UI/Layout/SnapMgr.h @@ -40,7 +40,7 @@ private: extern const int g_snapOppositeSide[4]; extern bool g_snapEnabled; extern int g_snapDirection; -extern SnapObject* g_snapBoundary; +extern CSnapMgr g_snapMgr; #if defined(_WIN32) && !defined(_WIN64) static_assert(sizeof(CSnapMgr) == 16); diff --git a/Source/UI/Window/MiniPartyWndAreaMgr.h b/Source/UI/Window/MiniPartyWndAreaMgr.h new file mode 100644 index 0000000..4916b03 --- /dev/null +++ b/Source/UI/Window/MiniPartyWndAreaMgr.h @@ -0,0 +1,30 @@ +#ifndef RAGNAROK_SOURCE_UI_WINDOW_MINIPARTYWNDAREAMGR_H +#define RAGNAROK_SOURCE_UI_WINDOW_MINIPARTYWNDAREAMGR_H + +#include +#include +#include + +class CMiniPartyWndAreaMgr { +public: + /* 0004 */ RECT area; + /* 0014 */ int columns; + /* 0018 */ int rows; + /* 001C */ std::vector excluded; + /* 0028 */ std::vector available; + + // INLINED + virtual ~CMiniPartyWndAreaMgr() = default; + + CMiniPartyWndAreaMgr(); +}; + +extern CMiniPartyWndAreaMgr* g_miniPartyWndAreaMgr; + +#if defined(_WIN32) && !defined(_WIN64) +static_assert(offsetof(CMiniPartyWndAreaMgr, excluded) == 0x1C); +static_assert(offsetof(CMiniPartyWndAreaMgr, available) == 0x28); +static_assert(sizeof(CMiniPartyWndAreaMgr) == 0x34); +#endif + +#endif diff --git a/Source/UI/Window/UIWindowMgr.cpp b/Source/UI/Window/UIWindowMgr.cpp index 8c3cae6..73c4a5a 100644 --- a/Source/UI/Window/UIWindowMgr.cpp +++ b/Source/UI/Window/UIWindowMgr.cpp @@ -1,8 +1,25 @@ +#include "Client/Browser/WebBrowser.h" #include "Client/Mode/ActiveGameMode.h" #include "Client/Replay.h" #include "Contents/Configuration/ServiceConfiguration.h" +#include "Contents/Configuration/ServiceOptions.h" +#include "UI/Layout/SnapMgr.h" +#include "UI/Layout/WindowSnapping.h" +#include "UI/Lists/UIDropDownBox.h" +#include "UI/Window/MiniPartyWndAreaMgr.h" +#include "UI/Window/UIWindow.h" +#include "UI/Window/WindowRetirement.h" #include "UI/Window/UIWindowMgr.h" +#include +#include + +// GLOBAL: gl_24525 +CMiniPartyWndAreaMgr* g_miniPartyWndAreaMgr = nullptr; + +// GLOBAL: gl_24366 +UIWindowMgr g_windowMgr; + // OFFSET: 0x00A94FD0 // FUNCTION: fn_17179 void UIWindowMgr::InitializeWindowPolicy() { @@ -527,3 +544,86 @@ UIWindowMgr::UIWindowMgr() this->unknown_4F23C = 37; } +// OFFSET: 0x007375E0 +// FUNCTION: fn_07649 +CMiniPartyWndAreaMgr::CMiniPartyWndAreaMgr() { + SetRect(&this->area, 0, 0, g_windowMgr.unknown_047C, g_windowMgr.unknown_0480); +} + +// OFFSET: 0x00AA66D0 +// FUNCTION: fn_17233 +void UIWindowMgr::Shutdown() { + if (!this->modalWindows.empty() && this->modalWindows.back()) { + this->activeWindowId = 185; + } + + if (this->window_0A30 && this->window_0A30->geometry.visible) { + static_cast(this->window_0A30)->Detach(); + this->window_0A30->Show(0); + } + + for (UIWindow*& window : this->rendered) { + if (!this->modalWindows.empty() && this->modalWindows.back() && this->persistentWindows.find(window) != this->persistentWindows.end()) { + this->retainedPersistentWindow = true; + } else if (this->modalWindows.empty() || !this->modalWindows.back() || + std::find(this->modalWindows.begin(), this->modalWindows.end(), window) == this->modalWindows.end()) { + this->persistentWindows.erase(window); + window->Slot11(); + delete window; + window = nullptr; + } + } + + for (auto& entry : this->browsers) { + delete entry.second; + entry.second = nullptr; + } + this->browsers.clear(); + if (this->browser_09D0) { + delete this->browser_09D0; + this->browser_09D0 = nullptr; + } + + for (auto entry = this->overlays.begin(); entry != this->overlays.end();) { + delete entry->second; + entry = this->overlays.erase(entry); + } + this->rendered.clear(); + this->retired.clear(); + this->snapRectangles.clear(); + this->messageBoxes.clear(); + this->ResetWindows(); + + for (UIWindow*& window : this->snapExcluded) { + const bool snappingEnabled = g_serviceOptions.Get(141) != 0; + WindowSnapping snapping{g_snapMgr, this->snapRectangles, this->snapExcluded, snappingEnabled, this->unknown_047C, this->unknown_0480}; + WindowRetirement retirement{this->rendered, this->retired, this->overlays, snapping, this->window_03D4, this->window_03D8, + this->window_03DC, this->window_01B8, this->window_4F2AC}; + retirement.Destroy(window); + window = nullptr; + } + this->snapExcluded.clear(); +} + +// OFFSET: 0x00A8A1C0 +// FUNCTION: fn_17099 +UIWindowMgr::~UIWindowMgr() { + if (!g_miniPartyWndAreaMgr) { + g_miniPartyWndAreaMgr = new (std::nothrow) CMiniPartyWndAreaMgr; + } + if (g_miniPartyWndAreaMgr) { + delete g_miniPartyWndAreaMgr; + g_miniPartyWndAreaMgr = nullptr; + } + + this->Shutdown(); + if (this->unknown_0478) { + delete this->unknown_0478; + this->unknown_0478 = nullptr; + } + for (auto& entry : this->savedRectangles) { + delete entry.second; + } + this->savedRectangles.clear(); +} + diff --git a/Source/UI/Window/UIWindowMgr.h b/Source/UI/Window/UIWindowMgr.h index 22279f6..575de77 100644 --- a/Source/UI/Window/UIWindowMgr.h +++ b/Source/UI/Window/UIWindowMgr.h @@ -416,9 +416,12 @@ public: void InitializeWindowPolicy(); void ResetWindows(); + void Shutdown(); UIWindow* LookupWindow(int id); }; +extern UIWindowMgr g_windowMgr; + #if defined(_WIN32) && !defined(_WIN64) static_assert(sizeof(WindowTextEntry) == 0x1C); static_assert(sizeof(WindowTextRecord) == 0x20);