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 <queue>
00024 #include <cassert>
00025 #include <cstring>
00026
00027 #include "game-server/map.hpp"
00028
00029 MetaTile::MetaTile():
00030 whichList(0),
00031 blockmask(0)
00032 {
00033 }
00034
00035
00036 Location::Location(int x, int y, MetaTile *tile):
00037 x(x), y(y), tile(tile)
00038 {
00039 }
00040
00041 bool Location::operator< (const Location &loc) const
00042 {
00043 return tile->Fcost > loc.tile->Fcost;
00044 }
00045
00046 Map::Map(int width, int height, int twidth, int theight):
00047 mWidth(width), mHeight(height),
00048 tileWidth(twidth), tileHeight(theight),
00049 onClosedList(1), onOpenList(2)
00050 {
00051 mMetaTiles = new MetaTile[mWidth * mHeight];
00052 for (int i=0; i < NB_BLOCKTYPES; i++)
00053 {
00054 mOccupation[i] = new int[mWidth * mHeight];
00055 memset(mOccupation[i], 0, mWidth * mHeight * sizeof(int));
00056 }
00057 }
00058
00059 Map::~Map()
00060 {
00061 delete[] mMetaTiles;
00062 for (int i=0; i < NB_BLOCKTYPES; i++)
00063 {
00064 delete[] mOccupation[i];
00065 }
00066 }
00067
00068 void Map::setSize(int width, int height)
00069 {
00070 this->mWidth = width;
00071 this->mHeight = height;
00072
00073 delete[] mMetaTiles;
00074 mMetaTiles = new MetaTile[mWidth * mHeight];
00075
00076 for (int i=0; i < NB_BLOCKTYPES; i++)
00077 {
00078 delete[] mOccupation[i];
00079 mOccupation[i] = new int[mWidth * mHeight];
00080 }
00081 }
00082
00083 const std::string &Map::getProperty(const std::string &key) const
00084 {
00085 static std::string empty;
00086 std::map<std::string, std::string>::const_iterator i;
00087 i = mProperties.find(key);
00088 if (i == mProperties.end())
00089 return empty;
00090 return i->second;
00091 }
00092
00093 void Map::blockTile(int x, int y, BlockType type)
00094 {
00095 if (type == BLOCKTYPE_NONE || x < 0 || y < 0 || x >= mWidth || y >= mHeight)
00096 {
00097 return;
00098 }
00099
00100 int tileNum = x + y * mWidth;
00101
00102 if (++mOccupation[type][tileNum])
00103 {
00104 switch (type)
00105 {
00106 case BLOCKTYPE_WALL:
00107 mMetaTiles[tileNum].blockmask |= BLOCKMASK_WALL;
00108 break;
00109 case BLOCKTYPE_CHARACTER:
00110 mMetaTiles[tileNum].blockmask |= BLOCKMASK_CHARACTER;
00111 break;
00112 case BLOCKTYPE_MONSTER:
00113 mMetaTiles[tileNum].blockmask |= BLOCKMASK_MONSTER;
00114 break;
00115 default:
00116
00117 break;
00118 }
00119 }
00120 }
00121
00122 void Map::freeTile(int x, int y, BlockType type)
00123 {
00124 if (type == BLOCKTYPE_NONE || x < 0 || y < 0 || x >= mWidth || y >= mHeight)
00125 {
00126 return;
00127 }
00128
00129 int tileNum = x + y * mWidth;
00130
00131 if (!(--mOccupation[type][tileNum]))
00132 {
00133 switch (type)
00134 {
00135 case BLOCKTYPE_WALL:
00136 mMetaTiles[tileNum].blockmask &= (BLOCKMASK_WALL xor 0xff);
00137 break;
00138 case BLOCKTYPE_CHARACTER:
00139 mMetaTiles[tileNum].blockmask &= (BLOCKMASK_CHARACTER xor 0xff);
00140 break;
00141 case BLOCKTYPE_MONSTER:
00142 mMetaTiles[tileNum].blockmask &= (BLOCKMASK_MONSTER xor 0xff);
00143 break;
00144 default:
00145
00146 break;
00147 }
00148 }
00149 }
00150
00151 bool Map::getWalk(int x, int y, char walkmask) const
00152 {
00153
00154 if (x < 0 || y < 0 || x >= mWidth || y >= mHeight)
00155 {
00156 return false;
00157 }
00158
00159
00160 return !(mMetaTiles[x + y * mWidth].blockmask & walkmask);
00161 }
00162
00163 MetaTile *Map::getMetaTile(int x, int y)
00164 {
00165 return &mMetaTiles[x + y * mWidth];
00166 }
00167
00168 static int const basicCost = 100;
00169
00170 std::list<PATH_NODE>
00171 Map::findPath(int startX, int startY, int destX, int destY, unsigned char walkmask, int maxCost)
00172 {
00173
00174 std::list<PATH_NODE> path;
00175
00176
00177 std::priority_queue<Location> openList;
00178
00179
00180 if (!getWalk(destX, destY, walkmask)) return path;
00181
00182
00183 MetaTile *startTile = getMetaTile(startX, startY);
00184 startTile->Gcost = 0;
00185
00186
00187 openList.push(Location(startX, startY, startTile));
00188
00189 bool foundPath = false;
00190
00191
00192 while (!openList.empty() && !foundPath)
00193 {
00194
00195
00196 Location curr = openList.top();
00197 openList.pop();
00198
00199
00200
00201 if (curr.tile->whichList == onClosedList)
00202 {
00203 continue;
00204 }
00205
00206
00207 curr.tile->whichList = onClosedList;
00208
00209
00210 for (int dy = -1; dy <= 1; dy++)
00211 {
00212 for (int dx = -1; dx <= 1; dx++)
00213 {
00214
00215 int x = curr.x + dx;
00216 int y = curr.y + dy;
00217
00218
00219
00220 if ((dx == 0 && dy == 0) ||
00221 (x < 0 || y < 0 || x >= mWidth || y >= mHeight))
00222 {
00223 continue;
00224 }
00225
00226 MetaTile *newTile = getMetaTile(x, y);
00227
00228
00229 if (newTile->whichList == onClosedList || newTile->blockmask & walkmask)
00230 {
00231 continue;
00232 }
00233
00234
00235
00236 if (dx != 0 && dy != 0)
00237 {
00238 MetaTile *t1 = getMetaTile(curr.x, curr.y + dy);
00239 MetaTile *t2 = getMetaTile(curr.x + dx, curr.y);
00240
00241 if (t1->blockmask & walkmask && !(t2->blockmask & walkmask))
00242 {
00243 continue;
00244 }
00245 }
00246
00247
00248 int Gcost = curr.tile->Gcost +
00249 (dx == 0 || dy == 0 ? basicCost : basicCost * 362 / 256);
00250
00251
00252
00253
00254
00255
00256
00257
00258 if (dx == 0 || dy == 0)
00259 {
00260
00261
00262 ++Gcost;
00263 }
00264
00265
00266
00267 if (Gcost > maxCost * basicCost)
00268 {
00269 continue;
00270 }
00271
00272 if (newTile->whichList != onOpenList)
00273 {
00274
00275
00276
00277
00278
00279
00280 int dx = std::abs(x - destX), dy = std::abs(y - destY);
00281 newTile->Hcost = std::abs(dx - dy) * basicCost +
00282 std::min(dx, dy) * (basicCost * 362 / 256);
00283
00284
00285 newTile->parentX = curr.x;
00286 newTile->parentY = curr.y;
00287
00288
00289 newTile->Gcost = Gcost;
00290 newTile->Fcost = newTile->Gcost + newTile->Hcost;
00291
00292 if (x != destX || y != destY) {
00293
00294 newTile->whichList = onOpenList;
00295 openList.push(Location(x, y, newTile));
00296 }
00297 else {
00298
00299 foundPath = true;
00300 }
00301 }
00302 else if (Gcost < newTile->Gcost)
00303 {
00304
00305
00306 newTile->Gcost = Gcost;
00307 newTile->Fcost = newTile->Gcost + newTile->Hcost;
00308
00309
00310 newTile->parentX = curr.x;
00311 newTile->parentY = curr.y;
00312
00313
00314
00315 openList.push(Location(x, y, newTile));
00316 }
00317 }
00318 }
00319 }
00320
00321
00322
00323 onClosedList += 2;
00324 onOpenList += 2;
00325
00326
00327
00328 if (foundPath)
00329 {
00330 int pathX = destX;
00331 int pathY = destY;
00332
00333 while (pathX != startX || pathY != startY)
00334 {
00335
00336 path.push_front(PATH_NODE(pathX, pathY));
00337
00338
00339 MetaTile *tile = getMetaTile(pathX, pathY);
00340 pathX = tile->parentX;
00341 pathY = tile->parentY;
00342 }
00343 }
00344
00345 return path;
00346 }