summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBjørn Lindeijer <bjorn@lindeijer.nl>2008-07-01 17:41:30 +0000
committerBjørn Lindeijer <bjorn@lindeijer.nl>2008-07-01 17:41:30 +0000
commit4ca8675700dfae625376c4afdd30b8590d68087e (patch)
tree7f661baf3d566fcf5d0318da13e29c13098cf21a
parentcf5cfbcb8ff63005b1e08f9718ce3f80f919271e (diff)
downloadmana-client-4ca8675700dfae625376c4afdd30b8590d68087e.tar.gz
mana-client-4ca8675700dfae625376c4afdd30b8590d68087e.tar.bz2
mana-client-4ca8675700dfae625376c4afdd30b8590d68087e.tar.xz
mana-client-4ca8675700dfae625376c4afdd30b8590d68087e.zip
Merged revisions 4044-4067 via svnmerge from
https://themanaworld.svn.sourceforge.net/svnroot/themanaworld/tmw/trunk ........ r4044 | b_lindeijer | 2008-04-07 11:02:38 +0200 (Mon, 07 Apr 2008) | 2 lines Added support for basing one sprite definition on another by including it. ........ r4057 | b_lindeijer | 2008-04-08 20:43:44 +0200 (Tue, 08 Apr 2008) | 4 lines Implemented support for an arbitrary number of map layers. The only layer requirement for map layers are now that the fringe layer is called "Fringe" and that the collision layer is called "Collision". ........ r4067 | b_lindeijer | 2008-04-11 00:03:57 +0200 (Fri, 11 Apr 2008) | 3 lines Fixed some compiler warnings and don't try to load particle effects when no file is set. ........
-rw-r--r--ChangeLog24
-rw-r--r--src/gui/viewport.cpp12
-rw-r--r--src/log.h4
-rw-r--r--src/map.cpp206
-rw-r--r--src/map.h110
-rw-r--r--src/resources/imageset.cpp2
-rw-r--r--src/resources/imageset.h14
-rw-r--r--src/resources/mapreader.cpp164
-rw-r--r--src/resources/mapreader.h4
-rw-r--r--src/resources/spritedef.cpp98
-rw-r--r--src/resources/spritedef.h6
-rw-r--r--src/tileset.h3
12 files changed, 388 insertions, 259 deletions
diff --git a/ChangeLog b/ChangeLog
index 759af38a..37c6ed4a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -284,6 +284,23 @@
src/Makefile.am: Re-enabled non-functional item shortcut window,
planned to be fixed for 0.0.25.
+2008-04-12 Bjørn Lindeijer <bjorn@lindeijer.nl>
+
+ * src/gui/widgets/layout.h, src/gui/skill.cpp, src/gui/trade.h,
+ src/log.h, src/resources/mapreader.cpp, src/resources/spritedef.cpp:
+ Fixed some compiler warnings and don't try to load particle effects
+ when no file is set.
+
+2008-04-08 Bjørn Lindeijer <bjorn@lindeijer.nl>
+
+ * src/map.cpp, src/gui/viewport.cpp, src/tileset.h, src/map.h,
+ src/resources/imageset.cpp, src/resources/mapreader.cpp,
+ src/resources/imageset.h, src/resources/mapreader.h,
+ data/maps/new_3-1.tmx, data/maps/new_1-1.tmx: Implemented support for
+ an arbitrary number of map layers. The only layer requirement for map
+ layers are now that the fringe layer is called "Fringe" and that the
+ collision layer is called "Collision".
+
2008-04-07 Bjørn Lindeijer <bjorn@lindeijer.nl>
* src/particle.cpp, src/utils/xml.cpp, src/utils/xml.h,
@@ -292,11 +309,14 @@
src/resources/itemdb.cpp, src/resources/npcdb.cpp,
src/resources/spritedef.h: Added XML::Document class which simplifies
parsing an XML document and automatically cleans it up again.
+ * src/resources/spritedef.cpp, src/resources/spritedef.h,
+ data/graphics/sprites/item008.xml: Added support for basing one sprite
+ definition on another by including it.
* src/being.cpp: Fixed crash on trying to show out of range emoticon.
* src/winver.h, README, configure.ac, data/help/changes.txt,
data/help/header.txt, NEWS, CMakeLists.txt: Updated version, release
date and changes.
-
+
2008-04-03 David Athay <ko2fan@gmail.com>
* src/game.cpp: Tweaked disconnect dialog, hoping to fix a crash bug.
@@ -307,7 +327,7 @@
src/resources/npcdb.cpp, data/npcs.xml, src/Makefile.am, tmc.cbp:
Implemented NPC XML database which maps NPC IDs to one or more
animation files and thus enables animated NPCs.
-
+
2008-03-30 Dennis Friis <peavey@placid.dk>
* configure.ac: Updated for tmwdata split.
diff --git a/src/gui/viewport.cpp b/src/gui/viewport.cpp
index 01324a47..9d1e5a1d 100644
--- a/src/gui/viewport.cpp
+++ b/src/gui/viewport.cpp
@@ -48,6 +48,8 @@
#include <cassert>
+extern volatile int tick_time;
+
Viewport::Viewport():
mMap(0),
mPixelViewX(0.0f),
@@ -222,12 +224,8 @@ Viewport::draw(gcn::Graphics *gcnGraphics)
// Draw tiles and sprites
if (mMap)
{
- mMap->draw(graphics, (int) mPixelViewX, (int) mPixelViewY, 0);
- drawTargetCursor(graphics);
- mMap->draw(graphics, (int) mPixelViewX, (int) mPixelViewY, 1);
- mMap->draw(graphics, (int) mPixelViewX, (int) mPixelViewY, 2);
- mMap->drawOverlay(graphics, mPixelViewX, mPixelViewY,
- (int) config.getValue("OverlayDetail", 2));
+ mMap->draw(graphics, (int) mPixelViewX, (int) mPixelViewY);
+ drawTargetCursor(graphics); // TODO: Draw the cursor with the sprite
drawTargetName(graphics);
}
@@ -259,7 +257,7 @@ Viewport::draw(gcn::Graphics *gcnGraphics)
}
}
- // Draw player nickname, speech, and emotion sprite as needed
+ // Draw player names, speech, and emotion sprite as needed
Beings &beings = beingManager->getAll();
for (BeingIterator i = beings.begin(); i != beings.end(); i++)
{
diff --git a/src/log.h b/src/log.h
index 6fe9dccd..30078e35 100644
--- a/src/log.h
+++ b/src/log.h
@@ -68,8 +68,8 @@ class Logger
;
/**
- * Log an error and quit. The error will pop-up in Windows and will be
- * printed to standard error everywhere else.
+ * Log an error and quit. The error will pop-up on Windows and Mac, and
+ * will be printed to standard error everywhere else.
*/
void error(const std::string &error_text);
diff --git a/src/map.cpp b/src/map.cpp
index c65b0cd6..23eff3b0 100644
--- a/src/map.cpp
+++ b/src/map.cpp
@@ -27,6 +27,7 @@
#include <queue>
#include "beingmanager.h"
+#include "configuration.h"
#include "game.h"
#include "graphics.h"
#include "particle.h"
@@ -40,6 +41,8 @@
#include "utils/dtor.h"
#include "utils/tostring.h"
+extern volatile int tick_time;
+
/**
* A location on a tile map. Used for pathfinding, open list.
*/
@@ -62,6 +65,80 @@ struct Location
MetaTile *tile;
};
+MapLayer::MapLayer(int x, int y, int width, int height, bool isFringeLayer):
+ mX(x), mY(y),
+ mWidth(width), mHeight(height),
+ mIsFringeLayer(isFringeLayer)
+{
+ const int size = mWidth * mHeight;
+ mTiles = new Image*[size];
+ std::fill_n(mTiles, size, (Image*) 0);
+}
+
+MapLayer::~MapLayer()
+{
+ delete[] mTiles;
+}
+
+void MapLayer::setTile(int x, int y, Image *img)
+{
+ mTiles[x + y * mWidth] = img;
+}
+
+Image* MapLayer::getTile(int x, int y) const
+{
+ return mTiles[x + y * mWidth];
+}
+
+void MapLayer::draw(Graphics *graphics,
+ int startX, int startY,
+ int endX, int endY,
+ int scrollX, int scrollY,
+ const Sprites &sprites) const
+{
+ startX -= mX;
+ startY -= mY;
+ endX -= mX;
+ endY -= mY;
+
+ if (startX < 0) startX = 0;
+ if (startY < 0) startY = 0;
+ if (endX > mWidth) endX = mWidth;
+ if (endY > mHeight) endY = mHeight;
+
+ Sprites::const_iterator si = sprites.begin();
+
+ for (int y = startY; y < endY; y++)
+ {
+ // If drawing the fringe layer, make sure all sprites above this row of
+ // tiles have been drawn
+ if (mIsFringeLayer) {
+ while (si != sprites.end() && (*si)->getPixelY() <= y * 32 - 32) {
+ (*si)->draw(graphics, -scrollX, -scrollY);
+ si++;
+ }
+ }
+
+ for (int x = startX; x < endX; x++)
+ {
+ Image *img = getTile(x, y);
+ if (img) {
+ const int px = (x + mX) * 32 - scrollX;
+ const int py = (y + mY) * 32 - scrollY + 32 - img->getHeight();
+ graphics->drawImage(img, px, py);
+ }
+ }
+ }
+
+ // Draw any remaining sprites
+ if (mIsFringeLayer) {
+ while (si != sprites.end()) {
+ (*si)->draw(graphics, -scrollX, -scrollY);
+ si++;
+ }
+ }
+}
+
Map::Map(int width, int height, int tileWidth, int tileHeight):
mWidth(width), mHeight(height),
mTileWidth(tileWidth), mTileHeight(tileHeight),
@@ -69,22 +146,17 @@ Map::Map(int width, int height, int tileWidth, int tileHeight):
mOnClosedList(1), mOnOpenList(2),
mLastScrollX(0.0f), mLastScrollY(0.0f)
{
- int size = mWidth * mHeight;
+ const int size = mWidth * mHeight;
mMetaTiles = new MetaTile[size];
- mTiles = new Image*[size * 3];
- std::fill_n(mTiles, size * 3, (Image*)0);
}
Map::~Map()
{
- // clean up map data
+ // delete metadata, layers, tilesets and overlays
delete[] mMetaTiles;
- delete[] mTiles;
- // clean up tilesets
+ for_each(mLayers.begin(), mLayers.end(), make_dtor(mLayers));
for_each(mTilesets.begin(), mTilesets.end(), make_dtor(mTilesets));
- mTilesets.clear();
- // clean up overlays
for_each(mOverlays.begin(), mOverlays.end(), make_dtor(mOverlays));
}
@@ -99,9 +171,9 @@ void Map::initializeOverlays()
const std::string name = "overlay" + toString(i);
Image *img = resman->getImage(getProperty(name + "image"));
- float speedX = getFloatProperty(name + "scrollX");
- float speedY = getFloatProperty(name + "scrollY");
- float parallax = getFloatProperty(name + "parallax");
+ const float speedX = getFloatProperty(name + "scrollX");
+ const float speedY = getFloatProperty(name + "scrollY");
+ const float parallax = getFloatProperty(name + "parallax");
if (img)
{
@@ -114,6 +186,11 @@ void Map::initializeOverlays()
}
}
+void Map::addLayer(MapLayer *layer)
+{
+ mLayers.push_back(layer);
+}
+
void Map::addTileset(Tileset *tileset)
{
mTilesets.push_back(tileset);
@@ -127,63 +204,31 @@ bool spriteCompare(const Sprite *a, const Sprite *b)
return a->getPixelY() < b->getPixelY();
}
-void Map::draw(Graphics *graphics, int scrollX, int scrollY, int layer)
+void Map::draw(Graphics *graphics, int scrollX, int scrollY)
{
int endPixelY = graphics->getHeight() + scrollY + mTileHeight - 1;
- // If drawing the fringe layer, make sure sprites are sorted
- SpriteIterator si;
- if (layer == 1)
- {
- mSprites.sort(spriteCompare);
- si = mSprites.begin();
- endPixelY += mMaxTileHeight - mTileHeight;
- }
+ // TODO: Do this per-layer
+ endPixelY += mMaxTileHeight - mTileHeight;
int startX = scrollX / mTileWidth;
int startY = scrollY / mTileHeight;
int endX = (graphics->getWidth() + scrollX + mTileWidth - 1) / mTileWidth;
int endY = endPixelY / mTileHeight;
- if (startX < 0) startX = 0;
- if (startY < 0) startY = 0;
- if (endX > mWidth) endX = mWidth;
- if (endY > mHeight) endY = mHeight;
+ // Make sure sprites are sorted
+ mSprites.sort(spriteCompare);
- for (int y = startY; y < endY; y++)
- {
- // If drawing the fringe layer, make sure all sprites above this row of
- // tiles have been drawn
- if (layer == 1)
- {
- while (si != mSprites.end() && (*si)->getPixelY() <= y * 32 - 32)
- {
- (*si)->draw(graphics, -scrollX, -scrollY);
- si++;
- }
- }
-
- for (int x = startX; x < endX; x++)
- {
- Image *img = getTile(x, y, layer);
- if (img) {
- graphics->drawImage(img,
- x * mTileWidth - scrollX,
- y * mTileHeight - scrollY +
- mTileHeight - img->getHeight());
- }
- }
+ Layers::const_iterator layeri = mLayers.begin();
+ for (; layeri != mLayers.end(); ++layeri) {
+ (*layeri)->draw(graphics,
+ startX, startY, endX, endY,
+ scrollX, scrollY,
+ mSprites);
}
- // Draw any remaining sprites
- if (layer == 1)
- {
- while (si != mSprites.end())
- {
- (*si)->draw(graphics, -scrollX, -scrollY);
- si++;
- }
- }
+ drawOverlay(graphics, scrollX, scrollY,
+ (int) config.getValue("OverlayDetail", 2));
}
void Map::drawOverlay(Graphics *graphics,
@@ -226,23 +271,10 @@ void Map::drawOverlay(Graphics *graphics,
};
}
-void Map::setTileWithGid(int x, int y, int layer, int gid)
-{
- if (layer == 3)
- {
- Tileset *set = getTilesetWithGid(gid);
- setWalk(x, y, (!set || (gid - set->getFirstGid() == 0)));
- }
- else if (layer < 3)
- {
- setTile(x, y, layer, getTileWithGid(gid));
- }
-}
-
class ContainsGidFunctor
{
public:
- bool operator() (Tileset* set)
+ bool operator() (const Tileset* set) const
{
return (set->getFirstGid() <= gid &&
gid - set->getFirstGid() < (int)set->size());
@@ -260,17 +292,6 @@ Tileset* Map::getTilesetWithGid(int gid) const
return (i == mTilesets.end()) ? NULL : *i;
}
-Image* Map::getTileWithGid(int gid) const
-{
- Tileset *set = getTilesetWithGid(gid);
-
- if (set) {
- return set->get(gid - set->getFirstGid());
- }
-
- return NULL;
-}
-
void Map::setWalk(int x, int y, bool walkable)
{
mMetaTiles[x + y * mWidth].walkable = walkable;
@@ -301,16 +322,6 @@ bool Map::contains(int x, int y) const
return x >= 0 && y >= 0 && x < mWidth && y < mHeight;
}
-void Map::setTile(int x, int y, int layer, Image *img)
-{
- mTiles[x + y * mWidth + layer * (mWidth * mHeight)] = img;
-}
-
-Image* Map::getTile(int x, int y, int layer)
-{
- return mTiles[x + y * mWidth + layer * (mWidth * mHeight)];
-}
-
MetaTile* Map::getMetaTile(int x, int y)
{
return &mMetaTiles[x + y * mWidth];
@@ -367,8 +378,8 @@ Path Map::findPath(int startX, int startY, int destX, int destY)
for (int dx = -1; dx <= 1; dx++)
{
// Calculate location of tile to check
- int x = curr.x + dx;
- int y = curr.y + dy;
+ const int x = curr.x + dx;
+ const int y = curr.y + dy;
// Skip if if we're checking the same tile we're leaving from,
// or if the new location falls outside of the map boundaries
@@ -379,7 +390,8 @@ Path Map::findPath(int startX, int startY, int destX, int destY)
MetaTile *newTile = getMetaTile(x, y);
- // Skip if the tile is on the closed list or collides unless its the destination tile
+ // Skip if the tile is on the closed list or collides unless
+ // its the destination tile
if (newTile->whichList == mOnClosedList ||
(tileCollides(x, y) && !(x == destX && y == destY)))
{
@@ -430,7 +442,7 @@ Path Map::findPath(int startX, int startY, int destX, int destY)
// Update Gcost and Fcost of new tile
newTile->Gcost = Gcost;
- newTile->Fcost = newTile->Gcost + newTile->Hcost;
+ newTile->Fcost = Gcost + newTile->Hcost;
if (x != destX || y != destY) {
// Add this tile to the open list
@@ -447,7 +459,7 @@ Path Map::findPath(int startX, int startY, int destX, int destY)
// Found a shorter route.
// Update Gcost and Fcost of the new tile
newTile->Gcost = Gcost;
- newTile->Fcost = newTile->Gcost + newTile->Hcost;
+ newTile->Fcost = Gcost + newTile->Hcost;
// Set the current tile as the parent of the new tile
newTile->parentX = curr.x;
@@ -488,7 +500,7 @@ Path Map::findPath(int startX, int startY, int destX, int destY)
return path;
}
-void Map::addParticleEffect (std::string effectFile, int x, int y)
+void Map::addParticleEffect(const std::string &effectFile, int x, int y)
{
ParticleEffectData newEffect;
newEffect.file = effectFile;
diff --git a/src/map.h b/src/map.h
index fab7bfb7..95532eb3 100644
--- a/src/map.h
+++ b/src/map.h
@@ -32,6 +32,7 @@
class AmbientOverlay;
class Graphics;
class Image;
+class MapLayer;
class Particle;
class Sprite;
class Tileset;
@@ -41,8 +42,7 @@ struct PATH_NODE;
typedef std::vector<Tileset*> Tilesets;
typedef std::list<Sprite*> Sprites;
typedef Sprites::iterator SpriteIterator;
-
-extern volatile int tick_time;
+typedef std::vector<MapLayer*> Layers;
/**
* A meta tile stores additional information about a location on a tile map.
@@ -67,6 +67,56 @@ struct MetaTile
};
/**
+ * A map layer. Stores a grid of tiles and their offset, and implements layer
+ * rendering.
+ */
+class MapLayer
+{
+ public:
+ /**
+ * Constructor, taking layer origin, size and whether this layer is the
+ * fringe layer. The fringe layer is the layer that draws the sprites.
+ * There can be only one fringe layer per map.
+ */
+ MapLayer(int x, int y, int width, int height, bool isFringeLayer);
+
+ /**
+ * Destructor.
+ */
+ ~MapLayer();
+
+ /**
+ * Set tile image, with x and y in layer coordinates.
+ */
+ void setTile(int x, int y, Image *img);
+
+ /**
+ * Get tile image, with x and y in layer coordinates.
+ */
+ Image *getTile(int x, int y) const;
+
+ /**
+ * Draws this layer to the given graphics context. The coordinates are
+ * expected to be in map range and will be translated to local layer
+ * coordinates and clipped to the layer's dimensions.
+ *
+ * The given sprites are only drawn when this layer is the fringe
+ * layer.
+ */
+ void draw(Graphics *graphics,
+ int startX, int startY,
+ int endX, int endY,
+ int scrollX, int scrollY,
+ const Sprites &sprites) const;
+
+ private:
+ int mX, mY;
+ int mWidth, mHeight;
+ bool mIsFringeLayer; /**< Whether the sprites are drawn. */
+ Image **mTiles;
+};
+
+/**
* A tile map.
*/
class Map : public Properties
@@ -89,39 +139,30 @@ class Map : public Properties
void initializeOverlays();
/**
- * Draws a map layer to the given graphics output.
- */
- void draw(Graphics *graphics, int scrollX, int scrollY, int layer);
-
- /**
- * Draws the overlay graphic to the given graphics output.
- */
- void
- drawOverlay(Graphics *graphics, float scrollX, float scrollY,
- int detail);
-
- /**
- * Adds a tileset to this map.
+ * Draws the map to the given graphics output. This method draws all
+ * layers, sprites and overlay effects.
+ *
+ * TODO: For efficiency reasons, this method could take into account
+ * the clipping rectangle set on the Graphics object. However,
+ * currently the map is always drawn full-screen.
*/
- void
- addTileset(Tileset *tileset);
+ void draw(Graphics *graphics, int scrollX, int scrollY);
/**
- * Sets a tile using a global tile id. Used by the layer loading
- * routine.
+ * Adds a layer to this map. The map takes ownership of the layer.
*/
- void
- setTileWithGid(int x, int y, int layer, int gid);
+ void addLayer(MapLayer *layer);
/**
- * Set tile ID.
+ * Adds a tileset to this map. The map takes ownership of the tileset.
*/
- void setTile(int x, int y, int layer, Image *img);
+ void addTileset(Tileset *tileset);
/**
- * Get tile ID.
+ * Finds the tile set that a tile with the given global id is part of.
*/
- Image *getTile(int x, int y, int layer);
+ Tileset*
+ getTilesetWithGid(int gid) const;
/**
* Get tile reference.
@@ -183,7 +224,7 @@ class Map : public Properties
/**
* Adds a particle effect
*/
- void addParticleEffect (std::string effectFile, int x, int y);
+ void addParticleEffect(const std::string &effectFile, int x, int y);
/**
* Initializes all added particle effects
@@ -193,15 +234,11 @@ class Map : public Properties
private:
/**
- * Converts a global tile id to the Image* pointing to the associated
- * tile image.
- */
- Image* getTileWithGid(int gid) const;
-
- /**
- * Finds the tile set that a tile with the given global id is part of.
+ * Draws the overlay graphic to the given graphics output.
*/
- Tileset* getTilesetWithGid(int gid) const;
+ void
+ drawOverlay(Graphics *graphics, float scrollX, float scrollY,
+ int detail);
/**
* Tells whether a tile is occupied by a being.
@@ -217,15 +254,14 @@ class Map : public Properties
int mTileWidth, mTileHeight;
int mMaxTileHeight;
MetaTile *mMetaTiles;
- Image **mTiles;
-
+ Layers mLayers;
Tilesets mTilesets;
Sprites mSprites;
// Pathfinding members
int mOnClosedList, mOnOpenList;
- // Overlay Data
+ // Overlay data
std::list<AmbientOverlay*> mOverlays;
float mLastScrollX;
float mLastScrollY;
diff --git a/src/resources/imageset.cpp b/src/resources/imageset.cpp
index 4b6dd592..1a753648 100644
--- a/src/resources/imageset.cpp
+++ b/src/resources/imageset.cpp
@@ -50,7 +50,7 @@ ImageSet::~ImageSet()
}
Image*
-ImageSet::get(size_type i)
+ImageSet::get(size_type i) const
{
if (i >= mImages.size())
{
diff --git a/src/resources/imageset.h b/src/resources/imageset.h
index 15c21d90..fa1840ec 100644
--- a/src/resources/imageset.h
+++ b/src/resources/imageset.h
@@ -47,14 +47,20 @@ class ImageSet : public Resource
*/
~ImageSet();
- int getWidth() { return mWidth; };
+ /**
+ * Returns the width of the images in the image set.
+ */
+ int getWidth() const { return mWidth; };
- int getHeight() { return mHeight; };
+ /**
+ * Returns the height of the images in the image set.
+ */
+ int getHeight() const { return mHeight; };
typedef std::vector<Image*>::size_type size_type;
- Image* get(size_type i);
+ Image* get(size_type i) const;
- size_type size() { return mImages.size(); }
+ size_type size() const { return mImages.size(); }
private:
std::vector<Image*> mImages;
diff --git a/src/resources/mapreader.cpp b/src/resources/mapreader.cpp
index 2a080fb0..328b66e0 100644
--- a/src/resources/mapreader.cpp
+++ b/src/resources/mapreader.cpp
@@ -206,20 +206,17 @@ MapReader::readMap(const std::string &filename)
Map*
MapReader::readMap(xmlNodePtr node, const std::string &path)
{
- xmlChar *prop;
-
// Take the filename off the path
- std::string pathDir = path.substr(0, path.rfind("/") + 1);
+ const std::string pathDir = path.substr(0, path.rfind("/") + 1);
- prop = xmlGetProp(node, BAD_CAST "version");
- xmlFree(prop);
+ //xmlChar *prop = xmlGetProp(node, BAD_CAST "version");
+ //xmlFree(prop);
- int w = XML::getProperty(node, "width", 0);
- int h = XML::getProperty(node, "height", 0);
- int tilew = XML::getProperty(node, "tilewidth", DEFAULT_TILE_WIDTH);
- int tileh = XML::getProperty(node, "tileheight", DEFAULT_TILE_HEIGHT);
- int layerNr = 0;
- Map *map = new Map(w, h, tilew, tileh);
+ const int w = XML::getProperty(node, "width", 0);
+ const int h = XML::getProperty(node, "height", 0);
+ const int tw = XML::getProperty(node, "tilewidth", DEFAULT_TILE_WIDTH);
+ const int th = XML::getProperty(node, "tileheight", DEFAULT_TILE_HEIGHT);
+ Map *map = new Map(w, h, tw, th);
for_each_xml_child_node(childNode, node)
{
@@ -232,9 +229,7 @@ MapReader::readMap(xmlNodePtr node, const std::string &path)
}
else if (xmlStrEqual(childNode->name, BAD_CAST "layer"))
{
- logger->log("- Loading layer %d", layerNr);
- readLayer(childNode, map, layerNr);
- layerNr++;
+ readLayer(childNode, map);
}
else if (xmlStrEqual(childNode->name, BAD_CAST "properties"))
{
@@ -246,15 +241,31 @@ MapReader::readMap(xmlNodePtr node, const std::string &path)
{
if (xmlStrEqual(objectNode->name, BAD_CAST "object"))
{
- std::string objName = XML::getProperty(objectNode, "name", "");
- std::string objType = XML::getProperty(objectNode, "type", "");
- int objX = XML::getProperty(objectNode, "x", 0);
- int objY = XML::getProperty(objectNode, "y", 0);
+ const std::string objType =
+ XML::getProperty(objectNode, "type", "");
+
+ if (objType == "WARP" || objType == "NPC" ||
+ objType == "SCRIPT" || objType == "SPAWN")
+ {
+ // Silently skip server-side objects.
+ continue;
+ }
+
+ const std::string objName =
+ XML::getProperty(objectNode, "name", "");
+ const int objX = XML::getProperty(objectNode, "x", 0);
+ const int objY = XML::getProperty(objectNode, "y", 0);
logger->log("- Loading object name: %s type: %s at %d:%d",
objName.c_str(), objType.c_str(), objX, objY);
+
if (objType == "PARTICLE_EFFECT")
{
+ if (objName.empty()) {
+ logger->log(" Warning: No particle file given");
+ continue;
+ }
+
map->addParticleEffect(objName, objX, objY);
}
else
@@ -280,43 +291,66 @@ MapReader::readProperties(xmlNodePtr node, Properties* props)
continue;
// Example: <property name="name" value="value"/>
- xmlChar *name = xmlGetProp(childNode, BAD_CAST "name");
- xmlChar *value = xmlGetProp(childNode, BAD_CAST "value");
+ const std::string name = XML::getProperty(childNode, "name", "");
+ const std::string value = XML::getProperty(childNode, "value", "");
- if (name && value) {
- props->setProperty((const char*)name, (const char*)value);
- }
+ if (!name.empty() && !value.empty())
+ props->setProperty(name, value);
+ }
+}
- if (name) xmlFree(name);
- if (value) xmlFree(value);
+static void setTile(Map *map, MapLayer *layer, int x, int y, int gid)
+{
+ const Tileset * const set = map->getTilesetWithGid(gid);
+ if (layer) {
+ // Set regular tile on a layer
+ Image * const img = set ? set->get(gid - set->getFirstGid()) : 0;
+ layer->setTile(x, y, img);
+ } else {
+ // Set collision tile
+ map->setWalk(x, y, (!set || (gid - set->getFirstGid() == 0)));
}
}
void
-MapReader::readLayer(xmlNodePtr node, Map *map, int layer)
+MapReader::readLayer(xmlNodePtr node, Map *map)
{
- int h = map->getHeight();
- int w = map->getWidth();
+ // Layers are not necessarily the same size as the map
+ const int w = XML::getProperty(node, "width", map->getWidth());
+ const int h = XML::getProperty(node, "height", map->getHeight());
+ const int offsetX = XML::getProperty(node, "xoffset", 0);
+ const int offsetY = XML::getProperty(node, "yoffset", 0);
+ const std::string name = XML::getProperty(node, "name", "");
+
+ const bool isFringeLayer = (name == "Fringe");
+ const bool isCollisionLayer = (name == "Collision");
+
+ MapLayer *layer = 0;
+
+ if (!isCollisionLayer) {
+ layer = new MapLayer(offsetX, offsetY, w, h, isFringeLayer);
+ map->addLayer(layer);
+ }
+
+ logger->log("- Loading layer \"%s\"", name.c_str());
int x = 0;
int y = 0;
- // Load the tile data. Layers are assumed to be map size, with (0,0) as
- // origin.
+ // Load the tile data
for_each_xml_child_node(childNode, node)
{
if (!xmlStrEqual(childNode->name, BAD_CAST "data"))
continue;
- xmlChar *encoding = xmlGetProp(childNode, BAD_CAST "encoding");
- xmlChar *compression = xmlGetProp(childNode, BAD_CAST "compression");
+ const std::string encoding =
+ XML::getProperty(childNode, "encoding", "");
+ const std::string compression =
+ XML::getProperty(childNode, "compression", "");
- if (encoding && xmlStrEqual(encoding, BAD_CAST "base64"))
+ if (encoding == "base64")
{
- xmlFree(encoding);
-
- if (compression && !xmlStrEqual(compression, BAD_CAST "gzip")) {
+ if (!compression.empty() && compression != "gzip") {
logger->log("Warning: only gzip layer compression supported!");
- xmlFree(compression);
return;
}
@@ -348,34 +382,29 @@ MapReader::readLayer(xmlNodePtr node, Map *map, int layer)
delete[] charData;
if (binData) {
- if (compression) {
- if (xmlStrEqual(compression, BAD_CAST "gzip")) {
- // Inflate the gzipped layer data
- unsigned char *inflated;
- unsigned int inflatedSize =
- inflateMemory(binData, binLen, inflated);
-
- free(binData);
- binData = inflated;
- binLen = inflatedSize;
-
- if (inflated == NULL)
- {
- logger->log("Error: Could not decompress layer!");
- xmlFree(compression);
- return;
- }
+ if (compression == "gzip") {
+ // Inflate the gzipped layer data
+ unsigned char *inflated;
+ unsigned int inflatedSize =
+ inflateMemory(binData, binLen, inflated);
+
+ free(binData);
+ binData = inflated;
+ binLen = inflatedSize;
+
+ if (!inflated) {
+ logger->log("Error: Could not decompress layer!");
+ return;
}
- xmlFree(compression);
}
for (int i = 0; i < binLen - 3; i += 4) {
- int gid = binData[i] |
+ const int gid = binData[i] |
binData[i + 1] << 8 |
binData[i + 2] << 16 |
binData[i + 3] << 24;
- map->setTileWithGid(x, y, layer, gid);
+ setTile(map, layer, x, y, gid);
x++;
if (x == w) {x = 0; y++;}
@@ -390,8 +419,8 @@ MapReader::readLayer(xmlNodePtr node, Map *map, int layer)
if (!xmlStrEqual(childNode2->name, BAD_CAST "tile"))
continue;
- int gid = XML::getProperty(childNode2, "gid", -1);
- map->setTileWithGid(x, y, layer, gid);
+ const int gid = XML::getProperty(childNode2, "gid", -1);
+ setTile(map, layer, x, y, gid);
x++;
if (x == w) {
@@ -423,20 +452,20 @@ MapReader::readTileset(xmlNodePtr node,
return NULL;
}
- int firstGid = XML::getProperty(node, "firstgid", 0);
- int tw = XML::getProperty(node, "tilewidth", map->getTileWidth());
- int th = XML::getProperty(node, "tileheight", map->getTileHeight());
+ const int firstGid = XML::getProperty(node, "firstgid", 0);
+ const int tw = XML::getProperty(node, "tilewidth", map->getTileWidth());
+ const int th = XML::getProperty(node, "tileheight", map->getTileHeight());
for_each_xml_child_node(childNode, node)
{
if (!xmlStrEqual(childNode->name, BAD_CAST "image"))
continue;
- xmlChar* source = xmlGetProp(childNode, BAD_CAST "source");
+ const std::string source = XML::getProperty(childNode, "source", "");
- if (source)
+ if (!source.empty())
{
- std::string sourceStr = std::string((const char*)source);
+ std::string sourceStr = source;
sourceStr.erase(0, 3); // Remove "../"
ResourceManager *resman = ResourceManager::getInstance();
@@ -446,14 +475,15 @@ MapReader::readTileset(xmlNodePtr node,
{
Tileset *set = new Tileset(tilebmp, tw, th, firstGid);
tilebmp->decRef();
- xmlFree(source);
return set;
}
else {
- logger->log("Warning: Failed to load tileset (%s)", source);
+ logger->log("Warning: Failed to load tileset (%s)",
+ source.c_str());
}
}
+ // Only one image element expected
break;
}
diff --git a/src/resources/mapreader.h b/src/resources/mapreader.h
index d16ff1d5..60056358 100644
--- a/src/resources/mapreader.h
+++ b/src/resources/mapreader.h
@@ -63,10 +63,10 @@ class MapReader
readProperties(xmlNodePtr node, Properties* props);
/**
- * Reads a map layer.
+ * Reads a map layer and adds it to the given map.
*/
static void
- readLayer(xmlNodePtr node, Map *map, int layer);
+ readLayer(xmlNodePtr node, Map *map);
/**
* Reads a tile set.
diff --git a/src/resources/spritedef.cpp b/src/resources/spritedef.cpp
index 334474d7..ebc60240 100644
--- a/src/resources/spritedef.cpp
+++ b/src/resources/spritedef.cpp
@@ -70,33 +70,8 @@ SpriteDef *SpriteDef::load(std::string const &animationFile, int variant)
}
}
- // Get the variant
- int variant_num = XML::getProperty(rootNode, "variants", 0);
- int variant_offset = 0;
-
- if (variant_num > 0 && variant < variant_num)
- {
- variant_offset = variant * XML::getProperty(rootNode, "variant_offset", 0);
- }
-
SpriteDef *def = new SpriteDef;
-
- for_each_xml_child_node(node, rootNode)
- {
- if (xmlStrEqual(node->name, BAD_CAST "imageset"))
- {
- def->loadImageSet(node, palettes);
- }
- else if (xmlStrEqual(node->name, BAD_CAST "action"))
- {
- def->loadAction(node, variant_offset);
- }
- else if (xmlStrEqual(node->name, BAD_CAST "include"))
- {
- def->includeSprite(node);
- }
- }
-
+ def->loadSprite(rootNode, variant, palettes);
def->substituteActions();
return def;
}
@@ -119,11 +94,47 @@ void SpriteDef::substituteActions()
substituteAction(ACTION_DEAD, ACTION_HURT);
}
+void SpriteDef::loadSprite(xmlNodePtr spriteNode, int variant,
+ const std::string &palettes)
+{
+ // Get the variant
+ const int variantCount = XML::getProperty(spriteNode, "variants", 0);
+ int variant_offset = 0;
+
+ if (variantCount > 0 && variant < variantCount)
+ {
+ variant_offset =
+ variant * XML::getProperty(spriteNode, "variant_offset", 0);
+ }
+
+ for_each_xml_child_node(node, spriteNode)
+ {
+ if (xmlStrEqual(node->name, BAD_CAST "imageset"))
+ {
+ loadImageSet(node, palettes);
+ }
+ else if (xmlStrEqual(node->name, BAD_CAST "action"))
+ {
+ loadAction(node, variant_offset);
+ }
+ else if (xmlStrEqual(node->name, BAD_CAST "include"))
+ {
+ includeSprite(node);
+ }
+ }
+}
+
void SpriteDef::loadImageSet(xmlNodePtr node, std::string const &palettes)
{
- int width = XML::getProperty(node, "width", 0);
- int height = XML::getProperty(node, "height", 0);
- std::string name = XML::getProperty(node, "name", "");
+ const std::string name = XML::getProperty(node, "name", "");
+
+ // We don't allow redefining image sets. This way, an included sprite
+ // definition will use the already loaded image set with the same name.
+ if (mImageSets.find(name) != mImageSets.end())
+ return;
+
+ const int width = XML::getProperty(node, "width", 0);
+ const int height = XML::getProperty(node, "height", 0);
std::string imageSrc = XML::getProperty(node, "src", "");
Dye::instantiate(imageSrc, palettes);
@@ -184,9 +195,9 @@ SpriteDef::loadAnimation(xmlNodePtr animationNode,
Action *action, ImageSet *imageSet,
int variant_offset)
{
- std::string directionName =
+ const std::string directionName =
XML::getProperty(animationNode, "direction", "");
- SpriteDirection directionType = makeSpriteDirection(directionName);
+ const SpriteDirection directionType = makeSpriteDirection(directionName);
if (directionType == DIRECTION_INVALID)
{
@@ -201,7 +212,7 @@ SpriteDef::loadAnimation(xmlNodePtr animationNode,
// Get animation frames
for_each_xml_child_node(frameNode, animationNode)
{
- int delay = XML::getProperty(frameNode, "delay", 0);
+ const int delay = XML::getProperty(frameNode, "delay", 0);
int offsetX = XML::getProperty(frameNode, "offsetX", 0);
int offsetY = XML::getProperty(frameNode, "offsetY", 0);
offsetY -= imageSet->getHeight() - 32;
@@ -209,7 +220,7 @@ SpriteDef::loadAnimation(xmlNodePtr animationNode,
if (xmlStrEqual(frameNode->name, BAD_CAST "frame"))
{
- int index = XML::getProperty(frameNode, "index", -1);
+ const int index = XML::getProperty(frameNode, "index", -1);
if (index < 0)
{
@@ -230,7 +241,7 @@ SpriteDef::loadAnimation(xmlNodePtr animationNode,
else if (xmlStrEqual(frameNode->name, BAD_CAST "sequence"))
{
int start = XML::getProperty(frameNode, "start", -1);
- int end = XML::getProperty(frameNode, "end", -1);
+ const int end = XML::getProperty(frameNode, "end", -1);
if (start < 0 || end < 0)
{
@@ -263,12 +274,23 @@ SpriteDef::loadAnimation(xmlNodePtr animationNode,
void
SpriteDef::includeSprite(xmlNodePtr includeNode)
{
+ // TODO: Perform circular dependency check, since it's easy to crash the
+ // client this way.
const std::string filename = XML::getProperty(includeNode, "file", "");
- ResourceManager *resman = ResourceManager::getInstance();
- SpriteDef *sprite = resman->getSprite("graphics/sprites/" + filename);
- // TODO: Somehow implement actually including it
- sprite->decRef();
+ if (filename.empty())
+ return;
+
+ XML::Document doc("graphics/sprites/" + filename);
+ xmlNodePtr rootNode = doc.rootNode();
+
+ if (!rootNode || !xmlStrEqual(rootNode->name, BAD_CAST "sprite"))
+ {
+ logger->log("Error, no sprite root node in %s", filename.c_str());
+ return;
+ }
+
+ loadSprite(rootNode, 0);
}
void
diff --git a/src/resources/spritedef.h b/src/resources/spritedef.h
index 531dfb3d..72c2566f 100644
--- a/src/resources/spritedef.h
+++ b/src/resources/spritedef.h
@@ -92,6 +92,12 @@ class SpriteDef : public Resource
~SpriteDef();
/**
+ * Loads a sprite element.
+ */
+ void loadSprite(xmlNodePtr spriteNode, int variant,
+ const std::string &palettes = "");
+
+ /**
* Loads an imageset element.
*/
void loadImageSet(xmlNodePtr node, std::string const &palettes);
diff --git a/src/tileset.h b/src/tileset.h
index 6af69235..625fac1b 100644
--- a/src/tileset.h
+++ b/src/tileset.h
@@ -44,8 +44,7 @@ class Tileset : public ImageSet
/**
* Returns the first gid.
*/
- int
- getFirstGid()
+ int getFirstGid() const
{
return mFirstGid;
}