diff --git a/src/framework/luafunctions.cpp b/src/framework/luafunctions.cpp index 08ac9abc..d8246931 100644 --- a/src/framework/luafunctions.cpp +++ b/src/framework/luafunctions.cpp @@ -66,6 +66,7 @@ void Application::registerLuaFunctions() g_lua.bindGlobalFunction("iptostring", [](int v) { return stdext::ip_to_string(v); }); g_lua.bindGlobalFunction("stringtoip", [](const std::string& v) { return stdext::string_to_ip(v); }); g_lua.bindGlobalFunction("listSubnetAddresses", [](uint32 a, uint8 b) { return stdext::listSubnetAddresses(a, b); }); + g_lua.bindGlobalFunction("ucwords", [](std::string s) { return stdext::ucwords(s); }); // Application g_lua.registerSingletonClass("g_app"); @@ -154,6 +155,7 @@ void Application::registerLuaFunctions() g_lua.bindSingletonFunction("g_resources", "searchAndAddPackages", &ResourceManager::searchAndAddPackages, &g_resources); g_lua.bindSingletonFunction("g_resources", "removeSearchPath", &ResourceManager::removeSearchPath, &g_resources); g_lua.bindSingletonFunction("g_resources", "fileExists", &ResourceManager::fileExists, &g_resources); + g_lua.bindSingletonFunction("g_resources", "directoryExists", &ResourceManager::directoryExists, &g_resources); g_lua.bindSingletonFunction("g_resources", "getRealDir", &ResourceManager::getRealDir, &g_resources); g_lua.bindSingletonFunction("g_resources", "getWorkDir", &ResourceManager::getWorkDir, &g_resources); g_lua.bindSingletonFunction("g_resources", "getSearchPaths", &ResourceManager::getSearchPaths, &g_resources); diff --git a/src/framework/xml/tinyxml.h b/src/framework/xml/tinyxml.h index 9907c6c0..f402c206 100644 --- a/src/framework/xml/tinyxml.h +++ b/src/framework/xml/tinyxml.h @@ -43,6 +43,7 @@ distribution. #include #include #include +#include // Help out windows: #if defined( _DEBUG ) && !defined( DEBUG ) @@ -51,7 +52,7 @@ distribution. #ifdef TIXML_USE_STL #include - #include + #include #include #define TIXML_STRING std::string #else @@ -1005,6 +1006,7 @@ public: std::string Attribute( const std::string& name, double* d ) const; void SetAttribute( const std::string& name, const std::string& _value ); + void SetAttribute( const std::string& name, int _value) { SetAttribute(name, stdext::to_string(_value)); } void RemoveAttribute( const std::string& name ); diff --git a/src/otclient/creatures.cpp b/src/otclient/creatures.cpp index a0a38df7..27c952cb 100644 --- a/src/otclient/creatures.cpp +++ b/src/otclient/creatures.cpp @@ -22,22 +22,138 @@ #include "creatures.h" #include "creature.h" +#include "map.h" #include #include #include -Creatures g_creatures; +CreatureManager g_creatures; + +void Spawn::load(TiXmlElement* node) +{ + Position centerPos = node->readPos("center"); + setCenterPos(centerPos); + setRadius(node->readType("radius")); + + CreatureTypePtr cType(nullptr); + for(TiXmlElement* cNode = node->FirstChildElement(); cNode; cNode = cNode->NextSiblingElement()) { + if(cNode->ValueStr() != "monster" && cNode->ValueStr() != "npc") + stdext::throw_exception(stdext::format("invalid spawn-subnode %s", cNode->ValueStr())); + + std::string cName = cNode->Attribute("name"); + stdext::tolower(cName); + stdext::trim(cName); + + if (!(cType = g_creatures.getCreatureByName(cName))) + continue; + + cType->setSpawnTime(cNode->readType("spawntime")); + Otc::Direction dir = Otc::North; + int16 dir_ = cNode->readType("direction"); + if(dir_ >= Otc::East && dir_ <= Otc::West) + dir = (Otc::Direction)dir_; + cType->setDirection(dir); + + centerPos.x += cNode->readType("x"); + centerPos.y += cNode->readType("y"); + centerPos.z = cNode->readType("z"); + __addCreature(centerPos, cType); + } +} + +void Spawn::save(TiXmlElement*& node) +{ + node = new TiXmlElement("spawn"); + + const Position& c = getCenterPos(); + node->SetAttribute("centerx", c.x); + node->SetAttribute("centery", c.y); + node->SetAttribute("centerz", c.z); + + node->SetAttribute("radius", getRadius()); + + TiXmlElement* creatureNode = nullptr; + for(const auto& pair : m_creatures) { + if(!(creatureNode = new TiXmlElement("monster"))) + stdext::throw_exception("oom?"); + + const CreatureTypePtr& creature = pair.second; + + creatureNode->SetAttribute("name", creature->getName()); + creatureNode->SetAttribute("spawntime", creature->getSpawnTime()); + creatureNode->SetAttribute("direction", creature->getDirection()); + + const Position& placePos = pair.first; + assert(placePos.isValid()); + + creatureNode->SetAttribute("x", placePos.x); + creatureNode->SetAttribute("y", placePos.y); + creatureNode->SetAttribute("z", placePos.z); + + node->LinkEndChild(creatureNode); + } +} + +void Spawn::addCreature(const Position& placePos, const CreatureTypePtr& cType) +{ + const Position& centerPos = getCenterPos(); + int m_radius = getRadius(); + if(m_radius != -1 && placePos.x < centerPos.x - m_radius && + placePos.x > centerPos.x + m_radius && placePos.y < centerPos.y - m_radius && + placePos.y > centerPos.y + m_radius) + stdext::throw_exception(stdext::format("cannot place creature, out of range %s %s %d - increment radius.", + stdext::to_string(placePos), stdext::to_string(centerPos), m_radius)); + + return __addCreature(placePos, cType); +} + +void Spawn::__addCreature(const Position& centerPos, const CreatureTypePtr& cType) +{ + g_map.addThing(cType->cast(), centerPos, 4); + m_creatures.insert(std::make_pair(centerPos, cType)); +} + +void Spawn::removeCreature(const Position& pos) +{ + auto iterator = m_creatures.find(pos); + if(iterator != m_creatures.end()) + __removeCreature(iterator); +} + +void Spawn::__removeCreature(std::unordered_map::iterator iter) +{ + assert(iter->first.isValid()); + assert(g_map.removeThingByPos(iter->first, 4)); + m_creatures.erase(iter); +} CreaturePtr CreatureType::cast() { CreaturePtr ret(new Creature); - ret->setName(getName()); + + std::string cName = getName(); + stdext::ucwords(cName); + ret->setName(cName); + + ret->setDirection(getDirection()); ret->setOutfit(getOutfit()); return ret; } -void Creatures::loadMonsters(const std::string& file) +CreatureManager::CreatureManager() +{ + m_nullCreature = CreatureTypePtr(new CreatureType); +} + +void CreatureManager::clearSpawns() +{ + for(auto it : m_spawns) + it->clear(); + m_spawns.clear(); +} + +void CreatureManager::loadMonsters(const std::string& file) { TiXmlDocument doc; doc.Parse(g_resources.loadFile(file).c_str()); @@ -60,12 +176,12 @@ void Creatures::loadMonsters(const std::string& file) m_loaded = true; } -void Creatures::loadSingleCreature(const std::string& file) +void CreatureManager::loadSingleCreature(const std::string& file) { loadCreatureBuffer(g_resources.loadFile(file)); } -void Creatures::loadNpcs(const std::string& folder) +void CreatureManager::loadNpcs(const std::string& folder) { boost::filesystem::path npcPath(boost::filesystem::current_path().generic_string() + folder); if(!boost::filesystem::exists(npcPath)) @@ -83,7 +199,61 @@ void Creatures::loadNpcs(const std::string& folder) } } -void Creatures::loadCreatureBuffer(const std::string &buffer) +void CreatureManager::loadSpawns(const std::string& fileName) +{ + if(!isLoaded()) { + g_logger.fatal("creatures aren't loaded yet to load spawns."); + return; + } + + if(m_spawnLoaded) { + g_logger.warning("attempt to reload spawns."); + return; + } + + TiXmlDocument doc; + doc.Parse(g_resources.loadFile(fileName).c_str()); + if(doc.Error()) + stdext::throw_exception(stdext::format("cannot load spawns xml file '%s: '%s'", fileName, doc.ErrorDesc())); + + TiXmlElement* root = doc.FirstChildElement(); + if(!root || root->ValueStr() != "spawns") + stdext::throw_exception("malformed spawns file"); + + for(TiXmlElement* node = root->FirstChildElement(); node; node = node->NextSiblingElement()) { + if(node->ValueTStr() != "spawn") + stdext::throw_exception("invalid spawn node"); + + SpawnPtr spawn(new Spawn); + spawn->load(node); + m_spawns.push_back(spawn); + } + doc.Clear(); + m_spawnLoaded = true; +} + +void CreatureManager::saveSpawns(const std::string& fileName) +{ + TiXmlDocument doc; + doc.SetTabSize(2); + + TiXmlDeclaration* decl = new TiXmlDeclaration("1.0", "UTF-8", ""); + doc.LinkEndChild(decl); + + TiXmlElement* root = new TiXmlElement("spawns"); + doc.LinkEndChild(root); + + for(auto spawn : m_spawns) { + TiXmlElement* elem; + spawn->save(elem); + root->LinkEndChild(elem); + } + + if(!doc.SaveFile(fileName)) + stdext::throw_exception(stdext::format("failed to save spawns XML: %s", doc.ErrorDesc())); +} + +void CreatureManager::loadCreatureBuffer(const std::string& buffer) { TiXmlDocument doc; doc.Parse(buffer.c_str()); @@ -103,24 +273,24 @@ void Creatures::loadCreatureBuffer(const std::string &buffer) if(attrib->ValueStr() != "look") continue; - if(m_loadCreatureBuffer(attrib, newType)) - break; + m_loadCreatureBuffer(attrib, newType); + break; } doc.Clear(); } -bool Creatures::m_loadCreatureBuffer(TiXmlElement* attrib, const CreatureTypePtr& m) +void CreatureManager::m_loadCreatureBuffer(TiXmlElement* attrib, const CreatureTypePtr& m) { if(std::find(m_creatures.begin(), m_creatures.end(), m) != m_creatures.end()) - return true; + return; Outfit out; out.setCategory(ThingCategoryCreature); if(!attrib->Attribute("type").empty()) out.setId(attrib->readType("type")); else - out.setAuxId(attrib->readType("typeex")); + out.setId(attrib->readType("typeex")); { out.setHead(attrib->readType(("head"))); @@ -133,25 +303,30 @@ bool Creatures::m_loadCreatureBuffer(TiXmlElement* attrib, const CreatureTypePtr m->setOutfit(out); m_creatures.push_back(m); - return true; } -CreatureTypePtr Creatures::getCreatureByName(std::string name) +const CreatureTypePtr& CreatureManager::getCreatureByName(std::string name) { stdext::tolower(name); stdext::trim(name); auto it = std::find_if(m_creatures.begin(), m_creatures.end(), [=] (const CreatureTypePtr& m) -> bool { return m->getName() == name; }); - return it != m_creatures.end() ? *it : nullptr; + if(it != m_creatures.end()) + return *it; + g_logger.warning(stdext::format("could not find creature with name: %s", name)); + return m_nullCreature; } -CreatureTypePtr Creatures::getCreatureByLook(int look) +const CreatureTypePtr& CreatureManager::getCreatureByLook(int look) { auto findFun = [=] (const CreatureTypePtr& c) -> bool { const Outfit& o = c->getOutfit(); - return o.getId() == look || o.getAuxId() == look; + return o.getId() == look; }; auto it = std::find_if(m_creatures.begin(), m_creatures.end(), findFun); - return it != m_creatures.end() ? *it : nullptr; + if(it != m_creatures.end()) + return *it; + g_logger.warning(stdext::format("could not find creature with looktype: %d", look)); + return m_nullCreature; } diff --git a/src/otclient/creatures.h b/src/otclient/creatures.h index 68725f1e..7f11e269 100644 --- a/src/otclient/creatures.h +++ b/src/otclient/creatures.h @@ -32,7 +32,43 @@ enum CreatureAttr : uint8 CreatureAttrPosition = 0, CreatureAttrName = 1, CreatureAttrOutfit = 2, - CreatureAttrSpawnTime = 3 + CreatureAttrSpawnTime = 3, + CreatureAttrDir = 4 +}; + +enum SpawnAttr : uint8 +{ + SpawnAttrRadius = 0, + SpawnAttrCenter = 1, + SpawnAttrPos = 2 +}; + +class Spawn : public LuaObject +{ +public: + Spawn() { } + Spawn(int32 radius) { setRadius(radius); } + + void setRadius(int32 r) { m_attribs.set(SpawnAttrRadius, r) ;} + int32 getRadius() { return m_attribs.get(SpawnAttrRadius); } + + void setCenterPos(const Position& pos) { m_attribs.set(SpawnAttrCenter, pos); } + Position getCenterPos() { return m_attribs.get(SpawnAttrPos); } + + void addCreature(const Position& placePos, const CreatureTypePtr& cType); + void removeCreature(const Position& pos); + void clear() { m_creatures.clear(); } + +protected: + void load(TiXmlElement* node); + void save(TiXmlElement*& node); + void __addCreature(const Position& centerPos, const CreatureTypePtr& cType); + void __removeCreature(std::unordered_map::iterator iter); + +private: + stdext::dynamic_storage m_attribs; + std::unordered_map m_creatures; + friend class CreatureManager; }; class CreatureType : public LuaObject @@ -41,46 +77,57 @@ public: CreatureType() { } CreatureType(const std::string& name) { setName(name); } - void setSpawnTime(int spawnTime) { m_attribs.set(CreatureAttrSpawnTime, spawnTime); } - int getSpawnTime() { return m_attribs.get(CreatureAttrSpawnTime); } + void setSpawnTime(int32 spawnTime) { m_attribs.set(CreatureAttrSpawnTime, spawnTime); } + int32 getSpawnTime() { return m_attribs.get(CreatureAttrSpawnTime); } - void setName(const std::string& name) { m_attribs.set(CreatureAttrName, name); } + void setName(const std::string& name) { m_attribs.set(CreatureAttrName, name); dump << "set"<(CreatureAttrName); } void setOutfit(const Outfit& o) { m_attribs.set(CreatureAttrOutfit, o); } Outfit getOutfit() { return m_attribs.get(CreatureAttrOutfit); } + void setDirection(Otc::Direction dir) { m_attribs.set(CreatureAttrDir, dir); } + Otc::Direction getDirection() { return m_attribs.get(CreatureAttrDir); } + CreaturePtr cast(); private: stdext::dynamic_storage m_attribs; }; -class Creatures +class CreatureManager { public: + CreatureManager(); void clear() { m_creatures.clear(); } + void clearSpawns(); void loadMonsters(const std::string& file); void loadSingleCreature(const std::string& file); void loadNpcs(const std::string& folder); void loadCreatureBuffer(const std::string& buffer); + void loadSpawns(const std::string& fileName); + void saveSpawns(const std::string& fileName); - CreatureTypePtr getCreatureByName(std::string name); - CreatureTypePtr getCreatureByLook(int look); + const CreatureTypePtr& getCreatureByName(std::string name); + const CreatureTypePtr& getCreatureByLook(int look); - bool isLoaded() const { return m_loaded; } + bool isLoaded() { return m_loaded; } + bool isSpawnLoaded() { return m_spawnLoaded; } const std::vector& getCreatures() { return m_creatures; } + const std::vector& getSpawns() { return m_spawns; } protected: - bool m_loadCreatureBuffer(TiXmlElement* elem, const CreatureTypePtr& m); + void m_loadCreatureBuffer(TiXmlElement* elem, const CreatureTypePtr& m); private: std::vector m_creatures; - stdext::boolean m_loaded; + std::vector m_spawns; + stdext::boolean m_loaded, m_spawnLoaded; + CreatureTypePtr m_nullCreature; }; -extern Creatures g_creatures; +extern CreatureManager g_creatures; #endif diff --git a/src/otclient/declarations.h b/src/otclient/declarations.h index fa06e51f..698182ed 100644 --- a/src/otclient/declarations.h +++ b/src/otclient/declarations.h @@ -49,6 +49,7 @@ class ItemType; class House; class Town; class CreatureType; +class Spawn; typedef stdext::shared_object_ptr MapViewPtr; typedef stdext::shared_object_ptr TilePtr; @@ -69,6 +70,7 @@ typedef stdext::shared_object_ptr ItemTypePtr; typedef stdext::shared_object_ptr HousePtr; typedef stdext::shared_object_ptr TownPtr; typedef stdext::shared_object_ptr CreatureTypePtr; +typedef stdext::shared_object_ptr SpawnPtr; typedef std::vector ThingList; typedef std::vector ThingTypeList; diff --git a/src/otclient/houses.cpp b/src/otclient/houses.cpp index 6b5be5b1..f88eba6e 100644 --- a/src/otclient/houses.cpp +++ b/src/otclient/houses.cpp @@ -24,8 +24,16 @@ #include +HouseManager g_houses; + +House::House() +{ + m_nullTile = TilePtr(new Tile(Position())); +} + House::House(uint32 hId, const std::string &name, const Position &pos) { + m_nullTile = TilePtr(new Tile(Position())); setId(hId); setName(name); if(pos.isValid()) @@ -38,39 +46,73 @@ void House::setTile(const TilePtr& tile) m_tiles.insert(std::make_pair(tile->getPosition(), tile)); } +const TilePtr& House::getTile(const Position& position) +{ + TileMap::const_iterator iter = m_tiles.find(position); + if(iter != m_tiles.end()) + return iter->second; + return m_nullTile; +} + void House::load(const TiXmlElement *elem) { std::string name = elem->Attribute("name"); if(name.empty()) name = stdext::format("Unnamed house #%lu", getId()); + setName(name); setRent(elem->readType("rent")); setSize(elem->readType("size")); setTownId(elem->readType("townid")); - m_isGuildHall = elem->readType("rent"); + m_isGuildHall = elem->readType("guildhall"); setEntry(elem->readPos("entry")); } -void Houses::addHouse(const HousePtr& house) +void House::save(TiXmlElement*& elem) +{ +#define s(x) stdext::to_string((x)) // ugly macro again... to save "typing". + elem = new TiXmlElement("house"); + + elem->SetAttribute("name", getName()); + elem->SetAttribute("houseid", s(getId())); + + Position entry = getEntry(); + elem->SetAttribute("entryx", s(entry.x)); + elem->SetAttribute("entryy", s(entry.y)); + elem->SetAttribute("entryz", s(entry.z)); + + elem->SetAttribute("rent", s(getRent())); + elem->SetAttribute("townid", s(getTownId())); + elem->SetAttribute("size", s(getSize())); + elem->SetAttribute("guildhall", s(m_isGuildHall)); +} + +HouseManager::HouseManager() +{ + m_nullHouse = HousePtr(new House); +} + +void HouseManager::addHouse(const HousePtr& house) { if(findHouse(house->getId()) == m_houses.end()) m_houses.push_back(house); } -void Houses::removeHouse(uint32 houseId) +void HouseManager::removeHouse(uint32 houseId) { auto it = findHouse(houseId); if(it != m_houses.end()) m_houses.erase(it); } -HousePtr Houses::getHouse(uint32 houseId) +const HousePtr& HouseManager::getHouse(uint32 houseId) { - auto it = findHouse(houseId); - return it != m_houses.end() ? *it : nullptr; + auto it = std::find_if(m_houses.begin(), m_houses.end(), + [=] (const HousePtr& house) -> bool { return house->getId() == houseId; }); + return it != m_houses.end() ? *it : m_nullHouse; } -void Houses::load(const std::string& fileName) +void HouseManager::load(const std::string& fileName) { TiXmlDocument doc; doc.Parse(g_resources.loadFile(fileName).c_str()); @@ -94,9 +136,29 @@ void Houses::load(const std::string& fileName) } } -HouseList::iterator Houses::findHouse(uint32 houseId) +void HouseManager::save(const std::string& fileName) +{ + TiXmlDocument doc; + doc.SetTabSize(2); + + TiXmlDeclaration* decl = new TiXmlDeclaration("1.0", "UTF-8", ""); + doc.LinkEndChild(decl); + + TiXmlElement* root = new TiXmlElement("houses"); + doc.LinkEndChild(root); + + for(auto house : m_houses) { + TiXmlElement *elem; + house->save(elem); + root->LinkEndChild(elem); + } + + if(!doc.SaveFile(fileName)) + stdext::throw_exception(stdext::format("failed to save houses XML: %s", doc.ErrorDesc())); +} + +HouseList::iterator HouseManager::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 index cfa82c78..ea73676a 100644 --- a/src/otclient/houses.h +++ b/src/otclient/houses.h @@ -41,50 +41,65 @@ enum HouseAttr : uint8 class House : public LuaObject { public: - House() { } + House(); House(uint32 hId, const std::string& name = "", const Position& pos=Position()); - ~House() { m_tiles.clear(); } + ~House() { m_tiles.clear(); m_nullTile = nullptr; } void setTile(const TilePtr& tile); - void setId(uint32 hId) { m_attribs.set(HouseAttrId, hId); } + const TilePtr& getTile(const Position& pos); + void setName(const std::string& name) { m_attribs.set(HouseAttrName, name); } + std::string getName() { return m_attribs.get(HouseAttrName); } + + void setId(uint32 hId) { m_attribs.set(HouseAttrId, hId); } + uint32 getId() { return m_attribs.get(HouseAttrId); } + void setTownId(uint32 tid) { m_attribs.set(HouseAttrTown, tid); } + uint32 getTownId() { return m_attribs.get(HouseAttrTown); } + void setSize(uint32 s) { m_attribs.set(HouseAttrSize, s); } - void setRent(uint32 r) { m_attribs.set(HouseAttrRent, r); } - void setEntry(const Position& p) { m_attribs.set(HouseAttrEntry, p); } + uint32 getSize() { return m_attribs.get(HouseAttrSize); } - uint32 getId() { return m_attribs.get(HouseAttrId); } - std::string getName() { return m_attribs.get(HouseAttrName); } + void setRent(uint32 r) { m_attribs.set(HouseAttrRent, r); } uint32 getRent() { return m_attribs.get(HouseAttrRent); } - uint32 getSize() { return m_attribs.get(HouseAttrSize); } + + void setEntry(const Position& p) { m_attribs.set(HouseAttrEntry, p); } + Position getEntry() { return m_attribs.get(HouseAttrEntry); } protected: void load(const TiXmlElement* elem); - void save(TiXmlElement &elem) { } // TODO + void save(TiXmlElement*& elem); private: stdext::packed_storage m_attribs; TileMap m_tiles; + TilePtr m_nullTile; stdext::boolean m_isGuildHall; - friend class Houses; + friend class HouseManager; }; -class Houses { +class HouseManager { public: - void clear() { m_houses.clear(); } + HouseManager(); + void addHouse(const HousePtr& house); void removeHouse(uint32 houseId); - void load(const std::string& fileName); + HouseList getHouseList() { return m_houses; } + const HousePtr& getHouse(uint32 houseId); + void clear() { m_houses.clear(); m_nullHouse = nullptr; } - HouseList houseList() const { return m_houses; } - HousePtr getHouse(uint32 houseId); + void load(const std::string& fileName); + void save(const std::string& fileName); -private: +private: HouseList m_houses; + HousePtr m_nullHouse; protected: HouseList::iterator findHouse(uint32 houseId); }; +extern HouseManager g_houses; + #endif diff --git a/src/otclient/luafunctions.cpp b/src/otclient/luafunctions.cpp index 0904c023..a9d35aa4 100644 --- a/src/otclient/luafunctions.cpp +++ b/src/otclient/luafunctions.cpp @@ -64,18 +64,20 @@ void OTClient::registerLuaFunctions() g_lua.bindSingletonFunction("g_things", "findThingTypeByAttr", &ThingTypeManager::findThingTypeByAttr, &g_things); g_lua.bindSingletonFunction("g_things", "findItemTypeByCategory", &ThingTypeManager::findItemTypeByCategory, &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.bindSingletonFunction("g_houses", "clear", &HouseManager::clear, &g_houses); + g_lua.bindSingletonFunction("g_houses", "load", &HouseManager::load, &g_houses); + g_lua.bindSingletonFunction("g_houses", "save", &HouseManager::save, &g_houses); + g_lua.bindSingletonFunction("g_houses", "getHouse", &HouseManager::getHouse, &g_houses); + g_lua.bindSingletonFunction("g_houses", "addHouse", &HouseManager::addHouse, &g_houses); + g_lua.bindSingletonFunction("g_houses", "removeHouse", &HouseManager::removeHouse, &g_houses); + g_lua.bindSingletonFunction("g_houses", "getHouseList", &HouseManager::getHouseList, &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.bindSingletonFunction("g_towns", "getTown", &TownManager::getTown, &g_towns); + g_lua.bindSingletonFunction("g_towns", "addTown", &TownManager::addTown, &g_towns); + g_lua.bindSingletonFunction("g_towns", "removeTown", &TownManager::removeTown, &g_towns); + g_lua.bindSingletonFunction("g_towns", "getTowns", &TownManager::getTowns, &g_towns); g_lua.registerSingletonClass("g_sprites"); g_lua.bindSingletonFunction("g_sprites", "loadSpr", &SpriteManager::loadSpr, &g_sprites); @@ -104,19 +106,25 @@ void OTClient::registerLuaFunctions() g_lua.bindSingletonFunction("g_map", "findPath", &Map::findPath, &g_map); g_lua.bindSingletonFunction("g_map", "loadOtbm", &Map::loadOtbm, &g_map); g_lua.bindSingletonFunction("g_map", "saveOtbm", &Map::saveOtbm, &g_map); - g_lua.bindSingletonFunction("g_map", "loadSpawns", &Map::loadSpawns, &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.bindSingletonFunction("g_map", "getHouseFile", &Map::getHouseFile, &g_map); + g_lua.bindSingletonFunction("g_map", "getSpawnFile", &Map::getSpawnFile, &g_map); g_lua.registerSingletonClass("g_creatures"); - g_lua.bindSingletonFunction("g_creatures", "getCreatures", &Creatures::getCreatures, &g_creatures); - g_lua.bindSingletonFunction("g_creatures", "getCreatureByName", &Creatures::getCreatureByName, &g_creatures); - g_lua.bindSingletonFunction("g_creatures", "getCreatureByLook", &Creatures::getCreatureByLook, &g_creatures); - g_lua.bindSingletonFunction("g_creatures", "loadMonsters", &Creatures::loadMonsters, &g_creatures); - g_lua.bindSingletonFunction("g_creatures", "loadNpcs", &Creatures::loadNpcs, &g_creatures); - g_lua.bindSingletonFunction("g_creatures", "loadSingleCreature", &Creatures::loadSingleCreature, &g_creatures); + g_lua.bindSingletonFunction("g_creatures", "getCreatures", &CreatureManager::getCreatures, &g_creatures); + g_lua.bindSingletonFunction("g_creatures", "getSpawns", &CreatureManager::getSpawns, &g_creatures); + g_lua.bindSingletonFunction("g_creatures", "getCreatureByName", &CreatureManager::getCreatureByName, &g_creatures); + g_lua.bindSingletonFunction("g_creatures", "getCreatureByLook", &CreatureManager::getCreatureByLook, &g_creatures); + g_lua.bindSingletonFunction("g_creatures", "loadMonsters", &CreatureManager::loadMonsters, &g_creatures); + g_lua.bindSingletonFunction("g_creatures", "loadNpcs", &CreatureManager::loadNpcs, &g_creatures); + g_lua.bindSingletonFunction("g_creatures", "loadSingleCreature", &CreatureManager::loadSingleCreature, &g_creatures); + g_lua.bindSingletonFunction("g_creatures", "loadSpawns", &CreatureManager::loadSpawns, &g_creatures); + g_lua.bindSingletonFunction("g_creatures", "saveSpawns", &CreatureManager::saveSpawns, &g_creatures); + g_lua.bindSingletonFunction("g_creatures", "isLoaded", &CreatureManager::isLoaded, &g_creatures); + g_lua.bindSingletonFunction("g_creatures", "isSpawnLoaded", &CreatureManager::isSpawnLoaded, &g_creatures); + g_lua.bindSingletonFunction("g_creatures", "clear", &CreatureManager::clear, &g_creatures); + g_lua.bindSingletonFunction("g_creatures", "clearSpawns", &CreatureManager::clearSpawns, &g_creatures); g_lua.registerSingletonClass("g_game"); g_lua.bindSingletonFunction("g_game", "loginWorld", &Game::loginWorld, &g_game); @@ -294,9 +302,26 @@ void OTClient::registerLuaFunctions() g_lua.bindClassStaticFunction("create", []{ return HousePtr(new House); }); g_lua.bindClassMemberFunction("setId", &House::setId); g_lua.bindClassMemberFunction("setName", &House::setName); + g_lua.bindClassMemberFunction("getName", &House::getName); + g_lua.bindClassMemberFunction("setTownId", &House::setTownId); + g_lua.bindClassMemberFunction("getTownId", &House::getTownId); g_lua.bindClassMemberFunction("setTile", &House::setTile); - g_lua.bindClassMemberFunction("addTile", &House::setTile); // alternative method + g_lua.bindClassMemberFunction("getTile", &House::getTile); g_lua.bindClassMemberFunction("setEntry", &House::setEntry); + g_lua.bindClassMemberFunction("getEntry", &House::getEntry); + g_lua.bindClassMemberFunction("setSize", &House::setSize); + g_lua.bindClassMemberFunction("getSize", &House::getSize); + g_lua.bindClassMemberFunction("setRent", &House::setRent); + g_lua.bindClassMemberFunction("getRent", &House::getRent); + + g_lua.registerClass(); + g_lua.bindClassStaticFunction("create", []{ return SpawnPtr(new Spawn); }); + g_lua.bindClassMemberFunction("setRadius", &Spawn::setRadius); + g_lua.bindClassMemberFunction("getRadius", &Spawn::getRadius); + g_lua.bindClassMemberFunction("setCenterPos", &Spawn::setCenterPos); + g_lua.bindClassMemberFunction("getCenterPos", &Spawn::getCenterPos); + g_lua.bindClassMemberFunction("addCreature", &Spawn::addCreature); + g_lua.bindClassMemberFunction("removeCreature", &Spawn::removeCreature); g_lua.registerClass(); g_lua.bindClassStaticFunction("create", []{ return TownPtr(new Town); }); diff --git a/src/otclient/map.cpp b/src/otclient/map.cpp index 36ca4e56..8572c83f 100644 --- a/src/otclient/map.cpp +++ b/src/otclient/map.cpp @@ -67,9 +67,9 @@ void Map::clean() m_waypoints.clear(); - m_towns.clear(); - m_houses.clear(); - g_creatures.clear(); + g_towns.clear(); + g_houses.clear(); + g_creatures.clearSpawns(); m_tilesRect = Rect(65534, 65534, 0, 0); } diff --git a/src/otclient/map.h b/src/otclient/map.h index dc2597ba..5f98cd47 100644 --- a/src/otclient/map.h +++ b/src/otclient/map.h @@ -135,9 +135,6 @@ public: void loadOtbm(const std::string& fileName, const UIWidgetPtr& pbar = 0); void saveOtbm(const std::string& fileName, const UIWidgetPtr& pbar = 0); - void loadSpawns(const std::string& fileName); - void saveSpawns(const std::string&); - // otbm attributes (description, size, etc.) void setHouseFile(const std::string& file) { m_attribs.set(OTBM_ATTR_HOUSE_FILE, file); } void setSpawnFile(const std::string& file) { m_attribs.set(OTBM_ATTR_SPAWN_FILE, file); } @@ -176,11 +173,6 @@ 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/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 g_creatures.getCreatureByName(name); } - void setLight(const Light& light) { m_light = light; } void setCentralPosition(const Position& centralPosition); @@ -205,6 +197,7 @@ private: std::unordered_map m_tileBlocks[Otc::MAX_Z+1]; std::unordered_map m_knownCreatures; + std::unordered_map m_creatureTypes; std::array, Otc::MAX_Z+1> m_floorMissiles; std::vector m_animatedTexts; std::vector m_staticTexts; @@ -216,8 +209,6 @@ private: Rect m_tilesRect; stdext::packed_storage m_attribs; - Houses m_houses; - Towns m_towns; static TilePtr m_nulltile; }; diff --git a/src/otclient/mapio.cpp b/src/otclient/mapio.cpp index c6dc614b..6d48147a 100644 --- a/src/otclient/mapio.cpp +++ b/src/otclient/mapio.cpp @@ -109,9 +109,9 @@ void Map::loadOtbm(const std::string& fileName, const UIWidgetPtr& pbar) if(type == OTBM_HOUSETILE) { uint32 hId = nodeTile->getU32(); TilePtr tile = getOrCreateTile(pos); - if(!(house = m_houses.getHouse(hId))) { + if(!(house = g_houses.getHouse(hId))) { house = HousePtr(new House(hId)); - m_houses.addHouse(house); + g_houses.addHouse(house); } house->setTile(tile); } @@ -189,9 +189,9 @@ void Map::loadOtbm(const std::string& fileName, const UIWidgetPtr& pbar) uint32 townId = nodeTown->getU32(); std::string townName = nodeTown->getString(); Position townCoords = nodeTown->getPosition(); - if(!(town = m_towns.getTown(townId))) { + if(!(town = g_towns.getTown(townId))) { town = TownPtr(new Town(townId, townName, townCoords)); - m_towns.addTown(town); + g_towns.addTown(town); } } } else if(mapDataType == OTBM_WAYPOINTS && headerVersion > 1) { @@ -208,7 +208,6 @@ void Map::loadOtbm(const std::string& fileName, const UIWidgetPtr& pbar) stdext::throw_exception(stdext::format("Unknown map data node %d", (int)mapDataType)); } - g_logger.debug("OTBM read successfully."); fin->close(); } @@ -358,7 +357,7 @@ void Map::saveOtbm(const std::string &fileName, const UIWidgetPtr&/* pbar*/) root->endNode(); // OTBM_TILE_AREA root->startNode(OTBM_TOWNS); - for(const TownPtr& town : m_towns.getTowns()) { + for(const TownPtr& town : g_towns.getTowns()) { root->addU32(town->getId()); root->addString(town->getName()); root->addPos(town->getPos()); @@ -382,70 +381,6 @@ void Map::saveOtbm(const std::string &fileName, const UIWidgetPtr&/* pbar*/) fin->close(); } -void Map::loadSpawns(const std::string &fileName) -{ - if(!g_creatures.isLoaded()) { - g_logger.error("cannot load spawns; monsters/nps aren't loaded."); - return; - } - - TiXmlDocument doc; - doc.Parse(g_resources.loadFile(fileName).c_str()); - if(doc.Error()) - stdext::throw_exception(stdext::format("cannot load spawns xml file '%s: '%s'", fileName, doc.ErrorDesc())); - - TiXmlElement* root = doc.FirstChildElement(); - if(!root || root->ValueStr() != "spawns") - stdext::throw_exception("malformed spawns file"); - - CreatureTypePtr cType(nullptr); - for(TiXmlElement* node = root->FirstChildElement(); node; node = node->NextSiblingElement()) { - if(node->ValueTStr() != "spawn") - stdext::throw_exception("invalid spawn node"); - - Position centerPos = node->readPos("center"); - for(TiXmlElement* cNode = node->FirstChildElement(); cNode; cNode = cNode->NextSiblingElement()) { - if(cNode->ValueStr() != "monster" && cNode->ValueStr() != "npc") - stdext::throw_exception(stdext::format("invalid spawn-subnode %s", cNode->ValueStr())); - - std::string cName = cNode->Attribute("name"); - stdext::tolower(cName); - stdext::trim(cName); - - if (!(cType = g_creatures.getCreatureByName(cName))) - continue; - - cType->setSpawnTime(cNode->readType("spawntime")); - CreaturePtr creature(new Creature); - creature->setOutfit(cType->getOutfit()); - - stdext::ucwords(cName); - creature->setName(cName); - - centerPos.x += cNode->readType("x"); - centerPos.y += cNode->readType("y"); - centerPos.z = cNode->readType("z"); - - addThing(creature, centerPos, 4); - } - } -} - -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/towns.cpp b/src/otclient/towns.cpp index 6faee33d..5d90a0e9 100644 --- a/src/otclient/towns.cpp +++ b/src/otclient/towns.cpp @@ -22,6 +22,8 @@ #include "towns.h" +TownManager g_towns; + Town::Town(uint32 tid, const std::string& name, const Position& pos) : m_id(tid), m_name(name) { @@ -29,29 +31,34 @@ Town::Town(uint32 tid, const std::string& name, const Position& pos) m_pos = pos; } +TownManager::TownManager() +{ + m_nullTown = TownPtr(new Town); +} -void Towns::addTown(const TownPtr &town) +void TownManager::addTown(const TownPtr &town) { if(findTown(town->getId()) == m_towns.end()) m_towns.push_back(town); } -void Towns::removeTown(uint32 townId) +void TownManager::removeTown(uint32 townId) { auto it = findTown(townId); if(it != m_towns.end()) m_towns.erase(it); } -TownPtr Towns::getTown(uint32 townId) +const TownPtr& TownManager::getTown(uint32 townId) { - auto it = findTown(townId); + auto it = std::find_if(m_towns.begin(), m_towns.end(), + [=] (const TownPtr& town) -> bool { return town->getId() == townId; }); if(it != m_towns.end()) return *it; - return nullptr; + return m_nullTown; } -TownList::iterator Towns::findTown(uint32 townId) +TownList::iterator TownManager::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 index 5662f51d..440b1859 100644 --- a/src/otclient/towns.h +++ b/src/otclient/towns.h @@ -26,7 +26,6 @@ #include "declarations.h" #include - class Town : public LuaObject { public: @@ -47,22 +46,26 @@ private: Position m_pos; // temple pos }; -class Towns +class TownManager { public: - void addTown(const TownPtr &town); + TownManager(); + + void addTown(const TownPtr& town); void removeTown(uint32 townId); + const TownPtr& getTown(uint32 townId); - TownPtr getTown(uint32 townId); TownList getTowns() { return m_towns; } - - void clear() { m_towns.clear(); } + void clear() { m_towns.clear(); m_nullTown = nullptr; } private: TownList m_towns; + TownPtr m_nullTown; protected: TownList::iterator findTown(uint32 townId); }; +extern TownManager g_towns; + #endif diff --git a/src/otclient/uicreature.h b/src/otclient/uicreature.h index b8fe04a3..6693a534 100644 --- a/src/otclient/uicreature.h +++ b/src/otclient/uicreature.h @@ -30,6 +30,7 @@ class UICreature : public UIWidget { public: + UICreature() { m_color = Color::white; } void drawSelf(Fw::DrawPane drawPane); void setCreature(const CreaturePtr& creature) { m_creature = creature; }