summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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;
}