mirror of
https://github.com/vcmi/vcmi.git
synced 2025-09-16 09:26:28 +02:00
Pathfinding: rework isLayerTransitionPossible and fix formatting
This commit is contained in:
@@ -35,7 +35,7 @@ CPathfinder::PathfinderOptions::PathfinderOptions()
|
|||||||
originalMovementRules = true;
|
originalMovementRules = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
CPathfinder::CPathfinder(CPathsInfo &_out, CGameState *_gs, const CGHeroInstance *_hero)
|
CPathfinder::CPathfinder(CPathsInfo & _out, CGameState * _gs, const CGHeroInstance * _hero)
|
||||||
: CGameInfoCallback(_gs, boost::optional<PlayerColor>()), out(_out), hero(_hero)
|
: CGameInfoCallback(_gs, boost::optional<PlayerColor>()), out(_out), hero(_hero)
|
||||||
{
|
{
|
||||||
assert(hero);
|
assert(hero);
|
||||||
@@ -82,7 +82,7 @@ void CPathfinder::calculatePaths()
|
|||||||
return true;
|
return true;
|
||||||
else if(dp->turns > turn)
|
else if(dp->turns > turn)
|
||||||
return true;
|
return true;
|
||||||
else if(dp->turns >= turn && dp->moveRemains < remains) //this route is faster
|
else if(dp->turns >= turn && dp->moveRemains < remains) //this route is faster
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@@ -91,7 +91,7 @@ void CPathfinder::calculatePaths()
|
|||||||
//logGlobal->infoStream() << boost::format("Calculating paths for hero %s (adress %d) of player %d") % hero->name % hero % hero->tempOwner;
|
//logGlobal->infoStream() << boost::format("Calculating paths for hero %s (adress %d) of player %d") % hero->name % hero % hero->tempOwner;
|
||||||
|
|
||||||
//initial tile - set cost on 0 and add to the queue
|
//initial tile - set cost on 0 and add to the queue
|
||||||
CGPathNode *initialNode = out.getNode(out.hpos, hero->boat ? ELayer::SAIL : ELayer::LAND);
|
CGPathNode * initialNode = out.getNode(out.hpos, hero->boat ? ELayer::SAIL : ELayer::LAND);
|
||||||
initialNode->turns = 0;
|
initialNode->turns = 0;
|
||||||
initialNode->moveRemains = hero->movement;
|
initialNode->moveRemains = hero->movement;
|
||||||
pq.push(initialNode);
|
pq.push(initialNode);
|
||||||
@@ -195,7 +195,7 @@ void CPathfinder::calculatePaths()
|
|||||||
} //queue loop
|
} //queue loop
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPathfinder::addNeighbours(const int3 &coord)
|
void CPathfinder::addNeighbours(const int3 & coord)
|
||||||
{
|
{
|
||||||
neighbours.clear();
|
neighbours.clear();
|
||||||
std::vector<int3> tiles;
|
std::vector<int3> tiles;
|
||||||
@@ -242,7 +242,7 @@ void CPathfinder::addTeleportExits(bool noTeleportExcludes)
|
|||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
const CGTeleport *sTileTeleport = dynamic_cast<const CGTeleport *>(cObj);
|
const CGTeleport * sTileTeleport = dynamic_cast<const CGTeleport *>(cObj);
|
||||||
if(isAllowedTeleportEntrance(sTileTeleport))
|
if(isAllowedTeleportEntrance(sTileTeleport))
|
||||||
{
|
{
|
||||||
for(auto objId : gs->getTeleportChannelExits(sTileTeleport->channel, hero->tempOwner))
|
for(auto objId : gs->getTeleportChannelExits(sTileTeleport->channel, hero->tempOwner))
|
||||||
@@ -271,20 +271,21 @@ void CPathfinder::addTeleportExits(bool noTeleportExcludes)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CPathfinder::isLayerAvailable(const ELayer &layer, const int &turn) const
|
bool CPathfinder::isLayerAvailable(const ELayer layer, const int turn) const
|
||||||
{
|
{
|
||||||
switch(layer)
|
switch(layer)
|
||||||
{
|
{
|
||||||
case ELayer::AIR:
|
case ELayer::AIR:
|
||||||
if(!hlp->ti->bonusFlying)
|
if(!hlp->ti->bonusFlying)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ELayer::WATER:
|
case ELayer::WATER:
|
||||||
if(!hlp->ti->bonusWaterWalking)
|
if(!hlp->ti->bonusWaterWalking)
|
||||||
return false;
|
return false;
|
||||||
break;
|
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -296,17 +297,45 @@ bool CPathfinder::isLayerTransitionPossible() const
|
|||||||
if(cp->action == CGPathNode::BATTLE)
|
if(cp->action == CGPathNode::BATTLE)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if((cp->layer == ELayer::AIR || cp->layer == ELayer::WATER)
|
switch(cp->layer)
|
||||||
&& dp->layer != ELayer::LAND)
|
|
||||||
{
|
|
||||||
/// Hero that fly or walking on water can only go into ground layer
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else if(cp->layer == ELayer::AIR && dp->layer == ELayer::LAND)
|
|
||||||
{
|
{
|
||||||
|
case ELayer::LAND:
|
||||||
|
if(options.lightweightFlyingMode && dp->layer == ELayer::AIR)
|
||||||
|
{
|
||||||
|
if(!isSourceInitialPosition())
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if(dp->layer == ELayer::SAIL)
|
||||||
|
{
|
||||||
|
/// Cannot enter empty water tile from land -> it has to be visitable
|
||||||
|
if(dp->accessible == CGPathNode::ACCESSIBLE)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ELayer::SAIL:
|
||||||
|
if(dp->layer != ELayer::LAND)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if(!dt->isCoastal())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
//tile must be accessible -> exception: unblocked blockvis tiles -> clear but guarded by nearby monster coast
|
||||||
|
if((dp->accessible != CGPathNode::ACCESSIBLE && (dp->accessible != CGPathNode::BLOCKVIS || dt->blocked))
|
||||||
|
|| dt->visitable) //TODO: passableness problem -> town says it's passable (thus accessible) but we obviously can't disembark onto town gate
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ELayer::AIR:
|
||||||
|
if(dp->layer != ELayer::LAND)
|
||||||
|
return false;
|
||||||
|
|
||||||
if(options.originalMovementRules)
|
if(options.originalMovementRules)
|
||||||
{
|
{
|
||||||
if ((cp->accessible != CGPathNode::ACCESSIBLE &&
|
if((cp->accessible != CGPathNode::ACCESSIBLE &&
|
||||||
cp->accessible != CGPathNode::VISITABLE) &&
|
cp->accessible != CGPathNode::VISITABLE) &&
|
||||||
(dp->accessible != CGPathNode::VISITABLE &&
|
(dp->accessible != CGPathNode::VISITABLE &&
|
||||||
dp->accessible != CGPathNode::ACCESSIBLE))
|
dp->accessible != CGPathNode::ACCESSIBLE))
|
||||||
@@ -319,74 +348,60 @@ bool CPathfinder::isLayerTransitionPossible() const
|
|||||||
/// Hero that fly can only land on accessible tiles
|
/// Hero that fly can only land on accessible tiles
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else if(cp->layer == ELayer::LAND && dp->layer == ELayer::AIR)
|
break;
|
||||||
{
|
|
||||||
if(options.lightweightFlyingMode && !isSourceInitialPosition())
|
case ELayer::WATER:
|
||||||
return false;
|
if(dp->layer != ELayer::LAND)
|
||||||
}
|
|
||||||
else if(cp->layer == ELayer::SAIL && dp->layer != ELayer::LAND)
|
|
||||||
return false;
|
|
||||||
else if(cp->layer == ELayer::SAIL && dp->layer == ELayer::LAND)
|
|
||||||
{
|
|
||||||
if(!dt->isCoastal())
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
//tile must be accessible -> exception: unblocked blockvis tiles -> clear but guarded by nearby monster coast
|
break;
|
||||||
if((dp->accessible != CGPathNode::ACCESSIBLE && (dp->accessible != CGPathNode::BLOCKVIS || dt->blocked))
|
|
||||||
|| dt->visitable) //TODO: passableness problem -> town says it's passable (thus accessible) but we obviously can't disembark onto town gate
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else if(cp->layer == ELayer::LAND && dp->layer == ELayer::SAIL)
|
|
||||||
{
|
|
||||||
if(dp->accessible == CGPathNode::ACCESSIBLE) //cannot enter empty water tile from land -> it has to be visitable
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CPathfinder::isMovementToDestPossible() const
|
bool CPathfinder::isMovementToDestPossible() const
|
||||||
{
|
{
|
||||||
auto obj = dt->topVisitableObj();
|
|
||||||
switch(dp->layer)
|
switch(dp->layer)
|
||||||
{
|
{
|
||||||
case ELayer::LAND:
|
case ELayer::LAND:
|
||||||
if(!canMoveBetween(cp->coord, dp->coord) || dp->accessible == CGPathNode::BLOCKED)
|
if(!canMoveBetween(cp->coord, dp->coord) || dp->accessible == CGPathNode::BLOCKED)
|
||||||
return false;
|
return false;
|
||||||
if(isSourceGuarded())
|
if(isSourceGuarded())
|
||||||
|
{
|
||||||
|
if(!(options.originalMovementRules && cp->layer == ELayer::AIR) &&
|
||||||
|
!isDestinationGuardian()) // Can step into tile of guard
|
||||||
{
|
{
|
||||||
if(!(options.originalMovementRules && cp->layer == ELayer::AIR) &&
|
return false;
|
||||||
!isDestinationGuardian()) // Can step into tile of guard
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ELayer::SAIL:
|
case ELayer::SAIL:
|
||||||
if(!canMoveBetween(cp->coord, dp->coord) || dp->accessible == CGPathNode::BLOCKED)
|
if(!canMoveBetween(cp->coord, dp->coord) || dp->accessible == CGPathNode::BLOCKED)
|
||||||
return false;
|
return false;
|
||||||
if(isSourceGuarded() && !isDestinationGuardian()) // Can step into tile of guard
|
if(isSourceGuarded() && !isDestinationGuardian()) // Can step into tile of guard
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if(cp->layer == ELayer::LAND)
|
||||||
|
{
|
||||||
|
if(!dObj)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if(cp->layer == ELayer::LAND)
|
if(dObj->ID != Obj::BOAT && dObj->ID != Obj::HERO)
|
||||||
{
|
|
||||||
if(!obj)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if(obj->ID != Obj::BOAT && obj->ID != Obj::HERO)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ELayer::WATER:
|
|
||||||
if(!canMoveBetween(cp->coord, dp->coord) || dp->accessible != CGPathNode::ACCESSIBLE)
|
|
||||||
return false;
|
|
||||||
if(isDestinationGuarded())
|
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
break;
|
case ELayer::WATER:
|
||||||
|
if(!canMoveBetween(cp->coord, dp->coord) || dp->accessible != CGPathNode::ACCESSIBLE)
|
||||||
|
return false;
|
||||||
|
if(isDestinationGuarded())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -401,16 +416,17 @@ bool CPathfinder::isMovementAfterDestPossible() const
|
|||||||
case CGPathNode::VISIT:
|
case CGPathNode::VISIT:
|
||||||
/// For now we only add visitable tile into queue when it's teleporter that allow transit
|
/// For now we only add visitable tile into queue when it's teleporter that allow transit
|
||||||
/// Movement from visitable tile when hero is standing on it is possible into any layer
|
/// Movement from visitable tile when hero is standing on it is possible into any layer
|
||||||
if(CGTeleport::isTeleport(dt->topVisitableObj()))
|
if(CGTeleport::isTeleport(dObj))
|
||||||
{
|
{
|
||||||
/// For now we'll always allow transit over teleporters
|
/// For now we'll always allow transit over teleporters
|
||||||
/// Transit over whirlpools only allowed when hero protected
|
/// Transit over whirlpools only allowed when hero protected
|
||||||
auto whirlpool = dynamic_cast<const CGWhirlpool *>(dt->topVisitableObj());
|
auto whirlpool = dynamic_cast<const CGWhirlpool *>(dObj);
|
||||||
if(!whirlpool || options.useTeleportWhirlpool)
|
if(!whirlpool || options.useTeleportWhirlpool)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
return false;
|
break;
|
||||||
|
|
||||||
case CGPathNode::NORMAL:
|
case CGPathNode::NORMAL:
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
@@ -418,14 +434,20 @@ bool CPathfinder::isMovementAfterDestPossible() const
|
|||||||
if(options.useEmbarkAndDisembark)
|
if(options.useEmbarkAndDisembark)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
case CGPathNode::DISEMBARK:
|
case CGPathNode::DISEMBARK:
|
||||||
if(options.useEmbarkAndDisembark && !isDestinationGuarded())
|
if(options.useEmbarkAndDisembark && !isDestinationGuarded())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
case CGPathNode::BATTLE:
|
case CGPathNode::BATTLE:
|
||||||
/// Movement after BATTLE action only possible to guardian tile
|
/// Movement after BATTLE action only possible to guardian tile
|
||||||
if(isDestinationGuarded())
|
if(isDestinationGuardian())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@@ -461,7 +483,7 @@ CGPathNode::ENodeAction CPathfinder::getDestAction() const
|
|||||||
else if(dObj->ID == Obj::TOWN && objRel == PlayerRelations::ENEMIES)
|
else if(dObj->ID == Obj::TOWN && objRel == PlayerRelations::ENEMIES)
|
||||||
{
|
{
|
||||||
const CGTownInstance * townObj = dynamic_cast<const CGTownInstance *>(dObj);
|
const CGTownInstance * townObj = dynamic_cast<const CGTownInstance *>(dObj);
|
||||||
if (townObj->armedGarrison())
|
if(townObj->armedGarrison())
|
||||||
action = CGPathNode::BATTLE;
|
action = CGPathNode::BATTLE;
|
||||||
}
|
}
|
||||||
else if(dObj->ID == Obj::GARRISON || dObj->ID == Obj::GARRISON2)
|
else if(dObj->ID == Obj::GARRISON || dObj->ID == Obj::GARRISON2)
|
||||||
@@ -509,9 +531,9 @@ bool CPathfinder::isSourceGuarded() const
|
|||||||
if(getSourceGuardPosition() != int3(-1, -1, -1) && !isSourceInitialPosition())
|
if(getSourceGuardPosition() != int3(-1, -1, -1) && !isSourceInitialPosition())
|
||||||
{
|
{
|
||||||
//special case -> hero embarked a boat standing on a guarded tile -> we must allow to move away from that tile
|
//special case -> hero embarked a boat standing on a guarded tile -> we must allow to move away from that tile
|
||||||
if(cp->accessible != CGPathNode::VISITABLE
|
if(cp->accessible != CGPathNode::VISITABLE ||
|
||||||
|| cp->theNodeBefore->layer == ELayer::LAND
|
cp->theNodeBefore->layer == ELayer::LAND ||
|
||||||
|| ct->topVisitableId() != Obj::BOAT)
|
cObj->ID != Obj::BOAT)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -538,7 +560,7 @@ bool CPathfinder::isDestinationGuardian() const
|
|||||||
|
|
||||||
void CPathfinder::initializeGraph()
|
void CPathfinder::initializeGraph()
|
||||||
{
|
{
|
||||||
auto updateNode = [&](int3 pos, ELayer layer, const TerrainTile *tinfo, bool blockNotAccessible)
|
auto updateNode = [&](int3 pos, ELayer layer, const TerrainTile * tinfo, bool blockNotAccessible)
|
||||||
{
|
{
|
||||||
auto node = out.getNode(pos, layer);
|
auto node = out.getNode(pos, layer);
|
||||||
node->reset();
|
node->reset();
|
||||||
@@ -558,7 +580,7 @@ void CPathfinder::initializeGraph()
|
|||||||
{
|
{
|
||||||
for(pos.z=0; pos.z < out.sizes.z; ++pos.z)
|
for(pos.z=0; pos.z < out.sizes.z; ++pos.z)
|
||||||
{
|
{
|
||||||
const TerrainTile *tinfo = &gs->map->getTile(pos);
|
const TerrainTile * tinfo = &gs->map->getTile(pos);
|
||||||
switch(tinfo->terType)
|
switch(tinfo->terType)
|
||||||
{
|
{
|
||||||
case ETerrainType::ROCK:
|
case ETerrainType::ROCK:
|
||||||
@@ -581,7 +603,7 @@ void CPathfinder::initializeGraph()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CGPathNode::EAccessibility CPathfinder::evaluateAccessibility(const int3 &pos, const TerrainTile *tinfo) const
|
CGPathNode::EAccessibility CPathfinder::evaluateAccessibility(const int3 & pos, const TerrainTile * tinfo) const
|
||||||
{
|
{
|
||||||
CGPathNode::EAccessibility ret = (tinfo->blocked ? CGPathNode::BLOCKED : CGPathNode::ACCESSIBLE);
|
CGPathNode::EAccessibility ret = (tinfo->blocked ? CGPathNode::BLOCKED : CGPathNode::ACCESSIBLE);
|
||||||
|
|
||||||
@@ -596,7 +618,7 @@ CGPathNode::EAccessibility CPathfinder::evaluateAccessibility(const int3 &pos, c
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for(const CGObjectInstance *obj : tinfo->visitableObjects)
|
for(const CGObjectInstance * obj : tinfo->visitableObjects)
|
||||||
{
|
{
|
||||||
if(obj->passableFor(hero->tempOwner))
|
if(obj->passableFor(hero->tempOwner))
|
||||||
{
|
{
|
||||||
@@ -608,7 +630,7 @@ CGPathNode::EAccessibility CPathfinder::evaluateAccessibility(const int3 &pos, c
|
|||||||
}
|
}
|
||||||
else if(obj->ID != Obj::EVENT) //pathfinder should ignore placed events
|
else if(obj->ID != Obj::EVENT) //pathfinder should ignore placed events
|
||||||
{
|
{
|
||||||
ret = CGPathNode::VISITABLE;
|
ret = CGPathNode::VISITABLE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -623,7 +645,7 @@ CGPathNode::EAccessibility CPathfinder::evaluateAccessibility(const int3 &pos, c
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CPathfinder::canMoveBetween(const int3 &a, const int3 &b) const
|
bool CPathfinder::canMoveBetween(const int3 & a, const int3 & b) const
|
||||||
{
|
{
|
||||||
return gs->checkForVisitableDir(a, b);
|
return gs->checkForVisitableDir(a, b);
|
||||||
}
|
}
|
||||||
@@ -673,7 +695,7 @@ CPathfinderHelper::CPathfinderHelper(const CGHeroInstance * Hero)
|
|||||||
updateTurnInfo();
|
updateTurnInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPathfinderHelper::updateTurnInfo(const int &turn)
|
void CPathfinderHelper::updateTurnInfo(const int turn)
|
||||||
{
|
{
|
||||||
if(!ti || ti->turn != turn)
|
if(!ti || ti->turn != turn)
|
||||||
{
|
{
|
||||||
@@ -687,12 +709,12 @@ void CPathfinderHelper::updateTurnInfo(const int &turn)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int CPathfinderHelper::getMaxMovePoints(const EPathfindingLayer &layer) const
|
int CPathfinderHelper::getMaxMovePoints(const EPathfindingLayer layer) const
|
||||||
{
|
{
|
||||||
return layer == EPathfindingLayer::SAIL ? ti->maxMovePointsWater : ti->maxMovePointsLand;
|
return layer == EPathfindingLayer::SAIL ? ti->maxMovePointsWater : ti->maxMovePointsLand;
|
||||||
}
|
}
|
||||||
|
|
||||||
TurnInfo * CPathfinderHelper::getTurnInfo(const CGHeroInstance * h, const int &turn)
|
TurnInfo * CPathfinderHelper::getTurnInfo(const CGHeroInstance * h, const int turn)
|
||||||
{
|
{
|
||||||
auto turnInfo = new TurnInfo;
|
auto turnInfo = new TurnInfo;
|
||||||
turnInfo->turn = turn;
|
turnInfo->turn = turn;
|
||||||
@@ -703,19 +725,19 @@ TurnInfo * CPathfinderHelper::getTurnInfo(const CGHeroInstance * h, const int &t
|
|||||||
return turnInfo;
|
return turnInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPathfinderHelper::getNeighbours(CGameState * gs, const TerrainTile &srct, const int3 &tile, std::vector<int3> &vec, const boost::logic::tribool &onLand, const bool &limitCoastSailing)
|
void CPathfinderHelper::getNeighbours(CGameState * gs, const TerrainTile & srct, const int3 & tile, std::vector<int3> & vec, const boost::logic::tribool & onLand, const bool limitCoastSailing)
|
||||||
{
|
{
|
||||||
static const int3 dirs[] = { int3(0,1,0),int3(0,-1,0),int3(-1,0,0),int3(+1,0,0),
|
static const int3 dirs[] = { int3(0,1,0),int3(0,-1,0),int3(-1,0,0),int3(+1,0,0),
|
||||||
int3(1,1,0),int3(-1,1,0),int3(1,-1,0),int3(-1,-1,0) };
|
int3(1,1,0),int3(-1,1,0),int3(1,-1,0),int3(-1,-1,0) };
|
||||||
|
|
||||||
//vec.reserve(8); //optimization
|
//vec.reserve(8); //optimization
|
||||||
for (auto & dir : dirs)
|
for(auto & dir : dirs)
|
||||||
{
|
{
|
||||||
const int3 hlp = tile + dir;
|
const int3 hlp = tile + dir;
|
||||||
if(!gs->isInTheMap(hlp))
|
if(!gs->isInTheMap(hlp))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
const TerrainTile &hlpt = gs->map->getTile(hlp);
|
const TerrainTile & hlpt = gs->map->getTile(hlp);
|
||||||
|
|
||||||
// //we cannot visit things from blocked tiles
|
// //we cannot visit things from blocked tiles
|
||||||
// if(srct.blocked && !srct.visitable && hlpt.visitable && srct.blockingObjects.front()->ID != HEROI_TYPE)
|
// if(srct.blocked && !srct.visitable && hlpt.visitable && srct.blockingObjects.front()->ID != HEROI_TYPE)
|
||||||
@@ -734,7 +756,7 @@ void CPathfinderHelper::getNeighbours(CGameState * gs, const TerrainTile &srct,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if((indeterminate(onLand) || onLand == (hlpt.terType!=ETerrainType::WATER) )
|
if((indeterminate(onLand) || onLand == (hlpt.terType!=ETerrainType::WATER) )
|
||||||
&& hlpt.terType != ETerrainType::ROCK)
|
&& hlpt.terType != ETerrainType::ROCK)
|
||||||
{
|
{
|
||||||
vec.push_back(hlp);
|
vec.push_back(hlp);
|
||||||
@@ -742,7 +764,7 @@ void CPathfinderHelper::getNeighbours(CGameState * gs, const TerrainTile &srct,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int CPathfinderHelper::getMovementCost(const CGHeroInstance * h, const int3 &src, const int3 &dst, const int &remainingMovePoints, const TurnInfo * ti, const bool &checkLast)
|
int CPathfinderHelper::getMovementCost(const CGHeroInstance * h, const int3 & src, const int3 & dst, const int remainingMovePoints, const TurnInfo * ti, const bool checkLast)
|
||||||
{
|
{
|
||||||
if(src == dst) //same tile
|
if(src == dst) //same tile
|
||||||
return 0;
|
return 0;
|
||||||
@@ -793,7 +815,7 @@ int CPathfinderHelper::getMovementCost(const CGHeroInstance * h, const int3 &src
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int CPathfinderHelper::getMovementCost(const CGHeroInstance * h, const int3 &dst)
|
int CPathfinderHelper::getMovementCost(const CGHeroInstance * h, const int3 & dst)
|
||||||
{
|
{
|
||||||
return getMovementCost(h, h->visitablePos(), dst, h->movement);
|
return getMovementCost(h, h->visitablePos(), dst, h->movement);
|
||||||
}
|
}
|
||||||
@@ -840,7 +862,7 @@ void CGPath::convert(ui8 mode)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CPathsInfo::CPathsInfo(const int3 &Sizes)
|
CPathsInfo::CPathsInfo(const int3 & Sizes)
|
||||||
: sizes(Sizes)
|
: sizes(Sizes)
|
||||||
{
|
{
|
||||||
hero = nullptr;
|
hero = nullptr;
|
||||||
@@ -856,7 +878,7 @@ CPathsInfo::~CPathsInfo()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
const CGPathNode * CPathsInfo::getPathInfo(const int3 &tile, const ELayer &layer) const
|
const CGPathNode * CPathsInfo::getPathInfo(const int3 & tile, const ELayer layer) const
|
||||||
{
|
{
|
||||||
boost::unique_lock<boost::mutex> pathLock(pathMx);
|
boost::unique_lock<boost::mutex> pathLock(pathMx);
|
||||||
|
|
||||||
@@ -865,25 +887,25 @@ const CGPathNode * CPathsInfo::getPathInfo(const int3 &tile, const ELayer &layer
|
|||||||
return getNode(tile, layer);
|
return getNode(tile, layer);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CPathsInfo::getPath(CGPath &out, const int3 &dst, const ELayer &layer) const
|
bool CPathsInfo::getPath(CGPath & out, const int3 & dst, const ELayer layer) const
|
||||||
{
|
{
|
||||||
boost::unique_lock<boost::mutex> pathLock(pathMx);
|
boost::unique_lock<boost::mutex> pathLock(pathMx);
|
||||||
|
|
||||||
out.nodes.clear();
|
out.nodes.clear();
|
||||||
const CGPathNode *curnode = getNode(dst, layer);
|
const CGPathNode * curnode = getNode(dst, layer);
|
||||||
if(!curnode->theNodeBefore)
|
if(!curnode->theNodeBefore)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
while(curnode)
|
while(curnode)
|
||||||
{
|
{
|
||||||
CGPathNode cpn = *curnode;
|
CGPathNode cpn = * curnode;
|
||||||
curnode = curnode->theNodeBefore;
|
curnode = curnode->theNodeBefore;
|
||||||
out.nodes.push_back(cpn);
|
out.nodes.push_back(cpn);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int CPathsInfo::getDistance(const int3 &tile, const ELayer &layer) const
|
int CPathsInfo::getDistance(const int3 & tile, const ELayer layer) const
|
||||||
{
|
{
|
||||||
boost::unique_lock<boost::mutex> pathLock(pathMx);
|
boost::unique_lock<boost::mutex> pathLock(pathMx);
|
||||||
|
|
||||||
@@ -894,7 +916,7 @@ int CPathsInfo::getDistance(const int3 &tile, const ELayer &layer) const
|
|||||||
return 255;
|
return 255;
|
||||||
}
|
}
|
||||||
|
|
||||||
CGPathNode *CPathsInfo::getNode(const int3 &coord, const ELayer &layer) const
|
CGPathNode * CPathsInfo::getNode(const int3 & coord, const ELayer layer) const
|
||||||
{
|
{
|
||||||
if(layer != ELayer::AUTO)
|
if(layer != ELayer::AUTO)
|
||||||
return nodes[coord.x][coord.y][coord.z][layer];
|
return nodes[coord.x][coord.y][coord.z][layer];
|
||||||
|
@@ -75,23 +75,23 @@ struct DLL_LINKAGE CPathsInfo
|
|||||||
|
|
||||||
mutable boost::mutex pathMx;
|
mutable boost::mutex pathMx;
|
||||||
|
|
||||||
const CGHeroInstance *hero;
|
const CGHeroInstance * hero;
|
||||||
int3 hpos;
|
int3 hpos;
|
||||||
int3 sizes;
|
int3 sizes;
|
||||||
boost::multi_array<CGPathNode *, 4> nodes; //[w][h][level][layer]
|
boost::multi_array<CGPathNode *, 4> nodes; //[w][h][level][layer]
|
||||||
|
|
||||||
CPathsInfo(const int3 &Sizes);
|
CPathsInfo(const int3 & Sizes);
|
||||||
~CPathsInfo();
|
~CPathsInfo();
|
||||||
const CGPathNode * getPathInfo(const int3 &tile, const ELayer &layer = ELayer::AUTO) const;
|
const CGPathNode * getPathInfo(const int3 & tile, const ELayer layer = ELayer::AUTO) const;
|
||||||
bool getPath(CGPath &out, const int3 &dst, const ELayer &layer = ELayer::AUTO) const;
|
bool getPath(CGPath & out, const int3 & dst, const ELayer layer = ELayer::AUTO) const;
|
||||||
int getDistance(const int3 &tile, const ELayer &layer = ELayer::AUTO) const;
|
int getDistance(const int3 & tile, const ELayer layer = ELayer::AUTO) const;
|
||||||
CGPathNode *getNode(const int3 &coord, const ELayer &layer) const;
|
CGPathNode * getNode(const int3 & coord, const ELayer layer) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CPathfinder : private CGameInfoCallback
|
class CPathfinder : private CGameInfoCallback
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CPathfinder(CPathsInfo &_out, CGameState *_gs, const CGHeroInstance *_hero);
|
CPathfinder(CPathsInfo & _out, CGameState * _gs, const CGHeroInstance * _hero);
|
||||||
void calculatePaths(); //calculates possible paths for hero, uses current hero position and movement left; returns pointer to newly allocated CPath or nullptr if path does not exists
|
void calculatePaths(); //calculates possible paths for hero, uses current hero position and movement left; returns pointer to newly allocated CPath or nullptr if path does not exists
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -134,8 +134,8 @@ private:
|
|||||||
PathfinderOptions();
|
PathfinderOptions();
|
||||||
} options;
|
} options;
|
||||||
|
|
||||||
CPathsInfo &out;
|
CPathsInfo & out;
|
||||||
const CGHeroInstance *hero;
|
const CGHeroInstance * hero;
|
||||||
unique_ptr<CPathfinderHelper> hlp;
|
unique_ptr<CPathfinderHelper> hlp;
|
||||||
|
|
||||||
struct NodeComparer
|
struct NodeComparer
|
||||||
@@ -154,16 +154,16 @@ private:
|
|||||||
|
|
||||||
std::vector<int3> neighbours;
|
std::vector<int3> neighbours;
|
||||||
|
|
||||||
CGPathNode *cp; //current (source) path node -> we took it from the queue
|
CGPathNode * cp; //current (source) path node -> we took it from the queue
|
||||||
CGPathNode *dp; //destination node -> it's a neighbour of cp that we consider
|
CGPathNode * dp; //destination node -> it's a neighbour of cp that we consider
|
||||||
const TerrainTile *ct, *dt; //tile info for both nodes
|
const TerrainTile * ct, * dt; //tile info for both nodes
|
||||||
const CGObjectInstance * cObj, * dObj;
|
const CGObjectInstance * cObj, * dObj;
|
||||||
CGPathNode::ENodeAction destAction;
|
CGPathNode::ENodeAction destAction;
|
||||||
|
|
||||||
void addNeighbours(const int3 &coord);
|
void addNeighbours(const int3 & coord);
|
||||||
void addTeleportExits(bool noTeleportExcludes = false);
|
void addTeleportExits(bool noTeleportExcludes = false);
|
||||||
|
|
||||||
bool isLayerAvailable(const ELayer &layer, const int &turn) const;
|
bool isLayerAvailable(const ELayer layer, const int turn) const;
|
||||||
bool isLayerTransitionPossible() const;
|
bool isLayerTransitionPossible() const;
|
||||||
bool isMovementToDestPossible() const;
|
bool isMovementToDestPossible() const;
|
||||||
bool isMovementAfterDestPossible() const;
|
bool isMovementAfterDestPossible() const;
|
||||||
@@ -177,8 +177,8 @@ private:
|
|||||||
|
|
||||||
void initializeGraph();
|
void initializeGraph();
|
||||||
|
|
||||||
CGPathNode::EAccessibility evaluateAccessibility(const int3 &pos, const TerrainTile *tinfo) const;
|
CGPathNode::EAccessibility evaluateAccessibility(const int3 & pos, const TerrainTile * tinfo) 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 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 addTeleportTwoWay(const CGTeleport * obj) const;
|
bool addTeleportTwoWay(const CGTeleport * obj) const;
|
||||||
bool addTeleportOneWay(const CGTeleport * obj) const;
|
bool addTeleportOneWay(const CGTeleport * obj) const;
|
||||||
@@ -205,14 +205,14 @@ public:
|
|||||||
const CGHeroInstance * hero;
|
const CGHeroInstance * hero;
|
||||||
|
|
||||||
CPathfinderHelper(const CGHeroInstance * Hero);
|
CPathfinderHelper(const CGHeroInstance * Hero);
|
||||||
void updateTurnInfo(const int &turn = 0);
|
void updateTurnInfo(const int turn = 0);
|
||||||
int getMaxMovePoints(const EPathfindingLayer &layer) const;
|
int getMaxMovePoints(const EPathfindingLayer layer) const;
|
||||||
static TurnInfo * getTurnInfo(const CGHeroInstance * h, const int &turn = 0);
|
static TurnInfo * getTurnInfo(const CGHeroInstance * h, const int turn = 0);
|
||||||
|
|
||||||
static void getNeighbours(CGameState * gs, const TerrainTile &srct, const int3 &tile, std::vector<int3> &vec, const boost::logic::tribool &onLand, const bool &limitCoastSailing);
|
static void getNeighbours(CGameState * gs, const TerrainTile & srct, const int3 & tile, std::vector<int3> & vec, const boost::logic::tribool & onLand, const bool limitCoastSailing);
|
||||||
|
|
||||||
static int getMovementCost(const CGHeroInstance * h, const int3 &src, const int3 &dst, const int &remainingMovePoints =- 1, const TurnInfo * ti = nullptr, const bool &checkLast = true);
|
static int getMovementCost(const CGHeroInstance * h, const int3 & src, const int3 & dst, const int remainingMovePoints =- 1, const TurnInfo * ti = nullptr, const bool checkLast = true);
|
||||||
static int getMovementCost(const CGHeroInstance * h, const int3 &dst);
|
static int getMovementCost(const CGHeroInstance * h, const int3 & dst);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<TurnInfo *> turnsInfo;
|
std::vector<TurnInfo *> turnsInfo;
|
||||||
|
Reference in New Issue
Block a user