diff --git a/lib/CPathfinder.cpp b/lib/CPathfinder.cpp index f57a08af2..ab2146796 100644 --- a/lib/CPathfinder.cpp +++ b/lib/CPathfinder.cpp @@ -321,10 +321,13 @@ bool CPathfinder::isLayerTransitionPossible() const bool CPathfinder::isMovementToDestPossible() const { + if(dp->accessible == CGPathNode::BLOCKED) + return false; + switch(dp->layer) { case ELayer::LAND: - if(!canMoveBetween(cp->coord, dp->coord) || dp->accessible == CGPathNode::BLOCKED) + if(!canMoveBetween(cp->coord, dp->coord)) return false; if(isSourceGuarded()) { @@ -338,7 +341,7 @@ bool CPathfinder::isMovementToDestPossible() const break; case ELayer::SAIL: - if(!canMoveBetween(cp->coord, dp->coord) || dp->accessible == CGPathNode::BLOCKED) + if(!canMoveBetween(cp->coord, dp->coord)) return false; if(isSourceGuarded()) { @@ -531,17 +534,10 @@ bool CPathfinder::isDestinationGuardian() const void CPathfinder::initializeGraph() { - auto updateNode = [&](int3 pos, ELayer layer, const TerrainTile * tinfo, bool blockNotAccessible) + auto updateNode = [&](int3 pos, ELayer layer, const TerrainTile * tinfo) { auto node = out.getNode(pos, layer); - - auto accessibility = evaluateAccessibility(pos, tinfo); - /// TODO: Probably this shouldn't be handled by initializeGraph - if(blockNotAccessible - && (accessibility != CGPathNode::ACCESSIBLE || tinfo->terType == ETerrainType::WATER)) - { - accessibility = CGPathNode::BLOCKED; - } + auto accessibility = evaluateAccessibility(pos, tinfo, layer); node->update(pos, layer, accessibility); }; @@ -555,65 +551,86 @@ void CPathfinder::initializeGraph() const TerrainTile * tinfo = getTile(pos); switch(tinfo->terType) { - case ETerrainType::ROCK: - break; - case ETerrainType::WATER: - updateNode(pos, ELayer::SAIL, tinfo, false); - if(options.useFlying) - updateNode(pos, ELayer::AIR, tinfo, true); - if(options.useWaterWalking) - updateNode(pos, ELayer::WATER, tinfo, false); - break; - default: - updateNode(pos, ELayer::LAND, tinfo, false); - if(options.useFlying) - updateNode(pos, ELayer::AIR, tinfo, true); - break; + case ETerrainType::ROCK: + break; + + case ETerrainType::WATER: + updateNode(pos, ELayer::SAIL, tinfo); + if(options.useFlying) + updateNode(pos, ELayer::AIR, tinfo); + if(options.useWaterWalking) + updateNode(pos, ELayer::WATER, tinfo); + break; + + default: + updateNode(pos, ELayer::LAND, tinfo); + if(options.useFlying) + updateNode(pos, ELayer::AIR, tinfo); + break; } } } } } -CGPathNode::EAccessibility CPathfinder::evaluateAccessibility(const int3 & pos, const TerrainTile * tinfo) const +CGPathNode::EAccessibility CPathfinder::evaluateAccessibility(const int3 & pos, const TerrainTile * tinfo, const ELayer layer) const { - CGPathNode::EAccessibility ret = (tinfo->blocked ? CGPathNode::BLOCKED : CGPathNode::ACCESSIBLE); - if(tinfo->terType == ETerrainType::ROCK || !isVisible(pos, hero->tempOwner)) return CGPathNode::BLOCKED; - if(tinfo->visitable) + switch(layer) { - if(tinfo->visitableObjects.front()->ID == Obj::SANCTUARY && tinfo->visitableObjects.back()->ID == Obj::HERO && tinfo->visitableObjects.back()->tempOwner != hero->tempOwner) //non-owned hero stands on Sanctuary + case ELayer::LAND: + case ELayer::SAIL: + if(tinfo->visitable) { - return CGPathNode::BLOCKED; - } - else - { - for(const CGObjectInstance * obj : tinfo->visitableObjects) + if(tinfo->visitableObjects.front()->ID == Obj::SANCTUARY && tinfo->visitableObjects.back()->ID == Obj::HERO && tinfo->visitableObjects.back()->tempOwner != hero->tempOwner) //non-owned hero stands on Sanctuary { - if(obj->passableFor(hero->tempOwner)) + return CGPathNode::BLOCKED; + } + else + { + for(const CGObjectInstance * obj : tinfo->visitableObjects) { - ret = CGPathNode::ACCESSIBLE; - } - else if(obj->blockVisit) - { - return CGPathNode::BLOCKVIS; - } - else if(obj->ID != Obj::EVENT) //pathfinder should ignore placed events - { - ret = CGPathNode::VISITABLE; + if(obj->passableFor(hero->tempOwner)) + { + return CGPathNode::ACCESSIBLE; + } + else if(obj->blockVisit) + { + return CGPathNode::BLOCKVIS; + } + else if(obj->ID != Obj::EVENT) //pathfinder should ignore placed events + { + return CGPathNode::VISITABLE; + } } } } - } - else if(guardingCreaturePosition(pos).valid() && !tinfo->blocked) - { - // Monster close by; blocked visit for battle. - return CGPathNode::BLOCKVIS; + else if(guardingCreaturePosition(pos).valid() && !tinfo->blocked) + { + // Monster close by; blocked visit for battle + return CGPathNode::BLOCKVIS; + } + else if(tinfo->blocked) + return CGPathNode::BLOCKED; + + break; + + case ELayer::WATER: + if(tinfo->blocked || tinfo->terType != ETerrainType::WATER) + return CGPathNode::BLOCKED; + + break; + + case ELayer::AIR: + if(tinfo->blocked || tinfo->terType == ETerrainType::WATER) + return CGPathNode::FLYABLE; + + break; } - return ret; + return CGPathNode::ACCESSIBLE; } bool CPathfinder::canMoveBetween(const int3 & a, const int3 & b) const diff --git a/lib/CPathfinder.h b/lib/CPathfinder.h index 64c80dee5..51a47af41 100644 --- a/lib/CPathfinder.h +++ b/lib/CPathfinder.h @@ -43,6 +43,7 @@ struct DLL_LINKAGE CGPathNode ACCESSIBLE = 1, //tile can be entered and passed VISITABLE, //tile can be entered as the last tile in path BLOCKVIS, //visitable from neighbouring tile but not passable + FLYABLE, //can only be accessed in air layer BLOCKED //tile can't be entered nor visited }; @@ -181,7 +182,7 @@ private: void initializeGraph(); - CGPathNode::EAccessibility evaluateAccessibility(const int3 & pos, const TerrainTile * tinfo) const; + CGPathNode::EAccessibility evaluateAccessibility(const int3 & pos, const TerrainTile * tinfo, const ELayer layer) const; bool canMoveBetween(const int3 & a, const int3 & b) const; //checks only for visitable objects that may make moving between tiles impossible, not other conditions (like tiles itself accessibility) bool isAllowedTeleportEntrance(const CGTeleport * obj) const;