diff --git a/src/game/game.cpp b/src/game/game.cpp index 4d41ae26f58..2f110b21350 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -322,9 +322,9 @@ bool Game::loadCustomMap(const std::string& filename) return map.loadMapCustom(g_configManager().getString(DATA_DIRECTORY) + "/world/custom/" + filename + ".otbm", true, true, true); } -void Game::loadMap(const std::string& path) +void Game::loadMap(const std::string& path, const Position& pos, bool unload) { - map.loadMap(path); + map.loadMap(path, false, false, false, false, pos, unload); } Cylinder* Game::internalGetCylinder(Player* player, const Position& pos) const diff --git a/src/game/game.h b/src/game/game.h index 031b509f3b2..4caeb92d449 100644 --- a/src/game/game.h +++ b/src/game/game.h @@ -78,7 +78,7 @@ class Game * \returns true if the custom map was loaded successfully */ bool loadCustomMap(const std::string& filename); - void loadMap(const std::string& path); + void loadMap(const std::string& path, const Position& pos = Position(), bool unload = false); void getMapDimensions(uint32_t& width, uint32_t& height) const { width = map.width; diff --git a/src/io/iomap.cpp b/src/io/iomap.cpp index 4b4b072bb9a..ed14db2a17a 100644 --- a/src/io/iomap.cpp +++ b/src/io/iomap.cpp @@ -11,6 +11,7 @@ #include "io/iomap.h" #include "game/movement/teleport.h" +#include "game/game.h" /* OTBM_ROOTV1 @@ -55,7 +56,7 @@ Tile* IOMap::createTile(Item*& ground, Item* item, uint16_t x, uint16_t y, uint8 return tile; } -bool IOMap::loadMap(Map* map, const std::string& fileName) +bool IOMap::loadMap(Map* map, const std::string& fileName, const Position& pos, bool unload) { int64_t start = OTSYS_TIME(); OTB::Loader loader{fileName, OTB::Identifier{{'O', 'T', 'B', 'M'}}}; @@ -108,7 +109,7 @@ bool IOMap::loadMap(Map* map, const std::string& fileName) for (auto& mapDataNode : mapNode.children) { if (mapDataNode.type == OTBM_TILE_AREA) { - if (!parseTileArea(loader, mapDataNode, *map)) { + if (!parseTileArea(loader, mapDataNode, *map, pos, unload)) { return false; } } else if (mapDataNode.type == OTBM_TOWNS) { @@ -188,7 +189,7 @@ bool IOMap::parseMapDataAttributes(OTB::Loader& loader, const OTB::Node& mapNode return true; } -bool IOMap::parseTileArea(OTB::Loader& loader, const OTB::Node& tileAreaNode, Map& map) +bool IOMap::parseTileArea(OTB::Loader& loader, const OTB::Node& tileAreaNode, Map& map, const Position& pos, bool unload) { PropStream propStream; if (!loader.getProps(tileAreaNode, propStream)) { @@ -204,7 +205,7 @@ bool IOMap::parseTileArea(OTB::Loader& loader, const OTB::Node& tileAreaNode, Ma uint16_t base_x = area_coord.x; uint16_t base_y = area_coord.y; - uint16_t z = area_coord.z; + uint16_t base_z = area_coord.z; static std::map teleportMap; @@ -225,8 +226,31 @@ bool IOMap::parseTileArea(OTB::Loader& loader, const OTB::Node& tileAreaNode, Ma return false; } - uint16_t x = base_x + tile_coord.x; - uint16_t y = base_y + tile_coord.y; + uint16_t x = base_x + tile_coord.x + pos.x; + uint16_t y = base_y + tile_coord.y + pos.y; + uint8_t z = static_cast(base_z + pos.z); + + if (unload) { + Tile* tile = map.getTile(Position(x, y, z)); + + if (const TileItemVector* items = tile->getItemList(); + items) { + TileItemVector item_list = *items; + if (!item_list.size() == 0) { + for (Item* item : item_list) { + if (item) { + g_game().internalRemoveItem(item); + } + } + } + } + + if (Item* ground = tile->getGround(); + ground) { + g_game().internalRemoveItem(ground); + } + continue; + } bool isHouseTile = false; House* house = nullptr; @@ -243,17 +267,19 @@ bool IOMap::parseTileArea(OTB::Loader& loader, const OTB::Node& tileAreaNode, Ma return false; } - house = map.houses.addHouse(houseId); - if (!house) { - std::ostringstream ss; - ss << "[x:" << x << ", y:" << y << ", z:" << z << "] Could not create house id: " << houseId; - setLastErrorString(ss.str()); - return false; - } + if (!unload) { + house = map.houses.addHouse(houseId); + if (!house) { + std::ostringstream ss; + ss << "[x:" << x << ", y:" << y << ", z:" << z << "] Could not create house id: " << houseId; + setLastErrorString(ss.str()); + return false; + } - tile = new HouseTile(x, y, z, house); - house->addTile(static_cast(tile)); - isHouseTile = true; + tile = new HouseTile(x, y, z, house); + house->addTile(static_cast(tile)); + isHouseTile = true; + } } uint8_t attribute; @@ -261,24 +287,28 @@ bool IOMap::parseTileArea(OTB::Loader& loader, const OTB::Node& tileAreaNode, Ma while (propStream.read(attribute)) { switch (attribute) { case OTBM_ATTR_TILE_FLAGS: { - uint32_t flags; - if (!propStream.read(flags)) { - std::ostringstream ss; - ss << "[x:" << x << ", y:" << y << ", z:" << z << "] Failed to read tile flags."; - setLastErrorString(ss.str()); - return false; - } + if (!unload) { + uint32_t flags; + if (!propStream.read(flags)) { + std::ostringstream ss; + ss << "[x:" << x << ", y:" << y << ", z:" << z << "] Failed to read tile flags."; + setLastErrorString(ss.str()); + return false; + } - if ((flags & OTBM_TILEFLAG_PROTECTIONZONE) != 0) { - tileflags |= TILESTATE_PROTECTIONZONE; - } else if ((flags & OTBM_TILEFLAG_NOPVPZONE) != 0) { - tileflags |= TILESTATE_NOPVPZONE; - } else if ((flags & OTBM_TILEFLAG_PVPZONE) != 0) { - tileflags |= TILESTATE_PVPZONE; - } + if ((flags & OTBM_TILEFLAG_PROTECTIONZONE) != 0) { + tileflags |= TILESTATE_PROTECTIONZONE; + } + else if ((flags & OTBM_TILEFLAG_NOPVPZONE) != 0) { + tileflags |= TILESTATE_NOPVPZONE; + } + else if ((flags & OTBM_TILEFLAG_PVPZONE) != 0) { + tileflags |= TILESTATE_PVPZONE; + } - if ((flags & OTBM_TILEFLAG_NOLOGOUT) != 0) { - tileflags |= TILESTATE_NOLOGOUT; + if ((flags & OTBM_TILEFLAG_NOLOGOUT) != 0) { + tileflags |= TILESTATE_NOLOGOUT; + } } break; } diff --git a/src/io/iomap.h b/src/io/iomap.h index 82291762daf..c772d18a80e 100644 --- a/src/io/iomap.h +++ b/src/io/iomap.h @@ -47,7 +47,7 @@ class IOMap static Tile* createTile(Item*& ground, Item* item, uint16_t x, uint16_t y, uint8_t z); public: - bool loadMap(Map* map, const std::string& identifier); + bool loadMap(Map* map, const std::string& identifier, const Position& pos = Position(), bool unload = false); /** * Load main map monsters @@ -157,7 +157,7 @@ class IOMap bool parseMapDataAttributes(OTB::Loader& loader, const OTB::Node& mapNode, Map& map, const std::string& fileName); bool parseWaypoints(OTB::Loader& loader, const OTB::Node& waypointsNode, Map& map); bool parseTowns(OTB::Loader& loader, const OTB::Node& townsNode, Map& map); - bool parseTileArea(OTB::Loader& loader, const OTB::Node& tileAreaNode, Map& map); + bool parseTileArea(OTB::Loader& loader, const OTB::Node& tileAreaNode, Map& map, const Position& pos, bool unload); std::string errorString; }; diff --git a/src/lua/functions/core/game/game_functions.cpp b/src/lua/functions/core/game/game_functions.cpp index 56b3668fa24..8d7df74fe33 100644 --- a/src/lua/functions/core/game/game_functions.cpp +++ b/src/lua/functions/core/game/game_functions.cpp @@ -146,6 +146,15 @@ int GameFunctions::luaGameLoadMap(lua_State* L) { return 0; } +int GameFunctions::luaGameloadMapChunk(lua_State* L) { + // Game.loadMapChunk(path, position, remove) + const std::string& path = getString(L, 1); + const Position& position = getPosition(L, 2); + bool unload = getBoolean(L, 3); + g_dispatcher().addTask(createTask([path, position, unload]() {g_game().loadMap(path, position, unload); })); + return 0; +} + int GameFunctions::luaGameGetMonsterCount(lua_State* L) { // Game.getMonsterCount() lua_pushnumber(L, g_game().getMonstersOnline()); diff --git a/src/lua/functions/core/game/game_functions.hpp b/src/lua/functions/core/game/game_functions.hpp index 3f8d42decbf..cddc639eef5 100644 --- a/src/lua/functions/core/game/game_functions.hpp +++ b/src/lua/functions/core/game/game_functions.hpp @@ -27,6 +27,7 @@ class GameFunctions final : LuaScriptInterface { registerMethod(L, "Game", "getPlayers", GameFunctions::luaGameGetPlayers); registerMethod(L, "Game", "loadMap", GameFunctions::luaGameLoadMap); + registerMethod(L, "Game", "loadMapChunk", GameFunctions::luaGameloadMapChunk); registerMethod(L, "Game", "getMonsterCount", GameFunctions::luaGameGetMonsterCount); registerMethod(L, "Game", "getPlayerCount", GameFunctions::luaGameGetPlayerCount); @@ -85,6 +86,7 @@ class GameFunctions final : LuaScriptInterface { static int luaGameGetPlayers(lua_State* L); static int luaGameLoadMap(lua_State* L); + static int luaGameloadMapChunk(lua_State* L); static int luaGameGetMonsterCount(lua_State* L); static int luaGameGetPlayerCount(lua_State* L); diff --git a/src/map/map.cpp b/src/map/map.cpp index f1eb30e2fa6..b1558b650d5 100644 --- a/src/map/map.cpp +++ b/src/map/map.cpp @@ -16,10 +16,10 @@ #include "game/game.h" #include "creatures/monsters/monster.h" -bool Map::load(const std::string& identifier) { +bool Map::load(const std::string& identifier, const Position& pos, bool unload) { try { IOMap loader; - if (!loader.loadMap(this, identifier)) { + if (!loader.loadMap(this, identifier, pos, unload)) { SPDLOG_ERROR("[Map::load] - {}", loader.getLastErrorString()); return false; } @@ -33,7 +33,8 @@ bool Map::load(const std::string& identifier) { bool Map::loadMap(const std::string& identifier, bool mainMap /*= false*/,bool loadHouses /*= false*/, - bool loadMonsters /*= false*/, bool loadNpcs /*= false*/) + bool loadMonsters /*= false*/, bool loadNpcs /*= false*/, + const Position& pos /*= Position()*/, bool unload /*= false*/) { // Only download map if is loading the main map and it is not already downloaded if (mainMap && g_configManager().getBoolean(TOGGLE_DOWNLOAD_MAP) && !std::filesystem::exists(identifier)) { @@ -56,7 +57,7 @@ bool Map::loadMap(const std::string& identifier, } // Load the map - this->load(identifier); + this->load(identifier, pos, unload); // Only create items from lua functions if is loading main map // It needs to be after the load map to ensure the map already exists before creating the items diff --git a/src/map/map.h b/src/map/map.h index d3731168994..73f2cbd23d9 100644 --- a/src/map/map.h +++ b/src/map/map.h @@ -175,7 +175,7 @@ class Map * Load a map. * \returns true if the map was loaded successfully */ - bool load(const std::string& identifier); + bool load(const std::string& identifier, const Position& pos = Position(), bool unload = false); /** * Load the main map * \param identifier Is the main map name (name of file .otbm) @@ -184,7 +184,7 @@ class Map * \param loadNpcs if true, the main map npcs is loaded * \returns true if the main map was loaded successfully */ - bool loadMap(const std::string& identifier, bool mainMap = false, bool loadHouses = false, bool loadMonsters = false, bool loadNpcs = false); + bool loadMap(const std::string& identifier, bool mainMap = false, bool loadHouses = false, bool loadMonsters = false, bool loadNpcs = false, const Position& pos = Position(), bool unload = false); /** * Load the custom map * \param identifier Is the map custom folder