World.cpp

Go to the documentation of this file.
00001 /*
00002 Copyright (C) 2003-2007 The Pentagram team
00003 
00004 This program is free software; you can redistribute it and/or
00005 modify it under the terms of the GNU General Public License
00006 as published by the Free Software Foundation; either version 2
00007 of the License, or (at your option) any later version.
00008 
00009 This program is distributed in the hope that it will be useful,
00010 but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 GNU General Public License for more details.
00013 
00014 You should have received a copy of the GNU General Public License
00015 along with this program; if not, write to the Free Software
00016 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00017 */
00018 
00019 #include "pent_include.h"
00020 
00021 #include "World.h"
00022 #include "Map.h"
00023 #include "CurrentMap.h"
00024 #include "IDataSource.h"
00025 #include "ODataSource.h"
00026 #include "FlexFile.h"
00027 #include "RawArchive.h"
00028 #include "ItemFactory.h"
00029 #include "Actor.h"
00030 #include "MainActor.h"
00031 #include "idMan.h"
00032 #include "GameData.h"
00033 #include "Kernel.h"
00034 #include "ObjectManager.h"
00035 #include "GUIApp.h"
00036 #include "CameraProcess.h" // for resetting the camera
00037 #include "Gump.h" // For CloseItemDependents notification
00038 #include "Animation.h"
00039 #include "getObject.h"
00040 #include "MemoryManager.h"
00041 #include "AudioProcess.h"
00042 
00043 //#define DUMP_ITEMS
00044 
00045 World* World::world = 0;
00046 
00047 World::World()
00048         : currentmap(0)
00049 {
00050         con.Print(MM_INFO, "Creating World...\n");
00051         assert(world == 0);
00052 
00053         world = this;
00054 }
00055 
00056 
00057 World::~World()
00058 {
00059         con.Print(MM_INFO, "Destroying World...\n");
00060         clear();
00061 
00062         world = 0;
00063 }
00064 
00065 
00066 void World::clear()
00067 {
00068         unsigned int i;
00069 
00070         for (i = 0; i < maps.size(); ++i) {
00071                 delete maps[i];
00072         }
00073         maps.clear();
00074 
00075         while (!ethereal.empty())
00076                 ethereal.pop_front();
00077 
00078         if (currentmap)
00079                 delete currentmap;
00080         currentmap = 0;
00081 }
00082 
00083 void World::reset()
00084 {
00085         con.Print(MM_INFO, "Resetting World...\n");
00086 
00087         clear();
00088 
00089         initMaps();
00090 }
00091 
00092 void World::initMaps()
00093 {
00094         // Q: How do we determine which Maps to create? Only create those
00095         // with non-zero size in fixed.dat?
00096 
00097         maps.resize(256);
00098         for (unsigned int i = 0; i < 256; ++i) {
00099                 maps[i] = new Map(i);
00100         }
00101 
00102         currentmap = new CurrentMap();
00103 }
00104 
00105 bool World::switchMap(uint32 newmap)
00106 {
00107         assert(currentmap);
00108 
00109         if (currentmap->getNum() == newmap)
00110                 return true;
00111 
00112         if (newmap >= maps.size() || maps[newmap] == 0)
00113                 return false; // no such map
00114 
00115         // Map switching procedure:
00116 
00117         // get rid of camera
00118         // stop all sound effects (except speech, such as Guardian barks)
00119         // notify all gumps of a map change
00120         // delete any ethereal objects
00121         // write back CurrentMap to the old map, which
00122         //   deletes all disposable items
00123         //   deletes the EggHatcher
00124         //   resets all eggs
00125         // swap out fixed items in old map
00126         // kill all processes (except those of type 1 or of item 0)
00127         // load fixed items in new map
00128         // load new map into CurrentMap, which also
00129         //   assigns objIDs to fixed items
00130         //   assigns objIDs to nonfixed items
00131         //   creates an EggHatcher and notifies it of all eggs
00132         //   sets up all NPCs in the new map
00133         // reset camera
00134 
00135 
00136         // kill camera
00137         CameraProcess::ResetCameraProcess();
00138 
00139         AudioProcess *ap = AudioProcess::get_instance();
00140         if (ap) ap->stopAllExceptSpeech();
00141 
00142         // Notify all the gumps of the mapchange
00143         GUIApp *gui = GUIApp::get_instance();
00144         if (gui) 
00145         {
00146                 Gump *desktop = gui->getDesktopGump();
00147                 if (desktop) desktop->CloseItemDependents();
00148         }
00149 
00150         // get rid of any remaining ethereal items
00151         while (!ethereal.empty()) {
00152                 uint16 eth = ethereal.front();
00153                 ethereal.pop_front();
00154                 Item* i = getItem(eth);
00155                 if(i) i->destroy();
00156         }
00157 
00158         uint32 oldmap = currentmap->getNum();
00159         if (oldmap != 0) {
00160                 perr << "Unloading map " << oldmap << std::endl;
00161 
00162                 assert(oldmap < maps.size() && maps[oldmap] != 0);
00163 
00164                 currentmap->writeback();
00165 
00166                 perr << "Unloading Fixed items from map " << oldmap << std::endl;
00167 
00168                 maps[oldmap]->unloadFixed();
00169         }
00170 
00171         // Kill any processes that need killing (those with type != 1 && item != 0)
00172         Kernel::get_instance()->killProcessesNotOfType(0, 1, true);
00173 
00174         pout << "Loading Fixed items in map " << newmap << std::endl;
00175         IDataSource *items = GameData::get_instance()->getFixed()
00176                 ->get_datasource(newmap);
00177         maps[newmap]->loadFixed(items);
00178         delete items;
00179 
00180         currentmap->loadMap(maps[newmap]);
00181 
00182         // reset camera
00183         CameraProcess::SetCameraProcess(new CameraProcess(1));
00184         CameraProcess::SetEarthquake(0);
00185 
00186         MemoryManager::get_instance()->freeResources();
00187 
00188         return true;
00189 }
00190 
00191 void World::loadNonFixed(IDataSource* ds)
00192 {
00193         FlexFile* f = new FlexFile(ds);
00194 
00195         pout << "Loading NonFixed items" << std::endl;
00196                         
00197         for (unsigned int i = 0; i < f->getCount(); ++i) {
00198 
00199                 // items in this map?
00200                 if (f->getSize(i) > 0) {
00201                         assert(maps.size() > i);
00202                         assert(maps[i] != 0);
00203 
00204                         IDataSource *items = f->getDataSource(i);
00205 
00206                         maps[i]->loadNonFixed(items);
00207 
00208                         delete items;
00209 
00210                 }
00211         }
00212 
00213         delete f;
00214 }
00215 
00216 void World::loadItemCachNPCData(IDataSource* itemcach, IDataSource* npcdata)
00217 {
00218         FlexFile* itemcachflex = new FlexFile(itemcach);
00219         FlexFile* npcdataflex = new FlexFile(npcdata);
00220 
00221         IDataSource* itemds = itemcachflex->getDataSource(0);
00222         IDataSource* npcds = npcdataflex->getDataSource(0);
00223 
00224         delete itemcachflex;
00225         delete npcdataflex;
00226 
00227         pout << "Loading NPCs" << std::endl;
00228 
00229         for (uint32 i = 1; i < 256; ++i) // Get rid of constants?
00230         {
00231                 // These are ALL unsigned on disk
00232                 itemds->seek(0x00000+i*2);
00233                 sint32 x = static_cast<sint32>(itemds->readX(2));
00234                 itemds->seek(0x04800+i*2);
00235                 sint32 y = static_cast<sint32>(itemds->readX(2));
00236                 itemds->seek(0x09000+i*1);
00237                 sint32 z = static_cast<sint32>(itemds->readX(1));
00238 
00239                 itemds->seek(0x0B400+i*2);
00240                 uint32 shape = itemds->read2();
00241                 itemds->seek(0x0FC00+i*1);
00242                 uint32 frame = itemds->read1();
00243                 itemds->seek(0x12000+i*2);
00244                 uint16 flags = itemds->read2();
00245                 itemds->seek(0x16800+i*2);
00246                 uint16 quality = itemds->read2();
00247                 itemds->seek(0x1B000+i*1);
00248                 uint16 npcnum = static_cast<uint8>(itemds->read1());
00249                 itemds->seek(0x1D400+i*1);
00250                 uint16 mapnum = static_cast<uint8>(itemds->read1());
00251                 itemds->seek(0x1F800+i*2);
00252                 uint16 next;
00253                 next = itemds->read2();
00254 
00255                 // half the frame number is stored in npcdata.dat
00256                 npcds->seek(7 + i * 0x31);
00257                 frame += npcds->read1() << 8;
00258 
00259                 if (shape == 0) {
00260                         // U8's itemcach has a lot of garbage in it.
00261                         // Ignore it.
00262                         continue;
00263                 }
00264 
00265 #ifdef DUMP_ITEMS
00266                 pout << shape << "," << frame << ":\t(" << x << "," << y << "," << z << "),\t" << std::hex << flags << std::dec << ", " << quality << ", " << npcnum << ", " << mapnum << ", " << next << std::endl;
00267 #endif
00268 
00269                 Actor *actor = ItemFactory::createActor(shape,frame,quality,
00270                                                                                                 flags|Item::FLG_IN_NPC_LIST,
00271                                                                                                 npcnum,mapnum,
00272                                                                                                 Item::EXT_PERMANENT_NPC,false);
00273                 if (!actor) {
00274 #ifdef DUMP_ITEMS
00275                         pout << "Couldn't create actor" << std::endl;
00276 #endif
00277                         continue;
00278                 }
00279                 ObjectManager::get_instance()->assignActorObjId(actor, i);
00280 
00281                 actor->setLocation(x,y,z);
00282 
00283                 // read npcdata:
00284                 npcds->seek(i * 0x31);
00285                 actor->setStr(npcds->read1()); // 0x00: strength
00286                 actor->setDex(npcds->read1()); // 0x01: dexterity
00287                 actor->setInt(npcds->read1()); // 0x02: intelligence
00288                 actor->setHP(npcds->read1());  // 0x03: hitpoints
00289                 actor->setDir(npcds->read1()); // 0x04: direction
00290                 uint16 la = npcds->read2();    // 0x05,0x06: last anim
00291                 actor->setLastAnim(static_cast<Animation::Sequence>(la));
00292                 npcds->skip(1); // 0x07: high byte of framenum
00293                 npcds->skip(1); // 0x08: current anim frame
00294                 npcds->skip(1); // 0x09: start Z of current fall
00295                 npcds->skip(1); // 0x0A: unknown, always zero
00296                 uint8 align = npcds->read1(); // 0x0B: alignments
00297                 actor->setAlignment(align & 0x0F);
00298                 actor->setEnemyAlignment(align & 0xF0);
00299                 actor->setUnk0C(npcds->read1()); // 0x0C: unknown; 
00300                                 // 0x0C is almost always zero, except for
00301                         // the avatar (0xC0) and
00302                         // Malchir, Vardion, Gorgrond, Beren (0xE0)
00303                 npcds->skip(14); // 0x0D-0x1A: unknown, always zero
00304                 actor->clearActorFlag(0xFF);
00305                 actor->setActorFlag(npcds->read1()); // 0x1B: flags
00306                 npcds->skip(1);  // 0x1C: unknown, always zero
00307                 npcds->skip(16); // 0x1D-0x2C: equipment
00308                 sint16 mana = static_cast<sint16>(npcds->read2()); // 0x2D,0x2E: mana
00309                 actor->setMana(mana);
00310                 actor->clearActorFlag(0xFFFF00);
00311                 uint32 flags2F = npcds->read1(); // 0x2F: flags
00312                 actor->setActorFlag(flags2F << 8);
00313                 uint32 flags30 = npcds->read1(); // 0x30: flags
00314                 actor->setActorFlag(flags30 << 16);
00315         }
00316 
00317         delete itemds;
00318         delete npcds;
00319 }
00320 
00321 
00322 void World::worldStats()
00323 {
00324         unsigned int i, mapcount = 0;
00325 
00326         for (i = 0; i < maps.size(); i++) {
00327                 if (maps[i] != 0 && !maps[i]->isEmpty())
00328                         mapcount++;
00329         }
00330 
00331         pout << "World memory stats:" << std::endl;
00332         pout << "Maps       : " << mapcount << "/256" << std::endl;
00333         Actor* av = getMainActor();
00334         pout << "Avatar pos.: ";
00335         if (av) {
00336                 pout << "map " << av->getMapNum() << ", (";
00337                 sint32 x,y,z;
00338                 av->getLocation(x,y,z);
00339                 pout << x << "," << y << "," << z << ")" << std::endl;
00340         } else {
00341                 pout << "missing (null)" << std::endl;
00342         }
00343 }
00344 
00345 void World::save(ODataSource* ods)
00346 {
00347         ods->write4(currentmap->getNum());
00348 
00349         ods->write2(currentmap->egghatcher);
00350 
00351         uint16 es = ethereal.size();
00352         ods->write4(es);
00353 
00354         // empty stack and refill it again
00355         uint16* e = new uint16[es];
00356         std::list<ObjId>::iterator it = ethereal.begin();
00357         unsigned int i;
00358         for (i = 0; i < es; ++i) {
00359                 e[es-i] = *it;
00360                 ++it;
00361         }
00362 
00363         for (i = 0; i < es; ++i) {
00364                 ods->write2(e[i]);
00365         }
00366         delete[] e;
00367 }
00368 
00369 // load items
00370 bool World::load(IDataSource* ids, uint32 version)
00371 {
00372         uint16 curmapnum = ids->read4();
00373         currentmap->setMap(maps[curmapnum]);
00374 
00375         currentmap->egghatcher = ids->read2();
00376 
00377         uint32 etherealcount = ids->read4();
00378         for (unsigned int i = 0; i < etherealcount; ++i) {
00379                 ethereal.push_front(ids->read2());
00380         }
00381 
00382         return true;
00383 }
00384 
00385 void World::saveMaps(ODataSource* ods)
00386 {
00387         ods->write4(maps.size());
00388         for (unsigned int i = 0; i < maps.size(); ++i) {
00389                 maps[i]->save(ods);
00390         }
00391 }
00392 
00393 
00394 bool World::loadMaps(IDataSource* ids, uint32 version)
00395 {
00396         uint32 mapcount = ids->read4();
00397 
00398         // Map objects have already been created by reset()
00399         for (unsigned int i = 0; i < mapcount; ++i) {
00400                 bool res = maps[i]->load(ids, version);
00401                 if (!res) return false;
00402         }
00403 
00404         return true;
00405 }

Generated on Fri Jul 27 22:27:53 2007 for pentagram by  doxygen 1.4.7