/* * CGPathNode.cpp, part of VCMI engine * * Authors: listed in file AUTHORS in main folder * * License: GNU General Public License v2.0 or later * Full text of license available in license.txt file, in main folder * */ #include "StdInc.h" #include "CGPathNode.h" #include "CPathfinder.h" #include "../gameState/CGameState.h" #include "../mapObjects/CGHeroInstance.h" #include "../mapping/CMapDefines.h" VCMI_LIB_NAMESPACE_BEGIN static bool canSeeObj(const CGObjectInstance * obj) { /// Pathfinder should ignore placed events return obj != nullptr && obj->ID != Obj::EVENT; } int3 CGPath::startPos() const { return nodes[nodes.size()-1].coord; } int3 CGPath::endPos() const { return nodes[0].coord; } CPathsInfo::CPathsInfo(const int3 & Sizes, const CGHeroInstance * hero_) : sizes(Sizes), hero(hero_) { nodes.resize(boost::extents[ELayer::NUM_LAYERS][sizes.z][sizes.x][sizes.y]); } CPathsInfo::~CPathsInfo() = default; const CGPathNode * CPathsInfo::getPathInfo(const int3 & tile) const { assert(vstd::iswithin(tile.x, 0, sizes.x)); assert(vstd::iswithin(tile.y, 0, sizes.y)); assert(vstd::iswithin(tile.z, 0, sizes.z)); return getNode(tile); } bool CPathsInfo::getPath(CGPath & out, const int3 & dst) const { out.nodes.clear(); const CGPathNode * curnode = getNode(dst); if(!curnode->theNodeBefore) return false; while(curnode) { const CGPathNode cpn = * curnode; curnode = curnode->theNodeBefore; out.nodes.push_back(cpn); } return true; } const CGPathNode * CPathsInfo::getNode(const int3 & coord) const { const auto * landNode = &nodes[ELayer::LAND][coord.z][coord.x][coord.y]; if(landNode->reachable()) return landNode; else return &nodes[ELayer::SAIL][coord.z][coord.x][coord.y]; } PathNodeInfo::PathNodeInfo() : node(nullptr), nodeObject(nullptr), tile(nullptr), coord(-1, -1, -1), guarded(false), isInitialPosition(false) { } void PathNodeInfo::setNode(CGameState * gs, CGPathNode * n) { node = n; if(coord != node->coord) { assert(node->coord.valid()); coord = node->coord; tile = gs->getTile(coord); nodeObject = tile->topVisitableObj(); if(nodeObject && nodeObject->ID == Obj::HERO) { nodeHero = dynamic_cast(nodeObject); nodeObject = tile->topVisitableObj(true); if(!nodeObject) nodeObject = nodeHero; } else { nodeHero = nullptr; } } guarded = false; } void PathNodeInfo::updateInfo(CPathfinderHelper * hlp, CGameState * gs) { if(gs->guardingCreaturePosition(node->coord).valid() && !isInitialPosition) { guarded = true; } if(nodeObject) { objectRelations = gs->getPlayerRelations(hlp->owner, nodeObject->tempOwner); } if(nodeHero) { heroRelations = gs->getPlayerRelations(hlp->owner, nodeHero->tempOwner); } } bool PathNodeInfo::isNodeObjectVisitable() const { /// Hero can't visit objects while walking on water or flying return (node->layer == EPathfindingLayer::LAND || node->layer == EPathfindingLayer::SAIL) && (canSeeObj(nodeObject) || canSeeObj(nodeHero)); } CDestinationNodeInfo::CDestinationNodeInfo(): blocked(false), action(EPathNodeAction::UNKNOWN) { } void CDestinationNodeInfo::setNode(CGameState * gs, CGPathNode * n) { PathNodeInfo::setNode(gs, n); blocked = false; action = EPathNodeAction::UNKNOWN; } bool CDestinationNodeInfo::isBetterWay() const { if(node->turns == 0xff) //we haven't been here before return true; else return cost < node->getCost(); //this route is faster } VCMI_LIB_NAMESPACE_END