/* ScummVM - Graphic Adventure Engine * * ScummVM is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "fullpipe/fullpipe.h" #include "fullpipe/gameloader.h" #include "fullpipe/scene.h" #include "fullpipe/input.h" #include "fullpipe/statics.h" #include "fullpipe/interaction.h" #include "fullpipe/motion.h" #include "fullpipe/constants.h" #include "fullpipe/scenes.h" #include "fullpipe/floaters.h" namespace Fullpipe { Inventory2 *getGameLoaderInventory() { return &g_fp->_gameLoader->_inventory; } MctlCompound *getSc2MctlCompoundBySceneId(int16 sceneId) { for (uint i = 0; i < g_fp->_gameLoader->_sc2array.size(); i++) if (g_fp->_gameLoader->_sc2array[i]._sceneId == sceneId) return (MctlCompound *)g_fp->_gameLoader->_sc2array[i]._motionController; return 0; } InteractionController *getGameLoaderInteractionController() { return g_fp->_gameLoader->_interactionController; } GameLoader::GameLoader() { _interactionController = new InteractionController(); _inputController = new InputController(); addMessageHandlerByIndex(global_messageHandler2, 0, 0); insertMessageHandler(global_messageHandler3, 0, 128); insertMessageHandler(global_messageHandler4, 0, 1); _field_FA = 0; _field_F8 = 0; _sceneSwitcher = 0; _preloadCallback = 0; _savegameCallback = 0; _gameVar = 0; _preloadSceneId = 0; _preloadEntranceId = 0; _updateCounter = 0; g_fp->_msgX = 0; g_fp->_msgY = 0; g_fp->_msgObjectId2 = 0; g_fp->_msgId = 0; } GameLoader::~GameLoader() { delete _interactionController; delete _inputController; for (uint i = 0; i < _sc2array.size(); i++) { if (_sc2array[i]._defPicAniInfos) free(_sc2array[i]._defPicAniInfos); if (_sc2array[i]._picAniInfos) free(_sc2array[i]._picAniInfos); if (_sc2array[i]._motionController) delete _sc2array[i]._motionController; if (_sc2array[i]._data1) free(_sc2array[i]._data1); if (_sc2array[i]._entranceData) free(_sc2array[i]._entranceData); } delete _gameVar; _gameVar = 0; _sc2array.clear(); } bool GameLoader::load(MfcArchive &file) { debugC(1, kDebugLoading, "GameLoader::load()"); _gameName = file.readPascalString(); debugC(1, kDebugLoading, "_gameName: %s", _gameName.c_str()); _gameProject.reset(new GameProject()); _gameProject->load(file); g_fp->_gameProject = _gameProject.get(); if (g_fp->_gameProjectVersion < 12) { error("Old gameProjectVersion: %d", g_fp->_gameProjectVersion); } _gameName = file.readPascalString(); debugC(1, kDebugLoading, "_gameName: %s", _gameName.c_str()); _inventory.load(file); _interactionController->load(file); debugC(1, kDebugLoading, "sceneTag count: %d", _gameProject->_sceneTagList->size()); _sc2array.resize(_gameProject->_sceneTagList->size()); int i = 0; for (SceneTagList::const_iterator it = _gameProject->_sceneTagList->begin(); it != _gameProject->_sceneTagList->end(); ++it, i++) { char tmp[12]; snprintf(tmp, 11, "%04d.sc2", it->_sceneId); debugC(1, kDebugLoading, "sc: %s", tmp); _sc2array[i].loadFile((const char *)tmp); } _preloadItems.load(file); _field_FA = file.readUint16LE(); _field_F8 = file.readUint16LE(); debugC(1, kDebugLoading, "_field_FA: %d\n_field_F8: %d", _field_FA, _field_F8); _gameVar = (GameVar *)file.readClass(); return true; } bool GameLoader::loadScene(int sceneId) { SceneTag *st; int idx = getSceneTagBySceneId(sceneId, &st); if (idx < 0) return false; if (!st->_scene) st->loadScene(); if (st->_scene) { st->_scene->init(); applyPicAniInfos(st->_scene, _sc2array[idx]._defPicAniInfos, _sc2array[idx]._defPicAniInfosCount); applyPicAniInfos(st->_scene, _sc2array[idx]._picAniInfos, _sc2array[idx]._picAniInfosCount); _sc2array[idx]._scene = st->_scene; _sc2array[idx]._isLoaded = 1; return true; } return false; } bool GameLoader::gotoScene(int sceneId, int entranceId) { SceneTag *st; int sc2idx = getSceneTagBySceneId(sceneId, &st); if (sc2idx < 0) return false; if (!_sc2array[sc2idx]._isLoaded) return false; if (_sc2array[sc2idx]._entranceDataCount < 1) { g_fp->_currentScene = st->_scene; return true; } if (_sc2array[sc2idx]._entranceDataCount <= 0) return false; int entranceIdx = 0; if (sceneId != 726) // WORKAROUND for (entranceIdx = 0; _sc2array[sc2idx]._entranceData[entranceIdx]->_field_4 != entranceId; entranceIdx++) { if (entranceIdx >= _sc2array[sc2idx]._entranceDataCount) return false; } GameVar *sg = _gameVar->getSubVarByName("OBJSTATES")->getSubVarByName("SAVEGAME"); if (sg || (sg = _gameVar->getSubVarByName("OBJSTATES")->addSubVarAsInt("SAVEGAME", 0)) != 0) sg->setSubVarAsInt("Entrance", entranceId); if (!g_fp->sceneSwitcher(_sc2array[sc2idx]._entranceData[entranceIdx])) return false; g_fp->_msgObjectId2 = 0; g_fp->_msgY = -1; g_fp->_msgX = -1; g_fp->_currentScene = st->_scene; MessageQueue *mq1 = g_fp->_currentScene->getMessageQueueById(_sc2array[sc2idx]._entranceData[entranceIdx]->_messageQueueId); if (mq1) { MessageQueue *mq = new MessageQueue(mq1, 0, 0); StaticANIObject *stobj = g_fp->_currentScene->getStaticANIObject1ById(_field_FA, -1); if (stobj) { stobj->_flags &= 0x100; ExCommand *ex = new ExCommand(stobj->_id, 34, 256, 0, 0, 0, 1, 0, 0, 0); ex->_field_14 = 256; ex->_messageNum = 0; ex->_excFlags |= 3; mq->addExCommandToEnd(ex); } mq->setFlags(mq->getFlags() | 1); if (!mq->chain(0)) { delete mq; return false; } } else { StaticANIObject *stobj = g_fp->_currentScene->getStaticANIObject1ById(_field_FA, -1); if (stobj) stobj->_flags &= 0xfeff; } return true; } bool preloadCallback(PreloadItem &pre, int flag) { if (flag) { if (flag == 50) g_fp->_aniMan->preloadMovements(g_fp->_movTable); StaticANIObject *pbar = g_fp->_loaderScene->getStaticANIObject1ById(ANI_PBAR, -1); if (pbar) { int sz; if (pbar->_movement->_currMovement) sz = pbar->_movement->_currMovement->_dynamicPhases.size(); else sz = pbar->_movement->_dynamicPhases.size(); pbar->_movement->setDynamicPhaseIndex(flag * (sz - 1) / 100); } g_fp->updateMap(&pre); g_fp->_currentScene = g_fp->_loaderScene; g_fp->_loaderScene->draw(); g_fp->_system->updateScreen(); } else { if (g_fp->_scene2) { g_fp->_aniMan = g_fp->_scene2->getAniMan(); g_fp->_scene2 = 0; setInputDisabled(1); } g_fp->_floaters->stopAll(); if (g_fp->_soundEnabled) { g_fp->_currSoundListCount = 1; g_fp->_currSoundList1[0] = g_fp->accessScene(SC_COMMON)->_soundList.get(); } g_vars->scene18_inScene18p1 = false; if ((pre.preloadId1 != SC_18 || pre.sceneId != SC_19) && (pre.preloadId1 != SC_19 || (pre.sceneId != SC_18 && pre.sceneId != SC_19))) { if (g_fp->_scene3) { if (pre.preloadId1 != SC_18) g_fp->_gameLoader->unloadScene(SC_18); g_fp->_scene3 = 0; } } else { scene19_setMovements(g_fp->accessScene(pre.preloadId1), pre.param); g_vars->scene18_inScene18p1 = true; if (pre.preloadId1 == SC_18) { g_fp->_gameLoader->saveScenePicAniInfos(SC_18); scene18_preload(); } } if (((pre.sceneId == SC_19 && pre.param == TrubaRight) || (pre.sceneId == SC_18 && pre.param == TrubaRight)) && !pre.preloadId2) { pre.sceneId = SC_18; pre.param = TrubaLeft; } if (!g_fp->_loaderScene) { g_fp->_gameLoader->loadScene(SC_LDR); g_fp->_loaderScene = g_fp->accessScene(SC_LDR); } StaticANIObject *pbar = g_fp->_loaderScene->getStaticANIObject1ById(ANI_PBAR, -1); if (pbar) { pbar->show1(ST_EGTR_SLIMSORROW, ST_MAN_GOU, MV_PBAR_RUN, 0); pbar->startAnim(MV_PBAR_RUN, 0, -1); } g_fp->_inventoryScene = 0; g_fp->_updateCursorCallback = 0; g_fp->_sceneRect.translate(-g_fp->_sceneRect.left, -g_fp->_sceneRect.top); g_fp->_system->delayMillis(10); Scene *oldsc = g_fp->_currentScene; g_fp->_currentScene = g_fp->_loaderScene; g_fp->_loaderScene->draw(); g_fp->_system->updateScreen(); g_fp->_currentScene = oldsc; } return true; } void GameLoader::addPreloadItem(PreloadItem *item) { _preloadItems.push_back(new PreloadItem(*item)); } bool GameLoader::preloadScene(int sceneId, int entranceId) { debugC(0, kDebugLoading, "preloadScene(%d, %d), ", sceneId, entranceId); if (_preloadSceneId != sceneId || _preloadEntranceId != entranceId) { _preloadSceneId = sceneId; _preloadEntranceId = entranceId; return true; } int idx = -1; for (uint i = 0; i < _preloadItems.size(); i++) if (_preloadItems[i]->preloadId1 == sceneId && _preloadItems[i]->preloadId2 == entranceId) { idx = i; break; } if (idx == -1) { _preloadSceneId = 0; _preloadEntranceId = 0; return false; } if (_preloadCallback) { if (!_preloadCallback(*_preloadItems[idx], 0)) return false; } if (g_fp->_currentScene && g_fp->_currentScene->_sceneId == sceneId) g_fp->_currentScene = 0; saveScenePicAniInfos(sceneId); clearGlobalMessageQueueList1(); unloadScene(sceneId); if (_preloadCallback) _preloadCallback(*_preloadItems[idx], 50); loadScene(_preloadItems[idx]->sceneId); ExCommand *ex = new ExCommand(_preloadItems[idx]->sceneId, 17, 62, 0, 0, 0, 1, 0, 0, 0); ex->_excFlags = 2; ex->_param = _preloadItems[idx]->param; _preloadSceneId = 0; _preloadEntranceId = 0; if (_preloadCallback) _preloadCallback(*_preloadItems[idx], 100); ex->postMessage(); return true; } bool GameLoader::unloadScene(int sceneId) { SceneTag *tag; int sceneTag = getSceneTagBySceneId(sceneId, &tag); if (sceneTag < 0) return false; if (_sc2array[sceneTag]._isLoaded) saveScenePicAniInfos(sceneId); _sc2array[sceneTag]._motionController->detachAllObjects(); delete tag->_scene; tag->_scene = 0; _sc2array[sceneTag]._isLoaded = 0; _sc2array[sceneTag]._scene = 0; return true; } int GameLoader::getSceneTagBySceneId(int sceneId, SceneTag **st) { if (_sc2array.size() > 0 && _gameProject->_sceneTagList->size() > 0) { for (uint i = 0; i < _sc2array.size(); i++) { if (_sc2array[i]._sceneId == sceneId) { int num = 0; for (SceneTagList::iterator s = _gameProject->_sceneTagList->begin(); s != _gameProject->_sceneTagList->end(); ++s, num++) { if (s->_sceneId == sceneId) { *st = &(*s); return num; } } } } } *st = 0; return -1; } void GameLoader::applyPicAniInfos(Scene *sc, PicAniInfo **picAniInfo, int picAniInfoCount) { if (picAniInfoCount <= 0) return; debugC(0, kDebugAnimation, "GameLoader::applyPicAniInfos(sc, ptr, %d)", picAniInfoCount); PictureObject *pict; StaticANIObject *ani; for (int i = 0; i < picAniInfoCount; i++) { debugC(7, kDebugAnimation, "PicAniInfo: id: %d type: %d", picAniInfo[i]->objectId, picAniInfo[i]->type); if (picAniInfo[i]->type & 2) { pict = sc->getPictureObjectById(picAniInfo[i]->objectId, picAniInfo[i]->field_8); if (pict) { pict->setPicAniInfo(picAniInfo[i]); continue; } pict = sc->getPictureObjectById(picAniInfo[i]->objectId, 0); if (pict) { PictureObject *pictNew = new PictureObject(pict); sc->_picObjList.push_back(pictNew); pictNew->setPicAniInfo(picAniInfo[i]); continue; } } else { if (!(picAniInfo[i]->type & 1)) continue; Scene *scNew = g_fp->accessScene(picAniInfo[i]->sceneId); if (!scNew) continue; ani = sc->getStaticANIObject1ById(picAniInfo[i]->objectId, picAniInfo[i]->field_8); if (ani) { ani->setPicAniInfo(picAniInfo[i]); continue; } ani = scNew->getStaticANIObject1ById(picAniInfo[i]->objectId, 0); if (ani) { StaticANIObject *aniNew = new StaticANIObject(ani); sc->addStaticANIObject(aniNew, 1); aniNew->setPicAniInfo(picAniInfo[i]); continue; } } } } void GameLoader::saveScenePicAniInfos(int sceneId) { SceneTag *st; int idx = getSceneTagBySceneId(sceneId, &st); if (idx < 0) return; if (!_sc2array[idx]._isLoaded) return; if (!st->_scene) return; int picAniInfosCount; PicAniInfo **pic = savePicAniInfos(st->_scene, 0, 128, &picAniInfosCount); if (_sc2array[idx]._picAniInfos) free(_sc2array[idx]._picAniInfos); _sc2array[idx]._picAniInfos = pic; _sc2array[idx]._picAniInfosCount = picAniInfosCount; } PicAniInfo **GameLoader::savePicAniInfos(Scene *sc, int flag1, int flag2, int *picAniInfoCount) { PicAniInfo **res; *picAniInfoCount = 0; if (!sc) return NULL; if (!sc->_picObjList.size()) return NULL; int numInfos = sc->_staticANIObjectList1.size() + sc->_picObjList.size() - 1; if (numInfos < 1) return NULL; res = (PicAniInfo **)malloc(sizeof(PicAniInfo *) * numInfos); int idx = 0; for (uint i = 0; i < sc->_picObjList.size(); i++) { PictureObject *obj = sc->_picObjList[i]; if (obj && ((obj->_flags & flag1) == flag1) && ((obj->_field_8 & flag2) == flag2)) { res[idx] = new PicAniInfo(); obj->getPicAniInfo(res[idx]); idx++; } } for (uint i = 0; i < sc->_staticANIObjectList1.size(); i++) { StaticANIObject *obj = sc->_staticANIObjectList1[i]; if (obj && ((obj->_flags & flag1) == flag1) && ((obj->_field_8 & flag2) == flag2)) { res[idx] = new PicAniInfo(); obj->getPicAniInfo(res[idx]); res[idx]->type &= 0xFFFF; idx++; } } *picAniInfoCount = idx; debugC(4, kDebugBehavior | kDebugAnimation, "savePicAniInfos: Stored %d infos", idx); if (!idx) { free(res); return NULL; } return res; } void GameLoader::updateSystems(int counterdiff) { if (g_fp->_currentScene) { g_fp->_currentScene->update(counterdiff); _exCommand._messageKind = 17; _updateCounter++; _exCommand._messageNum = 33; _exCommand._excFlags = 0; _exCommand.postMessage(); } processMessages(); if (_preloadSceneId) { processMessages(); preloadScene(_preloadSceneId, _preloadEntranceId); } } Sc2::Sc2() { _sceneId = 0; _field_2 = 0; _scene = 0; _motionController = 0; _data1 = 0; _count1 = 0; _defPicAniInfos = 0; _defPicAniInfosCount = 0; _picAniInfos = 0; _picAniInfosCount = 0; _isLoaded = 0; _entranceData = 0; _entranceDataCount = 0; } bool Sc2::load(MfcArchive &file) { debugC(5, kDebugLoading, "Sc2::load()"); _sceneId = file.readUint16LE(); _motionController = (MotionController *)file.readClass(); _count1 = file.readUint32LE(); debugC(4, kDebugLoading, "count1: %d", _count1); if (_count1 > 0) { _data1 = (int32 *)malloc(_count1 * sizeof(int32)); for (int i = 0; i < _count1; i++) { _data1[i] = file.readUint32LE(); } } else { _data1 = 0; } _defPicAniInfosCount = file.readUint32LE(); debugC(4, kDebugLoading, "defPicAniInfos: %d", _defPicAniInfosCount); if (_defPicAniInfosCount > 0) { _defPicAniInfos = (PicAniInfo **)malloc(_defPicAniInfosCount * sizeof(PicAniInfo *)); for (int i = 0; i < _defPicAniInfosCount; i++) { _defPicAniInfos[i] = new PicAniInfo(); _defPicAniInfos[i]->load(file); } } else { _defPicAniInfos = 0; } _picAniInfos = 0; _picAniInfosCount = 0; _entranceDataCount = file.readUint32LE(); debugC(4, kDebugLoading, "_entranceData: %d", _entranceDataCount); if (_entranceDataCount > 0) { _entranceData = (EntranceInfo **)malloc(_entranceDataCount * sizeof(EntranceInfo *)); for (int i = 0; i < _entranceDataCount; i++) { _entranceData[i] = new EntranceInfo(); _entranceData[i]->load(file); } } else { _entranceData = 0; } if (file.size() - file.pos() > 0) error("Sc2::load(): (%d bytes left)", file.size() - file.pos()); return true; } bool PreloadItems::load(MfcArchive &file) { debugC(5, kDebugLoading, "PreloadItems::load()"); int count = file.readCount(); clear(); for (int i = 0; i < count; i++) { PreloadItem *t = new PreloadItem(); t->preloadId1 = file.readUint32LE(); t->preloadId2 = file.readUint32LE(); t->sceneId = file.readUint32LE(); t->param = file.readSint32LE(); push_back(t); } return true; } const char *getSavegameFile(int saveGameIdx) { static char buffer[20]; sprintf(buffer, "fullpipe.s%02d", saveGameIdx); return buffer; } void GameLoader::restoreDefPicAniInfos() { for (uint i = 0; i < _sc2array.size(); i++) { if (_sc2array[i]._picAniInfos) { free(_sc2array[i]._picAniInfos); _sc2array[i]._picAniInfos = 0; _sc2array[i]._picAniInfosCount = 0; } if (_sc2array[i]._scene) applyPicAniInfos(_sc2array[i]._scene, _sc2array[i]._defPicAniInfos, _sc2array[i]._defPicAniInfosCount); } } GameVar *FullpipeEngine::getGameLoaderGameVar() { if (_gameLoader) return _gameLoader->_gameVar; else return 0; } InputController *FullpipeEngine::getGameLoaderInputController() { if (_gameLoader) return _gameLoader->_inputController; else return 0; } MctlCompound *getCurrSceneSc2MotionController() { return getSc2MctlCompoundBySceneId(g_fp->_currentScene->_sceneId); } } // End of namespace Fullpipe