From 916c039e72b5b0ac2f65529f684e2ce6a8675c5f Mon Sep 17 00:00:00 2001 From: Christian Semmler Date: Thu, 25 Apr 2024 10:00:58 -0400 Subject: [PATCH] Implement/match LegoAnimPresenter::ParseExtra (#848) * Implement/match LegoAnimPresenter::ParseExtra * Fix --- LEGO1/define.cpp | 20 +++ LEGO1/define.h | 5 + .../lego/legoomni/include/legoanimpresenter.h | 81 ++++++++---- LEGO1/lego/legoomni/include/legopathactor.h | 2 +- .../legoomni/src/actors/islepathactor.cpp | 1 + .../src/common/legoanimmmpresenter.cpp | 1 + LEGO1/lego/legoomni/src/common/legoutils.cpp | 1 + .../lego/legoomni/src/paths/legoanimactor.cpp | 1 + .../legoomni/src/paths/legoextraactor.cpp | 1 + .../lego/legoomni/src/paths/legopathactor.cpp | 1 + .../legoomni/src/video/legoanimpresenter.cpp | 115 ++++++++++++++++-- LEGO1/modeldb/modeldb.cpp | 2 +- 12 files changed, 198 insertions(+), 33 deletions(-) diff --git a/LEGO1/define.cpp b/LEGO1/define.cpp index 1ff1f868..cdc2def9 100644 --- a/LEGO1/define.cpp +++ b/LEGO1/define.cpp @@ -12,10 +12,26 @@ const char* g_strANIMATION = "ANIMATION"; // STRING: LEGO1 0x10102024 const char* g_strATTACH_CAMERA = "ATTACH_CAMERA"; +// GLOBAL: LEGO1 0x10102080 +// STRING: LEGO1 0x100f4368 +const char* g_strFROM_PARENT = "FROM_PARENT"; + +// GLOBAL: LEGO1 0x10102084 +// STRING: LEGO1 0x10101fa4 +const char* g_strHIDE_ON_STOP = "HIDE_ON_STOP"; + +// GLOBAL: LEGO1 0x10102098 +// STRING: LEGO1 0x10101f60 +const char* g_strMUST_SUCCEED = "MUST_SUCCEED"; + // GLOBAL: LEGO1 0x1010209c // STRING: LEGO1 0x10101f58 const char* g_strOBJECT = "OBJECT"; +// GLOBAL: LEGO1 0x101020a8 +// STRING: LEGO1 0x10101f38 +const char* g_strPTATCAM = "PTATCAM"; + // GLOBAL: LEGO1 0x101020b0 // STRING: LEGO1 0x10101f20 const char* g_strSOUND = "SOUND"; @@ -28,6 +44,10 @@ const char* g_strMUTE = "MUTE"; // STRING: LEGO1 0x100f09cc const char* g_strSPEED = "SPEED"; +// GLOBAL: LEGO1 0x101020bc +// STRING: LEGO1 0x10101f10 +const char* g_strSUBST = "SUBST"; + // GLOBAL: LEGO1 0x101020cc // STRING: LEGO1 0x100f3808 const char* g_strVISIBILITY = "VISIBILITY"; diff --git a/LEGO1/define.h b/LEGO1/define.h index 086c4500..d975d1fb 100644 --- a/LEGO1/define.h +++ b/LEGO1/define.h @@ -14,5 +14,10 @@ extern const char* g_strSPEED; extern const char* g_strATTACH_CAMERA; extern const char* g_strMUTE; extern const char* g_strANIMMAN_ID; +extern const char* g_strFROM_PARENT; +extern const char* g_strHIDE_ON_STOP; +extern const char* g_strMUST_SUCCEED; +extern const char* g_strSUBST; +extern const char* g_strPTATCAM; #endif // DEFINE_H diff --git a/LEGO1/lego/legoomni/include/legoanimpresenter.h b/LEGO1/lego/legoomni/include/legoanimpresenter.h index af6d58be..30f858b0 100644 --- a/LEGO1/lego/legoomni/include/legoanimpresenter.h +++ b/LEGO1/lego/legoomni/include/legoanimpresenter.h @@ -16,6 +16,10 @@ struct LegoAnimStructComparator { MxBool operator()(const char* const& p_a, const char* const& p_b) const { return strcmp(p_a, p_b) < 0; } }; +struct LegoAnimSubstComparator { + MxBool operator()(const char* const& p_a, const char* const& p_b) const { return strcmp(p_a, p_b) < 0; } +}; + // SIZE 0x08 struct LegoAnimStruct { LegoROI* m_roi; // 0x00 @@ -23,14 +27,15 @@ struct LegoAnimStruct { }; typedef map LegoAnimPresenterMap; +typedef map LegoAnimSubstMap; // VTABLE: LEGO1 0x100d90c8 // SIZE 0xbc class LegoAnimPresenter : public MxVideoPresenter { public: enum { - c_bit1 = 0x01, - c_bit2 = 0x02 + c_hideOnStop = 0x01, + c_mustSucceed = 0x02 }; LegoAnimPresenter(); @@ -100,33 +105,48 @@ class LegoAnimPresenter : public MxVideoPresenter { void FUN_1006b9a0(LegoAnim* p_anim, MxLong p_time, Matrix4* p_matrix); void FUN_1006c8a0(MxBool p_bool); - LegoAnim* m_anim; // 0x64 - LegoROI** m_roiMap; // 0x68 - MxU32 m_roiMapSize; // 0x6c - LegoROIList* m_unk0x70; // 0x70 - LegoROIList* m_unk0x74; // 0x74 - MxMatrix* m_unk0x78; // 0x78 - MxU32 m_flags; // 0x7c - LegoWorld* m_currentWorld; // 0x80 - MxAtomId m_animAtom; // 0x84 - undefined4 m_unk0x88; // 0x88 - LegoROI** m_unk0x8c; // 0x8c - const char** m_unk0x90; // 0x90 - MxU8 m_unk0x94; // 0x94 - undefined m_unk0x95; // 0x95 - MxBool m_unk0x96; // 0x96 - undefined m_unk0x97; // 0x97 - undefined4 m_unk0x98; // 0x98 - MxS16 m_unk0x9c; // 0x9c - undefined4 m_unk0xa0; // 0xa0 - undefined4 m_unk0xa4; // 0xa4 - Mx3DPointFloat m_unk0xa8; // 0xa8 + LegoAnim* m_anim; // 0x64 + LegoROI** m_roiMap; // 0x68 + MxU32 m_roiMapSize; // 0x6c + LegoROIList* m_unk0x70; // 0x70 + LegoROIList* m_unk0x74; // 0x74 + MxMatrix* m_unk0x78; // 0x78 + MxU32 m_flags; // 0x7c + LegoWorld* m_currentWorld; // 0x80 + MxAtomId m_worldAtom; // 0x84 + MxS32 m_worldId; // 0x88 + LegoROI** m_unk0x8c; // 0x8c + char** m_unk0x90; // 0x90 + MxU8 m_unk0x94; // 0x94 + undefined m_unk0x95; // 0x95 + MxBool m_unk0x96; // 0x96 + undefined m_unk0x97; // 0x97 + LegoAnimSubstMap* m_substMap; // 0x98 + MxS16 m_unk0x9c; // 0x9c + undefined4 m_unk0xa0; // 0xa0 + undefined4 m_unk0xa4; // 0xa4 + Mx3DPointFloat m_unk0xa8; // 0xa8 }; // clang-format off // SYNTHETIC: LEGO1 0x10068650 // LegoAnimPresenter::`scalar deleting destructor' +// TEMPLATE: LEGO1 0x100689c0 +// map >::~map > + +// TEMPLATE: LEGO1 0x10068a10 +// _Tree,map >::_Kfn,LegoAnimSubstComparator,allocator >::~_Tree,map + +// TEMPLATE: LEGO1 0x10068ae0 +// _Tree,map >::_Kfn,LegoAnimSubstComparator,allocator >::iterator::_Inc + +// TEMPLATE: LEGO1 0x10068b20 +// _Tree,map >::_Kfn,LegoAnimSubstComparator,allocator >::erase + +// TEMPLATE: LEGO1 0x10068f70 +// _Tree,map >::_Kfn,LegoAnimSubstComparator,allocator >::_Erase + // TEMPLATE: LEGO1 0x10069d80 // _Tree,map >::_Kfn,LegoAnimStructComparator,allocator >::~_Tree,map >::_Kfn,LegoAnimStructComparator,allocator >::_Insert +// TEMPLATE: LEGO1 0x1006c1b0 +// _Tree,map >::_Kfn,LegoAnimSubstComparator,allocator >::iterator::_Dec + +// TEMPLATE: LEGO1 0x1006c200 +// _Tree,map >::_Kfn,LegoAnimSubstComparator,allocator >::_Insert + +// TEMPLATE: LEGO1 0x1006c4b0 +// list >::~list > + +// TEMPLATE: LEGO1 0x1006c520 +// List::~List + +// GLOBAL: LEGO1 0x100f7680 +// _Tree,map >::_Kfn,LegoAnimSubstComparator,allocator >::_Nil + // GLOBAL: LEGO1 0x100f7688 // _Tree,map >::_Kfn,LegoAnimStructComparator,allocator >::_Nil // clang-format on diff --git a/LEGO1/lego/legoomni/include/legopathactor.h b/LEGO1/lego/legoomni/include/legopathactor.h index d1bbd0ef..e9488e8e 100644 --- a/LEGO1/lego/legoomni/include/legopathactor.h +++ b/LEGO1/lego/legoomni/include/legopathactor.h @@ -3,11 +3,11 @@ #include "geom/legounkown100db7f4.h" #include "legoactor.h" -#include "legopathboundary.h" #include "misc/legounknown.h" #include "mxtypes.h" #include "realtime/matrix.h" +class LegoPathBoundary; class LegoPathController; // VTABLE: LEGO1 0x100d6e28 diff --git a/LEGO1/lego/legoomni/src/actors/islepathactor.cpp b/LEGO1/lego/legoomni/src/actors/islepathactor.cpp index faf9709c..46dce944 100644 --- a/LEGO1/lego/legoomni/src/actors/islepathactor.cpp +++ b/LEGO1/lego/legoomni/src/actors/islepathactor.cpp @@ -2,6 +2,7 @@ #include "legoanimationmanager.h" #include "legonavcontroller.h" +#include "legopathboundary.h" #include "legoutils.h" #include "misc.h" #include "mxnotificationparam.h" diff --git a/LEGO1/lego/legoomni/src/common/legoanimmmpresenter.cpp b/LEGO1/lego/legoomni/src/common/legoanimmmpresenter.cpp index 17b47b46..e93e9a60 100644 --- a/LEGO1/lego/legoomni/src/common/legoanimmmpresenter.cpp +++ b/LEGO1/lego/legoomni/src/common/legoanimmmpresenter.cpp @@ -4,6 +4,7 @@ #include "define.h" #include "islepathactor.h" #include "legoanimationmanager.h" +#include "legoanimpresenter.h" #include "legotraninfo.h" #include "legovideomanager.h" #include "legoworld.h" diff --git a/LEGO1/lego/legoomni/src/common/legoutils.cpp b/LEGO1/lego/legoomni/src/common/legoutils.cpp index 613b01a8..3cf3e705 100644 --- a/LEGO1/lego/legoomni/src/common/legoutils.cpp +++ b/LEGO1/lego/legoomni/src/common/legoutils.cpp @@ -2,6 +2,7 @@ #include "act1state.h" #include "islepathactor.h" +#include "legoanimpresenter.h" #include "legogamestate.h" #include "legoinputmanager.h" #include "legonamedtexture.h" diff --git a/LEGO1/lego/legoomni/src/paths/legoanimactor.cpp b/LEGO1/lego/legoomni/src/paths/legoanimactor.cpp index 832d05f9..c94b498d 100644 --- a/LEGO1/lego/legoomni/src/paths/legoanimactor.cpp +++ b/LEGO1/lego/legoomni/src/paths/legoanimactor.cpp @@ -2,6 +2,7 @@ #include "define.h" #include "legolocomotionanimpresenter.h" +#include "legopathboundary.h" #include "legoworld.h" #include "misc.h" #include "mxutilities.h" diff --git a/LEGO1/lego/legoomni/src/paths/legoextraactor.cpp b/LEGO1/lego/legoomni/src/paths/legoextraactor.cpp index 066615ed..4402756d 100644 --- a/LEGO1/lego/legoomni/src/paths/legoextraactor.cpp +++ b/LEGO1/lego/legoomni/src/paths/legoextraactor.cpp @@ -1,6 +1,7 @@ #include "legoextraactor.h" #include "legolocomotionanimpresenter.h" +#include "legopathboundary.h" #include "legosoundmanager.h" #include "misc.h" #include "mxmisc.h" diff --git a/LEGO1/lego/legoomni/src/paths/legopathactor.cpp b/LEGO1/lego/legoomni/src/paths/legopathactor.cpp index 945e5f27..977624b5 100644 --- a/LEGO1/lego/legoomni/src/paths/legopathactor.cpp +++ b/LEGO1/lego/legoomni/src/paths/legopathactor.cpp @@ -1,6 +1,7 @@ #include "legopathactor.h" #include "legonavcontroller.h" +#include "legopathboundary.h" #include "legosoundmanager.h" #include "misc.h" #include "mxmisc.h" diff --git a/LEGO1/lego/legoomni/src/video/legoanimpresenter.cpp b/LEGO1/lego/legoomni/src/video/legoanimpresenter.cpp index 2d0c2297..c3b8c107 100644 --- a/LEGO1/lego/legoomni/src/video/legoanimpresenter.cpp +++ b/LEGO1/lego/legoomni/src/video/legoanimpresenter.cpp @@ -1,8 +1,10 @@ #include "legoanimpresenter.h" +#include "define.h" #include "legoanimationmanager.h" #include "legoanimmmpresenter.h" #include "legocharactermanager.h" +#include "legopathboundary.h" #include "legovideomanager.h" #include "legoworld.h" #include "misc.h" @@ -13,6 +15,7 @@ #include "mxstreamchunk.h" #include "mxtimer.h" #include "mxtype18notificationparam.h" +#include "mxutilities.h" #include "mxvideomanager.h" #include "realtime/realtime.h" @@ -44,9 +47,9 @@ void LegoAnimPresenter::Init() m_unk0xa4 = 0; m_currentWorld = NULL; m_unk0x95 = 0; - m_unk0x88 = -1; - m_unk0x98 = 0; - m_animAtom.Clear(); + m_worldId = -1; + m_substMap = NULL; + m_worldAtom.Clear(); m_unk0x9c = 0; m_unk0x8c = NULL; m_unk0x90 = NULL; @@ -645,7 +648,7 @@ void LegoAnimPresenter::StartingTickle() FUN_100692b0(); FUN_100695c0(); - if (m_flags & c_bit2 && !FUN_1006aba0()) { + if (m_flags & c_mustSucceed && !FUN_1006aba0()) { goto done; } @@ -799,10 +802,106 @@ void LegoAnimPresenter::FUN_1006b9a0(LegoAnim* p_anim, MxLong p_time, Matrix4* p LegoROI::FUN_100a8e80(root, mat, p_time, m_roiMap); } -// STUB: LEGO1 0x1006bac0 +// FUNCTION: LEGO1 0x1006bac0 +// FUNCTION: BETA10 0x100512e1 void LegoAnimPresenter::ParseExtra() { - // TODO + MxU16 extraLength; + char* extraData; + m_action->GetExtra(extraLength, extraData); + + if (extraLength & MAXWORD) { + char extraCopy[256]; + memcpy(extraCopy, extraData, extraLength & MAXWORD); + extraCopy[extraLength & MAXWORD] = '\0'; + + char output[256]; + if (KeyValueStringParse(NULL, g_strFROM_PARENT, extraCopy) && m_compositePresenter != NULL) { + m_compositePresenter->GetAction()->GetExtra(extraLength, extraData); + + if (extraLength & MAXWORD) { + memcpy(extraCopy, extraData, extraLength & MAXWORD); + extraCopy[extraLength & MAXWORD] = '\0'; + } + } + + if (KeyValueStringParse(output, g_strHIDE_ON_STOP, extraCopy)) { + m_flags |= c_hideOnStop; + } + + if (KeyValueStringParse(output, g_strMUST_SUCCEED, extraCopy)) { + m_flags |= c_mustSucceed; + } + + if (KeyValueStringParse(output, g_strSUBST, extraCopy)) { + m_substMap = new LegoAnimSubstMap(); + + char* substToken = output; + char *key, *value; + + while ((key = strtok(substToken, g_parseExtraTokens))) { + substToken = NULL; + + if ((value = strtok(NULL, g_parseExtraTokens))) { + char* keyCopy = new char[strlen(key) + 1]; + strcpy(keyCopy, key); + char* valueCopy = new char[strlen(value) + 1]; + strcpy(valueCopy, value); + (*m_substMap)[keyCopy] = valueCopy; + } + } + } + + if (KeyValueStringParse(output, g_strWORLD, extraCopy)) { + char* token = strtok(output, g_parseExtraTokens); + m_worldAtom = MxAtomId(token, e_lowerCase2); + + token = strtok(NULL, g_parseExtraTokens); + m_worldId = atoi(token); + } + + if (KeyValueStringParse(output, g_strPTATCAM, extraCopy)) { + list tmp; + + if (m_unk0x90 != NULL) { + for (MxS32 i = 0; i < m_unk0x94; i++) { + if (m_unk0x90[i] != NULL) { + // (modernization) critical bug: wrong free + delete[] m_unk0x90; + } + } + + delete[] m_unk0x90; + m_unk0x90 = NULL; + } + + if (m_unk0x8c != NULL) { + delete[] m_unk0x8c; + m_unk0x8c = NULL; + } + + char* token = strtok(output, g_parseExtraTokens); + while (token != NULL) { + char* valueCopy = new char[strlen(token) + 1]; + strcpy(valueCopy, token); + tmp.push_back(valueCopy); + token = strtok(NULL, g_parseExtraTokens); + } + + m_unk0x94 = tmp.size(); + if (m_unk0x94 != 0) { + m_unk0x8c = new LegoROI*[m_unk0x94]; + m_unk0x90 = new char*[m_unk0x94]; + memset(m_unk0x8c, 0, sizeof(*m_unk0x8c) * m_unk0x94); + memset(m_unk0x90, 0, sizeof(*m_unk0x90) * m_unk0x94); + + MxS32 i = 0; + for (list::iterator it = tmp.begin(); it != tmp.end(); it++, i++) { + m_unk0x90[i] = *it; + } + } + } + } } // FUNCTION: LEGO1 0x1006c570 @@ -845,7 +944,7 @@ void LegoAnimPresenter::EndAction() FUN_1006b9a0(m_anim, m_anim->GetDuration(), m_unk0x78); } - if (m_roiMapSize != 0 && m_roiMap != NULL && m_roiMap[1] != NULL && m_flags & c_bit1) { + if (m_roiMapSize != 0 && m_roiMap != NULL && m_roiMap[1] != NULL && m_flags & c_hideOnStop) { for (MxS16 i = 1; i <= m_roiMapSize; i++) { if (m_roiMap[i] != NULL) { m_roiMap[i]->SetVisibility(FALSE); @@ -876,7 +975,7 @@ void LegoAnimPresenter::VTable0x8c() } if (m_currentWorld == NULL) { - m_currentWorld = m_unk0x88 != -1 ? FindWorld(m_animAtom, m_unk0x88) : CurrentWorld(); + m_currentWorld = m_worldId != -1 ? FindWorld(m_worldAtom, m_worldId) : CurrentWorld(); } if (m_currentWorld) { diff --git a/LEGO1/modeldb/modeldb.cpp b/LEGO1/modeldb/modeldb.cpp index d7a8336f..b0489b8c 100644 --- a/LEGO1/modeldb/modeldb.cpp +++ b/LEGO1/modeldb/modeldb.cpp @@ -58,7 +58,7 @@ MxResult ModelDbPart::Read(FILE* p_file) return FAILURE; } - // Critical bug: buffer overrun + // (modernization) critical bug: buffer overrun if (fread(buff, len, 1, p_file) != 1) { return FAILURE; }