00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <algorithm>
00023 #include <cassert>
00024
00025 #include "point.h"
00026 #include "common/configuration.hpp"
00027 #include "game-server/map.hpp"
00028 #include "game-server/mapcomposite.hpp"
00029 #include "game-server/character.hpp"
00030 #include "scripting/script.hpp"
00031 #include "utils/logger.h"
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045 static int const zoneDiam = 256;
00046
00047 void MapZone::insert(Actor *obj)
00048 {
00049 int type = obj->getType();
00050 switch (type)
00051 {
00052 case OBJECT_CHARACTER:
00053 {
00054 if (nbCharacters != nbMovingObjects)
00055 {
00056 if (nbMovingObjects != objects.size())
00057 {
00058 objects.push_back(objects[nbMovingObjects]);
00059 objects[nbMovingObjects] = objects[nbCharacters];
00060 }
00061 else
00062 {
00063 objects.push_back(objects[nbCharacters]);
00064 }
00065 objects[nbCharacters] = obj;
00066 ++nbCharacters;
00067 ++nbMovingObjects;
00068 break;
00069 }
00070 ++nbCharacters;
00071 }
00072 case OBJECT_MONSTER:
00073 case OBJECT_NPC:
00074 {
00075 if (nbMovingObjects != objects.size())
00076 {
00077 objects.push_back(objects[nbMovingObjects]);
00078 objects[nbMovingObjects] = obj;
00079 ++nbMovingObjects;
00080 break;
00081 }
00082 ++nbMovingObjects;
00083 }
00084 default:
00085 {
00086 objects.push_back(obj);
00087 }
00088 }
00089 }
00090
00091 void MapZone::remove(Actor *obj)
00092 {
00093 std::vector< Actor * >::iterator i_beg = objects.begin(), i, i_end;
00094 int type = obj->getType();
00095 switch (type)
00096 {
00097 case OBJECT_CHARACTER:
00098 {
00099 i = i_beg;
00100 i_end = objects.begin() + nbCharacters;
00101 } break;
00102 case OBJECT_MONSTER:
00103 case OBJECT_NPC:
00104 {
00105 i = objects.begin() + nbCharacters;
00106 i_end = objects.begin() + nbMovingObjects;
00107 } break;
00108 default:
00109 {
00110 i = objects.begin() + nbMovingObjects;
00111 i_end = objects.end();
00112 }
00113 }
00114 i = std::find(i, i_end, obj);
00115 assert(i != i_end);
00116 unsigned pos = i - i_beg;
00117 if (pos < nbCharacters)
00118 {
00119 objects[pos] = objects[nbCharacters - 1];
00120 pos = nbCharacters - 1;
00121 --nbCharacters;
00122 }
00123 if (pos < nbMovingObjects)
00124 {
00125 objects[pos] = objects[nbMovingObjects - 1];
00126 pos = nbMovingObjects - 1;
00127 --nbMovingObjects;
00128 }
00129 objects[pos] = objects[objects.size() - 1];
00130 objects.pop_back();
00131 }
00132
00133 static void addZone(MapRegion &r, unsigned z)
00134 {
00135 MapRegion::iterator i_end = r.end(),
00136 i = std::lower_bound(r.begin(), i_end, z);
00137 if (i == i_end || *i != z)
00138 {
00139 r.insert(i, z);
00140 }
00141 }
00142
00143 ZoneIterator::ZoneIterator(const MapRegion &r, const MapContent *m)
00144 : region(r), pos(0), map(m)
00145 {
00146 current = &map->zones[r.empty() ? 0 : r[0]];
00147 }
00148
00149 void ZoneIterator::operator++()
00150 {
00151 current = NULL;
00152 if (!region.empty())
00153 {
00154 if (++pos != region.size())
00155 {
00156 current = &map->zones[region[pos]];
00157 }
00158 }
00159 else
00160 {
00161 if (++pos != (unsigned)map->mapWidth * map->mapHeight)
00162 {
00163 current = &map->zones[pos];
00164 }
00165 }
00166 }
00167
00168 CharacterIterator::CharacterIterator(const ZoneIterator &it)
00169 : iterator(it), pos(0)
00170 {
00171 while (iterator && (*iterator)->nbCharacters == 0) ++iterator;
00172 if (iterator)
00173 {
00174 current = static_cast< Character * >((*iterator)->objects[pos]);
00175 }
00176 }
00177
00178 void CharacterIterator::operator++()
00179 {
00180 if (++pos == (*iterator)->nbCharacters)
00181 {
00182 do ++iterator; while (iterator && (*iterator)->nbCharacters == 0);
00183 pos = 0;
00184 }
00185 if (iterator)
00186 {
00187 current = static_cast< Character * >((*iterator)->objects[pos]);
00188 }
00189 }
00190
00191 BeingIterator::BeingIterator(const ZoneIterator &it)
00192 : iterator(it), pos(0)
00193 {
00194 while (iterator && (*iterator)->nbMovingObjects == 0) ++iterator;
00195 if (iterator)
00196 {
00197 current = static_cast< Being * >((*iterator)->objects[pos]);
00198 }
00199 }
00200
00201 void BeingIterator::operator++()
00202 {
00203 if (++pos == (*iterator)->nbMovingObjects)
00204 {
00205 do ++iterator; while (iterator && (*iterator)->nbMovingObjects == 0);
00206 pos = 0;
00207 }
00208 if (iterator)
00209 {
00210 current = static_cast< Being * >((*iterator)->objects[pos]);
00211 }
00212 }
00213
00214 FixedActorIterator::FixedActorIterator(const ZoneIterator &it)
00215 : iterator(it), pos(0)
00216 {
00217 while (iterator && (*iterator)->nbMovingObjects == (*iterator)->objects.size()) ++iterator;
00218 if (iterator)
00219 {
00220 pos = (*iterator)->nbMovingObjects;
00221 current = (*iterator)->objects[pos];
00222 }
00223 }
00224
00225 void FixedActorIterator::operator++()
00226 {
00227 if (++pos == (*iterator)->objects.size())
00228 {
00229 do ++iterator; while (iterator && (*iterator)->nbMovingObjects == (*iterator)->objects.size());
00230 if (iterator)
00231 {
00232 pos = (*iterator)->nbMovingObjects;
00233 }
00234 }
00235 if (iterator)
00236 {
00237 current = (*iterator)->objects[pos];
00238 }
00239 }
00240
00241 ActorIterator::ActorIterator(const ZoneIterator &it)
00242 : iterator(it), pos(0)
00243 {
00244 while (iterator && (*iterator)->objects.empty()) ++iterator;
00245 if (iterator)
00246 {
00247 current = (*iterator)->objects[pos];
00248 }
00249 }
00250
00251 void ActorIterator::operator++()
00252 {
00253 if (++pos == (*iterator)->objects.size())
00254 {
00255 do ++iterator; while (iterator && (*iterator)->objects.empty());
00256 pos = 0;
00257 }
00258 if (iterator)
00259 {
00260 current = (*iterator)->objects[pos];
00261 }
00262 }
00263
00264 ObjectBucket::ObjectBucket()
00265 : free(256), next_object(1)
00266 {
00267 for (unsigned i = 0; i < 256 / int_bitsize; ++i)
00268 {
00269
00270 bitmap[i] = ~0u;
00271 }
00272 }
00273
00274 int ObjectBucket::allocate()
00275 {
00276
00277 if (!free)
00278 {
00279 LOG_INFO("No free id in bucket");
00280 return -1;
00281 }
00282
00283
00284
00285 if (bitmap[next_object / int_bitsize] & (1 << (next_object % int_bitsize)))
00286 {
00287 bitmap[next_object / int_bitsize] &= ~(1 << (next_object % int_bitsize));
00288 int i = next_object;
00289 next_object = (i + 1) & 255;
00290 --free;
00291 return i;
00292 }
00293
00294
00295
00296 for (unsigned i = 0; i < 256 / int_bitsize; ++i)
00297 {
00298 int k = (i + next_object / int_bitsize) & 255;
00299
00300 if (unsigned b = bitmap[k])
00301 {
00302
00303 int j = 0;
00304 while (!(b & 1))
00305 {
00306 b >>= 1;
00307 ++j;
00308 }
00309 bitmap[k] &= ~(1 << j);
00310 j += k * int_bitsize;
00311 next_object = (j + 1) & 255;
00312 --free;
00313 return j;
00314 }
00315 }
00316
00317
00318 LOG_INFO("No free id in the bucket");
00319 return -1;
00320 }
00321
00322 void ObjectBucket::deallocate(int i)
00323 {
00324 assert(!(bitmap[i / int_bitsize] & (1 << (i % int_bitsize))));
00325 bitmap[i / int_bitsize] |= 1 << (i % int_bitsize);
00326 ++free;
00327 }
00328
00329 MapContent::MapContent(Map *map)
00330 : last_bucket(0), zones(NULL)
00331 {
00332 buckets[0] = new ObjectBucket;
00333 for (int i = 1; i < 256; ++i)
00334 {
00335 buckets[i] = NULL;
00336 }
00337 mapWidth = (map->getWidth() * 32 + zoneDiam - 1) / zoneDiam;
00338 mapHeight = (map->getHeight() * 32 + zoneDiam - 1) / zoneDiam;
00339 zones = new MapZone[mapWidth * mapHeight];
00340 }
00341
00342 MapContent::~MapContent()
00343 {
00344 for (int i = 0; i < 256; ++i)
00345 {
00346 delete buckets[i];
00347 }
00348 delete[] zones;
00349 }
00350
00351 bool MapContent::allocate(Actor *obj)
00352 {
00353
00354 ObjectBucket *b = buckets[last_bucket];
00355 int i = b->allocate();
00356 if (i >= 0)
00357 {
00358 b->objects[i] = obj;
00359 obj->setPublicID(last_bucket * 256 + i);
00360 return true;
00361 }
00362
00363
00364
00365 for (i = 0; i < 256; ++i)
00366 {
00367 b = buckets[i];
00368 if (!b)
00369 {
00370
00371
00372
00373 b = new ObjectBucket;
00374 buckets[i] = b;
00375 LOG_INFO("New bucket created");
00376 }
00377 int j = b->allocate();
00378 if (j >= 0)
00379 {
00380 last_bucket = i;
00381 b->objects[j] = obj;
00382 obj->setPublicID(last_bucket * 256 + j);
00383 return true;
00384 }
00385 }
00386
00387
00388 LOG_ERROR("unable to allocate id");
00389 return false;
00390 }
00391
00392 void MapContent::deallocate(Actor *obj)
00393 {
00394 unsigned short id = obj->getPublicID();
00395 buckets[id / 256]->deallocate(id % 256);
00396 }
00397
00398 void MapContent::fillRegion(MapRegion &r, const Point &p, int radius) const
00399 {
00400 int ax = p.x > radius ? (p.x - radius) / zoneDiam : 0,
00401 ay = p.y > radius ? (p.y - radius) / zoneDiam : 0,
00402 bx = std::min((p.x + radius) / zoneDiam, mapWidth - 1),
00403 by = std::min((p.y + radius) / zoneDiam, mapHeight - 1);
00404 for (int y = ay; y <= by; ++y)
00405 {
00406 for (int x = ax; x <= bx; ++x)
00407 {
00408 addZone(r, x + y * mapWidth);
00409 }
00410 }
00411 }
00412
00413 void MapContent::fillRegion(MapRegion &r, const Rectangle &p) const
00414 {
00415 int ax = p.x / zoneDiam,
00416 ay = p.y / zoneDiam,
00417 bx = std::min((p.x + p.w) / zoneDiam, mapWidth - 1),
00418 by = std::min((p.y + p.h) / zoneDiam, mapHeight - 1);
00419 for (int y = ay; y <= by; ++y)
00420 {
00421 for (int x = ax; x <= bx; ++x)
00422 {
00423 addZone(r, x + y * mapWidth);
00424 }
00425 }
00426 }
00427
00428 MapZone& MapContent::getZone(const Point &pos) const
00429 {
00430 return zones[(pos.x / zoneDiam) + (pos.y / zoneDiam) * mapWidth];
00431 }
00432
00433 MapComposite::MapComposite(int id, const std::string &name):
00434 mMap(NULL),
00435 mContent(NULL),
00436 mScript(NULL),
00437 mName(name),
00438 mID(id)
00439 {
00440 }
00441
00442 MapComposite::~MapComposite()
00443 {
00444 delete mMap;
00445 delete mContent;
00446 delete mScript;
00447 }
00448
00449 ZoneIterator MapComposite::getAroundPointIterator(const Point &p, int radius) const
00450 {
00451 MapRegion r;
00452 mContent->fillRegion(r, p, radius);
00453 return ZoneIterator(r, mContent);
00454 }
00455
00456 ZoneIterator MapComposite::getAroundActorIterator(Actor *obj, int radius) const
00457 {
00458 MapRegion r;
00459 mContent->fillRegion(r, obj->getPosition(), radius);
00460 return ZoneIterator(r, mContent);
00461 }
00462
00463 ZoneIterator MapComposite::getInsideRectangleIterator(const Rectangle &p) const
00464 {
00465 MapRegion r;
00466 mContent->fillRegion(r, p);
00467 return ZoneIterator(r, mContent);
00468 }
00469
00470 ZoneIterator MapComposite::getAroundBeingIterator(Being *obj, int radius) const
00471 {
00472 MapRegion r1;
00473 mContent->fillRegion(r1, obj->getOldPosition(), radius);
00474 MapRegion r2 = r1;
00475 for (MapRegion::iterator i = r1.begin(), i_end = r1.end(); i != i_end; ++i)
00476 {
00477
00478
00479
00480
00481 MapRegion &r4 = mContent->zones[*i].destinations;
00482 if (!r4.empty())
00483 {
00484 MapRegion r3;
00485 r3.reserve(r2.size() + r4.size());
00486 std::set_union(r2.begin(), r2.end(), r4.begin(), r4.end(),
00487 std::back_insert_iterator< MapRegion >(r3));
00488 r2.swap(r3);
00489 }
00490 }
00491 mContent->fillRegion(r2, obj->getPosition(), radius);
00492 return ZoneIterator(r2, mContent);
00493 }
00494
00495 bool MapComposite::insert(Thing *ptr)
00496 {
00497 if (ptr->isVisible())
00498 {
00499 if (ptr->canMove() && !mContent->allocate(static_cast< Being * >(ptr)))
00500 {
00501 return false;
00502 }
00503
00504 Actor *obj = static_cast< Actor * >(ptr);
00505 mContent->getZone(obj->getPosition()).insert(obj);
00506 }
00507
00508 ptr->setMap(this);
00509 mContent->things.push_back(ptr);
00510 return true;
00511 }
00512
00513 void MapComposite::remove(Thing *ptr)
00514 {
00515 if (ptr->isVisible())
00516 {
00517 Actor *obj = static_cast< Actor * >(ptr);
00518 mContent->getZone(obj->getPosition()).remove(obj);
00519
00520 if (ptr->canMove())
00521 {
00522 std::stringstream str;
00523 str << "Deallocating " << ptr->getType();
00524 LOG_INFO(str.str());
00525 mContent->deallocate(static_cast< Being * >(ptr));
00526 }
00527 }
00528
00529 for (std::vector< Thing * >::iterator i = mContent->things.begin(),
00530 i_end = mContent->things.end(); i != i_end; ++i)
00531 {
00532 if (*i == ptr)
00533 {
00534 *i = *(i_end - 1);
00535 mContent->things.pop_back();
00536 return;
00537 }
00538 }
00539 assert(false);
00540 }
00541
00542 void MapComposite::setMap(Map *m)
00543 {
00544 assert(!mMap && m);
00545 mMap = m;
00546 mContent = new MapContent(m);
00547
00548 std::string sPvP = m->getProperty ("pvp");
00549 if (sPvP == "")
00550 sPvP = Configuration::getValue("defaultPvp", "");
00551
00552 if (sPvP == "free") mPvPRules = PVP_FREE;
00553 else if (sPvP == "none") mPvPRules = PVP_NONE;
00554 else mPvPRules = PVP_NONE;
00555
00556 }
00557
00558 void MapComposite::update()
00559 {
00560 for (int i = 0; i < mContent->mapHeight * mContent->mapWidth; ++i)
00561 {
00562 mContent->zones[i].destinations.clear();
00563 }
00564
00565
00566 for (std::vector< Thing * >::iterator i = mContent->things.begin(),
00567 i_end = mContent->things.end(); i != i_end; ++i)
00568 {
00569 if (!(*i)->canMove())
00570 continue;
00571
00572 Being *obj = static_cast< Being * >(*i);
00573
00574 const Point &pos1 = obj->getOldPosition(),
00575 &pos2 = obj->getPosition();
00576
00577 MapZone &src = mContent->getZone(pos1),
00578 &dst = mContent->getZone(pos2);
00579 if (&src != &dst)
00580 {
00581 addZone(src.destinations, &dst - mContent->zones);
00582 src.remove(obj);
00583 dst.insert(obj);
00584 }
00585 }
00586 }
00587
00588 const std::vector< Thing * > &MapComposite::getEverything() const
00589 {
00590 return mContent->things;
00591 }