#include "legoanimationmanager.h" #include "3dmanager/lego3dmanager.h" #include "anim/legoanim.h" #include "animstate.h" #include "define.h" #include "islepathactor.h" #include "legoanimmmpresenter.h" #include "legoanimpresenter.h" #include "legocharactermanager.h" #include "legoendanimnotificationparam.h" #include "legoextraactor.h" #include "legogamestate.h" #include "legolocomotionanimpresenter.h" #include "legomain.h" #include "legonavcontroller.h" #include "legoroilist.h" #include "legosoundmanager.h" #include "legovideomanager.h" #include "legoworld.h" #include "misc.h" #include "mxbackgroundaudiomanager.h" #include "mxmisc.h" #include "mxnotificationmanager.h" #include "mxticklemanager.h" #include "mxtimer.h" #include "mxutilities.h" #include "viewmanager/viewmanager.h" #include #include DECOMP_SIZE_ASSERT(LegoAnimationManager, 0x500) DECOMP_SIZE_ASSERT(LegoAnimationManager::Character, 0x18) DECOMP_SIZE_ASSERT(LegoAnimationManager::Vehicle, 0x08) DECOMP_SIZE_ASSERT(LegoAnimationManager::Extra, 0x18) DECOMP_SIZE_ASSERT(LegoTranInfo, 0x78) // GLOBAL: LEGO1 0x100d8b28 MxU8 g_unk0x100d8b28[] = {0, 1, 2, 4, 8, 16}; // GLOBAL: LEGO1 0x100f6d20 LegoAnimationManager::Vehicle g_vehicles[] = { {"bikebd", 0, FALSE}, {"bikepg", 0, FALSE}, {"bikerd", 0, FALSE}, {"bikesy", 0, FALSE}, {"motoni", 0, FALSE}, {"motola", 0, FALSE}, {"board", 0, FALSE} }; // GLOBAL: LEGO1 0x100f6d58 const char* g_unk0x100f6d58[11][17] = { {"CNs001xx", "CNs002xx", "CNs003xx", "CNs004xx", "CNs005xx", "CNs007xx", "CNs006xx", "CNs008xx", "CNs009xx", "CNs010xx", "CNs011xx", "CNs012xx", NULL, NULL, NULL, NULL, NULL}, {"CNs001Pe", "CNs002Pe", "CNs003Pe", "CNs004Pe", "CNs005Pe", "CNs007Pe", "CNs006Pe", "CNs008Pe", "CNs009Pe", "CNs010Pe", "CNs001sk", NULL, NULL, NULL, NULL, NULL, NULL}, {"CNs001Ma", "CNs002Ma", "CNs003Ma", "CNs004Ma", "CNs005Ma", "CNs007Ma", "CNs006Ma", "CNs008Ma", "CNs009Ma", "CNs010Ma", "CNs0x4Ma", NULL, NULL, "CNs011Ma", "CNs012Ma", "CNs013Ma", NULL}, {"CNs001Pa", "CNs002Pa", "CNs003Pa", "CNs004Pa", "CNs005Pa", "CNs007Pa", "CNs006Pa", "CNs008Pa", "CNs009Pa", "CNs010Pa", "CNs0x4Pa", NULL, NULL, "CNs011Pa", "CNs012Pa", "CNs013Pa", NULL}, {"CNs001Ni", "CNs002Ni", "CNs003Ni", "CNs004Ni", "CNs005Ni", "CNs007Ni", "CNs006Ni", "CNs008Ni", "CNs009Ni", "CNs010Ni", "CNs011Ni", "CNsx11Ni", NULL, NULL, NULL, NULL, NULL}, {"CNs001La", "CNs002La", "CNs003La", "CNs004La", "CNs005La", "CNs007La", "CNs006La", "CNs008La", "CNs009La", "CNs010La", "CNs011La", "CNsx11La", NULL, NULL, NULL, NULL, NULL}, {"CNs001Br", "CNs002Br", "CNs003Br", "CNs004Br", "CNs005Br", "CNs007Br", "CNs006Br", "CNs008Br", "CNs009Br", "CNs010Br", "CNs011Br", "CNs900Br", "CNs901Br", "CNs011Br", "CNs012Br", "CNs013Br", "CNs014Br"}, {"CNs001xx", "CNs002xx", "CNs003xx", "CNs004xx", "CNs005xx", "CNs007xx", "CNs006xx", "CNs008xx", "CNs009xx", "CNs010xx", "CNs001Bd", "CNs012xx", NULL, NULL, NULL, NULL, NULL}, {"CNs001xx", "CNs002xx", "CNs003xx", "CNs004xx", "CNs005xx", "CNs007xx", "CNs006xx", "CNs008xx", "CNs009xx", "CNs010xx", "CNs001Pg", "CNs012xx", NULL, NULL, NULL, NULL, NULL}, {"CNs001xx", "CNs002xx", "CNs003xx", "CNs004xx", "CNs005xx", "CNs007xx", "CNs006xx", "CNs008xx", "CNs009xx", "CNs010xx", "CNs001Rd", "CNs012xx", NULL, NULL, NULL, NULL, NULL}, {"CNs001xx", "CNs002xx", "CNs003xx", "CNs004xx", "CNs005xx", "CNs007xx", "CNs006xx", "CNs008xx", "CNs009xx", "CNs010xx", "CNs001Sy", "CNs012xx", NULL, NULL, NULL, NULL, NULL} }; // GLOBAL: LEGO1 0x100f7048 LegoAnimationManager::Character g_characters[47] = { {"pepper", FALSE, 6, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 50, 1}, {"mama", FALSE, -1, 0, FALSE, FALSE, FALSE, 1500, 20000, FALSE, 0, 2}, {"papa", FALSE, -1, 0, FALSE, FALSE, FALSE, 1500, 20000, FALSE, 0, 3}, {"nick", FALSE, 4, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 20, 4}, {"laura", FALSE, 5, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 20, 5}, {"brickstr", FALSE, -1, 0, FALSE, FALSE, FALSE, 1000, 20000, FALSE, 0, 6}, {"studs", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, {"rhoda", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, {"valerie", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, {"snap", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, {"pt", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, {"mg", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, {"bu", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, {"ml", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, {"nu", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, {"na", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, {"cl", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, {"en", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, {"re", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, {"ro", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, {"d1", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, {"d2", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, {"d3", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, {"d4", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, {"l1", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, {"l2", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, {"l3", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, {"l4", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, {"l5", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, {"l6", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, {"b1", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, {"b2", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, {"b3", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, {"b4", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, {"cm", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, {"gd", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, {"rd", FALSE, 2, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 50, 9}, {"pg", FALSE, 1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 50, 8}, {"bd", FALSE, 0, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 100, 7}, {"sy", FALSE, 3, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 100, 10}, {"gn", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, {"df", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, {"bs", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, {"lt", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, {"st", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, {"bm", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, {"jk", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0} }; // GLOBAL: LEGO1 0x100f74b0 float g_unk0x100f74b0[6][3] = { {10.0f, -1.0f, 1.0f}, {7.0f, 144.0f, 100.0f}, {5.0f, 100.0f, 36.0f}, {3.0f, 36.0f, 25.0f}, {1.0f, 25.0f, 16.0f}, {-1.0f, 16.0f, 2.0f} }; // GLOBAL: LEGO1 0x100f74f8 MxS32 g_legoAnimationManagerConfig = 1; // GLOBAL: LEGO1 0x100f7500 float g_unk0x100f7500 = 0.1f; // GLOBAL: LEGO1 0x100f7504 MxS32 g_unk0x100f7504 = 0; // FUNCTION: LEGO1 0x1005eb50 void LegoAnimationManager::configureLegoAnimationManager(MxS32 p_legoAnimationManagerConfig) { g_legoAnimationManagerConfig = p_legoAnimationManagerConfig; } // FUNCTION: LEGO1 0x1005eb60 // FUNCTION: BETA10 0x1003f940 LegoAnimationManager::LegoAnimationManager() { m_unk0x1c = 0; m_animState = NULL; m_unk0x424 = NULL; Init(); NotificationManager()->Register(this); TickleManager()->RegisterClient(this, 10); } // FUNCTION: LEGO1 0x1005ed30 // FUNCTION: BETA10 0x1003fa27 LegoAnimationManager::~LegoAnimationManager() { TickleManager()->UnregisterClient(this); FUN_10061010(FALSE); for (MxS32 i = 0; i < (MxS32) sizeOfArray(m_extras); i++) { LegoROI* roi = m_extras[i].m_roi; if (roi != NULL) { LegoPathActor* actor = CharacterManager()->GetActor(roi->GetName()); if (actor != NULL && actor->GetController() != NULL && CurrentWorld() != NULL) { CurrentWorld()->RemovePathActor(actor); actor->SetController(NULL); } CharacterManager()->FUN_10083db0(roi); } } if (m_tranInfoList != NULL) { delete m_tranInfoList; } if (m_tranInfoList2 != NULL) { delete m_tranInfoList2; } DeleteAnimations(); if (m_unk0x424 != NULL) { FUN_10063aa0(); delete m_unk0x424; } NotificationManager()->Unregister(this); } // FUNCTION: LEGO1 0x1005ee80 // FUNCTION: BETA10 0x1003fbc0 void LegoAnimationManager::Reset(MxBool p_und) { m_unk0x402 = FALSE; if (p_und && m_animState != NULL) { m_animState->SetFlag(); } MxBool suspended = m_suspended; Suspend(); if (m_tranInfoList != NULL) { delete m_tranInfoList; } if (m_tranInfoList2 != NULL) { delete m_tranInfoList2; } DeleteAnimations(); Init(); m_suspended = suspended; m_suspendedEnableCamAnims = m_enableCamAnims; m_unk0x429 = m_unk0x400; m_unk0x42a = m_unk0x402; } // FUNCTION: LEGO1 0x1005ef10 // FUNCTION: BETA10 0x1003fc7a void LegoAnimationManager::Suspend() { m_animState = (AnimState*) GameState()->GetState("AnimState"); if (m_animState == NULL) { m_animState = (AnimState*) GameState()->CreateState("AnimState"); } if (m_scriptIndex == 0) { m_animState->FUN_10065240(m_animCount, m_anims, m_lastExtraCharacterId); } if (!m_suspended) { m_suspended = TRUE; m_suspendedEnableCamAnims = m_enableCamAnims; m_unk0x429 = m_unk0x400; m_unk0x42a = m_unk0x402; m_unk0x402 = FALSE; FUN_10061010(FALSE); MxS32 i; for (i = 0; i < (MxS32) sizeOfArray(m_extras); i++) { LegoROI* roi = m_extras[i].m_roi; if (roi != NULL) { LegoPathActor* actor = CharacterManager()->GetActor(roi->GetName()); if (actor != NULL && actor->GetController() != NULL) { actor->GetController()->RemoveActor(actor); actor->SetController(NULL); } CharacterManager()->FUN_10083db0(roi); } if (m_extras[i].m_unk0x14) { m_extras[i].m_unk0x14 = FALSE; MxS32 vehicleId = g_characters[m_extras[i].m_characterId].m_vehicleId; if (vehicleId >= 0) { g_vehicles[vehicleId].m_unk0x05 = FALSE; LegoROI* roi = Lego()->FindROI(g_vehicles[vehicleId].m_name); if (roi != NULL) { roi->SetVisibility(FALSE); } } } m_extras[i].m_roi = NULL; m_extras[i].m_characterId = -1; m_extras[i].m_speed = -1.0f; } m_unk0x18 = 0; m_unk0x1a = FALSE; m_enableCamAnims = FALSE; m_unk0x400 = FALSE; m_unk0x414 = 0; m_unk0x401 = FALSE; for (i = 0; i < (MxS32) sizeOfArray(g_characters); i++) { g_characters[i].m_unk0x04 = FALSE; } } } // FUNCTION: LEGO1 0x1005f0b0 // FUNCTION: BETA10 0x1003fefe void LegoAnimationManager::Resume() { if (m_suspended) { m_unk0x408 = m_unk0x40c = m_unk0x404 = Timer()->GetTime(); m_unk0x410 = 5000; m_enableCamAnims = m_suspendedEnableCamAnims; m_unk0x400 = m_unk0x429; m_unk0x402 = m_unk0x42a; m_suspended = FALSE; } } // FUNCTION: LEGO1 0x1005f130 // FUNCTION: BETA10 0x1003ffb7 void LegoAnimationManager::Init() { m_unk0x402 = FALSE; m_scriptIndex = -1; m_animCount = 0; m_anims = NULL; m_unk0x18 = 0; m_unk0x1a = FALSE; m_tranInfoList = NULL; m_tranInfoList2 = NULL; m_unk0x41c = g_legoAnimationManagerConfig <= 1 ? 10 : 20; MxS32 i; for (i = 0; i < (MxS32) sizeOfArray(m_unk0x28); i++) { m_unk0x28[i] = NULL; m_unk0x30[i] = 0; } for (i = 0; i < (MxS32) sizeOfArray(m_extras); i++) { m_extras[i].m_roi = NULL; m_extras[i].m_characterId = -1; m_extras[i].m_speed = -1.0f; m_extras[i].m_unk0x14 = FALSE; } m_unk0x38 = FALSE; m_animRunning = FALSE; m_enableCamAnims = TRUE; m_lastExtraCharacterId = 0; m_unk0x400 = FALSE; m_unk0x414 = 0; m_numAllowedExtras = 5; m_unk0x0e = 0; m_unk0x10 = 0; m_unk0x401 = FALSE; m_suspended = FALSE; m_unk0x430 = FALSE; m_unk0x42c = NULL; m_unk0x408 = m_unk0x40c = m_unk0x404 = Timer()->GetTime(); m_unk0x410 = 5000; for (i = 0; i < (MxS32) sizeOfArray(g_characters); i++) { g_characters[i].m_active = FALSE; g_characters[i].m_unk0x04 = FALSE; } for (i = 0; i < (MxS32) sizeOfArray(g_vehicles); i++) { g_vehicles[i].m_unk0x04 = FALSE; g_vehicles[i].m_unk0x05 = FALSE; } if (m_unk0x424 != NULL) { FUN_10063aa0(); delete m_unk0x424; } m_unk0x424 = new LegoROIList(); } // FUNCTION: LEGO1 0x1005f6d0 // FUNCTION: BETA10 0x100401e7 void LegoAnimationManager::FUN_1005f6d0(MxBool p_unk0x400) { if (m_suspended) { m_unk0x429 = p_unk0x400; } else { m_unk0x400 = p_unk0x400; if (!p_unk0x400) { PurgeExtra(TRUE); } } } // FUNCTION: LEGO1 0x1005f700 // FUNCTION: BETA10 0x1004024c void LegoAnimationManager::EnableCamAnims(MxBool p_enableCamAnims) { if (m_suspended) { m_suspendedEnableCamAnims = p_enableCamAnims; } else { m_enableCamAnims = p_enableCamAnims; } } // FUNCTION: LEGO1 0x1005f720 MxResult LegoAnimationManager::LoadScriptInfo(MxS32 p_scriptIndex) { MxResult result = FAILURE; MxS32 i, j, k; if (m_scriptIndex != 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) sizeOfArray(m_unk0x28); i++) { m_unk0x28[i] = NULL; m_unk0x30[i] = 0; } m_unk0x38 = FALSE; m_animRunning = FALSE; m_unk0x430 = FALSE; m_unk0x42c = NULL; for (j = 0; j < (MxS32) sizeOfArray(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_scriptIndex == 0) { m_animState->FUN_10065240(m_animCount, m_anims, m_lastExtraCharacterId); } DeleteAnimations(); LegoFile file; if (p_scriptIndex == -1) { result = SUCCESS; goto done; } char filename[128]; char path[1024]; sprintf(filename, "lego\\data\\%sinf.dta", Lego()->GetScriptName(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 = GetCharacterIndex(m_anims[j].m_name + strlen(m_anims[j].m_name) - 2); m_anims[j].m_unk0x29 = FALSE; for (k = 0; k < 3; k++) { m_anims[j].m_unk0x2a[k] = -1; } if (m_anims[j].m_location == -1) { for (MxS32 l = 0; l < m_anims[j].m_modelCount; l++) { MxS32 index = GetCharacterIndex(m_anims[j].m_models[l].m_name); 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 (FindVehicle(m_anims[j].m_models[m].m_name, n) && m_anims[j].m_models[m].m_unk0x2c) { m_anims[j].m_unk0x2a[count++] = n; if (count > 3) { break; } } } } m_scriptIndex = p_scriptIndex; m_tranInfoList = new LegoTranInfoList(); m_tranInfoList2 = new LegoTranInfoList(); FUN_100617c0(-1, m_unk0x0e, m_unk0x10); result = SUCCESS; m_unk0x402 = TRUE; if (m_suspended) { m_suspendedEnableCamAnims = m_enableCamAnims; m_unk0x429 = m_unk0x400; m_unk0x42a = TRUE; m_enableCamAnims = FALSE; m_unk0x400 = FALSE; m_unk0x402 = FALSE; } if (p_scriptIndex == 0) { m_animState->FUN_100651d0(m_animCount, m_anims, m_lastExtraCharacterId); } } done: if (result == FAILURE) { DeleteAnimations(); } return result; } // FUNCTION: LEGO1 0x10060140 MxBool LegoAnimationManager::FindVehicle(const char* p_name, MxU32& p_index) { for (MxS32 i = 0; i < sizeOfArray(g_vehicles); i++) { if (!strcmpi(p_name, g_vehicles[i].m_name)) { p_index = i; return TRUE; } } 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_name = new char[length + 1]; if (p_file->Read(p_info->m_name, length) == FAILURE) { goto done; } p_info->m_name[length] = 0; if (p_file->Read(&p_info->m_objectId, sizeof(p_info->m_objectId)) == FAILURE) { goto done; } if (p_file->Read(&p_info->m_location, sizeof(p_info->m_location)) == 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) sizeOfArray(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_name = new char[length + 1]; if (p_file->Read(p_info->m_name, length) == FAILURE) { goto done; } p_info->m_name[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; } // FUNCTION: LEGO1 0x100603c0 void LegoAnimationManager::DeleteAnimations() { MxBool suspended = m_suspended; if (m_anims != NULL) { for (MxS32 i = 0; i < m_animCount; i++) { delete m_anims[i].m_name; if (m_anims[i].m_models != NULL) { for (MxS32 j = 0; j < m_anims[i].m_modelCount; j++) { delete m_anims[i].m_models[j].m_name; } delete m_anims[i].m_models; } } delete m_anims; } Init(); m_suspended = suspended; } // FUNCTION: LEGO1 0x100604d0 // FUNCTION: BETA10 0x10041335 void LegoAnimationManager::FUN_100604d0(MxBool p_unk0x08) { for (MxS32 i = 0; i < (MxS32) sizeOfArray(g_characters); i++) { g_characters[i].m_unk0x08 = p_unk0x08; } } // FUNCTION: LEGO1 0x10060540 // FUNCTION: BETA10 0x1004140f void LegoAnimationManager::FUN_10060540(MxBool p_unk0x29) { for (MxS32 i = 0; i < m_animCount; i++) { m_anims[i].m_unk0x29 = p_unk0x29; } } // FUNCTION: LEGO1 0x10060570 // FUNCTION: BETA10 0x10041463 void LegoAnimationManager::FUN_10060570(MxBool p_unk0x1a) { m_animRunning = FALSE; m_unk0x430 = FALSE; m_unk0x42c = NULL; if (m_unk0x1a != p_unk0x1a && (m_unk0x1a = p_unk0x1a)) { do { if (FUN_100605e0(m_unk0x18, TRUE, NULL, TRUE, NULL, FALSE, TRUE, TRUE, TRUE) != FAILURE) { return; } m_unk0x18++; } while (m_unk0x18 < m_animCount); m_unk0x1a = FALSE; m_unk0x18 = 0; } } // FUNCTION: LEGO1 0x100605e0 // FUNCTION: BETA10 0x1004152b MxResult LegoAnimationManager::FUN_100605e0( MxU32 p_index, MxBool p_unk0x0a, MxMatrix* p_matrix, MxBool p_bool1, LegoROI* p_roi, MxBool p_bool2, MxBool p_bool3, MxBool p_bool4, MxBool p_bool5 ) { MxResult result = FAILURE; if (m_scriptIndex != -1 && p_index < m_animCount && m_tranInfoList != NULL) { PurgeExtra(FALSE); FUN_10062770(); MxDSAction action; AnimInfo& animInfo = m_anims[p_index]; if (!p_bool1) { if (m_animRunning || !animInfo.m_unk0x29) { return FAILURE; } if (FUN_100623a0(animInfo)) { return FAILURE; } if (FUN_10062710(animInfo)) { return FAILURE; } } FUN_10062580(animInfo); LegoTranInfo* tranInfo = new LegoTranInfo(); tranInfo->m_animInfo = &animInfo; tranInfo->m_index = ++m_unk0x1c; tranInfo->m_unk0x10 = 0; tranInfo->m_unk0x08 = p_roi; tranInfo->m_location = m_anims[p_index].m_location; tranInfo->m_unk0x14 = p_unk0x0a; tranInfo->m_objectId = animInfo.m_objectId; tranInfo->m_unk0x15 = p_bool2; if (p_matrix != NULL) { tranInfo->m_unk0x0c = new MxMatrix(*p_matrix); } tranInfo->m_unk0x1c = m_unk0x28; tranInfo->m_unk0x20 = m_unk0x30; tranInfo->m_unk0x28 = p_bool3; tranInfo->m_unk0x29 = p_bool4; if (m_tranInfoList != NULL) { m_tranInfoList->Append(tranInfo); } char buf[256]; sprintf(buf, "%s:%d", g_strANIMMAN_ID, tranInfo->m_index); action.SetAtomId(*Lego()->GetScriptAtom(m_scriptIndex)); action.SetObjectId(animInfo.m_objectId); action.SetUnknown24(-1); action.AppendExtra(strlen(buf) + 1, buf); if (StartActionIfUnknown0x13c(action) == SUCCESS) { BackgroundAudioManager()->LowerVolume(); tranInfo->m_flags |= LegoTranInfo::c_bit2; animInfo.m_unk0x22++; m_unk0x404 = Timer()->GetTime(); if (p_bool5) { FUN_100648f0(tranInfo, m_unk0x404); } else if (p_unk0x0a) { LegoPathActor* actor = CurrentActor(); if (actor != NULL) { actor->SetState(4); actor->SetWorldSpeed(0.0f); } } m_animRunning = TRUE; result = SUCCESS; } } return result; } // FUNCTION: LEGO1 0x100609f0 // FUNCTION: BETA10 0x10041a38 MxResult LegoAnimationManager::FUN_100609f0(MxU32 p_objectId, MxMatrix* p_matrix, MxBool p_und1, MxBool p_und2) { MxResult result = FAILURE; MxDSAction action; PurgeExtra(FALSE); LegoTranInfo* info = new LegoTranInfo(); info->m_animInfo = NULL; info->m_index = ++m_unk0x1c; info->m_unk0x10 = 0; info->m_unk0x08 = NULL; info->m_location = -1; info->m_unk0x14 = FALSE; info->m_objectId = p_objectId; if (p_matrix != NULL) { info->m_unk0x0c = new MxMatrix(*p_matrix); } FUN_10062770(); info->m_unk0x1c = m_unk0x28; info->m_unk0x20 = m_unk0x30; info->m_unk0x28 = p_und1; info->m_unk0x29 = p_und2; if (m_tranInfoList != NULL) { m_tranInfoList->Append(info); } char buf[256]; sprintf(buf, "%s:%d", g_strANIMMAN_ID, info->m_index); action.SetAtomId(*Lego()->GetScriptAtom(m_scriptIndex)); action.SetObjectId(p_objectId); action.SetUnknown24(-1); action.AppendExtra(strlen(buf) + 1, buf); if (StartActionIfUnknown0x13c(action) == SUCCESS) { BackgroundAudioManager()->LowerVolume(); info->m_flags |= LegoTranInfo::c_bit2; m_animRunning = TRUE; m_unk0x404 = Timer()->GetTime(); result = SUCCESS; } return result; } // FUNCTION: LEGO1 0x10060d00 MxResult LegoAnimationManager::StartEntityAction(MxDSAction& p_dsAction, LegoEntity* p_entity) { MxResult result = FAILURE; LegoROI* roi = p_entity->GetROI(); if (p_entity->GetType() == LegoEntity::e_character) { LegoPathActor* actor = CharacterManager()->GetActor(roi->GetName()); if (actor) { LegoPathController* controller = actor->GetController(); if (controller) { controller->RemoveActor(actor); actor->SetController(NULL); for (MxS32 i = 0; i < (MxS32) sizeOfArray(m_extras); i++) { if (m_extras[i].m_roi == roi) { MxS32 characterId = m_extras[i].m_characterId; g_characters[characterId].m_unk0x07 = TRUE; MxS32 vehicleId = g_characters[characterId].m_vehicleId; if (vehicleId >= 0) { g_vehicles[vehicleId].m_unk0x05 = FALSE; } break; } } } } } if (LegoOmni::GetInstance()->StartActionIfUnknown0x13c(p_dsAction) == SUCCESS) { result = SUCCESS; } return result; } // FUNCTION: LEGO1 0x10060dc0 // FUNCTION: BETA10 0x10041f2c MxResult LegoAnimationManager::FUN_10060dc0( IsleScript::Script p_objectId, MxMatrix* p_matrix, MxBool p_param3, MxBool p_param4, LegoROI* p_roi, MxBool p_param6, MxBool p_param7, MxBool p_param8, MxBool p_param9 ) { MxResult result = FAILURE; MxBool found = FALSE; if (!Lego()->m_unk0x13c) { return SUCCESS; } for (MxS32 i = 0; i < m_animCount; i++) { if (m_anims[i].m_objectId == p_objectId) { found = TRUE; MxBool unk0x0a; switch (p_param4) { case FALSE: unk0x0a = m_anims[i].m_unk0x0a; break; case TRUE: unk0x0a = TRUE; break; default: unk0x0a = FALSE; break; } result = FUN_100605e0(i, unk0x0a, p_matrix, p_param3, p_roi, p_param6, p_param7, p_param8, p_param9); break; } } if (!found && p_param3 != FALSE) { result = FUN_100609f0(p_objectId, p_matrix, p_param7, p_param8); } return result; } // FUNCTION: LEGO1 0x10060eb0 // FUNCTION: BETA10 0x1004206c void LegoAnimationManager::CameraTriggerFire(LegoPathActor* p_actor, MxBool, MxU32 p_location, MxBool p_bool) { if (Lego()->m_unk0x13c && m_enableCamAnims && !m_animRunning) { LegoLocation* location = LegoNavController::GetLocation(p_location); if (location != NULL) { if (location->m_frequency == 0) { return; } if (location->m_unk0x5c && location->m_frequency < rand() % 100) { return; } } MxU16 unk0x0e, unk0x10; if (FUN_100617c0(p_location, unk0x0e, unk0x10) == SUCCESS) { MxU16 index = unk0x0e; MxU32 unk0x22 = -1; MxBool success = FALSE; for (MxU16 i = unk0x0e; i <= unk0x10; i++) { AnimInfo& animInfo = m_anims[i]; if ((p_bool || !FUN_100623a0(animInfo)) && !FUN_10062710(animInfo) && animInfo.m_unk0x29 && animInfo.m_unk0x22 < unk0x22 && (animInfo.m_unk0x22 == 0 || *animInfo.m_name != 'i') && *animInfo.m_name != 'I') { index = i; unk0x22 = animInfo.m_unk0x22; success = TRUE; } } if (success) { FUN_100605e0(index, m_anims[index].m_unk0x0a, NULL, TRUE, NULL, FALSE, TRUE, TRUE, TRUE); location->m_unk0x5c = TRUE; } } } } // FUNCTION: LEGO1 0x10061010 // FUNCTION: BETA10 0x100422cc void LegoAnimationManager::FUN_10061010(MxBool p_und) { MxBool unk0x39 = FALSE; FUN_10064b50(-1); if (m_tranInfoList != NULL) { LegoTranInfoListCursor cursor(m_tranInfoList); LegoTranInfo* tranInfo; while (cursor.Next(tranInfo)) { if (tranInfo->m_presenter != NULL) { // TODO: Match MxU32 flags = tranInfo->m_flags; if (tranInfo->m_unk0x14 && tranInfo->m_location != -1 && p_und) { LegoAnim* anim; if (tranInfo->m_presenter->GetPresenter() != NULL && (anim = tranInfo->m_presenter->GetPresenter()->GetAnimation()) != NULL && anim->GetScene() != NULL) { if (flags & LegoTranInfo::c_bit2) { BackgroundAudioManager()->RaiseVolume(); tranInfo->m_flags &= ~LegoTranInfo::c_bit2; } tranInfo->m_presenter->FUN_1004b840(); tranInfo->m_unk0x14 = FALSE; } else { tranInfo->m_presenter->FUN_1004b8c0(); tranInfo->m_unk0x14 = FALSE; unk0x39 = TRUE; } } else { if (flags & LegoTranInfo::c_bit2) { BackgroundAudioManager()->RaiseVolume(); tranInfo->m_flags &= ~LegoTranInfo::c_bit2; } tranInfo->m_presenter->FUN_1004b840(); } } else { if (m_tranInfoList2 != NULL) { LegoTranInfoListCursor cursor(m_tranInfoList2); if (!cursor.Find(tranInfo)) { m_tranInfoList2->Append(tranInfo); } } unk0x39 = TRUE; } } } m_animRunning = unk0x39; m_unk0x404 = Timer()->GetTime(); } // FUNCTION: LEGO1 0x10061530 void LegoAnimationManager::FUN_10061530() { if (m_tranInfoList2 != NULL) { LegoTranInfoListCursor cursor(m_tranInfoList2); LegoTranInfo* tranInfo; while (cursor.Next(tranInfo)) { LegoTranInfoListCursor cursor2(m_tranInfoList); if (cursor2.Find(tranInfo)) { if (tranInfo->m_presenter != NULL) { if (tranInfo->m_flags & LegoTranInfo::c_bit2) { BackgroundAudioManager()->RaiseVolume(); tranInfo->m_flags &= ~LegoTranInfo::c_bit2; } tranInfo->m_presenter->FUN_1004b840(); cursor.Detach(); } } else { cursor.Detach(); } } } } // FUNCTION: LEGO1 0x100617c0 // FUNCTION: BETA10 0x1004240b MxResult LegoAnimationManager::FUN_100617c0(MxS32 p_location, MxU16& p_unk0x0e, MxU16& p_unk0x10) { MxResult result = FAILURE; MxU16 unk0x0e = 0; MxU16 unk0x10 = 0; MxBool success = FALSE; if (p_location == -1) { MxS32 i; for (i = 0; i < m_animCount; i++) { if (m_anims[i].m_location == p_location) { unk0x0e = i; success = TRUE; break; } } if (success) { for (; i < m_animCount && m_anims[i].m_location == p_location; i++) { unk0x10 = i; } } } else { MxS32 i; for (i = 0; m_animCount > i && m_anims[i].m_location != -1; i++) { if (m_anims[i].m_location == p_location) { unk0x0e = i; success = TRUE; break; } } if (success) { for (; i < m_animCount && m_anims[i].m_location == p_location; i++) { unk0x10 = i; } } } if (success) { p_unk0x0e = unk0x0e; p_unk0x10 = unk0x10; result = SUCCESS; } return result; } // FUNCTION: LEGO1 0x100618f0 // FUNCTION: BETA10 0x100425f0 LegoTranInfo* LegoAnimationManager::GetTranInfo(MxU32 p_index) { if (m_tranInfoList != NULL) { LegoTranInfoListCursor cursor(m_tranInfoList); LegoTranInfo* tranInfo; while (cursor.Next(tranInfo)) { if (tranInfo->m_index == p_index) { return tranInfo; } } } return NULL; } // FUNCTION: LEGO1 0x100619f0 // FUNCTION: BETA10 0x100426b1 MxLong LegoAnimationManager::Notify(MxParam& p_param) { if (((MxNotificationParam&) p_param).GetSender() == this) { if (((MxNotificationParam&) p_param).GetType() == c_notificationEndAnim) { FUN_100605e0(m_unk0x18, TRUE, NULL, TRUE, NULL, FALSE, TRUE, TRUE, TRUE); } } else if (((MxNotificationParam&) p_param).GetType() == c_notificationEndAnim && m_tranInfoList != NULL) { LegoTranInfoListCursor cursor(m_tranInfoList); LegoTranInfo* tranInfo; MxU32 index = ((LegoEndAnimNotificationParam&) p_param).GetIndex(); MxBool found = FALSE; while (cursor.Next(tranInfo)) { if (tranInfo->m_index == index) { if (m_unk0x430 && m_unk0x42c == tranInfo) { FUN_10064b50(-1); } if (tranInfo->m_flags & LegoTranInfo::c_bit2) { BackgroundAudioManager()->RaiseVolume(); } m_animRunning = FALSE; m_unk0x404 = Timer()->GetTime(); found = TRUE; cursor.Detach(); delete tranInfo; for (MxS32 i = 0; i < (MxS32) sizeOfArray(m_extras); i++) { LegoROI* roi = m_extras[i].m_roi; if (roi != NULL) { LegoExtraActor* actor = CharacterManager()->GetActor(roi->GetName()); if (actor != NULL) { actor->Restart(); } } } break; } } if (m_unk0x1a && found) { m_unk0x18++; if (m_animCount <= m_unk0x18) { m_unk0x1a = FALSE; } else { LegoEndAnimNotificationParam param(c_notificationEndAnim, this, 0); NotificationManager()->Send(this, param); } } } return 0; } // FUNCTION: LEGO1 0x10061cc0 // FUNCTION: BETA10 0x1004293c MxResult LegoAnimationManager::Tickle() { FUN_10061530(); if (!m_unk0x402) { return SUCCESS; } LegoPathActor* actor = CurrentActor(); LegoROI* roi; if (actor == NULL || (roi = actor->GetROI()) == NULL) { return SUCCESS; } if (m_unk0x401) { for (MxS32 i = 0; i < (MxS32) sizeOfArray(m_extras); i++) { LegoROI* roi = m_extras[i].m_roi; if (roi != NULL && m_extras[i].m_unk0x0d) { LegoPathActor* actor = CharacterManager()->GetActor(roi->GetName()); if (actor != NULL && actor->GetController() != NULL) { actor->GetController()->RemoveActor(actor); actor->SetController(NULL); } CharacterManager()->FUN_10083db0(roi); if (m_extras[i].m_unk0x14) { m_extras[i].m_unk0x14 = FALSE; MxS32 vehicleId = g_characters[m_extras[i].m_characterId].m_vehicleId; if (vehicleId >= 0) { g_vehicles[vehicleId].m_unk0x05 = FALSE; LegoROI* roi = Lego()->FindROI(g_vehicles[vehicleId].m_name); if (roi != NULL) { roi->SetVisibility(FALSE); } } } m_extras[i].m_roi = NULL; g_characters[m_extras[i].m_characterId].m_unk0x04 = FALSE; g_characters[m_extras[i].m_characterId].m_unk0x07 = FALSE; m_extras[i].m_characterId = -1; m_extras[i].m_unk0x0d = FALSE; m_unk0x414--; } } m_unk0x401 = FALSE; } MxLong time = Timer()->GetTime(); float speed = actor->GetWorldSpeed(); FUN_10064b50(time); if (!m_animRunning && time - m_unk0x404 > 10000 && speed < g_unk0x100f74b0[0][0] && speed > g_unk0x100f74b0[5][0]) { LegoPathBoundary* boundary = actor->GetBoundary(); Mx3DPointFloat position(roi->GetWorldPosition()); Mx3DPointFloat direction(roi->GetWorldDirection()); MxU8 unk0x0c = 0; MxU8 actorId = GameState()->GetActorId(); if (actorId <= 5) { unk0x0c = g_unk0x100d8b28[actorId]; } for (MxS32 i = 0; i < (MxS32) sizeOfArray(m_extras); i++) { LegoROI* roi = m_extras[i].m_roi; if (roi != NULL) { MxU16 result = FUN_10062110(roi, direction, position, boundary, speed, unk0x0c, m_extras[i].m_unk0x14); if (result) { MxMatrix mat; mat = roi->GetLocal2World(); if (FUN_100605e0(result & USHRT_MAX, FALSE, &mat, TRUE, roi, FALSE, TRUE, TRUE, TRUE) == SUCCESS) { m_unk0x404 = time; return SUCCESS; } } } } } if (time - m_unk0x40c > 1000) { FUN_10063d10(); m_unk0x40c = time; } if (time - m_unk0x408 < m_unk0x410) { return SUCCESS; } m_unk0x410 = (rand() * 10000 / SHRT_MAX) + 5000; m_unk0x408 = time; if (time - m_unk0x404 > 10000) { AddExtra(-1, FALSE); } double elapsedSeconds = VideoManager()->GetElapsedSeconds(); if (elapsedSeconds < 1.0 && elapsedSeconds > 0.01) { g_unk0x100f7500 = (g_unk0x100f7500 * 2.0 + elapsedSeconds) / 3.0; if (elapsedSeconds > 0.2 && m_numAllowedExtras > 2) { m_numAllowedExtras--; } else if (g_unk0x100f7500 < 0.16 && m_numAllowedExtras < m_unk0x41c) { m_numAllowedExtras++; } } return SUCCESS; } // FUNCTION: LEGO1 0x10062110 // FUNCTION: BETA10 0x10042f41 MxU16 LegoAnimationManager::FUN_10062110( LegoROI* p_roi, Vector3& p_direction, Vector3& p_position, LegoPathBoundary* p_boundary, float p_speed, MxU8 p_unk0x0c, MxBool p_unk0x14 ) { LegoPathActor* actor = (LegoPathActor*) p_roi->GetEntity(); if (actor != NULL && actor->GetBoundary() == p_boundary && actor->GetState() == 0) { if (GetViewManager()->FUN_100a6150(p_roi->GetWorldBoundingBox())) { Mx3DPointFloat direction(p_roi->GetWorldDirection()); if (direction.Dot(&direction, &p_direction) > 0.707) { Mx3DPointFloat position(p_roi->GetWorldPosition()); // TODO: Fix call ((Vector3&) position).Sub(&p_position); float len = position.LenSquared(); float min, max; for (MxU32 i = 0; i < sizeOfArray(g_unk0x100f74b0); i++) { if (g_unk0x100f74b0[i][0] < p_speed) { max = g_unk0x100f74b0[i][1]; min = g_unk0x100f74b0[i][2]; break; } } if (len < max && len > min) { MxS8 index = GetCharacterIndex(p_roi->GetName()); for (MxU16 i = m_unk0x0e; i <= m_unk0x10; i++) { if (m_anims[i].m_unk0x28 == index && m_anims[i].m_unk0x0c & p_unk0x0c && m_anims[i].m_unk0x29) { MxS32 vehicleId = g_characters[index].m_vehicleId; if (vehicleId >= 0) { MxBool found = FALSE; for (MxS32 j = 0; j < (MxS32) sizeOfArray(m_anims[i].m_unk0x2a); j++) { if (m_anims[i].m_unk0x2a[j] == vehicleId) { found = TRUE; break; } } if (p_unk0x14 != found) { continue; } } MxU16 result = i; MxU16 unk0x22 = m_anims[i].m_unk0x22; for (i = i + 1; i <= m_unk0x10; i++) { if (m_anims[i].m_unk0x28 == index && m_anims[i].m_unk0x0c & p_unk0x0c && m_anims[i].m_unk0x29 && m_anims[i].m_unk0x22 < unk0x22) { result = i; unk0x22 = m_anims[i].m_unk0x22; } } return result; } } } } } } return 0; } // FUNCTION: LEGO1 0x10062360 // FUNCTION: BETA10 0x100432dd MxS8 LegoAnimationManager::GetCharacterIndex(const char* p_name) { MxS8 i; for (i = 0; i < sizeOfArray(g_characters); i++) { if (!strnicmp(p_name, g_characters[i].m_name, 2)) { return i; } } return -1; } // FUNCTION: LEGO1 0x100623a0 // FUNCTION: BETA10 0x10043342 MxBool LegoAnimationManager::FUN_100623a0(AnimInfo& p_info) { LegoWorld* world = CurrentWorld(); if (world != NULL) { LegoEntityList* entityList = world->GetEntityList(); if (entityList != NULL) { Mx3DPointFloat position(p_info.m_unk0x10[0], p_info.m_unk0x10[1], p_info.m_unk0x10[2]); float und = p_info.m_unk0x10[3]; LegoEntityListCursor cursor(entityList); LegoEntity* entity; LegoPathActor* actor = CurrentActor(); while (cursor.Next(entity)) { if (entity != actor && entity->IsA("LegoPathActor")) { LegoROI* roi = entity->GetROI(); if (roi->GetVisibility() && FUN_10062650(position, und, roi)) { if (!ModelExists(p_info, roi->GetName())) { return TRUE; } } } } } } return FALSE; } // FUNCTION: LEGO1 0x10062520 // FUNCTION: BETA10 0x100434bf MxBool LegoAnimationManager::ModelExists(AnimInfo& p_info, const char* p_name) { ModelInfo* models = p_info.m_models; MxU8 modelCount = p_info.m_modelCount; if (models != NULL && modelCount) { for (MxU8 i = 0; i < modelCount; i++) { if (!strcmpi(models[i].m_name, p_name)) { return TRUE; } } } return FALSE; } // FUNCTION: LEGO1 0x10062580 // FUNCTION: BETA10 0x10043552 void LegoAnimationManager::FUN_10062580(AnimInfo& p_info) { ModelInfo* models = p_info.m_models; MxU8 modelCount = p_info.m_modelCount; if (models != NULL && modelCount) { for (MxU8 i = 0; i < modelCount; i++) { LegoPathActor* actor = CharacterManager()->GetActor(models[i].m_name); if (actor) { LegoPathController* controller = actor->GetController(); if (controller) { controller->RemoveActor(actor); actor->SetController(NULL); for (MxS32 i = 0; i < (MxS32) sizeOfArray(m_extras); i++) { if (m_extras[i].m_roi == actor->GetROI()) { MxS32 characterId = m_extras[i].m_characterId; g_characters[characterId].m_unk0x07 = TRUE; MxS32 vehicleId = g_characters[characterId].m_vehicleId; if (vehicleId >= 0) { g_vehicles[vehicleId].m_unk0x05 = FALSE; } break; } } } } } } } // FUNCTION: LEGO1 0x10062650 // FUNCTION: BETA10 0x100436e2 MxBool LegoAnimationManager::FUN_10062650(Vector3& p_position, float p_und, LegoROI* p_roi) { if (p_roi != NULL) { Mx3DPointFloat position(p_position); // TODO: Fix call ((Vector3&) position).Sub(p_roi->GetWorldPosition()); float len = position.LenSquared(); if (len <= 0.0f) { return TRUE; } len = sqrt(len); if (p_roi->GetWorldBoundingSphere().Radius() + p_und >= len) { return TRUE; } } return FALSE; } // FUNCTION: LEGO1 0x10062710 // FUNCTION: BETA10 0x10043787 MxBool LegoAnimationManager::FUN_10062710(AnimInfo& p_info) { MxU8 und = 0; MxU8 actorId = GameState()->GetActorId(); if (actorId <= 5) { und = g_unk0x100d8b28[actorId]; } if (!(und & p_info.m_unk0x0c)) { return TRUE; } if (ModelExists(p_info, GameState()->GetActorName())) { return TRUE; } return FALSE; } // FUNCTION: LEGO1 0x10062770 // FUNCTION: BETA10 0x1004381a void LegoAnimationManager::FUN_10062770() { if (!m_unk0x38) { LegoWorld* world = CurrentWorld(); if (world != NULL) { m_unk0x28[1] = (MxPresenter*) world->Find("MxSoundPresenter", "TransitionSound1"); m_unk0x28[0] = (MxPresenter*) world->Find("MxSoundPresenter", "TransitionSound2"); m_unk0x30[1] = 200; m_unk0x30[0] = 750; m_unk0x38 = TRUE; } } } // FUNCTION: LEGO1 0x100627d0 // FUNCTION: BETA10 0x1004389d void LegoAnimationManager::PurgeExtra(MxBool p_und) { ViewManager* viewManager = GetViewManager(); if (p_und || viewManager != NULL) { MxLong time = Timer()->GetTime(); for (MxS32 i = 0; i < (MxS32) sizeOfArray(m_extras); i++) { LegoROI* roi = m_extras[i].m_roi; if (roi != NULL) { MxU16 prefix = *(MxU16*) roi->GetName(); MxLong und = ((m_numAllowedExtras - 2) * 280000 / 18) + 20000; MxBool maOrPa = prefix == TWOCC('m', 'a') || prefix == TWOCC('p', 'a'); if ((p_und && !maOrPa) || (g_characters[m_extras[i].m_characterId].m_unk0x10 >= 0 && time - m_extras[i].m_unk0x08 > und && CharacterManager()->GetRefCount(roi) == 1 && !viewManager->FUN_100a6150(roi->GetWorldBoundingBox()))) { m_unk0x414--; LegoPathActor* actor = CharacterManager()->GetActor(roi->GetName()); if (actor != NULL && actor->GetController() != NULL) { actor->GetController()->RemoveActor(actor); actor->SetController(NULL); } CharacterManager()->FUN_10083db0(roi); if (m_extras[i].m_unk0x14) { m_extras[i].m_unk0x14 = FALSE; MxS32 vehicleId = g_characters[m_extras[i].m_characterId].m_vehicleId; if (vehicleId >= 0) { g_vehicles[vehicleId].m_unk0x05 = FALSE; LegoROI* roi = Lego()->FindROI(g_vehicles[vehicleId].m_name); if (roi != NULL) { roi->SetVisibility(FALSE); } } } m_extras[i].m_roi = NULL; g_characters[m_extras[i].m_characterId].m_unk0x04 = FALSE; g_characters[m_extras[i].m_characterId].m_unk0x07 = FALSE; m_extras[i].m_characterId = -1; } } } } } // FUNCTION: LEGO1 0x100629b0 // FUNCTION: BETA10 0x10043c10 void LegoAnimationManager::AddExtra(MxS32 p_location, MxBool p_und) { LegoLocation::Boundary* boundary = NULL; if (p_und || (!m_animRunning && m_unk0x400)) { LegoWorld* world = CurrentWorld(); if (world != NULL) { PurgeExtra(FALSE); LegoPathActor* actor = CurrentActor(); if (actor == NULL || actor->GetWorldSpeed() <= 20.0f) { MxU32 i; for (i = 0; i < m_numAllowedExtras && m_extras[i].m_roi != NULL; i++) { } if (i != m_numAllowedExtras) { MxU8 und = rand() % 2 != 0 ? 1 : 2; MxBool bool1, bool2; switch (g_unk0x100f7504 % 4) { case 0: bool1 = FALSE; bool2 = FALSE; break; case 1: bool1 = FALSE; bool2 = TRUE; break; default: bool1 = TRUE; bool2 = FALSE; break; } if (p_location < 0) { boundary = new LegoLocation::Boundary; if (!FUN_10064120(boundary, und == 2, bool2)) { delete boundary; boundary = NULL; } } else { LegoLocation* location = LegoNavController::GetLocation(p_location); if (location != NULL) { if (location->m_boundaryA.m_unk0x10 || FUN_10063fb0(&location->m_boundaryA, world)) { boundary = &location->m_boundaryA; } else if (location->m_boundaryB.m_unk0x10 || FUN_10063fb0(&location->m_boundaryB, world)) { boundary = &location->m_boundaryB; } } bool1 = FALSE; } if (boundary != NULL) { for (i = 0; i < m_numAllowedExtras; i++) { if (m_extras[i].m_roi == NULL) { m_lastExtraCharacterId++; if (m_lastExtraCharacterId >= sizeOfArray(g_characters)) { m_lastExtraCharacterId = 0; } MxU32 characterIdStart = m_lastExtraCharacterId; MxBool active; if (bool1) { active = TRUE; } else { active = rand() % 100 < 50; } tryNextCharacter: if (g_characters[m_lastExtraCharacterId].m_unk0x09 && g_characters[m_lastExtraCharacterId].m_unk0x08 && !g_characters[m_lastExtraCharacterId].m_unk0x04 && g_characters[m_lastExtraCharacterId].m_active == active) { if (!CharacterManager()->FUN_10083b20(g_characters[m_lastExtraCharacterId].m_name )) { m_extras[i].m_roi = CharacterManager()->GetROI( g_characters[m_lastExtraCharacterId].m_name, TRUE ); LegoExtraActor* actor = CharacterManager()->GetActor(g_characters[m_lastExtraCharacterId].m_name); switch (g_unk0x100f7504++ % 4) { case 0: actor->SetUnknown0x0c(und != 1 ? 1 : 2); break; case 1: { actor->SetUnknown0x0c(und); MxS32 src = boundary->m_src; boundary->m_src = boundary->m_dest; boundary->m_dest = src; break; } default: actor->SetUnknown0x0c(und); break; } if (world->PlaceActor( actor, boundary->m_name, boundary->m_src, boundary->m_srcScale, boundary->m_dest, boundary->m_destScale ) == SUCCESS) { MxS32 vehicleId = g_characters[m_lastExtraCharacterId].m_vehicleId; if (vehicleId >= 0) { g_vehicles[vehicleId].m_unk0x04 = rand() % 100 < g_characters[m_lastExtraCharacterId].m_unk0x15; } if (FUN_10063b90( world, actor, CharacterManager()->FUN_10085180(m_extras[i].m_roi), m_lastExtraCharacterId )) { m_extras[i].m_unk0x14 = TRUE; g_vehicles[vehicleId].m_unk0x05 = TRUE; } else { m_extras[i].m_unk0x14 = FALSE; } float speed; if (m_extras[i].m_unk0x14) { speed = ((float) (rand() * 1.5) / 32767.0f) + 0.9; } else { speed = ((float) (rand() * 1.4) / 32767.0f) + 0.6; } actor->SetWorldSpeed(speed); m_extras[i].m_characterId = m_lastExtraCharacterId; g_characters[m_lastExtraCharacterId].m_unk0x04 = TRUE; m_extras[i].m_unk0x08 = Timer()->GetTime(); m_extras[i].m_speed = -1; m_extras[i].m_unk0x0d = FALSE; m_unk0x414++; return; } else { CharacterManager()->FUN_10083db0(m_extras[i].m_roi); m_extras[i].m_roi = NULL; continue; } } } m_lastExtraCharacterId++; if (m_lastExtraCharacterId >= sizeOfArray(g_characters)) { m_lastExtraCharacterId = 0; } if (m_lastExtraCharacterId == characterIdStart) { return; } goto tryNextCharacter; } } } } } } } } // STUB: LEGO1 0x10063270 void LegoAnimationManager::FUN_10063270(LegoROIList*, LegoAnimPresenter*) { // TODO } // FUNCTION: LEGO1 0x10063780 void LegoAnimationManager::FUN_10063780(LegoROIList* p_list) { if (p_list != NULL && m_unk0x424 != NULL) { LegoROIListCursor cursor(p_list); LegoROI* roi; while (cursor.Next(roi)) { const char* name = roi->GetName(); if (CharacterManager()->Exists(name)) { m_unk0x424->Append(roi); cursor.Detach(); } } } } // FUNCTION: LEGO1 0x10063aa0 void LegoAnimationManager::FUN_10063aa0() { LegoROIListCursor cursor(m_unk0x424); LegoROI* roi; while (cursor.Next(roi)) { CharacterManager()->FUN_10083db0(roi); } } // STUB: LEGO1 0x10063b90 // FUNCTION: BETA10 0x10044d46 MxBool LegoAnimationManager::FUN_10063b90( LegoWorld* p_world, LegoExtraActor* p_actor, MxU8 p_unk0x14, MxU32 p_characterId ) { // TODO return TRUE; } // FUNCTION: LEGO1 0x10063d10 // FUNCTION: BETA10 0x10045034 void LegoAnimationManager::FUN_10063d10() { if (CurrentWorld() != NULL) { MxLong time = Timer()->GetTime(); for (MxS32 i = 0; i < (MxS32) sizeOfArray(m_extras); i++) { LegoROI* roi = m_extras[i].m_roi; if (roi != NULL) { if (m_extras[i].m_unk0x0c && g_characters[m_extras[i].m_characterId].m_unk0x0c >= 0 && g_characters[m_extras[i].m_characterId].m_unk0x0c < time - m_extras[i].m_unk0x08) { m_extras[i].m_unk0x0c = FALSE; LegoExtraActor* actor = CharacterManager()->GetActor(roi->GetName()); if (actor != NULL) { float speed = m_extras[i].m_speed; if (speed < 0.0f) { if (m_extras[i].m_unk0x14) { speed = ((float) (rand() * 1.5) / 32767.0f) + 0.9; } else { speed = ((float) (rand() * 1.4) / 32767.0f) + 0.6; } } actor->SetWorldSpeed(speed); } } else { LegoExtraActor* actor = CharacterManager()->GetActor(roi->GetName()); if (actor != NULL) { actor->Restart(); } } } } } } // FUNCTION: LEGO1 0x10063fb0 // FUNCTION: BETA10 0x100452a7 MxBool LegoAnimationManager::FUN_10063fb0(LegoLocation::Boundary* p_boundary, LegoWorld* p_world) { if (p_boundary->m_name != NULL) { Mx3DPointFloat vec; LegoPathBoundary* boundary = p_world->FindPathBoundary(p_boundary->m_name); LegoUnknown100db7f4* pSrcE = (LegoUnknown100db7f4*) boundary->GetEdges()[p_boundary->m_src]; return FUN_10064010(boundary, pSrcE, p_boundary->m_srcScale); } return FALSE; } // FUNCTION: LEGO1 0x10064010 // FUNCTION: BETA10 0x100453a5 MxBool LegoAnimationManager::FUN_10064010(LegoPathBoundary* p_boundary, LegoUnknown100db7f4* p_edge, float p_destScale) { Mx3DPointFloat p1; Vector3* v1 = p_edge->GetOpposingPoint(*p_boundary); Vector3* v2 = p_edge->CCWVertex(*p_boundary); p1 = *v2; ((Vector3&) p1).Sub(v1); ((Vector3&) p1).Mul(p_destScale); ((Vector3&) p1).Add(v1); BoundingBox boundingBox; Mx3DPointFloat vec(1.0f, 1.0f, 1.0f); boundingBox.Min() = p1; boundingBox.Min().Sub(&vec); boundingBox.Max() = p1; boundingBox.Max().Add(&vec); return GetViewManager()->FUN_100a6150(boundingBox) == FALSE; } // FUNCTION: LEGO1 0x10064120 // FUNCTION: BETA10 0x100454f5 MxBool LegoAnimationManager::FUN_10064120(LegoLocation::Boundary* p_boundary, MxBool p_bool1, MxBool p_bool2) { MxU32 local2c = 12; float destScale = ((rand() * 0.5) / 32767.0) + 0.25; LegoPathActor* actor = CurrentActor(); if (actor == NULL) { return FALSE; } LegoPathBoundary* boundary = actor->GetBoundary(); if (boundary == NULL) { return FALSE; } Mx3DPointFloat direction = actor->GetWorldDirection(); float local4c = 0.0f; LegoUnknown100db7f4* local50 = NULL; LegoS32 numEdges = boundary->GetNumEdges(); Mx3DPointFloat vec; LegoUnknown100db7f4* e; MxS32 i; for (i = 0; i < numEdges; i++) { e = (LegoUnknown100db7f4*) boundary->GetEdges()[i]; e->FUN_1002ddc0(*boundary, vec); float dot = vec.Dot(&direction, &vec); if (dot > local4c) { local50 = e; local4c = dot; } } e = local50; do { e = (LegoUnknown100db7f4*) e->GetCounterclockwiseEdge(*boundary); if (e->GetMask0x03()) { break; } } while (e != local50); if (e == local50) { return FALSE; } LegoUnknown100db7f4* local34 = e; LegoUnknown100db7f4* local8 = local50; while (local2c--) { if (local34 != NULL) { if (local34->Unknown(*boundary, LegoWEGEdge::c_bit1) && FUN_10064010(boundary, local34, destScale) && (!p_bool2 || FUN_10064010(boundary, local8, destScale))) { p_boundary->m_srcScale = p_boundary->m_destScale = destScale; p_boundary->m_name = boundary->GetName(); numEdges = boundary->GetNumEdges(); for (i = 0; i < numEdges; i++) { LegoUnknown100db7f4* e = (LegoUnknown100db7f4*) boundary->GetEdges()[i]; if (local34 == e) { p_boundary->m_src = i; } else if (local8 == e) { p_boundary->m_dest = i; } } return TRUE; } local8 = local34; boundary = (LegoPathBoundary*) local34->OtherFace(boundary); local50 = local34; do { if (p_bool1) { local34 = (LegoUnknown100db7f4*) local34->GetCounterclockwiseEdge(*boundary); } else { local34 = (LegoUnknown100db7f4*) local34->GetClockwiseEdge(*boundary); } } while (!local34->GetMask0x03() && local34 != local50); if (local34 == local50) { return FALSE; } } } return FALSE; } // FUNCTION: LEGO1 0x10064380 // FUNCTION: BETA10 0x1004583a MxResult LegoAnimationManager::FUN_10064380( const char* p_name, const char* p_boundaryName, MxS32 p_src, float p_srcScale, MxS32 p_dest, float p_destScale, MxU32 p_undIdx1, MxS32 p_unk0x0c, MxU32 p_undIdx2, MxS32 p_unk0x10, float p_speed ) { LegoWorld* world = CurrentWorld(); MxS32 extraIndex = -1; LegoExtraActor* actor = NULL; MxS32 i; for (i = 0; i < (MxS32) sizeOfArray(m_extras); i++) { LegoROI* roi = m_extras[i].m_roi; if (roi == NULL && extraIndex == -1) { extraIndex = i; } if (roi != NULL && !strcmpi(roi->GetName(), p_name)) { actor = CharacterManager()->GetActor(p_name); if (actor != NULL && actor->GetController() != NULL) { actor->GetController()->RemoveActor(actor); actor->SetController(NULL); actor->ClearMaps(); } break; } } if (actor == NULL && extraIndex != -1) { i = extraIndex; MxS32 characterId; for (characterId = 0; characterId < (MxS32) sizeOfArray(g_characters); characterId++) { if (!strcmpi(g_characters[characterId].m_name, p_name)) { break; } } if (characterId > sizeOfArray(g_characters)) { return FAILURE; } m_extras[extraIndex].m_roi = CharacterManager()->GetROI(p_name, TRUE); m_extras[extraIndex].m_characterId = characterId; m_extras[extraIndex].m_speed = p_speed; actor = CharacterManager()->GetActor(p_name); m_unk0x414++; } if (actor != NULL) { MxU8 unk0x0c = rand() % 2 != 0 ? 1 : 2; actor->SetUnknown0x0c(unk0x0c); actor->SetWorldSpeed(0.0f); if (world->PlaceActor(actor, p_boundaryName, p_src, p_srcScale, p_dest, p_destScale) != SUCCESS) { CharacterManager()->FUN_10083db0(m_extras[i].m_roi); m_extras[i].m_roi = NULL; m_unk0x414--; return FAILURE; } MxS32 characterId = m_extras[i].m_characterId; const char** unk0x100f6d58 = g_unk0x100f6d58[g_characters[characterId].m_unk0x16]; LegoLocomotionAnimPresenter* presenter = (LegoLocomotionAnimPresenter*) world->Find("LegoAnimPresenter", unk0x100f6d58[p_undIdx1]); if (presenter != NULL) { presenter->FUN_1006d680(actor, 0.0f); } presenter = (LegoLocomotionAnimPresenter*) world->Find("LegoAnimPresenter", unk0x100f6d58[p_undIdx2]); if (presenter != NULL) { presenter->FUN_1006d680(actor, 4.0f); } m_extras[i].m_unk0x08 = Timer()->GetTime(); m_extras[i].m_unk0x0c = TRUE; m_extras[i].m_speed = p_speed; g_characters[characterId].m_unk0x0c = p_unk0x0c; g_characters[characterId].m_unk0x10 = p_unk0x10; g_characters[characterId].m_unk0x04 = TRUE; return SUCCESS; } return FAILURE; } // FUNCTION: LEGO1 0x10064670 MxResult LegoAnimationManager::FUN_10064670(Vector3* p_position) { MxBool success = FALSE; if (p_position != NULL) { Mx3DPointFloat vec(98.875f, 0.0f, -46.1564f); ((Vector3&) vec).Sub(p_position); if (vec.LenSquared() < 800.0f) { success = TRUE; } } else { success = TRUE; } if (success) { return FUN_10064380("brickstr", "EDG02_95", 1, 0.5f, 3, 0.5f, rand() % 3 + 14, -1, rand() % 3, -1, 0.5f); } return FAILURE; } // FUNCTION: LEGO1 0x10064740 MxResult LegoAnimationManager::FUN_10064740(Vector3* p_position) { MxBool success = FALSE; if (p_position != NULL) { Mx3DPointFloat vec(-21.375f, 0.0f, -41.75f); ((Vector3&) vec).Sub(p_position); if (vec.LenSquared() < 1000.0f) { success = TRUE; } } else { success = TRUE; } if (success) { if (GameState()->GetActorId() != 2) { FUN_10064380("mama", "USR00_47", 1, 0.43f, 3, 0.84f, rand() % 3 + 13, -1, rand() % 3, -1, 0.7f); } if (GameState()->GetActorId() != 3) { FUN_10064380("papa", "USR00_193", 3, 0.55f, 1, 0.4f, rand() % 3 + 13, -1, rand() % 3, -1, 0.9f); } return SUCCESS; } return FAILURE; } // FUNCTION: LEGO1 0x10064880 // FUNCTION: BETA10 0x10045d02 MxResult LegoAnimationManager::FUN_10064880(const char* p_name, MxS32 p_unk0x0c, MxS32 p_unk0x10) { for (MxS32 i = 0; i < (MxS32) sizeOfArray(m_extras); i++) { LegoROI* roi = m_extras[i].m_roi; if (roi != NULL) { if (!strcmpi(roi->GetName(), p_name)) { g_characters[m_extras[i].m_characterId].m_unk0x0c = p_unk0x0c; g_characters[m_extras[i].m_characterId].m_unk0x10 = p_unk0x10; return SUCCESS; } } } return FAILURE; } // STUB: LEGO1 0x100648f0 // FUNCTION: BETA10 0x10045daf void LegoAnimationManager::FUN_100648f0(LegoTranInfo*, MxLong) { // TODO } // FUNCTION: LEGO1 0x10064b50 // FUNCTION: BETA10 0x10045f14 void LegoAnimationManager::FUN_10064b50(MxLong p_time) { if (m_unk0x430 && m_unk0x42c != NULL) { MxMatrix mat; if (p_time < 0 || p_time <= m_unk0x438) { m_unk0x430 = FALSE; m_unk0x42c->m_flags &= ~LegoTranInfo::c_bit1; m_unk0x42c = NULL; mat = m_unk0x484; } else { float und = (float) (p_time - m_unk0x434) / (float) (m_unk0x438 - m_unk0x434); float sub[3]; sub[0] = (m_unk0x484[3][0] - m_unk0x43c[3][0]) * und; sub[1] = (m_unk0x484[3][1] - m_unk0x43c[3][1]) * und; sub[2] = (m_unk0x484[3][2] - m_unk0x43c[3][2]) * und; m_unk0x4cc.Unknown_100040a0(mat, (float) (p_time - m_unk0x434) / 1000.0f); VPV3(mat[3], m_unk0x43c[3], sub); mat[3][4] = 1.0f; } LegoROI* viewROI = VideoManager()->GetViewROI(); viewROI->WrappedSetLocalTransform(mat); VideoManager()->Get3DManager()->Moved(*viewROI); SoundManager()->FUN_1002a410( viewROI->GetWorldPosition(), viewROI->GetWorldDirection(), viewROI->GetWorldUp(), viewROI->GetWorldVelocity() ); } }