2007-08-08 22:28:56 +03:00
# include "stdafx.h"
2007-08-07 16:49:15 +03:00
# include "global.h"
# include "CPathfinder.h"
2007-08-17 20:42:21 +03:00
# include "CGameInfo.h"
2008-07-01 11:01:02 +03:00
# include "hch/CAmbarCendamo.h"
2007-08-29 15:18:31 +03:00
# include "mapHandler.h"
2008-02-23 21:20:41 +02:00
# include "CGameState.h"
2008-07-02 11:39:56 +03:00
# include "hch/CObjectHandler.h"
2008-09-18 17:18:08 +03:00
# include "hch/CDefObjInfoHandler.h"
2008-06-01 17:55:31 +03:00
2008-11-15 15:44:32 +02:00
using namespace boost : : logic ;
2008-06-01 17:55:31 +03:00
2008-11-15 15:44:32 +02:00
int3 CPath : : startPos ( )
2007-10-03 22:56:08 +03:00
{
2008-11-15 15:44:32 +02:00
return int3 ( nodes [ nodes . size ( ) - 1 ] . coord . x , nodes [ nodes . size ( ) - 1 ] . coord . y , nodes [ nodes . size ( ) - 1 ] . coord . z ) ;
}
int3 CPath : : endPos ( )
{
return int3 ( nodes [ 0 ] . coord . x , nodes [ 0 ] . coord . y , nodes [ 0 ] . coord . z ) ;
2007-10-03 22:56:08 +03:00
}
2007-09-22 04:16:31 +03:00
2008-11-15 15:44:32 +02:00
CPath * CPathfinder : : getPath ( int3 src , int3 dest , const CGHeroInstance * hero , unsigned char type ) //TODO: test it (seems to be finished, but relies on unwritten functions :()
2007-08-07 16:49:15 +03:00
{
2007-10-05 21:16:22 +03:00
//check input
2008-11-15 15:44:32 +02:00
if ( ( src . x < 0 ) | | ( src . y < 0 ) | | ( src . z < 0 ) | | ( dest . x < 0 ) | | ( dest . y < 0 ) | | ( dest . z < 0 ) )
2007-10-05 21:16:22 +03:00
{
return NULL ;
}
2008-11-15 15:44:32 +02:00
if ( ( src . x > = CGI - > mh - > sizes . x ) | | ( src . y > = CGI - > mh - > sizes . y ) | | ( src . z > = CGI - > mh - > sizes . z )
| | ( dest . x > = CGI - > mh - > sizes . x ) | | ( dest . y > = CGI - > mh - > sizes . y ) | | ( dest . z > = CGI - > mh - > sizes . z ) )
2007-10-05 21:16:22 +03:00
{
2007-08-07 16:49:15 +03:00
return NULL ;
2007-10-05 21:16:22 +03:00
}
2008-11-15 15:44:32 +02:00
int3 hpos = hero - > getPosition ( false ) ;
2007-10-05 21:16:22 +03:00
2008-11-15 15:44:32 +02:00
tribool blockLandSea ; //true - blocks sea, false - blocks land, indeterminate - allows all
if ( ! hero - > canWalkOnSea ( ) )
2007-10-05 21:16:22 +03:00
{
2008-11-19 09:55:17 +02:00
if ( CGI - > mh - > ttiles [ hpos . x ] [ hpos . y ] [ hpos . z ] . tileInfo - > tertype = = water )
2007-10-05 21:16:22 +03:00
blockLandSea = false ;
else
blockLandSea = true ;
}
else
2007-10-03 22:56:08 +03:00
{
2008-11-15 15:44:32 +02:00
blockLandSea = indeterminate ;
2008-06-01 17:55:31 +03:00
}
2008-11-15 15:44:32 +02:00
//graph initialization
graph . resize ( CGI - > mh - > sizes . x ) ;
2008-12-21 21:17:35 +02:00
for ( size_t i = 0 ; i < graph . size ( ) ; + + i )
2007-08-07 16:49:15 +03:00
{
2008-11-15 15:44:32 +02:00
graph [ i ] . resize ( CGI - > mh - > sizes . y ) ;
2008-12-21 21:17:35 +02:00
for ( size_t j = 0 ; j < graph [ i ] . size ( ) ; + + j )
2007-08-07 16:49:15 +03:00
{
2008-11-15 15:44:32 +02:00
graph [ i ] [ j ] . accesible = ! CGI - > mh - > ttiles [ i ] [ j ] [ src . z ] . tileInfo - > blocked ;
2008-12-23 15:59:03 +02:00
if ( i = = dest . x & & j = = dest . y & & CGI - > mh - > ttiles [ i ] [ j ] [ src . z ] . tileInfo - > visitable )
{
2008-11-15 15:44:32 +02:00
graph [ i ] [ j ] . accesible = true ; //for allowing visiting objects
2008-12-23 15:59:03 +02:00
}
2008-11-15 15:44:32 +02:00
graph [ i ] [ j ] . dist = - 1 ;
graph [ i ] [ j ] . theNodeBefore = NULL ;
graph [ i ] [ j ] . visited = false ;
graph [ i ] [ j ] . coord . x = i ;
graph [ i ] [ j ] . coord . y = j ;
graph [ i ] [ j ] . coord . z = dest . z ;
2008-12-23 15:59:03 +02:00
if ( CGI - > mh - > ttiles [ i ] [ j ] [ src . z ] . tileInfo - > tertype = = rock )
{
2008-11-15 15:44:32 +02:00
graph [ i ] [ j ] . accesible = false ;
2008-12-23 15:59:03 +02:00
}
if ( ( blockLandSea ) & & ( CGI - > mh - > ttiles [ i ] [ j ] [ src . z ] . tileInfo - > tertype = = water ) )
{
2008-11-15 15:44:32 +02:00
graph [ i ] [ j ] . accesible = false ;
2008-12-23 15:59:03 +02:00
}
else if ( ( ! blockLandSea ) & & ( CGI - > mh - > ttiles [ i ] [ j ] [ src . z ] . tileInfo - > tertype ! = water ) )
{
2008-11-15 15:44:32 +02:00
graph [ i ] [ j ] . accesible = false ;
2008-12-23 15:59:03 +02:00
}
if ( graph [ i ] [ j ] . accesible )
{
2008-11-15 15:44:32 +02:00
graph [ i ] [ j ] . accesible = CGI - > state - > players [ hero - > tempOwner ] . fogOfWarMap [ i ] [ j ] [ src . z ] ;
2008-12-23 15:59:03 +02:00
}
2007-08-07 16:49:15 +03:00
}
}
2008-11-15 15:44:32 +02:00
//graph initialized
2007-08-12 20:48:05 +03:00
2008-11-15 15:44:32 +02:00
graph [ src . x ] [ src . y ] . dist = 0 ;
2007-08-17 20:42:21 +03:00
2008-11-15 15:44:32 +02:00
std : : queue < CPathNode > mq ;
mq . push ( graph [ src . x ] [ src . y ] ) ;
2007-08-17 20:42:21 +03:00
2008-12-21 21:17:35 +02:00
unsigned int curDist = 4000000000 ; //XXX 2 147 483 648 // only in C90 //but numeric limit shows 0-4294967295...confused
2008-06-01 17:55:31 +03:00
2008-11-15 15:44:32 +02:00
while ( ! mq . empty ( ) )
{
CPathNode cp = mq . front ( ) ;
mq . pop ( ) ;
if ( ( cp . coord . x = = dest . x ) & & ( cp . coord . y = = dest . y ) )
2007-08-07 16:49:15 +03:00
{
2008-11-15 15:44:32 +02:00
if ( cp . dist < curDist )
curDist = cp . dist ;
2007-08-12 20:48:05 +03:00
}
2008-11-15 15:44:32 +02:00
else
2007-08-12 20:48:05 +03:00
{
2008-11-15 15:44:32 +02:00
if ( cp . dist > curDist )
continue ;
2007-08-12 20:48:05 +03:00
}
2008-11-15 15:44:32 +02:00
if ( cp . coord . x > 0 )
2007-08-12 20:48:05 +03:00
{
2008-11-15 15:44:32 +02:00
CPathNode & dp = graph [ cp . coord . x - 1 ] [ cp . coord . y ] ;
processNode ( dp , hero , mq , cp , src , false ) ;
2007-08-12 20:48:05 +03:00
}
2008-11-15 15:44:32 +02:00
if ( cp . coord . y > 0 )
2007-08-12 20:48:05 +03:00
{
2008-11-15 15:44:32 +02:00
CPathNode & dp = graph [ cp . coord . x ] [ cp . coord . y - 1 ] ;
processNode ( dp , hero , mq , cp , src , false ) ;
2007-08-07 16:49:15 +03:00
}
2008-11-15 15:44:32 +02:00
if ( cp . coord . x > 0 & & cp . coord . y > 0 )
2008-06-03 17:44:09 +03:00
{
2008-11-15 15:44:32 +02:00
CPathNode & dp = graph [ cp . coord . x - 1 ] [ cp . coord . y - 1 ] ;
processNode ( dp , hero , mq , cp , src , true ) ;
2008-06-03 17:44:09 +03:00
}
2008-11-15 15:44:32 +02:00
if ( cp . coord . x < graph . size ( ) - 1 )
{
CPathNode & dp = graph [ cp . coord . x + 1 ] [ cp . coord . y ] ;
processNode ( dp , hero , mq , cp , src , false ) ;
}
if ( cp . coord . y < graph [ 0 ] . size ( ) - 1 )
{
CPathNode & dp = graph [ cp . coord . x ] [ cp . coord . y + 1 ] ;
processNode ( dp , hero , mq , cp , src , false ) ;
}
if ( cp . coord . x < graph . size ( ) - 1 & & cp . coord . y < graph [ 0 ] . size ( ) - 1 )
{
CPathNode & dp = graph [ cp . coord . x + 1 ] [ cp . coord . y + 1 ] ;
processNode ( dp , hero , mq , cp , src , true ) ;
}
if ( cp . coord . x > 0 & & cp . coord . y < graph [ 0 ] . size ( ) - 1 )
{
CPathNode & dp = graph [ cp . coord . x - 1 ] [ cp . coord . y + 1 ] ;
processNode ( dp , hero , mq , cp , src , true ) ;
}
if ( cp . coord . x < graph . size ( ) - 1 & & cp . coord . y > 0 )
{
CPathNode & dp = graph [ cp . coord . x + 1 ] [ cp . coord . y - 1 ] ;
processNode ( dp , hero , mq , cp , src , true ) ;
}
}
2007-08-07 16:49:15 +03:00
2008-11-15 15:44:32 +02:00
CPathNode curNode = graph [ dest . x ] [ dest . y ] ;
if ( ! curNode . theNodeBefore )
return NULL ;
2008-06-01 17:55:31 +03:00
2008-11-15 15:44:32 +02:00
CPath * ret = new CPath ;
2007-08-12 20:48:05 +03:00
2008-11-15 15:44:32 +02:00
while ( curNode . coord ! = graph [ src . x ] [ src . y ] . coord )
2008-06-01 17:55:31 +03:00
{
2008-11-15 15:44:32 +02:00
ret - > nodes . push_back ( curNode ) ;
curNode = * ( curNode . theNodeBefore ) ;
2008-06-01 17:55:31 +03:00
}
2007-08-17 20:42:21 +03:00
2008-11-15 15:44:32 +02:00
ret - > nodes . push_back ( graph [ src . x ] [ src . y ] ) ;
return ret ;
2007-08-07 16:49:15 +03:00
}
2007-10-05 21:16:22 +03:00
void CPathfinder : : convertPath ( CPath * path , unsigned int mode ) //mode=0 -> from 'manifest' to 'object'
{
if ( mode = = 0 )
{
for ( int i = 0 ; i < path - > nodes . size ( ) ; i + + )
{
2007-10-27 23:14:25 +03:00
path - > nodes [ i ] . coord = CGHeroInstance : : convertPosition ( path - > nodes [ i ] . coord , true ) ;
2007-10-05 21:16:22 +03:00
}
}
2008-06-01 17:55:31 +03:00
}
2008-11-15 15:44:32 +02:00
void CPathfinder : : processNode ( CPathNode & dp , const CGHeroInstance * hero , std : : queue < CPathNode > & mq , const CPathNode & cp , const int3 & src , bool diagonal )
2008-06-01 17:55:31 +03:00
{
2008-11-15 15:44:32 +02:00
const TerrainTile * tinfo = CGI - > mh - > ttiles [ dp . coord . x ] [ dp . coord . y ] [ src . z ] . tileInfo ;
2009-02-06 17:56:03 +02:00
int cost = hero - > getTileCost ( tinfo - > tertype , tinfo - > malle , tinfo - > nuine , hero - > movement - cp . dist ) ;
if ( diagonal & & ( hero - > movement - cp . dist ) > 145 ) //second condition - workaround for strange behaviour manifested by Heroes III
2008-11-15 15:44:32 +02:00
cost * = std : : sqrt ( 2.0 ) ;
if ( ( dp . dist = = - 1 | | ( dp . dist > cp . dist + cost ) ) & & dp . accesible & & checkForVisitableDir ( cp . coord , dp . coord ) & & checkForVisitableDir ( dp . coord , cp . coord ) )
2008-06-01 17:55:31 +03:00
{
2008-11-15 15:44:32 +02:00
dp . dist = cp . dist + cost ;
dp . theNodeBefore = & graph [ cp . coord . x ] [ cp . coord . y ] ;
mq . push ( dp ) ;
2008-06-01 17:55:31 +03:00
}
}
2008-11-15 15:44:32 +02:00
bool CPathfinder : : checkForVisitableDir ( const int3 & src , const int3 & dst ) const
2008-06-01 17:55:31 +03:00
{
2008-11-15 15:44:32 +02:00
for ( int b = 0 ; b < CGI - > mh - > ttiles [ dst . x ] [ dst . y ] [ dst . z ] . tileInfo - > visitableObjects . size ( ) ; + + b ) //checking destination tile
{
const TerrainTile * pom = CGI - > mh - > ttiles [ dst . x ] [ dst . y ] [ dst . z ] . tileInfo ;
if ( ! vstd : : contains ( pom - > blockingObjects , pom - > visitableObjects [ b ] ) )
continue ;
CGDefInfo * di = pom - > visitableObjects [ b ] - > defInfo ;
if ( ( dst . x = = src . x - 1 & & dst . y = = src . y - 1 ) & & ! ( di - > visitDir & ( 1 < < 4 ) ) )
{
return false ;
}
if ( ( dst . x = = src . x & & dst . y = = src . y - 1 ) & & ! ( di - > visitDir & ( 1 < < 5 ) ) )
{
return false ;
}
if ( ( dst . x = = src . x + 1 & & dst . y = = src . y - 1 ) & & ! ( di - > visitDir & ( 1 < < 6 ) ) )
{
return false ;
}
if ( ( dst . x = = src . x + 1 & & dst . y = = src . y ) & & ! ( di - > visitDir & ( 1 < < 7 ) ) )
{
return false ;
}
if ( ( dst . x = = src . x + 1 & & dst . y = = src . y + 1 ) & & ! ( di - > visitDir & ( 1 < < 0 ) ) )
{
return false ;
}
if ( ( dst . x = = src . x & & dst . y = = src . y + 1 ) & & ! ( di - > visitDir & ( 1 < < 1 ) ) )
{
return false ;
}
if ( ( dst . x = = src . x - 1 & & dst . y = = src . y + 1 ) & & ! ( di - > visitDir & ( 1 < < 2 ) ) )
{
return false ;
}
if ( ( dst . x = = src . x - 1 & & dst . y = = src . y ) & & ! ( di - > visitDir & ( 1 < < 3 ) ) )
{
return false ;
}
}
return true ;
2008-08-02 18:08:03 +03:00
}