From 12d30f7355c8b79ebfa61d3aff38f122cbd8c269 Mon Sep 17 00:00:00 2001 From: niczkx Date: Mon, 16 Jul 2012 05:41:38 +0300 Subject: [PATCH] monsters --- src/framework/stdext/string.h | 13 +++++ src/otclient/CMakeLists.txt | 2 + src/otclient/creature.h | 5 ++ src/otclient/luafunctions.cpp | 3 + src/otclient/map.cpp | 41 +++++++++++++- src/otclient/map.h | 11 +++- src/otclient/monsters.cpp | 103 ++++++++++++++++++++++++++++++++++ src/otclient/monsters.h | 45 +++++++++++++++ 8 files changed, 221 insertions(+), 2 deletions(-) create mode 100644 src/otclient/monsters.cpp create mode 100644 src/otclient/monsters.h diff --git a/src/framework/stdext/string.h b/src/framework/stdext/string.h index f924eba6..649ccf9e 100644 --- a/src/framework/stdext/string.h +++ b/src/framework/stdext/string.h @@ -29,6 +29,7 @@ #include #include #include +#include #include #include "types.h" @@ -213,6 +214,18 @@ inline std::string utf8StringToLatin1(uchar *utf8) { return out; } +// Convert string to lower case +inline std::string toLowerCaseString(std::string& str) { + std::transform(str.begin(), str.end(), str.begin(), tolower); + return str; +} + +// Convert string to upper case +inline std::string toUpperCaseString(std::string& str) { + std::transform(str.begin(), str.end(), str.begin(), toupper); + return str; +} + // utility for printing messages into stdout template void print(const T&... args) { diff --git a/src/otclient/CMakeLists.txt b/src/otclient/CMakeLists.txt index 89b68fe7..acf526c9 100644 --- a/src/otclient/CMakeLists.txt +++ b/src/otclient/CMakeLists.txt @@ -79,6 +79,8 @@ set(otclient_SOURCES ${otclient_SOURCES} ${CMAKE_CURRENT_LIST_DIR}/houses.h ${CMAKE_CURRENT_LIST_DIR}/towns.cpp ${CMAKE_CURRENT_LIST_DIR}/towns.h + ${CMAKE_CURRENT_LIST_DIR}/monsters.cpp + ${CMAKE_CURRENT_LIST_DIR}/monsters.h # lua ${CMAKE_CURRENT_LIST_DIR}/luavaluecasts.cpp diff --git a/src/otclient/creature.h b/src/otclient/creature.h index 98e816d6..e779b87c 100644 --- a/src/otclient/creature.h +++ b/src/otclient/creature.h @@ -160,6 +160,11 @@ class Monster : public Creature public: MonsterPtr asMonster() { return std::static_pointer_cast(shared_from_this()); } bool isMonster() { return true; } + + Position getPos() { return m_pos; } + void setPos(const Position& pos) { m_pos = pos; } +private: + Position m_pos; }; #endif diff --git a/src/otclient/luafunctions.cpp b/src/otclient/luafunctions.cpp index c79865af..287bc3a3 100644 --- a/src/otclient/luafunctions.cpp +++ b/src/otclient/luafunctions.cpp @@ -96,8 +96,11 @@ 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", "loadMonsters", &Map::loadMonsters, &g_map); + g_lua.bindSingletonFunction("g_map", "loadSingleMonster", &Map::loadSingleMonster, &g_map); g_lua.bindSingletonFunction("g_map", "getTown", &Map::getTown, &g_map); g_lua.bindSingletonFunction("g_map", "getHouse", &Map::getHouse, &g_map); + g_lua.bindSingletonFunction("g_map", "getMonster", &Map::getMonster, &g_map); g_lua.registerSingletonClass("g_game"); g_lua.bindSingletonFunction("g_game", "loginWorld", &Game::loginWorld, &g_game); diff --git a/src/otclient/map.cpp b/src/otclient/map.cpp index c5d1f796..59f7a122 100644 --- a/src/otclient/map.cpp +++ b/src/otclient/map.cpp @@ -34,6 +34,7 @@ #include #include #include +#include Map g_map; @@ -261,7 +262,9 @@ void Map::loadOtbm(const std::string& fileName) g_logger.debug(stdext::format("Total tiles: %d", m_tiles.size())); g_logger.debug("OTBM read successfully."); fin->close(); - /// TODO read XML Stuff (houses & spawns). + + loadSpawns(m_spawnFile); + m_houses.load(m_houseFile); } void Map::saveOtbm(const std::string &fileName) @@ -373,6 +376,41 @@ void Map::saveOtbm(const std::string &fileName) #endif } +void Map::loadSpawns(const std::string &fileName) +{ +#define cast(NAME, TYPE, NODE) stdext::unsafe_cast(NODE->Attribute((NAME))) + if(!m_monsters.isLoaded()) + stdext::throw_exception("cannot load spawns; monsters aren't loaded."); + + TiXmlDocument doc(fileName); + if(!doc.LoadFile()) + stdext::throw_exception(stdext::format("cannot load spawns xml file '%s", fileName)); + + TiXmlElement* root = doc.FirstChildElement(); + if(!root || root->ValueStr() != "spawns") + stdext::throw_exception(stdext::format("malformed spawns file")); + + for(TiXmlElement* node = root->FirstChildElement(); node; node = node->NextSiblingElement()) { + if (node->ValueTStr() != "spawn") + stdext::throw_exception(stdext::format("invalid spawn node")); + + Position centerPos(cast("x", uint16, node), cast("y", uint16, node), cast("z", uint8, node)); + for(TiXmlElement* mType = node->FirstChildElement(); mType; mType = mType->NextSiblingElement()) { + if (mType->ValueStr() != "monster") + stdext::throw_exception("invalid spawn-subnode"); + + std::string mName = mType->Attribute("name"); + MonsterPtr m = m_monsters.getMonster(mName); + if (!m) + stdext::throw_exception(stdext::format("unkown monster %s", mName)); + + Point off(cast("x", int, mType), cast("y", int, mType)); + Position mPos(centerPos.x + off.x, centerPos.y + off.y, centerPos.z); + addThing(m, mPos, -1); + } + } +} + bool Map::loadOtcm(const std::string& fileName) { try { @@ -521,6 +559,7 @@ void Map::clean() // This is a fix to a segfault on exit. m_towns.clear(); m_houses.clear(); + m_monsters.clear(); } void Map::cleanDynamicThings() diff --git a/src/otclient/map.h b/src/otclient/map.h index cde5c46d..44b5ba30 100644 --- a/src/otclient/map.h +++ b/src/otclient/map.h @@ -26,6 +26,7 @@ #include "creature.h" #include "houses.h" #include "towns.h" +#include "monsters.h" #include "animatedtext.h" #include @@ -115,6 +116,12 @@ public: void loadOtbm(const std::string& fileName); void saveOtbm(const std::string& fileName); + void loadSpawns(const std::string& fileName); + void saveSpawns(const std::string&) { } + + void loadMonsters(const std::string& fileName) { m_monsters.loadMonsters(fileName); } + void loadSingleMonster(const std::string& file) { m_monsters.loadSingleMonster(file); } + void clean(); void cleanDynamicThings(); void cleanTexts(); @@ -141,9 +148,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 + // town/house/monster related TownPtr getTown(uint32 tid) { return m_towns.getTown(tid); } HousePtr getHouse(uint32 hid) { return m_houses.getHouse(hid); } + MonsterPtr getMonster(const std::string& name) { return m_monsters.getMonster(name); } void setLight(const Light& light) { m_light = light; } void setCentralPosition(const Position& centralPosition); @@ -181,6 +189,7 @@ private: Houses m_houses; Towns m_towns; + Monsters m_monsters; uint16 m_width, m_height; }; diff --git a/src/otclient/monsters.cpp b/src/otclient/monsters.cpp new file mode 100644 index 00000000..cc2436b3 --- /dev/null +++ b/src/otclient/monsters.cpp @@ -0,0 +1,103 @@ +/* + * 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 "monsters.h" +#include "creature.h" + +#include + +void Monsters::loadMonsters(const std::string& file) +{ + TiXmlDocument doc(file); + if(!doc.LoadFile()) + stdext::throw_exception(stdext::format("cannot open monsters file '%s'", file)); + + TiXmlElement* root = doc.FirstChildElement(); + if(!root || root->ValueStr() != "monsters") + stdext::throw_exception("malformed monsters xml file"); + + for(TiXmlElement* monster = root->FirstChildElement(); root; root = root->NextSiblingElement()) { + MonsterPtr newMonster(new Monster); + newMonster->setName(monster->Attribute("name")); + + loadSingleMonster(file.substr(0, file.find_last_of('/')) + '/' + monster->Attribute("file"), newMonster); + } + + doc.Clear(); + m_loaded = true; +} + +void Monsters::loadSingleMonster(const std::string& file, const MonsterPtr& m) +{ +#define read(str) stdext::unsafe_cast(attrib->Attribute((str))) + if (!m || std::find(m_monsters.begin(), m_monsters.end(), m) != m_monsters.end()) + stdext::throw_exception("reloading monsters is not supported yet."); + + TiXmlDocument doc(file); + if(!doc.LoadFile()) + stdext::throw_exception(stdext::format("cannot load single monster file '%s'", file)); + + TiXmlElement* root = doc.FirstChildElement(); + if(!root || root->ValueStr() != "monster") + stdext::throw_exception(stdext::format("malformed monster xml file: %s", file)); + + for(TiXmlElement* attrib = root->FirstChildElement(); attrib; attrib = attrib->NextSiblingElement()) { + if(attrib->ValueStr() == "look") { + Outfit out; + + int type = read("type"); + if (type <= 0) + type = read("typeex"); + if(type) { + out.setId(type); + { + out.setHead(read("head")); + out.setBody(read("body")); + out.setLegs(read("legs")); + out.setFeet(read("feet")); + out.setAddons(read("addons")); + out.setMount(read("mount")); + } + } else + stdext::throw_exception(stdext::format("invalid look type/typeex for monster %s", m->getName())); + m->setOutfit(out); + } + } + + m_monsters.push_back(m); +} + +MonsterPtr Monsters::getMonster(const std::string& name) +{ + auto it = std::find_if(m_monsters.begin(), m_monsters.end(), + [=] (const MonsterPtr& m) -> bool { return m->getName() == name; }); + if (it != m_monsters.end()) + return *it; + return nullptr; +} + +MonsterPtr Monsters::getMonsterByPos(const Position& pos) +{ + auto it = std::find_if(m_monsters.begin(), m_monsters.end(), + [=] (const MonsterPtr& m) -> bool { return m->getPos() == pos; }); + return it != m_monsters.end() ? *it : nullptr; +} diff --git a/src/otclient/monsters.h b/src/otclient/monsters.h new file mode 100644 index 00000000..8fad328f --- /dev/null +++ b/src/otclient/monsters.h @@ -0,0 +1,45 @@ +/* + * 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 MONSTERS_H +#define MONSTERS_H + +#include "declarations.h" + +class Monsters +{ +public: + void clear() { m_monsters.clear(); } + + void loadMonsters(const std::string& file); + void loadSingleMonster(const std::string& file, const MonsterPtr& m = nullptr); + + MonsterPtr getMonster(const std::string& name); + MonsterPtr getMonsterByPos(const Position& pos); + + bool isLoaded() const { return m_loaded; } +private: + std::vector m_monsters; + bool m_loaded; +}; + +#endif