CurrentMap.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 "CurrentMap.h"
00022 #include "Map.h"
00023 #include "Item.h"
00024 #include "GlobEgg.h"
00025 #include "Egg.h"
00026 #include "Actor.h"
00027 #include "World.h"
00028 #include "Rect.h"
00029 #include "Container.h"
00030 #include "UCList.h"
00031 #include "ShapeInfo.h"
00032 #include "TeleportEgg.h"
00033 #include "EggHatcherProcess.h"
00034 #include "Kernel.h"
00035 #include "GameData.h"
00036 #include "MainShapeArchive.h"
00037 #include "GUIApp.h"
00038 #include "GameMapGump.h"
00039 #include "Direction.h"
00040 #include "getObject.h"
00041 
00042 #include "IDataSource.h"        
00043 #include "ODataSource.h"
00044 
00045 using std::list; // too messy otherwise
00046 using Pentagram::Rect;
00047 typedef list<Item*> item_list;
00048 
00049 CurrentMap::CurrentMap()
00050         : current_map(0), egghatcher(0),
00051                 fast_x_min(-1), fast_y_min(-1),
00052                 fast_x_max(-1), fast_y_max(-1)
00053 {
00054         items = new list<Item*>*[MAP_NUM_CHUNKS];
00055         fast = new uint32*[MAP_NUM_CHUNKS];
00056         for (unsigned int i = 0; i < MAP_NUM_CHUNKS; i++) {
00057                 items[i] = new list<Item*>[MAP_NUM_CHUNKS];
00058                 fast[i] = new uint32[MAP_NUM_CHUNKS/32];
00059                 std::memset(fast[i],false,sizeof(uint32)*MAP_NUM_CHUNKS/32);
00060         }
00061 
00062         if (GAME_IS_U8) {
00063                 mapChunkSize = 512;
00064         } else if (GAME_IS_CRUSADER) {
00065                 mapChunkSize = 1024;
00066         } else {
00067                 CANT_HAPPEN_MSG("Unknown game type in CurrentMap constructor.");
00068         }
00069 }
00070 
00071 
00072 CurrentMap::~CurrentMap()
00073 {
00074 //      clear();
00075 
00076         for (unsigned int i = 0; i < MAP_NUM_CHUNKS; i++) {
00077                 delete[] items[i];
00078                 delete[] fast[i];
00079         }
00080         delete[] items;
00081         delete[] fast;
00082 }
00083 
00084 void CurrentMap::clear()
00085 {
00086         for (unsigned int i = 0; i < MAP_NUM_CHUNKS; i++) {
00087                 for (unsigned int j = 0; j < MAP_NUM_CHUNKS; j++) {
00088                         item_list::iterator iter;
00089                         for (iter = items[i][j].begin(); iter != items[i][j].end(); ++iter)
00090                                 delete *iter;
00091                         items[i][j].clear();
00092                 }
00093                 std::memset(fast[i],false,sizeof(uint32)*MAP_NUM_CHUNKS/32);
00094         }
00095 
00096         fast_x_min =  fast_y_min = fast_x_max = fast_y_max = -1;
00097         current_map = 0;
00098 
00099         Process* ehp = Kernel::get_instance()->getProcess(egghatcher);
00100         if (ehp)
00101                 ehp->terminate();
00102         egghatcher = 0;
00103 }
00104 
00105 uint32 CurrentMap::getNum() const
00106 {
00107         if (current_map == 0)
00108                 return 0;
00109 
00110         return current_map->mapnum;
00111 }
00112 
00113 void CurrentMap::createEggHatcher()
00114 {
00115         // get rid of old one, if any
00116         Process* ehp = Kernel::get_instance()->getProcess(egghatcher);
00117         if (ehp)
00118                 ehp->terminate();
00119 
00120     ehp = new EggHatcherProcess();
00121         egghatcher = Kernel::get_instance()->addProcess(ehp);
00122 }
00123 
00124 void CurrentMap::writeback()
00125 {
00126         if (!current_map)
00127                 return;
00128 
00129         for (unsigned int i = 0; i < MAP_NUM_CHUNKS; i++) {
00130                 for (unsigned int j = 0; j < MAP_NUM_CHUNKS; j++) {
00131                         item_list::iterator iter;
00132                         for (iter = items[i][j].begin(); iter != items[i][j].end(); ++iter)
00133                         {
00134                                 Item* item = *iter;
00135 
00136                                 // item is being removed from the CurrentMap item lists
00137                                 item->clearExtFlag(Item::EXT_INCURMAP);
00138 
00139                                 // delete all fast only and disposable items
00140                                 if ((item->getFlags() & Item::FLG_FAST_ONLY) ||
00141                                         (item->getFlags() & Item::FLG_DISPOSABLE))
00142                                 {
00143                                         delete item;
00144                                         continue;
00145                                 }
00146 
00147                                 // Reset the egg
00148                                 Egg* egg = p_dynamic_cast<Egg*>(item);
00149                                 if (egg) {
00150                                         egg->reset();
00151                                 }
00152 
00153                                 // this item isn't from the Map. (like NPCs)
00154                                 if (item->getFlags() & Item::FLG_IN_NPC_LIST)
00155                                         continue;
00156 
00157                                 item->clearObjId();
00158                                 if (item->getExtFlags() & Item::EXT_FIXED) {
00159                                         // item came from fixed
00160                                         current_map->fixeditems.push_back(item);
00161                                 } else {
00162                                         current_map->dynamicitems.push_back(item);
00163                                 }
00164                         }
00165                         items[i][j].clear();
00166                 }
00167         }
00168 
00169         // delete egghatcher
00170         Process* ehp = Kernel::get_instance()->getProcess(egghatcher);
00171         if (ehp)
00172                 ehp->terminate();
00173         egghatcher = 0;
00174 }
00175 
00176 void CurrentMap::loadItems(list<Item*> itemlist, bool callCacheIn)
00177 {
00178         item_list::iterator iter;
00179         for (iter = itemlist.begin(); iter != itemlist.end(); ++iter)
00180         {
00181                 Item* item = *iter;
00182 
00183                 item->assignObjId();
00184 
00185                 // No fast area for you!
00186                 item->clearFlag(Item::FLG_FASTAREA);
00187 
00188                 // add item to internal object list
00189                 addItemToEnd(item);
00190 
00191                 if (callCacheIn)
00192                         item->callUsecodeEvent_cachein();
00193         }
00194 }
00195 
00196 void CurrentMap::loadMap(Map* map)
00197 {
00198         // don't call the cachein events at startup or when loading a savegame
00199         bool callCacheIn = (current_map != 0);
00200 
00201         current_map = map;
00202 
00203         createEggHatcher();
00204 
00205         // Clear fast area
00206         for (unsigned int i = 0; i < MAP_NUM_CHUNKS; i++) {
00207                 std::memset(fast[i],false,sizeof(uint32)*MAP_NUM_CHUNKS/32);
00208         }
00209         fast_x_min = -1;
00210         fast_y_min = -1;
00211         fast_x_max = -1;
00212         fast_y_max = -1;
00213 
00214         loadItems(map->fixeditems, callCacheIn);
00215         loadItems(map->dynamicitems, callCacheIn);
00216 
00217         // we take control of the items in map, so clear the pointers
00218         map->fixeditems.clear();
00219         map->dynamicitems.clear();
00220 
00221         // load relevant NPCs to the item lists
00222         // !constant
00223         for (uint16 i = 0; i < 256; ++i) {
00224                 Actor* actor = getActor(i);
00225                 if (!actor) continue;
00226 
00227                 // Schedule
00228                 // CHECKME: is this the right time to pass?
00229                 if (callCacheIn)
00230                         actor->schedule(GUIApp::get_instance()->getGameTimeInSeconds()/60);
00231                 
00232                 if (actor->getMapNum() == getNum()) {
00233                         addItemToEnd(actor);
00234 
00235 #if 0
00236                         // the avatar's cachein function is very strange; disabled for now
00237                         if (callCacheIn)
00238                                 actor->callUsecodeEvent_cachein();
00239 #endif
00240                 }
00241         }
00242 }
00243 
00244 void CurrentMap::addItem(Item* item)
00245 {
00246         sint32 ix, iy, iz;
00247 
00248         item->getLocation(ix, iy, iz);
00249 
00250         if (ix < 0 || ix >= mapChunkSize*MAP_NUM_CHUNKS || 
00251                 iy < 0 || iy >= mapChunkSize*MAP_NUM_CHUNKS) {
00252                 perr << "Skipping item " << item->getObjId() << ": out of range (" 
00253                          << ix << "," << iy << ")" << std::endl;
00254                 return;
00255         }
00256 
00257         sint32 cx = ix / mapChunkSize;
00258         sint32 cy = iy / mapChunkSize;
00259 
00260         items[cx][cy].push_front(item);
00261         item->setExtFlag(Item::EXT_INCURMAP);
00262 
00263         Egg* egg = p_dynamic_cast<Egg*>(item);
00264         if (egg) {
00265                 EggHatcherProcess* ehp = p_dynamic_cast<EggHatcherProcess*>(Kernel::get_instance()->getProcess(egghatcher));
00266                 assert(ehp);
00267                 ehp->addEgg(egg);
00268         }
00269 }
00270 
00271 void CurrentMap::addItemToEnd(Item* item)
00272 {
00273         sint32 ix, iy, iz;
00274 
00275         item->getLocation(ix, iy, iz);
00276 
00277         if (ix < 0 || ix >= mapChunkSize*MAP_NUM_CHUNKS || 
00278                 iy < 0 || iy >= mapChunkSize*MAP_NUM_CHUNKS) {
00279                 perr << "Skipping item " << item->getObjId() << ": out of range (" 
00280                          << ix << "," << iy << ")" << std::endl;
00281                 return;
00282         }
00283 
00284         sint32 cx = ix / mapChunkSize;
00285         sint32 cy = iy / mapChunkSize;
00286 
00287         items[cx][cy].push_back(item);
00288         item->setExtFlag(Item::EXT_INCURMAP);
00289 
00290         Egg* egg = p_dynamic_cast<Egg*>(item);
00291         if (egg) {
00292                 EggHatcherProcess* ehp = p_dynamic_cast<EggHatcherProcess*>(Kernel::get_instance()->getProcess(egghatcher));
00293                 assert(ehp);
00294                 ehp->addEgg(egg);
00295         }
00296 }
00297 
00298 void CurrentMap::removeItem(Item* item)
00299 {
00300         sint32 ix, iy, iz;
00301 
00302         item->getLocation(ix, iy, iz);
00303 
00304         removeItemFromList(item, ix, iy);
00305 }
00306 
00307 
00308 void CurrentMap::removeItemFromList(Item* item, sint32 oldx, sint32 oldy)
00309 {
00311         // if it's really a problem we could change the item lists into sets
00312         // or something, but let's see how it turns out
00313 
00314         if (oldx < 0 || oldx >= mapChunkSize*MAP_NUM_CHUNKS || 
00315                 oldy < 0 || oldy >= mapChunkSize*MAP_NUM_CHUNKS) {
00316                 perr << "Skipping item " << item->getObjId() << ": out of range (" 
00317                          << oldx << "," << oldy << ")" << std::endl;
00318                 return;
00319         }
00320 
00321         sint32 cx = oldx / mapChunkSize;
00322         sint32 cy = oldy / mapChunkSize;
00323 
00324         items[cx][cy].remove(item);
00325         item->clearExtFlag(Item::EXT_INCURMAP);
00326 }
00327 
00328 // Check to see if the chunk is on the screen 
00329 static inline bool ChunkOnScreen(sint32 cx, sint32 cy, sint32 sleft, sint32 stop, sint32 sright, sint32 sbot, int mapChunkSize)
00330 {
00331         sint32 scx = (cx*mapChunkSize - cy*mapChunkSize)/4;
00332         sint32 scy = ((cx*mapChunkSize + cy*mapChunkSize)/8);
00333 
00334         // Screenspace bounding box left extent    (LNT x coord)
00335         sint32 cxleft = scx-mapChunkSize/4;
00336         // Screenspace bounding box right extent   (RFT x coord)
00337         sint32 cxright= scx+mapChunkSize/4;
00338 
00339         // Screenspace bounding box top extent     (LFT y coord)
00340         sint32 cytop = scy - 256;
00341         // Screenspace bounding box bottom extent  (RNB y coord)
00342         sint32 cybot = scy + 128;
00343 
00344         const bool right_clear = cxright <= sleft;
00345         const bool left_clear = cxleft >= sright;
00346         const bool top_clear = cytop >= sbot;
00347         const bool bot_clear = cybot <= stop;
00348 
00349         const bool clear = right_clear|left_clear|top_clear|bot_clear;
00350 
00351         return !clear;
00352 }
00353 
00354 static inline void CalcFastAreaLimits( sint32 &sx_limit, 
00355                                                                                 sint32 &sy_limit, 
00356                                                                                 sint32 &xy_limit,
00357                                                                                 const Pentagram::Rect &dims)
00358 {
00359         // By default the fastArea is the screensize plus a border of no more
00360         // than 256 pixels wide and 384 pixels high
00361         // dims.w and dims.h need to be divided by 2 for crusader
00362         sx_limit = dims.w/256 + 3;
00363         sy_limit = dims.h/128 + 7;
00364         xy_limit = (sy_limit+sx_limit)/2;
00365 }
00366 
00367 void CurrentMap::updateFastArea(sint32 from_x, sint32 from_y, sint32 from_z, sint32 to_x, sint32 to_y, sint32 to_z)
00368 {
00369         int x_min = from_x;
00370         int x_max = to_x;
00371 
00372         if (x_max < x_min)  {
00373                 x_min = to_x;
00374                 x_max = from_x;
00375         }
00376 
00377         int y_min = from_y;
00378         int y_max = to_y;
00379 
00380         if (y_max < y_min)  {
00381                 y_min = to_y;
00382                 y_max = from_y;
00383         }
00384 
00385         int z_min = from_z;
00386         int z_max = to_z;
00387 
00388         if (z_max < z_min)  {
00389                 z_min = to_z;
00390                 z_max = from_z;
00391         }
00392 
00393         // Work out Fine (screenspace) Limits of chunks with half chunk border
00394         Pentagram::Rect dims;
00395         GUIApp::get_instance()->getGameMapGump()->GetDims(dims);
00396 
00397         sint32 sleft  = ((x_min - y_min)/4)         - (dims.w/2 + mapChunkSize/4);
00398         sint32 stop   = ((x_min + y_min)/8 - z_max) - (dims.h/2 + mapChunkSize/8);
00399         sint32 sright = ((x_max - y_max)/4)         + (dims.w/2 + mapChunkSize/4);
00400         sint32 sbot   = ((x_max + y_max)/8 - z_min) + (dims.h/2 + mapChunkSize/8);
00401 
00402         // Don't do anything IF the regions are the same
00403         if (fast_x_min == sleft && fast_y_min == stop &&
00404                 fast_x_max == sright && fast_y_max == sbot )
00405                 return;
00406 
00407         // Update the saved region
00408         fast_x_min = sleft;
00409         fast_y_min = stop;
00410         fast_x_max = sright;
00411         fast_y_max = sbot;
00412 
00413         // Get Coarse Limits
00414         sint32 sx_limit;
00415         sint32 sy_limit;
00416         sint32 xy_limit;
00417 
00418         CalcFastAreaLimits(sx_limit, sy_limit, xy_limit, dims);
00419 
00420         x_min = x_min/mapChunkSize - xy_limit;
00421         x_max = x_max/mapChunkSize + xy_limit;
00422         y_min = y_min/mapChunkSize - xy_limit;
00423         y_max = y_max/mapChunkSize + xy_limit;
00424 
00425         for (sint32 cy = 0; cy < MAP_NUM_CHUNKS; cy++) {
00426                 for (sint32 cx = 0; cx < MAP_NUM_CHUNKS; cx++) {
00427 
00428                         // Coarse
00429                         bool want_fast = cx>=x_min && cx<=x_max && cy>=y_min && cy<=y_max;
00430 
00431                         // Fine
00432                         if (want_fast) want_fast = ChunkOnScreen(cx,cy,sleft,stop,sright,sbot,mapChunkSize);
00433 
00434                         bool currently_fast = isChunkFast(cx,cy);
00435 
00436                         // Don't do anything, they are the same
00437                         if (want_fast == currently_fast) continue;
00438 
00439                         // leave fast area
00440                         if (!want_fast) unsetChunkFast(cx,cy);
00441                         // Enter fast area
00442                         else setChunkFast(cx,cy);
00443                 }
00444         }
00445 }
00446 
00447 void CurrentMap::setChunkFast(sint32 cx, sint32 cy)
00448 {
00449         fast[cy][cx/32] |= 1<<(cx&31);
00450 
00451         item_list::iterator iter;
00452         for (iter = items[cx][cy].begin();
00453                         iter != items[cx][cy].end(); ++iter) {
00454                                 (*iter)->enterFastArea();
00455                         }
00456 }
00457 
00458 void CurrentMap::unsetChunkFast(sint32 cx, sint32 cy)
00459 {
00460         fast[cy][cx/32] &= ~(1<<(cx&31));
00461 
00462         item_list::iterator iter = items[cx][cy].begin();
00463         while (iter != items[cx][cy].end())
00464         {
00465                 Item* item = *iter;
00466                 ++iter;
00467                 item->leaveFastArea();  // Can destroy the item
00468         }
00469 }
00470 
00471 void CurrentMap::areaSearch(UCList* itemlist, const uint8* loopscript,
00472                                                         uint32 scriptsize, Item* check, uint16 range,
00473                                                         bool recurse, sint32 x, sint32 y)
00474 {
00475         sint32 z;
00476         sint32 xd = 0, yd = 0, zd = 0;
00477 
00478         // if item != 0, search an area around item. Otherwise, search an area
00479         // around (x,y)
00480         if (check) {
00481                 check->getLocationAbsolute(x,y,z);
00482                 check->getFootpadWorld(xd,yd,zd);
00483         }
00484 
00485         Rect searchrange(x-xd-range,y-yd-range,2*range+xd,2*range+yd);
00486 
00487         int minx, miny, maxx, maxy;
00488 
00489         minx = ((x-xd-range)/mapChunkSize) - 1;
00490         maxx = ((x+range)/mapChunkSize) + 1;
00491         miny = ((y-yd-range)/mapChunkSize) - 1;
00492         maxy = ((y+range)/mapChunkSize) + 1;
00493         if (minx < 0) minx = 0;
00494         if (maxx >= MAP_NUM_CHUNKS) maxx = MAP_NUM_CHUNKS-1;
00495         if (miny < 0) miny = 0;
00496         if (maxy >= MAP_NUM_CHUNKS) maxy = MAP_NUM_CHUNKS-1;
00497 
00498         for (int cx = minx; cx <= maxx; cx++) {
00499                 for (int cy = miny; cy <= maxy; cy++) {
00500                         item_list::iterator iter;
00501                         for (iter = items[cx][cy].begin();
00502                                  iter != items[cx][cy].end(); ++iter) {
00503 
00504                                 Item* item = *iter;
00505 
00506                                 if (item->getExtFlags() & Item::EXT_SPRITE) continue;
00507 
00508                                 // check if item is in range?
00509                                 sint32 ix, iy, iz;
00510                                 item->getLocation(ix, iy, iz);
00511 
00512                                 ShapeInfo* info = item->getShapeInfo();
00513                                 sint32 ixd, iyd;
00514 
00516                                 if (item->getFlags() & Item::FLG_FLIPPED) {
00517                                         ixd = 32 * info->y;
00518                                         iyd = 32 * info->x;
00519                                 } else {
00520                                         ixd = 32 * info->x;
00521                                         iyd = 32 * info->y;
00522                                 }
00523 
00524                                 Rect itemrect(ix - ixd, iy - iyd, ixd, iyd);
00525 
00526                                 if (!itemrect.Overlaps(searchrange)) continue;
00527                                 
00528                                 // check item against loopscript
00529                                 if ((*iter)->checkLoopScript(loopscript, scriptsize)) {
00530                                         uint16 objid = (*iter)->getObjId();
00531                                         uint8 buf[2];
00532                                         buf[0] = static_cast<uint8>(objid);
00533                                         buf[1] = static_cast<uint8>(objid >> 8);
00534                                         itemlist->append(buf);                          
00535                                 }
00536 
00537                                 if (recurse) {
00538                                         // recurse into child-containers
00539                                         Container *container = p_dynamic_cast<Container*>(*iter);
00540                                         if (container)
00541                                                 container->containerSearch(itemlist, loopscript,
00542                                                                                                    scriptsize, recurse);
00543                                 }
00544                         }
00545                 }
00546         }
00547 }
00548 
00549 void CurrentMap::surfaceSearch(UCList* itemlist, const uint8* loopscript,
00550                                         uint32 scriptsize, Item* check, bool above, bool below,
00551                                         bool recurse)
00552 {
00553         sint32 origin[3];
00554         sint32 dims[3];
00555         check->getLocationAbsolute(origin[0], origin[1], origin[2]);
00556         check->getFootpadWorld(dims[0], dims[1], dims[2]);
00557         surfaceSearch(itemlist, loopscript, scriptsize, check->getObjId(),
00558                                 origin, dims, above, below, recurse);
00559 }
00560 
00561 void CurrentMap::surfaceSearch(UCList* itemlist, const uint8* loopscript,
00562                                         uint32 scriptsize, ObjId check,
00563                                         sint32 origin[3], sint32 dims[3],
00564                                         bool above, bool below, bool recurse)
00565 {
00566         Rect searchrange(origin[0] - dims[0], origin[1] - dims[1],
00567                                         dims[0], dims[1]);
00568 
00569         sint32 minx, miny, maxx, maxy;
00570 
00571         minx = ((origin[0] - dims[0])/mapChunkSize) - 1;
00572         maxx = ((origin[0])/mapChunkSize) + 1;
00573         miny = ((origin[1] - dims[1])/mapChunkSize) - 1;
00574         maxy = ((origin[1])/mapChunkSize) + 1;
00575         if (minx < 0) minx = 0;
00576         if (maxx >= MAP_NUM_CHUNKS) maxx = MAP_NUM_CHUNKS-1;
00577         if (miny < 0) miny = 0;
00578         if (maxy >= MAP_NUM_CHUNKS) maxy = MAP_NUM_CHUNKS-1;
00579 
00580         for (sint32 cx = minx; cx <= maxx; cx++) {
00581                 for (sint32 cy = miny; cy <= maxy; cy++) {
00582                         item_list::iterator iter;
00583                         for (iter = items[cx][cy].begin();
00584                                  iter != items[cx][cy].end(); ++iter) {
00585 
00586                                 Item* item = *iter;
00587 
00588                                 if (item->getObjId() == check) continue;
00589                                 if (item->getExtFlags() & Item::EXT_SPRITE) continue;
00590 
00591                                 // check if item is in range?
00592                                 sint32 ix, iy, iz;
00593                                 item->getLocation(ix, iy, iz);
00594                                 sint32 ixd, iyd, izd;
00595                                 item->getFootpadWorld(ixd, iyd, izd);
00596 
00597                                 Rect itemrect(ix - ixd, iy - iyd, ixd, iyd);
00598 
00599                                 if (!itemrect.Overlaps(searchrange)) continue;
00600 
00601                                 bool ok = false;
00602                                 
00603                                 if (above && iz == (origin[2] + dims[2]))
00604                                 {
00605                                         ok = true;
00606                                         // Only recursive if tops aren't same (i.e. NOT flat)
00607                                         if (recurse && (izd+iz != origin[2] + dims[2]) )
00608                                                 surfaceSearch(itemlist, loopscript, scriptsize, item, true, false, true);
00609                                 }
00610                                 
00611                                 if (below && origin[2] == (iz + izd))
00612                                 {
00613                                         ok = true;
00614                                         // Only recursive if bottoms aren't same (i.e. NOT flat)
00615                                         if (recurse && (izd != dims[2]) )
00616                                                 surfaceSearch(itemlist, loopscript, scriptsize, item, false, true, true);
00617                                 }
00618 
00619                                 if (!ok) continue;
00620 
00621                                 // check item against loopscript
00622                                 if ((*iter)->checkLoopScript(loopscript, scriptsize)) {
00623                                         uint16 objid = (*iter)->getObjId();
00624                                         uint8 buf[2];
00625                                         buf[0] = static_cast<uint8>(objid);
00626                                         buf[1] = static_cast<uint8>(objid >> 8);
00627                                         itemlist->append(buf);
00628                                 }
00629                         }
00630                 }
00631         }
00632 }
00633 
00634 TeleportEgg* CurrentMap::findDestination(uint16 id)
00635 {
00636         for (unsigned int i = 0; i < MAP_NUM_CHUNKS; i++) {
00637                 for (unsigned int j = 0; j < MAP_NUM_CHUNKS; j++) {
00638                         item_list::iterator iter;
00639                         for (iter = items[i][j].begin();
00640                                  iter != items[i][j].end(); ++iter)
00641                         {
00642                                 TeleportEgg* egg = p_dynamic_cast<TeleportEgg*>(*iter);
00643                                 if (egg) {
00644                                         if (!egg->isTeleporter() && egg->getTeleportId() == id)
00645                                                 return egg;
00646                                 }
00647                         }
00648                 }
00649         }
00650         return 0;
00651 }
00652 
00653 bool CurrentMap::isValidPosition(sint32 x, sint32 y, sint32 z,
00654                                                                  uint32 shape,
00655                                                                  ObjId item, Item** support, uint16* roof)
00656 {
00657         int xd, yd, zd;
00658         ShapeInfo* si = GameData::get_instance()->
00659                 getMainShapes()->getShapeInfo(shape);
00661         xd = si->x * 32;
00662         yd = si->y * 32;
00663         zd = si->z * 8;
00664 
00665         return isValidPosition(x,y,z,
00666                                                    INT_MAX/2,INT_MAX/2,INT_MAX/2,
00667                                                    xd,yd,zd,
00668                                                    si->flags, item, support, roof);
00669 }
00670 
00671 bool CurrentMap::isValidPosition(sint32 x, sint32 y, sint32 z,
00672                                                                  int xd, int yd, int zd,
00673                                                                  uint32 shapeflags,
00674                                                                  ObjId item_, Item** support_, uint16* roof_)
00675 {
00676         return isValidPosition(x,y,z,
00677                                                    INT_MAX/2,INT_MAX/2,INT_MAX/2,
00678                                                    xd,yd,zd,
00679                                                    shapeflags,item_,support_,roof_);
00680 }
00681 
00682 
00683 bool CurrentMap::isValidPosition(sint32 x, sint32 y, sint32 z,
00684                                                                  sint32 startx, sint32 starty, sint32 startz,
00685                                                                  int xd, int yd, int zd,
00686                                                                  uint32 shapeflags,
00687                                                                  ObjId item_, Item** support_, uint16* roof_)
00688 {
00689         const uint32 flagmask = (ShapeInfo::SI_SOLID | ShapeInfo::SI_DAMAGING |
00690                                                          ShapeInfo::SI_ROOF);
00691         const uint32 blockflagmask = (ShapeInfo::SI_SOLID|ShapeInfo::SI_DAMAGING);
00692 
00693         bool valid = true;
00694         Item* support = 0;
00695         ObjId roof = 0;
00696         sint32 roofz = 1 << 24; 
00697 
00698         int minx, miny, maxx, maxy;
00699 
00700         minx = ((x-xd)/mapChunkSize) - 1;
00701         maxx = (x/mapChunkSize) + 1;
00702         miny = ((y-yd)/mapChunkSize) - 1;
00703         maxy = (y/mapChunkSize) + 1;
00704         if (minx < 0) minx = 0;
00705         if (maxx >= MAP_NUM_CHUNKS) maxx = MAP_NUM_CHUNKS-1;
00706         if (miny < 0) miny = 0;
00707         if (maxy >= MAP_NUM_CHUNKS) maxy = MAP_NUM_CHUNKS-1;
00708 
00709         for (int cx = minx; cx <= maxx; cx++) {
00710                 for (int cy = miny; cy <= maxy; cy++) {
00711                         item_list::iterator iter;
00712                         for (iter = items[cx][cy].begin();
00713                                  iter != items[cx][cy].end(); ++iter)
00714                         {
00715                                 Item* item = *iter;
00716                                 if (item->getObjId() == item_) continue;
00717                                 if (item->getExtFlags() & Item::EXT_SPRITE) continue;
00718 
00719                                 ShapeInfo* si = item->getShapeInfo();
00721                                 if (!(si->flags & flagmask))
00722                                         continue; // not an interesting item
00723 
00724                                 sint32 ix, iy, iz, ixd, iyd, izd;
00725                                 si->getFootpadWorld(ixd, iyd, izd, item->getFlags() & Item::FLG_FLIPPED);
00726                                 item->getLocation(ix, iy, iz);
00727 
00728 #if 0
00729                                 if (item->getShape() == 145) {
00730                                         perr << "Shape 145: (" << ix-ixd << "," << iy-iyd << ","
00731                                                  << iz << ")-(" << ix << "," << iy << "," << iz+izd
00732                                                  << ")" << std::endl;
00733                                         if (!si->is_solid()) perr << "not solid" << std::endl;
00734                                 }
00735 #endif
00736 
00737                                 // check overlap
00738                                 if ((si->flags & shapeflags & blockflagmask) &&
00739                                         /* not non-overlapping */
00740                                         !(x <= ix - ixd || x - xd >= ix ||
00741                                           y <= iy - iyd || y - yd >= iy ||
00742                                           z + zd <= iz || z >= iz + izd) &&
00743                                         /* non-overlapping start position */
00744                                         (startx <= ix - ixd || startx - xd >= ix ||
00745                                          starty <= iy - iyd || starty - yd >= iy ||
00746                                          startz + zd <= iz || startz >= iz + izd))
00747                                 {
00748                                         // overlapping an item. Invalid position
00749 #if 0
00750                                         item->dumpInfo();
00751 #endif                                  
00752                                         valid = false;
00753                                 }
00754 
00755                                 // check xy overlap
00756                                 if (!(x <= ix - ixd || x - xd >= ix ||
00757                                           y <= iy - iyd || y - yd >= iy))
00758                                 {
00759                                         // check support
00760                                         if (support == 0 && si->is_solid() &&
00761                                                 iz + izd == z)
00762                                         {
00763                                                 support = item;
00764                                         }
00765 
00766                                         // check roof
00767                                         if (si->is_roof() && iz < roofz && iz >= z + zd) {
00768                                                 roof = item->getObjId();
00769                                                 roofz = iz;
00770                                         }
00771                                 }
00772                         }
00773                 }
00774         }
00775 
00776         if (support_)
00777                 *support_ = support;
00778         if (roof_)
00779                 *roof_ = roof;
00780 
00781         return valid;
00782 }
00783 
00784 bool CurrentMap::scanForValidPosition(sint32 x, sint32 y, sint32 z, Item* item,
00785                                                                           int movedir, bool wantsupport,
00786                                                                           sint32& tx, sint32& ty, sint32& tz)
00787 {
00788         // TODO: clean this up. Currently the mask arrays are filled with more
00789         // data than is actually used.
00790 
00791         uint32 blockflagmask = (ShapeInfo::SI_SOLID | ShapeInfo::SI_DAMAGING);
00792         static uint32 validmask[17];
00793         static uint32 supportmask[17];
00794 
00795         int searchdir = (movedir + 2) % 4;
00796 
00797         int xdir = (x_fact[searchdir] != 0) ? 1 : 0;
00798         int ydir = (y_fact[searchdir] != 0) ? 1 : 0;
00799 
00800         // mark everything as valid, but without support
00801         for (int i = 0; i < 17; ++i) {
00802                 validmask[i] = 0x1FFFF;
00803                 supportmask[i] = 0;
00804         }
00805 
00806         blockflagmask &= item->getShapeInfo()->flags;
00807 
00808         sint32 xd,yd,zd;
00809         item->getFootpadWorld(xd, yd, zd);      
00810 
00811         // Note on scan direction:
00812         // The 'horiz' variable below will always mean a direction in
00813         // the positive  x/y directions, with the exception of searchdir 1,
00814         // in which case positive horiz points in the (positive x, negative y)
00815         // direction.
00816 
00817 
00818         // next, we'll loop over all objects in the area, and mark the areas
00819         // overlapped and supported by each object
00820 
00821         int minx, miny, maxx, maxy;
00822 
00823         minx = ((x-xd)/mapChunkSize) - 1;
00824         maxx = (x/mapChunkSize) + 1;
00825         miny = ((y-yd)/mapChunkSize) - 1;
00826         maxy = (y/mapChunkSize) + 1;
00827         if (minx < 0) minx = 0;
00828         if (maxx >= MAP_NUM_CHUNKS) maxx = MAP_NUM_CHUNKS-1;
00829         if (miny < 0) miny = 0;
00830         if (maxy >= MAP_NUM_CHUNKS) maxy = MAP_NUM_CHUNKS-1;
00831 
00832         for (int cx = minx; cx <= maxx; cx++) {
00833                 for (int cy = miny; cy <= maxy; cy++) {
00834                         item_list::iterator iter;
00835                         for (iter = items[cx][cy].begin();
00836                                  iter != items[cx][cy].end(); ++iter)
00837                         {
00838                                 Item* citem = *iter;
00839                                 if (citem->getObjId() == item->getObjId()) continue;
00840                                 if (citem->getExtFlags() & Item::EXT_SPRITE) continue;
00841 
00842                                 ShapeInfo* si = citem->getShapeInfo();
00844                                 if (!(si->flags & blockflagmask))
00845                                         continue; // not an interesting item
00846 
00847                                 sint32 ix, iy, iz, ixd, iyd, izd;
00848                                 citem->getLocation(ix, iy, iz);
00849                                 citem->getFootpadWorld(ixd, iyd, izd);
00850 
00851                                 int minv = iz-z-zd+1;
00852                                 int maxv = iz+izd-z-1;
00853                                 if (minv < -8) minv = -8;
00854                                 if (maxv > 8) maxv = 8;
00855 
00856                                 int sminx,smaxx,sminy,smaxy;
00857                                 sminx = ix-ixd+1 -x;
00858                                 smaxx = ix+xd-1  -x;
00859                                 sminy = iy-iyd+1 -y;
00860                                 smaxy = iy+yd-1  -y;
00861 
00862                                 int minh = -100;
00863                                 int maxh = 100;
00864                                 if (!xdir && (sminx > 0 || smaxx < 0)) continue;
00865                                 if (!ydir && (sminy > 0 || smaxy < 0)) continue;
00866 
00867                                 if (xdir && minh < sminx)
00868                                         minh = sminx;
00869                                 if (xdir && maxh > smaxx)
00870                                         maxh = smaxx;
00871                                 if ((ydir && searchdir != 1) && minh < sminy)
00872                                         minh = sminy;
00873                                 if ((ydir && searchdir != 1) && maxh > smaxy)
00874                                         maxh = smaxy;
00875                                 if (searchdir == 1 && minh < -smaxy)
00876                                         minh = -smaxy;
00877                                 if (searchdir == 1 && maxh > -sminy)
00878                                         maxh = -sminy;
00879                                 
00880                                 if (minh < -8) minh = -8;
00881                                 if (maxh > 8) maxh = 8;
00882 
00883                                 for (int j = minv; j <= maxv; ++j)
00884                                         for (int i = minh; i <= maxh; ++i)
00885                                                 validmask[j+8] &= ~(1 << (i+8));
00886 
00887                                 if (wantsupport && si->is_solid() &&
00888                                         iz+izd >= z-8 && iz+izd <= z+8)
00889                                 {
00890                                         for (int i = minh; i <= maxh; ++i)
00891                                                 supportmask[iz+izd-z+8] |= (1 << (i+8));
00892 
00893                                 }
00894                         }
00895                 }
00896         }
00897 
00898         bool foundunsupported = false;
00899 
00900 #if 0
00901         for (unsigned int i = 0; i < 17; ++i) {
00902                 pout.printf("%05x | %05x\n", validmask[16-i], supportmask[16-i]);
00903         }
00904         pout.printf("-----------\n");
00905 #endif
00906 
00907         for (unsigned int i = 0; i < 3; ++i) {
00908                 int horiz;
00909                 if (i % 2 == 0)
00910                         horiz = 4*(i/2);
00911                 else
00912                         horiz = -4 - 4*(i/2);
00913                 
00914                 for (unsigned int j = 0; j < 5; ++j) {
00915                         int vert;
00916                         if (j % 2 == 0)
00917                                 vert = 4*(j/2);
00918                         else
00919                                 vert = -4 - 4*(j/2);
00920 
00921                         if (validmask[vert+8] & (1<<(horiz+8))) {
00922                                 if (!wantsupport || !foundunsupported || 
00923                                         (supportmask[vert+8] & (1<<(horiz+8))))
00924                                 {
00925                                         tz = z + vert;
00926                                         tx = x;
00927                                         if (searchdir != 0)
00928                                                 tx += horiz;
00929                                         ty = y;
00930                                         if (searchdir == 1) 
00931                                                 ty -= horiz;
00932                                         else if (searchdir != 2)
00933                                                 ty += horiz;
00934                                 }
00935                                 if (!wantsupport || (supportmask[vert+8] & (1<<(horiz+8))))
00936                                         return true;
00937                                 foundunsupported = true;
00938                         }
00939                 }
00940         }
00941 
00942         // no supported location found, so return unsupported unblocked one
00943         if (foundunsupported)
00944                 return true;
00945 
00946         return false;
00947 }
00948 
00949 
00950 // Do a sweepTest of an item from start to end point.
00951 // dims is the bounding box size.
00952 // item is the item that we are checking to move
00953 // blocking_only forces us to check against blocking items only.
00954 // skip will skip all items until item num skip is reached
00955 // Returns item hit or 0 if no hit.
00956 // end is set to the colision point
00957 bool CurrentMap::sweepTest(const sint32 start[3], const sint32 end[3],
00958                                                    const sint32 dims[3], uint32 shapeflags,
00959                                                    ObjId item, bool blocking_only,
00960                                                    std::list<SweepItem> *hit)
00961 {
00962         const uint32 blockflagmask = (ShapeInfo::SI_SOLID|ShapeInfo::SI_DAMAGING);
00963 
00964         int i;
00965 
00966         int minx, miny, maxx, maxy;
00967         minx = ((start[0]-dims[0])/mapChunkSize) - 1;
00968         maxx = (start[0]/mapChunkSize) + 1;
00969         miny = ((start[1]-dims[1])/mapChunkSize) - 1;
00970         maxy = (start[1]/mapChunkSize) + 1;
00971 
00972         {
00973                 int dminx, dminy, dmaxx, dmaxy;
00974                 dminx = ((end[0]-dims[0])/mapChunkSize) - 1;
00975                 dmaxx = (end[0]/mapChunkSize) + 1;
00976                 dminy = ((end[1]-dims[1])/mapChunkSize) - 1;
00977                 dmaxy = (end[1]/mapChunkSize) + 1;
00978                 if (dminx < minx) minx = dminx;
00979                 if (dmaxx > maxx) maxx = dmaxx;
00980                 if (dminy < miny) miny = dminy;
00981                 if (dmaxy > maxy) maxy = dmaxy;
00982         }
00983 
00984         if (minx < 0) minx = 0;
00985         if (maxx >= MAP_NUM_CHUNKS) maxx = MAP_NUM_CHUNKS-1;
00986         if (miny < 0) miny = 0;
00987         if (maxy >= MAP_NUM_CHUNKS) maxy = MAP_NUM_CHUNKS-1;
00988 
00989         // Get velocity of item
00990         sint32 vel[3];
00991         sint32 ext[3];
00992         for (i = 0; i < 3; i++) 
00993         {
00994                 vel[i] = end[i] - start[i];
00995                 ext[i] = dims[i]/2;
00996         }
00997 
00998         // Centre of object
00999         sint32 centre[3];
01000         centre[0] = start[0] - ext[0];
01001         centre[1] = start[1] - ext[1];
01002         centre[2] = start[2] + ext[2];
01003 
01004 //      pout << "Sweeping from (" << -ext[0] << ", " << -ext[1] << ", " << -ext[2] << ")" << std::endl;
01005 //      pout << "              (" << ext[0] << ", " << ext[1] << ", " << ext[2] << ")" << std::endl;
01006 //      pout << "Sweeping to   (" << vel[0]-ext[0] << ", " << vel[1]-ext[1] << ", " << vel[2]-ext[2] << ")" << std::endl;
01007 //      pout << "              (" << vel[0]+ext[0] << ", " << vel[1]+ext[1] << ", " << vel[2]+ext[2] << ")" << std::endl;
01008 
01009         std::list<SweepItem>::iterator sw_it;
01010         if (hit) sw_it = hit->end();
01011 
01012         for (int cx = minx; cx <= maxx; cx++) {
01013                 for (int cy = miny; cy <= maxy; cy++) {
01014                         item_list::iterator iter;
01015                         for (iter = items[cx][cy].begin();
01016                                  iter != items[cx][cy].end(); ++iter)
01017                         {
01018                                 Item* other_item = *iter;
01019                                 if (other_item->getObjId()==item) continue;
01020                                 if (other_item->getExtFlags() & Item::EXT_SPRITE) continue;
01021 
01022                                 uint32 othershapeflags = other_item->getShapeInfo()->flags;
01023                                 bool blocking = (othershapeflags & shapeflags &
01024                                                                  blockflagmask) != 0;
01025 
01026                                 // This WILL hit everything and return them unless
01027                                 // blocking_only is set
01028                                 if (blocking_only && !blocking)
01029                                         continue;
01030 
01031                                 sint32 other[3], oext[3];
01032                                 other_item->getLocation(other[0], other[1], other[2]);
01033                                 other_item->getFootpadWorld(oext[0], oext[1], oext[2]);
01034 
01035                                 // If the objects overlapped at the start, ignore collision.
01036                                 // The -1 and +1 portions are to still consider collisions
01037                                 // for items which were merely touching at the start for all
01038                                 // intents and purposes, but partially overlapped due to an
01039                                 // off-by-one error (hypothetically, but they do happen so
01040                                 // protect against it).
01041                                 if(/* not non-overlapping start position */
01042                                    !(start[0] <= other[0] - (oext[0]-1) ||
01043                                          start[0] - dims[0] >= other[0]-1 ||
01044                                          start[1] <= other[1] - (oext[1]-1) ||
01045                                          start[1] - dims[1] >= other[1]-1 ||
01046                                          start[2] + dims[2] <= other[2]+1 ||
01047                                          start[2] >= other[2] + (oext[2]-1)))
01048                                 {
01049                                         // Overlapped at the start, and not just touching so
01050                                         // ignore collision
01051                                         continue;
01052                                 }
01053 
01054                                 oext[0] /= 2; oext[1] /= 2; oext[2] /= 2;
01055 
01056                                 // Put other into our coord frame
01057                                 other[0] -= oext[0]+centre[0];
01058                                 other[1] -= oext[1]+centre[1];
01059                                 other[2] += oext[2]-centre[2];
01060 
01061                                 //first times of overlap along each axis
01062                                 sint32 u_1[3] = {0,0,0};
01063 
01064                                 //last times of overlap along each axis 
01065                                 sint32 u_0[3] = {0x4000,0x4000,0x4000}; // CONSTANTS
01066 
01067                                 bool touch = false;
01068                                 bool touch_floor = false;
01069 
01070                                 //find the possible first and last times
01071                                 //of overlap along each axis
01072                                 for( long i=0 ; i<3 ; i++ )
01073                                 {
01074                                         sint32 A_max = ext[i];  
01075                                         sint32 A_min = -ext[i]; 
01076                                         sint32 B_max = other[i]+oext[i];        
01077                                         sint32 B_min = other[i]-oext[i];        
01078 
01079                                         if ( vel[i] < 0 && A_max>=B_min )               // A_max>=B_min not required
01080                                         {
01081                                                 // Special case: if moving item has zero height and
01082                                                 // other item is a 128x128 flat, then moving item is
01083                                                 // considered blocked by the flat
01084                                                 // FIXME: it might be better to make this extra check
01085                                                 // identical to the 'flats' special case in ItemSorter
01086                                                 if (A_max==B_min && !
01087                                                         (i == 2 && ext[i] == 0 && oext[i] == 0 &&
01088                                                          oext[0] == 64 && oext[1] == 64))
01089                                                         touch = true; // touch at start
01090                                                 if (A_min+vel[i]==B_max) touch = true; // touch at end
01091 
01092                                                 // - want to know when rear of A passes front of B
01093                                                 u_0[i] = ((B_max - A_min)*0x4000) / vel[i];
01094                                                 // - want to know when front of A passes rear of B
01095                                                 u_1[i] = ((B_min - A_max)*0x4000) / vel[i]; 
01096                                         }
01097                                         else if( vel[i] > 0 && A_min<=B_max)    // A_min<=B_max not required
01098                                         {
01099                                                 if (A_min==B_max) touch = true; // touch at start
01100                                                 if (A_max-vel[i]==B_min) touch = true; // touch at end
01101 
01102                                                 // + want to know when front of A passes rear of B
01103                                                 u_0[i] = ((B_min - A_max)*0x4000) / vel[i];
01104                                                 // + want to know when rear of A passes front of B
01105                                                 u_1[i] = ((B_max - A_min)*0x4000) / vel[i]; 
01106                                         }
01107                                         else if( vel[i] == 0 && A_max >= B_min && A_min <= B_max)
01108                                         {
01109                                                 if (A_min==B_max || A_max==B_min) touch = true;
01110                                                 if (i == 2 && A_min == B_max) touch_floor = true;
01111 
01112                                                 u_0[i] = -1;
01113                                                 u_1[i] = 0x4000;
01114                                         }
01115                                         else
01116                                         {
01117                                                 u_0[i] = 0x4001;
01118                                                 u_1[i] = -1;
01119                                         }
01120 
01121                                         if (u_1[i] >= u_0[i] && (u_0[i] > 0x4000 || u_1[i] < 0))
01122                                         {
01123                                                 u_0[i] = 0x4001;
01124                                                 u_1[i] = -1;
01125                                         }
01126                                 }
01127 
01128                                 //possible first time of overlap
01129                                 sint32 first = u_0[0];
01130                                 if (u_0[1] > first) first = u_0[1];
01131                                 if (u_0[2] > first) first = u_0[2];
01132 
01133                                 //possible last time of overlap
01134                                 sint32 last = u_1[0];
01135                                 if (u_1[1] < last) last = u_1[1];
01136                                 if (u_1[2] < last) last = u_1[2];
01137 
01138                                 //they could have only collided if
01139                                 //the first time of overlap occurred
01140                                 //before the last time of overlap
01141                                 if (first <= last)
01142                                 {
01143                                         //pout << "Hit item " << other_item->getObjId() << " at first: " << first << "  last: " << last << std::endl;
01144 
01145                                         if (!hit) return true;
01146 
01147                                         // Clamp
01148                                         if (first < -1) first = -1;
01149                                         if (last > 0x4000) last = 0x4000;
01150 
01151                                         // Ok, what we want to do here is add to the list.
01152                                         // Sorted by hit_time. 
01153 
01154                                         // Small speed up.
01155                                         if (sw_it != hit->end())
01156                                         {
01157                                                 SweepItem &si = *sw_it;
01158                                                 if (si.hit_time > first) sw_it = hit->begin();
01159                                         }
01160                                         else
01161                                                 sw_it = hit->begin();
01162 
01163                                         for (;sw_it != hit->end(); ++sw_it) 
01164                                                 if ((*sw_it).hit_time > first) break;
01165 
01166                                         // Now add it
01167                                         sw_it = hit->insert(sw_it, SweepItem(other_item->getObjId(),first,last,touch,touch_floor,blocking));
01168 //                                      pout << "Hit item " << other_item->getObjId() << " at (" << first << "," << last << ")" << std::endl;
01169 //                                      pout << "hit item      (" << other[0] << ", " << other[1] << ", " << other[2] << ")" << std::endl;
01170 //                                      pout << "hit item time (" << u_0[0] << "-" << u_1[0] << ") (" << u_0[1] << "-" << u_1[1] << ") ("
01171 //                                               << u_0[2] << "-" << u_1[2] << ")" << std::endl;
01172 //                                      pout << "touch: " << touch << ", floor: " << touch_floor << ", block: " << blocking << std::endl;
01173                                 }
01174                         }
01175                 }
01176         }
01177 
01178         return hit && hit->size();
01179 }
01180 
01181 
01182 Item *CurrentMap::traceTopItem(sint32 x, sint32 y, sint32 ztop, sint32 zbot, ObjId ignore, uint32 shflags)
01183 {
01184         Item* top = 0;
01185 
01186         if (ztop < zbot) {
01187                 sint32 temp = ztop;
01188                 ztop = zbot;
01189                 zbot = temp;
01190         }
01191 
01192         int minx, miny, maxx, maxy;
01193         minx = (x/mapChunkSize);
01194         maxx = (x/mapChunkSize) + 1;
01195         miny = (y/mapChunkSize);
01196         maxy = (y/mapChunkSize) + 1;
01197         if (minx < 0) minx = 0;
01198         if (maxx >= MAP_NUM_CHUNKS) maxx = MAP_NUM_CHUNKS-1;
01199         if (miny < 0) miny = 0;
01200         if (maxy >= MAP_NUM_CHUNKS) maxy = MAP_NUM_CHUNKS-1;
01201 
01202         for (int cx = minx; cx <= maxx; cx++) {
01203                 for (int cy = miny; cy <= maxy; cy++) {
01204                         item_list::iterator iter;
01205                         for (iter = items[cx][cy].begin();
01206                                  iter != items[cx][cy].end(); ++iter)
01207                         {
01208                                 Item* item = *iter;
01209                                 if (item->getObjId() == ignore) continue;
01210                                 if (item->getExtFlags() & Item::EXT_SPRITE) continue;
01211 
01212                                 ShapeInfo* si = item->getShapeInfo();
01213                                 if (!(si->flags & shflags) || si->is_editor() || si->is_translucent()) continue;
01214 
01215                                 sint32 ix, iy, iz, ixd, iyd, izd;
01216                                 item->getLocation(ix, iy, iz);
01217                                 item->getFootpadWorld(ixd, iyd, izd);
01218 
01219                                 if ((ix-ixd) >= x || ix <= x) continue;
01220                                 if ((iy-iyd) >= y || iy <= y) continue;
01221                                 if (iz >= ztop || (iz+izd) <= zbot) continue;
01222 
01223                                 if (top) {
01224                                         sint32 tix, tiy, tiz, tixd, tiyd, tizd;
01225                                         top->getLocation(tix, tiy, tiz);
01226                                         top->getFootpadWorld(tixd, tiyd, tizd);
01227 
01228                                         if ((tiz+tizd) < (iz+izd)) top = 0;
01229                                 }
01230 
01231                                 if (!top) top = item;
01232                         }
01233                 }
01234         }
01235         return top;
01236 }
01237 
01238 void CurrentMap::setWholeMapFast()
01239 {
01240         for (unsigned int i = 0; i < MAP_NUM_CHUNKS; ++i) {
01241                 for (unsigned int j = 0; j < MAP_NUM_CHUNKS; ++j) {
01242                         if (!isChunkFast(j,i)) setChunkFast(j,i);
01243                 }
01244         }
01245 }
01246 
01247 void CurrentMap::save(ODataSource* ods)
01248 {
01249         for (unsigned int i = 0; i < MAP_NUM_CHUNKS; ++i) {
01250                 for (unsigned int j = 0; j < MAP_NUM_CHUNKS/32; ++j) {
01251                         ods->write4(fast[i][j]);
01252                 }
01253         }
01254 }
01255 
01256 bool CurrentMap::load(IDataSource* ids, uint32 version)
01257 {
01258         for (unsigned int i = 0; i < MAP_NUM_CHUNKS; ++i) {
01259                 for (unsigned int j = 0; j < MAP_NUM_CHUNKS/32; ++j) {
01260                         fast[i][j] = ids->read4();
01261                 }
01262         }
01263 
01264         fast_x_min = -1;
01265         fast_y_min = -1;
01266         fast_x_max = -1;
01267         fast_y_max = -1;
01268 
01269         return true;
01270 }
01271 
01272 uint32 CurrentMap::I_canExistAt(const uint8* args, unsigned int /*argsize*/)
01273 {
01274         ARG_UINT16(shape);
01275         ARG_UINT16(x);
01276         ARG_UINT16(y);
01277         ARG_UINT16(z);
01279         ARG_UINT16(unk1); // is either 1 or 4
01280         ARG_UINT16(unk2); // looks like it could be an objid
01281         ARG_UINT16(unk3); // always zero
01282 
01283         CurrentMap* cm = World::get_instance()->getCurrentMap();
01284         bool valid = cm->isValidPosition(x, y, z, shape, 0, 0, 0);
01285 
01286         if (valid)
01287                 return 1;
01288         else
01289                 return 0;
01290 }

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