diff options
-rw-r--r-- | ChangeLog | 24 | ||||
-rw-r--r-- | src/gui/viewport.cpp | 12 | ||||
-rw-r--r-- | src/log.h | 4 | ||||
-rw-r--r-- | src/map.cpp | 206 | ||||
-rw-r--r-- | src/map.h | 110 | ||||
-rw-r--r-- | src/resources/imageset.cpp | 2 | ||||
-rw-r--r-- | src/resources/imageset.h | 14 | ||||
-rw-r--r-- | src/resources/mapreader.cpp | 164 | ||||
-rw-r--r-- | src/resources/mapreader.h | 4 | ||||
-rw-r--r-- | src/resources/spritedef.cpp | 98 | ||||
-rw-r--r-- | src/resources/spritedef.h | 6 | ||||
-rw-r--r-- | src/tileset.h | 3 |
12 files changed, 388 insertions, 259 deletions
@@ -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++) { @@ -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; @@ -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; } |