From ee7241f73de4e1ab0d34be5c22918fc7d73addfe Mon Sep 17 00:00:00 2001 From: MS Date: Fri, 19 Jan 2024 15:23:12 -0500 Subject: [PATCH 1/9] GifManager: use STL members (#460) * Truncate symbol names to 255 characters when matching * GifManager refactor * Refactor, annotations --------- Co-authored-by: Christian Semmler --- LEGO1/lego/legoomni/include/gifmanager.h | 136 +++++++++++++----- LEGO1/lego/legoomni/src/common/gifmanager.cpp | 71 ++++++--- LEGO1/lego/legoomni/src/infocenter/score.cpp | 3 +- tools/isledecomp/isledecomp/compare/db.py | 6 + 4 files changed, 158 insertions(+), 58 deletions(-) diff --git a/LEGO1/lego/legoomni/include/gifmanager.h b/LEGO1/lego/legoomni/include/gifmanager.h index aa6d2d80..898ab1fb 100644 --- a/LEGO1/lego/legoomni/include/gifmanager.h +++ b/LEGO1/lego/legoomni/include/gifmanager.h @@ -3,73 +3,139 @@ #include "compat.h" #include "decomp.h" +#include "mxstl/stlcompat.h" #include "mxtypes.h" #include #include +#pragma warning(disable : 4237) + +// SIZE 0x14 struct GifData { public: - const char* m_name; - LPDIRECTDRAWSURFACE m_surface; - LPDIRECTDRAWPALETTE m_palette; - LPDIRECT3DRMTEXTURE2 m_texture; - MxU8* m_data; + char* m_name; // 0x00 + LPDIRECTDRAWSURFACE m_surface; // 0x04 + LPDIRECTDRAWPALETTE m_palette; // 0x08 + LPDIRECT3DRMTEXTURE2 m_texture; // 0x0c + MxU8* m_data; // 0x10 + + ~GifData(); }; -struct GifMapEntry { -public: - GifMapEntry* m_right; - GifMapEntry* m_parent; - GifMapEntry* m_left; - const char* m_key; - GifData* m_value; +struct GifMapComparator { + bool operator()(const char* const& p_key0, const char* const& p_key1) const { return strcmp(p_key0, p_key1) > 0; } }; -class GifMap { -public: - GifMapEntry* FindNode(const char*& p_string); - - inline GifData* Get(const char* p_string) - { - GifData* ret = NULL; - GifMapEntry* entry = FindNode(p_string); - if (((m_unk0x4 == entry || strcmp(p_string, entry->m_key) > 0) ? m_unk0x4 : entry) != entry) - ret = entry->m_value; - return ret; - } - - undefined4 m_unk0x0; - GifMapEntry* m_unk0x4; +// SIZE 0x10 +class GifMap : public map { + // SYNTHETIC: LEGO1 0x1005a400 + // GifMap::~GifMap }; +typedef list GifList; + // VTABLE: LEGO1 0x100d86d4 +// SIZE 0x18 class GifManagerBase { public: - // STUB: LEGO1 0x1005b660 - virtual ~GifManagerBase() {} + // FUNCTION: LEGO1 0x1005b660 + virtual ~GifManagerBase() + { + GifMap::iterator it; + for (it = m_map.begin(); it != m_map.end(); it++) { + // DECOMP: Use of const_cast here matches ~ViewLODListManager from 96 source. + const char* const& key = (*it).first; + delete[] const_cast(key); + + if (m_ownership) { + delete (*it).second; // GifData* + } + } + } + + inline GifData* Get(const char* p_name) + { + GifMap::iterator it = m_map.find(p_name); + if (it != m_map.end()) { + return (*it).second; + } + + return NULL; + } // SYNTHETIC: LEGO1 0x1005a310 // GifManagerBase::`scalar deleting destructor' - inline GifData* Get(const char* p_name) { return m_unk0x8.Get(p_name); } - protected: - undefined4 m_unk0x0; - undefined4 m_unk0x4; - GifMap m_unk0x8; + MxBool m_ownership; // 0x04 + GifMap m_map; // 0x08 }; // VTABLE: LEGO1 0x100d86fc +// SIZE 0x24 class GifManager : public GifManagerBase { public: + GifManager() { m_ownership = TRUE; }; virtual ~GifManager() override; // SYNTHETIC: LEGO1 0x1005a580 // GifManager::`scalar deleting destructor' + void FUN_10099cc0(GifData* p_data); + protected: - undefined m_unk0x14[0x1c]; + GifList m_list; // 0x18 }; +// TEMPLATE: LEGO1 0x10059c50 +// allocator::_Charalloc + +// clang-format off +// TEMPLATE: LEGO1 0x10001cc0 +// _Tree,map >::_Kfn,GifMapComparator,allocator >::_Lbound + +// TEMPLATE: LEGO1 0x1004f9b0 +// _Tree,map >::_Kfn,GifMapComparator,allocator >::_Insert + +// TEMPLATE: LEGO1 0x10059c70 +// _Tree,map >::_Kfn,GifMapComparator,allocator >::_Color + +// TEMPLATE: LEGO1 0x10059c80 +// _Tree,map >::_Kfn,GifMapComparator,allocator >::_Left + +// TEMPLATE: LEGO1 0x10059c90 +// _Tree,map >::_Kfn,GifMapComparator,allocator >::_Parent + +// TEMPLATE: LEGO1 0x10059ca0 +// _Tree,map >::_Kfn,GifMapComparator,allocator >::_Right + +// TEMPLATE: LEGO1 0x10059cb0 +// _Tree,map >::_Kfn,GifMapComparator,allocator >::~_Tree,map >::_Kfn,GifMapComparator,allocator > + +// TEMPLATE: LEGO1 0x10059d80 +// _Tree,map >::_Kfn,GifMapComparator,allocator >::iterator::_Inc + +// TEMPLATE: LEGO1 0x10059dc0 +// _Tree,map >::_Kfn,GifMapComparator,allocator >::erase + +// TEMPLATE: LEGO1 0x1005a210 +// _Tree,map >::_Kfn,GifMapComparator,allocator >::_Erase + +// TEMPLATE: LEGO1 0x1005a250 +// list >::~list > + +// TEMPLATE: LEGO1 0x1005a2c0 +// map >::~map > + +// TEMPLATE: LEGO1 0x1005a450 +// Map::~Map + +// TEMPLATE: LEGO1 0x1005a5a0 +// List::~List + +// GLOBAL: LEGO1 0x100f0100 +// _Tree,map >::_Kfn,GifMapComparator,allocator >::_Nil +// clang-format on + #endif // GIFMANAGER_H diff --git a/LEGO1/lego/legoomni/src/common/gifmanager.cpp b/LEGO1/lego/legoomni/src/common/gifmanager.cpp index c83714d4..cd485b11 100644 --- a/LEGO1/lego/legoomni/src/common/gifmanager.cpp +++ b/LEGO1/lego/legoomni/src/common/gifmanager.cpp @@ -1,32 +1,61 @@ #include "gifmanager.h" DECOMP_SIZE_ASSERT(GifData, 0x14); -DECOMP_SIZE_ASSERT(GifMapEntry, 0x14); -DECOMP_SIZE_ASSERT(GifMap, 0x08); -DECOMP_SIZE_ASSERT(GifManagerBase, 0x14); -DECOMP_SIZE_ASSERT(GifManager, 0x30); +DECOMP_SIZE_ASSERT(GifMap, 0x10); +DECOMP_SIZE_ASSERT(GifManagerBase, 0x18); +DECOMP_SIZE_ASSERT(GifManager, 0x24); -// GLOBAL: LEGO1 0x100f0100 -GifMapEntry* g_unk0x100f0100; - -// FUNCTION: LEGO1 0x10001cc0 -GifMapEntry* GifMap::FindNode(const char*& p_string) +// FUNCTION: LEGO1 0x10065c00 +GifData::~GifData() { - GifMapEntry* ret = m_unk0x4; - GifMapEntry* current = ret->m_parent; - while (current != g_unk0x100f0100) { - if (strcmp(current->m_key, p_string) <= 0) { - ret = current; - current = current->m_right; - } - else - current = current->m_left; + if (m_name) { + delete[] m_name; + m_name = NULL; + } + + if (m_palette) { + m_palette->Release(); + m_palette = NULL; + } + + if (m_surface) { + m_surface->Release(); + m_surface = NULL; + } + + if (m_texture) { + m_texture->Release(); + m_texture = NULL; } - return ret; } -// STUB: LEGO1 0x10099870 +// FUNCTION: LEGO1 0x10099870 GifManager::~GifManager() { - // TODO +} + +// FUNCTION: LEGO1 0x10099cc0 +void GifManager::FUN_10099cc0(GifData* p_data) +{ + if (p_data == NULL) + return; + +#ifdef COMPAT_MODE + GifList::iterator it; + for (it = m_list.begin(); it != m_list.end(); it++) { +#else + for (GifList::iterator it = m_list.begin(); it != m_list.end(); it++) { +#endif + if (*it == p_data) { + // TODO: This is wrong, but what is at +0xc on the iterator? + *it = NULL; + + if (p_data->m_texture->Release() == TRUE) { + delete p_data; + m_list.erase(it); + } + + return; + } + } } diff --git a/LEGO1/lego/legoomni/src/infocenter/score.cpp b/LEGO1/lego/legoomni/src/infocenter/score.cpp index c1bba3e6..5a7a95a3 100644 --- a/LEGO1/lego/legoomni/src/infocenter/score.cpp +++ b/LEGO1/lego/legoomni/src/infocenter/score.cpp @@ -227,8 +227,7 @@ void Score::VTable0x68(MxBool p_add) // FUNCTION: LEGO1 0x100019d0 void Score::Paint() { - GifManager* gm = GetGifManager(); - GifData* gd = gm->Get("bigcube.gif"); + GifData* gd = GetGifManager()->Get("bigcube.gif"); if (gd) { RaceState* l78 = (RaceState*) GameState()->GetState("JetskiRaceState"); diff --git a/tools/isledecomp/isledecomp/compare/db.py b/tools/isledecomp/isledecomp/compare/db.py index dea2b590..43d6811b 100644 --- a/tools/isledecomp/isledecomp/compare/db.py +++ b/tools/isledecomp/isledecomp/compare/db.py @@ -170,6 +170,12 @@ def skip_compare(self, orig: int): def _match_on(self, compare_type: SymbolType, addr: int, name: str) -> bool: # Update the compare_type here too since the marker tells us what we should do + + # Truncate the name to 255 characters. It will not be possible to match a name + # longer than that because MSVC truncates the debug symbols to this length. + # See also: warning C4786. + name = name[:255] + logger.debug("Looking for %s %s", compare_type.name.lower(), name) cur = self._db.execute( """UPDATE `symbols` From 1c4f772a82feedf36505eb11f4e3df72e8175de8 Mon Sep 17 00:00:00 2001 From: Christian Semmler Date: Fri, 19 Jan 2024 17:06:39 -0500 Subject: [PATCH 2/9] Implement/match MxOmni::ActionSourceEquals (#462) --- LEGO1/omni/include/mxomni.h | 2 +- LEGO1/omni/src/main/mxomni.cpp | 23 ++++++++++++++++++----- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/LEGO1/omni/include/mxomni.h b/LEGO1/omni/include/mxomni.h index 52faf709..9ade97b3 100644 --- a/LEGO1/omni/include/mxomni.h +++ b/LEGO1/omni/include/mxomni.h @@ -57,7 +57,7 @@ class MxOmni : public MxCore { virtual MxBool IsTimerRunning() { return m_timerRunning; }; // vtable+40 static void SetInstance(MxOmni* p_instance); - static MxBool FUN_100b06b0(MxDSAction* p_action, const char* p_name); + static MxBool ActionSourceEquals(MxDSAction* p_action, const char* p_name); HWND GetWindowHandle() const { return this->m_windowHandle; } MxObjectFactory* GetObjectFactory() const { return this->m_objectFactory; } diff --git a/LEGO1/omni/src/main/mxomni.cpp b/LEGO1/omni/src/main/mxomni.cpp index 6df6d009..f9fa5733 100644 --- a/LEGO1/omni/src/main/mxomni.cpp +++ b/LEGO1/omni/src/main/mxomni.cpp @@ -3,6 +3,7 @@ #include "mxactionnotificationparam.h" #include "mxatomidcounter.h" #include "mxautolocker.h" +#include "mxdsmultiaction.h" #include "mxeventmanager.h" #include "mxmusicmanager.h" #include "mxnotificationmanager.h" @@ -377,11 +378,23 @@ void MxOmni::DestroyInstance() } } -// STUB: LEGO1 0x100b06b0 -MxBool MxOmni::FUN_100b06b0(MxDSAction* p_action, const char* p_name) +// FUNCTION: LEGO1 0x100b06b0 +MxBool MxOmni::ActionSourceEquals(MxDSAction* p_action, const char* p_name) { - // TODO - return FAILURE; + if (!strcmp(p_action->GetSourceName(), p_name)) + return TRUE; + + if (p_action->IsA("MxDSMultiAction")) { + MxDSActionListCursor cursor(((MxDSMultiAction*) p_action)->GetActionList()); + MxDSAction* action; + + while (cursor.Next(action)) { + if (ActionSourceEquals(action, p_name)) + return TRUE; + } + } + + return FALSE; } // FUNCTION: LEGO1 0x100b07f0 @@ -404,7 +417,7 @@ MxLong MxOmni::HandleActionEnd(MxParam& p_param) if (controller != NULL) { action = controller->GetUnk0x54().Find(action, FALSE); if (action) { - if (FUN_100b06b0(action, "LegoLoopingAnimPresenter") == FALSE) { + if (ActionSourceEquals(action, "LegoLoopingAnimPresenter") == FALSE) { delete controller->GetUnk0x54().Find(action, TRUE); } } From 701c700d69973b90dab089e8e97b883ac0a31f1c Mon Sep 17 00:00:00 2001 From: Christian Semmler Date: Fri, 19 Jan 2024 17:11:51 -0500 Subject: [PATCH 3/9] Add library symbols for flic and smack (#461) --- 3rdparty/flic/flic.asm | 77 ++++++++++++++--------------------- 3rdparty/flic/flic.lib | Bin 2876 -> 2940 bytes LEGO1/library_flic.h | 6 +++ LEGO1/library_smack.h | 18 ++++++++ LEGO1/omni/include/mxsmack.h | 9 ---- 5 files changed, 54 insertions(+), 56 deletions(-) create mode 100644 LEGO1/library_flic.h create mode 100644 LEGO1/library_smack.h diff --git a/3rdparty/flic/flic.asm b/3rdparty/flic/flic.asm index ef402a14..44f42086 100644 --- a/3rdparty/flic/flic.asm +++ b/3rdparty/flic/flic.asm @@ -6,7 +6,10 @@ assume fs:nothing public DecodeFLCFrame -.text SEGMENT PARA PUBLIC 'CODE' +; This is so reccmp can detect the end of DecodeFLCFrame +public EndOfSection + +.text SEGMENT BYTE PUBLIC 'CODE' ?_25162 LABEL NEAR mov ax, word ptr [esp+0CH] ; 100BD530 _ 66: 8B. 44 24, 0C @@ -37,10 +40,8 @@ public DecodeFLCFrame ; Filling space: 0DH ; Filler type: INT 3 Debug breakpoint -; db 0CCH, 0CCH, 0CCH, 0CCH, 0CCH, 0CCH, 0CCH, 0CCH -; db 0CCH, 0CCH, 0CCH, 0CCH, 0CCH - -ALIGN 16 + db 0CCH, 0CCH, 0CCH, 0CCH, 0CCH, 0CCH, 0CCH, 0CCH + db 0CCH, 0CCH, 0CCH, 0CCH, 0CCH ?_25164 LABEL NEAR lea eax, [esp+18H] ; 100BD580 _ 8D. 44 24, 18 @@ -89,10 +90,8 @@ ALIGN 16 ; Filling space: 0CH ; Filler type: INT 3 Debug breakpoint -; db 0CCH, 0CCH, 0CCH, 0CCH, 0CCH, 0CCH, 0CCH, 0CCH -; db 0CCH, 0CCH, 0CCH, 0CCH - -ALIGN 16 + db 0CCH, 0CCH, 0CCH, 0CCH, 0CCH, 0CCH, 0CCH, 0CCH + db 0CCH, 0CCH, 0CCH, 0CCH ?_25168 LABEL NEAR mov ecx, dword ptr [esp+8H] ; 100BD600 _ 8B. 4C 24, 08 @@ -149,9 +148,7 @@ ALIGN 16 ; Filling space: 8H ; Filler type: INT 3 Debug breakpoint -; db 0CCH, 0CCH, 0CCH, 0CCH, 0CCH, 0CCH, 0CCH, 0CCH - -ALIGN 16 + db 0CCH, 0CCH, 0CCH, 0CCH, 0CCH, 0CCH, 0CCH, 0CCH ?_25173 LABEL NEAR lea eax, [esp+18H] ; 100BD680 _ 8D. 44 24, 18 @@ -188,10 +185,8 @@ ALIGN 16 ; Filling space: 0AH ; Filler type: INT 3 Debug breakpoint -; db 0CCH, 0CCH, 0CCH, 0CCH, 0CCH, 0CCH, 0CCH, 0CCH -; db 0CCH, 0CCH - -ALIGN 16 + db 0CCH, 0CCH, 0CCH, 0CCH, 0CCH, 0CCH, 0CCH, 0CCH + db 0CCH, 0CCH ?_25176 LABEL NEAR lea eax, [esp+18H] ; 100BD6E0 _ 8D. 44 24, 18 @@ -238,9 +233,7 @@ ALIGN 16 ; Filling space: 3H ; Filler type: INT 3 Debug breakpoint -; db 0CCH, 0CCH, 0CCH - -ALIGN 8 + db 0CCH, 0CCH, 0CCH ?_25180 LABEL NEAR mov eax, dword ptr [esp+18H] ; 100BD760 _ 8B. 44 24, 18 @@ -373,10 +366,8 @@ ALIGN 8 ; Filling space: 0DH ; Filler type: INT 3 Debug breakpoint -; db 0CCH, 0CCH, 0CCH, 0CCH, 0CCH, 0CCH, 0CCH, 0CCH -; db 0CCH, 0CCH, 0CCH, 0CCH, 0CCH - -ALIGN 16 + db 0CCH, 0CCH, 0CCH, 0CCH, 0CCH, 0CCH, 0CCH, 0CCH + db 0CCH, 0CCH, 0CCH, 0CCH, 0CCH ?_25195 LABEL NEAR mov eax, dword ptr [esp+8H] ; 100BD8A0 _ 8B. 44 24, 08 @@ -447,9 +438,7 @@ ALIGN 16 ; Filling space: 8H ; Filler type: INT 3 Debug breakpoint -; db 0CCH, 0CCH, 0CCH, 0CCH, 0CCH, 0CCH, 0CCH, 0CCH - -ALIGN 16 + db 0CCH, 0CCH, 0CCH, 0CCH, 0CCH, 0CCH, 0CCH, 0CCH ?_25202 LABEL NEAR mov eax, dword ptr [esp+8H] ; 100BD940 _ 8B. 44 24, 08 @@ -462,10 +451,8 @@ ALIGN 16 ; Filling space: 0DH ; Filler type: INT 3 Debug breakpoint -; db 0CCH, 0CCH, 0CCH, 0CCH, 0CCH, 0CCH, 0CCH, 0CCH -; db 0CCH, 0CCH, 0CCH, 0CCH, 0CCH - -ALIGN 16 + db 0CCH, 0CCH, 0CCH, 0CCH, 0CCH, 0CCH, 0CCH, 0CCH + db 0CCH, 0CCH, 0CCH, 0CCH, 0CCH ?_25203 LABEL NEAR mov eax, dword ptr [esp+10H] ; 100BD960 _ 8B. 44 24, 10 @@ -539,10 +526,8 @@ ALIGN 16 ; Filling space: 0CH ; Filler type: INT 3 Debug breakpoint -; db 0CCH, 0CCH, 0CCH, 0CCH, 0CCH, 0CCH, 0CCH, 0CCH -; db 0CCH, 0CCH, 0CCH, 0CCH - -ALIGN 16 + db 0CCH, 0CCH, 0CCH, 0CCH, 0CCH, 0CCH, 0CCH, 0CCH + db 0CCH, 0CCH, 0CCH, 0CCH ?_25213 LABEL NEAR mov ecx, dword ptr [esp+0CH] ; 100BDA10 _ 8B. 4C 24, 0C @@ -621,9 +606,7 @@ ALIGN 16 ; Filling space: 3H ; Filler type: INT 3 Debug breakpoint -; db 0CCH, 0CCH, 0CCH - -ALIGN 8 + db 0CCH, 0CCH, 0CCH ?_25220 LABEL NEAR mov edx, dword ptr [esp+10H] ; 100BDAC0 _ 8B. 54 24, 10 @@ -738,9 +721,7 @@ ALIGN 8 ; Filling space: 3H ; Filler type: INT 3 Debug breakpoint -; db 0CCH, 0CCH, 0CCH - -ALIGN 8 + db 0CCH, 0CCH, 0CCH ?_25227 LABEL NEAR mov eax, dword ptr [esp+10H] ; 100BDC00 _ 8B. 44 24, 10 @@ -798,10 +779,8 @@ ALIGN 8 ; Filling space: 0CH ; Filler type: INT 3 Debug breakpoint -; db 0CCH, 0CCH, 0CCH, 0CCH, 0CCH, 0CCH, 0CCH, 0CCH -; db 0CCH, 0CCH, 0CCH, 0CCH - -ALIGN 16 + db 0CCH, 0CCH, 0CCH, 0CCH, 0CCH, 0CCH, 0CCH, 0CCH + db 0CCH, 0CCH, 0CCH, 0CCH ?_25231 LABEL NEAR mov eax, dword ptr [esp+10H] ; 100BDC90 _ 8B. 44 24, 10 @@ -839,9 +818,7 @@ ALIGN 16 ; Filling space: 7H ; Filler type: INT 3 Debug breakpoint -; db 0CCH, 0CCH, 0CCH, 0CCH, 0CCH, 0CCH, 0CCH - -ALIGN 8 + db 0CCH, 0CCH, 0CCH, 0CCH, 0CCH, 0CCH, 0CCH DecodeFLCFrame LABEL NEAR mov ecx, dword ptr [esp+10H] ; 100BDCE0 _ 8B. 4C 24, 10 @@ -863,6 +840,12 @@ DecodeFLCFrame LABEL NEAR add esp, 24 ; 100BDD0A _ 83. C4, 18 ?_25235:ret ; 100BDD0D _ C3 +; Filling space: 2H +; Filler type: INT 3 Debug breakpoint + db 0CCH, 0CCH + +EndOfSection LABEL NEAR + .text ENDS END diff --git a/3rdparty/flic/flic.lib b/3rdparty/flic/flic.lib index 8e297be87d487a9654384afd9f8f2123866a7f60..fea46a2524205492607347c02caac50e1c15f37b 100644 GIT binary patch delta 975 zcmdlZ_D5`jY`vv{xv7x?3NV23OyJ@PTnr2hOh9}CgyUUOlk-zj-F%$giV|~E8RA{@ zQvB0`Q$hLcu)lVm?}760+Y`%g>k_+XUQQ_$JQDF%Pd=dEn|NrJA9EV|2V0!X8)+Id1B9r6TQWUxVfRswSRt9R7 z=?+nmNaNr40%(*_XjnjaV9<+KlOMBbfL+4J9>XX!Ih#F$@#o|#>^_V}yH79W_U24wMrSz17r0GOo* zWC?;WyK$ghl-JDbFL6HbD85OVqxgZ&4V1zO;*vA{08d@5G?FMQD zib6z;8SH>uhzLkO$d)yzx-5(sI)H8mnFG~jVazZOAyN-A+QNik4MGSkV#;s`O~j1h j0-A_9!#y++3x+qSB9;aWzu_WEKByfQYOx^}HnUMkA=(L>7WWD^PESMEAqm3+3?KCtnFf%h#P%tus zc_e|$hmn~c(|Sk60B?tZ9o<$FznbE6qp$pc)%wk^`K}3MI8dz#~Ya%S{i|E0xDx*W`KwoGdKXb z5D}1S79idL)D27+3``I;7DfzRK$n6xK85W?4m@uqEh~$DSvoK{if)E0Wm@!;J c6ESCafF@$W@D5eP(tzPFTto!uJoFp@0QOJ7qW}N^ diff --git a/LEGO1/library_flic.h b/LEGO1/library_flic.h new file mode 100644 index 00000000..1c6a6d8b --- /dev/null +++ b/LEGO1/library_flic.h @@ -0,0 +1,6 @@ +#ifdef 0 + +// LIBRARY: LEGO1 0x100bdce0 +// _DecodeFLCFrame + +#endif diff --git a/LEGO1/library_smack.h b/LEGO1/library_smack.h new file mode 100644 index 00000000..2909ebd3 --- /dev/null +++ b/LEGO1/library_smack.h @@ -0,0 +1,18 @@ +#ifdef 0 + +// LIBRARY: LEGO1 0x100cd782 +// _SmackGetSizeTables + +// LIBRARY: LEGO1 0x100cd7e8 +// _SmackDoTables + +// LIBRARY: LEGO1 0x100cda83 +// _SmackDoFrameToBuffer + +// LIBRARY: LEGO1 0x100d052c +// _SmackGetSizeDeltas + +// LIBRARY: LEGO1 0x100d0543 +// _SmackGetRect + +#endif diff --git a/LEGO1/omni/include/mxsmack.h b/LEGO1/omni/include/mxsmack.h index e0f8c76e..227dbd6d 100644 --- a/LEGO1/omni/include/mxsmack.h +++ b/LEGO1/omni/include/mxsmack.h @@ -12,10 +12,7 @@ // but present in SMACK.LIB and used directly by Mindscape. extern "C" { - // (SMACK.LIB) FUNCTION: LEGO1 0x100cd782 u32 SmackGetSizeTables(); - - // (SMACK.LIB) FUNCTION: LEGO1 0x100cd7e8 void SmackDoTables( u8* p_huffmanTrees, u8* p_huffmanTables, @@ -24,14 +21,8 @@ extern "C" u32 p_detailSize, u32 p_typeSize ); - - // (SMACK.LIB) FUNCTION: LEGO1 0x100cda83 void SmackDoFrameToBuffer(u8* p_source, u8* p_huffmanTables, u8* p_unk0x6b4); - - // (SMACK.LIB) FUNCTION: LEGO1 0x100d052c u32 SmackGetSizeDeltas(u32 p_width, u32 p_height); - - // (SMACK.LIB) FUNCTION: LEGO1 0x100d0543 u8 SmackGetRect(u8* p_unk0x6b4, u32* p_rect); } From 9c0843e69bb495d93de2a2fc03106b8cc24ca11d Mon Sep 17 00:00:00 2001 From: Christian Semmler Date: Fri, 19 Jan 2024 23:18:39 +0100 Subject: [PATCH 4/9] Update README.md [skip ci] --- tools/README.md | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/tools/README.md b/tools/README.md index da23d84c..75a25668 100644 --- a/tools/README.md +++ b/tools/README.md @@ -71,7 +71,7 @@ Synthetic functions should be annotated with `SYNTHETIC`. A synthetic function i // MxList::`scalar deleting destructor' ``` -## Virtual tables (**WIP**) +## Virtual tables Classes with a virtual table should be annotated using the `VTABLE` marker, which includes the module name and address of the virtual table. Additionally, virtual function declarations should be annotated with a comment indicating their relative offset. Please use the following example as a reference. @@ -86,7 +86,7 @@ public: virtual MxResult Create(MxU32 p_frequencyMS, MxBool p_createThread); // vtable+0x28 ``` -## Class size (**WIP**) +## Class size Classes should be annotated using the `SIZE` marker to indicate their size. If you are unsure about the class size in the original binary, please use the currently available information (known member variables) and detail the circumstances in an extra comment if necessary. @@ -112,7 +112,7 @@ private: undefined4 m_unk0x14; // 0x14 ``` -## Global variables (**WIP**) +## Global variables Global variables should be annotated using the `GLOBAL` marker, which includes the module name and address of the variable. @@ -127,6 +127,18 @@ MxAtomId* g_pz5Script = NULL; MxAtomId* g_introScript = NULL; ``` +## Strings + +String values should be annotated using the `STRING` marker, which includes the module name and address of the string. + +``` +inline virtual const char* ClassName() const override // vtable+0x0c +{ + // STRING: LEGO1 0x100f03fc + return "Act2PoliceStation"; +} +``` + # Tooling Use `pip` to install the required packages to be able to use the Python tools found in this folder: From 837fc4b7cc7a84990352003f36009f8f0feed825 Mon Sep 17 00:00:00 2001 From: Christian Semmler Date: Fri, 19 Jan 2024 23:19:36 +0100 Subject: [PATCH 5/9] Update README.md [skip ci] --- tools/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/README.md b/tools/README.md index 75a25668..6d8ec1a7 100644 --- a/tools/README.md +++ b/tools/README.md @@ -86,7 +86,7 @@ public: virtual MxResult Create(MxU32 p_frequencyMS, MxBool p_createThread); // vtable+0x28 ``` -## Class size +## Class size (**WIP**) Classes should be annotated using the `SIZE` marker to indicate their size. If you are unsure about the class size in the original binary, please use the currently available information (known member variables) and detail the circumstances in an extra comment if necessary. From a2aa99485f44022921aeba9a9f00c799e6c7c974 Mon Sep 17 00:00:00 2001 From: Christian Semmler Date: Fri, 19 Jan 2024 23:24:03 +0100 Subject: [PATCH 6/9] Update README.md [skip ci] --- tools/README.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tools/README.md b/tools/README.md index 6d8ec1a7..5d810ee2 100644 --- a/tools/README.md +++ b/tools/README.md @@ -71,6 +71,21 @@ Synthetic functions should be annotated with `SYNTHETIC`. A synthetic function i // MxList::`scalar deleting destructor' ``` +### `LIBRARY` + +Functions located in 3rd party libraries should be annotated with `LIBRARY`. Since the goal is to eventually have a full accounting of all the functions present in the binaries, please make an effort to find and annotate every function of every statically linked library, including the MSVC standard libraries. + +``` +// LIBRARY: ISLE 0x4061b0 +// _MemPoolInit@4 + +// LIBRARY: ISLE 0x406520 +// _MemPoolSetPageSize@8 + +// LIBRARY: ISLE 0x406630 +// _MemPoolSetBlockSizeFS@8 +``` + ## Virtual tables Classes with a virtual table should be annotated using the `VTABLE` marker, which includes the module name and address of the virtual table. Additionally, virtual function declarations should be annotated with a comment indicating their relative offset. Please use the following example as a reference. From b19807cb146260a4e32c603a8dfaf2bd7b216f50 Mon Sep 17 00:00:00 2001 From: Christian Semmler Date: Fri, 19 Jan 2024 23:27:11 +0100 Subject: [PATCH 7/9] Update README.md [skip ci] --- tools/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/README.md b/tools/README.md index 5d810ee2..b24a8f50 100644 --- a/tools/README.md +++ b/tools/README.md @@ -58,7 +58,7 @@ Templated functions should be annotated with `TEMPLATE`. Since the goal is to ev ### `SYNTHETIC` -Synthetic functions should be annotated with `SYNTHETIC`. A synthetic function is generated by the compiler; for the time being, the only case is the "scalar deleting destructor" found in virtual tables. Note: `SYNTHETIC` takes precedence over `TEMPLATE`. +Synthetic functions should be annotated with `SYNTHETIC`. A synthetic function is generated by the compiler; most common is the "scalar deleting destructor" found in virtual tables. Other cases include default destructors and assignment operators. Note: `SYNTHETIC` takes precedence over `TEMPLATE`. ``` // SYNTHETIC: LEGO1 0x10003210 From 9000f731ac8f073c3891ebd768c9af12526c3c5c Mon Sep 17 00:00:00 2001 From: Joshua Peisach Date: Sat, 20 Jan 2024 09:22:33 -0500 Subject: [PATCH 8/9] PoliceState constructor (#463) * PoliceState constructor * Changes --------- Co-authored-by: Christian Semmler --- LEGO1/lego/legoomni/include/policestate.h | 5 +++++ LEGO1/lego/legoomni/src/police/policestate.cpp | 9 +++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/LEGO1/lego/legoomni/include/policestate.h b/LEGO1/lego/legoomni/include/policestate.h index 611ced07..be55ecae 100644 --- a/LEGO1/lego/legoomni/include/policestate.h +++ b/LEGO1/lego/legoomni/include/policestate.h @@ -1,6 +1,7 @@ #ifndef POLICESTATE_H #define POLICESTATE_H +#include "decomp.h" #include "legostate.h" // VTABLE: LEGO1 0x100d8af0 @@ -24,6 +25,10 @@ class PoliceState : public LegoState { // SYNTHETIC: LEGO1 0x1005e920 // PoliceState::`scalar deleting destructor' + +private: + undefined4 m_unk0x8; // 0x8 + undefined4 m_unk0xc; // 0xc }; #endif // POLICESTATE_H diff --git a/LEGO1/lego/legoomni/src/police/policestate.cpp b/LEGO1/lego/legoomni/src/police/policestate.cpp index a2c66a45..4965a36f 100644 --- a/LEGO1/lego/legoomni/src/police/policestate.cpp +++ b/LEGO1/lego/legoomni/src/police/policestate.cpp @@ -1,7 +1,12 @@ #include "policestate.h" -// STUB: LEGO1 0x1005e7c0 +#include + +DECOMP_SIZE_ASSERT(PoliceState, 0x10) + +// FUNCTION: LEGO1 0x1005e7c0 PoliceState::PoliceState() { - // TODO + m_unk0xc = 0; + m_unk0x8 = (rand() % 2 == 0) ? 501 : 500; } From 9a3df8d9f8e4d4a814b21e16bbd04d412db79cdc Mon Sep 17 00:00:00 2001 From: Misha <106913236+MishaProductions@users.noreply.github.com> Date: Sat, 20 Jan 2024 09:24:54 -0500 Subject: [PATCH 9/9] Implement various methods in InfoCenter folder (#465) * push changes * Fix return type of Infocenter::Tickle * Fixes/matches * Code clarity * Move assert --------- Co-authored-by: Christian Semmler --- LEGO1/lego/legoomni/include/elevatorbottom.h | 2 + LEGO1/lego/legoomni/include/infocenter.h | 6 +- LEGO1/lego/legoomni/include/infocenterdoor.h | 3 + .../legoomni/include/legocontrolmanager.h | 2 +- .../src/control/legocontrolmanager.cpp | 2 +- .../src/infocenter/elevatorbottom.cpp | 29 +++++++-- .../legoomni/src/infocenter/infocenter.cpp | 62 ++++++++++++++----- .../src/infocenter/infocenterdoor.cpp | 39 +++++++++--- .../src/infocenter/infocenterstate.cpp | 13 +++- 9 files changed, 123 insertions(+), 35 deletions(-) diff --git a/LEGO1/lego/legoomni/include/elevatorbottom.h b/LEGO1/lego/legoomni/include/elevatorbottom.h index ed424efd..1f02d28f 100644 --- a/LEGO1/lego/legoomni/include/elevatorbottom.h +++ b/LEGO1/lego/legoomni/include/elevatorbottom.h @@ -40,6 +40,8 @@ class ElevatorBottom : public LegoWorld { private: undefined4 m_unk0xf8; // 0xf8 + + MxLong HandleNotification17(MxParam& p_param); }; #endif // ELEVATORBOTTOM_H diff --git a/LEGO1/lego/legoomni/include/infocenter.h b/LEGO1/lego/legoomni/include/infocenter.h index 4d8ed408..7de6ec45 100644 --- a/LEGO1/lego/legoomni/include/infocenter.h +++ b/LEGO1/lego/legoomni/include/infocenter.h @@ -170,10 +170,10 @@ class Infocenter : public LegoWorld { InfocenterUnkDataEntry m_entries[7]; // 0x120 MxS16 m_unk0x1c8; // 0x1c8 undefined4 m_unk0x1cc; // 0x1cc - MxU16 m_unk0x1d0; // 0x1d0 - MxU16 m_unk0x1d2; // 0x1d2 + MxS16 m_infoManDialogueTimer; // 0x1d0 + MxS16 m_bookAnimationTimer; // 0x1d2 MxU16 m_unk0x1d4; // 0x1d4 - MxU16 m_unk0x1d6; // 0x1d6 + MxS16 m_unk0x1d6; // 0x1d6 }; #endif // INFOCENTER_H diff --git a/LEGO1/lego/legoomni/include/infocenterdoor.h b/LEGO1/lego/legoomni/include/infocenterdoor.h index effb22cf..1890f0b1 100644 --- a/LEGO1/lego/legoomni/include/infocenterdoor.h +++ b/LEGO1/lego/legoomni/include/infocenterdoor.h @@ -36,6 +36,9 @@ class InfocenterDoor : public LegoWorld { // SYNTHETIC: LEGO1 0x100378d0 // InfocenterDoor::`scalar deleting destructor' + +private: + MxS32 m_unk0xf8; // 0xf8 }; #endif // INFOCENTERDOOR_H diff --git a/LEGO1/lego/legoomni/include/legocontrolmanager.h b/LEGO1/lego/legoomni/include/legocontrolmanager.h index df003f06..385ee92b 100644 --- a/LEGO1/lego/legoomni/include/legocontrolmanager.h +++ b/LEGO1/lego/legoomni/include/legocontrolmanager.h @@ -28,7 +28,7 @@ class LegoControlManager : public MxCore { void FUN_10028df0(MxPresenterList* p_presenterList); void Register(MxCore* p_listener); void Unregister(MxCore* p_listener); - void FUN_100293c0(undefined4, const MxAtomId&, undefined2); + void FUN_100293c0(undefined4, const char*, undefined2); // SYNTHETIC: LEGO1 0x10028d40 // LegoControlManager::`scalar deleting destructor' diff --git a/LEGO1/lego/legoomni/src/control/legocontrolmanager.cpp b/LEGO1/lego/legoomni/src/control/legocontrolmanager.cpp index 64c19cd5..481bd9c5 100644 --- a/LEGO1/lego/legoomni/src/control/legocontrolmanager.cpp +++ b/LEGO1/lego/legoomni/src/control/legocontrolmanager.cpp @@ -31,7 +31,7 @@ void LegoControlManager::Unregister(MxCore* p_listener) } // STUB: LEGO1 0x100293c0 -void LegoControlManager::FUN_100293c0(undefined4, const MxAtomId&, undefined2) +void LegoControlManager::FUN_100293c0(undefined4, const char*, undefined2) { } diff --git a/LEGO1/lego/legoomni/src/infocenter/elevatorbottom.cpp b/LEGO1/lego/legoomni/src/infocenter/elevatorbottom.cpp index ad199882..c3d6a7a2 100644 --- a/LEGO1/lego/legoomni/src/infocenter/elevatorbottom.cpp +++ b/LEGO1/lego/legoomni/src/infocenter/elevatorbottom.cpp @@ -1,7 +1,5 @@ #include "elevatorbottom.h" -DECOMP_SIZE_ASSERT(ElevatorBottom, 0xfc) - #include "legocontrolmanager.h" #include "legogamestate.h" #include "legoinputmanager.h" @@ -9,6 +7,8 @@ DECOMP_SIZE_ASSERT(ElevatorBottom, 0xfc) #include "mxnotificationmanager.h" #include "mxomni.h" +DECOMP_SIZE_ASSERT(ElevatorBottom, 0xfc) + // FUNCTION: LEGO1 0x10017e90 ElevatorBottom::ElevatorBottom() { @@ -43,11 +43,24 @@ MxResult ElevatorBottom::Create(MxDSAction& p_dsAction) return result; } -// STUB: LEGO1 0x10018150 +// FUNCTION: LEGO1 0x10018150 MxLong ElevatorBottom::Notify(MxParam& p_param) { - // TODO - return LegoWorld::Notify(p_param); + MxLong ret = 0; + LegoWorld::Notify(p_param); + + if (m_worldStarted) { + switch (((MxNotificationParam&) p_param).GetType()) { + case c_notificationType17: + ret = HandleNotification17(p_param); + break; + case c_notificationTransitioned: + GameState()->HandleAction(m_unk0xf8); + break; + } + } + + return ret; } // FUNCTION: LEGO1 0x100181b0 @@ -58,6 +71,12 @@ void ElevatorBottom::VTable0x50() FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); } +// STUB: LEGO1 0x100181d0 +MxLong ElevatorBottom::HandleNotification17(MxParam& p_param) +{ + return 0; +} + // FUNCTION: LEGO1 0x100182c0 void ElevatorBottom::VTable0x68(MxBool p_add) { diff --git a/LEGO1/lego/legoomni/src/infocenter/infocenter.cpp b/LEGO1/lego/legoomni/src/infocenter/infocenter.cpp index 68090a69..5ffa3676 100644 --- a/LEGO1/lego/legoomni/src/infocenter/infocenter.cpp +++ b/LEGO1/lego/legoomni/src/infocenter/infocenter.cpp @@ -35,14 +35,14 @@ Infocenter::Infocenter() m_currentInfomainScript = c_noInfomain; m_currentCutscene = e_noIntro; - memset(&m_entries, 0, sizeof(InfocenterUnkDataEntry) * 7); + memset(&m_entries, 0, sizeof(m_entries)); m_unk0x1c8 = -1; SetAppCursor(1); NotificationManager()->Register(this); - m_unk0x1d0 = 0; - m_unk0x1d2 = 0; + m_infoManDialogueTimer = 0; + m_bookAnimationTimer = 0; m_unk0x1d4 = 0; m_unk0x1d6 = 0; } @@ -130,7 +130,7 @@ MxLong Infocenter::Notify(MxParam& p_param) break; case c_notificationTransitioned: StopBookAnimation(); - m_unk0x1d2 = 0; + m_bookAnimationTimer = 0; if (m_infocenterState->GetUnknown0x74() == 0xc) { StartCredits(); @@ -198,7 +198,7 @@ MxLong Infocenter::HandleEndAction(MxParam& p_param) return result; if (action->GetObjectId() == c_returnBackGuidanceDialogue2) { - ControlManager()->FUN_100293c0(0x10, action->GetAtomId(), 0); + ControlManager()->FUN_100293c0(0x10, action->GetAtomId().GetInternal(), 0); m_unk0x1d6 = 0; } @@ -232,7 +232,7 @@ MxLong Infocenter::HandleEndAction(MxParam& p_param) m_currentCutscene = e_noIntro; if (m_infocenterState->GetInfocenterBufferElement(0) == 0) { - m_unk0x1d2 = 1; + m_bookAnimationTimer = 1; return 1; } break; @@ -278,7 +278,7 @@ MxLong Infocenter::HandleEndAction(MxParam& p_param) if (m_infocenterState->GetInfocenterBufferElement(0) == 0 && m_currentInfomainScript != 40 && m_currentInfomainScript != 41 && m_currentInfomainScript != 42 && m_currentInfomainScript != 43 && m_currentInfomainScript != 44) { - m_unk0x1d0 = 1; + m_infoManDialogueTimer = 1; PlayMusic(11); } @@ -299,8 +299,8 @@ MxLong Infocenter::HandleEndAction(MxParam& p_param) // STUB: LEGO1 0x1006f4e0 void Infocenter::VTable0x50() { - m_unk0x1d0 = 0; - m_unk0x1d2 = 0; + m_infoManDialogueTimer = 0; + m_bookAnimationTimer = 0; m_unk0x1d4 = 0; m_unk0x1d6 = 0; @@ -319,7 +319,7 @@ void Infocenter::VTable0x50() case 4: m_infocenterState->SetUnknown0x74(2); if (m_infocenterState->GetInfocenterBufferElement(0) == 0) { - m_unk0x1d2 = 1; + m_bookAnimationTimer = 1; } PlayAction(c_letsGetStartedDialogue); @@ -337,7 +337,7 @@ void Infocenter::VTable0x50() return; case 0xf: if (m_infocenterState->GetInfocenterBufferElement(0) == 0) { - m_unk0x1d2 = 1; + m_bookAnimationTimer = 1; } PlayAction(c_clickOnInfomanDialogue); @@ -383,7 +383,7 @@ MxLong Infocenter::HandleKeyPress(MxS8 p_key) m_infocenterState->SetUnknown0x74(1); if (m_infocenterState->GetInfocenterBufferElement(0) == 0) { - m_unk0x1d2 = 1; + m_bookAnimationTimer = 1; return 1; } break; @@ -452,11 +452,43 @@ void Infocenter::VTable0x68(MxBool p_add) } } -// STUB: LEGO1 0x10070af0 +// FUNCTION: LEGO1 0x10070af0 MxResult Infocenter::Tickle() { - // TODO - return LegoWorld::Tickle(); + if (m_worldStarted == FALSE) { + LegoWorld::Tickle(); + return SUCCESS; + } + + if (m_infoManDialogueTimer != 0 && (m_infoManDialogueTimer += 100) > 25000) { + PlayAction(c_clickOnInfomanDialogue); + m_infoManDialogueTimer = 0; + } + + if (m_bookAnimationTimer != 0 && (m_bookAnimationTimer += 100) > 3000) { + PlayBookAnimation(); + m_bookAnimationTimer = 1; + } + + if (m_unk0x1d6 != 0) { + m_unk0x1d6 += 100; + + if (m_unk0x1d6 > 3400 && m_unk0x1d6 < 3650) { + ControlManager()->FUN_100293c0(0x10, m_atom.GetInternal(), 1); + } + else if (m_unk0x1d6 > 3650 && m_unk0x1d6 < 3900) { + ControlManager()->FUN_100293c0(0x10, m_atom.GetInternal(), 0); + } + else if (m_unk0x1d6 > 3900 && m_unk0x1d6 < 4150) { + ControlManager()->FUN_100293c0(0x10, m_atom.GetInternal(), 1); + } + else if (m_unk0x1d6 > 4400) { + ControlManager()->FUN_100293c0(0x10, m_atom.GetInternal(), 0); + m_unk0x1d6 = 0; + } + } + + return SUCCESS; } // FUNCTION: LEGO1 0x10070c20 diff --git a/LEGO1/lego/legoomni/src/infocenter/infocenterdoor.cpp b/LEGO1/lego/legoomni/src/infocenter/infocenterdoor.cpp index 4c50a321..7ba892b4 100644 --- a/LEGO1/lego/legoomni/src/infocenter/infocenterdoor.cpp +++ b/LEGO1/lego/legoomni/src/infocenter/infocenterdoor.cpp @@ -1,24 +1,47 @@ #include "infocenterdoor.h" +#include "legocontrolmanager.h" +#include "legogamestate.h" #include "legoinputmanager.h" #include "legoomni.h" +#include "mxnotificationmanager.h" -// STUB: LEGO1 0x10037730 +DECOMP_SIZE_ASSERT(InfocenterDoor, 0xfc) + +// FUNCTION: LEGO1 0x10037730 InfocenterDoor::InfocenterDoor() { - // TODO + m_unk0xf8 = 0; + + NotificationManager()->Register(this); } -// STUB: LEGO1 0x100378f0 +// FUNCTION: LEGO1 0x100378f0 InfocenterDoor::~InfocenterDoor() { - // TODO + if (InputManager()->GetWorld() == this) { + InputManager()->ClearWorld(); + } + + ControlManager()->Unregister(this); + NotificationManager()->Unregister(this); } -// STUB: LEGO1 0x10037980 +// FUNCTION: LEGO1 0x10037980 MxResult InfocenterDoor::Create(MxDSAction& p_dsAction) { - return SUCCESS; + MxResult result = LegoWorld::Create(p_dsAction); + if (result == SUCCESS) { + InputManager()->SetWorld(this); + ControlManager()->Register(this); + } + + SetIsWorldActive(FALSE); + + GameState()->SetUnknown424(3); + GameState()->FUN_1003a720(0); + + return result; } // STUB: LEGO1 0x100379e0 @@ -52,8 +75,10 @@ void InfocenterDoor::VTable0x68(MxBool p_add) } } -// STUB: LEGO1 0x10037cd0 +// FUNCTION: LEGO1 0x10037cd0 MxBool InfocenterDoor::VTable0x64() { + DeleteObjects(&m_atom, 500, 510); + m_unk0xf8 = 2; return TRUE; } diff --git a/LEGO1/lego/legoomni/src/infocenter/infocenterstate.cpp b/LEGO1/lego/legoomni/src/infocenter/infocenterstate.cpp index 96e47c55..76ffd3ea 100644 --- a/LEGO1/lego/legoomni/src/infocenter/infocenterstate.cpp +++ b/LEGO1/lego/legoomni/src/infocenter/infocenterstate.cpp @@ -2,15 +2,22 @@ DECOMP_SIZE_ASSERT(InfocenterState, 0x94); -// STUB: LEGO1 0x10071600 +// FUNCTION: LEGO1 0x10071600 InfocenterState::InfocenterState() { // TODO memset(m_buffer, 0, sizeof(m_buffer)); } -// STUB: LEGO1 0x10071920 +// FUNCTION: LEGO1 0x10071920 InfocenterState::~InfocenterState() { - // TODO + MxS16 i = 0; + do { + if (GetInfocenterBufferElement(i) != NULL) { + delete GetInfocenterBufferElement(i)->GetAction(); + delete GetInfocenterBufferElement(i); + } + i++; + } while (i < GetInfocenterBufferSize()); }