00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
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;
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
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
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
00137 item->clearExtFlag(Item::EXT_INCURMAP);
00138
00139
00140 if ((item->getFlags() & Item::FLG_FAST_ONLY) ||
00141 (item->getFlags() & Item::FLG_DISPOSABLE))
00142 {
00143 delete item;
00144 continue;
00145 }
00146
00147
00148 Egg* egg = p_dynamic_cast<Egg*>(item);
00149 if (egg) {
00150 egg->reset();
00151 }
00152
00153
00154 if (item->getFlags() & Item::FLG_IN_NPC_LIST)
00155 continue;
00156
00157 item->clearObjId();
00158 if (item->getExtFlags() & Item::EXT_FIXED) {
00159
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
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
00186 item->clearFlag(Item::FLG_FASTAREA);
00187
00188
00189 addItemToEnd(item);
00190
00191 if (callCacheIn)
00192 item->callUsecodeEvent_cachein();
00193 }
00194 }
00195
00196 void CurrentMap::loadMap(Map* map)
00197 {
00198
00199 bool callCacheIn = (current_map != 0);
00200
00201 current_map = map;
00202
00203 createEggHatcher();
00204
00205
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
00218 map->fixeditems.clear();
00219 map->dynamicitems.clear();
00220
00221
00222
00223 for (uint16 i = 0; i < 256; ++i) {
00224 Actor* actor = getActor(i);
00225 if (!actor) continue;
00226
00227
00228
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
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
00312
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
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
00335 sint32 cxleft = scx-mapChunkSize/4;
00336
00337 sint32 cxright= scx+mapChunkSize/4;
00338
00339
00340 sint32 cytop = scy - 256;
00341
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
00360
00361
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
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
00403 if (fast_x_min == sleft && fast_y_min == stop &&
00404 fast_x_max == sright && fast_y_max == sbot )
00405 return;
00406
00407
00408 fast_x_min = sleft;
00409 fast_y_min = stop;
00410 fast_x_max = sright;
00411 fast_y_max = sbot;
00412
00413
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
00429 bool want_fast = cx>=x_min && cx<=x_max && cy>=y_min && cy<=y_max;
00430
00431
00432 if (want_fast) want_fast = ChunkOnScreen(cx,cy,sleft,stop,sright,sbot,mapChunkSize);
00433
00434 bool currently_fast = isChunkFast(cx,cy);
00435
00436
00437 if (want_fast == currently_fast) continue;
00438
00439
00440 if (!want_fast) unsetChunkFast(cx,cy);
00441
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();
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
00479
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
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
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
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
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
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
00615 if (recurse && (izd != dims[2]) )
00616 surfaceSearch(itemlist, loopscript, scriptsize, item, false, true, true);
00617 }
00618
00619 if (!ok) continue;
00620
00621
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;
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
00738 if ((si->flags & shapeflags & blockflagmask) &&
00739
00740 !(x <= ix - ixd || x - xd >= ix ||
00741 y <= iy - iyd || y - yd >= iy ||
00742 z + zd <= iz || z >= iz + izd) &&
00743
00744 (startx <= ix - ixd || startx - xd >= ix ||
00745 starty <= iy - iyd || starty - yd >= iy ||
00746 startz + zd <= iz || startz >= iz + izd))
00747 {
00748
00749 #if 0
00750 item->dumpInfo();
00751 #endif
00752 valid = false;
00753 }
00754
00755
00756 if (!(x <= ix - ixd || x - xd >= ix ||
00757 y <= iy - iyd || y - yd >= iy))
00758 {
00759
00760 if (support == 0 && si->is_solid() &&
00761 iz + izd == z)
00762 {
00763 support = item;
00764 }
00765
00766
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
00789
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
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
00812
00813
00814
00815
00816
00817
00818
00819
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;
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
00943 if (foundunsupported)
00944 return true;
00945
00946 return false;
00947 }
00948
00949
00950
00951
00952
00953
00954
00955
00956
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
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
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
01005
01006
01007
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
01027
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
01036
01037
01038
01039
01040
01041 if(
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
01050
01051 continue;
01052 }
01053
01054 oext[0] /= 2; oext[1] /= 2; oext[2] /= 2;
01055
01056
01057 other[0] -= oext[0]+centre[0];
01058 other[1] -= oext[1]+centre[1];
01059 other[2] += oext[2]-centre[2];
01060
01061
01062 sint32 u_1[3] = {0,0,0};
01063
01064
01065 sint32 u_0[3] = {0x4000,0x4000,0x4000};
01066
01067 bool touch = false;
01068 bool touch_floor = false;
01069
01070
01071
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 )
01080 {
01081
01082
01083
01084
01085
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;
01090 if (A_min+vel[i]==B_max) touch = true;
01091
01092
01093 u_0[i] = ((B_max - A_min)*0x4000) / vel[i];
01094
01095 u_1[i] = ((B_min - A_max)*0x4000) / vel[i];
01096 }
01097 else if( vel[i] > 0 && A_min<=B_max)
01098 {
01099 if (A_min==B_max) touch = true;
01100 if (A_max-vel[i]==B_min) touch = true;
01101
01102
01103 u_0[i] = ((B_min - A_max)*0x4000) / vel[i];
01104
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
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
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
01139
01140
01141 if (first <= last)
01142 {
01143
01144
01145 if (!hit) return true;
01146
01147
01148 if (first < -1) first = -1;
01149 if (last > 0x4000) last = 0x4000;
01150
01151
01152
01153
01154
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
01167 sw_it = hit->insert(sw_it, SweepItem(other_item->getObjId(),first,last,touch,touch_floor,blocking));
01168
01169
01170
01171
01172
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 )
01273 {
01274 ARG_UINT16(shape);
01275 ARG_UINT16(x);
01276 ARG_UINT16(y);
01277 ARG_UINT16(z);
01279 ARG_UINT16(unk1);
01280 ARG_UINT16(unk2);
01281 ARG_UINT16(unk3);
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 }