From 1ed95b612001807cf46ac35e352ea9ad809fa981 Mon Sep 17 00:00:00 2001 From: niczkx Date: Sun, 19 Aug 2012 15:41:03 +0000 Subject: [PATCH] More work on OTBM/OTB/XML --- src/framework/core/binarytree.cpp | 29 -------- src/framework/core/binarytree.h | 21 ------ src/framework/core/filestream.cpp | 11 +++ src/framework/core/filestream.h | 6 ++ src/otclient/creatures.cpp | 15 +++- src/otclient/creatures.h | 13 +++- src/otclient/effect.cpp | 2 +- src/otclient/item.cpp | 32 ++++---- src/otclient/item.h | 5 +- src/otclient/itemtype.cpp | 12 +-- src/otclient/itemtype.h | 16 ++-- src/otclient/luafunctions.cpp | 8 ++ src/otclient/map.cpp | 2 +- src/otclient/map.h | 11 ++- src/otclient/mapio.cpp | 118 +++++++++++++++++------------- src/otclient/thingtypemanager.cpp | 113 ++++++++++++++++++++++------ src/otclient/thingtypemanager.h | 1 + src/otclient/tile.h | 2 +- 18 files changed, 252 insertions(+), 165 deletions(-) diff --git a/src/framework/core/binarytree.cpp b/src/framework/core/binarytree.cpp index c5d601cb..1439ecac 100644 --- a/src/framework/core/binarytree.cpp +++ b/src/framework/core/binarytree.cpp @@ -181,32 +181,3 @@ Point BinaryTree::getPoint() ret.y = getU8(); return ret; } - -/// BinaryWriteTree -BinaryWriteTree::BinaryWriteTree(const FileStreamPtr& fin) : - m_fin(fin) -{ -} - -BinaryWriteTree::~BinaryWriteTree() -{ - m_fin->close(); - m_fin = nullptr; -} - -void BinaryWriteTree::startNode(uint8 type) -{ - writeU8(BINARYTREE_NODE_START); - writeU8(type); -} - -void BinaryWriteTree::endNode() -{ - writeU8(BINARYTREE_NODE_END); -} - -void BinaryWriteTree::writeU8(uint8 u8) { m_fin->addU8(u8); } -void BinaryWriteTree::writeU16(uint16 u16) { m_fin->addU16(u16); } -void BinaryWriteTree::writeU32(uint32 u32) { m_fin->addU32(u32); } -void BinaryWriteTree::writeString(const std::string& str) { m_fin->addString(str); } - diff --git a/src/framework/core/binarytree.h b/src/framework/core/binarytree.h index 670da174..65d68d20 100644 --- a/src/framework/core/binarytree.h +++ b/src/framework/core/binarytree.h @@ -66,25 +66,4 @@ private: uint m_startPos; }; -class BinaryWriteTree : public stdext::shared_object -{ -public: - BinaryWriteTree(const FileStreamPtr& fin); - ~BinaryWriteTree(); - - void startNode(uint8 type); - void endNode(); - - void writeU8(uint8 u8); - void writeU16(uint16 u16); - void writeU32(uint32 u32); - void writeString(const std::string& str); - - void writePoint(const Point& p) { writeU8(p.x); writeU8(p.y); } - void writePos(const Position& p) { writeU16(p.x); writeU16(p.y); writeU8(p.z); } - -private: - FileStreamPtr m_fin; -}; - #endif diff --git a/src/framework/core/filestream.cpp b/src/framework/core/filestream.cpp index 307aca47..10556d42 100644 --- a/src/framework/core/filestream.cpp +++ b/src/framework/core/filestream.cpp @@ -267,6 +267,17 @@ BinaryTreePtr FileStream::getBinaryTree() return BinaryTreePtr(new BinaryTree(asFileStream())); } +void FileStream::startNode(uint8 n) +{ + addU8(BINARYTREE_NODE_START); + addU8(n); +} + +void FileStream::endNode() +{ + addU8(BINARYTREE_NODE_END); +} + void FileStream::addU8(uint8 v) { if(!m_caching) { diff --git a/src/framework/core/filestream.h b/src/framework/core/filestream.h index d7adfd2c..2126fb9e 100644 --- a/src/framework/core/filestream.h +++ b/src/framework/core/filestream.h @@ -26,6 +26,8 @@ #include "declarations.h" #include #include +#include +#include struct PHYSFS_File; @@ -55,11 +57,15 @@ public: std::string getString(); BinaryTreePtr getBinaryTree(); + void startNode(uint8 n); + void endNode(); void addU8(uint8 v); void addU16(uint16 v); void addU32(uint32 v); void addU64(uint64 v); void addString(const std::string& v); + void addPos(const Position& pos) { addU16(pos.x); addU16(pos.y); addU8(pos.z); } + void addPoint(const Point& p) { addU8(p.x); addU8(p.y); } FileStreamPtr asFileStream() { return static_self_cast(); } diff --git a/src/otclient/creatures.cpp b/src/otclient/creatures.cpp index 278aa25a..eb888865 100644 --- a/src/otclient/creatures.cpp +++ b/src/otclient/creatures.cpp @@ -26,6 +26,8 @@ #include #include +Creatures g_creatures; + void Creatures::loadMonsters(const std::string& file) { TiXmlDocument doc; @@ -127,7 +129,7 @@ bool Creatures::m_loadCreatureBuffer(TiXmlElement* attrib, const CreatureTypePtr return type >= 0; } -CreatureTypePtr Creatures::getCreature(std::string name) +CreatureTypePtr Creatures::getCreatureByName(std::string name) { stdext::tolower(name); stdext::trim(name); @@ -135,3 +137,14 @@ CreatureTypePtr Creatures::getCreature(std::string name) [=] (const CreatureTypePtr& m) -> bool { return m->getName() == name; }); return it != m_creatures.end() ? *it : nullptr; } + +CreatureTypePtr Creatures::getCreatureByLook(int look) +{ + auto findFun = [=] (const CreatureTypePtr& c) -> bool + { + const Outfit& o = c->getOutfit(); + return o.getId() == look; + }; + auto it = std::find_if(m_creatures.begin(), m_creatures.end(), findFun); + return it != m_creatures.end() ? *it : nullptr; +} diff --git a/src/otclient/creatures.h b/src/otclient/creatures.h index de3731ac..35dc72f3 100644 --- a/src/otclient/creatures.h +++ b/src/otclient/creatures.h @@ -41,13 +41,14 @@ public: CreatureType() { } CreatureType(const std::string& name) { setName(name); } - void setName(const std::string& name) { m_attribs.set(CreatureAttrName, name); } - void setOutfit(const Outfit& o) { m_attribs.set(CreatureAttrOutfit, o); } void setSpawnTime(int spawnTime) { m_attribs.set(CreatureAttrSpawnTime, spawnTime); } + int getSpawnTime() { return m_attribs.get(CreatureAttrSpawnTime); } + void setName(const std::string& name) { m_attribs.set(CreatureAttrName, name); } std::string getName() { return m_attribs.get(CreatureAttrName); } + + void setOutfit(const Outfit& o) { m_attribs.set(CreatureAttrOutfit, o); } Outfit getOutfit() { return m_attribs.get(CreatureAttrOutfit); } - int getSpawnTime() { return m_attribs.get(CreatureAttrSpawnTime); } private: stdext::dynamic_storage m_attribs; @@ -63,7 +64,9 @@ public: void loadNpcs(const std::string& folder); void loadCreatureBuffer(const std::string& buffer); - CreatureTypePtr getCreature(std::string name); + CreatureTypePtr getCreatureByName(std::string name); + CreatureTypePtr getCreatureByLook(int look); + bool isLoaded() const { return m_loaded; } protected: @@ -74,4 +77,6 @@ private: stdext::boolean m_loaded; }; +extern Creatures g_creatures; + #endif diff --git a/src/otclient/effect.cpp b/src/otclient/effect.cpp index ef52c9ec..b64cdfc2 100644 --- a/src/otclient/effect.cpp +++ b/src/otclient/effect.cpp @@ -42,7 +42,7 @@ void Effect::onAppear() // hack to fix some animation phases duration, currently there is no better solution if(m_id == 33) - m_phaseDuration *= 4; + m_phaseDuration <<= 2; // schedule removal auto self = asEffect(); diff --git a/src/otclient/item.cpp b/src/otclient/item.cpp index b6ce4699..c05ce3eb 100644 --- a/src/otclient/item.cpp +++ b/src/otclient/item.cpp @@ -268,41 +268,45 @@ void Item::unserializeItem(const BinaryTreePtr &in) } } -void Item::serializeItem(const BinaryWriteTreePtr& out) +void Item::serializeItem(const FileStreamPtr& out) { out->startNode(OTBM_ITEM); - out->writeU16(getId()); + out->addU16(getId()); - out->writeU8(ATTR_COUNT); - out->writeU8(getCount()); + out->addU8(ATTR_COUNT); + out->addU8(getCount()); - out->writeU8(ATTR_CHARGES); - out->writeU16(getCountOrSubType()); + out->addU8(ATTR_CHARGES); + out->addU16(getCountOrSubType()); Position dest = m_attribs.get(ATTR_TELE_DEST); if(dest.isValid()) { - out->writeU8(ATTR_TELE_DEST); - out->writePos(dest); + out->addU8(ATTR_TELE_DEST); + out->addPos(dest); } if(isDepot()) { - out->writeU8(ATTR_DEPOT_ID); - out->writeU16(getDepotId()); + out->addU8(ATTR_DEPOT_ID); + out->addU16(getDepotId()); } uint16 aid = m_attribs.get(ATTR_ACTION_ID); uint16 uid = m_attribs.get(ATTR_UNIQUE_ID); if(aid) { - out->writeU8(ATTR_ACTION_ID); - out->writeU16(aid); + out->addU8(ATTR_ACTION_ID); + out->addU16(aid); } if(uid) { - out->writeU8(ATTR_UNIQUE_ID); - out->writeU16(uid); + out->addU8(ATTR_UNIQUE_ID); + out->addU16(uid); } out->endNode(); + if(!m_containerItems.empty()) { + for(auto c : m_containerItems) + c->serializeItem(out); + } } int Item::getSubType() diff --git a/src/otclient/item.h b/src/otclient/item.h index 00a8e064..549ef09b 100644 --- a/src/otclient/item.h +++ b/src/otclient/item.h @@ -98,7 +98,7 @@ public: ItemPtr clone(); void unserializeItem(const BinaryTreePtr& in); - void serializeItem(const BinaryWriteTreePtr& out); + void serializeItem(const FileStreamPtr& out); void setDepotId(uint16 depotId) { m_attribs.set(ATTR_DEPOT_ID, depotId); } uint16 getDepotId() { return m_attribs.get(ATTR_DEPOT_ID); } @@ -119,6 +119,8 @@ public: ItemPtr asItem() { return static_self_cast(); } bool isItem() { return true; } + void addContainerItem(const ItemPtr& i) { m_containerItems.push_back(i); } + const ThingTypePtr& getThingType(); ThingType *rawGetThingType(); @@ -127,6 +129,7 @@ private: uint16 m_otbId; uint8 m_countOrSubType; stdext::packed_storage m_attribs; + std::vector m_containerItems; }; #pragma pack(pop) diff --git a/src/otclient/itemtype.cpp b/src/otclient/itemtype.cpp index e568c395..3721d475 100644 --- a/src/otclient/itemtype.cpp +++ b/src/otclient/itemtype.cpp @@ -41,6 +41,7 @@ void ItemType::unserialize(const BinaryTreePtr& node) node->getU32(); // flags static uint16 lastId = 99; + static ItemTypePtr nullType = g_things.getNullItemType(); while(node->canRead()) { uint8 attr = node->getU8(); if(attr == 0 || attr == 0xFF) @@ -53,10 +54,13 @@ void ItemType::unserialize(const BinaryTreePtr& node) if(serverId > 20000 && serverId < 20100) { serverId -= 20000; } else if(lastId > 99 && lastId != serverId - 1) { - while(lastId != serverId - 1) - ++lastId; + while(lastId != serverId - 1) { + nullType->setServerId(lastId++); + g_things.addItemType(nullType); + } } setServerId(serverId); + lastId = serverId; break; } case ItemTypeAttrClientId: { @@ -67,10 +71,6 @@ void ItemType::unserialize(const BinaryTreePtr& node) setName(node->getString(len)); break; } - case ItemTypeAttrDesc: { - setDesc(node->getString()); - break; - } default: node->skip(len); // skip attribute break; diff --git a/src/otclient/itemtype.h b/src/otclient/itemtype.h index 7dbd16fc..dda270a0 100644 --- a/src/otclient/itemtype.h +++ b/src/otclient/itemtype.h @@ -28,7 +28,7 @@ #include #include -enum ItemCategory { +enum ItemCategory : uint8 { ItemCategoryInvalid = 0, ItemCategoryGround = 1, ItemCategoryContainer = 2, @@ -86,19 +86,23 @@ public: void unserialize(const BinaryTreePtr& node); + void setServerId(uint16 serverId) { m_attribs.set(ItemTypeAttrServerId, serverId); } uint16 getServerId() { return m_attribs.get(ItemTypeAttrServerId); } + + void setClientId(uint16 clientId) { m_attribs.set(ItemTypeAttrClientId, clientId); } uint16 getClientId() { return m_attribs.get(ItemTypeAttrClientId); } + + void setCategory(ItemCategory category) { m_category = category; } ItemCategory getCategory() { return m_category; } + + void setName(const std::string& name) { m_attribs.set(ItemTypeAttrName, name); } std::string getName() { return m_attribs.get(ItemTypeAttrName); } + + void setDesc(const std::string& desc) { m_attribs.set(ItemTypeAttrDesc, desc); } std::string getDesc() { return m_attribs.get(ItemTypeAttrDesc); } bool isNull() { return m_null; } - void setClientId(uint16 clientId) { m_attribs.set(ItemTypeAttrClientId, clientId); } - void setServerId(uint16 serverId) { m_attribs.set(ItemTypeAttrServerId, serverId); } - void setName(const std::string& name) { m_attribs.set(ItemTypeAttrName, name); } - void setDesc(const std::string& desc) { m_attribs.set(ItemTypeAttrDesc, desc); } - private: ItemCategory m_category; stdext::boolean m_null; diff --git a/src/otclient/luafunctions.cpp b/src/otclient/luafunctions.cpp index a59c1eb8..55960116 100644 --- a/src/otclient/luafunctions.cpp +++ b/src/otclient/luafunctions.cpp @@ -59,9 +59,11 @@ void OTClient::registerLuaFunctions() g_lua.bindSingletonFunction("g_things", "getDatSignature", &ThingTypeManager::getDatSignature, &g_things); g_lua.bindSingletonFunction("g_things", "getThingType", &ThingTypeManager::getThingType, &g_things); g_lua.bindSingletonFunction("g_things", "getItemType", &ThingTypeManager::getItemType, &g_things); + g_lua.bindSingletonFunction("g_things", "getThingTypes", &ThingTypeManager::getThingTypes, &g_things); g_lua.bindSingletonFunction("g_things", "findItemTypeByClientId", &ThingTypeManager::findItemTypeByClientId, &g_things); g_lua.bindSingletonFunction("g_things", "findThingTypeByAttr", &ThingTypeManager::findThingTypeByAttr, &g_things); g_lua.bindSingletonFunction("g_things", "findItemTypeByCategory", &ThingTypeManager::findItemTypeByCategory, &g_things); + g_lua.bindSingletonFunction("g_things", "castThingToCreature", &ThingTypeManager::castThingToCreature, &g_things); #if 0 g_lua.registerSingletonClass("g_houses"); @@ -112,6 +114,11 @@ void OTClient::registerLuaFunctions() g_lua.bindSingletonFunction("g_map", "getHouse", &Map::getHouse, &g_map); g_lua.bindSingletonFunction("g_map", "getCreature", &Map::getCreature, &g_map); + /// \todo move creatures from Map to here + g_lua.registerSingletonClass("g_creatures"); + g_lua.bindSingletonFunction("g_creatures", "getCreature", &Creatures::getCreatureByName, &g_creatures); + g_lua.bindSingletonFunction("g_creatures", "getCreatureByLook", &Creatures::getCreatureByLook, &g_creatures); + g_lua.registerSingletonClass("g_game"); g_lua.bindSingletonFunction("g_game", "loginWorld", &Game::loginWorld, &g_game); g_lua.bindSingletonFunction("g_game", "cancelLogin", &Game::cancelLogin, &g_game); @@ -340,6 +347,7 @@ void OTClient::registerLuaFunctions() g_lua.bindClassMemberFunction("getId", &ThingType::getId); g_lua.bindClassMemberFunction("getMarketData", &ThingType::getMarketData); g_lua.bindClassMemberFunction("getClothSlot", &ThingType::getClothSlot); + g_lua.bindClassMemberFunction("getCategory", &ThingType::getCategory); g_lua.registerClass(); g_lua.bindClassStaticFunction("create", &Item::create); diff --git a/src/otclient/map.cpp b/src/otclient/map.cpp index 0ad5d238..78ecd272 100644 --- a/src/otclient/map.cpp +++ b/src/otclient/map.cpp @@ -69,7 +69,7 @@ void Map::clean() m_towns.clear(); m_houses.clear(); - m_creatures.clear(); + g_creatures.clear(); m_tilesRect = Rect(65534, 65534, 0, 0); } diff --git a/src/otclient/map.h b/src/otclient/map.h index 85299f14..69fbf08d 100644 --- a/src/otclient/map.h +++ b/src/otclient/map.h @@ -187,7 +187,7 @@ public: void saveOtbm(const std::string& fileName); void loadSpawns(const std::string& fileName); - void saveSpawns(const std::string&) { } + void saveSpawns(const std::string&); // otbm attributes (description, size, etc.) void setHouseFile(const std::string& file) { m_attribs.set(OTBM_ATTR_HOUSE_FILE, file); } @@ -201,9 +201,9 @@ public: Size getSize() { return Size(m_attribs.get(OTBM_ATTR_WIDTH), m_attribs.get(OTBM_ATTR_HEIGHT)); } std::vector getDescriptions() { return stdext::split(m_attribs.get(OTBM_ATTR_DESCRIPTION), "\n"); } - void loadMonsters(const std::string& fileName) { m_creatures.loadMonsters(fileName); } - void loadSingleCreature(const std::string& file) { m_creatures.loadSingleCreature(file); } - void loadNpcs(const std::string& folder) { m_creatures.loadNpcs(folder); } + void loadMonsters(const std::string& fileName) { g_creatures.loadMonsters(fileName); } + void loadSingleCreature(const std::string& file) { g_creatures.loadSingleCreature(file); } + void loadNpcs(const std::string& folder) { g_creatures.loadNpcs(folder); } void clean(); void cleanDynamicThings(); @@ -234,7 +234,7 @@ public: // town/house/monster related TownPtr getTown(uint32 tid) { return m_towns.getTown(tid); } HousePtr getHouse(uint32 hid) { return m_houses.getHouse(hid); } - CreatureTypePtr getCreature(const std::string &name) { return m_creatures.getCreature(name); } + CreatureTypePtr getCreature(const std::string &name) { return g_creatures.getCreatureByName(name); } void setLight(const Light& light) { m_light = light; } void setCentralPosition(const Position& centralPosition); @@ -273,7 +273,6 @@ private: stdext::packed_storage m_attribs; Houses m_houses; Towns m_towns; - Creatures m_creatures; static TilePtr m_nulltile; }; diff --git a/src/otclient/mapio.cpp b/src/otclient/mapio.cpp index 21ae6c17..84a444ad 100644 --- a/src/otclient/mapio.cpp +++ b/src/otclient/mapio.cpp @@ -95,7 +95,7 @@ void Map::loadOtbm(const std::string& fileName) } } - for(const BinaryTreePtr &nodeMapData : node->getChildren()) { + for(const BinaryTreePtr& nodeMapData : node->getChildren()) { uint8 mapDataType = nodeMapData->getU8(); if(mapDataType == OTBM_TILE_AREA) { Position basePos = nodeMapData->getPosition(); @@ -149,7 +149,7 @@ void Map::loadOtbm(const std::string& fileName) } } - for(const BinaryTreePtr &nodeItem : nodeTile->getChildren()) { + for(const BinaryTreePtr& nodeItem : nodeTile->getChildren()) { if(nodeItem->getU8() != OTBM_ITEM) stdext::throw_exception("invalid item node"); @@ -163,7 +163,7 @@ void Map::loadOtbm(const std::string& fileName) ItemPtr cItem = Item::createFromOtb(containerItem->getU16()); cItem->unserializeItem(containerItem); - //item->addContainerItem(cItem); + item->addContainerItem(cItem); } } @@ -175,8 +175,11 @@ void Map::loadOtbm(const std::string& fileName) addThing(item, pos); } - if(const TilePtr& tile = getTile(pos)) + if(const TilePtr& tile = getTile(pos)) { + if(house) + tile->setHouseId(house->getId()); tile->setFlags((tileflags_t)flags); + } } } else if(mapDataType == OTBM_TOWNS) { TownPtr town = nullptr; @@ -263,41 +266,40 @@ void Map::saveOtbm(const std::string &fileName) #endif fin->addU32(0); // file version - BinaryWriteTreePtr root(new BinaryWriteTree(fin)); - root->startNode(0); + fin->startNode(0); { - root->writeU32(version); + fin->addU32(version); Size mapSize = getSize(); - root->writeU16(mapSize.width()); - root->writeU16(mapSize.height()); + fin->addU16(mapSize.width()); + fin->addU16(mapSize.height()); - root->writeU32(g_things.getOtbMajorVersion()); - root->writeU32(g_things.getOtbMinorVersion()); + fin->addU32(g_things.getOtbMajorVersion()); + fin->addU32(g_things.getOtbMinorVersion()); - root->startNode(OTBM_MAP_DATA); + fin->startNode(OTBM_MAP_DATA); { // own description. for(const auto& desc : getDescriptions()) { - root->writeU8(OTBM_ATTR_DESCRIPTION); - root->writeString(desc); + fin->addU8(OTBM_ATTR_DESCRIPTION); + fin->addString(desc); } // special one - root->writeU8(OTBM_ATTR_DESCRIPTION); - root->writeString(stdext::format("Saved with %s v%s", g_app.getName(), g_app.getVersion())); + fin->addU8(OTBM_ATTR_DESCRIPTION); + fin->addString(stdext::format("Saved with %s v%s", g_app.getName(), g_app.getVersion())); // spawn file. - root->writeU8(OTBM_ATTR_SPAWN_FILE); - root->writeString(spawnFile); + fin->addU8(OTBM_ATTR_SPAWN_FILE); + fin->addString(spawnFile); // house file. if(version > 1) { - root->writeU8(OTBM_ATTR_HOUSE_FILE); - root->writeString(houseFile); + fin->addU8(OTBM_ATTR_HOUSE_FILE); + fin->addString(houseFile); } - Position base(-1, -1, -1); + Position base(0, 0, 0); bool firstNode = true; for(uint8_t z = 0; z <= Otc::MAX_Z; ++z) { @@ -311,71 +313,72 @@ void Map::saveOtbm(const std::string &fileName) if(!pos.isValid()) continue; - if(pos.x < base.x || pos.x >= base.x + 256 || pos.y < base.y|| pos.y >= base.y + 256 || - pos.z != base.z) { + if(pos.x < base.x || pos.x >= base.x + 255 + || pos.y < base.y || pos.y >= base.y + 255 + || pos.z != base.z) { if(!firstNode) - root->endNode(); /// OTBM_TILE_AREA + fin->endNode(); /// OTBM_TILE_AREA - root->startNode(OTBM_TILE_AREA); + fin->startNode(OTBM_TILE_AREA); firstNode = false; - root->writePos(base = pos & 0xFF00); + fin->addPos(base = pos & 0xFF00); } uint32 flags = tile->getFlags(); - root->startNode((flags & TILESTATE_HOUSE) == TILESTATE_HOUSE ? OTBM_HOUSETILE : OTBM_TILE); - root->writePoint(Point(pos.x, pos.y) & 0xFF); -// if(tileNode->getType() == OTBM_HOUSETILE) -// tileNode->writeU32(tile->getHouseId()); + fin->startNode((flags & TILESTATE_HOUSE) == TILESTATE_HOUSE ? OTBM_HOUSETILE : OTBM_TILE); + fin->addPoint(Point(pos.x, pos.y) & 0xFF); + if((flags & TILESTATE_HOUSE) == TILESTATE_HOUSE) + fin->addU32(tile->getHouseId()); if(flags) { - root->writeU8(OTBM_ATTR_TILE_FLAGS); - root->writeU32(flags); + fin->addU8(OTBM_ATTR_TILE_FLAGS); + fin->addU32(flags); } for(const ItemPtr& item : tile->getItems()) { if(item->isGround()) { - root->writeU8(OTBM_ATTR_ITEM); - root->writeU16(item->getId()); + fin->addU8(OTBM_ATTR_ITEM); + fin->addU16(item->getId()); continue; } - item->serializeItem(root); + item->serializeItem(fin); } - root->endNode(); // OTBM_TILE + fin->endNode(); // OTBM_TILE } } } if(!firstNode) - root->endNode(); // OTBM_TILE_AREA + fin->endNode(); // OTBM_TILE_AREA - root->startNode(OTBM_TOWNS); + fin->startNode(OTBM_TOWNS); for(const TownPtr& town : m_towns.getTowns()) { - root->writeU32(town->getId()); - root->writeString(town->getName()); - root->writePos(town->getPos()); + fin->addU32(town->getId()); + fin->addString(town->getName()); + fin->addPos(town->getPos()); } - root->endNode(); + fin->endNode(); if(version > 1) { - root->startNode(OTBM_WAYPOINTS); + fin->startNode(OTBM_WAYPOINTS); for(const auto& it : m_waypoints) { - root->writeString(it.second); - root->writePos(it.first); + fin->addString(it.second); + fin->addPos(it.first); } - root->endNode(); + fin->endNode(); } } - root->endNode(); // OTBM_MAP_DATA + fin->endNode(); // OTBM_MAP_DATA } - root->endNode(); // 0 (root) + fin->endNode(); // 0 (root) } void Map::loadSpawns(const std::string &fileName) { - if(!m_creatures.isLoaded()) + if(!g_creatures.isLoaded()) stdext::throw_exception("cannot load spawns; monsters/nps aren't loaded."); TiXmlDocument doc; @@ -401,7 +404,7 @@ void Map::loadSpawns(const std::string &fileName) stdext::tolower(cName); stdext::trim(cName); - if (!(cType = m_creatures.getCreature(cName))) + if (!(cType = g_creatures.getCreatureByName(cName))) continue; cType->setSpawnTime(cNode->readType("spawntime")); @@ -420,6 +423,21 @@ void Map::loadSpawns(const std::string &fileName) } } +void Map::saveSpawns(const std::string& fileName) +{ +#if 0 + TiXmlDocument doc; + + TiXmlDeclaration* decl = new TiXmlDeclaration("1.0", "UTF-8", ""); + doc.LinkEndChild(decl); + + TiXmlElement* root = new TiXmlElement("spawns"); + doc.LinkEndChild(root); + + TiXmlElement* spawn = NULL; +#endif +} + bool Map::loadOtcm(const std::string& fileName) { try { diff --git a/src/otclient/thingtypemanager.cpp b/src/otclient/thingtypemanager.cpp index 0699643b..e64fd80b 100644 --- a/src/otclient/thingtypemanager.cpp +++ b/src/otclient/thingtypemanager.cpp @@ -25,6 +25,8 @@ #include "thing.h" #include "thingtype.h" #include "itemtype.h" +#include "creature.h" +#include "creatures.h" #include #include @@ -125,7 +127,9 @@ void ThingTypeManager::loadOtb(const std::string& file) void ThingTypeManager::loadXml(const std::string& file) { - /// Read XML + if(!isOtbLoaded()) + stdext::throw_exception("OTB must be loaded before XML"); + TiXmlDocument doc; doc.Parse(g_resources.loadFile(file).c_str()); if(doc.Error()) @@ -140,19 +144,27 @@ void ThingTypeManager::loadXml(const std::string& file) continue; uint16 id = element->readType("id"); - if(id > 20000 && id < 20100) { - id -= 20000; - ItemTypePtr newType(new ItemType); - newType->setServerId(id); - addItemType(newType); - } - - if(id != 0) - parseItemType(id, element); - else { - uint16 fromId = element->readType("fromid"), toId = element->readType("toid"); - for(uint16 i = fromId; i < toId; ++i) - parseItemType(i, element); + if(id != 0) { + std::vector s_ids = stdext::split(element->Attribute("id"), ";"); + for(const std::string& s : s_ids) { + std::vector ids = stdext::split(s, "-"); + if(ids.size() > 1) { + int32 i = ids[0]; + while(i <= ids[1]) + parseItemType(i++, element); + } else + parseItemType(atoi(s.c_str()), element); + } + } else { + std::vector begin = stdext::split(element->Attribute("fromid"), ";"); + std::vector end = stdext::split(element->Attribute("toid"), ";"); + if(begin[0] && begin.size() == end.size()) { + size_t size = begin.size(); + for(size_t i = 0; i < size; ++i) { + while(begin[i] <= end[i]) + parseItemType(begin[i]++, element); + } + } } } @@ -164,23 +176,53 @@ void ThingTypeManager::loadXml(const std::string& file) void ThingTypeManager::parseItemType(uint16 id, TiXmlElement* elem) { uint16 serverId = id; + ItemTypePtr itemType = nullptr; if(serverId > 20000 && id < 20100) { serverId -= 20000; - ItemTypePtr newType(new ItemType); - newType->setServerId(serverId); - addItemType(newType); + itemType = ItemTypePtr(new ItemType); + itemType->setServerId(serverId); + addItemType(itemType); + } + + if(!itemType) { + itemType = getItemType(serverId); + if(itemType == m_nullItemType) { + itemType = ItemTypePtr(new ItemType); + itemType->setServerId(id); + addItemType(itemType); + } } - ItemTypePtr itemType = getItemType(serverId); itemType->setName(elem->Attribute("name")); for(TiXmlElement* attrib = elem->FirstChildElement(); attrib; attrib = attrib->NextSiblingElement()) { - if(attrib->ValueStr() != "attribute") - break; + std::string key = attrib->Attribute("key"); + if(key.empty()) + continue; - if(attrib->Attribute("key") == "description") { + stdext::tolower(key); + if(key == "description") itemType->setDesc(attrib->Attribute("value")); - break; + else if(key == "weapontype") + itemType->setCategory(ItemCategoryWeapon); + else if(key == "ammotype") + itemType->setCategory(ItemCategoryAmmunition); + else if(key == "armor") + itemType->setCategory(ItemCategoryArmor); + else if(key == "charges") + itemType->setCategory(ItemCategoryCharges); + else if(key == "type") { + std::string value = attrib->Attribute("value"); + stdext::tolower(value); + + if(value == "key") + itemType->setCategory(ItemCategoryKey); + else if(value == "magicfield") + itemType->setCategory(ItemCategoryMagicField); + else if(value == "teleport") + itemType->setCategory(ItemCategoryTeleport); + else if(value == "door") + itemType->setCategory(ItemCategoryDoor); } } } @@ -189,7 +231,7 @@ void ThingTypeManager::addItemType(const ItemTypePtr& itemType) { uint16 id = itemType->getServerId(); if(m_itemTypes.size() <= id) - m_itemTypes.resize(id+1, m_nullItemType); + m_itemTypes.resize((id * 3) / 2 + 1, m_nullItemType); m_itemTypes[id] = itemType; } @@ -217,13 +259,36 @@ const ThingTypePtr& ThingTypeManager::getThingType(uint16 id, ThingCategory cate const ItemTypePtr& ThingTypeManager::getItemType(uint16 id) { - if(id >= m_itemTypes.size()) { + if(id >= m_itemTypes.size() || m_itemTypes[id] == m_nullItemType) { g_logger.error(stdext::format("invalid thing type server id %d", id)); return m_nullItemType; } return m_itemTypes[id]; } +CreaturePtr ThingTypeManager::castThingToCreature(const ThingTypePtr& thing) +{ + if(!thing) + return nullptr; + + if(thing->getCategory() != ThingCategoryCreature) + stdext::throw_exception("Thing type is not a creature"); + + uint16 clientId = thing->getId(); + CreaturePtr ret(new Creature); + CreatureTypePtr cType = g_creatures.getCreatureByLook(clientId); + if(!cType) { + // a creature can have a look item with whether client id or even server id + const ItemTypePtr& item = findItemTypeByClientId(clientId); + if(item && !(cType = g_creatures.getCreatureByLook(item->getServerId()))) + stdext::throw_exception(stdext::format("failed to find creature with look type/item %hd", clientId)); + } + + ret->setName(cType->getName()); + ret->setOutfit(cType->getOutfit()); + return ret; +} + ThingTypeList ThingTypeManager::findThingTypeByAttr(ThingAttr attr, ThingCategory category) { ThingTypeList ret; diff --git a/src/otclient/thingtypemanager.h b/src/otclient/thingtypemanager.h index b61585ff..56f1d80f 100644 --- a/src/otclient/thingtypemanager.h +++ b/src/otclient/thingtypemanager.h @@ -50,6 +50,7 @@ public: const ItemTypePtr& getItemType(uint16 id); ThingType* rawGetThingType(uint16 id, ThingCategory category) { return m_thingTypes[category][id].get(); } ItemType* rawGetItemType(uint16 id) { return m_itemTypes[id].get(); } + CreaturePtr castThingToCreature(const ThingTypePtr& thing); ThingTypeList findThingTypeByAttr(ThingAttr attr, ThingCategory category); ItemTypeList findItemTypeByCategory(ItemCategory category); diff --git a/src/otclient/tile.h b/src/otclient/tile.h index ee836e6b..9927b2be 100644 --- a/src/otclient/tile.h +++ b/src/otclient/tile.h @@ -109,7 +109,7 @@ public: void setFlags(tileflags_t flags) { m_flags |= (uint32)flags; } uint32 getFlags() { return m_flags; } - void setHouseId(uint32 hid) { if(m_flags & TILESTATE_HOUSE) m_houseId = hid; } + void setHouseId(uint32 hid) { m_houseId = hid; } uint32 getHouseId() { return m_houseId; } TilePtr asTile() { return static_self_cast(); }