ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

resourceprovider.cpp

Go to the documentation of this file.
00001 /* ResidualVM - A 3D game interpreter
00002  *
00003  * ResidualVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the AUTHORS
00005  * file distributed with this source distribution.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 #include "engines/stark/services/resourceprovider.h"
00024 
00025 #include "engines/stark/resources/bookmark.h"
00026 #include "engines/stark/resources/camera.h"
00027 #include "engines/stark/resources/floor.h"
00028 #include "engines/stark/resources/item.h"
00029 #include "engines/stark/resources/knowledgeset.h"
00030 #include "engines/stark/resources/layer.h"
00031 #include "engines/stark/resources/level.h"
00032 #include "engines/stark/resources/location.h"
00033 #include "engines/stark/resources/root.h"
00034 #include "engines/stark/resources/script.h"
00035 #include "engines/stark/resources/sound.h"
00036 
00037 #include "engines/stark/services/services.h"
00038 #include "engines/stark/services/archiveloader.h"
00039 #include "engines/stark/services/global.h"
00040 #include "engines/stark/services/stateprovider.h"
00041 #include "engines/stark/services/userinterface.h"
00042 
00043 namespace Stark {
00044 
00045 ResourceProvider::ResourceProvider(ArchiveLoader *archiveLoader, StateProvider *stateProvider, Global *global) :
00046         _archiveLoader(archiveLoader),
00047         _stateProvider(stateProvider),
00048         _global(global),
00049         _locationChangeRequest(false),
00050         _restoreCurrentState(false),
00051         _nextDirection(0) {
00052 }
00053 
00054 void ResourceProvider::initGlobal() {
00055     // Load the root archive
00056     _archiveLoader->load("x.xarc");
00057 
00058     // Set the root tree
00059     Resources::Root *root = _archiveLoader->useRoot<Resources::Root>("x.xarc");
00060     _global->setRoot(root);
00061 
00062     // Resources lifecycle update
00063     root->onAllLoaded();
00064 
00065     // Find the global level node
00066     Resources::Level *global = root->findChildWithSubtype<Resources::Level>(Resources::Level::kGlobal);
00067 
00068     // Load the global archive
00069     Common::String globalArchiveName = _archiveLoader->buildArchiveName(global);
00070     _archiveLoader->load(globalArchiveName);
00071 
00072     // Set the global tree
00073     global = _archiveLoader->useRoot<Resources::Level>(globalArchiveName);
00074     _global->setLevel(global);
00075 
00076     // Resources lifecycle update
00077     global->onAllLoaded();
00078 
00079     // Load the state
00080     _stateProvider->restoreLevelState(global);
00081 
00082     _global->setInventory(global->findChildWithSubtype<Resources::KnowledgeSet>(Resources::KnowledgeSet::kInventory));
00083     _global->setApril(global->findChildWithSubtype<Resources::GlobalItemTemplate>(Resources::Item::kItemGlobalTemplate));
00084 }
00085 
00086 Current *ResourceProvider::findLevel(uint16 level) const {
00087     for (CurrentList::const_iterator it = _locations.begin(); it != _locations.end(); it++) {
00088         if ((*it)->getLevel()->getIndex() == level) {
00089             return *it;
00090         }
00091     }
00092 
00093     return nullptr;
00094 }
00095 
00096 Current *ResourceProvider::findLocation(uint16 level, uint16 location) const {
00097     for (CurrentList::const_iterator it = _locations.begin(); it != _locations.end(); it++) {
00098         if ((*it)->getLevel()->getIndex() == level
00099                 && (*it)->getLocation()->getIndex() == location) {
00100             return *it;
00101         }
00102     }
00103 
00104     return nullptr;
00105 }
00106 
00107 Resources::Level *ResourceProvider::getLevel(uint16 level) const {
00108     Current *current = findLevel(level);
00109 
00110     if (current) {
00111         return current->getLevel();
00112     }
00113 
00114     return nullptr;
00115 }
00116 
00117 Resources::Location *ResourceProvider::getLocation(uint16 level, uint16 location) const {
00118     Current *current = findLocation(level, location);
00119 
00120     if (current) {
00121         return current->getLocation();
00122     }
00123 
00124     return nullptr;
00125 }
00126 
00127 void ResourceProvider::pushAndChangeLocation(int16 level, int16 location) {
00128     pushCurrentLocation();
00129     requestLocationChange(level, location);
00130 }
00131 
00132 void ResourceProvider::returnToPushedLocation() {
00133     popCurrentLocation();
00134 }
00135 
00136 void ResourceProvider::pushCurrentLocation() {
00137     PreviousLocation current;
00138     current.level = _global->getCurrent()->getLevel()->getIndex();
00139     current.location = _global->getCurrent()->getLocation()->getIndex();
00140     current.inventoryOpen = StarkUserInterface->isInventoryOpen();
00141 
00142     _locationStack.push_back(current);
00143 
00144     StarkUserInterface->inventoryOpen(false);
00145 }
00146 
00147 void ResourceProvider::popCurrentLocation() {
00148     if (_locationStack.empty()) {
00149         error("Empty location stack");
00150     } else {
00151         PreviousLocation previous = _locationStack.back();
00152         _locationStack.pop_back();
00153 
00154         requestLocationChange(previous.level, previous.location);
00155         StarkUserInterface->inventoryOpen(previous.inventoryOpen);
00156     }
00157 }
00158 
00159 void ResourceProvider::requestLocationChange(uint16 level, uint16 location) {
00160     Current *currentLocation = new Current();
00161     _locations.push_back(currentLocation);
00162 
00163     // Retrieve the level archive name
00164     Resources::Root *root = _global->getRoot();
00165     Resources::Level *rootLevelResource = root->findChildWithIndex<Resources::Level>(level);
00166     Common::String levelArchive = _archiveLoader->buildArchiveName(rootLevelResource);
00167 
00168     // Load the archive, and get the resource sub-tree root
00169     bool newlyLoaded = _archiveLoader->load(levelArchive);
00170     currentLocation->setLevel(_archiveLoader->useRoot<Resources::Level>(levelArchive));
00171 
00172     // If we just loaded a resource tree, restore its state
00173     if (newlyLoaded) {
00174         currentLocation->getLevel()->onAllLoaded();
00175         _stateProvider->restoreLevelState(currentLocation->getLevel());
00176     }
00177 
00178     // Retrieve the location archive name
00179     Resources::Level *levelResource = currentLocation->getLevel();
00180     Resources::Location *levelLocationResource = levelResource->findChildWithIndex<Resources::Location>(location);
00181     Common::String locationArchive = _archiveLoader->buildArchiveName(levelResource, levelLocationResource);
00182 
00183     // Load the archive, and get the resource sub-tree root
00184     newlyLoaded = _archiveLoader->load(locationArchive);
00185     currentLocation->setLocation(_archiveLoader->useRoot<Resources::Location>(locationArchive));
00186 
00187     if (currentLocation->getLocation()->has3DLayer()) {
00188         Resources::Layer3D *layer = currentLocation->getLocation()->findChildWithSubtype<Resources::Layer3D>(Resources::Layer::kLayer3D);
00189         currentLocation->setFloor(layer->findChild<Resources::Floor>());
00190         currentLocation->setCamera(layer->findChild<Resources::Camera>());
00191     } else {
00192         currentLocation->setFloor(nullptr);
00193         currentLocation->setCamera(nullptr);
00194     }
00195 
00196     // If we just loaded a resource tree, restore its state
00197     if (newlyLoaded) {
00198         currentLocation->getLocation()->onAllLoaded();
00199         _stateProvider->restoreLocationState(currentLocation->getLevel(), currentLocation->getLocation());
00200     }
00201 
00202     _locationChangeRequest = true;
00203 }
00204 
00205 void ResourceProvider::performLocationChange() {
00206     Current *current = _locations.back();
00207     Current *previous = _global->getCurrent();
00208     bool levelChanged = !previous || previous->getLevel() != current->getLevel();
00209 
00210     // Exit the previous location
00211     if (previous) {
00212         // Trigger location change scripts
00213         if (levelChanged) {
00214             runLocationChangeScripts(previous->getLevel(), Resources::Script::kCallModeExitLocation);
00215         }
00216         runLocationChangeScripts(previous->getLocation(), Resources::Script::kCallModeExitLocation);
00217 
00218         // Resources lifecycle update
00219         previous->getLocation()->onExitLocation();
00220         previous->getLevel()->onExitLocation();
00221         _global->getLevel()->onExitLocation();
00222     }
00223 
00224     // Clear all pointers to location objects in the UI instances
00225     StarkUserInterface->clearLocationDependentState();
00226 
00227     // Set the new current location
00228     _global->setCurrent(current);
00229 
00230     // Resources lifecycle update
00231     _global->getLevel()->onEnterLocation();
00232     current->getLevel()->onEnterLocation();
00233     current->getLocation()->onEnterLocation();
00234 
00235     if (current->getLocation()->has3DLayer()) {
00236         // Fetch the scene item for April
00237         current->setInteractive(Resources::Object::cast<Resources::ModelItem>(_global->getApril()->getSceneInstance()));
00238     }
00239 
00240     if (_restoreCurrentState) {
00241         _stateProvider->restoreGlobalState(_global->getLevel());
00242         _stateProvider->restoreCurrentLevelState(current->getLevel());
00243         _stateProvider->restoreCurrentLocationState(current->getLevel(), current->getLocation());
00244         _restoreCurrentState = false;
00245     } else {
00246         setAprilInitialPosition();
00247         setScrollInitialPosition();
00248 
00249         // Trigger location change scripts
00250         if (levelChanged) {
00251             runLocationChangeScripts(current->getLevel(), Resources::Script::kCallModeEnterLocation);
00252         }
00253         runLocationChangeScripts(current->getLocation(), Resources::Script::kCallModeEnterLocation);
00254     }
00255 
00256     current->getLocation()->resetAnimationBlending();
00257     purgeOldLocations();
00258 
00259     _locationChangeRequest = false;
00260 }
00261 
00262 void ResourceProvider::runLocationChangeScripts(Resources::Object *resource, uint32 scriptCallMode) {
00263     Common::Array<Resources::Script *> scripts = resource->listChildrenRecursive<Resources::Script>();
00264 
00265     if (scriptCallMode == Resources::Script::kCallModeEnterLocation) {
00266         for (uint i = 0; i < scripts.size(); i++) {
00267             scripts[i]->reset();
00268         }
00269     }
00270 
00271     for (uint i = 0; i < scripts.size(); i++) {
00272         scripts[i]->execute(scriptCallMode);
00273     }
00274 
00275     if (scriptCallMode == Resources::Script::kCallModeExitLocation) {
00276         Common::Array<Resources::Sound *> sounds = resource->listChildrenRecursive<Resources::Sound>();
00277         for (uint i = 0; i < sounds.size(); i++) {
00278             sounds[i]->stop();
00279         }
00280     }
00281 }
00282 
00283 void ResourceProvider::setNextLocationPosition(const ResourceReference &bookmark, int32 direction) {
00284     _nextPositionBookmarkReference = bookmark;
00285     _nextDirection = direction;
00286 }
00287 
00288 void ResourceProvider::setAprilInitialPosition() {
00289     Current *current = _global->getCurrent();
00290     Resources::ModelItem *april = current->getInteractive();
00291     if (!april) {
00292         return; // No character
00293     }
00294 
00295     // Set the initial position for April
00296     if (!_nextPositionBookmarkReference.empty()) {
00297         Resources::Bookmark *position = _nextPositionBookmarkReference.resolve<Resources::Bookmark>();
00298         april->placeOnBookmark(position);
00299 
00300         Resources::Camera *camera = current->getCamera();
00301         Math::Angle cameraAngle = camera->getHorizontalAngle();
00302         april->setDirection(_nextDirection + cameraAngle);
00303     } else if (april->getFloorFaceIndex() <= 0) {
00304         // No target location provided, place April on the first floor face
00305         april->placeDefaultPosition();
00306     }
00307 
00308     _nextPositionBookmarkReference = ResourceReference();
00309     _nextDirection = 0;
00310 }
00311 
00312 void ResourceProvider::setScrollInitialPosition() {
00313     Current *current = _global->getCurrent();
00314     Resources::Location *location = current->getLocation();
00315     location->scrollToCharacterImmediate();
00316 }
00317 
00318 void ResourceProvider::purgeOldLocations() {
00319     while (_locations.size() > 2) {
00320         Current *location = _locations.front();
00321 
00322         _stateProvider->saveLocationState(location->getLevel(), location->getLocation());
00323         _stateProvider->saveLevelState(location->getLevel());
00324 
00325         _archiveLoader->returnRoot(_archiveLoader->buildArchiveName(location->getLevel(), location->getLocation()));
00326         _archiveLoader->returnRoot(_archiveLoader->buildArchiveName(location->getLevel()));
00327 
00328         delete location;
00329 
00330         _locations.pop_front();
00331     }
00332 
00333     _archiveLoader->unloadUnused();
00334 }
00335 
00336 void ResourceProvider::commitActiveLocationsState() {
00337     // Save active location states
00338     for (CurrentList::const_iterator it = _locations.begin(); it != _locations.end(); it++) {
00339         _stateProvider->saveLocationState((*it)->getLevel(), (*it)->getLocation());
00340         _stateProvider->saveLevelState((*it)->getLevel());
00341     }
00342 
00343     _stateProvider->saveLevelState(_global->getLevel());
00344 
00345     // Save the current location "extended" state, to be able to restore them to the exact same state.
00346     Current *location = _global->getCurrent();
00347     _stateProvider->saveCurrentLocationState(location->getLevel(), location->getLocation());
00348     _stateProvider->saveCurrentLevelState(location->getLevel());
00349 
00350     _stateProvider->saveGlobalState(_global->getLevel());
00351 }
00352 
00353 void ResourceProvider::shutdown() {
00354     _stateProvider->clear();
00355 
00356     _locationStack.clear();
00357 
00358     // Flush the locations list
00359     for (CurrentList::const_iterator it = _locations.begin(); it != _locations.end(); it++) {
00360         Current *location = *it;
00361 
00362         _archiveLoader->returnRoot(_archiveLoader->buildArchiveName(location->getLevel(), location->getLocation()));
00363         _archiveLoader->returnRoot(_archiveLoader->buildArchiveName(location->getLevel()));
00364 
00365         delete location;
00366     }
00367     _locations.clear();
00368 
00369     // Return the global resources
00370     if (_global->getLevel()) {
00371         _archiveLoader->returnRoot(_archiveLoader->buildArchiveName(_global->getLevel()));
00372         _global->setLevel(nullptr);
00373     }
00374 
00375     if (_global->getRoot()) {
00376         _archiveLoader->returnRoot("x.xarc");
00377         _global->setRoot(nullptr);
00378     }
00379 
00380     _global->setCurrent(nullptr);
00381     _global->setInventory(nullptr);
00382     _global->setApril(nullptr);
00383 
00384     _archiveLoader->unloadUnused();
00385 }
00386 
00387 Resources::Level *ResourceProvider::getLevelFromLocation(Resources::Location *location) const {
00388     for (CurrentList::const_iterator it = _locations.begin(); it != _locations.end(); it++) {
00389         if ((*it)->getLocation() == location) {
00390             return (*it)->getLevel();
00391         }
00392     }
00393 
00394     return nullptr;
00395 }
00396 
00397 void ResourceProvider::readLocationStack(Common::SeekableReadStream *stream, uint32 version) {
00398     ResourceSerializer serializer(stream, nullptr, version);
00399     saveLoadLocationStack(serializer);
00400 }
00401 
00402 void ResourceProvider::writeLocationStack(Common::WriteStream *stream) {
00403     ResourceSerializer serializer(nullptr, stream, StateProvider::kSaveVersion);
00404     saveLoadLocationStack(serializer);
00405 }
00406 
00407 void ResourceProvider::saveLoadLocationStack(ResourceSerializer &serializer) {
00408     serializer.syncArraySize(_locationStack, 12);
00409 
00410     for (uint i = 0; i < _locationStack.size(); i++) {
00411         serializer.syncAsUint16LE(_locationStack[i].level);
00412         serializer.syncAsUint16LE(_locationStack[i].location);
00413         serializer.syncAsUint32LE(_locationStack[i].inventoryOpen);
00414     }
00415 }
00416 
00417 } // End of namespace Stark


Generated on Sat Mar 16 2019 05:01:52 for ResidualVM by doxygen 1.7.1
curved edge   curved edge