diff --git a/LEGO1/lego/legoomni/include/animstate.h b/LEGO1/lego/legoomni/include/animstate.h index 16c92120..507858be 100644 --- a/LEGO1/lego/legoomni/include/animstate.h +++ b/LEGO1/lego/legoomni/include/animstate.h @@ -3,6 +3,33 @@ #include "legostate.h" +// SIZE 0x30 +struct ModelInfo { + char* m_modelName; // 0x00 + MxU8 m_unk0x04; // 0x04 + float m_location[3]; // 0x08 + float m_direction[3]; // 0x14 + float m_up[3]; // 0x20 + MxU8 m_unk0x2c; // 0x2c +}; + +// SIZE 0x30 +struct AnimInfo { + char* m_animName; // 0x00 + undefined4 m_unk0x04; // 0x04 + MxS16 m_unk0x08; // 0x08 + MxU8 m_unk0x0a; // 0x0a + MxU8 m_unk0x0b; // 0x0b + MxU8 m_unk0x0c; // 0x0c + MxU8 m_unk0x0d; // 0x0d + MxU32 m_unk0x10[4]; // 0x10 + MxU8 m_modelCount; // 0x20 + ModelInfo* m_models; // 0x24 + MxU8 m_unk0x28; // 0x28 + MxU8 m_unk0x29; // 0x29 + MxS8 m_unk0x2a[3]; // 0x2a +}; + // VTABLE: LEGO1 0x100d8d80 // SIZE 0x1c class AnimState : public LegoState { @@ -26,6 +53,9 @@ class AnimState : public LegoState { MxBool SetFlag() override; // vtable+0x18 MxResult VTable0x1c(LegoFile* p_legoFile) override; // vtable+0x1c + void FUN_100651d0(MxU32, AnimInfo*, MxU32&); + void FUN_10065240(MxU32, AnimInfo*, MxU32); + // SYNTHETIC: LEGO1 0x10065130 // AnimState::`scalar deleting destructor' diff --git a/LEGO1/lego/legoomni/include/isle.h b/LEGO1/lego/legoomni/include/isle.h index f94e6832..1945a0f9 100644 --- a/LEGO1/lego/legoomni/include/isle.h +++ b/LEGO1/lego/legoomni/include/isle.h @@ -24,6 +24,7 @@ class Isle : public LegoWorld { public: Isle(); ~Isle() override; + MxLong Notify(MxParam& p_param) override; // vtable+0x04 // FUNCTION: LEGO1 0x10030910 @@ -42,22 +43,25 @@ class Isle : public LegoWorld { MxResult Create(MxDSAction& p_dsAction) override; // vtable+0x18 void ReadyWorld() override; // vtable+50 void Add(MxCore* p_object) override; // vtable+58 + // FUNCTION: LEGO1 0x10030900 MxBool VTable0x5c() override { return TRUE; } // vtable+5c + // FUNCTION: LEGO1 0x10033170 - void VTable0x60() override {} // vtable+60 + void VTable0x60() override {} // vtable+60 + MxBool VTable0x64() override; // vtable+64 void Enable(MxBool p_enable) override; // vtable+68 virtual void VTable0x6c(IslePathActor* p_actor); // vtable+6c - inline void SetUnknown13c(MxU32 p_unk0x13c) { m_unk0x13c = p_unk0x13c; } - MxLong StopAction(MxParam& p_param); MxLong HandleType17Notification(MxParam& p_param); MxLong HandleType19Notification(MxParam& p_param); MxLong HandleTransitionEnd(); void FUN_10032620(); + inline void SetUnknown13c(MxU32 p_unk0x13c) { m_unk0x13c = p_unk0x13c; } + // SYNTHETIC: LEGO1 0x10030a30 // Isle::`scalar deleting destructor' diff --git a/LEGO1/lego/legoomni/include/legoanimationmanager.h b/LEGO1/lego/legoomni/include/legoanimationmanager.h index 31ee5a37..adce38cd 100644 --- a/LEGO1/lego/legoomni/include/legoanimationmanager.h +++ b/LEGO1/lego/legoomni/include/legoanimationmanager.h @@ -1,15 +1,24 @@ #ifndef LEGOANIMATIONMANAGER_H #define LEGOANIMATIONMANAGER_H +#include "animstate.h" #include "decomp.h" +#include "legotraninfolist.h" #include "mxcore.h" +// SIZE 0x18 +struct Character { + char* m_name; // 0x00 + undefined m_unk0x04[0x10]; // 0x04 + MxBool m_active; // 0x14 +}; + // VTABLE: LEGO1 0x100d8c18 // SIZE 0x500 class LegoAnimationManager : public MxCore { public: LegoAnimationManager(); - ~LegoAnimationManager() override; // vtable+0x00 + ~LegoAnimationManager() override; MxLong Notify(MxParam& p_param) override; // vtable+0x04 MxResult Tickle() override; // vtable+0x08 @@ -31,8 +40,14 @@ class LegoAnimationManager : public MxCore { void FUN_1005ef10(); void FUN_1005f0b0(); void FUN_1005f6d0(MxBool); - void FUN_1005f720(MxS32 p_scriptIndex); + MxResult LoadScriptInfo(MxS32 p_scriptIndex); + MxBool FUN_10060140(char* p_name, MxU32& p_index); + MxResult ReadAnimInfo(LegoFile* p_file, AnimInfo* p_info); + MxResult ReadModelInfo(LegoFile* p_file, ModelInfo* p_info); + void FUN_100603c0(); void FUN_10061010(undefined4); + void FUN_100617c0(MxS32, MxU16&, MxU32&); + MxS8 FUN_10062360(char*); void FUN_10064670(MxBool); static void configureLegoAnimationManager(MxS32 p_legoAnimationManagerConfig); @@ -43,7 +58,34 @@ class LegoAnimationManager : public MxCore { private: void Init(); - undefined m_unk0x08[0x4f8]; // 0x08 + undefined4 m_unk0x08; // 0x08 + MxU16 m_animCount; // 0x0c + MxU16 m_unk0x0e; // 0x0e + MxU32 m_unk0x10; // 0x10 + AnimInfo* m_anims; // 0x14 + undefined m_unk0x018[8]; // 0x18 + LegoTranInfoList* m_tranInfoList; // 0x20 + LegoTranInfoList* m_tranInfoList2; // 0x24 + undefined4 m_unk0x28[2]; // 0x28 + undefined4 m_unk0x30[2]; // 0x30 + undefined m_unk0x38; // 0x38 + undefined m_unk0x39; // 0x39 + undefined m_unk0x3a; // 0x3a + undefined m_unk0x3b[0x3c1]; // 0x3b + undefined4 m_unk0x3fc; // 0x3fc + MxU8 m_unk0x400; // 0x400 + undefined m_unk0x401; // 0x401 + MxU8 m_unk0x402; // 0x402 + undefined m_unk0x403[0x1d]; // 0x403 + AnimState* m_animState; // 0x420 + undefined4 m_unk0x424; // 0x424 + undefined m_unk0x428; // 0x428 + undefined m_unk0x429; // 0x429 + undefined m_unk0x42a; // 0x42a + undefined m_unk0x42b; // 0x42b + undefined4 m_unk0x42c; // 0x42c + undefined m_unk0x430; // 0x430 + undefined m_unk0x431[0xcf]; // 0x431 }; #endif // LEGOANIMATIONMANAGER_H diff --git a/LEGO1/lego/legoomni/include/legoomni.h b/LEGO1/lego/legoomni/include/legoomni.h index 5d1df4fa..a8fb5191 100644 --- a/LEGO1/lego/legoomni/include/legoomni.h +++ b/LEGO1/lego/legoomni/include/legoomni.h @@ -98,7 +98,6 @@ class LegoOmni : public MxOmni { inline MxS32 GetIndex() { return m_index; } inline const char* GetKey() { return m_key; } - private: MxS32 m_index; // 0x00 char m_key[20]; // 0x04 MxAtomId* m_script; // 0x18 @@ -203,6 +202,7 @@ class LegoOmni : public MxOmni { MxS32 GetScriptIndex(const char* p_key); static MxS32 GetCurrPathInfo(LegoPathBoundary**, MxS32&); + const char* FindScript(MxU32 p_id); static void CreateInstance(); static LegoOmni* GetInstance(); diff --git a/LEGO1/lego/legoomni/include/legotraninfo.h b/LEGO1/lego/legoomni/include/legotraninfo.h new file mode 100644 index 00000000..ee29fc58 --- /dev/null +++ b/LEGO1/lego/legoomni/include/legotraninfo.h @@ -0,0 +1,11 @@ +#ifndef LEGOTRANINFO_H +#define LEGOTRANINFO_H + +#include "decomp.h" + +// SIZE 0x78 +struct LegoTranInfo { // See FUN_100609f0 for construction + undefined m_unk0x00[0x78]; // 0x00 +}; + +#endif // LEGOTRANINFO_H diff --git a/LEGO1/lego/legoomni/include/legotraninfolist.h b/LEGO1/lego/legoomni/include/legotraninfolist.h new file mode 100644 index 00000000..96c46535 --- /dev/null +++ b/LEGO1/lego/legoomni/include/legotraninfolist.h @@ -0,0 +1,51 @@ +#ifndef LEGOTRANINFOLIST_H +#define LEGOTRANINFOLIST_H + +#include "legotraninfo.h" +#include "mxlist.h" +#include "mxtypes.h" + +// VTABLE: LEGO1 0x100d8ca8 +// class MxCollection + +// VTABLE: LEGO1 0x100d8cc0 +// class MxList + +// VTABLE: LEGO1 0x100d8cd8 +// class MxPtrList + +// VTABLE: LEGO1 0x100d8c90 +// SIZE 0x18 +class LegoTranInfoList : public MxPtrList { +public: + LegoTranInfoList() : MxPtrList(FALSE) {} +}; + +// TEMPLATE: LEGO1 0x1005fdf0 +// MxCollection::Compare + +// TEMPLATE: LEGO1 0x1005fe00 +// MxCollection::~MxCollection + +// TEMPLATE: LEGO1 0x1005fe50 +// MxCollection::Destroy + +// TEMPLATE: LEGO1 0x1005fe60 +// MxList::~MxList + +// SYNTHETIC: LEGO1 0x1005fef0 +// LegoTranInfoList::`scalar deleting destructor' + +// TEMPLATE: LEGO1 0x1005ff60 +// MxPtrList::~MxPtrList + +// SYNTHETIC: LEGO1 0x1005ffb0 +// MxCollection::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x10060020 +// MxList::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x100600d0 +// MxPtrList::`scalar deleting destructor' + +#endif // LEGOTRANINFOLIST_H diff --git a/LEGO1/lego/legoomni/src/common/animstate.cpp b/LEGO1/lego/legoomni/src/common/animstate.cpp index c7665237..4a4aa53f 100644 --- a/LEGO1/lego/legoomni/src/common/animstate.cpp +++ b/LEGO1/lego/legoomni/src/common/animstate.cpp @@ -1,6 +1,8 @@ #include "animstate.h" -DECOMP_SIZE_ASSERT(AnimState, 0x1c); +DECOMP_SIZE_ASSERT(AnimState, 0x1c) +DECOMP_SIZE_ASSERT(ModelInfo, 0x30) +DECOMP_SIZE_ASSERT(AnimInfo, 0x30) // FUNCTION: LEGO1 0x10064ff0 AnimState::AnimState() @@ -17,6 +19,18 @@ AnimState::~AnimState() // TODO } +// STUB: LEGO1 0x100651d0 +void AnimState::FUN_100651d0(MxU32, AnimInfo*, MxU32&) +{ + // TODO +} + +// STUB: LEGO1 0x10065240 +void AnimState::FUN_10065240(MxU32, AnimInfo*, MxU32) +{ + // TODO +} + // STUB: LEGO1 0x100652d0 MxResult AnimState::VTable0x1c(LegoFile* p_legoFile) { diff --git a/LEGO1/lego/legoomni/src/common/legoanimationmanager.cpp b/LEGO1/lego/legoomni/src/common/legoanimationmanager.cpp index bdf3eb98..452e88ca 100644 --- a/LEGO1/lego/legoomni/src/common/legoanimationmanager.cpp +++ b/LEGO1/lego/legoomni/src/common/legoanimationmanager.cpp @@ -1,9 +1,19 @@ #include "legoanimationmanager.h" +#include "legogamestate.h" +#include "legoomni.h" +#include "misc.h" +#include "mxutilities.h" + +#include + DECOMP_SIZE_ASSERT(LegoAnimationManager, 0x500) +// GLOBAL: LEGO1 0x100f7048 +Character g_characters[47]; // TODO: Initialize this + // GLOBAL: LEGO1 0x100f74f8 -int g_legoAnimationManagerConfig = 1; +MxS32 g_legoAnimationManagerConfig = 1; // FUNCTION: LEGO1 0x1005eb50 void LegoAnimationManager::configureLegoAnimationManager(MxS32 p_legoAnimationManagerConfig) @@ -53,8 +63,277 @@ void LegoAnimationManager::FUN_1005f6d0(MxBool) // TODO } -// STUB: LEGO1 0x1005f720 -void LegoAnimationManager::FUN_1005f720(MxS32 p_scriptIndex) +// FUNCTION: LEGO1 0x1005f720 +MxResult LegoAnimationManager::LoadScriptInfo(MxS32 p_scriptIndex) +{ + MxResult result = FAILURE; + MxS32 i, j, k; + + if (m_unk0x08 != p_scriptIndex) { + if (m_tranInfoList != NULL) { + delete m_tranInfoList; + m_tranInfoList = NULL; + } + + if (m_tranInfoList2 != NULL) { + delete m_tranInfoList2; + m_tranInfoList2 = NULL; + } + + for (i = 0; i < (MxS32) _countof(m_unk0x28); i++) { + m_unk0x28[i] = 0; + m_unk0x30[i] = 0; + } + + m_unk0x38 = 0; + m_unk0x39 = 0; + m_unk0x430 = 0; + m_unk0x42c = 0; + + for (j = 0; j < (MxS32) _countof(g_characters); j++) { + g_characters[j].m_active = FALSE; + } + + m_animState = (AnimState*) GameState()->GetState("AnimState"); + if (m_animState == NULL) { + m_animState = (AnimState*) GameState()->CreateState("AnimState"); + } + + if (m_unk0x08 == 0) { + m_animState->FUN_10065240(m_animCount, m_anims, m_unk0x3fc); + } + + FUN_100603c0(); + + LegoFile file; + + if (p_scriptIndex == -1) { + result = SUCCESS; + goto done; + } + + char filename[128]; + char path[1024]; + sprintf(filename, "lego\\data\\%sinf.dta", Lego()->FindScript(p_scriptIndex)); + sprintf(path, "%s", MxOmni::GetHD()); + + if (path[strlen(path) - 1] != '\\') { + strcat(path, "\\"); + } + + strcat(path, filename); + + if (_access(path, 4)) { + sprintf(path, "%s", MxOmni::GetCD()); + + if (path[strlen(path) - 1] != '\\') { + strcat(path, "\\"); + } + + strcat(path, filename); + + if (_access(path, 4)) { + goto done; + } + } + + if (file.Open(path, LegoFile::c_read) == FAILURE) { + goto done; + } + + MxU32 version; + if (file.Read(&version, sizeof(version)) == FAILURE) { + goto done; + } + + if (version != 3) { + OmniError("World animation version mismatch", 0); + goto done; + } + + if (file.Read(&m_animCount, sizeof(m_animCount)) == FAILURE) { + goto done; + } + + m_anims = new AnimInfo[m_animCount]; + memset(m_anims, 0, m_animCount * sizeof(*m_anims)); + + for (j = 0; j < m_animCount; j++) { + if (ReadAnimInfo(&file, &m_anims[j]) == FAILURE) { + goto done; + } + + m_anims[j].m_unk0x28 = FUN_10062360(m_anims[j].m_animName + strlen(m_anims[j].m_animName) - 2); + m_anims[j].m_unk0x29 = 0; + + for (k = 0; k < 3; k++) { + m_anims[j].m_unk0x2a[k] = -1; + } + + if (m_anims[j].m_unk0x08 == -1) { + for (MxS32 l = 0; l < m_anims[j].m_modelCount; l++) { + MxS32 index = FUN_10062360(m_anims[j].m_models[l].m_modelName); + + if (index >= 0) { + g_characters[index].m_active = TRUE; + } + } + } + + MxS32 count = 0; + for (MxS32 m = 0; m < m_anims[j].m_modelCount; m++) { + MxU32 n; + + if (FUN_10060140(m_anims[j].m_models[m].m_modelName, n) && m_anims[j].m_models[m].m_unk0x2c) { + m_anims[j].m_unk0x2a[count++] = n; + if (count > 3) { + break; + } + } + } + } + + m_unk0x08 = p_scriptIndex; + m_tranInfoList = new LegoTranInfoList(); + m_tranInfoList2 = new LegoTranInfoList(); + + FUN_100617c0(-1, m_unk0x0e, m_unk0x10); + + result = SUCCESS; + m_unk0x402 = 1; + + if (m_unk0x42b) { + m_unk0x428 = m_unk0x3a; + m_unk0x429 = m_unk0x400; + m_unk0x42a = 1; + m_unk0x3a = 0; + m_unk0x400 = 0; + m_unk0x402 = 0; + } + + if (p_scriptIndex == 0) { + m_animState->FUN_100651d0(m_animCount, m_anims, m_unk0x3fc); + } + } + +done: + if (result == FAILURE) { + FUN_100603c0(); + } + + return result; +} + +// STUB: LEGO1 0x10060140 +MxBool LegoAnimationManager::FUN_10060140(char* p_name, MxU32& p_index) +{ + // TODO + return FALSE; +} + +// FUNCTION: LEGO1 0x10060180 +MxResult LegoAnimationManager::ReadAnimInfo(LegoFile* p_file, AnimInfo* p_info) +{ + MxResult result = FAILURE; + MxU8 length; + MxS32 i, j; + + if (p_file->Read(&length, sizeof(length)) == FAILURE) { + goto done; + } + + p_info->m_animName = new char[length + 1]; + if (p_file->Read(p_info->m_animName, length) == FAILURE) { + goto done; + } + + p_info->m_animName[length] = 0; + if (p_file->Read(&p_info->m_unk0x04, sizeof(p_info->m_unk0x04)) == FAILURE) { + goto done; + } + + if (p_file->Read(&p_info->m_unk0x08, sizeof(p_info->m_unk0x08)) == FAILURE) { + goto done; + } + if (p_file->Read(&p_info->m_unk0x0a, sizeof(p_info->m_unk0x0a)) == FAILURE) { + goto done; + } + if (p_file->Read(&p_info->m_unk0x0b, sizeof(p_info->m_unk0x0b)) == FAILURE) { + goto done; + } + if (p_file->Read(&p_info->m_unk0x0c, sizeof(p_info->m_unk0x0c)) == FAILURE) { + goto done; + } + if (p_file->Read(&p_info->m_unk0x0d, sizeof(p_info->m_unk0x0d)) == FAILURE) { + goto done; + } + + for (i = 0; i < (MxS32) _countof(p_info->m_unk0x10); i++) { + if (p_file->Read(&p_info->m_unk0x10[i], sizeof(*p_info->m_unk0x10)) != SUCCESS) { + goto done; + } + } + + if (p_file->Read(&p_info->m_modelCount, sizeof(p_info->m_modelCount)) == FAILURE) { + goto done; + } + + p_info->m_models = new ModelInfo[p_info->m_modelCount]; + memset(p_info->m_models, 0, p_info->m_modelCount * sizeof(*p_info->m_models)); + + for (j = 0; j < p_info->m_modelCount; j++) { + if (ReadModelInfo(p_file, &p_info->m_models[j]) == FAILURE) { + goto done; + } + } + + result = SUCCESS; + +done: + return result; +} + +// FUNCTION: LEGO1 0x10060310 +MxResult LegoAnimationManager::ReadModelInfo(LegoFile* p_file, ModelInfo* p_info) +{ + MxResult result = FAILURE; + MxU8 length; + + if (p_file->Read(&length, 1) == FAILURE) { + goto done; + } + + p_info->m_modelName = new char[length + 1]; + if (p_file->Read(p_info->m_modelName, length) == FAILURE) { + goto done; + } + + p_info->m_modelName[length] = 0; + if (p_file->Read(&p_info->m_unk0x04, sizeof(p_info->m_unk0x04)) == FAILURE) { + goto done; + } + + if (p_file->Read(p_info->m_location, sizeof(p_info->m_location)) != SUCCESS) { + goto done; + } + if (p_file->Read(p_info->m_direction, sizeof(p_info->m_direction)) != SUCCESS) { + goto done; + } + if (p_file->Read(p_info->m_up, sizeof(p_info->m_up)) != SUCCESS) { + goto done; + } + if (p_file->Read(&p_info->m_unk0x2c, sizeof(p_info->m_unk0x2c)) == FAILURE) { + goto done; + } + + result = SUCCESS; + +done: + return result; +} + +// STUB: LEGO1 0x100603c0 +void LegoAnimationManager::FUN_100603c0() { // TODO } @@ -65,11 +344,16 @@ void LegoAnimationManager::FUN_10061010(undefined4) // TODO } +// STUB: LEGO1 0x100617c0 +void LegoAnimationManager::FUN_100617c0(MxS32, MxU16&, MxU32&) +{ + // TODO +} + // STUB: LEGO1 0x100619f0 MxLong LegoAnimationManager::Notify(MxParam& p_param) { // TODO - return 0; } @@ -77,11 +361,18 @@ MxLong LegoAnimationManager::Notify(MxParam& p_param) MxResult LegoAnimationManager::Tickle() { // TODO - return SUCCESS; } +// STUB: LEGO1 0x10062360 +MxS8 LegoAnimationManager::FUN_10062360(char*) +{ + // TODO + return 0; +} + // STUB: LEGO1 0x10064670 void LegoAnimationManager::FUN_10064670(MxBool) { + // TODO } diff --git a/LEGO1/lego/legoomni/src/entity/legoworld.cpp b/LEGO1/lego/legoomni/src/entity/legoworld.cpp index fc31b459..12a69958 100644 --- a/LEGO1/lego/legoomni/src/entity/legoworld.cpp +++ b/LEGO1/lego/legoomni/src/entity/legoworld.cpp @@ -577,7 +577,7 @@ void LegoWorld::Enable(MxBool p_enable) if (m_scriptIndex != -1) { PlantManager()->FUN_10026360(m_scriptIndex); - AnimationManager()->FUN_1005f720(m_scriptIndex); + AnimationManager()->LoadScriptInfo(m_scriptIndex); BuildingManager()->FUN_1002fa00(); AnimationManager()->FUN_1005f0b0(); } diff --git a/LEGO1/lego/legoomni/src/entity/legoworldpresenter.cpp b/LEGO1/lego/legoomni/src/entity/legoworldpresenter.cpp index 76253d89..e3d93ba8 100644 --- a/LEGO1/lego/legoomni/src/entity/legoworldpresenter.cpp +++ b/LEGO1/lego/legoomni/src/entity/legoworldpresenter.cpp @@ -54,7 +54,7 @@ LegoWorldPresenter::~LegoWorldPresenter() if (m_entity) { MxS32 scriptIndex = ((LegoWorld*) m_entity)->GetScriptIndex(); PlantManager()->FUN_10026360(scriptIndex); - AnimationManager()->FUN_1005f720(scriptIndex); + AnimationManager()->LoadScriptInfo(scriptIndex); BuildingManager()->FUN_1002fa00(); result = ((LegoWorld*) m_entity)->VTable0x5c(); } diff --git a/LEGO1/lego/legoomni/src/main/legoomni.cpp b/LEGO1/lego/legoomni/src/main/legoomni.cpp index 32b40120..827d3341 100644 --- a/LEGO1/lego/legoomni/src/main/legoomni.cpp +++ b/LEGO1/lego/legoomni/src/main/legoomni.cpp @@ -706,6 +706,18 @@ MxS32 LegoOmni::GetCurrPathInfo(LegoPathBoundary** p_path, MxS32& p_value) return ::CurrentWorld()->GetCurrPathInfo(p_path, p_value); } +// FUNCTION: LEGO1 0x1005b430 +const char* LegoOmni::FindScript(MxU32 p_index) +{ + for (MxS32 i = 0; i < 19; i++) { + if (m_scripts[i].m_index == p_index) { + return m_scripts[i].m_key; + } + } + + return NULL; +} + // FUNCTION: LEGO1 0x1005b490 MxS32 LegoOmni::GetScriptIndex(const char* p_key) {