123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474 |
- /* GCSx
- ** WORLD.CPP
- **
- ** World storage
- ** Non-editor functionality
- */
- /*****************************************************************************
- ** Copyright (C) 2003-2006 Janson
- **
- ** 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., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
- *****************************************************************************/
- #include "all.h"
- World::World() : title("World"), scenesById(), scenesByName(), tilesetsById(), tilesetsByName(), animgroupsById(), animgroupsByName(), scriptsById(), scriptsByNameCode(), scriptsByNameLib(), scriptsByNameNote(), globalLinks() { start_func
- filename = NULL;
- file = NULL;
- startingScene = 0;
- globalLinksDone = 0;
- globalLinksCount = 0;
- }
- World::World(const char* wFilename) throw_File : title(blankString), scenesById(), scenesByName(), tilesetsById(), tilesetsByName(), animgroupsById(), animgroupsByName(), scriptsById(), scriptsByNameCode(), scriptsByNameLib(), scriptsByNameNote(), globalLinks() { start_func
- filename = NULL;
- file = NULL;
- startingScene = 0;
- globalLinksDone = 0;
- globalLinksCount = 0;
-
- TileSet* tileset = NULL;
- Scene* scene = NULL;
- AnimGroup* animgroup = NULL;
- Script* script = NULL;
-
- try {
- filename = new string(wFilename);
- file = new WorldFileLoad(filename);
- Uint32 type;
- Uint32 id;
-
- // Loop pass 1- World Info, TileSets
- file->scanBlocks();
- while (file->nextBlock(&type, &id)) {
- switch (type) {
- case WorldFileLoad::BLOCKTYPE_WORLDINFO:
- file->claimBlock(id, this);
- break;
-
- case WorldFileLoad::BLOCKTYPE_TILESET:
- tileset = new TileSet(this);
- file->claimBlock(id, tileset);
- indexTileSet(tileset);
- tileset = NULL;
- break;
- }
- }
- // Loop pass 2- Animation Groups (need tilesets)
- file->scanBlocks();
- while (file->nextBlock(&type, &id)) {
- switch (type) {
- case WorldFileLoad::BLOCKTYPE_ANIMGROUP:
- animgroup = new AnimGroup(this);
- file->claimBlock(id, animgroup);
- indexAnimGroup(animgroup);
- animgroup = NULL;
- break;
- }
- }
- // Loop pass 3- Scripts (need tilesets/animgroups)
- file->scanBlocks();
- while (file->nextBlock(&type, &id)) {
- switch (type) {
- case WorldFileLoad::BLOCKTYPE_SCRIPT:
- script = new Script(this);
- file->claimBlock(id, script);
- indexScript(script);
- script = NULL;
- break;
- }
- }
- // Loop pass 4- Scenes (need tilesets/animgroups/scripts for spawns)
- file->scanBlocks();
- while (file->nextBlock(&type, &id)) {
- switch (type) {
- case WorldFileLoad::BLOCKTYPE_SCENE:
- scene = new Scene(this);
- file->claimBlock(id, scene);
- indexScene(scene);
- scene = NULL;
- break;
- }
- }
- }
- catch (...) {
- // Temporaries
- delete tileset;
- delete scene;
- delete animgroup;
- delete script;
-
- // Collections
- deleteCollections();
-
- // File
- delete filename;
- delete file;
- filename = NULL;
- file = NULL;
- throw;
- }
- }
- World::~World() { start_func
- clearGlobalLinks();
- // Tilesets, etc.
- deleteCollections();
-
- // Close world file
- delete file;
- delete filename;
- }
-
- void World::clearGlobalLinks() { start_func
- GlobalMap::iterator pos = globalLinks.begin();
- while (pos != globalLinks.end()) {
- delete[] (*pos).second.second;
- const char* toDel = (*pos).first;
- globalLinks.erase(pos);
- delete[] toDel;
- pos = globalLinks.begin();
- }
-
- globalLinksDone = 0;
- globalLinksCount = 0;
- }
- void World::deleteCollections() { start_func
- // Delete scenes (and layers/spawns)
- SceneIndex::iterator posS;
- SceneIndex::iterator endS = scenesById.end();
- for (posS = scenesById.begin(); posS != endS; ++posS) {
- delete (*posS).second;
- (*posS).second = NULL;
- }
-
- // Delete anim groups
- AnimGroupIndex::iterator posA;
- AnimGroupIndex::iterator endA = animgroupsById.end();
- for (posA = animgroupsById.begin(); posA != endA; ++posA) {
- delete (*posA).second;
- (*posA).second = NULL;
- }
- // Scenes and Anim Groups depend on tilesets
- // Delete tilesets
- TileSetIndex::iterator posT;
- TileSetIndex::iterator endT = tilesetsById.end();
- for (posT = tilesetsById.begin(); posT != endT; ++posT) {
- delete (*posT).second;
- (*posT).second = NULL;
- }
-
- // Many things depend on scripts
- // Delete scripts
- ScriptIndex::iterator posX;
- ScriptIndex::iterator endX = scriptsById.end();
- for (posX = scriptsById.begin(); posX != endX; ++posX) {
- delete (*posX).second;
- (*posX).second = NULL;
- }
- }
- void World::loadHeader(FileRead* file) throw_File { start_func
- if (file->getVersion() > 1) {
- throw FileException("Unsupported world header version %d", file->getVersion());
- }
- file->readStr(title);
- startingScene = file->readInt();
-
- clearGlobalLinks();
- globalLinksCount = file->readInt();
- if (globalLinksCount >= 0) {
- int count = globalLinksCount;
- set<int> posUsed;
- while (count--) {
- string name;
- string wart;
-
- file->readStr(name);
- int pos = file->readInt();
- file->readStr(wart);
-
- // (ensure globals aren't duplicated in name or position)
- if ((pos < 0) || (pos >= globalLinksCount) ||
- (globalLinks.find(name.c_str()) != globalLinks.end()) ||
- (posUsed.find(pos) != posUsed.end()))
- throw FileException("Corrupted global variables");
-
- // (ensure name contains a valid wart)
- DataType dt;
- const char* endWart = wartToDataType(wart.c_str(), dt);
- if ((!endWart) || (*endWart != 0) || (dt.baseType == DATA_VOID))
- throw FileException("Corrupted global variables");
-
- const char* nameC = newCpCopy(name);
- globalLinks[nameC].first = pos;
- globalLinks[nameC].second = newCpCopy(wart);
- posUsed.insert(pos);
- }
- globalLinksDone = 1;
- }
- else if (globalLinksCount == -1) {
- globalLinksCount = 0;
- }
- else {
- throw FileException("Corrupted world header");
- }
- }
- void World::loadContent(FileRead* file) { start_func
- // (no content; worldedit may override this)
- delete file;
- }
- int World::isContentCached() const { start_func
- // (no content; worldedit doesn't cache content)
- return 0;
- }
- void World::cacheLoad() { start_func
- // (no content; worldedit doesn't cache content)
- }
- int World::markLock() { start_func
- // (no content to lock)
- return 0;
- }
- int World::markUnlock() { start_func
- // (no content to lock)
- return 0;
- }
- int World::isLocked() const { start_func
- // (no content, no lock)
- return 0;
- }
- void World::indexScene(Scene* addScene) { start_func
- assert(addScene);
- assert(scenesByName.find(addScene->getNameL().c_str()) == scenesByName.end());
- assert(scenesById.find(addScene->getId()) == scenesById.end());
- scenesByName.insert(pair<const char*, Scene*>(addScene->getNameL().c_str(), addScene));
- scenesById.insert(pair<int, Scene*>(addScene->getId(), addScene));
- }
- void World::deindexScene(Scene* remScene) { start_func
- assert(remScene);
- scenesByName.erase(remScene->getNameL().c_str());
- scenesById.erase(remScene->getId());
- }
- Scene* World::findScene(const string& fName) const { start_func
- SceneMap::const_iterator loc = scenesByName.find(fName.c_str());
- if (loc == scenesByName.end()) return NULL;
- return (*loc).second;
- }
- Scene* World::findScene(int fId) const { start_func
- SceneIndex::const_iterator loc = scenesById.find(fId);
- if (loc == scenesById.end()) return NULL;
- return (*loc).second;
- }
- void World::indexTileSet(TileSet* addTileSet) { start_func
- assert(addTileSet);
- assert(tilesetsByName.find(addTileSet->getNameL().c_str()) == tilesetsByName.end());
- assert(tilesetsById.find(addTileSet->getId()) == tilesetsById.end());
- tilesetsByName.insert(pair<const char*, TileSet*>(addTileSet->getNameL().c_str(), addTileSet));
- tilesetsById.insert(pair<int, TileSet*>(addTileSet->getId(), addTileSet));
- }
- void World::deindexTileSet(TileSet* remTileSet) { start_func
- assert(remTileSet);
- tilesetsByName.erase(remTileSet->getNameL().c_str());
- tilesetsById.erase(remTileSet->getId());
- }
- TileSet* World::findTileSet(const string& fName) const { start_func
- TileSetMap::const_iterator loc = tilesetsByName.find(fName.c_str());
- if (loc == tilesetsByName.end()) return NULL;
- return (*loc).second;
- }
- TileSet* World::findTileSet(int fId) const { start_func
- TileSetIndex::const_iterator loc = tilesetsById.find(fId);
- if (loc == tilesetsById.end()) return NULL;
- return (*loc).second;
- }
- void World::indexAnimGroup(AnimGroup* addAnimGroup) { start_func
- assert(addAnimGroup);
- assert(animgroupsByName.find(addAnimGroup->getNameL().c_str()) == animgroupsByName.end());
- assert(animgroupsById.find(addAnimGroup->getId()) == animgroupsById.end());
- animgroupsByName.insert(pair<const char*, AnimGroup*>(addAnimGroup->getNameL().c_str(), addAnimGroup));
- animgroupsById.insert(pair<int, AnimGroup*>(addAnimGroup->getId(), addAnimGroup));
- }
- void World::deindexAnimGroup(AnimGroup* remAnimGroup) { start_func
- assert(remAnimGroup);
- animgroupsByName.erase(remAnimGroup->getNameL().c_str());
- animgroupsById.erase(remAnimGroup->getId());
- }
- AnimGroup* World::findAnimGroup(const string& fName) const { start_func
- AnimGroupMap::const_iterator loc = animgroupsByName.find(fName.c_str());
- if (loc == animgroupsByName.end()) return NULL;
- return (*loc).second;
- }
- AnimGroup* World::findAnimGroup(int fId) const { start_func
- AnimGroupIndex::const_iterator loc = animgroupsById.find(fId);
- if (loc == animgroupsById.end()) return NULL;
- return (*loc).second;
- }
- void World::indexScript(Script* addScript) { start_func
- assert(addScript);
- if (addScript->getType() == Script::SCRIPT_CODE) {
- assert(scriptsByNameCode.find(addScript->getNameL().c_str()) == scriptsByNameCode.end());
- scriptsByNameCode.insert(pair<const char*, Script*>(addScript->getNameL().c_str(), addScript));
- }
- else if (addScript->getType() == Script::SCRIPT_LIBRARY) {
- assert(scriptsByNameLib.find(addScript->getNameL().c_str()) == scriptsByNameLib.end());
- scriptsByNameLib.insert(pair<const char*, Script*>(addScript->getNameL().c_str(), addScript));
- }
- else {
- assert(addScript->getType() == Script::SCRIPT_NOTE);
- assert(scriptsByNameNote.find(addScript->getNameL().c_str()) == scriptsByNameNote.end());
- scriptsByNameNote.insert(pair<const char*, Script*>(addScript->getNameL().c_str(), addScript));
- }
- assert(scriptsById.find(addScript->getId()) == scriptsById.end());
- scriptsById.insert(pair<int, Script*>(addScript->getId(), addScript));
- }
- void World::deindexScript(Script* remScript) { start_func
- assert(remScript);
- if (remScript->getType() == Script::SCRIPT_CODE) {
- scriptsByNameCode.erase(remScript->getNameL().c_str());
- }
- else if (remScript->getType() == Script::SCRIPT_LIBRARY) {
- scriptsByNameLib.erase(remScript->getNameL().c_str());
- }
- else {
- assert(remScript->getType() == Script::SCRIPT_NOTE);
- scriptsByNameNote.erase(remScript->getNameL().c_str());
- }
- scriptsById.erase(remScript->getId());
- }
- Script* World::findScriptCode(const string& fName) const { start_func
- ScriptMap::const_iterator loc = scriptsByNameCode.find(fName.c_str());
- if (loc == scriptsByNameCode.end()) return NULL;
- return (*loc).second;
- }
- Script* World::findScriptLib(const string& fName) const { start_func
- ScriptMap::const_iterator loc = scriptsByNameLib.find(fName.c_str());
- if (loc == scriptsByNameLib.end()) return NULL;
- return (*loc).second;
- }
- Script* World::findScriptNote(const string& fName) const { start_func
- ScriptMap::const_iterator loc = scriptsByNameNote.find(fName.c_str());
- if (loc == scriptsByNameNote.end()) return NULL;
- return (*loc).second;
- }
- Script* World::findScript(int fId) const { start_func
- ScriptIndex::const_iterator loc = scriptsById.find(fId);
- if (loc == scriptsById.end()) return NULL;
- return (*loc).second;
- }
- int World::buildScripts() { start_func
- // Determine what to build (to prevent locking unnecessarily)
- vector<Script*> toBuild;
- ScriptIndex::iterator pos;
- ScriptIndex::iterator end = scriptsById.end();
- for (pos = scriptsById.begin(); pos != end; ++pos) {
- if (((*pos).second->getType() != Script::SCRIPT_NOTE) &&
- ((*pos).second->status() < Script::CODE_COMPILED)) {
- (*pos).second->markLock();
- toBuild.push_back((*pos).second);
- }
- }
-
- // toBuild is all locked- now parse all (anything not in toBuild
- // is already parsed and that parsed function list is already loaded anyway)
- vector<Script*>::iterator posB;
- vector<Script*>::iterator endB = toBuild.end();
- for (posB = toBuild.begin(); posB != endB; ++posB) {
- (*posB)->parseFuncs();
- }
- // Compile all
- int errors = 0;
- for (posB = toBuild.begin(); posB != endB; ++posB) {
- (*posB)->compile();
- errors += (*posB)->numErrors();
- }
- // Unlock all
- for (posB = toBuild.begin(); posB != endB; ++posB) {
- (*posB)->markUnlock();
- }
-
- // Generate global variable list
- if (!errors) {
- // only generate if 1) we compiled something or
- // 2) has never been generated
- if ((!globalLinksDone) || (!toBuild.empty()))
- errors = prepGlobalLinks();
- }
- return errors;
- }
- int World::prepGlobalLinks() { start_func
- int errors = 0;
- clearGlobalLinks();
-
- // Scan ALL link lists for LINK_GLOBAL(VAR)
- ScriptIndex::iterator pos;
- ScriptIndex::iterator end = scriptsById.end();
- for (pos = scriptsById.begin(); pos != end; ++pos) {
- Script* script = (*pos).second;
- if (script->getType() != Script::SCRIPT_NOTE) {
- assert(script->status() >= Script::CODE_COMPILED);
- assert(script->numErrors() == 0);
-
- script->collectGlobalLinks(&globalLinks, &globalLinksCount);
- errors += script->numErrors();
-
- assert(globalLinksCount == globalLinks.size());
- }
- }
-
- if (!errors) globalLinksDone = 1;
-
- return errors;
- }
|