44 const std::string &path,
47static void readTileAnimation(
XML::Node tileNode,
52static std::string resolveRelativePath(std::string base, std::string relative)
55 size_t i = base.length();
56 if (base.at(i - 1) ==
'/')
59 while (relative.substr(0, 3) ==
"../")
64 i = base.find_last_of(
'/');
65 if (i == std::string::npos)
67 base.erase(i, base.length());
72 if (!base.empty() && base[base.length() - 1] !=
'/')
75 return base + relative;
80 Log::info(
"Attempting to read map %s", filename.c_str());
90 if (node.
name() !=
"map")
92 Log::error(
"Not a map file (%s)!", filename.c_str());
101 Log::info(
"Error while parsing map file (%s)!", filename.c_str());
113 const std::string pathDir = path.substr(0, path.rfind(
"/") + 1);
117 const int tilew = node.
getProperty(
"tilewidth", -1);
118 const int tileh = node.
getProperty(
"tileheight", -1);
120 if (tilew < 0 || tileh < 0)
123 "Unitialized tile width or height value for map: %s",
128 Map *map =
new Map(w, h, tilew, tileh);
130 for (
auto childNode : node.
children())
132 if (childNode.name() ==
"tileset")
134 Tileset *tileset = readTileset(childNode, pathDir, map);
140 else if (childNode.name() ==
"layer")
142 readLayer(childNode, map);
144 else if (childNode.name() ==
"properties")
146 readProperties(childNode, map);
148 else if (childNode.name() ==
"objectgroup")
151 const int tileOffsetX = childNode.getProperty(
"x", 0);
152 const int tileOffsetY = childNode.getProperty(
"y", 0);
153 const int offsetX = tileOffsetX * tilew;
154 const int offsetY = tileOffsetY * tileh;
156 for (
auto objectNode : childNode.children())
158 if (objectNode.name() ==
"object")
160 std::string objType = objectNode.getProperty(
"type",
"");
163 if (objType ==
"NPC" ||
164 objType ==
"SCRIPT" ||
171 const std::string objName = objectNode.getProperty(
"name",
"");
172 const int objX = objectNode.getProperty(
"x", 0);
173 const int objY = objectNode.getProperty(
"y", 0);
174 const int objW = objectNode.getProperty(
"width", 0);
175 const int objH = objectNode.getProperty(
"height", 0);
177 Log::info(
"- Loading object name: %s type: %s at %d:%d",
178 objName.c_str(), objType.c_str(),
181 if (objType ==
"PARTICLE_EFFECT")
185 Log::info(
" Warning: No particle file given");
194 else if (objType ==
"WARP")
201 objX, objY, objW, objH);
206 Log::info(
" Warning: Unknown object type");
227 for (
auto childNode : node.children())
229 if (childNode.name() !=
"property")
233 const std::string name = childNode.getProperty(
"name",
"");
234 const std::string value = childNode.getProperty(
"value",
"");
236 if (!name.empty() && !value.empty())
241static void setTile(
Map *map,
MapLayer *layer,
int x,
int y,
unsigned gid)
244 const int FlippedHorizontallyFlag = 0x80000000;
245 const int FlippedVerticallyFlag = 0x40000000;
246 const int FlippedAntiDiagonallyFlag = 0x20000000;
250 gid &= ~(FlippedHorizontallyFlag |
251 FlippedVerticallyFlag |
252 FlippedAntiDiagonallyFlag);
262 ani->addAffectedTile(layer, x + y * layer->
getWidth());
285 const bool isFringeLayer = (name.substr(0,6) ==
"fringe");
286 const bool isCollisionLayer = (name.substr(0,9) ==
"collision");
290 if (!isCollisionLayer)
292 layer =
new MapLayer(offsetX, offsetY, w, h, isFringeLayer, map);
296 Log::info(
"- Loading layer \"%s\"", name.c_str());
301 for (
auto childNode : node.children())
303 if (childNode.name() ==
"properties")
305 for (
auto prop : childNode.children())
307 if (prop.name() !=
"property")
310 const std::string pname = prop.getProperty(
"name",
"");
311 const std::string value = prop.getProperty(
"value",
"");
317 layer->
setMask(atoi(value.c_str()));
323 if (childNode.name() !=
"data")
326 const std::string encoding =
327 childNode.getProperty(
"encoding",
"");
328 const std::string compression =
329 childNode.getProperty(
"compression",
"");
331 if (encoding ==
"base64")
333 if (!compression.empty() && compression !=
"gzip"
334 && compression !=
"zlib")
337 "compression supported!");
342 const auto data = childNode.textContent();
346 auto *charStart = data.data();
347 auto *charData =
new unsigned char[data.length() + 1];
348 unsigned char *charIndex = charData;
352 if (*charStart !=
' ' &&
353 *charStart !=
'\t' &&
356 *charIndex = *charStart;
364 unsigned char *binData =
366 charIndex - charData,
373 if (compression ==
"gzip" || compression ==
"zlib")
376 unsigned char *inflated;
377 unsigned int inflatedSize =
382 binLen = inflatedSize;
391 for (
int i = 0; i < binLen - 3; i += 4)
393 const unsigned gid = binData[i] |
394 binData[i + 1] << 8 |
395 binData[i + 2] << 16 |
396 binData[i + 3] << 24;
398 setTile(map, layer, x, y, gid);
413 else if (encoding ==
"csv")
415 const auto data = childNode.textContent();
422 auto *pos = data.data();
429 unsigned gid = strtol(pos, &end, 10);
435 Log::error(
"Range error in tile layer data!");
439 setTile(map, layer, x, y, gid);
452 pos = strchr(end,
',');
464 for (
auto childNode2 : childNode.children())
466 if (childNode2.name() !=
"tile")
469 unsigned gid = childNode2.getProperty(
"gid", 0);
470 setTile(map, layer, x, y, gid);
483 std::cerr <<
"TOO SMALL!\n";
485 std::cerr <<
"TOO SMALL!\n";
498 const unsigned firstGid = node.
getProperty(
"firstgid", 0);
500 const int spacing = node.
getProperty(
"spacing", 0);
503 std::string pathDir(path);
507 std::string filename = node.
getProperty(
"source", std::string());
508 filename = resolveRelativePath(path, filename);
514 pathDir = filename.substr(0, filename.rfind(
"/") + 1);
520 for (
auto childNode : node.children())
522 if (childNode.name() ==
"image")
524 const auto source = childNode.getProperty(
"source", std::string());
527 std::string sourceStr = resolveRelativePath(pathDir, source);
530 auto tilebmp = resman->
getImage(sourceStr);
534 set =
new Tileset(tilebmp, tw, th, firstGid, margin,
539 Log::warn(
"Failed to load tileset (%s)", source.c_str());
543 else if (set && childNode.name() ==
"tile")
545 const int tileGID = firstGid + childNode.getProperty(
"id", 0);
547 for (
auto tileNode : childNode.children())
549 if (tileNode.name() ==
"animation")
550 readTileAnimation(tileNode, set, tileGID, map);
560static void readTileAnimation(
XML::Node tileNode,
566 for (
auto frameNode : tileNode.children())
568 if (frameNode.name() ==
"frame")
570 const int tileId = frameNode.getProperty(
"tileid", 0);
571 const int duration = frameNode.getProperty(
"duration", 0);
unsigned char * php3_base64_decode(const unsigned char *string, int length, int *ret_length)
An animation consists of several frames, each with their own delay and offset.
int getLength() const
Returns the length of this animation in frames.
void addFrame(Image *image, int delay, int offsetX, int offsetY)
Appends a new animation at the end of the sequence.
std::string getStringValue(const std::string &key) const
Image * get(size_t i) const
Defines a class for loading and storing images.
void setTile(int x, int y, Image *img)
Set tile image, with x and y in layer coordinates.
static Map * readMap(const std::string &filename)
Read an XML map from a file.
TileAnimation * getAnimationForGid(int gid)
Gets the tile animation for a specific gid.
int getHeight() const
Returns the height of this map in tiles.
int getTileHeight() const
Returns the tile height used by this map.
void addLayer(MapLayer *layer)
Adds a layer to this map.
void addAnimation(int gid, TileAnimation animation)
Adds a tile animation to the map.
int getWidth() const
Returns the width of this map in tiles.
void initializeAmbientLayers()
Initialize ambient layers.
int getTileWidth() const
Returns the tile width of this map.
void blockTile(int x, int y, BlockType type)
Marks a tile as occupied.
Tileset * getTilesetWithGid(unsigned gid) const
Finds the tile set that a tile with the given global id is part of.
void addTileset(Tileset *tileset)
Adds a tileset to this map.
void addParticleEffect(const std::string &effectFile, int x, int y, int w=0, int h=0)
Adds a particle effect.
A class holding a set of properties.
void setProperty(const std::string &name, const std::string &value)
Set a map property.
A class for loading and managing resources.
static ResourceManager * getInstance()
Returns an instance of the class, creating one if it does not already exist.
ResourceRef< Image > getImage(const std::string &idPath)
Loads the Image resource found at the given identifier path.
Animation cycle of a tile image which changes the map accordingly.
A tileset, which is basically just an image set but it stores a firstgid.
unsigned getFirstGid() const
Returns the first gid.
A helper class for parsing an XML document, which also cleans it up again (RAII).
Node rootNode() const
Returns the root node of the document (or NULL if there was a load error).
std::string_view name() const
int getProperty(const char *name, int def) const
Children children() const
bool hasAttribute(const char *name) const
Config config
Global settings (config.xml)
Configuration paths
XML default paths information reader.
void warn(const char *log_text,...) LOG_PRINTF_ATTR
void info(const char *log_text,...) LOG_PRINTF_ATTR
void error(const char *log_text,...) LOG_PRINTF_ATTR
std::string & toUpper(std::string &str)
Converts the given string to upper case.
std::string & toLower(std::string &str)
Converts the given string to lower case.
int inflateMemory(unsigned char *in, unsigned int inLength, unsigned char *&out, unsigned int &outLength)
Inflates either zlib or gzip deflated memory.