From 57d5949d8498cb1763679f494d5e78b50abde8cf Mon Sep 17 00:00:00 2001 From: Anonymous Maarten <madebr@users.noreply.github.com> Date: Sat, 3 Feb 2024 02:03:52 +0100 Subject: [PATCH] Implement some Act1State functions (#520) * Implement some Act1State functions * ci: push fix commits to pr * ci fix * Show diffs generated by clang-format * Run clang-format * Fix naming * re-use _countof + add parentheses * Fix naming * Use MxS32 * Annotate Act1State::NamedPlane::~NamedPlane * Apply suggestions * Read and Write Mx3DPointFloat's * Annotations, spacing * Add Mx3DPointFloat copy ctor, match some functions * Fix WriteVector3 * Adding more spacing for readability * Use MxResult as a return type for Serialize --------- Co-authored-by: Christian Semmler <mail@csemmler.com> --- .github/workflows/format.yml | 3 +- CMakeLists.txt | 5 +- LEGO1/lego/legoomni/include/act1state.h | 102 ++++++- LEGO1/lego/legoomni/include/legoutil.h | 26 ++ LEGO1/lego/legoomni/src/act1/act1state.cpp | 264 +++++++++++++++++- LEGO1/lego/legoomni/src/common/legoutil.cpp | 20 ++ .../src/infocenter/elevatorbottom.cpp | 2 +- LEGO1/lego/sources/misc/legostorage.h | 40 +++ LEGO1/mxgeometry/mxgeometry3d.h | 3 + util/decomp.h | 2 +- 10 files changed, 433 insertions(+), 34 deletions(-) diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml index 10e85e0d..4cfb5d9e 100644 --- a/.github/workflows/format.yml +++ b/.github/workflows/format.yml @@ -14,10 +14,9 @@ jobs: run: | find LEGO1 ISLE -iname '*.h' -o -iname '*.cpp' | xargs \ pipx run "clang-format>=17,<18" \ - --Werror \ - --dry-run \ --style=file \ -i + git diff --exit-code python-format: name: 'Python' diff --git a/CMakeLists.txt b/CMakeLists.txt index eb509e5b..dfcabe6f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -151,7 +151,7 @@ add_library(misc STATIC ) register_lego1_target(misc) set_property(TARGET misc PROPERTY ARCHIVE_OUTPUT_NAME "misc$<$<CONFIG:Debug>:d>") -target_include_directories(misc PRIVATE "${CMAKE_SOURCE_DIR}/LEGO1/omni/include" "${CMAKE_SOURCE_DIR}/util") +target_include_directories(misc PRIVATE "${CMAKE_SOURCE_DIR}/LEGO1/omni/include" "${CMAKE_SOURCE_DIR}/LEGO1" "${CMAKE_SOURCE_DIR}/LEGO1/realtime" "${CMAKE_SOURCE_DIR}/util") target_link_libraries(misc PRIVATE) add_library(3dmanager STATIC @@ -249,7 +249,7 @@ add_library(omni STATIC ) register_lego1_target(omni) set_property(TARGET omni PROPERTY ARCHIVE_OUTPUT_NAME "omni$<$<CONFIG:Debug>:d>") -target_include_directories(omni PRIVATE "${CMAKE_SOURCE_DIR}/LEGO1/omni/include" "${CMAKE_SOURCE_DIR}/LEGO1" "${CMAKE_SOURCE_DIR}/util") +target_include_directories(omni PRIVATE "${CMAKE_SOURCE_DIR}/LEGO1/omni/include" "${CMAKE_SOURCE_DIR}/LEGO1" "${CMAKE_SOURCE_DIR}/LEGO1" "${CMAKE_SOURCE_DIR}/util") target_link_libraries(omni PRIVATE dsound winmm FLIC::FLIC Smacker::Smacker) add_library(lego1 SHARED @@ -393,6 +393,7 @@ target_include_directories(lego1 PUBLIC "${CMAKE_SOURCE_DIR}/LEGO1") target_include_directories(lego1 PUBLIC "${CMAKE_SOURCE_DIR}/LEGO1/omni/include") target_include_directories(lego1 PUBLIC "${CMAKE_SOURCE_DIR}/LEGO1/lego/sources") target_include_directories(lego1 PUBLIC "${CMAKE_SOURCE_DIR}/LEGO1/lego/legoomni/include") +target_include_directories(lego1 PUBLIC "${CMAKE_SOURCE_DIR}/LEGO1/realtime") # Link libraries target_link_libraries(lego1 PRIVATE tglrl viewmanager realtime mxdirectx roi FLIC::FLIC Vec::Vec dinput dxguid misc 3dmanager omni) diff --git a/LEGO1/lego/legoomni/include/act1state.h b/LEGO1/lego/legoomni/include/act1state.h index 1ad86c64..8b1a09b1 100644 --- a/LEGO1/lego/legoomni/include/act1state.h +++ b/LEGO1/lego/legoomni/include/act1state.h @@ -2,11 +2,19 @@ #define ACT1STATE_H #include "legostate.h" +#include "legoutil.h" +#include "roi/legoroi.h" // VTABLE: LEGO1 0x100d7028 // SIZE 0x26c class Act1State : public LegoState { public: + enum { + e_unk953 = 953, + e_unk954 = 954, + e_unk955 = 955, + }; + Act1State(); // FUNCTION: LEGO1 0x100338a0 @@ -25,29 +33,93 @@ public: MxBool SetFlag() override; // vtable+0x18 MxResult VTable0x1c(LegoFile* p_legoFile) override; // vtable+0x1c - inline void SetUnknown18(MxU32 p_unk0x18) { m_unk0x18 = p_unk0x18; } - inline MxU32 GetUnknown18() { return m_unk0x18; } - inline MxU32 GetUnknown1c() { return m_unk0x1c; } - inline MxS16 GetUnknown21() { return m_unk0x21; } + inline void SetUnknown18(MxU32 p_unk0x18) { m_unk0x018 = p_unk0x18; } + inline MxU32 GetUnknown18() { return m_unk0x018; } + inline MxU32 GetUnknown1c() { return m_unk0x01c; } + inline MxS16 GetUnknown21() { return m_unk0x021; } - inline void SetUnknown1c(MxU32 p_unk0x1c) { m_unk0x1c = p_unk0x1c; } - inline void SetUnknown21(MxS16 p_unk0x21) { m_unk0x21 = p_unk0x21; } + inline void SetUnknown1c(MxU32 p_unk0x1c) { m_unk0x01c = p_unk0x1c; } + inline void SetUnknown21(MxS16 p_unk0x21) { m_unk0x021 = p_unk0x21; } void FUN_10034d00(); // SYNTHETIC: LEGO1 0x10033960 // Act1State::`scalar deleting destructor' + // SIZE 0x4c + class NamedPlane { + public: + // FUNCTION: LEGO1 0x10033800 + NamedPlane() {} + + inline void SetName(const char* p_name) { m_name = p_name; } + inline const MxString* GetName() const { return &m_name; } + + // FUNCTION: LEGO1 0x100344d0 + MxResult Serialize(LegoFile* p_file) + { + if (p_file->IsWriteMode()) { + p_file->FUN_10006030(m_name); + p_file->WriteVector3(m_point1); + p_file->WriteVector3(m_point2); + p_file->WriteVector3(m_point3); + } + else if (p_file->IsReadMode()) { + p_file->ReadString(m_name); + p_file->ReadVector3(m_point1); + p_file->ReadVector3(m_point2); + p_file->ReadVector3(m_point3); + } + + return SUCCESS; + } + + private: + MxString m_name; // 0x00 + Mx3DPointFloat m_point1; // 0x10 + Mx3DPointFloat m_point2; // 0x24 + Mx3DPointFloat m_point3; // 0x38 + }; + protected: - undefined m_unk0x08[0x10]; // 0x08 - MxU32 m_unk0x18; // 0x18 - undefined2 m_unk0x1c; // 0x1c - undefined m_unk0x1e; // 0x1e - undefined m_unk0x1f; // 0x1f - undefined m_unk0x20; // 0x20 - MxBool m_unk0x21; // 0x21 - undefined m_unk0x22; // 0x22 - // TODO + MxS32* m_unk0x008; // 0x008 + // FIXME: count for m_unk0x008 + MxS16 m_unk0x00c; // 0x00c + undefined2 m_unk0x00e; // 0x00e + undefined2 m_unk0x010; // 0x010 + undefined m_unk0x012; // 0x012 + MxS32 m_unk0x014; // 0x014 + MxU32 m_unk0x018; // 0x018 + MxU16 m_unk0x01c; // 0x01c + undefined m_unk0x01e; // 0x01e + undefined m_unk0x01f; // 0x01f + undefined m_unk0x020; // 0x020 + undefined m_unk0x021; // 0x021 + undefined m_unk0x022; // 0x022 + undefined m_unk0x023; // 0x023 + NamedPlane m_unk0x024; // 0x024 + NamedPlane m_unk0x070; // 0x070 + NamedPlane m_unk0x0bc; // 0x0bc + NamedPlane m_unk0x108; // 0x108 + NamedTexture* m_unk0x154; // 0x154 + NamedTexture* m_unk0x158; // 0x158 + NamedTexture* m_unk0x15c; // 0x15c + MxCore* m_unk0x160; // 0x160 + NamedPlane m_unk0x164; // 0x164 + NamedTexture* m_unk0x1b0; // 0x1b0 + NamedTexture* m_unk0x1b4; // 0x1b4 + MxCore* m_unk0x1b8; // 0x1b8 + NamedPlane m_unk0x1bc; // 0x1bc + NamedTexture* m_unk0x208; // 0x208 + MxCore* m_unk0x20c; // 0x20c + NamedPlane m_unk0x210; // 0x210 + NamedTexture* m_unk0x25c; // 0x25c + NamedTexture* m_unk0x260; // 0x260 + NamedTexture* m_unk0x264; // 0x264 + MxCore* m_unk0x268; // 0x268 }; +// FUNCTION: LEGO1 0x10033a70 +// Act1State::NamedPlane::~NamedPlane + #endif // ACT1STATE_H diff --git a/LEGO1/lego/legoomni/include/legoutil.h b/LEGO1/lego/legoomni/include/legoutil.h index 922a2c60..696a1cc4 100644 --- a/LEGO1/lego/legoomni/include/legoutil.h +++ b/LEGO1/lego/legoomni/include/legoutil.h @@ -2,6 +2,9 @@ #define LEGOUTIL_H #include "extra.h" +#include "misc/legostorage.h" +#include "misc/legotexture.h" +#include "mxstring.h" #include "mxtypes.h" #include "mxutil.h" @@ -11,6 +14,23 @@ class MxAtomId; class LegoEntity; class LegoAnimPresenter; +class LegoTexture; + +// SIZE 0x14 +class NamedTexture { +public: + ~NamedTexture() { delete m_texture; } + + // FUNCTION: LEGO1 0x1003f920 + const MxString* GetName() const { return &m_name; } + + LegoTexture* GetTexture() { return m_texture; } + +private: + MxString m_name; // 0x00 + LegoTexture* m_texture; // 0x04 +}; + void FUN_1003e050(LegoAnimPresenter* p_presenter); Extra::ActionType MatchActionString(const char*); void InvokeAction(Extra::ActionType p_actionId, MxAtomId& p_pAtom, int p_targetEntityId, LegoEntity* p_sender); @@ -20,5 +40,11 @@ void FUN_1003ef00(MxBool); void SetAppCursor(WPARAM p_wparam); MxBool FUN_1003ef60(); MxBool RemoveFromWorld(MxAtomId& p_atomId1, MxS32 p_id1, MxAtomId& p_atomId2, MxS32 p_id2); +NamedTexture* ReadNamedTexture(LegoFile* p_file); +void FUN_1003f540(LegoFile* p_file, const char* p_filename); +void WriteNamedTexture(LegoFile* p_file, NamedTexture* p_texture); + +// SYNTHETIC: LEGO1 0x10034b40 +// LegoTexture::`scalar deleting destructor' #endif // LEGOUTIL_H diff --git a/LEGO1/lego/legoomni/src/act1/act1state.cpp b/LEGO1/lego/legoomni/src/act1/act1state.cpp index cd39f1e2..b4696e2e 100644 --- a/LEGO1/lego/legoomni/src/act1/act1state.cpp +++ b/LEGO1/lego/legoomni/src/act1/act1state.cpp @@ -1,30 +1,268 @@ #include "act1state.h" +DECOMP_SIZE_ASSERT(Act1State, 0x26c) +DECOMP_SIZE_ASSERT(Act1State::NamedPlane, 0x4c) + +// GLOBAL: ISLE 0x100f37f0 +MxS32 g_unk0x100f37f0[] = { + Act1State::e_unk953, + Act1State::e_unk954, + Act1State::e_unk955, +}; + // STUB: LEGO1 0x100334b0 -Act1State::Act1State() +Act1State::Act1State() : m_unk0x00c(0), m_unk0x00e(0), m_unk0x008(NULL), m_unk0x010(0) { - // TODO - m_unk0x1e = 0; - m_unk0x18 = 1; - m_unk0x20 = 0; - m_unk0x1f = 0; - m_unk0x21 = TRUE; - m_unk0x22 = 0; - m_unk0x1c = 1; + m_unk0x01e = 0; + m_unk0x018 = 1; + m_unk0x010 = 0; + m_unk0x020 = 0; + m_unk0x00e = 0; + m_unk0x01f = 0; + m_unk0x008 = g_unk0x100f37f0; + m_unk0x014 = -1; + m_unk0x022 = 0; + m_unk0x154 = NULL; + m_unk0x158 = NULL; + m_unk0x15c = NULL; + m_unk0x160 = NULL; + m_unk0x1b0 = NULL; + m_unk0x021 = 1; + m_unk0x01c = 1; + m_unk0x00c = _countof(g_unk0x100f37f0); + m_unk0x1b4 = NULL; + m_unk0x1b8 = NULL; + m_unk0x208 = NULL; + m_unk0x20c = NULL; + m_unk0x25c = NULL; + m_unk0x260 = NULL; + m_unk0x264 = NULL; + m_unk0x268 = NULL; + SetFlag(); } -// STUB: LEGO1 0x10033ac0 +// FUNCTION: LEGO1 0x10033ac0 MxResult Act1State::VTable0x1c(LegoFile* p_legoFile) { + if (p_legoFile->IsWriteMode()) { + p_legoFile->FUN_10006030(ClassName()); + } + + m_unk0x024.Serialize(p_legoFile); + m_unk0x070.Serialize(p_legoFile); + m_unk0x0bc.Serialize(p_legoFile); + m_unk0x108.Serialize(p_legoFile); + m_unk0x164.Serialize(p_legoFile); + m_unk0x1bc.Serialize(p_legoFile); + m_unk0x210.Serialize(p_legoFile); + + if (p_legoFile->IsWriteMode()) { + if (m_unk0x108.GetName()->Compare("") != 0) { + if (m_unk0x154) { + WriteNamedTexture(p_legoFile, m_unk0x154); + } + else { + FUN_1003f540(p_legoFile, "chwind.gif"); + } + if (m_unk0x158) { + WriteNamedTexture(p_legoFile, m_unk0x158); + } + else { + FUN_1003f540(p_legoFile, "chjetl.gif"); + } + if (m_unk0x15c) { + WriteNamedTexture(p_legoFile, m_unk0x15c); + } + else { + FUN_1003f540(p_legoFile, "chjetr.gif"); + } + } + if (m_unk0x164.GetName()->Compare("") != 0) { + if (m_unk0x1b0) { + WriteNamedTexture(p_legoFile, m_unk0x1b0); + } + else { + FUN_1003f540(p_legoFile, "jsfrnt.gif"); + } + if (m_unk0x1b4) { + WriteNamedTexture(p_legoFile, m_unk0x1b4); + } + else { + FUN_1003f540(p_legoFile, "jswnsh.gif"); + } + } + if (m_unk0x1bc.GetName()->Compare("") != 0) { + if (m_unk0x208) { + WriteNamedTexture(p_legoFile, m_unk0x208); + } + else { + FUN_1003f540(p_legoFile, "dbfrfn.gif"); + } + } + if (m_unk0x210.GetName()->Compare("") != 0) { + if (m_unk0x25c) { + WriteNamedTexture(p_legoFile, m_unk0x25c); + } + else { + FUN_1003f540(p_legoFile, "rcfrnt.gif"); + } + if (m_unk0x260) { + WriteNamedTexture(p_legoFile, m_unk0x260); + } + else { + FUN_1003f540(p_legoFile, "rcback.gif"); + } + if (m_unk0x264) { + WriteNamedTexture(p_legoFile, m_unk0x264); + } + else { + FUN_1003f540(p_legoFile, "rctail.gif"); + } + } + + p_legoFile->Write(&m_unk0x010, sizeof(undefined2)); + p_legoFile->Write(&m_unk0x022, sizeof(undefined)); + } + else if (p_legoFile->IsReadMode()) { + if (m_unk0x108.GetName()->Compare("") != 0) { + m_unk0x154 = ReadNamedTexture(p_legoFile); + if (m_unk0x154 == NULL) { + return FAILURE; + } + + m_unk0x158 = ReadNamedTexture(p_legoFile); + if (m_unk0x158 == NULL) { + return FAILURE; + } + + m_unk0x15c = ReadNamedTexture(p_legoFile); + if (m_unk0x15c == NULL) { + return FAILURE; + } + } + if (m_unk0x164.GetName()->Compare("") != 0) { + m_unk0x1b0 = ReadNamedTexture(p_legoFile); + if (m_unk0x1b0 == NULL) { + return FAILURE; + } + + m_unk0x1b4 = ReadNamedTexture(p_legoFile); + if (m_unk0x1b4 == NULL) { + return FAILURE; + } + } + if (m_unk0x1bc.GetName()->Compare("") != 0) { + m_unk0x208 = ReadNamedTexture(p_legoFile); + if (m_unk0x208 == NULL) { + return FAILURE; + } + } + if (m_unk0x210.GetName()->Compare("") != 0) { + m_unk0x25c = ReadNamedTexture(p_legoFile); + if (m_unk0x25c == NULL) { + return FAILURE; + } + + m_unk0x260 = ReadNamedTexture(p_legoFile); + if (m_unk0x260 == NULL) { + return FAILURE; + } + + m_unk0x264 = ReadNamedTexture(p_legoFile); + if (m_unk0x264 == NULL) { + return FAILURE; + } + } + + p_legoFile->Read(&m_unk0x010, sizeof(undefined2)); + p_legoFile->Read(&m_unk0x022, sizeof(undefined)); + } + // TODO return SUCCESS; } -// STUB: LEGO1 0x100346d0 +// FUNCTION: LEGO1 0x100346d0 MxBool Act1State::SetFlag() { - // TODO - return FALSE; + m_unk0x024.SetName(""); + m_unk0x070.SetName(""); + m_unk0x0bc.SetName(""); + m_unk0x022 = 0; + m_unk0x108.SetName(""); + + if (m_unk0x154) { + delete m_unk0x154; + m_unk0x154 = NULL; + } + + if (m_unk0x158) { + delete m_unk0x158; + m_unk0x158 = NULL; + } + + if (m_unk0x15c) { + delete m_unk0x15c; + m_unk0x15c = NULL; + } + + if (m_unk0x160) { + delete m_unk0x160; + m_unk0x160 = NULL; + } + + m_unk0x164.SetName(""); + + if (m_unk0x1b0) { + delete m_unk0x1b0; + m_unk0x1b0 = NULL; + } + + if (m_unk0x1b4) { + delete m_unk0x1b4; + m_unk0x1b4 = NULL; + } + + if (m_unk0x1b8) { + delete m_unk0x1b8; + m_unk0x1b8 = NULL; + } + + m_unk0x1bc.SetName(""); + + if (m_unk0x208) { + delete m_unk0x208; + m_unk0x208 = NULL; + } + + if (m_unk0x20c) { + delete m_unk0x20c; + m_unk0x20c = NULL; + } + + m_unk0x210.SetName(""); + + if (m_unk0x25c) { + delete m_unk0x25c; + m_unk0x25c = NULL; + } + + if (m_unk0x260) { + delete m_unk0x260; + m_unk0x260 = NULL; + } + + if (m_unk0x264) { + delete m_unk0x264; + m_unk0x264 = NULL; + } + + if (m_unk0x268) { + delete m_unk0x268; + m_unk0x268 = NULL; + } + + return TRUE; } // STUB: LEGO1 0x10034d00 diff --git a/LEGO1/lego/legoomni/src/common/legoutil.cpp b/LEGO1/lego/legoomni/src/common/legoutil.cpp index 51cf4342..c6d0c22e 100644 --- a/LEGO1/lego/legoomni/src/common/legoutil.cpp +++ b/LEGO1/lego/legoomni/src/common/legoutil.cpp @@ -10,6 +10,8 @@ #include <process.h> #include <string.h> +DECOMP_SIZE_ASSERT(NamedTexture, 0x14) + // STUB: LEGO1 0x1003e050 void FUN_1003e050(LegoAnimPresenter* p_presenter) { @@ -253,3 +255,21 @@ MxBool FUN_1003ef60() { return TRUE; } + +// STUB: LEGO1 0x1003f3b0 +NamedTexture* ReadNamedTexture(LegoFile* p_file) +{ + return NULL; +} + +// STUB: LEGO1 0x1003f540 +void FUN_1003f540(LegoFile* p_file, const char* p_filename) +{ +} + +// FUNCTION: LEGO1 0x1003f8a0 +void WriteNamedTexture(LegoFile* p_file, NamedTexture* p_texture) +{ + p_file->FUN_10006030(*p_texture->GetName()); + p_texture->GetTexture()->Write(p_file); +} diff --git a/LEGO1/lego/legoomni/src/infocenter/elevatorbottom.cpp b/LEGO1/lego/legoomni/src/infocenter/elevatorbottom.cpp index 98e7d1b9..d8a87fa4 100644 --- a/LEGO1/lego/legoomni/src/infocenter/elevatorbottom.cpp +++ b/LEGO1/lego/legoomni/src/infocenter/elevatorbottom.cpp @@ -14,7 +14,7 @@ DECOMP_SIZE_ASSERT(ElevatorBottom, 0xfc) // STRING: LEGO1 0x100f0d34 // GLOBAL: LEGO1 0x100f3a44 -char* g_cameraLoc = "CAMERA_LOCATION"; +const char* g_cameraLoc = "CAMERA_LOCATION"; // FUNCTION: LEGO1 0x10017e90 ElevatorBottom::ElevatorBottom() diff --git a/LEGO1/lego/sources/misc/legostorage.h b/LEGO1/lego/sources/misc/legostorage.h index 97dcc538..e975c347 100644 --- a/LEGO1/lego/sources/misc/legostorage.h +++ b/LEGO1/lego/sources/misc/legostorage.h @@ -2,6 +2,7 @@ #define __LEGOSTORAGE_H #include "legotypes.h" +#include "mxgeometry/mxgeometry3d.h" #include "mxstring.h" #include <stdio.h> @@ -72,6 +73,45 @@ public: LegoResult SetPosition(LegoU32 p_position) override; LegoResult Open(const char* p_name, LegoU32 p_mode); + // FUNCTION: LEGO1 0x100343d0 + LegoStorage* WriteVector3(Mx3DPointFloat p_vec3) + { + float data = p_vec3[0]; + Write(&data, sizeof(float)); + + data = p_vec3[1]; + Write(&data, sizeof(float)); + + data = p_vec3[2]; + Write(&data, sizeof(float)); + return this; + } + + // FUNCTION: LEGO1 0x10034430 + LegoStorage* ReadVector3(Mx3DPointFloat& p_vec3) + { + Read(&p_vec3[0], sizeof(float)); + Read(&p_vec3[1], sizeof(float)); + Read(&p_vec3[2], sizeof(float)); + return this; + } + + // FUNCTION: LEGO1 0x10034470 + LegoStorage* ReadString(MxString& p_str) + { + MxS16 len; + Read(&len, sizeof(MxS16)); + + char* text = new char[len + 1]; + Read(text, len); + + text[len] = '\0'; + p_str = text; + delete[] text; + + return this; + } + // FUNCTION: LEGO1 0x10006030 LegoStorage* FUN_10006030(MxString p_str) { diff --git a/LEGO1/mxgeometry/mxgeometry3d.h b/LEGO1/mxgeometry/mxgeometry3d.h index 837a5b3a..bdb3f191 100644 --- a/LEGO1/mxgeometry/mxgeometry3d.h +++ b/LEGO1/mxgeometry/mxgeometry3d.h @@ -15,6 +15,9 @@ public: m_elements[2] = p_z; } + // FUNCTION: LEGO1 0x100343a0 + inline Mx3DPointFloat(const Mx3DPointFloat& p_other) : Vector3(m_elements) { EqualsImpl(p_other.m_data); } + // SYNTHETIC: LEGO1 0x1001d170 // Mx3DPointFloat::Mx3DPointFloat diff --git a/util/decomp.h b/util/decomp.h index 3470fcc3..100f9f21 100644 --- a/util/decomp.h +++ b/util/decomp.h @@ -14,7 +14,7 @@ #endif #ifndef _countof -#define _countof(arr) sizeof(arr) / sizeof(arr[0]) +#define _countof(arr) (sizeof(arr) / sizeof(arr[0])) #endif typedef unsigned char undefined;