#include "legoworldpresenter.h" #include "define.h" #include "legoactorpresenter.h" #include "legoanimationmanager.h" #include "legobuildingmanager.h" #include "legoentity.h" #include "legomodelpresenter.h" #include "legoomni.h" #include "legopartpresenter.h" #include "legoplantmanager.h" #include "legotexturepresenter.h" #include "legovideomanager.h" #include "legoworld.h" #include "modeldb/modeldb.h" #include "mxactionnotificationparam.h" #include "mxautolocker.h" #include "mxdsactionlist.h" #include "mxdschunk.h" #include "mxdsmediaaction.h" #include "mxdsmultiaction.h" #include "mxnotificationmanager.h" #include "mxobjectfactory.h" #include "mxpresenter.h" #include "mxstl/stlcompat.h" #include "mxutil.h" #include // GLOBAL: LEGO1 0x100f75d4 MxS32 g_legoWorldPresenterQuality = 1; // GLOBAL: LEGO1 0x100f75d8 MxLong g_wdbOffset = 0; // FUNCTION: LEGO1 0x100665b0 void LegoWorldPresenter::configureLegoWorldPresenter(MxS32 p_legoWorldPresenterQuality) { g_legoWorldPresenterQuality = p_legoWorldPresenterQuality; } // FUNCTION: LEGO1 0x100665c0 LegoWorldPresenter::LegoWorldPresenter() { m_unk0x50 = 50000; } // FUNCTION: LEGO1 0x10066770 LegoWorldPresenter::~LegoWorldPresenter() { MxBool result = FALSE; if (m_entity) { MxS32 scriptIndex = ((LegoWorld*) m_entity)->GetScriptIndex(); PlantManager()->FUN_10026360(scriptIndex); AnimationManager()->FUN_1005f720(scriptIndex); BuildingManager()->FUN_1002fa00(); result = ((LegoWorld*) m_entity)->VTable0x5c(); } if (result == FALSE) { FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); } if (m_entity) { #ifdef COMPAT_MODE { MxNotificationParam param(c_notificationNewPresenter, NULL); NotificationManager()->Send(m_entity, ¶m); } #else NotificationManager()->Send(m_entity, &MxNotificationParam(c_notificationNewPresenter, NULL)); #endif } } // FUNCTION: LEGO1 0x10066870 MxResult LegoWorldPresenter::StartAction(MxStreamController* p_controller, MxDSAction* p_action) { MxAutoLocker lock(&m_criticalSection); MxResult result = FAILURE; MxDSActionList* actions = ((MxDSMultiAction*) p_action)->GetActionList(); MxObjectFactory* factory = ObjectFactory(); MxDSActionListCursor cursor(actions); MxDSAction* action; if (MxPresenter::StartAction(p_controller, p_action) == SUCCESS) { cursor.Head(); while (cursor.Current(action)) { MxBool success = FALSE; const char* presenterName; MxPresenter* presenter = NULL; cursor.Next(); if (m_action->GetFlags() & MxDSAction::c_looping) { action->SetFlags(action->GetFlags() | MxDSAction::c_looping); } else if (m_action->GetFlags() & MxDSAction::c_bit3) { action->SetFlags(action->GetFlags() | MxDSAction::c_bit3); } presenterName = PresenterNameDispatch(*action); presenter = (MxPresenter*) factory->Create(presenterName); if (presenter && presenter->AddToManager() == SUCCESS) { presenter->SetCompositePresenter(this); if (presenter->StartAction(p_controller, action) == SUCCESS) { presenter->SetTickleState(e_idle); success = TRUE; } } if (success) { action->SetOrigin(this); m_list.push_back(presenter); } else if (presenter) { delete presenter; } } VideoManager()->RegisterPresenter(*this); result = SUCCESS; } return result; } // FUNCTION: LEGO1 0x10066a50 void LegoWorldPresenter::ReadyTickle() { m_entity = (LegoEntity*) MxPresenter::CreateEntity("LegoWorld"); if (m_entity) { m_entity->Create(*m_action); Lego()->AddWorld((LegoWorld*) m_entity); SetEntityLocation(m_action->GetLocation(), m_action->GetDirection(), m_action->GetUp()); } ParseExtra(); ProgressTickleState(e_starting); } // FUNCTION: LEGO1 0x10066ac0 void LegoWorldPresenter::StartingTickle() { if (m_action->IsA("MxDSSerialAction")) { MxPresenter* presenter = *m_list.begin(); if (presenter->GetCurrentTickleState() == e_idle) { presenter->SetTickleState(e_ready); } } else { for (MxCompositePresenterList::iterator it = m_list.begin(); it != m_list.end(); it++) { if ((*it)->GetCurrentTickleState() == e_idle) { (*it)->SetTickleState(e_ready); } } } ProgressTickleState(e_streaming); } // FUNCTION: LEGO1 0x10066b40 MxResult LegoWorldPresenter::LoadWorld(char* p_worldName, LegoWorld* p_world) { char wdbPath[512]; sprintf(wdbPath, "%s", MxOmni::GetHD()); if (wdbPath[strlen(wdbPath) - 1] != '\\') { strcat(wdbPath, "\\"); } strcat(wdbPath, "lego\\data\\world.wdb"); if (access(wdbPath, 4) != 0) { sprintf(wdbPath, "%s", MxOmni::GetCD()); if (wdbPath[strlen(wdbPath) - 1] != '\\') { strcat(wdbPath, "\\"); } strcat(wdbPath, "lego\\data\\world.wdb"); if (access(wdbPath, 4) != 0) { return FAILURE; } } ModelDbWorld* worlds = NULL; MxS32 numWorlds, i, j; MxU32 size; MxU8* buff; FILE* wdbFile = fopen(wdbPath, "rb"); if (wdbFile == NULL) { return FAILURE; } ReadModelDbWorlds(wdbFile, worlds, numWorlds); for (i = 0; i < numWorlds; i++) { if (!strcmpi(worlds[i].m_worldName, p_worldName)) { break; } } if (i == numWorlds) { return FAILURE; } if (g_wdbOffset == 0) { if (fread(&size, sizeof(size), 1, wdbFile) != 1) { return FAILURE; } buff = new MxU8[size]; if (fread(buff, size, 1, wdbFile) != 1) { return FAILURE; } MxDSChunk chunk; chunk.SetLength(size); chunk.SetData(buff); LegoTexturePresenter texturePresenter; if (texturePresenter.Read(chunk) == SUCCESS) { texturePresenter.Store(); } delete[] buff; if (fread(&size, sizeof(size), 1, wdbFile) != 1) { return FAILURE; } buff = new MxU8[size]; if (fread(buff, size, 1, wdbFile) != 1) { return FAILURE; } chunk.SetLength(size); chunk.SetData(buff); LegoPartPresenter partPresenter; if (partPresenter.Read(chunk) == SUCCESS) { partPresenter.Store(); } delete[] buff; g_wdbOffset = ftell(wdbFile); } else { if (fseek(wdbFile, g_wdbOffset, SEEK_SET) != 0) { return FAILURE; } } ModelDbPartListCursor cursor(worlds[i].m_partList); ModelDbPart* part; while (cursor.Next(part)) { if (GetViewLODListManager()->Lookup(part->m_roiName.GetData()) == NULL && FUN_10067360(*part, wdbFile) != SUCCESS) { return FAILURE; } } for (j = 0; j < worlds[i].m_numModels; j++) { if (!strnicmp(worlds[i].m_models[j].m_modelName, "isle", 4)) { switch (g_legoWorldPresenterQuality) { case 0: if (strcmpi(worlds[i].m_models[j].m_modelName, "isle_lo")) { continue; } break; case 1: if (strcmpi(worlds[i].m_models[j].m_modelName, "isle")) { continue; } break; case 2: if (strcmpi(worlds[i].m_models[j].m_modelName, "isle_hi")) { continue; } } } else if (g_legoWorldPresenterQuality <= 1 && !strnicmp(worlds[i].m_models[j].m_modelName, "haus", 4)) { if (worlds[i].m_models[j].m_modelName[4] == '3') { if (FUN_100674b0(worlds[i].m_models[j], wdbFile, p_world) != SUCCESS) { return FAILURE; } if (FUN_100674b0(worlds[i].m_models[j - 2], wdbFile, p_world) != SUCCESS) { return FAILURE; } if (FUN_100674b0(worlds[i].m_models[j - 1], wdbFile, p_world) != SUCCESS) { return FAILURE; } } continue; } if (FUN_100674b0(worlds[i].m_models[j], wdbFile, p_world) != SUCCESS) { return FAILURE; } } FreeModelDbWorlds(worlds, numWorlds); fclose(wdbFile); return SUCCESS; } // FUNCTION: LEGO1 0x10067360 MxResult LegoWorldPresenter::FUN_10067360(ModelDbPart& p_part, FILE* p_wdbFile) { MxResult result; MxU8* buff = new MxU8[p_part.m_partDataLength]; fseek(p_wdbFile, p_part.m_partDataOffset, 0); if (fread(buff, p_part.m_partDataLength, 1, p_wdbFile) != 1) { return FAILURE; } MxDSChunk chunk; chunk.SetLength(p_part.m_partDataLength); chunk.SetData(buff); LegoPartPresenter partPresenter; result = partPresenter.Read(chunk); if (result == SUCCESS) { partPresenter.Store(); } delete[] buff; return result; } // FUNCTION: LEGO1 0x100674b0 MxResult LegoWorldPresenter::FUN_100674b0(ModelDbModel& p_model, FILE* p_wdbFile, LegoWorld* p_world) { MxU8* buff = new MxU8[p_model.m_unk0x04]; fseek(p_wdbFile, p_model.m_unk0x08, 0); if (fread(buff, p_model.m_unk0x04, 1, p_wdbFile) != 1) { return FAILURE; } MxDSChunk chunk; chunk.SetLength(p_model.m_unk0x04); chunk.SetData(buff); MxDSAction action; MxAtomId atom; action.SetLocation(p_model.m_location); action.SetDirection(p_model.m_direction); action.SetUp(p_model.m_up); MxU32 objectId = m_unk0x50; m_unk0x50++; action.SetObjectId(objectId); action.SetAtomId(atom); LegoEntity* createdEntity = NULL; if (!strcmp(p_model.m_presenterName, "LegoActorPresenter")) { LegoActorPresenter presenter; presenter.SetAction(&action); LegoEntity* entity = (LegoEntity*) presenter.CreateEntity("LegoActor"); presenter.SetInternalEntity(entity); presenter.SetEntityLocation(p_model.m_location, p_model.m_direction, p_model.m_up); entity->Create(action); } else if (!strcmp(p_model.m_presenterName, "LegoEntityPresenter")) { LegoEntityPresenter presenter; presenter.SetAction(&action); createdEntity = (LegoEntity*) presenter.CreateEntity("LegoEntity"); presenter.SetInternalEntity(createdEntity); presenter.SetEntityLocation(p_model.m_location, p_model.m_direction, p_model.m_up); createdEntity->Create(action); } LegoModelPresenter modelPresenter; if (createdEntity != NULL) { action.SetLocation(Mx3DPointFloat(0.0, 0.0, 0.0)); action.SetUp(Mx3DPointFloat(0.0, 0.0, 1.0)); action.SetDirection(Mx3DPointFloat(0.0, 1.0, 0.0)); } modelPresenter.SetAction(&action); modelPresenter.FUN_1007ff70(chunk, createdEntity, p_model.m_unk0x34, p_world); delete[] buff; return SUCCESS; } // FUNCTION: LEGO1 0x10067a70 void LegoWorldPresenter::VTable0x60(MxPresenter* p_presenter) { MxCompositePresenter::VTable0x60(p_presenter); MxDSAction* action = p_presenter->GetAction(); if (action->GetDuration() != -1 && (action->GetFlags() & MxDSAction::c_looping) == 0) { if (!action->IsA("MxDSMediaAction")) { return; } if (((MxDSMediaAction*) action)->GetSustainTime() != -1) { return; } } if (!p_presenter->IsA("LegoAnimPresenter") && !p_presenter->IsA("MxControlPresenter") && !p_presenter->IsA("MxCompositePresenter")) { p_presenter->SendToCompositePresenter(Lego()); ((LegoWorld*) m_entity)->Add(p_presenter); } } // FUNCTION: LEGO1 0x10067b00 void LegoWorldPresenter::ParseExtra() { MxU16 extraLength; char* extraData; m_action->GetExtra(extraLength, extraData); if (extraLength & MAXWORD) { char extraCopy[1024]; memcpy(extraCopy, extraData, extraLength & MAXWORD); extraCopy[extraLength & MAXWORD] = '\0'; char output[1024]; if (KeyValueStringParse(output, g_strWORLD, extraCopy)) { char* worldKey = strtok(output, g_parseExtraTokens); LoadWorld(worldKey, (LegoWorld*) m_entity); ((LegoWorld*) m_entity)->SetScriptIndex(Lego()->GetScriptIndex(worldKey)); } } }