diff --git a/src/framework/core/binarytree.h b/src/framework/core/binarytree.h index 9acb1b9e..ca479e49 100644 --- a/src/framework/core/binarytree.h +++ b/src/framework/core/binarytree.h @@ -25,6 +25,7 @@ #include "declarations.h" #include +#include enum { BINARYTREE_ESCAPE_CHAR = 0xFD, @@ -48,6 +49,8 @@ public: uint32 getU32(); uint64 getU64(); std::string getString(); + Position getPosition() { return Position(getU16(), getU16(), getU8()); } + Point getPoint() { return Point(getU8(), getU8()); } BinaryTreeVec getChildren(); bool canRead() { unserialize(); return m_pos < m_buffer.size(); } diff --git a/src/framework/stdext/string.h b/src/framework/stdext/string.h index 64a5c1c9..11594315 100644 --- a/src/framework/stdext/string.h +++ b/src/framework/stdext/string.h @@ -30,6 +30,7 @@ #include #include #include +#include #include "types.h" #include "cast.h" @@ -180,6 +181,11 @@ inline std::string ip_to_string(uint32 ip) { return std::string(host); } +inline std::string pos_to_string(const Position& p) +{ + return format("{x = %h, y = %h, z = %hh}", p.x, p.y, p.z); +} + /// Convert utf8 characters to latin1 inline char utf8CharToLatin1(uchar *utf8, int *read) { char c = '?'; diff --git a/src/framework/xml/tinyxml.h b/src/framework/xml/tinyxml.h index ac032e12..e7658db4 100644 --- a/src/framework/xml/tinyxml.h +++ b/src/framework/xml/tinyxml.h @@ -173,7 +173,7 @@ enum TiXmlEncoding TIXML_ENCODING_LEGACY }; -const TiXmlEncoding TIXML_DEFAULT_ENCODING = TIXML_ENCODING_UNKNOWN; +constexpr TiXmlEncoding TIXML_DEFAULT_ENCODING = TIXML_ENCODING_UNKNOWN; /** TiXmlBase is a base class for every class in TinyXml. It does little except to establish that TinyXml classes diff --git a/src/otclient/creatures.cpp b/src/otclient/creatures.cpp index 1eb92cf5..42b89fc4 100644 --- a/src/otclient/creatures.cpp +++ b/src/otclient/creatures.cpp @@ -62,7 +62,7 @@ void Creatures::loadNpcs(const std::string &folder) for(boost::filesystem::directory_iterator it(npcPath), end; it != end; ++it) { std::string f = it->path().string(); - if(boost::filesystem::is_directory(it->status()) && ((f.size() > 4 ? f.substr(f.size() - 4) : "") != ".xml")) + if(boost::filesystem::is_directory(it->status()) || ((f.size() > 4 ? f.substr(f.size() - 4) : "") != ".xml")) continue; loadCreatureBuffer(g_resources.loadFile(f)); @@ -78,15 +78,18 @@ void Creatures::loadCreatureBuffer(const std::string &buffer) TiXmlElement* root = doc.FirstChildElement(); if(!root || root->ValueStr() != "npc") - stdext::throw_exception(("invalid root tag name")); + stdext::throw_exception("invalid root tag name"); for(TiXmlElement* attrib = root->FirstChildElement(); attrib; attrib = attrib->NextSiblingElement()) { if(attrib->ValueStr() != "npc" && attrib->ValueStr() != "monster") stdext::throw_exception(stdext::format("invalid attribute '%s'", attrib->ValueStr())); CreatureTypePtr newType(nullptr); - m_loadCreatureBuffer(attrib, newType); + if(m_loadCreatureBuffer(attrib, newType)) + break; } + + doc.Clear(); } bool Creatures::m_loadCreatureBuffer(TiXmlElement* attrib, CreatureTypePtr& m) @@ -98,13 +101,17 @@ bool Creatures::m_loadCreatureBuffer(TiXmlElement* attrib, CreatureTypePtr& m) Outfit out; int32 type; + bool isTypeEx=false; if(!attrib->Attribute("type").empty()) type = attrib->readType("type"); - else + else { type = attrib->readType("typeex"); + isTypeEx = true; + } out.setId(type); - { + + if(!isTypeEx) { out.setHead(attrib->readType(("head"))); out.setBody(attrib->readType(("body"))); out.setLegs(attrib->readType(("legs"))); diff --git a/src/otclient/creatures.h b/src/otclient/creatures.h index c33f3d75..a4c5b88e 100644 --- a/src/otclient/creatures.h +++ b/src/otclient/creatures.h @@ -20,34 +20,40 @@ * THE SOFTWARE. */ -#ifndef MONSTERS_H -#define MONSTERS_H +#ifndef CREATURES_H +#define CREATURES_H #include "declarations.h" #include +#include #include "outfit.h" +enum CreatureAttributes : unsigned char +{ + CreatureAttribPos, + CreatureAttribName, + CreatureAttribOutfit, + CreatureAttribSpawnTime +}; + class CreatureType : public LuaObject { public: CreatureType() { } - CreatureType(const std::string& name) - : m_name(name) { } + CreatureType(const std::string& name) { setName(name); } - void setPos(const Position& pos) { m_pos = pos; } - void setName(const std::string& name) { m_name = name; } - void setOutfit(const Outfit& o) { m_outfit = o; } - void setSpawnTime(int spawnTime) { m_spawnTime = spawnTime; } + void setPos(const Position& pos) { m_attribs.set(CreatureAttribPos, pos); } + void setName(const std::string& name) { m_attribs.set(CreatureAttribName, name); } + void setOutfit(const Outfit& o) { m_attribs.set(CreatureAttribOutfit, o); } + void setSpawnTime(int spawnTime) { m_attribs.set(CreatureAttribSpawnTime, spawnTime); } - std::string getName() { return m_name; } - Position getPos() { return m_pos; } - Outfit getOutfit() { return m_outfit; } + std::string getName() { return m_attribs.get(CreatureAttribName); } + Position getPos() { return m_attribs.get(CreatureAttribPos); } + Outfit getOutfit() { return m_attribs.get(CreatureAttribOutfit); } + int getSpawnTime() { return m_attribs.get(CreatureAttribSpawnTime); } private: - Position m_pos; - std::string m_name; - Outfit m_outfit; - int m_spawnTime; + AttribStorage m_attribs; }; class Creatures @@ -55,7 +61,7 @@ class Creatures public: void clear() { m_creatures.clear(); } - void loadMonsters(const std::string& file); + void loadMonsters(const std::string& file); void loadSingleCreature(const std::string& file); void loadNpcs(const std::string& folder); void loadCreatureBuffer(const std::string& buffer); @@ -63,7 +69,7 @@ public: CreatureTypePtr getCreature(const std::string& name); CreatureTypePtr getCreature(const Position& pos); - bool isLoaded() const { return m_loaded; } + bool isLoaded() const { return m_loaded; } protected: bool m_loadCreatureBuffer(TiXmlElement* elem, CreatureTypePtr& m); diff --git a/src/otclient/houses.h b/src/otclient/houses.h index 12185d23..a0c2cfbe 100644 --- a/src/otclient/houses.h +++ b/src/otclient/houses.h @@ -29,7 +29,7 @@ #include #include -enum HouseAttributes +enum HouseAttributes : unsigned char { HouseAttribId, HouseAttribName, @@ -73,6 +73,7 @@ private: class Houses { public: + void clear() { m_houses.clear(); } void addHouse(const HousePtr& house); void removeHouse(uint32 houseId); void load(const std::string& fileName); @@ -80,9 +81,6 @@ public: HouseList houseList() const { return m_houses; } HousePtr getHouse(uint32 houseId); - // Fix to segfault on exit. - void clear() { m_houses.clear(); } - private: HouseList m_houses; diff --git a/src/otclient/luafunctions.cpp b/src/otclient/luafunctions.cpp index 11814789..7144cc79 100644 --- a/src/otclient/luafunctions.cpp +++ b/src/otclient/luafunctions.cpp @@ -300,9 +300,11 @@ void OTClient::registerLuaFunctions() g_lua.bindClassMemberFunction("setPos", &CreatureType::setPos); g_lua.bindClassMemberFunction("setName", &CreatureType::setName); g_lua.bindClassMemberFunction("setOutfit", &CreatureType::setOutfit); + g_lua.bindClassMemberFunction("setSpawnTime", &CreatureType::setSpawnTime); g_lua.bindClassMemberFunction("getPos", &CreatureType::getPos); g_lua.bindClassMemberFunction("getName", &CreatureType::getName); g_lua.bindClassMemberFunction("getOutfit", &CreatureType::getOutfit); + g_lua.bindClassMemberFunction("getSpawnTime", &CreatureType::getSpawnTime); g_lua.registerClass(); g_lua.bindClassStaticFunction("create", []{ return CreaturePtr(new Creature); }); diff --git a/src/otclient/map.cpp b/src/otclient/map.cpp index 2870a5dc..c2405aaa 100644 --- a/src/otclient/map.cpp +++ b/src/otclient/map.cpp @@ -129,8 +129,7 @@ void Map::loadOtbm(const std::string& fileName) for(const BinaryTreePtr &nodeMapData : node->getChildren()) { uint8 mapDataType = nodeMapData->getU8(); if(mapDataType == OTBM_TILE_AREA) { - uint16 baseX = nodeMapData->getU16(), baseY = nodeMapData->getU16(); - uint8 pz = nodeMapData->getU8(); + Position basePos = nodeMapData->getPosition(); for(const BinaryTreePtr &nodeTile : nodeMapData->getChildren()) { uint8 type = nodeTile->getU8(); @@ -139,9 +138,7 @@ void Map::loadOtbm(const std::string& fileName) HousePtr house = nullptr; uint32 flags = TILESTATE_NONE; - - uint16 px = baseX + nodeTile->getU8(), py = baseY + nodeTile->getU8(); - Position pos(px, py, pz); + Position pos = basePos + nodeTile->getPoint(); if(type == OTBM_HOUSETILE) { uint32 hId = nodeTile->getU32(); @@ -178,8 +175,8 @@ void Map::loadOtbm(const std::string& fileName) break; } default: { - stdext::throw_exception(stdext::format("invalid tile attribute %d at pos %d, %d, %d", - (int)tileAttr, px, py, pz)); + stdext::throw_exception(stdext::format("invalid tile attribute %d at pos %s", + (int)tileAttr, stdext::pos_to_string(pos))); } } } @@ -206,8 +203,8 @@ void Map::loadOtbm(const std::string& fileName) } if(house && item->isMoveable()) { - g_logger.warning(stdext::format("Movable item found in house: %d at pos %d %d %d - escaping...", item->getId(), - px, py, pz)); + g_logger.warning(stdext::format("Movable item found in house: %d at pos %s - escaping...", item->getId(), + stdext::pos_to_string(pos))); item.reset(); } @@ -225,12 +222,11 @@ void Map::loadOtbm(const std::string& fileName) uint32 townId = nodeTown->getU32(); std::string townName = nodeTown->getString(); - Position townCoords(nodeTown->getU16(), nodeTown->getU16(), nodeTown->getU8()); + Position townCoords = nodeTown->getPosition(); if(!(town = m_towns.getTown(townId))) { town = TownPtr(new Town(townId, townName, townCoords)); m_towns.addTown(town); } - g_logger.debug(stdext::format("new town %ld %s", townId, townName)); } } else if(mapDataType == OTBM_WAYPOINTS && headerVersion > 1) { for(const BinaryTreePtr &nodeWaypoint : nodeMapData->getChildren()) { @@ -238,15 +234,14 @@ void Map::loadOtbm(const std::string& fileName) stdext::throw_exception("invalid waypoint node."); std::string name = nodeWaypoint->getString(); - Position waypointPos(nodeWaypoint->getU16(), nodeWaypoint->getU16(), nodeWaypoint->getU8()); + Position waypointPos = nodeWaypoint->getPosition(); if(waypointPos.isValid() && !name.empty() && m_waypoints.find(waypointPos) == m_waypoints.end()) m_waypoints.insert(std::make_pair(waypointPos, name)); } } else - stdext::throw_exception("Unknown map data node"); + stdext::throw_exception(stdext::format("Unknown map data node %d", (int)mapDataType)); } - int numItems = 0; for(const auto& it : m_tiles) numItems += it.second->getThingCount(); @@ -327,7 +322,7 @@ void Map::saveOtbm(const std::string &fileName) Position pos(-1, -1, -1); Boolean first; - for (auto& pair : m_tiles) { + for (const auto& pair : m_tiles) { TilePtr tile = pair.second; if(!tile || tile->isEmpty()) continue; @@ -397,15 +392,12 @@ void Map::loadSpawns(const std::string &fileName) if (!m) stdext::throw_exception(stdext::format("unkown monster '%s'", stdext::trim(stdext::tolower(mName)))); - Point off = mType->readPoint(); - Position mPos(centerPos.x + off.x, centerPos.y + off.y, centerPos.z); - m->setPos(mPos); + m->setPos(centerPos + mType->readPoint()); m->setSpawnTime(mType->readType("spawntime")); } } doc.Clear(); - g_logger.debug("Loaded spawns"); } bool Map::loadOtcm(const std::string& fileName) @@ -439,7 +431,6 @@ bool Map::loadOtcm(const std::string& fileName) } default: stdext::throw_exception("otcm version not supported"); - break; } fin->seek(start); diff --git a/src/otclient/map.h b/src/otclient/map.h index 9e0b4622..d6b99f5b 100644 --- a/src/otclient/map.h +++ b/src/otclient/map.h @@ -28,7 +28,9 @@ #include "towns.h" #include "creatures.h" #include "animatedtext.h" + #include +#include enum OTBM_AttrTypes_t { @@ -187,6 +189,7 @@ private: Position m_centralPosition; Rect m_tilesRect; + AttribStorage m_attribs; std::string m_description, m_spawnFile, m_houseFile; Houses m_houses; diff --git a/src/otclient/position.h b/src/otclient/position.h index 580032da..6326a577 100644 --- a/src/otclient/position.h +++ b/src/otclient/position.h @@ -25,6 +25,7 @@ #include "const.h" #include +#include #include class Position @@ -161,6 +162,9 @@ public: Position& operator+=(const Position& other) { x+=other.x; y+=other.y; z +=other.z; return *this; } Position operator-(const Position& other) const { return Position(x - other.x, y - other.y, z - other.z); } Position& operator-=(const Position& other) { x-=other.x; y-=other.y; z-=other.z; return *this; } + // Point conversion(s) + Position operator+(const Point& other) const { return Position(x + other.x, y + other.y, z); } + Position& operator+=(const Point& other) { x += other.x; y += other.y; return *this; } Position& operator=(const Position& other) { x = other.x; y = other.y; z = other.z; return *this; } bool operator==(const Position& other) const { return other.x == x && other.y == y && other.z == z; }