diff options
Diffstat (limited to 'src/map.cpp')
-rw-r--r-- | src/map.cpp | 236 |
1 files changed, 173 insertions, 63 deletions
diff --git a/src/map.cpp b/src/map.cpp index f845f2ff..da962253 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -21,32 +21,31 @@ #include "map.h" -#include "beingmanager.h" +#include "actorspritemanager.h" #include "client.h" #include "configuration.h" #include "graphics.h" #include "particle.h" #include "simpleanimation.h" -#include "sprite.h" #include "tileset.h" #include "resources/ambientlayer.h" #include "resources/image.h" #include "resources/resourcemanager.h" +#include "net/net.h" + #include "utils/dtor.h" #include "utils/stringutils.h" #include <queue> +#include <limits.h> /** * A location on a tile map. Used for pathfinding, open list. */ struct Location { - /** - * Constructor. - */ Location(int px, int py, MetaTile *ptile): x(px), y(py), tile(ptile) {} @@ -122,7 +121,7 @@ Image* MapLayer::getTile(int x, int y) const void MapLayer::draw(Graphics *graphics, int startX, int startY, int endX, int endY, int scrollX, int scrollY, - const MapSprites &sprites, int debugFlags) const + const Actors &actors, int debugFlags) const { startX -= mX; startY -= mY; @@ -134,47 +133,86 @@ void MapLayer::draw(Graphics *graphics, int startX, int startY, if (endX > mWidth) endX = mWidth; if (endY > mHeight) endY = mHeight; - MapSprites::const_iterator si = sprites.begin(); + Actors::const_iterator ai = actors.begin(); + + int dx = (mX * 32) - scrollX; + int dy = (mY * 32) - scrollY + 32; for (int y = startY; y < endY; y++) { - // If drawing the fringe layer, make sure all sprites above this row of + int y32 = y * 32; + + // If drawing the fringe layer, make sure all actors above this row of // tiles have been drawn if (mIsFringeLayer) { - while (si != sprites.end() && (*si)->getPixelY() <= y * 32) + while (ai != actors.end() && (*ai)->getPixelY() <= y * 32) { - (*si)->setAlpha(1.0f); - (*si)->draw(graphics, -scrollX, -scrollY); - si++; + (*ai)->draw(graphics, -scrollX, -scrollY); + ai++; } } - for (int x = startX; x < endX; x++) + if (debugFlags != Map::MAP_SPECIAL3) { - Image *img = getTile(x, y); - if (img) + const int py0 = y32 + dy; + + for (int x = startX; x < endX; x++) { - const int px = (x + mX) * 32 - scrollX; - const int py = (y + mY) * 32 - scrollY + 32 - img->getHeight(); - if (debugFlags != Map::MAP_SPECIAL || img->getHeight() <= 32) - graphics->drawImage(img, px, py); + Image *img = getTile(x, y); + if (img) + { + const int px = (x * 32) + dx; + const int py = py0 - img->getHeight(); + if ((debugFlags != Map::MAP_SPECIAL + && debugFlags != Map::MAP_SPECIAL2) + || img->getHeight() <= 32) + { + int width = 0; + int c = getTileDrawWidth(x, y, endX, width); + if (!c) + { + graphics->drawImage(img, px, py); + } + else + { + graphics->drawImagePattern(img, px, py, + width, img->getHeight()); + } + x += c; + } + } } } } - // Draw any remaining sprites + // Draw any remaining actors if (mIsFringeLayer) { - while (si != sprites.end()) + while (ai != actors.end()) { - (*si)->setAlpha(1.0f); - (*si)->draw(graphics, -scrollX, -scrollY); - si++; + (*ai)->draw(graphics, -scrollX, -scrollY); + ai++; } } } +int MapLayer::getTileDrawWidth(int x1, int y1, int endX, int &width) const +{ + Image *img1 = getTile(x1, y1); + int c = 0; + width = img1->getWidth(); + for (int x = x1 + 1; x < endX; x++) + { + Image *img = getTile(x, y1); + if (img != img1) + break; + c ++; + width += img->getWidth(); + } + return c; +} + Map::Map(int width, int height, int tileWidth, int tileHeight): mWidth(width), mHeight(height), mTileWidth(tileWidth), mTileHeight(tileHeight), @@ -188,8 +226,8 @@ Map::Map(int width, int height, int tileWidth, int tileHeight): mMetaTiles = new MetaTile[size]; for (int i = 0; i < NB_BLOCKTYPES; i++) { - mOccupation[i] = new int[size]; - memset(mOccupation[i], 0, size * sizeof(int)); + mOccupation[i] = new unsigned[size]; + memset(mOccupation[i], 0, size * sizeof(unsigned)); } } @@ -283,7 +321,7 @@ void Map::addTileset(Tileset *tileset) mMaxTileHeight = tileset->getHeight(); } -bool spriteCompare(const Sprite *a, const Sprite *b) +bool actorCompare(const Actor *a, const Actor *b) { return a->getPixelY() < b->getPixelY(); } @@ -309,25 +347,47 @@ void Map::draw(Graphics *graphics, int scrollX, int scrollY) int endX = (graphics->getWidth() + scrollX + mTileWidth - 1) / mTileWidth; int endY = endPixelY / mTileHeight; - // Make sure sprites are sorted ascending by Y-coordinate + // Make sure actors are sorted ascending by Y-coordinate // so that they overlap correctly - mSprites.sort(spriteCompare); + mActors.sort(actorCompare); // update scrolling of all ambient layers updateAmbientLayers(scrollX, scrollY); // Draw backgrounds drawAmbientLayers(graphics, BACKGROUND_LAYERS, scrollX, scrollY, - (int) config.getValue("OverlayDetail", 2)); + config.getIntValue("OverlayDetail")); // draw the game world Layers::const_iterator layeri = mLayers.begin(); - for (; layeri != mLayers.end(); ++layeri) + + bool overFringe = false; + + if (mDebugFlags == MAP_SPECIAL3) { - (*layeri)->draw(graphics, - startX, startY, endX, endY, - scrollX, scrollY, - mSprites, mDebugFlags); + for (; layeri != mLayers.end(); ++layeri) + { + if ((*layeri)->isFringeLayer()) + { + (*layeri)->draw(graphics, + startX, startY, endX, endY, + scrollX, scrollY, + mActors, mDebugFlags); + } + } + } + else + { + for (; layeri != mLayers.end() && !overFringe; ++layeri) + { + if ((*layeri)->isFringeLayer() && mDebugFlags == MAP_SPECIAL2) + overFringe = true; + + (*layeri)->draw(graphics, + startX, startY, endX, endY, + scrollX, scrollY, + mActors, mDebugFlags); + } } // If the transparency hasn't been disabled, @@ -335,24 +395,25 @@ void Map::draw(Graphics *graphics, int scrollX, int scrollY) { // We draw beings with a lower opacity to make them visible // even when covered by a wall or some other elements... - MapSprites::const_iterator si = mSprites.begin(); - while (si != mSprites.end()) + Actors::const_iterator ai = mActors.begin(); + while (ai != mActors.end()) { - if (Sprite *sprite = *si) + if (Actor *actor = *ai) { - // For now, just draw sprites with only one layer. - if (sprite->getNumberOfLayers() == 1) + // For now, just draw actors with only one layer. + if (actor->getNumberOfLayers() == 1) { - sprite->setAlpha(0.3f); - sprite->draw(graphics, -scrollX, -scrollY); + actor->setAlpha(0.3f); + actor->draw(graphics, -scrollX, -scrollY); + actor->setAlpha(1.0f); } } - si++; + ai++; } } drawAmbientLayers(graphics, FOREGROUND_LAYERS, scrollX, scrollY, - (int) config.getValue("OverlayDetail", 2)); + config.getIntValue("OverlayDetail")); } void Map::drawCollision(Graphics *graphics, int scrollX, int scrollY, @@ -496,7 +557,8 @@ void Map::blockTile(int x, int y, BlockType type) const int tileNum = x + y * mWidth; - if ((++mOccupation[type][tileNum]) > 0) + if (mOccupation[type][tileNum] < UINT_MAX && + (++mOccupation[type][tileNum]) > 0) { switch (type) { @@ -528,18 +590,29 @@ bool Map::getWalk(int x, int y, unsigned char walkmask) const bool Map::occupied(int x, int y) const { - const Beings &beings = beingManager->getAll(); - for (Beings::const_iterator i = beings.begin(); i != beings.end(); i++) + const ActorSprites &actors = actorSpriteManager->getAll(); + ActorSpritesConstIterator it, it_end; + for (it = actors.begin(), it_end = actors.end(); it != it_end; it++) { - const Being *being = *i; + const ActorSprite *actor = *it; - if (being->getTileX() == x && being->getTileY() == y) + if (actor->getTileX() == x && actor->getTileY() == y && + actor->getType() != ActorSprite::FLOOR_ITEM) return true; } return false; } +Vector Map::getTileCenter(int x, int y) +{ + Vector tileCenterPos; + + tileCenterPos.x = x * mTileWidth + mTileWidth / 2; + tileCenterPos.y = y * mTileHeight + mTileHeight / 2; + return tileCenterPos; +} + bool Map::contains(int x, int y) const { return x >= 0 && y >= 0 && x < mWidth && y < mHeight; @@ -550,15 +623,15 @@ MetaTile *Map::getMetaTile(int x, int y) const return &mMetaTiles[x + y * mWidth]; } -MapSprite Map::addSprite(Sprite *sprite) +Actors::iterator Map::addActor(Actor *actor) { - mSprites.push_front(sprite); - return mSprites.begin(); + mActors.push_front(actor); + return mActors.begin(); } -void Map::removeSprite(MapSprite iterator) +void Map::removeActor(Actors::iterator iterator) { - mSprites.erase(iterator); + mActors.erase(iterator); } const std::string Map::getMusicFile() const @@ -643,6 +716,30 @@ Position Map::checkNodeOffsets(int radius, unsigned char walkMask, return Position(tx * 32 + fx, ty * 32 + fy); } +Path Map::findTilePath(int startPixelX, int startPixelY, int endPixelX, + int endPixelY, unsigned char walkMask, int maxCost) +{ + Path myPath = findPath(startPixelX / mTileWidth, startPixelY / mTileHeight, + endPixelX / mTileWidth, endPixelY / mTileHeight, + walkMask, maxCost); + + // Don't compute empty coordinates. + if (myPath.empty()) + return myPath; + + // Convert the map path to pixels from the tile position + Path::iterator it = myPath.begin(); + while (it != myPath.end()) + { + // The new pixel position will be the tile center. + *it = Position(it->x * mTileWidth + mTileWidth / 2, + it->y * mTileHeight + mTileHeight / 2); + ++it; + } + + return myPath; +} + Path Map::findPixelPath(int startPixelX, int startPixelY, int endPixelX, int endPixelY, int radius, unsigned char walkMask, int maxCost) @@ -695,6 +792,7 @@ Path Map::findPixelPath(int startPixelX, int startPixelY, int endPixelX, Path Map::findPath(int startX, int startY, int destX, int destY, unsigned char walkmask, int maxCost) { + // The basic walking cost of a tile. static int const basicCost = 100; // Path to be built up (empty by default) @@ -726,9 +824,7 @@ Path Map::findPath(int startX, int startY, int destX, int destY, // If the tile is already on the closed list, this means it has already // been processed with a shorter path to the start point (lower G cost) if (curr.tile->whichList == mOnClosedList) - { continue; - } // Put the current tile on the closed list curr.tile->whichList = mOnClosedList; @@ -745,9 +841,7 @@ Path Map::findPath(int startX, int startY, int destX, int destY, // Skip if if we're checking the same tile we're leaving from, // or if the new location falls outside of the map boundaries if ((dx == 0 && dy == 0) || !contains(x, y)) - { continue; - } MetaTile *newTile = getMetaTile(x, y); @@ -767,7 +861,7 @@ Path Map::findPath(int startX, int startY, int destX, int destY, MetaTile *t1 = getMetaTile(curr.x, curr.y + dy); MetaTile *t2 = getMetaTile(curr.x + dx, curr.y); - if ((t1->blockmask | t2->blockmask) & BLOCKMASK_WALL) + if ((t1->blockmask | t2->blockmask) & walkmask) continue; } @@ -791,7 +885,9 @@ Path Map::findPath(int startX, int startY, int destX, int destY, // It costs extra to walk through a being (needs to be enough // to make it more attractive to walk around). - if (occupied(x, y)) + // N.B.: Specific to TmwAthena for now. + if (Net::getNetworkType() == ServerInfo::TMWATHENA && + occupied(x, y)) { Gcost += 3 * basicCost; } @@ -856,8 +952,22 @@ Path Map::findPath(int startX, int startY, int destX, int destY, // Two new values to indicate whether a tile is on the open or closed list, // this way we don't have to clear all the values between each pathfinding. - mOnClosedList += 2; - mOnOpenList += 2; + if (mOnOpenList > UINT_MAX - 2) + { + // We reset the list memebers value. + mOnClosedList = 1; + mOnOpenList = 2; + + // Clean up the metaTiles + const int size = mWidth * mHeight; + for (int i = 0; i < size; ++i) + mMetaTiles[i].whichList = 0; + } + else + { + mOnClosedList += 2; + mOnOpenList += 2; + } // If a path has been found, iterate backwards using the parent locations // to extract it. @@ -897,7 +1007,7 @@ void Map::initializeParticleEffects(Particle *particleEngine) { Particle *p; - if (config.getValue("particleeffects", 1)) + if (config.getBoolValue("particleeffects")) { for (std::list<ParticleEffectData>::iterator i = particleEffects.begin(); i != particleEffects.end(); |