From 64d607b59ed258813d1efac516e2bb05f9525e8e Mon Sep 17 00:00:00 2001 From: Eduardo Bart Date: Tue, 21 Aug 2012 23:10:56 -0300 Subject: [PATCH] Fix issue #77 and improve findPath --- modules/game_interface/gameinterface.lua | 2 +- modules/game_minimap/minimap.lua | 6 ++-- modules/gamelib/const.lua | 15 +++++++++ src/otclient/const.h | 17 +++++++--- src/otclient/map.cpp | 42 +++++++++++++++++------- src/otclient/map.h | 2 +- src/otclient/tile.cpp | 5 +-- 7 files changed, 64 insertions(+), 25 deletions(-) diff --git a/modules/game_interface/gameinterface.lua b/modules/game_interface/gameinterface.lua index 7af75deb..c1d16b2b 100644 --- a/modules/game_interface/gameinterface.lua +++ b/modules/game_interface/gameinterface.lua @@ -405,7 +405,7 @@ function processMouseAction(menuPosition, mouseButton, autoWalkPos, lookThing, u end if autoWalkPos and keyboardModifiers == KeyboardNoModifier and mouseButton == MouseLeftButton then - local dirs = g_map.findPath(g_game.getLocalPlayer():getPosition(), autoWalkPos, 127) + local dirs = g_map.findPath(g_game.getLocalPlayer():getPosition(), autoWalkPos, 127, PathFindFlags.AllowNullTiles) if #dirs == 0 then modules.game_textmessage.displayStatusMessage(tr('There is no way.')) return true diff --git a/modules/game_minimap/minimap.lua b/modules/game_minimap/minimap.lua index d768a524..f286a7ec 100644 --- a/modules/game_minimap/minimap.lua +++ b/modules/game_minimap/minimap.lua @@ -160,9 +160,9 @@ function onMinimapMouseRelease(self, mousePosition, mouseButton) navigating = false return end - local tile = self:getTile(mousePosition) - if tile and mouseButton == MouseLeftButton and self:isPressed() then - local dirs = g_map.findPath(g_game.getLocalPlayer():getPosition(), tile:getPosition(), 127) + local pos = self:getPosition(mousePosition) + if pos and mouseButton == MouseLeftButton and self:isPressed() then + local dirs = g_map.findPath(g_game.getLocalPlayer():getPosition(), pos, 127, PathFindFlags.AllowNullTiles) if #dirs == 0 then modules.game_textmessage.displayStatusMessage(tr('There is no way.')) return true diff --git a/modules/gamelib/const.lua b/modules/gamelib/const.lua index ee1ead0a..038412bf 100644 --- a/modules/gamelib/const.lua +++ b/modules/gamelib/const.lua @@ -156,4 +156,19 @@ OsTypes = { OtclientMac = 12 } +PathFindResults = { + Ok = 0, + Position = 1, + Impossipble = 2, + TooFar = 3, + NoWay = 4 +} + +PathFindFlags = { + AllowNullTiles = 1, + AllowCreatures = 2, + AllowNonPathable = 4, + AllowNonWalkable = 8 +} + -- @} diff --git a/src/otclient/const.h b/src/otclient/const.h index 2e89e7a8..7b72a9d5 100644 --- a/src/otclient/const.h +++ b/src/otclient/const.h @@ -341,11 +341,18 @@ namespace Otc }; enum PathFindResult { - PATHFIND_OK = 0, - PATHFIND_SAME_POSITION, - PATHFIND_IMPOSSIBLE, - PATHFIND_TOO_FAR, - PATHFIND_NO_WAY + PATHFIND_RESULT_OK = 0, + PATHFIND_RESULT_SAME_POSITION, + PATHFIND_RESULT_IMPOSSIBLE, + PATHFIND_RESULT_TOO_FAR, + PATHFIND_RESULT_NO_WAY + }; + + enum PathFindFlag { + PATHFIND_ALLOW_NULLTILES = 1, + PATHFIND_ALLOW_CREATURES = 2, + PATHFIND_ALLOW_NONPATHABLE = 4, + PATHFIND_ALLOW_NONWALKABLE = 8 }; } diff --git a/src/otclient/map.cpp b/src/otclient/map.cpp index 78ecd272..36ca4e56 100644 --- a/src/otclient/map.cpp +++ b/src/otclient/map.cpp @@ -428,7 +428,7 @@ int Map::getLastAwareFloor() return Otc::SEA_FLOOR; } -std::tuple, Otc::PathFindResult> Map::findPath(const Position& startPos, const Position& goalPos, int maxSteps) +std::tuple, Otc::PathFindResult> Map::findPath(const Position& startPos, const Position& goalPos, int maxSteps, int flags) { // pathfinding using A* search algorithm // as described in http://en.wikipedia.org/wiki/A*_search_algorithm @@ -455,20 +455,20 @@ std::tuple, Otc::PathFindResult> Map::findPath(const std::vector& dirs = std::get<0>(ret); Otc::PathFindResult& result = std::get<1>(ret); - result = Otc::PATHFIND_OK; + result = Otc::PATHFIND_RESULT_NO_WAY; if(startPos == goalPos) { - result = Otc::PATHFIND_SAME_POSITION; + result = Otc::PATHFIND_RESULT_SAME_POSITION; return ret; } if(startPos.z != goalPos.z) { - result = Otc::PATHFIND_IMPOSSIBLE; + result = Otc::PATHFIND_RESULT_IMPOSSIBLE; return ret; } if(startPos.distance(goalPos) > maxSteps) { - result = Otc::PATHFIND_TOO_FAR; + result = Otc::PATHFIND_RESULT_TOO_FAR; return ret; } @@ -479,10 +479,18 @@ std::tuple, Otc::PathFindResult> Map::findPath(const currentNode->pos = startPos; nodes[startPos] = currentNode; Node *foundNode = nullptr; - while(currentNode && currentNode->steps < maxSteps) { + while(currentNode) { + // too far + if(currentNode->steps >= maxSteps) { + result = Otc::PATHFIND_RESULT_TOO_FAR; + break; + } + + // path found if(currentNode->pos == goalPos && (!foundNode || currentNode->cost < foundNode->cost)) foundNode = currentNode; + // cost too high if(foundNode && currentNode->totalCost >= foundNode->cost) break; @@ -493,8 +501,19 @@ std::tuple, Otc::PathFindResult> Map::findPath(const Position neighborPos = currentNode->pos.translated(i, j); const TilePtr& tile = getTile(neighborPos); - if(!tile || (!tile->isPathable() && neighborPos != goalPos) || (!tile->isWalkable() && neighborPos == goalPos)) - continue; + + if(neighborPos != goalPos) { + if(!(flags & Otc::PATHFIND_ALLOW_NULLTILES) && !tile) + continue; + if(tile) { + if(!(flags & Otc::PATHFIND_ALLOW_CREATURES) && tile->hasCreature()) + continue; + if(!(flags & Otc::PATHFIND_ALLOW_NONPATHABLE) && !tile->isPathable()) + continue; + if(!(flags & Otc::PATHFIND_ALLOW_NONWALKABLE) && !tile->isWalkable()) + continue; + } + } float walkFactor; Otc::Direction walkDir = currentNode->pos.getDirectionFromPosition(neighborPos); @@ -503,7 +522,8 @@ std::tuple, Otc::PathFindResult> Map::findPath(const else walkFactor = 1.0f; - float cost = currentNode->cost + (tile->getGroundSpeed() * walkFactor) / 100.0f; + int groundSpeed = tile ? tile->getGroundSpeed() : 100; + float cost = currentNode->cost + (groundSpeed * walkFactor) / 100.0f; Node *neighborNode; if(nodes.find(neighborPos) == nodes.end()) { @@ -544,8 +564,8 @@ std::tuple, Otc::PathFindResult> Map::findPath(const } dirs.pop_back(); std::reverse(dirs.begin(), dirs.end()); - } else - result = Otc::PATHFIND_NO_WAY; + result = Otc::PATHFIND_RESULT_OK; + } for(auto it : nodes) delete it.second; diff --git a/src/otclient/map.h b/src/otclient/map.h index 69fbf08d..99367de6 100644 --- a/src/otclient/map.h +++ b/src/otclient/map.h @@ -253,7 +253,7 @@ public: std::vector getAnimatedTexts() { return m_animatedTexts; } std::vector getStaticTexts() { return m_staticTexts; } - std::tuple, Otc::PathFindResult> findPath(const Position& start, const Position& goal, int maxSteps); + std::tuple, Otc::PathFindResult> findPath(const Position& start, const Position& goal, int maxSteps, int flags = 0); private: uint getBlockIndex(const Position& pos) { return ((pos.y / BLOCK_SIZE) * (65536 / BLOCK_SIZE)) + (pos.x / BLOCK_SIZE); } diff --git a/src/otclient/tile.cpp b/src/otclient/tile.cpp index a4dadb36..b62a290e 100644 --- a/src/otclient/tile.cpp +++ b/src/otclient/tile.cpp @@ -469,11 +469,8 @@ bool Tile::changesFloor() bool Tile::isPathable() { - if(!isWalkable()) - return false; - for(const ThingPtr& thing : m_things) { - if(thing->isNotPathable() || thing->isCreature()) + if(thing->isNotPathable()) return false; }