summaryrefslogtreecommitdiff
path: root/src/map.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/map.cpp')
-rw-r--r--src/map.cpp236
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();