1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-11-28 08:48:48 +02:00

Implemented redesigned pathfinder. Using new info from it, implemented various adventure map cursors.

(Paths are still calculated using the old pathfinder, it will be changed soon)
This commit is contained in:
Michał W. Urbańczyk 2009-08-30 12:47:40 +00:00
parent c1b112d266
commit ca7ee8936c
12 changed files with 482 additions and 235 deletions

View File

@ -829,6 +829,16 @@ const CMapHeader * CCallback::getMapHeader() const
return gs->map;
}
const CGPathNode * CCallback::getPathInfo( int3 tile )
{
return &cl->pathInfo->nodes[tile.x][tile.y][tile.z];
}
bool CCallback::getPath2( int3 dest, CGPath &ret )
{
return cl->pathInfo->getPath(dest, ret);
}
InfoAboutHero::InfoAboutHero()
{
details = NULL;

View File

@ -40,6 +40,8 @@ class CHeroClass;
class IShipyard;
struct CPackForServer;
class CMapHeader;
struct CGPathNode;
struct CGPath;
struct InfoAboutHero
{
@ -135,6 +137,8 @@ public:
virtual std::vector < const CGHeroInstance *> getHeroesInfo(bool onlyOur=true)const =0;
virtual bool getHeroInfo(const CGObjectInstance *hero, InfoAboutHero &dest) const = 0;
virtual bool getPath(int3 src, int3 dest, const CGHeroInstance * hero, CPath &ret)=0;
virtual const CGPathNode *getPathInfo(int3 tile)=0;
virtual bool getPath2(int3 dest, CGPath &ret)=0;
//map
virtual std::vector < const CGObjectInstance * > getBlockingObjs(int3 pos)const =0;
@ -261,6 +265,8 @@ public:
const TerrainTile * getTileInfo(int3 tile) const;
int canBuildStructure(const CGTownInstance *t, int ID);//// 0 - no more than one capitol, 1 - lack of water, 2 - forbidden, 3 - Add another level to Mage Guild, 4 - already built, 5 - cannot build, 6 - cannot afford, 7 - build, 8 - lack of requirements
bool getPath(int3 src, int3 dest, const CGHeroInstance * hero, CPath &ret);
const CGPathNode *getPathInfo(int3 tile);
bool getPath2(int3 dest, CGPath &ret);
bool getHeroInfo(const CGObjectInstance *hero, InfoAboutHero &dest) const;
bool getTownInfo(const CGObjectInstance *town, InfoAboutTown &dest) const;

View File

@ -652,32 +652,121 @@ void CTerrainRect::mouseMoved (const SDL_MouseMotionEvent & sEvent)
{
LOCPLINT->adventureInt->statusbar.clear();
}
std::vector<const CGObjectInstance *> objs = LOCPLINT->cb->getVisitableObjs(pom);
for(int i=0; i<objs.size();i++)
const CGPathNode *pnode = LOCPLINT->cb->getPathInfo(pom);
std::vector<const CGObjectInstance *> objs = LOCPLINT->cb->getBlockingObjs(pom);
const CGObjectInstance *obj = objs.size() ? objs.back() : NULL;
bool accessible = pnode->turns < 255;
int turns = pnode->turns;
amin(turns, 4);
if(LOCPLINT->adventureInt->selection->ID == TOWNI_TYPE)
{
if(objs[i]->ID == TOWNI_TYPE) //town
if(obj)
{
CGI->curh->changeGraphic(0,0);
return;
if(obj->ID == TOWNI_TYPE)
{
CGI->curh->changeGraphic(0, 3);
}
else if(obj->ID == HEROI_TYPE)
{
CGI->curh->changeGraphic(0, 2);
}
}
else
{
CGI->curh->changeGraphic(0, 0);
}
}
objs = LOCPLINT->cb->getBlockingObjs(pom);
for(size_t i=0; i < objs.size(); ++i)
else if(LOCPLINT->adventureInt->selection->ID == HEROI_TYPE)
{
if(objs[i]->ID == TOWNI_TYPE && objs[i]->tempOwner == LOCPLINT->playerID) //town
const CGHeroInstance *h = static_cast<const CGHeroInstance *>(LOCPLINT->adventureInt->selection);
if(obj)
{
CGI->curh->changeGraphic(0,3);
return;
}
else if(objs[i]->ID == HEROI_TYPE //mouse over hero
&& (objs[i]==LOCPLINT->adventureInt->selection || LOCPLINT->adventureInt->selection->ID==TOWNI_TYPE)
&& objs[i]->tempOwner == LOCPLINT->playerID) //this hero is selected or we've selected a town
if(obj->ID == HEROI_TYPE)
{
if(obj->tempOwner != LOCPLINT->playerID) //enemy hero TODO: allies
{
if(accessible)
CGI->curh->changeGraphic(0, 5 + turns*6);
else
CGI->curh->changeGraphic(0, 0);
}
else //our hero
{
if(LOCPLINT->adventureInt->selection == obj)
CGI->curh->changeGraphic(0, 2);
else if(accessible)
CGI->curh->changeGraphic(0, 8 + turns*6);
else
CGI->curh->changeGraphic(0, 2);
}
}
else if(obj->ID == TOWNI_TYPE)
{
if(obj->tempOwner != LOCPLINT->playerID) //enemy town TODO: allies
{
if(accessible)
CGI->curh->changeGraphic(0, 5 + turns*6);
else
CGI->curh->changeGraphic(0, 0);
}
else //our town
{
if(accessible)
CGI->curh->changeGraphic(0, 9 + turns*6);
else
CGI->curh->changeGraphic(0, 3);
}
}
else if(obj->ID == 54) //monster
{
if(accessible)
CGI->curh->changeGraphic(0, 5 + turns*6);
else
CGI->curh->changeGraphic(0, 0);
}
else if(obj->ID == 8) //boat
{
if(accessible)
CGI->curh->changeGraphic(0, 6 + turns*6);
else
CGI->curh->changeGraphic(0, 0);
}
else
{
if(accessible)
{
if(pnode->land)
CGI->curh->changeGraphic(0, 9 + turns*6);
else
CGI->curh->changeGraphic(0, 28 + turns);
}
else
CGI->curh->changeGraphic(0, 0);
}
}
else //no objs
{
CGI->curh->changeGraphic(0,2);
return;
if(accessible)
{
if(pnode->land)
{
if(LOCPLINT->cb->getTileInfo(h->getPosition(false))->tertype != TerrainTile::water)
CGI->curh->changeGraphic(0, 4 + turns*6);
else
CGI->curh->changeGraphic(0, 7 + turns*6); //anchor
}
else
CGI->curh->changeGraphic(0, 6 + turns*6);
}
else
CGI->curh->changeGraphic(0, 0);
}
}
CGI->curh->changeGraphic(0,0);
//tlog1 << "Tile " << pom << ": Turns=" << (int)pnode->turns <<" Move:=" << pnode->moveRemains <</* " (from " << ")" << */std::endl;
}
void CTerrainRect::hover(bool on)
{

View File

@ -20,7 +20,7 @@ extern SDL_Surface * screen;
void CCursorHandler::initCursor()
{
mode = number = xpos = ypos = 0;
help = CSDL_Ext::newSurface(32,32);
help = CSDL_Ext::newSurface(40,40);
cursors.push_back(CDefHandler::giveDef("CRADVNTR.DEF"));
cursors.push_back(CDefHandler::giveDef("CRCOMBAT.DEF"));
cursors.push_back(CDefHandler::giveDef("CRDEFLT.DEF"));
@ -43,70 +43,116 @@ void CCursorHandler::draw1()
{
if(!Show) return;
int x = xpos, y = ypos;
if((mode==1 && number!=6) || mode ==3)
{
x-=16;
y-=16;
// Properly align the melee attack cursors.
if (mode == 1) {
switch (number) {
case 7: // Bottom left
x -= 6;
y += 16;
break;
case 8: // Left
x -= 16;
y += 10;
break;
case 9: // Top left
x -= 6;
y -= 6;
break;
case 10: // Top right
x += 16;
y -= 6;
break;
case 11: // Right
x += 16;
y += 11;
break;
case 12: // Bottom right
x += 16;
y += 16;
break;
case 13: // Below
x += 9;
y += 16;
break;
case 14: // Above
x += 9;
y -= 15;
break;
}
}
}
else if(mode==0 && number>0)
{
x-=12;
y-=10;
}
SDL_BlitSurface(screen, &genRect(32,32,x,y), help, &genRect(32,32,0,0));
shiftPos(x, y);
SDL_BlitSurface(screen, &genRect(40,40,x,y), help, &genRect(40,40,0,0));
blitAt(cursors[mode]->ourImages[number].bitmap,x,y);
}
void CCursorHandler::draw2()
{
if(!Show) return;
int x = xpos, y = ypos;
if((mode==1 && number!=6) || mode == 3)
shiftPos(x, y);
blitAt(help,x,y);
}
void CCursorHandler::shiftPos( int &x, int &y )
{
if((mode==1 && number!=6) || mode ==3)
{
x-=16;
y-=16;
// Properly align the melee attack cursors.
if (mode == 1)
{
switch (number)
{
case 7: // Bottom left
x -= 6;
y += 16;
break;
case 8: // Left
x -= 16;
y += 10;
break;
case 9: // Top left
x -= 6;
y -= 6;
break;
case 10: // Top right
x += 16;
y -= 6;
break;
case 11: // Right
x += 16;
y += 11;
break;
case 12: // Bottom right
x += 16;
y += 16;
break;
case 13: // Below
x += 9;
y += 16;
break;
case 14: // Above
x += 9;
y -= 15;
break;
}
}
}
else if(mode==0 && number>0)
else if(mode==0)
{
x-=12;
y-=10;
if(number == 0); //to exclude
else if(number == 2)
{
x -= 12;
y -= 10;
}
else if(number == 3)
{
x -= 12;
y -= 12;
}
else if(number < 27)
{
int hlpNum = (number - 4)%6;
if(hlpNum == 0)
{
x -= 15;
y -= 13;
}
else if(hlpNum == 1)
{
x -= 13;
y -= 13;
}
else if(hlpNum == 2)
{
x -= 20;
y -= 20;
}
else if(hlpNum == 3)
{
x -= 13;
y -= 16;
}
else if(hlpNum == 4)
{
x -= 8;
y -= 9;
}
else if(hlpNum == 5)
{
x -= 14;
y -= 16;
}
}
else if(number < 31)
{
x -= 20;
y -= 20;
}
}
blitAt(help,x,y);
}
}

View File

@ -29,6 +29,8 @@ public:
void cursorMove(const int & x, const int & y); //change cursor's positions to (x, y)
void changeGraphic(const int & type, const int & no); //changes cursor graphic for type type (0 - adventure, 1 - combat, 2 - default, 3 - spellbook) and frame no (not used for type 3)
void draw1();
void shiftPos( int &x, int &y );
void draw2();
void hide(){Show=0;};
void show(){Show=1;};

View File

@ -64,6 +64,7 @@ class KeyInterested;
class MotionInterested;
class TimeInterested;
class IShowable;
struct CPathsInfo;
namespace boost
{

View File

@ -82,6 +82,7 @@ public:
void CClient::init()
{
pathInfo = NULL;
applier = new CCLApplier;
IObjectInterface::cb = this;
serv = NULL;
@ -107,6 +108,7 @@ CClient::CClient(CConnection *con, StartInfo *si)
}
CClient::~CClient(void)
{
delete pathInfo;
delete applier;
delete shared;
}
@ -232,6 +234,7 @@ void CClient::load( const std::string & fname )
CGI->state = gs;
CGI->mh->map = gs->map;
pathInfo = new CPathsInfo(int3(gs->map->width, gs->map->height, gs->map->twoLevel+1));
CGI->mh->init();
tlog0 <<"Initing maphandler: "<<tmh.getDif()<<std::endl;
}
@ -344,6 +347,7 @@ void CClient::newGame( CConnection *con, StartInfo *si )
CGI->mh->map = mapa;
tlog0 <<"Creating mapHandler: "<<tmh.getDif()<<std::endl;
CGI->mh->init();
pathInfo = new CPathsInfo(int3(mapa->width, mapa->height, mapa->twoLevel+1));
tlog0 <<"Initializing mapHandler (together): "<<tmh.getDif()<<std::endl;
for (size_t i=0; i<gs->scenarioOps->playerInfos.size();++i) //initializing interfaces for players

View File

@ -25,6 +25,8 @@ class CCallback;
struct BattleAction;
struct SharedMem;
class CClient;
struct CPathsInfo;
void processCommand(const std::string &message, CClient *&client);
namespace boost
{
@ -62,6 +64,7 @@ public:
bool must_close;
SharedMem *shared;
BattleAction *curbaction;
CPathsInfo *pathInfo;
CondSh<bool> waitingRequest;

View File

@ -485,7 +485,17 @@ void EndAction::applyCl( CClient *cl )
void PackageApplied::applyCl( CClient *cl )
{
INTERFACE_CALL_IF_PRESENT(GS(cl)->currentPlayer,requestRealized,this);
ui8 player = GS(cl)->currentPlayer;
if(packType == typeList.getTypeID((MoveHero*)NULL))
{
//we've finished moving hero - paths info must be updated
const CGHeroInstance *h = cl->IGameCallback::getSelectedHero(player);
if(h)
GS(cl)->calculatePaths(h, *cl->pathInfo);
}
INTERFACE_CALL_IF_PRESENT(player, requestRealized, this);
if(cl->waitingRequest.get())
cl->waitingRequest.setn(false);
}
@ -526,6 +536,15 @@ void PlayerMessage::applyCl(CClient *cl)
LOCPLINT->cingconsole->print(str.str());
}
void SetSelection::applyCl(CClient *cl)
{
const CGHeroInstance *h = cl->getHero(id);
if(!h)
return;
CPackForClient::GS(cl)->calculatePaths(h, *cl->pathInfo);
}
void ShowInInfobox::applyCl(CClient *cl)
{
SComponent sc(c);

View File

@ -1580,7 +1580,7 @@ void CGameState::loadTownDInfos()
}
}
void CGameState::getNeighbours(int3 tile, std::vector<int3> &vec, const boost::logic::tribool &onLand)
void CGameState::getNeighbours( const TerrainTile &srct, int3 tile, std::vector<int3> &vec, const boost::logic::tribool &onLand )
{
static 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) };
@ -1588,19 +1588,21 @@ void CGameState::getNeighbours(int3 tile, std::vector<int3> &vec, const boost::l
vec.clear();
for (size_t i = 0; i < ARRAY_COUNT(dirs); i++)
{
int3 hlp = tile + dirs[i];
const int3 hlp = tile + dirs[i];
if(!map->isInTheMap(hlp))
continue;
if((indeterminate(onLand) || onLand == (map->getTile(hlp).tertype!=8) )
&& map->getTile(hlp).tertype!=9)
const TerrainTile &hlpt = map->getTile(hlp);
if((indeterminate(onLand) || onLand == (hlpt.tertype!=8) )
&& hlpt.tertype!=9)
{
vec.push_back(hlp);
}
}
}
int CGameState::getMovementCost(const CGHeroInstance *h, int3 src, int3 dest, int remainingMovePoints, bool checkLast)
int CGameState::getMovementCost(const CGHeroInstance *h, const int3 &src, const int3 &dest, int remainingMovePoints, bool checkLast)
{
if(src == dest) //same tile
return 0;
@ -1616,7 +1618,7 @@ int CGameState::getMovementCost(const CGHeroInstance *h, int3 src, int3 dest, in
int old = ret;
ret *= 1.414213;
//diagonal move costs too much but normal move is possible - allow diagonal move for remaining move points
if(ret > remainingMovePoints && remainingMovePoints > old)
if(ret > remainingMovePoints && remainingMovePoints >= old)
{
return remainingMovePoints;
}
@ -1627,7 +1629,7 @@ int CGameState::getMovementCost(const CGHeroInstance *h, int3 src, int3 dest, in
if(checkLast && left > 0 && remainingMovePoints-ret < 250) //it might be the last tile - if no further move possible we take all move points
{
std::vector<int3> vec;
getNeighbours(dest, vec, s.tertype != TerrainTile::water);
getNeighbours(d, dest, vec, s.tertype != TerrainTile::water);
for(size_t i=0; i < vec.size(); i++)
{
int fcost = getMovementCost(h,dest,vec[i],left,false);
@ -1818,7 +1820,7 @@ bool CGameState::getPath(int3 src, int3 dest, const CGHeroInstance * hero, CPath
}
//add accessible neighbouring nodes to the queue
getNeighbours(cp.coord, neighbours, boost::logic::indeterminate);
getNeighbours(map->getTile(cp.coord), cp.coord, neighbours, boost::logic::indeterminate);
for(unsigned int i=0; i < neighbours.size(); i++)
{
CPathNode & dp = graph[neighbours[i].x][neighbours[i].y];
@ -1852,146 +1854,144 @@ bool CGameState::getPath(int3 src, int3 dest, const CGHeroInstance * hero, CPath
return true;
}
//void CGameState::calculatePaths(const CGHeroInstance *hero, CPathsInfo &out, const int3 &src)
//{
// if(!map->isInTheMap(src)/* || !map->isInTheMap(dest)*/) //check input
// //todo: distater
// return;
//
// int3 hpos = hero->getPosition(false);
// tribool blockLandSea; //true - blocks sea, false - blocks land, indeterminate - allows all
//
// if (!hero->canWalkOnSea())
// blockLandSea = (map->getTile(hpos).tertype != TerrainTile::water); //block land if hero is on water and vice versa
// else
// blockLandSea = boost::logic::indeterminate;
//
// const std::vector<std::vector<std::vector<ui8> > > &FoW = getPlayer(hero->tempOwner)->fogOfWarMap;
//
// //graph initialization
// CGPathNode ***graph = out.nodes;
// for(size_t i=0; i < out.sizes.x; ++i)
// {
// for(size_t j=0; j < out.sizes.y; ++j)
// {
// for(size_t k=0; k < out.sizes.z; ++k)
// {
// const TerrainTile *tinfo = &map->terrain[i][j][k];
// CGPathNode &node = graph[i][j][k];
//
// node.accessible = (tinfo->blocked ? CGPathNode::BLOCKED : CGPathNode::ACCESSIBLE);
// node.visited = false;
// node.turns = 0xff;
// node.moveRemains = 0;
// node.coord.x = i;
// node.coord.y = j;
// node.coord.z = k;
// node.land = tinfo->tertype == TerrainTile::water;
//
// if ((tinfo->tertype == TerrainTile::rock) //it's rock
// || ((blockLandSea) && () //it's sea and we cannot walk on sea
// || ((!blockLandSea) && (tinfo->tertype != TerrainTile::water)) //it's land and we cannot walk on land
// || !FoW[i][j][k] //tile is covered by the FoW
// )
// {
// node.accessible = CGPathNode::BLOCKED;
// }
// else if(tinfo->visitable)
// {
// for(size_t ii = 0; ii < tinfo->visitableObjects.size(); ii++)
// {
// if(tinfo->visitableObjects[ii]->blockVisit)
// {
// node.accessible = CGPathNode::BLOCKVIS;
// break;
// }
// else
// node.accessible = CGPathNode::VISITABLE;
// }
// }
//
// if(blockLandSea && tinfo->tertype == TerrainTile::water) //hero can walk only on land and tile lays on the water
// {
// size_t i = 0;
// for(; i < tinfo->visitableObjects.size(); i++)
// if(tinfo->visitableObjects[i]->ID == 8 || tinfo->visitableObjects[i]->ID == HEROI_TYPE) //it's a Boat
// break;
//
// if(i < tinfo->visitableObjects.size())
// node.accessible = CGPathNode::BLOCKVIS; //dest is accessible only if there is boat/hero
// }
// else if(!blockLandSea && tinfo->tertype != TerrainTile::water) //hero is moving by water
// {
// if((tinfo->siodmyTajemniczyBajt & 64) && !tinfo->blocked)
// node.accessible = CGPathNode::ACCESSIBLE; //tile is accessible if it's coastal and not blocked
// }
// }
// }
// }
// //graph initialized
//
//
// //initial tile - set cost on 0 and add to the queue
// graph[src.x][src.y][src.z].turns = 0;
// graph[src.x][src.y][src.z].moveRemains = hero->movement;
// std::queue<CGPathNode*> mq;
// mq.push(&graph[src.x][src.y][src.z]);
//
// ui32 curDist = 0xffffffff; //total cost of path - init with max possible val
//
// std::vector<int3> neighbours;
// neighbours.reserve(8);
//
// while(!mq.empty())
// {
// CGPathNode *cp = graph[mq.front()->coord.x][mq.front()->coord.y];
// mq.pop();
//
// //add accessible neighbouring nodes to the queue
// getNeighbours(cp->coord, neighbours, boost::logic::indeterminate);
// for(unsigned int i=0; i < neighbours.size(); i++)
// {
// const int3 &n = neighbours[i]; //current neighbour
// CGPathNode & dp = graph[n.x][n.y][n.z];
// if(!cp->moveRemains)
// {
// cp->turns++;
// cp->moveRemains = hero->maxMovePoints(
// }
//
//
// if(dp.accessible != CGPathNode::BLOCKVIS)
// {
// int cost = getMovementCost(hero,cp->coord,dp.coord,hero->movement - cp->dist);
// if((dp.turns==0xff || (dp.dist > cp->dist + cost)) && dp.accesible && checkForVisitableDir(cp->coord, dp.coord) && checkForVisitableDir(dp.coord, cp->coord))
// {
// dp.moveRemains = cp.moveRemains - cost;
// dp.theNodeBefore = &cp;
// if(dp.accessible == CGPathNode::ACCESSIBLE)
// {
// mq.push(dp);
// }
// }
// }
// }
// }
//
// CPathNode *curNode = &graph[dest.x][dest.y];
// if(!curNode->theNodeBefore) //destination is not accessible
// return false;
//
//
// //fill ret with found path
// ret.nodes.clear();
// while(curNode->coord != graph[src.x][src.y].coord)
// {
// ret.nodes.push_back(*curNode);
// curNode = curNode->theNodeBefore;
// }
// ret.nodes.push_back(graph[src.x][src.y]);
//
// return true;
//}
void CGameState::calculatePaths(const CGHeroInstance *hero, CPathsInfo &out, int3 src, int movement)
{
if(src.x < 0)
src = hero->getPosition(false);
if(movement < 0)
movement = hero->movement;
if(!map->isInTheMap(src)/* || !map->isInTheMap(dest)*/) //check input
{
tlog1 << "CGameState::calculatePaths: Hero outside the map? How dare you...\n";
return;
}
tribool onLand; //true - blocks sea, false - blocks land, indeterminate - allows all
if (!hero->canWalkOnSea())
onLand = (map->getTile(src).tertype != TerrainTile::water); //block land if hero is on water and vice versa
else
onLand = boost::logic::indeterminate;
const std::vector<std::vector<std::vector<ui8> > > &FoW = getPlayer(hero->tempOwner)->fogOfWarMap;
//graph initialization
CGPathNode ***graph = out.nodes;
for(size_t i=0; i < out.sizes.x; ++i)
{
for(size_t j=0; j < out.sizes.y; ++j)
{
for(size_t k=0; k < out.sizes.z; ++k)
{
const TerrainTile *tinfo = &map->terrain[i][j][k];
CGPathNode &node = graph[i][j][k];
node.accessible = (tinfo->blocked ? CGPathNode::BLOCKED : CGPathNode::ACCESSIBLE);
node.turns = 0xff;
node.moveRemains = 0;
node.coord.x = i;
node.coord.y = j;
node.coord.z = k;
node.land = tinfo->tertype != TerrainTile::water;
if ( tinfo->tertype == TerrainTile::rock//it's rock
|| onLand && !node.land //it's sea and we cannot walk on sea
|| !onLand && node.land //it's land and we cannot walk on land
|| !FoW[i][j][k] //tile is covered by the FoW
)
{
node.accessible = CGPathNode::BLOCKED;
}
else if(tinfo->visitable)
{
for(size_t ii = 0; ii < tinfo->visitableObjects.size(); ii++)
{
if(tinfo->visitableObjects[ii]->blockVisit)
{
node.accessible = CGPathNode::BLOCKVIS;
break;
}
else
node.accessible = CGPathNode::VISITABLE;
}
}
if(onLand && !node.land) //hero can walk only on land and tile lays on the water
{
size_t i = 0;
for(; i < tinfo->visitableObjects.size(); i++)
if(tinfo->visitableObjects[i]->ID == 8 || tinfo->visitableObjects[i]->ID == HEROI_TYPE) //it's a Boat
break;
if(i < tinfo->visitableObjects.size())
node.accessible = CGPathNode::BLOCKVIS; //dest is accessible only if there is boat/hero
}
else if(!onLand && tinfo->tertype != TerrainTile::water) //hero is moving by water
{
if((tinfo->siodmyTajemniczyBajt & 64) && !tinfo->blocked)
node.accessible = CGPathNode::ACCESSIBLE; //tile is accessible if it's coastal and not blocked
}
}
}
}
//graph initialized
//initial tile - set cost on 0 and add to the queue
graph[src.x][src.y][src.z].turns = 0;
graph[src.x][src.y][src.z].moveRemains = movement;
std::queue<CGPathNode*> mq;
mq.push(&graph[src.x][src.y][src.z]);
ui32 curDist = 0xffffffff; //total cost of path - init with max possible val
std::vector<int3> neighbours;
neighbours.reserve(8);
while(!mq.empty())
{
CGPathNode *cp = mq.front();
mq.pop();
const TerrainTile &ct = map->getTile(cp->coord);
int movement = cp->moveRemains, turn = cp->turns;
if(!movement)
{
movement = hero->maxMovePoints(ct.tertype != TerrainTile::water);
turn++;
}
//add accessible neighbouring nodes to the queue
getNeighbours(ct, cp->coord, neighbours, boost::logic::indeterminate);
for(unsigned int i=0; i < neighbours.size(); i++)
{
const int3 &n = neighbours[i]; //current neighbor
CGPathNode & dp = graph[n.x][n.y][n.z];
if( !checkForVisitableDir(cp->coord, dp.coord)
|| !checkForVisitableDir(dp.coord, cp->coord)
|| dp.accessible == CGPathNode::BLOCKED )
{
continue;
}
int cost = getMovementCost(hero, cp->coord, dp.coord, movement);
int remains = movement - cost;
if(dp.turns==0xff //we haven't been here before
|| dp.turns > turn
|| (dp.turns >= turn && dp.moveRemains < remains)) //this route is faster
{
dp.moveRemains = remains;
dp.turns = turn;
dp.theNodeBefore = cp;
if(dp.accessible == CGPathNode::ACCESSIBLE)
{
mq.push(&dp);
}
}
} //neighbours loop
} //queue loop
}
bool CGameState::isVisible(int3 pos, int player)
{
@ -2022,6 +2022,11 @@ bool CGameState::isVisible( const CGObjectInstance *obj, int player )
bool CGameState::checkForVisitableDir(const int3 & src, const int3 & dst) const
{
const TerrainTile * pom = &map->getTile(dst);
return checkForVisitableDir(src, pom, dst);
}
bool CGameState::checkForVisitableDir( const int3 & src, const TerrainTile *pom, const int3 & dst ) const
{
for(unsigned int b=0; b<pom->visitableObjects.size(); ++b) //checking destination tile
{
if(!vstd::contains(pom->blockingObjects, pom->visitableObjects[b])) //this visitable object is not blocking, ignore
@ -2063,7 +2068,6 @@ bool CGameState::checkForVisitableDir(const int3 & src, const int3 & dst) const
}
return true;
}
std::pair<ui32, ui32> BattleInfo::calculateDmgRange(const CStack* attacker, const CStack* defender, const CGHeroInstance * attackerHero, const CGHeroInstance * defendingHero, bool shooting, ui8 charge)
{
int attackDefenseBonus,
@ -2574,3 +2578,55 @@ int3 CPath::endPos() const
{
return nodes[0].coord;
}
CGPathNode::CGPathNode()
:coord(-1,-1,-1)
{
accessible = 0;
land = 0;
moveRemains = 0;
turns = 255;
theNodeBefore = NULL;
}
bool CPathsInfo::getPath( const int3 &dst, CGPath &out )
{
out.nodes.clear();
const CGPathNode *curnode = &nodes[dst.x][dst.y][dst.z];
if(!curnode->theNodeBefore)
return false;
while(curnode->theNodeBefore)
{
out.nodes.push_back(*curnode);
curnode = curnode->theNodeBefore;
}
return true;
}
CPathsInfo::CPathsInfo( const int3 &Sizes )
:sizes(Sizes)
{
nodes = new CGPathNode**[sizes.x];
for(int i = 0; i < sizes.x; i++)
{
nodes[i] = new CGPathNode*[sizes.y];
for (int j = 0; j < sizes.y; j++)
{
nodes[i][j] = new CGPathNode[sizes.z];
}
}
}
CPathsInfo::~CPathsInfo()
{
for(int i = 0; i < sizes.x; i++)
{
for (int j = 0; j < sizes.y; j++)
{
delete [] nodes[i][j];
}
delete [] nodes[i];
}
delete [] nodes;
}

View File

@ -48,7 +48,7 @@ struct SetObjectProperty;
struct MetaString;
struct CPack;
class CSpell;
struct TerrainTile;
namespace boost
{
@ -244,13 +244,13 @@ struct CPathNode
struct CGPathNode
{
enum {ACCESSIBLE=1, VISITABLE, BLOCKVIS, BLOCKED}; //BLOCKVIS - visitable from neighbourign tile but not passable
ui8 land;
enum {ACCESSIBLE=1, VISITABLE, BLOCKVIS, BLOCKED}; //BLOCKVIS - visitable from neighbouring tile but not passable
ui8 accessible; //the enum above
ui8 land;
ui8 turns;
ui32 moveRemains;
CPathNode * theNodeBefore;
int3 coord; //coordiantes
CGPathNode * theNodeBefore;
int3 coord; //coordinates
CGPathNode();
};
@ -264,13 +264,22 @@ struct DLL_EXPORT CPath
void convert(ui8 mode); //mode=0 -> from 'manifest' to 'object'
};
struct CPathsInfo
struct DLL_EXPORT CGPath
{
std::vector<CGPathNode> nodes; //just get node by node
int3 startPos() const; // start point
int3 endPos() const; //destination point
void convert(ui8 mode); //mode=0 -> from 'manifest' to 'object'
};
struct DLL_EXPORT CPathsInfo
{
int3 sizes;
CGPathNode ***nodes; //[w][h][level]
void getPath(const int3 &src, const int3 &dst, CPath &out);
CPathsInfo(const int3 &sizes);
bool getPath(const int3 &dst, CGPath &out);
CPathsInfo(const int3 &Sizes);
~CPathsInfo();
};
@ -321,17 +330,18 @@ public:
UpgradeInfo getUpgradeInfo(CArmedInstance *obj, int stackPos);
float getMarketEfficiency(int player, int mode=0);
int canBuildStructure(const CGTownInstance *t, int ID);// 0 - no more than one capitol, 1 - lack of water, 2 - forbidden, 3 - Add another level to Mage Guild, 4 - already built, 5 - cannot build, 6 - cannot afford, 7 - build, 8 - lack of requirements
bool checkForVisitableDir(const int3 & src, const int3 & dst) const; //check if dst tile is visitable from dst tile
bool checkForVisitableDir(const int3 & src, const int3 & dst) const; //check if src tile is visitable from dst tile
bool checkForVisitableDir(const int3 & src, const TerrainTile *pom, const int3 & dst) const; //check if src tile is visitable from dst tile
bool getPath(int3 src, int3 dest, const CGHeroInstance * hero, CPath &ret); //calculates path between src and dest; returns pointer to newly allocated CPath or NULL if path does not exists
void calculatePaths(const CGHeroInstance *hero, CPathsInfo &out, const int3 &src = int3(-1,-1,-1)); //calculates path between src and dest; returns pointer to newly allocated CPath or NULL if path does not exists
void calculatePaths(const CGHeroInstance *hero, CPathsInfo &out, int3 src = int3(-1,-1,-1), int movement = -1); //calculates possible paths for hero, by default uses current hero position and movement left; returns pointer to newly allocated CPath or NULL if path does not exists
bool isVisible(int3 pos, int player);
bool isVisible(const CGObjectInstance *obj, int player);
CGameState(); //c-tor
~CGameState(); //d-tor
void getNeighbours(int3 tile, std::vector<int3> &vec, const boost::logic::tribool &onLand);
int getMovementCost(const CGHeroInstance *h, int3 src, int3 dest, int remainingMovePoints=-1, bool checkLast=true);
void getNeighbours(const TerrainTile &srct, int3 tile, std::vector<int3> &vec, const boost::logic::tribool &onLand);
int getMovementCost(const CGHeroInstance *h, const int3 &src, const int3 &dest, int remainingMovePoints=-1, bool checkLast=true);
int getDate(int mode=0) const; //mode=0 - total days in game, mode=1 - day of week, mode=2 - current week, mode=3 - current month
template <typename Handler> void serialize(Handler &h, const int version)
{

View File

@ -1302,6 +1302,7 @@ struct SetSelection : public CPackForClient, public CPackForServer //514
SetSelection(){CPackForClient::type = 514;};
DLL_EXPORT void applyGs(CGameState *gs);
bool applyGh(CGameHandler *gh);
void applyCl(CClient *cl);
ui8 player;
ui32 id;