1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-04-15 11:46:56 +02:00

CPathfinder: draft implementation of layers logic; not yet works

This commit is contained in:
ArseniyShestakov 2015-11-02 16:03:03 +03:00
parent 9c1c7d0caf
commit 400152caee
2 changed files with 110 additions and 68 deletions

View File

@ -100,13 +100,16 @@ void CPathfinder::calculatePaths()
addNeighbours(cp->coord); addNeighbours(cp->coord);
for(auto & neighbour : neighbours) for(auto & neighbour : neighbours)
{ {
dp = out.getNode(neighbour, EPathfindingLayer::LAND);
dt = &gs->map->getTile(neighbour); dt = &gs->map->getTile(neighbour);
for(EPathfindingLayer i = EPathfindingLayer::LAND; i <= EPathfindingLayer::AIR; i.advance(1))
{
useEmbarkCost = 0; //0 - usual movement; 1 - embark; 2 - disembark useEmbarkCost = 0; //0 - usual movement; 1 - embark; 2 - disembark
dp = out.getNode(neighbour, i);
if(cp->layer != i && isLayerTransitionPossible())
continue;
if(!isMovementPossible()) if(!isMovementPossible())
continue; continue;
int cost = gs->getMovementCost(hero, cp->coord, dp->coord, movement); int cost = gs->getMovementCost(hero, cp->coord, dp->coord, movement);
int remains = movement - cost; int remains = movement - cost;
if(useEmbarkCost) if(useEmbarkCost)
@ -135,6 +138,7 @@ void CPathfinder::calculatePaths()
if(checkDestinationTile()) if(checkDestinationTile())
mq.push_back(dp); mq.push_back(dp);
} }
}
} //neighbours loop } //neighbours loop
//just add all passable teleport exits //just add all passable teleport exits
@ -143,7 +147,7 @@ void CPathfinder::calculatePaths()
addTeleportExits(); addTeleportExits();
for(auto & neighbour : neighbours) for(auto & neighbour : neighbours)
{ {
dp = out.getNode(neighbour, EPathfindingLayer::LAND); dp = out.getNode(neighbour, cp->layer);
if(isBetterWay(movement, turn)) if(isBetterWay(movement, turn))
{ {
dp->moveRemains = movement; dp->moveRemains = movement;
@ -220,39 +224,43 @@ void CPathfinder::addTeleportExits(bool noTeleportExcludes)
bool CPathfinder::isMovementPossible() bool CPathfinder::isMovementPossible()
{ {
switch (dp->layer)
{
case EPathfindingLayer::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;
Obj destTopVisObjID = dt->topVisitableId();
if(cp->land != dp->land) //hero can traverse land<->sea only in special circumstances
{
if(cp->land) //from land to sea -> embark or assault hero on boat
{
if(dp->accessible == CGPathNode::ACCESSIBLE || destTopVisObjID < 0) //cannot enter empty water tile from land -> it has to be visitable
return false;
if(destTopVisObjID != Obj::HERO && destTopVisObjID != Obj::BOAT) //only boat or hero can be accessed from land
return false;
if(destTopVisObjID == Obj::BOAT)
useEmbarkCost = 1;
}
else //disembark
{
//can disembark only on coastal tiles
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;;
useEmbarkCost = 2;
}
}
if(isSourceGuarded() && !isDestinationGuardian()) // Can step into tile of guard if(isSourceGuarded() && !isDestinationGuardian()) // Can step into tile of guard
return false; return false;
break;
case EPathfindingLayer::SAIL:
if(!canMoveBetween(cp->coord, dp->coord) || dp->accessible == CGPathNode::BLOCKED)
return false;
if(isSourceGuarded() && !isDestinationGuardian()) // Can step into tile of guard
return false;
break;
case EPathfindingLayer::AIR:
if(!options.useFlying)
return false;
if(!canMoveBetween(cp->coord, dp->coord))
return false;
break;
case EPathfindingLayer::WATER:
if(!options.useWaterWalking)
return false;
if(!canMoveBetween(cp->coord, dp->coord) || dp->accessible == CGPathNode::BLOCKED)
return false;
if(isDestinationGuarded())
return false;
break;
}
return true; return true;
} }
@ -314,12 +322,9 @@ bool CPathfinder::isDestinationGuardian()
void CPathfinder::initializeGraph() void CPathfinder::initializeGraph()
{ {
int3 pos; auto addNode = [&](EPathfindingLayer layer, const TerrainTile *tinfo, int3 pos)
CGPathNode ****graph = out.nodes;
const TerrainTile *tinfo;
auto addNode = [&](EPathfindingLayer layer)
{ {
CGPathNode &node = graph[pos.x][pos.y][pos.z][layer]; CGPathNode &node = out.nodes[pos.x][pos.y][pos.z][layer];
node.accessible = evaluateAccessibility(pos, tinfo); node.accessible = evaluateAccessibility(pos, tinfo);
node.turns = 0xff; node.turns = 0xff;
node.moveRemains = 0; node.moveRemains = 0;
@ -329,6 +334,7 @@ void CPathfinder::initializeGraph()
node.layer = layer; node.layer = layer;
}; };
int3 pos;
for(pos.x=0; pos.x < out.sizes.x; ++pos.x) for(pos.x=0; pos.x < out.sizes.x; ++pos.x)
{ {
for(pos.y=0; pos.y < out.sizes.y; ++pos.y) for(pos.y=0; pos.y < out.sizes.y; ++pos.y)
@ -343,16 +349,16 @@ void CPathfinder::initializeGraph()
case ETerrainType::ROCK: case ETerrainType::ROCK:
break; break;
case ETerrainType::WATER: case ETerrainType::WATER:
addNode(EPathfindingLayer::SAIL); addNode(EPathfindingLayer::SAIL, tinfo, pos);
if(options.useFlying) // if(options.useFlying)
addNode(EPathfindingLayer::AIR); addNode(EPathfindingLayer::AIR, tinfo, pos);
if(options.useWaterWalking) // if(options.useWaterWalking)
addNode(EPathfindingLayer::WATER); addNode(EPathfindingLayer::WATER, tinfo, pos);
break; break;
default: default:
addNode(EPathfindingLayer::LAND); addNode(EPathfindingLayer::LAND, tinfo, pos);
if(options.useFlying) // if(options.useFlying)
addNode(EPathfindingLayer::AIR); addNode(EPathfindingLayer::AIR, tinfo, pos);
break; break;
} }
} }
@ -446,6 +452,40 @@ bool CPathfinder::canVisitObject() const
return cp->layer == EPathfindingLayer::LAND || cp->layer == EPathfindingLayer::SAIL; return cp->layer == EPathfindingLayer::LAND || cp->layer == EPathfindingLayer::SAIL;
} }
bool CPathfinder::isLayerTransitionPossible()
{
Obj destTopVisObjID = dt->topVisitableId();
if((cp->layer == EPathfindingLayer::AIR || EPathfindingLayer::WATER)
&& dp->layer != EPathfindingLayer::LAND)
{
return false;
}
else if(cp->layer == EPathfindingLayer::SAIL && dp->layer != EPathfindingLayer::LAND)
return false;
else if(cp->layer == EPathfindingLayer::SAIL && dp->layer == EPathfindingLayer::LAND)
{
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;
useEmbarkCost = 2;
}
else if(cp->layer == EPathfindingLayer::LAND && dp->layer == EPathfindingLayer::SAIL)
{
if(dp->accessible == CGPathNode::ACCESSIBLE || destTopVisObjID < 0) //cannot enter empty water tile from land -> it has to be visitable
return false;
if(destTopVisObjID != Obj::HERO && destTopVisObjID != Obj::BOAT) //only boat or hero can be accessed from land
return false;
if(destTopVisObjID == Obj::BOAT)
useEmbarkCost = 1;
}
return true;
}
CGPathNode::CGPathNode() CGPathNode::CGPathNode()
:coord(-1,-1,-1) :coord(-1,-1,-1)
{ {

View File

@ -124,4 +124,6 @@ private:
bool addTeleportWhirlpool(const CGWhirlpool * obj) const; bool addTeleportWhirlpool(const CGWhirlpool * obj) const;
bool canVisitObject() const; bool canVisitObject() const;
bool isLayerTransitionPossible();
}; };