From 8f492f7e067b1295cfa6cadc0ec928f08ab86496 Mon Sep 17 00:00:00 2001 From: Kamil Date: Mon, 9 Jul 2012 08:59:16 +0200 Subject: [PATCH 1/3] Fixed bug with adding Vip from console or map, who is already on viplist. --- init.lua | 4 +- modules/game/player.lua | 7 + modules/game_console/console.lua | 4 +- modules/game_interface/gameinterface.lua | 4 +- src/framework/core/binarytree.cpp | 15 +- src/framework/pch.h | 4 + src/otclient/CMakeLists.txt | 4 + src/otclient/core/declarations.h | 6 + src/otclient/core/item.cpp | 129 ++++++------ src/otclient/core/item.h | 13 +- src/otclient/core/map.cpp | 251 +++++++++++------------ src/otclient/core/map.h | 9 +- src/otclient/core/thingtypemanager.cpp | 5 +- src/otclient/core/tile.h | 2 +- 14 files changed, 229 insertions(+), 228 deletions(-) diff --git a/init.lua b/init.lua index 0bc3469e..deddc3b5 100644 --- a/init.lua +++ b/init.lua @@ -45,7 +45,7 @@ if g_resources.fileExists("/otclientrc.lua") then dofile("/otclientrc.lua") end ---g_things.loadOtb("/items.otb") ---g_map.loadOtbm("/forgotten.otbm") +g_things.loadOtb("/items.otb") +g_map.loadOtbm("/forgotten.otbm") diff --git a/modules/game/player.lua b/modules/game/player.lua index 715729a5..8043d336 100644 --- a/modules/game/player.lua +++ b/modules/game/player.lua @@ -31,3 +31,10 @@ function Player:isPartySharedExperienceActive() shield == ShieldBlueNoSharedExpBlink or shield == ShieldBlueNoSharedExp) end + +function Player:hasVip(creatureName) + for id, vip in pairs(g_game.getVips()) do + if (vip[1] == creatureName) then return true end + end + return false +end diff --git a/modules/game_console/console.lua b/modules/game_console/console.lua index f2cb0785..f4acfb75 100644 --- a/modules/game_console/console.lua +++ b/modules/game_console/console.lua @@ -403,7 +403,9 @@ function Console.popupMenu(mousePos, mouseButton, creatureName, text) if creatureName then if creatureName ~= g_game.getCharacterName() then menu:addOption(tr('Message to ' .. creatureName), function () g_game.openPrivateChannel(creatureName) end) - menu:addOption(tr('Add to VIP list'), function () g_game.addVip(creatureName) end) --TODO not show if creature already in vip + if (not Player:hasVip(creatureName)) then + menu:addOption(tr('Add to VIP list'), function () g_game.addVip(creatureName) end) + end -- TODO ignore creatureName menu:addSeparator() end diff --git a/modules/game_interface/gameinterface.lua b/modules/game_interface/gameinterface.lua index 13a1c402..92f2e28d 100644 --- a/modules/game_interface/gameinterface.lua +++ b/modules/game_interface/gameinterface.lua @@ -263,7 +263,9 @@ function GameInterface.createThingMenu(menuPosition, lookThing, useThing, creatu menu:addOption(tr('Invite to private chat'), function() g_game.inviteToOwnChannel(creatureName) end) menu:addOption(tr('Exclude from private chat'), function() g_game.excludeFromOwnChannel(creatureName) end) -- [TODO] must be removed after message's popup labels been implemented end - menu:addOption(tr('Add to VIP list'), function() g_game.addVip(creatureName) end) + if (not Player:hasVip(creatureName)) then + menu:addOption(tr('Add to VIP list'), function() g_game.addVip(creatureName) end) + end local localPlayerShield = localPlayer:asCreature():getShield() local creatureShield = creatureThing:getShield() diff --git a/src/framework/core/binarytree.cpp b/src/framework/core/binarytree.cpp index 3ebfa452..7a4ff7b5 100644 --- a/src/framework/core/binarytree.cpp +++ b/src/framework/core/binarytree.cpp @@ -60,7 +60,7 @@ void BinaryTree::seek(uint pos) uint8 BinaryTree::getU8() { - if(m_pos+1 > m_buffer.size()) + if (m_pos+1 > m_buffer.size()) stdext::throw_exception("BinaryTree: getU8 failed"); uint8 v = m_buffer[m_pos]; m_pos += 1; @@ -69,7 +69,7 @@ uint8 BinaryTree::getU8() uint16 BinaryTree::getU16() { - if(m_pos+2 > m_buffer.size()) + if (m_pos+2 > m_buffer.size()) stdext::throw_exception("BinaryTree: getU16 failed"); uint16 v = stdext::readLE16(&m_buffer[m_pos]); m_pos += 2; @@ -78,7 +78,7 @@ uint16 BinaryTree::getU16() uint32 BinaryTree::getU32() { - if(m_pos+4 > m_buffer.size()) + if (m_pos+4 > m_buffer.size()) stdext::throw_exception("BinaryTree: getU32 failed"); uint32 v = stdext::readLE32(&m_buffer[m_pos]); m_pos += 4; @@ -87,8 +87,8 @@ uint32 BinaryTree::getU32() uint64 BinaryTree::getU64() { - if(m_pos+8 > m_buffer.size()) - stdext::throw_exception("BinaryTree: getu64 failed"); + if (m_pos+8 > m_buffer.size()) + stdext::throw_exception("BinaryTree: getU64 failed"); uint64 v = stdext::readLE64(&m_buffer[m_pos]); m_pos += 8; return v; @@ -98,7 +98,10 @@ std::string BinaryTree::getString() { uint16 len = getU16(); if (len == 0 || len > 8192) - stdext::throw_exception("failed to get string from binary tree - invalid size read."); + stdext::throw_exception("BinaryTree: getString failed: invalid or too large string length"); + + if (m_pos+len > m_buffer.size()) + stdext::throw_exception("BinaryTree: getString failed: string length exceeded buffer size."); std::string ret((char *)&m_buffer[m_pos], len); m_pos += len; diff --git a/src/framework/pch.h b/src/framework/pch.h index e167b528..a27c02ee 100644 --- a/src/framework/pch.h +++ b/src/framework/pch.h @@ -63,4 +63,8 @@ // boost utilities #include +// tiny XML +#define TIXML_USE_STL +#include + #endif diff --git a/src/otclient/CMakeLists.txt b/src/otclient/CMakeLists.txt index 693778bf..dde44a03 100644 --- a/src/otclient/CMakeLists.txt +++ b/src/otclient/CMakeLists.txt @@ -74,6 +74,10 @@ SET(otclient_SOURCES ${otclient_SOURCES} ${CMAKE_CURRENT_LIST_DIR}/core/thingtypeotb.h ${CMAKE_CURRENT_LIST_DIR}/core/tile.cpp ${CMAKE_CURRENT_LIST_DIR}/core/tile.h + ${CMAKE_CURRENT_LIST_DIR}/core/houses.cpp + ${CMAKE_CURRENT_LIST_DIR}/core/houses.h + ${CMAKE_CURRENT_LIST_DIR}/core/towns.cpp + ${CMAKE_CURRENT_LIST_DIR}/core/towns.h # lua ${CMAKE_CURRENT_LIST_DIR}/luascript/luavaluecasts.cpp diff --git a/src/otclient/core/declarations.h b/src/otclient/core/declarations.h index 78dd4ccb..a03083de 100644 --- a/src/otclient/core/declarations.h +++ b/src/otclient/core/declarations.h @@ -43,6 +43,8 @@ class AnimatedText; class StaticText; class ThingTypeDat; class ThingTypeOtb; +class House; +class Town; typedef std::shared_ptr MapViewPtr; typedef std::shared_ptr TilePtr; @@ -60,9 +62,13 @@ typedef std::shared_ptr AnimatedTextPtr; typedef std::shared_ptr StaticTextPtr; typedef std::shared_ptr ThingTypeDatPtr; typedef std::shared_ptr ThingTypeOtbPtr; +typedef std::shared_ptr HousePtr; +typedef std::shared_ptr TownPtr; typedef std::vector ThingList; typedef std::vector ThingTypeDatList; typedef std::vector ThingTypeOtbList; +typedef std::vector HouseList; +typedef std::vector TownList; #endif diff --git a/src/otclient/core/item.cpp b/src/otclient/core/item.cpp index df5799fb..c9fbc41f 100644 --- a/src/otclient/core/item.cpp +++ b/src/otclient/core/item.cpp @@ -45,14 +45,14 @@ Item::Item() : ItemPtr Item::create(int id) { - ItemPtr item = ItemPtr(new Item); + ItemPtr item(new Item); item->setId(id); return item; } ItemPtr Item::createFromOtb(int id) { - ItemPtr item = ItemPtr(new Item); + ItemPtr item(new Item); item->setOtbId(id); return item; } @@ -204,70 +204,71 @@ bool Item::isValid() return g_things.isValidDatId(m_id, DatItemCategory); } -bool Item::unserializeAttr(const BinaryTreePtr &fin) +void Item::unserializeItem(const BinaryTreePtr &in) { - uint8 attrType; - while ((attrType = fin->getU8()) != 0) - readAttr((AttrTypes_t)attrType, fin); + // Yet another TODO. + while (in->canRead()) { + uint8 attrType = in->getU8(); + if (attrType == 0) + break; - return true; -} - -void Item::readAttr(AttrTypes_t attrType, const BinaryTreePtr &fin) -{ - switch (attrType) { - case ATTR_COUNT: - setSubType(fin->getU8()); - break; - case ATTR_ACTION_ID: - setActionId(fin->getU16()); - break; - case ATTR_UNIQUE_ID: - setUniqueId(fin->getU16()); - break; - case ATTR_NAME: - setName(fin->getString()); - break; - case ATTR_ARTICLE: - fin->getString(); - case ATTR_ATTACK: // \/ not needed. - case ATTR_EXTRAATTACK: - case ATTR_DEFENSE: - case ATTR_EXTRADEFENSE: - case ATTR_ARMOR: - case ATTR_ATTACKSPEED: - case ATTR_HPPITCHANCE: - case ATTR_DURATION: - fin->getU32(); - break; - case ATTR_SCRIPTPROTECTED: - case ATTR_DUALWIELD: - case ATTR_DECAYING_STATE: - case ATTR_HPPOUSEDOORID: - fin->getU8(); - break; - case ATTR_TEXT: - setText(fin->getString()); - break; - case ATTR_WRITTENDATE: - fin->getU32(); - break; - case ATTR_WRITTENBY: - fin->getString(); - break; - case ATTR_DESC: - setDescription(fin->getString()); - break; - case ATTR_RUNE_CHARGES: - fin->getU8(); - break; - case ATTR_TELE_DEST: // Teleport should read that. - case ATTR_SLEEPERGUID: // Bed should read that. - case ATTR_SLEEPSTART: - case ATTR_CONTAINER_ITEMS: - case ATTR_ATTRIBUTE_MAP: - default: - break; + switch ((AttrTypes_t)attrType) { + case ATTR_COUNT: + setSubType(in->getU8()); + break; + case ATTR_CHARGES: + setSubType(in->getU16()); + break; + case ATTR_ACTION_ID: + setActionId(in->getU16()); + break; + case ATTR_UNIQUE_ID: + setUniqueId(in->getU16()); + break; + case ATTR_NAME: + setName(in->getString()); + break; + case ATTR_ARTICLE: // ? + case ATTR_WRITTENBY: + case ATTR_DESC: + in->getString(); + break; + case ATTR_ATTACK: + case ATTR_EXTRAATTACK: + case ATTR_DEFENSE: + case ATTR_EXTRADEFENSE: + case ATTR_ARMOR: + case ATTR_ATTACKSPEED: + case ATTR_HITCHANCE: + case ATTR_DURATION: + case ATTR_WRITTENDATE: + case ATTR_SLEEPERGUID: + case ATTR_SLEEPSTART: + case ATTR_CONTAINER_ITEMS: + case ATTR_ATTRIBUTE_MAP: + in->skip(4); + break; + case ATTR_SCRIPTPROTECTED: + case ATTR_DUALWIELD: + case ATTR_DECAYING_STATE: + case ATTR_HOUSEDOORID: + case ATTR_RUNE_CHARGES: + in->skip(1); + break; + case ATTR_TEXT: + setText(in->getString()); + break; + case ATTR_DEPOT_ID: + in->skip(2); // trolol + break; + case ATTR_TELE_DEST: + { + Position pos(in->getU16(), in->getU16(), in->getU8()); + break; + } + default: + stdext::throw_exception(stdext::format("invalid item attribute %d", (int)attrType)); + } } } diff --git a/src/otclient/core/item.h b/src/otclient/core/item.h index a66997dd..6263f1db 100644 --- a/src/otclient/core/item.h +++ b/src/otclient/core/item.h @@ -29,8 +29,6 @@ enum AttrTypes_t { ATTR_END = 0, - //ATTR_DESCRIPTION = 1, - //ATTR_EXT_FILE = 2, ATTR_TILE_FLAGS = 3, ATTR_ACTION_ID = 4, ATTR_UNIQUE_ID = 5, @@ -39,10 +37,8 @@ enum AttrTypes_t { ATTR_TELE_DEST = 8, ATTR_ITEM = 9, ATTR_DEPOT_ID = 10, - //ATTR_EXT_SPAWN_FILE = 11, ATTR_RUNE_CHARGES = 12, - //ATTR_EXT_HPPOUSE_FILE = 13, - ATTR_HPPOUSEDOORID = 14, + ATTR_HOUSEDOORID = 14, ATTR_COUNT = 15, ATTR_DURATION = 16, ATTR_DECAYING_STATE = 17, @@ -60,7 +56,7 @@ enum AttrTypes_t { ATTR_EXTRADEFENSE = 36, ATTR_ARMOR = 37, ATTR_ATTACKSPEED = 38, - ATTR_HPPITCHANCE = 39, + ATTR_HITCHANCE = 39, ATTR_SHOOTRANGE = 40, ATTR_ARTICLE = 41, ATTR_SCRIPTPROTECTED = 42, @@ -100,10 +96,7 @@ public: ItemPtr asItem() { return std::static_pointer_cast(shared_from_this()); } bool isItem() { return true; } - // TODO: These should be abstract and declared in i.e containers, doors, etc. - bool unserializeAttr(const BinaryTreePtr &fin); - bool unserializeItemNode(const BinaryTreePtr &fin) { return unserializeAttr(fin); } - void readAttr(AttrTypes_t attrType, const BinaryTreePtr &fin); + void unserializeItem(const BinaryTreePtr &in); bool isMoveable(); private: diff --git a/src/otclient/core/map.cpp b/src/otclient/core/map.cpp index bcdb37ab..20c5b96f 100644 --- a/src/otclient/core/map.cpp +++ b/src/otclient/core/map.cpp @@ -27,12 +27,14 @@ #include "item.h" #include "missile.h" #include "statictext.h" +#include "houses.h" +#include "towns.h" #include #include "mapview.h" #include #include -#include +#include Map g_map; @@ -59,67 +61,61 @@ void Map::notificateTileUpdateToMapViews(const Position& pos) mapView->onTileUpdate(pos); } -bool Map::loadOtbm(const std::string& fileName) +void Map::loadOtbm(const std::string& fileName, bool /*display*/) { FileStreamPtr fin = g_resources.openFile(fileName); - if (!fin) { - g_logger.error(stdext::format("Unable to load map '%s'", fileName)); - return false; - } + if (!fin) + stdext::throw_exception(stdext::format("Unable to load map '%s'", fileName)); - if (!g_things.isOtbLoaded()/* || !g_things.isXmlLoaded()*/) { - g_logger.error("OTB and XML are not loaded yet to load a map."); - return false; - } + fin->cache(); + if (!g_things.isOtbLoaded()) + stdext::throw_exception("OTB isn't loaded yet to load a map."); + + if (fin->getU32()) + stdext::throw_exception("Unknown file version detected"); - assert(fin->getU32() == 0); BinaryTreePtr root = fin->getBinaryTree(); - root->skip(1); // Not sure, what exactly that is... perhaps node type? + if (root->getU8() != 0) + stdext::throw_exception("could not read root property!"); + uint32 headerVersion = root->getU32(); - dump << headerVersion; - if (!headerVersion || headerVersion > 3) { - g_logger.error("Unknown OTBM version detected."); - return false; - } + if (!headerVersion || headerVersion > 3) + stdext::throw_exception(stdext::format("Unknown OTBM version detected: %u.", headerVersion)); + + uint16 w = root->getU16(), h = root->getU16(); + dump << "Map size: " << w << "x" << h; - root->skip(1); // ?? uint32 headerMajorItems = root->getU8(); - dump << headerMajorItems; - dump << "major: " << g_things.getOtbMajorVersion(); - if (headerMajorItems < 3) { - g_logger.error("This map needs to be upgraded."); - return false; - } + if (headerMajorItems < 3) + stdext::throw_exception(stdext::format("This map needs to be upgraded. read %d what it's supposed to be: %u", + headerMajorItems, g_things.getOtbMajorVersion())); - if (headerMajorItems > g_things.getOtbMajorVersion()) { - g_logger.error("This map was saved with different OTB version."); - return false; - } + if (headerMajorItems > g_things.getOtbMajorVersion()) + stdext::throw_exception(stdext::format("This map was saved with different OTB version. read %d what it's supposed to be: %d", + headerMajorItems, g_things.getOtbMajorVersion())); - root->skip(1); /// ?? - uint32 headerMinorItems = root->getU8(); - dump << headerMinorItems; - dump << "minor: " << g_things.getOtbMinorVersion(); + root->skip(3); + uint32 headerMinorItems = root->getU32(); if (headerMinorItems > g_things.getOtbMinorVersion()) - g_logger.warning("This map needs an updated OTB."); + g_logger.warning(stdext::format("This map needs an updated OTB. read %d what it's supposed to be: %d", + headerMinorItems, g_things.getOtbMinorVersion())); BinaryTreePtr node = root->getChildren()[0]; - if (node->getU8() != OTBM_MAP_DATA) { - g_logger.error("Could not read data node."); - return false; - } + if (node->getU8() != OTBM_MAP_DATA) + stdext::throw_exception("Could not read root data node"); - std::string tmp; - uint8 attribute; + Boolean first; while (node->canRead()) { - attribute = node->getU8(); - tmp = node->getString(); + uint8 attribute = node->getU8(); + std::string tmp = node->getString(); switch (attribute) { case OTBM_ATTR_DESCRIPTION: - if (!m_description.empty()) - m_description += "\n" + tmp; - else + if (first) { + first = false; m_description = tmp; + } else { + m_description += "\n" + tmp; + } break; case OTBM_ATTR_SPAWN_FILE: m_spawnFile = fileName.substr(0, fileName.rfind('/') + 1) + tmp; @@ -128,151 +124,130 @@ bool Map::loadOtbm(const std::string& fileName) m_houseFile = fileName.substr(0, fileName.rfind('/') + 1) + tmp; break; default: - g_logger.error(stdext::format("Invalid attribute '%c'", attribute)); - break; + stdext::throw_exception(stdext::format("Invalid attribute '%c'", attribute)); } } - dump << m_description; - dump << m_houseFile; - dump << m_spawnFile; - for (const BinaryTreePtr &nodeMapData : node->getChildren()) { uint8 mapDataType = nodeMapData->getU8(); - dump << "mapData: " << (int)mapDataType; if (mapDataType == OTBM_TILE_AREA) { - dump << "Tile: reading pos..."; uint16 baseX = nodeMapData->getU16(), baseY = nodeMapData->getU16(); uint8 pz = nodeMapData->getU8(); for (const BinaryTreePtr &nodeTile : nodeMapData->getChildren()) { uint8 type = nodeTile->getU8(); if (type == OTBM_TILE || type == OTBM_HOUSETILE) { - TilePtr tile = 0; - ItemPtr ground = 0; + TilePtr tile = nullptr; + ItemPtr ground = nullptr; + HousePtr house = nullptr; uint32 flags = 0; - uint16 px = baseX + nodeTile->getU16(), py = baseY + nodeTile->getU16(); + uint16 px = baseX + nodeTile->getU8(), py = baseY + nodeTile->getU8(); Position pos(px, py, pz); - // TODO: Houses. if (type == OTBM_HOUSETILE) { uint32 hId = nodeTile->getU32(); - tile = createTile(pos); - // TODO: add it to house. + if (!(house = g_houses.getHouse(hId))) + house = HousePtr(new House(hId)); + house->setTile(tile); } - uint8 tileAttr; while (nodeTile->canRead()) { - tileAttr = nodeTile->getU8(); + uint8 tileAttr = nodeTile->getU8(); switch (tileAttr) { - case OTBM_ATTR_TILE_FLAGS: { - uint32 _flags = nodeTile->getU32(); - - if ((_flags & TILESTATE_PROTECTIONZONE) == TILESTATE_PROTECTIONZONE) - flags |= TILESTATE_PROTECTIONZONE; - else if ((_flags & TILESTATE_OPTIONALZONE) == TILESTATE_OPTIONALZONE) - flags |= TILESTATE_OPTIONALZONE; - else if ((_flags & TILESTATE_HPPARDCOREZONE) == TILESTATE_HPPARDCOREZONE) - flags |= TILESTATE_HPPARDCOREZONE; - - if ((_flags & TILESTATE_NOLOGOUT) == TILESTATE_NOLOGOUT) - flags |= TILESTATE_NOLOGOUT; - - if ((_flags & TILESTATE_REFRESH) == TILESTATE_REFRESH) - flags |= TILESTATE_REFRESH; - break; - } case OTBM_ATTR_ITEM: { - ItemPtr item = Item::createFromOtb(nodeTile->getU16()); - if (!item) { - g_logger.error(stdext::format("failed to create new item at tile pos %d, %d, %d", px, py, pz)); - return false; + case OTBM_ATTR_TILE_FLAGS: { + uint32 _flags = nodeTile->getU32(); + if ((_flags & TILESTATE_PROTECTIONZONE) == TILESTATE_PROTECTIONZONE) + flags |= TILESTATE_PROTECTIONZONE; + else if ((_flags & TILESTATE_OPTIONALZONE) == TILESTATE_OPTIONALZONE) + flags |= TILESTATE_OPTIONALZONE; + else if ((_flags & TILESTATE_HARDCOREZONE) == TILESTATE_HARDCOREZONE) + flags |= TILESTATE_HARDCOREZONE; + + if ((_flags & TILESTATE_NOLOGOUT) == TILESTATE_NOLOGOUT) + flags |= TILESTATE_NOLOGOUT; + + if ((_flags & TILESTATE_REFRESH) == TILESTATE_REFRESH) + flags |= TILESTATE_REFRESH; + + break; } - - if (tile) { - tile->addThing(item); - } else if (item->isGround()) { - ground = item; - } else { - tile = createTile(pos); - tile->addThing(ground); - tile->addThing(item); + case OTBM_ATTR_ITEM: { + ItemPtr item = Item::createFromOtb(nodeTile->getU16()); + if (tile) + tile->addThing(item); + else if (item->isGround()) + ground = item; + else { + tile = createTile(pos, ground); + tile->addThing(item); + } + break; } - } default: { - g_logger.error(stdext::format("invalid tile attribute at pos %d, %d, %d", px, py, pz)); - return false; - } + default: + stdext::throw_exception(stdext::format("invalid tile attribute %d at pos %d, %d, %d", + (int)tileAttr, px, py, pz)); } } for (const BinaryTreePtr &nodeItem : nodeTile->getChildren()) { if (nodeItem->getU8() == OTBM_ITEM) { ItemPtr item = Item::createFromOtb(nodeItem->getU16()); - if (!item) { - g_logger.error(stdext::format("failed to create new item at pos %d, %d, %d", px, py, pz)); - return false; - } - - if (item->unserializeItemNode(nodeItem)) { - if (/* house && */item->isMoveable()) { - g_logger.warning(stdext::format("Moveable item found in house: %d at pos %d %d %d", item->getId(), - px, py, pz)); - item = nullptr; - } else if (tile) { - tile->addThing(item); - } else if (item->isGround()) { - ground = item; - } else { - tile = createTile(pos); - tile->addThing(ground); - tile->addThing(item); - } + item->unserializeItem(nodeItem); + if (house && item->isMoveable()) { + g_logger.warning(stdext::format("Moveable item found in house: %d at pos %d %d %d", item->getId(), + px, py, pz)); + item = nullptr; + } else if (tile) { + tile->addThing(item); + } else if (item->isGround()) { + ground = item; } else { - g_logger.error(stdext::format("failed to unserialize item with %d at pos %d %d %d", item->getId(), - px, py, pz)); - return false; + tile = createTile(pos, ground); + tile->addThing(item); } - } else { - g_logger.error(stdext::format("Unknown item node type %d", type)); - return false; - } + } else + stdext::throw_exception("Unknown item node"); } - if (!tile) { - tile = createTile(pos); - tile->addThing(ground); - } + if (!tile) + tile = createTile(pos, ground); tile->setFlags((tileflags_t)flags); - } else { - g_logger.error(stdext::format("Unknown tile node type %d", type)); - return false; - } + } else + stdext::throw_exception(stdext::format("Unknown tile node type %d", type)); } } else if (mapDataType == OTBM_TOWNS) { + TownPtr town = nullptr; for (const BinaryTreePtr &nodeTown : nodeMapData->getChildren()) { if (nodeTown->getU8() == OTBM_TOWN) { uint32 townId = nodeTown->getU32(); std::string townName = nodeTown->getString(); - Position townCoords(nodeTown->getU16(), nodeTown->getU16(), nodeTown->getU8()); + if (!(town = g_towns.getTown(townId))) + town = TownPtr(new Town(townId, townName, townCoords)); } else - return false; + stdext::throw_exception("invalid town node"); } } else if (mapDataType == OTBM_WAYPOINTS && headerVersion > 1) { for (const BinaryTreePtr &nodeWaypoint : nodeMapData->getChildren()) { if (nodeWaypoint->getU8() == OTBM_WAYPOINT) { std::string name = nodeWaypoint->getString(); Position waypointPos(nodeWaypoint->getU16(), nodeWaypoint->getU16(), nodeWaypoint->getU8()); - } + if (waypointPos.isValid() && !name.empty()) + m_waypoints.insert(std::make_pair(waypointPos, name)); + + } else + stdext::throw_exception("invalid waypoint node"); } } else - return false; + stdext::throw_exception("Unknown map data node"); } - // TODO: Load house & spawns. - return true; + g_logger.debug("OTBM read successfully."); + fin->close(); + /// TODO read XML Stuff (houses & spawns). } bool Map::loadOtcm(const std::string& fileName) @@ -300,7 +275,7 @@ bool Map::loadOtcm(const std::string& fileName) fin->getString(); // world name if(datSignature != g_things.getDatSignature()) - g_logger.warning("otcm map loaded is was created with a different dat signature"); + g_logger.warning("otcm map loaded was created with a different dat signature"); break; } @@ -417,6 +392,7 @@ void Map::clean() { cleanDynamicThings(); m_tiles.clear(); + m_waypoints.clear(); } void Map::cleanDynamicThings() @@ -538,9 +514,12 @@ bool Map::removeThingByPos(const Position& pos, int stackPos) return false; } -TilePtr Map::createTile(const Position& pos) +TilePtr Map::createTile(const Position& pos, const ItemPtr &g) { TilePtr tile = TilePtr(new Tile(pos)); + if (g) + tile->addThing(g); + m_tiles[pos] = tile; return tile; } diff --git a/src/otclient/core/map.h b/src/otclient/core/map.h index 029d6fe6..4b79ff91 100644 --- a/src/otclient/core/map.h +++ b/src/otclient/core/map.h @@ -42,7 +42,7 @@ enum OTBM_AttrTypes_t OTBM_ATTR_SPAWN_FILE = 11, OTBM_ATTR_RUNE_CHARGES = 12, OTBM_ATTR_HOUSE_FILE = 13, - OTBM_ATTR_HPPOUSEDOORID = 14, + OTBM_ATTR_HOUSEDOORID = 14, OTBM_ATTR_COUNT = 15, OTBM_ATTR_DURATION = 16, OTBM_ATTR_DECAYING_STATE = 17, @@ -77,7 +77,7 @@ enum OTBM_NodeTypes_t enum { OTCM_SIGNATURE = 0x4D43544F, - OTCM_VERSION = 1, + OTCM_VERSION = 1 }; //@bindsingleton g_map @@ -93,7 +93,7 @@ public: bool loadOtcm(const std::string& fileName); void saveOtcm(const std::string& fileName); - bool loadOtbm(const std::string& fileName); + void loadOtbm(const std::string& fileName, bool display = false/* temporary*/); //void saveOtbm(const std::string& fileName); void clean(); @@ -106,7 +106,7 @@ public: bool removeThingByPos(const Position& pos, int stackPos); // tile related - TilePtr createTile(const Position& pos); + TilePtr createTile(const Position& pos, const ItemPtr &g = nullptr); const TilePtr& getTile(const Position& pos); TilePtr getOrCreateTile(const Position& pos); void cleanTile(const Position& pos); @@ -146,6 +146,7 @@ private: std::vector m_animatedTexts; std::vector m_staticTexts; std::vector m_mapViews; + std::unordered_map m_waypoints; Light m_light; Position m_centralPosition; diff --git a/src/otclient/core/thingtypemanager.cpp b/src/otclient/core/thingtypemanager.cpp index 1ea9ad8f..6782076f 100644 --- a/src/otclient/core/thingtypemanager.cpp +++ b/src/otclient/core/thingtypemanager.cpp @@ -30,9 +30,6 @@ #include #include -#define TIXML_USE_STL // use STL strings instead. -#include - ThingTypeManager g_things; void ThingTypeManager::init() @@ -112,9 +109,11 @@ bool ThingTypeManager::loadOtb(const std::string& file) root->getU32(); // build number root->skip(128); // description + m_otbTypes.resize(root->getChildren().size(), m_nullOtbType); for(const BinaryTreePtr& node : root->getChildren()) { ThingTypeOtbPtr otbType(new ThingTypeOtb); otbType->unserialize(node); + addOtbType(otbType); } m_otbLoaded = true; diff --git a/src/otclient/core/tile.h b/src/otclient/core/tile.h index 586502d2..013f7e9e 100644 --- a/src/otclient/core/tile.h +++ b/src/otclient/core/tile.h @@ -33,7 +33,7 @@ enum tileflags_t TILESTATE_TRASHED = 1 << 1, TILESTATE_OPTIONALZONE = 1 << 2, TILESTATE_NOLOGOUT = 1 << 3, - TILESTATE_HPPARDCOREZONE = 1 << 4, + TILESTATE_HARDCOREZONE = 1 << 4, TILESTATE_REFRESH = 1 << 5, // internal usage From 992cbf9d1d3a1021883e3a35153a7cb7f1ceea24 Mon Sep 17 00:00:00 2001 From: niczkx Date: Sat, 14 Jul 2012 16:20:38 -0700 Subject: [PATCH 2/3] mapeditor changes --- TODO | 2 +- init.lua | 12 +- src/framework/application.h | 1 + src/framework/const.h | 16 +- src/framework/core/filestream.h | 2 + src/framework/luafunctions.cpp | 1 + src/framework/pch.h | 2 +- src/otclient/core/item.cpp | 44 ++- src/otclient/core/item.h | 13 +- src/otclient/core/map.cpp | 357 ++++++++++++------ src/otclient/core/map.h | 37 +- src/otclient/core/thingtypemanager.cpp | 188 ++++----- src/otclient/core/thingtypemanager.h | 4 +- src/otclient/core/thingtypeotb.cpp | 11 + src/otclient/core/thingtypeotb.h | 13 +- src/otclient/core/tile.h | 1 + src/otclient/luafunctions.cpp | 37 ++ .../generate_bitmap_font.py | 0 .../generate_lua_bindings.lua | 0 tools/pkgs/makeotc | 0 20 files changed, 471 insertions(+), 270 deletions(-) mode change 100755 => 100644 tools/gimp-bitmap-generator/generate_bitmap_font.py mode change 100755 => 100644 tools/lua-binding-generator/generate_lua_bindings.lua mode change 100755 => 100644 tools/pkgs/makeotc diff --git a/TODO b/TODO index 0a208716..1537544c 100644 --- a/TODO +++ b/TODO @@ -1,6 +1,6 @@ == MODULES game_shaders (with shader manager) -game_map (with save/load/options) +game_map (with save/load/option) game_minimap (with all tibia functionality) == NOTABLE FEATURES diff --git a/init.lua b/init.lua index deddc3b5..3a3982dc 100644 --- a/init.lua +++ b/init.lua @@ -5,7 +5,7 @@ g_logger.setLogFile(g_resources.getWorkDir() .. g_app.getCompactName() .. ".log") -- print first terminal message -g_logger.info(g_app.getName() .. ' ' .. g_app.getVersion() .. ' rev ' .. g_app.getBuildRevision() .. ' (' .. g_app.getBuildCommit() .. ') built on ' .. g_app.getBuildDate()) +g_logger.info(g_app.getName() .. ' ' .. g_app.getVersion() .. ' rev ' .. g_app.getBuildRevision() .. ' (' .. g_app.getBuildCommit() .. ') built on ' .. g_app.getBuildDate() .. ' for arch ' .. g_app.getBuildArch()) --add base folder to search path g_resources.addToSearchPath(g_resources.getWorkDir()) @@ -27,15 +27,15 @@ g_configs.load("/config.otml") g_modules.discoverModules() -- core modules 0-99 -g_modules.autoLoadModules(99); +g_modules.autoLoadModules(99) g_modules.ensureModuleLoaded("corelib") -- client modules 100-499 -g_modules.autoLoadModules(499); +g_modules.autoLoadModules(499) g_modules.ensureModuleLoaded("client") -- game modules 500-999 -g_modules.autoLoadModules(999); +g_modules.autoLoadModules(999) g_modules.ensureModuleLoaded("game") -- addons 1000-9999 @@ -45,7 +45,3 @@ if g_resources.fileExists("/otclientrc.lua") then dofile("/otclientrc.lua") end -g_things.loadOtb("/items.otb") -g_map.loadOtbm("/forgotten.otbm") - - diff --git a/src/framework/application.h b/src/framework/application.h index d74909c0..910189a2 100644 --- a/src/framework/application.h +++ b/src/framework/application.h @@ -71,6 +71,7 @@ public: std::string getBuildRevision() { return BUILD_REVISION; } std::string getBuildCommit() { return BUILD_COMMIT; } std::string getBuildType() { return BUILD_TYPE; } + std::string getBuildArch() { return BUILD_ARCH; } std::string getStartupOptions() { return m_startupOptions; } protected: diff --git a/src/framework/const.h b/src/framework/const.h index cb7f2d2d..f103b0cc 100644 --- a/src/framework/const.h +++ b/src/framework/const.h @@ -29,8 +29,8 @@ #define BUILD_COMPILER "gcc " __VERSION__ #define BUILD_DATE __DATE__ - #ifndef BUILD_COMMIT -#define BUILD_COMMIT "custom" +#ifndef BUILD_COMMIT +#define BUILD_COMMIT "devel" #endif #ifndef BUILD_REVISION @@ -41,6 +41,16 @@ #define BUILD_TYPE "unknown" #endif +#ifndef BUILD_ARCH +#if defined(__amd64) || defined(_M_X64) +#define BUILD_ARCH "x64" +#elif defined(__i386) || defined(_M_IX86) || defined(_X86_) +#define BUILD_ARCH "X86" +#else +#define BUILD_ARCH "unknown" +#endif +#endif + namespace Fw { constexpr float pi = 3.14159265; @@ -207,7 +217,7 @@ namespace Fw AnchorLeft, AnchorRight, AnchorVerticalCenter, - AnchorHorizontalCenter, + AnchorHorizontalCenter }; enum FocusReason { diff --git a/src/framework/core/filestream.h b/src/framework/core/filestream.h index b55426f8..44801c2d 100644 --- a/src/framework/core/filestream.h +++ b/src/framework/core/filestream.h @@ -59,6 +59,8 @@ public: void addU32(uint32 v); void addU64(uint64 v); void addString(const std::string& v); + void startNode(uint8 nodeType) { addU8(0xFE); addU8(nodeType); } + void endNode() { addU8(0xFF); } FileStreamPtr asFileStream() { return std::static_pointer_cast(shared_from_this()); } diff --git a/src/framework/luafunctions.cpp b/src/framework/luafunctions.cpp index 8890a539..34a7e001 100644 --- a/src/framework/luafunctions.cpp +++ b/src/framework/luafunctions.cpp @@ -501,6 +501,7 @@ void Application::registerLuaFunctions() g_lua.bindSingletonFunction("g_app", "getBuildRevision", &Application::getBuildRevision, &g_app); g_lua.bindSingletonFunction("g_app", "getBuildCommit", &Application::getBuildCommit, &g_app); g_lua.bindSingletonFunction("g_app", "getBuildType", &Application::getBuildType, &g_app); + g_lua.bindSingletonFunction("g_app", "getBuildArch", &Application::getBuildArch, &g_app); g_lua.bindSingletonFunction("g_app", "exit", &Application::exit, &g_app); // ConfigManager diff --git a/src/framework/pch.h b/src/framework/pch.h index a27c02ee..222768c4 100644 --- a/src/framework/pch.h +++ b/src/framework/pch.h @@ -64,7 +64,7 @@ #include // tiny XML -#define TIXML_USE_STL +#define TIXML_USE_STL // use std::string's instead #include #endif diff --git a/src/otclient/core/item.cpp b/src/otclient/core/item.cpp index c9fbc41f..f32b6749 100644 --- a/src/otclient/core/item.cpp +++ b/src/otclient/core/item.cpp @@ -26,6 +26,9 @@ #include "thing.h" #include "tile.h" #include "shadermanager.h" +#include "container.h" +#include "map.h" +#include "houses.h" #include #include @@ -206,12 +209,12 @@ bool Item::isValid() void Item::unserializeItem(const BinaryTreePtr &in) { - // Yet another TODO. while (in->canRead()) { uint8 attrType = in->getU8(); if (attrType == 0) break; + // fugly switch yes? switch ((AttrTypes_t)attrType) { case ATTR_COUNT: setSubType(in->getU8()); @@ -228,9 +231,31 @@ void Item::unserializeItem(const BinaryTreePtr &in) case ATTR_NAME: setName(in->getString()); break; - case ATTR_ARTICLE: // ? - case ATTR_WRITTENBY: + case ATTR_TEXT: + setText(in->getString()); + break; case ATTR_DESC: + m_description = in->getString(); + break; + case ATTR_CONTAINER_ITEMS: + m_isContainer = true; + in->skip(4); + break; + case ATTR_HOUSEDOORID: + m_isDoor = true; + m_doorId = in->getU8(); + break; + case ATTR_DEPOT_ID: + m_depotId = in->getU16(); + break; + case ATTR_TELE_DEST: { + m_teleportDestination.x = in->getU16(); + m_teleportDestination.y = in->getU16(); + m_teleportDestination.z = in->getU8(); + break; + } + case ATTR_ARTICLE: + case ATTR_WRITTENBY: in->getString(); break; case ATTR_ATTACK: @@ -244,28 +269,15 @@ void Item::unserializeItem(const BinaryTreePtr &in) case ATTR_WRITTENDATE: case ATTR_SLEEPERGUID: case ATTR_SLEEPSTART: - case ATTR_CONTAINER_ITEMS: case ATTR_ATTRIBUTE_MAP: in->skip(4); break; case ATTR_SCRIPTPROTECTED: case ATTR_DUALWIELD: case ATTR_DECAYING_STATE: - case ATTR_HOUSEDOORID: case ATTR_RUNE_CHARGES: in->skip(1); break; - case ATTR_TEXT: - setText(in->getString()); - break; - case ATTR_DEPOT_ID: - in->skip(2); // trolol - break; - case ATTR_TELE_DEST: - { - Position pos(in->getU16(), in->getU16(), in->getU8()); - break; - } default: stdext::throw_exception(stdext::format("invalid item attribute %d", (int)attrType)); } diff --git a/src/otclient/core/item.h b/src/otclient/core/item.h index 6263f1db..0f22bd82 100644 --- a/src/otclient/core/item.h +++ b/src/otclient/core/item.h @@ -27,7 +27,8 @@ #include "thing.h" #include "thingtypeotb.h" -enum AttrTypes_t { +enum AttrTypes_t +{ ATTR_END = 0, ATTR_TILE_FLAGS = 3, ATTR_ACTION_ID = 4, @@ -82,6 +83,7 @@ public: void setSubType(int subType) { m_countOrSubType = subType; } void setActionId(int actionId) { m_actionId = actionId; } void setUniqueId(int uniqueId) { m_uniqueId = uniqueId; } + void setDoorId(int doorId) { m_doorId = doorId; } void setName(const std::string &name) { m_name = name; } void setText(const std::string &text) { m_text = text; } void setDescription(const std::string &description) { m_description = description; } @@ -91,6 +93,7 @@ public: int getCount() { return m_countOrSubType; } uint32 getId() { return m_id; } std::string getName() { return m_name; } + uint8 getDoorId() { return m_doorId; } bool isValid(); ItemPtr asItem() { return std::static_pointer_cast(shared_from_this()); } @@ -98,14 +101,22 @@ public: void unserializeItem(const BinaryTreePtr &in); bool isMoveable(); + bool isContainer() { return m_isContainer; } + bool isDoor() { return m_isDoor; } private: uint16 m_id; uint8 m_countOrSubType; uint32 m_actionId, m_uniqueId; + uint16 m_depotId; + uint8 m_doorId; + Boolean m_isContainer; + Boolean m_isDoor; + std::string m_name, m_text, m_description; PainterShaderProgramPtr m_shaderProgram; ThingTypeOtbPtr m_otbType; + Position m_teleportDestination; }; #endif diff --git a/src/otclient/core/map.cpp b/src/otclient/core/map.cpp index 20c5b96f..501d3d55 100644 --- a/src/otclient/core/map.cpp +++ b/src/otclient/core/map.cpp @@ -27,14 +27,13 @@ #include "item.h" #include "missile.h" #include "statictext.h" -#include "houses.h" -#include "towns.h" #include #include "mapview.h" #include #include #include +#include Map g_map; @@ -61,7 +60,7 @@ void Map::notificateTileUpdateToMapViews(const Position& pos) mapView->onTileUpdate(pos); } -void Map::loadOtbm(const std::string& fileName, bool /*display*/) +void Map::loadOtbm(const std::string& fileName) { FileStreamPtr fin = g_resources.openFile(fileName); if (!fin) @@ -75,47 +74,45 @@ void Map::loadOtbm(const std::string& fileName, bool /*display*/) stdext::throw_exception("Unknown file version detected"); BinaryTreePtr root = fin->getBinaryTree(); - if (root->getU8() != 0) + if (root->getU8()) stdext::throw_exception("could not read root property!"); uint32 headerVersion = root->getU32(); if (!headerVersion || headerVersion > 3) stdext::throw_exception(stdext::format("Unknown OTBM version detected: %u.", headerVersion)); - uint16 w = root->getU16(), h = root->getU16(); - dump << "Map size: " << w << "x" << h; + m_width = root->getU16(); + m_height = root->getU16(); + dump << "Map size: " << m_width << "x" << m_height; uint32 headerMajorItems = root->getU8(); - if (headerMajorItems < 3) + if (headerMajorItems < 3) { stdext::throw_exception(stdext::format("This map needs to be upgraded. read %d what it's supposed to be: %u", headerMajorItems, g_things.getOtbMajorVersion())); + } - if (headerMajorItems > g_things.getOtbMajorVersion()) + if (headerMajorItems > g_things.getOtbMajorVersion()) { stdext::throw_exception(stdext::format("This map was saved with different OTB version. read %d what it's supposed to be: %d", headerMajorItems, g_things.getOtbMajorVersion())); + } root->skip(3); uint32 headerMinorItems = root->getU32(); - if (headerMinorItems > g_things.getOtbMinorVersion()) + if (headerMinorItems > g_things.getOtbMinorVersion()) { g_logger.warning(stdext::format("This map needs an updated OTB. read %d what it's supposed to be: %d", headerMinorItems, g_things.getOtbMinorVersion())); + } BinaryTreePtr node = root->getChildren()[0]; if (node->getU8() != OTBM_MAP_DATA) stdext::throw_exception("Could not read root data node"); - Boolean first; while (node->canRead()) { uint8 attribute = node->getU8(); std::string tmp = node->getString(); switch (attribute) { case OTBM_ATTR_DESCRIPTION: - if (first) { - first = false; - m_description = tmp; - } else { - m_description += "\n" + tmp; - } + m_description += tmp + "\n"; break; case OTBM_ATTR_SPAWN_FILE: m_spawnFile = fileName.substr(0, fileName.rfind('/') + 1) + tmp; @@ -136,110 +133,131 @@ void Map::loadOtbm(const std::string& fileName, bool /*display*/) for (const BinaryTreePtr &nodeTile : nodeMapData->getChildren()) { uint8 type = nodeTile->getU8(); - if (type == OTBM_TILE || type == OTBM_HOUSETILE) { - TilePtr tile = nullptr; - ItemPtr ground = nullptr; - HousePtr house = nullptr; - uint32 flags = 0; - - uint16 px = baseX + nodeTile->getU8(), py = baseY + nodeTile->getU8(); - Position pos(px, py, pz); - - if (type == OTBM_HOUSETILE) { - uint32 hId = nodeTile->getU32(); - tile = createTile(pos); - if (!(house = g_houses.getHouse(hId))) - house = HousePtr(new House(hId)); - house->setTile(tile); + if (type != OTBM_TILE && type != OTBM_HOUSETILE) + stdext::throw_exception(stdext::format("invalid node tile type %d", (int)type)); + + TilePtr tile = nullptr; + ItemPtr ground = nullptr; + HousePtr house = nullptr; + uint32 flags = TILESTATE_NONE; + + uint16 px = baseX + nodeTile->getU8(), py = baseY + nodeTile->getU8(); + Position pos(px, py, pz); + + if (type == OTBM_HOUSETILE) { + uint32 hId = nodeTile->getU32(); + tile = createTile(pos); + if (!(house = m_houses.getHouse(hId))) { + house = HousePtr(new House(hId)); + m_houses.addHouse(house); } + house->setTile(tile); + } - while (nodeTile->canRead()) { - uint8 tileAttr = nodeTile->getU8(); - switch (tileAttr) { - case OTBM_ATTR_TILE_FLAGS: { - uint32 _flags = nodeTile->getU32(); - if ((_flags & TILESTATE_PROTECTIONZONE) == TILESTATE_PROTECTIONZONE) - flags |= TILESTATE_PROTECTIONZONE; - else if ((_flags & TILESTATE_OPTIONALZONE) == TILESTATE_OPTIONALZONE) - flags |= TILESTATE_OPTIONALZONE; - else if ((_flags & TILESTATE_HARDCOREZONE) == TILESTATE_HARDCOREZONE) - flags |= TILESTATE_HARDCOREZONE; - - if ((_flags & TILESTATE_NOLOGOUT) == TILESTATE_NOLOGOUT) - flags |= TILESTATE_NOLOGOUT; - - if ((_flags & TILESTATE_REFRESH) == TILESTATE_REFRESH) - flags |= TILESTATE_REFRESH; - - break; - } - case OTBM_ATTR_ITEM: { - ItemPtr item = Item::createFromOtb(nodeTile->getU16()); - if (tile) - tile->addThing(item); - else if (item->isGround()) - ground = item; - else { - tile = createTile(pos, ground); - tile->addThing(item); - } - break; - } - default: - stdext::throw_exception(stdext::format("invalid tile attribute %d at pos %d, %d, %d", - (int)tileAttr, px, py, pz)); + while (nodeTile->canRead()) { + uint8 tileAttr = nodeTile->getU8(); + switch (tileAttr) { + case OTBM_ATTR_TILE_FLAGS: { + uint32 _flags = nodeTile->getU32(); + if ((_flags & TILESTATE_PROTECTIONZONE) == TILESTATE_PROTECTIONZONE) + flags |= TILESTATE_PROTECTIONZONE; + else if ((_flags & TILESTATE_OPTIONALZONE) == TILESTATE_OPTIONALZONE) + flags |= TILESTATE_OPTIONALZONE; + else if ((_flags & TILESTATE_HARDCOREZONE) == TILESTATE_HARDCOREZONE) + flags |= TILESTATE_HARDCOREZONE; + + if ((_flags & TILESTATE_NOLOGOUT) == TILESTATE_NOLOGOUT) + flags |= TILESTATE_NOLOGOUT; + + if ((_flags & TILESTATE_REFRESH) == TILESTATE_REFRESH) + flags |= TILESTATE_REFRESH; + + break; } + case OTBM_ATTR_ITEM: { + ItemPtr item = Item::createFromOtb(nodeTile->getU16()); + if (tile) + addThing(item, pos, 255); + else if (item->isGround()) + ground = item; + else + tile = createTileEx(pos, ground, item); + break; + } + default: + stdext::throw_exception(stdext::format("invalid tile attribute %d at pos %d, %d, %d", + (int)tileAttr, px, py, pz)); } + } - for (const BinaryTreePtr &nodeItem : nodeTile->getChildren()) { - if (nodeItem->getU8() == OTBM_ITEM) { - ItemPtr item = Item::createFromOtb(nodeItem->getU16()); - item->unserializeItem(nodeItem); - if (house && item->isMoveable()) { - g_logger.warning(stdext::format("Moveable item found in house: %d at pos %d %d %d", item->getId(), - px, py, pz)); - item = nullptr; - } else if (tile) { - tile->addThing(item); - } else if (item->isGround()) { - ground = item; - } else { - tile = createTile(pos, ground); - tile->addThing(item); - } - } else - stdext::throw_exception("Unknown item node"); + for (const BinaryTreePtr &nodeItem : nodeTile->getChildren()) { + if (nodeItem->getU8() != OTBM_ITEM) + stdext::throw_exception("invalid item node"); + + ItemPtr item = Item::createFromOtb(nodeItem->getU16()); + item->unserializeItem(nodeItem); + if (item->isContainer()) { + // This is a temporary way for reading container items. + MapContainerPtr mapContainer(new MapContainer); + for (const BinaryTreePtr &insideItem : nodeItem->getChildren()) { + if (insideItem->getU8() != OTBM_ITEM) + stdext::throw_exception("invalid container item node"); + + ItemPtr newItem = Item::createFromOtb(insideItem->getU16()); + newItem->unserializeItem(insideItem); + mapContainer->add(newItem); + } + m_containers.push_back(mapContainer); } - if (!tile) - tile = createTile(pos, ground); + if (house) { + if (item->isMoveable()) { + g_logger.warning(stdext::format("Movable item found in house: %d at pos %d %d %d - escaping...", item->getId(), + px, py, pz)); + item = nullptr; + } else if (item->isDoor()) + house->addDoor(item->getDoorId(), pos); + } else if (tile) + addThing(item, pos, 255); + else if (item->isGround()) + ground = item; + else + tile = createTileEx(pos, ground, item); + } - tile->setFlags((tileflags_t)flags); - } else - stdext::throw_exception(stdext::format("Unknown tile node type %d", type)); + if (!tile) + tile = createTileEx(pos, ground); + + tile->setFlags((tileflags_t)flags); } } else if (mapDataType == OTBM_TOWNS) { TownPtr town = nullptr; for (const BinaryTreePtr &nodeTown : nodeMapData->getChildren()) { - if (nodeTown->getU8() == OTBM_TOWN) { - uint32 townId = nodeTown->getU32(); - std::string townName = nodeTown->getString(); - Position townCoords(nodeTown->getU16(), nodeTown->getU16(), nodeTown->getU8()); - if (!(town = g_towns.getTown(townId))) - town = TownPtr(new Town(townId, townName, townCoords)); - } else - stdext::throw_exception("invalid town node"); + if (nodeTown->getU8() != OTBM_TOWN) + stdext::throw_exception("invalid town node."); + + uint32 townId = nodeTown->getU32(); + std::string townName = nodeTown->getString(); + Position townCoords(nodeTown->getU16(), nodeTown->getU16(), nodeTown->getU8()); + if (!(town = m_towns.getTown(townId))) { + town = TownPtr(new Town(townId, townName, townCoords)); + m_towns.addTown(town); + } else { + // override data + town->setName(townName); + town->setPos(townCoords); + town->setId(townId); + } } } else if (mapDataType == OTBM_WAYPOINTS && headerVersion > 1) { for (const BinaryTreePtr &nodeWaypoint : nodeMapData->getChildren()) { - if (nodeWaypoint->getU8() == OTBM_WAYPOINT) { - std::string name = nodeWaypoint->getString(); - Position waypointPos(nodeWaypoint->getU16(), nodeWaypoint->getU16(), nodeWaypoint->getU8()); - if (waypointPos.isValid() && !name.empty()) - m_waypoints.insert(std::make_pair(waypointPos, name)); - - } else - stdext::throw_exception("invalid waypoint node"); + if (nodeWaypoint->getU8() != OTBM_WAYPOINT) + stdext::throw_exception("invalid waypoint node."); + + std::string name = nodeWaypoint->getString(); + Position waypointPos(nodeWaypoint->getU16(), nodeWaypoint->getU16(), nodeWaypoint->getU8()); + 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"); @@ -250,6 +268,115 @@ void Map::loadOtbm(const std::string& fileName, bool /*display*/) /// TODO read XML Stuff (houses & spawns). } +void Map::saveOtbm(const std::string &fileName) +{ + // TODO: Continue sleepy work. +#if 0 + /// TODO: Use binary trees for this + FileStreamPtr fin = g_resources.openFile(fileName); + if(!fin) + stdext::throw_exception(stdext::format("failed to open file '%s'", fileName)); + + std::string dir; + if (fileName.find_last_of('/') <= 0) + dir = g_resources.getWorkDir(); + else + dir = fileName.substr(0, fileName.find_last_of('/')); + + if (m_houseFile.empty()) + m_houseFile = "houses.xml"; + if (m_spawnFile.empty()) + m_spawnFile = "spawns.xml"; + +#if 0 + if (!m_houses->save(dir + "/" + m_houseFile)) + ; + if (!m_spawns->save(dir + "/" + m_spawnFile)) + ; +#endif + + uint32 ver; + if (g_things.getOtbMajorVersion() < 2) + ver =0; + else if (g_things.getOtbMajorVersion() < 10) + ver = 1; + else + ver = 2; + + fin->addU32(0x00); // file version + { + fin->startNode(0x00); // root + fin->addU32(ver); + fin->addU16(m_width); // some random width. + fin->addU16(m_height); // some random height. + + fin->addU32(g_things.getOtbMajorVersion()); + fin->addU32(g_things.getOtbMinorVersion()); + + fin->startNode(OTBM_MAP_DATA); // map data node + { + // own description. + fin->addU8(OTBM_ATTR_DESCRIPTION); + fin->addString(m_description); + + // special one + fin->addU8(OTBM_ATTR_DESCRIPTION); + fin->addString(stdext::format("Saved with %s v%d", g_app.getName(), stdext::unsafe_cast(g_app.getVersion()))); + + // spawn file. + fin->addU8(OTBM_ATTR_SPAWN_FILE); + fin->addString(m_spawnFile); + + // house file. + if (ver > 1) { + fin->addU8(OTBM_ATTR_HOUSE_FILE); + fin->addString(m_houseFile); + } + + Position pos(-1, -1, -1); + Boolean first; + for (auto& pair : m_tiles) { + TilePtr tile = pair.second; + if(!tile || tile->isEmpty()) + continue; + + Position tilePos = pair.first; + if (tilePos.x < pos.x || tilePos.x >= pos.x + 256 || + tilePos.y < pos.y || tilePos.y >= pos.y + 256 || + tilePos.z != pos.z) { + if (!first) + fin->endNode(); + + pos.x = tilePos.x & 0xFF00; + pos.y = tilePos.y & 0xFF00; + pos.z = tilePos.z; + fin->addU16(pos.x); + fin->addU16(pos.y); + fin->addU8(pos.z); + } + + // TODO: hOUSES. + fin->startNode(OTBM_TILE); + fin->addU8(tilePos.x); + fin->addU8(tilePos.y); + +#if 0 + // TODO: hOUSES again. + if (is house tile) + add u32 house id...; +#endif + if (tile->flags()) { + fin->addU8(OTBM_ATTR_TILE_FLAGS); + fin->addU32(tile->flags()); + } + + + } + } + } +#endif +} + bool Map::loadOtcm(const std::string& fileName) { try { @@ -393,6 +520,10 @@ void Map::clean() cleanDynamicThings(); m_tiles.clear(); m_waypoints.clear(); + + // This is a fix to a segfault on exit. + m_towns.clear(); + m_houses.clear(); } void Map::cleanDynamicThings() @@ -514,12 +645,20 @@ bool Map::removeThingByPos(const Position& pos, int stackPos) return false; } -TilePtr Map::createTile(const Position& pos, const ItemPtr &g) +template +TilePtr Map::createTileEx(const Position& pos, const Items&... items) { - TilePtr tile = TilePtr(new Tile(pos)); - if (g) - tile->addThing(g); + TilePtr tile = getOrCreateTile(pos); + auto vec = {items...}; + for (auto it : vec) + addThing(it, pos, 255); + return tile; +} + +TilePtr Map::createTile(const Position& pos) +{ + TilePtr tile = TilePtr(new Tile(pos)); m_tiles[pos] = tile; return tile; } diff --git a/src/otclient/core/map.h b/src/otclient/core/map.h index 4b79ff91..cf2a7f89 100644 --- a/src/otclient/core/map.h +++ b/src/otclient/core/map.h @@ -24,6 +24,8 @@ #define MAP_H #include "creature.h" +#include "houses.h" +#include "towns.h" #include "animatedtext.h" #include @@ -80,6 +82,23 @@ enum { OTCM_VERSION = 1 }; +/// Temporary way for reading container items +struct MapContainer { +private: + std::vector m_items; + +public: + void add(const ItemPtr& item) { m_items.push_back(item); } + ItemPtr operator[](uint idx) { return getItem(idx); } + ItemPtr getItem(int index) { + if (index < 0 || index > (int)m_items.size()) + return nullptr; + + return m_items[index]; + } +}; +typedef std::shared_ptr MapContainerPtr; + //@bindsingleton g_map class Map { @@ -93,8 +112,8 @@ public: bool loadOtcm(const std::string& fileName); void saveOtcm(const std::string& fileName); - void loadOtbm(const std::string& fileName, bool display = false/* temporary*/); - //void saveOtbm(const std::string& fileName); + void loadOtbm(const std::string& fileName); + void saveOtbm(const std::string& fileName); void clean(); void cleanDynamicThings(); @@ -106,7 +125,9 @@ public: bool removeThingByPos(const Position& pos, int stackPos); // tile related - TilePtr createTile(const Position& pos, const ItemPtr &g = nullptr); + template + TilePtr createTileEx(const Position& pos, const Items&... items); + TilePtr createTile(const Position& pos); const TilePtr& getTile(const Position& pos); TilePtr getOrCreateTile(const Position& pos); void cleanTile(const Position& pos); @@ -120,6 +141,10 @@ public: std::vector getSpectatorsInRange(const Position& centerPos, bool multiFloor, int xRange, int yRange); std::vector getSpectatorsInRangeEx(const Position& centerPos, bool multiFloor, int minXRange, int maxXRange, int minYRange, int maxYRange); + // town/house related + TownPtr getTown(uint32 tid) { return m_towns.getTown(tid); } + HousePtr getHouse(uint32 hid) { return m_houses.getHouse(hid); } + void setLight(const Light& light) { m_light = light; } void setCentralPosition(const Position& centralPosition); @@ -147,11 +172,17 @@ private: std::vector m_staticTexts; std::vector m_mapViews; std::unordered_map m_waypoints; + std::vector m_containers; Light m_light; Position m_centralPosition; std::string m_description, m_spawnFile, m_houseFile; + + Houses m_houses; + Towns m_towns; + + uint16 m_width, m_height; }; extern Map g_map; diff --git a/src/otclient/core/thingtypemanager.cpp b/src/otclient/core/thingtypemanager.cpp index 6782076f..5ebffdba 100644 --- a/src/otclient/core/thingtypemanager.cpp +++ b/src/otclient/core/thingtypemanager.cpp @@ -87,151 +87,89 @@ bool ThingTypeManager::loadDat(const std::string& file) } } -bool ThingTypeManager::loadOtb(const std::string& file) +void ThingTypeManager::loadOtb(const std::string& file) { - try { - FileStreamPtr fin = g_resources.openFile(file); + FileStreamPtr fin = g_resources.openFile(file); - uint signature = fin->getU32(); - if(signature != 0) - stdext::throw_exception("invalid otb file"); + uint signature = fin->getU32(); + if(signature != 0) + stdext::throw_exception("invalid otb file"); - BinaryTreePtr root = fin->getBinaryTree(); + BinaryTreePtr root = fin->getBinaryTree(); - signature = root->getU32(); - if(signature != 0) - stdext::throw_exception("invalid otb file"); + signature = root->getU32(); + if(signature != 0) + stdext::throw_exception("invalid otb file"); - root->getU32(); // flags + root->getU32(); // flags - m_otbMajorVersion = root->getU32(); - m_otbMinorVersion = root->getU32(); - root->getU32(); // build number - root->skip(128); // description - - m_otbTypes.resize(root->getChildren().size(), m_nullOtbType); - for(const BinaryTreePtr& node : root->getChildren()) { - ThingTypeOtbPtr otbType(new ThingTypeOtb); - otbType->unserialize(node); - addOtbType(otbType); - } + m_otbMajorVersion = root->getU32(); + m_otbMinorVersion = root->getU32(); + root->getU32(); // build number + root->skip(128); // description - m_otbLoaded = true; - return true; - } catch(stdext::exception& e) { - g_logger.error(stdext::format("failed to load otb '%s': %s", file, e.what())); - return false; + m_otbTypes.resize(root->getChildren().size(), m_nullOtbType); + for(const BinaryTreePtr& node : root->getChildren()) { + ThingTypeOtbPtr otbType(new ThingTypeOtb); + otbType->unserialize(node); + addOtbType(otbType); } + + m_otbLoaded = true; } -bool ThingTypeManager::loadXml(const std::string& file) +void ThingTypeManager::loadXml(const std::string& file) { - /* - try { - TiXmlDocument doc(file.c_str()); - if (!doc.LoadFile()) { - g_logger.error(stdext::format("failed to load xml '%s'", file)); - return false; - } - - TiXmlElement* root = doc.FirstChildElement(); - if (!root) { - g_logger.error("invalid xml root"); - return false; - } - - if (root->ValueTStr() != "items") { - g_logger.error("invalid xml tag name, should be 'items'"); - return false; - } - - for (TiXmlElement *element = root->FirstChildElement(); element; element = element->NextSiblingElement()) { - if (element->ValueTStr() != "item") - continue; - - std::string name = element->Attribute("id"); - if (name.empty()) - continue; - - uint16 id = stdext::unsafe_cast(element->Attribute("id")); - uint16 idEx = 0; - if (!id) { - bool found = false; - // fallback into reading fromid and toid - uint16 fromid = stdext::unsafe_cast(element->Attribute("fromid")); - uint16 toid = stdext::unsafe_cast(element->Attribute("toid")); - ThingTypeOtbPtr iType; - for (int __id = fromid; __id < toid; ++__id) { - if (!(iType = getType(__id))) - continue; - - iType->name = name; - idEx = iType->id == fromid ? fromid : toid; - found = true; - } - - if (!found) + TiXmlDocument doc(file.c_str()); + if (!doc.LoadFile()) + stdext::throw_exception(stdext::format("failed to load xml '%s'", file)); + + TiXmlElement* root = doc.FirstChildElement(); + if (!root || root->ValueTStr() != "items") + stdext::throw_exception("invalid root tag name"); + + ThingTypeOtbPtr otbType = nullptr; + for (TiXmlElement *element = root->FirstChildElement(); element; element = element->NextSiblingElement()) { + if (element->ValueTStr() != "item") + continue; + + std::string name = element->Attribute("id"); + if (name.empty()) + continue; + + uint16 id = stdext::unsafe_cast(element->Attribute("id")); + if (!(otbType = getOtbType(id))) { + // try reading fromId toId + uint16 from = stdext::unsafe_cast(element->Attribute("fromId")); + uint16 to = stdext::unsafe_cast(element->Attribute("toid")); + + for (uint16 __id = from; __id < to; ++__id) { + if (!(otbType = getOtbType(__id))) continue; - } - ThingTypeOtbPtr otbType = getType(id); - if (!otbType) { - otbType = ThingTypeOtbPtr(new ItemData); - otbType->id = idEx ? idEx : id; - otbType->name = name; - addType(otbType->id, otbType); + otbType->setHasRange(); + otbType->setFromServerId(from); + otbType->setToServerId(to); + break; } - otbType->name = name; - - for (TiXmlElement *attr = element->FirstChildElement(); attr; attr = attr->NextSiblingElement()) { - if (attr->ValueTStr() != "attribute") - continue; - - std::string key = attr->Attribute("key"); - std::string value = attr->Attribute("value"); - if (key == "type") { - if (value == "magicfield") - otbType->category = IsMagicField; - else if (value == "key") - otbType->category = IsKey; - else if (value == "depot") - otbType->isDepot = true; - else if (value == "teleport") - otbType->category = IsTeleport; - else if (value == "bed") - otbType->isBed = true; - else if (value == "door") - otbType->category = IsDoor; - } else if (key == "name") { - otbType->name = value; - } else if (key == "description") { - otbType->description = value; - } else if (key == "weight") { - otbType->weight = stdext::unsafe_cast(stdext::unsafe_cast(value) / 100.f); - } else if (key == "containerSize") { - int containerSize = stdext::unsafe_cast(value); - if (containerSize) - otbType->containerSize = containerSize; - otbType->category = IsContainer; - } else if (key == "writeable") { - if (!value.empty()) - otbType->category = IsWritable; - } else if (key == "maxTextLen") { - otbType->maxTextLength = stdext::unsafe_cast(value); - } else if (key == "charges") { - otbType->charges = stdext::unsafe_cast(value); - } + // perform last check + if (!otbType) { + stdext::throw_exception(stdext::format("failed to find item with server id %d - tried reading fromid to id", + id)); } } - doc.Clear(); - } catch(stdext::exception& e) { + for (TiXmlElement *attr = element->FirstChildElement(); attr; attr = attr->NextSiblingElement()) { + if (attr->ValueTStr() != "attribute") + continue; + otbType->unserializeXML(attr); + } } - return true; - */ - return false; + + doc.Clear(); + m_xmlLoaded = true; } void ThingTypeManager::addOtbType(const ThingTypeOtbPtr& otbType) diff --git a/src/otclient/core/thingtypemanager.h b/src/otclient/core/thingtypemanager.h index 811cdd63..904ba12a 100644 --- a/src/otclient/core/thingtypemanager.h +++ b/src/otclient/core/thingtypemanager.h @@ -36,8 +36,8 @@ public: void terminate(); bool loadDat(const std::string& file); - bool loadOtb(const std::string& file); - bool loadXml(const std::string& file); + void loadOtb(const std::string& file); + void loadXml(const std::string& file); void addOtbType(const ThingTypeOtbPtr& otbType); const ThingTypeOtbPtr& findOtbForClientId(uint16 id); diff --git a/src/otclient/core/thingtypeotb.cpp b/src/otclient/core/thingtypeotb.cpp index 4dbbaf2a..9d5f59a5 100644 --- a/src/otclient/core/thingtypeotb.cpp +++ b/src/otclient/core/thingtypeotb.cpp @@ -62,3 +62,14 @@ void ThingTypeOtb::unserialize(const BinaryTreePtr& node) } } } + +void ThingTypeOtb::unserializeXML(const TiXmlElement* elem) +{ + std::string key = elem->Attribute("key"); + std::string value = elem->Attribute("value"); + + if (key == "name") + setName(value); + else if (key == "description") + setDesc(value); +} diff --git a/src/otclient/core/thingtypeotb.h b/src/otclient/core/thingtypeotb.h index f99360bf..dda35414 100644 --- a/src/otclient/core/thingtypeotb.h +++ b/src/otclient/core/thingtypeotb.h @@ -85,19 +85,30 @@ public: ThingTypeOtb(); void unserialize(const BinaryTreePtr& node); - void unserializeXML(); + void unserializeXML(const TiXmlElement* elem); uint16 getServerId() { return m_serverId; } uint16 getClientId() { return m_clientId; } OtbCategory getCategory() { return m_category; } bool isNull() { return m_null; } + bool hasRange() { return m_hasRange; } + + void setHasRange() { m_hasRange = true; } + void setFromServerId(uint16 from) { m_fromId = from; } + void setToServerId(uint16 to) { m_toId = to; } + void setName(const std::string& name) { m_name = name; } + void setDesc(const std::string& desc) { m_desc = desc; } private: uint16 m_serverId; uint16 m_clientId; + uint16 m_fromId, m_toId; + + std::string m_name, m_desc; OtbCategory m_category; Boolean m_null; + Boolean m_hasRange; }; #endif diff --git a/src/otclient/core/tile.h b/src/otclient/core/tile.h index 013f7e9e..e6a6844b 100644 --- a/src/otclient/core/tile.h +++ b/src/otclient/core/tile.h @@ -100,6 +100,7 @@ public: TilePtr asTile() { return std::static_pointer_cast(shared_from_this()); } void setFlags(tileflags_t flags) { m_flags |= (uint32)flags; } + uint32 flags() { return m_flags; } private: void update(); diff --git a/src/otclient/luafunctions.cpp b/src/otclient/luafunctions.cpp index 4387fd62..4b612786 100644 --- a/src/otclient/luafunctions.cpp +++ b/src/otclient/luafunctions.cpp @@ -38,6 +38,8 @@ #include #include #include +#include +#include #include #include #include @@ -53,6 +55,19 @@ void OTClient::registerLuaFunctions() g_lua.bindSingletonFunction("g_things", "loadXml", &ThingTypeManager::loadXml, &g_things); g_lua.bindSingletonFunction("g_things", "getDatSignature", &ThingTypeManager::getDatSignature, &g_things); +#if 0 + g_lua.registerSingletonClass("g_houses"); + g_lua.bindSingletonFunction("g_houses", "load", &Houses::load, &g_houses); + g_lua.bindSingletonFunction("g_houses", "getHouse", &Houses::getHouse, &g_houses); + g_lua.bindSingletonFunction("g_houses", "addHouse", &Houses::addHouse, &g_houses); + g_lua.bindSingletonFunction("g_houses", "removeHouse", &Houses::removeHouse, &g_houses); + + g_lua.registerSingletonClass("g_towns"); + g_lua.bindSingletonFunction("g_towns", "getTown", &Towns::getTown, &g_towns); + g_lua.bindSingletonFunction("g_towns", "addTown", &Towns::addTown, &g_towns); + g_lua.bindSingletonFunction("g_towns", "removeTown", &Towns::removeTown, &g_towns); +#endif + g_lua.registerSingletonClass("g_sprites"); g_lua.bindSingletonFunction("g_sprites", "loadSpr", &SpriteManager::loadSpr, &g_sprites); g_lua.bindSingletonFunction("g_sprites", "unload", &SpriteManager::unload, &g_sprites); @@ -81,6 +96,8 @@ void OTClient::registerLuaFunctions() //g_lua.bindSingletonFunction("g_map", "saveOtbm", &Map::saveOtbm, &g_map); g_lua.bindSingletonFunction("g_map", "loadOtcm", &Map::loadOtcm, &g_map); g_lua.bindSingletonFunction("g_map", "saveOtcm", &Map::saveOtcm, &g_map); + g_lua.bindSingletonFunction("g_map", "getTown", &Map::getTown, &g_map); + g_lua.bindSingletonFunction("g_map", "getHouse", &Map::getHouse, &g_map); g_lua.registerSingletonClass("g_game"); g_lua.bindSingletonFunction("g_game", "loginWorld", &Game::loginWorld, &g_game); @@ -255,6 +272,26 @@ void OTClient::registerLuaFunctions() g_lua.bindClassMemberFunction("isFullGround", &Thing::isFullGround); g_lua.bindClassMemberFunction("getParentContainer", &Thing::getParentContainer); + g_lua.registerClass(); + g_lua.bindClassStaticFunction("create", []{ return HousePtr(new House); }); + g_lua.bindClassMemberFunction("setId", &House::setId); + g_lua.bindClassMemberFunction("setName", &House::setName); + g_lua.bindClassMemberFunction("addDoor", &House::addDoor); + g_lua.bindClassMemberFunction("addDoorPos", &House::addDoor); // alternative method + g_lua.bindClassMemberFunction("setTile", &House::setTile); + g_lua.bindClassMemberFunction("addTile", &House::addDoor); // alternative method + + g_lua.registerClass(); + g_lua.bindClassStaticFunction("create", []{ return TownPtr(new Town); }); + g_lua.bindClassMemberFunction("setId", &Town::setId); + g_lua.bindClassMemberFunction("setName", &Town::setName); + g_lua.bindClassMemberFunction("setPos", &Town::setPos); + g_lua.bindClassMemberFunction("setTemplePos", &Town::setPos); // alternative method + g_lua.bindClassMemberFunction("getId", &Town::getId); + g_lua.bindClassMemberFunction("getName", &Town::getName); + g_lua.bindClassMemberFunction("getPos", &Town::getPos); + g_lua.bindClassMemberFunction("getTemplePos", &Town::getPos); // alternative method + g_lua.registerClass(); g_lua.bindClassStaticFunction("create", []{ return CreaturePtr(new Creature); }); g_lua.bindClassMemberFunction("getId", &Creature::getId); diff --git a/tools/gimp-bitmap-generator/generate_bitmap_font.py b/tools/gimp-bitmap-generator/generate_bitmap_font.py old mode 100755 new mode 100644 diff --git a/tools/lua-binding-generator/generate_lua_bindings.lua b/tools/lua-binding-generator/generate_lua_bindings.lua old mode 100755 new mode 100644 diff --git a/tools/pkgs/makeotc b/tools/pkgs/makeotc old mode 100755 new mode 100644 From 5e0f18ab5bcdaa75c131044ccfa64048dabd20fc Mon Sep 17 00:00:00 2001 From: niczkx Date: Sat, 14 Jul 2012 16:34:24 -0700 Subject: [PATCH 3/3] missing files --- src/otclient/houses.cpp | 124 ++++++++++++++++++++++++++++++++++++++++ src/otclient/houses.h | 80 ++++++++++++++++++++++++++ src/otclient/towns.cpp | 60 +++++++++++++++++++ src/otclient/towns.h | 69 ++++++++++++++++++++++ 4 files changed, 333 insertions(+) create mode 100644 src/otclient/houses.cpp create mode 100644 src/otclient/houses.h create mode 100644 src/otclient/towns.cpp create mode 100644 src/otclient/towns.h diff --git a/src/otclient/houses.cpp b/src/otclient/houses.cpp new file mode 100644 index 00000000..ea0af0c9 --- /dev/null +++ b/src/otclient/houses.cpp @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2010-2012 OTClient + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "map.h" + +Houses g_houses; + +House::House(uint32 hId, const std::string &name, const Position &pos) + : m_id(hId), m_name(name) +{ + if (pos.isValid()) + m_doors.insert(std::make_pair(0, pos)); // first door +} + +void House::addDoor(uint16 doorId, const Position& pos) +{ + if (m_doors.find(doorId) == m_doors.end()) + m_doors.insert(std::make_pair(doorId, pos)); +} + +void House::setTile(const TilePtr& tile) +{ + tile->setFlags(TILESTATE_HOUSE); + if (std::find(m_tiles.begin(), m_tiles.end(), tile) == m_tiles.end()) + m_tiles.push_back(tile); +} + +#define fugly_get(attrib, type) stdext::unsafe_cast(elem->Attribute((attrib))) + +void House::load(const TiXmlElement *elem) +{ + std::string name = elem->Attribute("name"); + if (name.empty()) + name = stdext::format("UnNamed house #%u", getId()); + + uint32 rent = fugly_get("rent", uint32); + m_rent = rent; + + uint32 townId = fugly_get("townid", uint32); + if (!g_map.getTown(townId)) + stdext::throw_exception(stdext::format("invalid town id for house %d", townId)); + + uint32 size = fugly_get("size", uint32); + if (size == 0) + size = 1; + + m_size = size; + m_isGuildHall = fugly_get("guildhall", bool); + addDoor(0, Position(fugly_get("entryx", uint16), fugly_get("entryy", uint16), + fugly_get("entryz", uint8))); +} + +void Houses::addHouse(const HousePtr& house) +{ + if (findHouse(house->getId()) == m_houses.end()) + m_houses.push_back(house); +} + +void Houses::removeHouse(uint32 houseId) +{ + auto it = findHouse(houseId); + if (it != m_houses.end()) + m_houses.erase(it); +} + +HousePtr Houses::getHouse(uint32 houseId) +{ + auto it = findHouse(houseId); + if (it != m_houses.end()) + return *it; + + return nullptr; +} + +void Houses::load(const std::string& fileName) +{ + TiXmlDocument doc(fileName.c_str()); + if (!doc.LoadFile()) + stdext::throw_exception(stdext::format("failed to load '%s' (House XML)", fileName)); + + TiXmlElement *root = doc.FirstChildElement(); + if (!root || root->ValueTStr() != "houses") + stdext::throw_exception("invalid root tag name"); + + for (TiXmlElement *elem = root->FirstChildElement(); elem; elem = elem->NextSiblingElement()) { + if (elem->ValueTStr() != "house") + stdext::throw_exception("invalid house tag."); + + uint32 houseId = fugly_get("houseid", uint32); + HousePtr house = getHouse(houseId); + if (!house) + house = HousePtr(new House(houseId)), addHouse(house); + + house->load(elem); + } + + stdext::throw_exception("This has not been fully implemented yet."); +} + +HouseList::iterator Houses::findHouse(uint32 houseId) +{ + return std::find_if(m_houses.begin(), m_houses.end(), + [=] (const HousePtr& house) -> bool { return house->getId() == houseId; }); +} + diff --git a/src/otclient/houses.h b/src/otclient/houses.h new file mode 100644 index 00000000..0bff0c71 --- /dev/null +++ b/src/otclient/houses.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2010-2012 OTClient + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef HOUSES_H +#define HOUSES_H + +#include "declarations.h" +#include "tile.h" + +#include + +class House : public LuaObject +{ +public: + House() { } + House(uint32 hId, const std::string& name = "", const Position& pos=Position()); + ~House() { m_tiles.clear(); m_doors.clear(); } + + void setId(uint32 hId) { m_id = hId; } + void setName(const std::string& name) { m_name = name; } + void addDoor(uint16 doorId, const Position& pos); + void setTile(const TilePtr& tile); + + uint32 getId() const { return m_id; } + std::string getName() const { return m_name; } + +protected: + void load(const TiXmlElement* elem); + void save(TiXmlElement &elem) { } // TODO + +private: + uint32 m_id, m_size, m_rent; + std::string m_name; + + std::map m_doors; + std::vector m_tiles; + Boolean m_isGuildHall; + + friend class Houses; +}; + +class Houses { +public: + void addHouse(const HousePtr& house); + void removeHouse(uint32 houseId); + void load(const std::string& fileName); + + HouseList houseList() const { return m_houses; } + HousePtr getHouse(uint32 houseId); + + // Fix to segfault on exit. + void clear() { m_houses.clear(); } + +private: + HouseList m_houses; + +protected: + HouseList::iterator findHouse(uint32 houseId); +}; + +#endif diff --git a/src/otclient/towns.cpp b/src/otclient/towns.cpp new file mode 100644 index 00000000..426b4ec8 --- /dev/null +++ b/src/otclient/towns.cpp @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2010-2012 OTClient + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "towns.h" + +Towns g_towns; + +Town::Town(uint32 tid, const std::string& name, const Position& pos) + : m_id(tid), m_name(name) +{ + if (pos.isValid()) + m_pos = pos; +} + + +void Towns::addTown(const TownPtr &town) +{ + if (findTown(town->getId()) == m_towns.end()) + m_towns.push_back(town); +} + +void Towns::removeTown(uint32 townId) +{ + auto it = findTown(townId); + if (it != m_towns.end()) + m_towns.erase(it); +} + +TownPtr Towns::getTown(uint32 townId) +{ + auto it = findTown(townId); + if (it != m_towns.end()) + return *it; + return nullptr; +} + +TownList::iterator Towns::findTown(uint32 townId) +{ + return std::find_if(m_towns.begin(), m_towns.end(), + [=] (const TownPtr& town) -> bool { return town->getId() == townId; }); +} diff --git a/src/otclient/towns.h b/src/otclient/towns.h new file mode 100644 index 00000000..979ad1e7 --- /dev/null +++ b/src/otclient/towns.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2010-2012 OTClient + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef TOWNS_H +#define TOWNS_H + +#include "declarations.h" +#include + + +class Town : public LuaObject +{ +public: + Town() { } + Town(uint32 tid, const std::string& name, const Position& pos=Position()); + + void setId(uint32 tid) { m_id = tid; } + void setName(const std::string& name) { m_name = name; } + void setPos(const Position& pos) { m_pos = pos; } + + uint32 getId() { return m_id; } + std::string getName() { return m_name; } + Position getPos() { return m_pos; } + +private: + uint32 m_id; + std::string m_name; + Position m_pos; // temple pos +}; + +class Towns +{ +public: + void addTown(const TownPtr &town); + void removeTown(uint32 townId); + + TownPtr getTown(uint32 townId); + TownList getTowns() { return m_towns; } + + // Fix to segfault on exit + void clear() { m_towns.clear(); } + +private: + TownList m_towns; + +protected: + TownList::iterator findTown(uint32 townId); +}; + +#endif