diff --git a/client/HeroMovementController.cpp b/client/HeroMovementController.cpp index 81a625d12..6b1152f60 100644 --- a/client/HeroMovementController.cpp +++ b/client/HeroMovementController.cpp @@ -100,7 +100,8 @@ void HeroMovementController::showTeleportDialog(const CGHeroInstance * hero, Tel } } - assert(0); // exit not found? How? + // may happen when hero has path but does not moves alongside it + // for example, while standing on teleporter set path that does not leads throught teleporter and press space LOCPLINT->cb->selectionMade(-1, askID); return; } diff --git a/lib/mapObjects/CGCreature.cpp b/lib/mapObjects/CGCreature.cpp index ca661dc8e..f76915582 100644 --- a/lib/mapObjects/CGCreature.cpp +++ b/lib/mapObjects/CGCreature.cpp @@ -215,12 +215,8 @@ void CGCreature::pickRandomObject(CRandomGenerator & rand) subID = VLC->creh->pickRandomMonster(rand, 7); break; } - - if (ID != MapObjectID::MONSTER) - { - ID = MapObjectID::MONSTER; - setType(ID, subID); - } + ID = MapObjectID::MONSTER; + setType(ID, subID); } void CGCreature::initObj(CRandomGenerator & rand) diff --git a/lib/mapping/CMap.cpp b/lib/mapping/CMap.cpp index 92893cdbf..c825899e2 100644 --- a/lib/mapping/CMap.cpp +++ b/lib/mapping/CMap.cpp @@ -348,13 +348,8 @@ int3 CMap::guardingCreaturePosition (int3 pos) const { for (CGObjectInstance* obj : posTile.visitableObjects) { - if(obj->isBlockedVisitable()) - { - if (obj->ID == Obj::MONSTER) // Monster - return pos; - else - return int3(-1, -1, -1); //blockvis objects are not guarded by neighbouring creatures - } + if (obj->ID == Obj::MONSTER) + return pos; } } diff --git a/lib/pathfinder/CPathfinder.cpp b/lib/pathfinder/CPathfinder.cpp index 61cf7aa48..a713b5bdc 100644 --- a/lib/pathfinder/CPathfinder.cpp +++ b/lib/pathfinder/CPathfinder.cpp @@ -24,11 +24,45 @@ VCMI_LIB_NAMESPACE_BEGIN +bool CPathfinderHelper::canMoveFromNode(const PathNodeInfo & source) const +{ + // we can always make the first step, even when standing on object + if(source.node->theNodeBefore == nullptr) + return true; + + if (!source.nodeObject) + return true; + + if (!source.isNodeObjectVisitable()) + return true; + + // we can always move from visitable object if hero has teleported here (e.g. went through monolith) + if (source.node->isTeleportAction()) + return true; + + // we can go through garrisons + if (source.nodeObject->ID == MapObjectID::GARRISON || source.nodeObject->ID == MapObjectID::GARRISON2) + return true; + + // or through border gate (if we stand on it then we already have the key) + if (source.nodeObject->ID == MapObjectID::BORDER_GATE) + return true; + + // or "through" boat, but only if this is embarking + if (source.nodeObject->ID == MapObjectID::BOAT && source.node->action == EPathNodeAction::EMBARK) + return true; + + return false; +} + std::vector<int3> CPathfinderHelper::getNeighbourTiles(const PathNodeInfo & source) const { std::vector<int3> neighbourTiles; - neighbourTiles.reserve(8); + if (!canMoveFromNode(source)) + return neighbourTiles; + + neighbourTiles.reserve(8); getNeighbours( *source.tile, source.node->coord, @@ -38,7 +72,7 @@ std::vector<int3> CPathfinderHelper::getNeighbourTiles(const PathNodeInfo & sour if(source.isNodeObjectVisitable()) { - vstd::erase_if(neighbourTiles, [&](const int3 & tile) -> bool + vstd::erase_if(neighbourTiles, [&](const int3 & tile) -> bool { return !canMoveBetween(tile, source.nodeObject->visitablePos()); }); @@ -136,6 +170,9 @@ void CPathfinder::calculatePaths() if(neighbour->locked) continue; + if (source.node->theNodeBefore && source.node->theNodeBefore->coord == neighbour->coord ) + continue; // block U-turns + if(!hlp->isLayerAvailable(neighbour->layer)) continue; diff --git a/lib/pathfinder/CPathfinder.h b/lib/pathfinder/CPathfinder.h index af12ca56a..4203c8ba1 100644 --- a/lib/pathfinder/CPathfinder.h +++ b/lib/pathfinder/CPathfinder.h @@ -79,6 +79,7 @@ public: virtual ~CPathfinderHelper(); void initializePatrol(); bool isHeroPatrolLocked() const; + bool canMoveFromNode(const PathNodeInfo & source) const; bool isPatrolMovementAllowed(const int3 & dst) const; void updateTurnInfo(const int turn = 0); bool isLayerAvailable(const EPathfindingLayer & layer) const;