1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-07-15 01:24:45 +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; 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() InfoAboutHero::InfoAboutHero()
{ {
details = NULL; details = NULL;

View File

@ -40,6 +40,8 @@ class CHeroClass;
class IShipyard; class IShipyard;
struct CPackForServer; struct CPackForServer;
class CMapHeader; class CMapHeader;
struct CGPathNode;
struct CGPath;
struct InfoAboutHero struct InfoAboutHero
{ {
@ -135,6 +137,8 @@ public:
virtual std::vector < const CGHeroInstance *> getHeroesInfo(bool onlyOur=true)const =0; virtual std::vector < const CGHeroInstance *> getHeroesInfo(bool onlyOur=true)const =0;
virtual bool getHeroInfo(const CGObjectInstance *hero, InfoAboutHero &dest) 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 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 //map
virtual std::vector < const CGObjectInstance * > getBlockingObjs(int3 pos)const =0; virtual std::vector < const CGObjectInstance * > getBlockingObjs(int3 pos)const =0;
@ -261,6 +265,8 @@ public:
const TerrainTile * getTileInfo(int3 tile) const; 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 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); 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 getHeroInfo(const CGObjectInstance *hero, InfoAboutHero &dest) const;
bool getTownInfo(const CGObjectInstance *town, InfoAboutTown &dest) const; bool getTownInfo(const CGObjectInstance *town, InfoAboutTown &dest) const;

View File

@ -652,33 +652,122 @@ void CTerrainRect::mouseMoved (const SDL_MouseMotionEvent & sEvent)
{ {
LOCPLINT->adventureInt->statusbar.clear(); 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); if(obj->ID == TOWNI_TYPE)
return;
}
}
objs = LOCPLINT->cb->getBlockingObjs(pom);
for(size_t i=0; i < objs.size(); ++i)
{
if(objs[i]->ID == TOWNI_TYPE && objs[i]->tempOwner == LOCPLINT->playerID) //town
{ {
CGI->curh->changeGraphic(0, 3); CGI->curh->changeGraphic(0, 3);
return;
} }
else if(objs[i]->ID == HEROI_TYPE //mouse over hero else if(obj->ID == HEROI_TYPE)
&& (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
{ {
CGI->curh->changeGraphic(0, 2); CGI->curh->changeGraphic(0, 2);
return;
} }
} }
else
{
CGI->curh->changeGraphic(0, 0); CGI->curh->changeGraphic(0, 0);
} }
}
else if(LOCPLINT->adventureInt->selection->ID == HEROI_TYPE)
{
const CGHeroInstance *h = static_cast<const CGHeroInstance *>(LOCPLINT->adventureInt->selection);
if(obj)
{
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
{
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);
}
}
//tlog1 << "Tile " << pom << ": Turns=" << (int)pnode->turns <<" Move:=" << pnode->moveRemains <</* " (from " << ")" << */std::endl;
}
void CTerrainRect::hover(bool on) void CTerrainRect::hover(bool on)
{ {
if (!on) if (!on)

View File

@ -20,7 +20,7 @@ extern SDL_Surface * screen;
void CCursorHandler::initCursor() void CCursorHandler::initCursor()
{ {
mode = number = xpos = ypos = 0; 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("CRADVNTR.DEF"));
cursors.push_back(CDefHandler::giveDef("CRCOMBAT.DEF")); cursors.push_back(CDefHandler::giveDef("CRCOMBAT.DEF"));
cursors.push_back(CDefHandler::giveDef("CRDEFLT.DEF")); cursors.push_back(CDefHandler::giveDef("CRDEFLT.DEF"));
@ -43,14 +43,30 @@ void CCursorHandler::draw1()
{ {
if(!Show) return; if(!Show) return;
int x = xpos, y = ypos; int x = xpos, y = ypos;
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;
shiftPos(x, y);
blitAt(help,x,y);
}
void CCursorHandler::shiftPos( int &x, int &y )
{
if((mode==1 && number!=6) || mode ==3) if((mode==1 && number!=6) || mode ==3)
{ {
x-=16; x-=16;
y-=16; y-=16;
// Properly align the melee attack cursors. // Properly align the melee attack cursors.
if (mode == 1) { if (mode == 1)
switch (number) { {
switch (number)
{
case 7: // Bottom left case 7: // Bottom left
x -= 6; x -= 6;
y += 16; y += 16;
@ -86,27 +102,57 @@ void CCursorHandler::draw1()
} }
} }
} }
else if(mode==0 && number>0) else if(mode==0)
{
if(number == 0); //to exclude
else if(number == 2)
{ {
x -= 12; x -= 12;
y -= 10; y -= 10;
} }
SDL_BlitSurface(screen, &genRect(32,32,x,y), help, &genRect(32,32,0,0)); else if(number == 3)
blitAt(cursors[mode]->ourImages[number].bitmap,x,y); {
x -= 12;
y -= 12;
} }
void CCursorHandler::draw2() else if(number < 27)
{ {
if(!Show) return; int hlpNum = (number - 4)%6;
int x = xpos, y = ypos; if(hlpNum == 0)
if((mode==1 && number!=6) || mode == 3)
{ {
x-=16; 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; y -= 16;
} }
else if(mode==0 && number>0) else if(hlpNum == 4)
{ {
x-=12; x -= 8;
y-=10; 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 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 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 draw1();
void shiftPos( int &x, int &y );
void draw2(); void draw2();
void hide(){Show=0;}; void hide(){Show=0;};
void show(){Show=1;}; void show(){Show=1;};

View File

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

View File

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

View File

@ -485,7 +485,17 @@ void EndAction::applyCl( CClient *cl )
void PackageApplied::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()) if(cl->waitingRequest.get())
cl->waitingRequest.setn(false); cl->waitingRequest.setn(false);
} }
@ -526,6 +536,15 @@ void PlayerMessage::applyCl(CClient *cl)
LOCPLINT->cingconsole->print(str.str()); 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) void ShowInInfobox::applyCl(CClient *cl)
{ {
SComponent sc(c); 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), 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) }; 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(); vec.clear();
for (size_t i = 0; i < ARRAY_COUNT(dirs); i++) 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)) if(!map->isInTheMap(hlp))
continue; continue;
if((indeterminate(onLand) || onLand == (map->getTile(hlp).tertype!=8) ) const TerrainTile &hlpt = map->getTile(hlp);
&& map->getTile(hlp).tertype!=9)
if((indeterminate(onLand) || onLand == (hlpt.tertype!=8) )
&& hlpt.tertype!=9)
{ {
vec.push_back(hlp); 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 if(src == dest) //same tile
return 0; return 0;
@ -1616,7 +1618,7 @@ int CGameState::getMovementCost(const CGHeroInstance *h, int3 src, int3 dest, in
int old = ret; int old = ret;
ret *= 1.414213; ret *= 1.414213;
//diagonal move costs too much but normal move is possible - allow diagonal move for remaining move points //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; 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 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; 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++) for(size_t i=0; i < vec.size(); i++)
{ {
int fcost = getMovementCost(h,dest,vec[i],left,false); 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 //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++) for(unsigned int i=0; i < neighbours.size(); i++)
{ {
CPathNode & dp = graph[neighbours[i].x][neighbours[i].y]; 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; return true;
} }
//void CGameState::calculatePaths(const CGHeroInstance *hero, CPathsInfo &out, const int3 &src) void CGameState::calculatePaths(const CGHeroInstance *hero, CPathsInfo &out, int3 src, int movement)
//{ {
// if(!map->isInTheMap(src)/* || !map->isInTheMap(dest)*/) //check input if(src.x < 0)
// //todo: distater src = hero->getPosition(false);
// return; if(movement < 0)
// movement = hero->movement;
// int3 hpos = hero->getPosition(false);
// tribool blockLandSea; //true - blocks sea, false - blocks land, indeterminate - allows all if(!map->isInTheMap(src)/* || !map->isInTheMap(dest)*/) //check input
// {
// if (!hero->canWalkOnSea()) tlog1 << "CGameState::calculatePaths: Hero outside the map? How dare you...\n";
// blockLandSea = (map->getTile(hpos).tertype != TerrainTile::water); //block land if hero is on water and vice versa return;
// else }
// blockLandSea = boost::logic::indeterminate;
// tribool onLand; //true - blocks sea, false - blocks land, indeterminate - allows all
// const std::vector<std::vector<std::vector<ui8> > > &FoW = getPlayer(hero->tempOwner)->fogOfWarMap;
// if (!hero->canWalkOnSea())
// //graph initialization onLand = (map->getTile(src).tertype != TerrainTile::water); //block land if hero is on water and vice versa
// CGPathNode ***graph = out.nodes; else
// for(size_t i=0; i < out.sizes.x; ++i) onLand = boost::logic::indeterminate;
// {
// for(size_t j=0; j < out.sizes.y; ++j) const std::vector<std::vector<std::vector<ui8> > > &FoW = getPlayer(hero->tempOwner)->fogOfWarMap;
// {
// for(size_t k=0; k < out.sizes.z; ++k) //graph initialization
// { CGPathNode ***graph = out.nodes;
// const TerrainTile *tinfo = &map->terrain[i][j][k]; for(size_t i=0; i < out.sizes.x; ++i)
// CGPathNode &node = graph[i][j][k]; {
// for(size_t j=0; j < out.sizes.y; ++j)
// node.accessible = (tinfo->blocked ? CGPathNode::BLOCKED : CGPathNode::ACCESSIBLE); {
// node.visited = false; for(size_t k=0; k < out.sizes.z; ++k)
// node.turns = 0xff; {
// node.moveRemains = 0; const TerrainTile *tinfo = &map->terrain[i][j][k];
// node.coord.x = i; CGPathNode &node = graph[i][j][k];
// node.coord.y = j;
// node.coord.z = k; node.accessible = (tinfo->blocked ? CGPathNode::BLOCKED : CGPathNode::ACCESSIBLE);
// node.land = tinfo->tertype == TerrainTile::water; node.turns = 0xff;
// node.moveRemains = 0;
// if ((tinfo->tertype == TerrainTile::rock) //it's rock node.coord.x = i;
// || ((blockLandSea) && () //it's sea and we cannot walk on sea node.coord.y = j;
// || ((!blockLandSea) && (tinfo->tertype != TerrainTile::water)) //it's land and we cannot walk on land node.coord.z = k;
// || !FoW[i][j][k] //tile is covered by the FoW node.land = tinfo->tertype != TerrainTile::water;
// )
// { if ( tinfo->tertype == TerrainTile::rock//it's rock
// node.accessible = CGPathNode::BLOCKED; || onLand && !node.land //it's sea and we cannot walk on sea
// } || !onLand && node.land //it's land and we cannot walk on land
// else if(tinfo->visitable) || !FoW[i][j][k] //tile is covered by the FoW
// { )
// for(size_t ii = 0; ii < tinfo->visitableObjects.size(); ii++) {
// { node.accessible = CGPathNode::BLOCKED;
// if(tinfo->visitableObjects[ii]->blockVisit) }
// { else if(tinfo->visitable)
// node.accessible = CGPathNode::BLOCKVIS; {
// break; for(size_t ii = 0; ii < tinfo->visitableObjects.size(); ii++)
// } {
// else if(tinfo->visitableObjects[ii]->blockVisit)
// node.accessible = CGPathNode::VISITABLE; {
// } node.accessible = CGPathNode::BLOCKVIS;
// } break;
// }
// if(blockLandSea && tinfo->tertype == TerrainTile::water) //hero can walk only on land and tile lays on the water else
// { node.accessible = CGPathNode::VISITABLE;
// 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(onLand && !node.land) //hero can walk only on land and tile lays on the water
// {
// if(i < tinfo->visitableObjects.size()) size_t i = 0;
// node.accessible = CGPathNode::BLOCKVIS; //dest is accessible only if there is boat/hero for(; i < tinfo->visitableObjects.size(); i++)
// } if(tinfo->visitableObjects[i]->ID == 8 || tinfo->visitableObjects[i]->ID == HEROI_TYPE) //it's a Boat
// else if(!blockLandSea && tinfo->tertype != TerrainTile::water) //hero is moving by water break;
// { if(i < tinfo->visitableObjects.size())
// if((tinfo->siodmyTajemniczyBajt & 64) && !tinfo->blocked) node.accessible = CGPathNode::BLOCKVIS; //dest is accessible only if there is boat/hero
// node.accessible = CGPathNode::ACCESSIBLE; //tile is accessible if it's coastal and not blocked }
// } 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 initialized
// graph[src.x][src.y][src.z].moveRemains = hero->movement;
// std::queue<CGPathNode*> mq;
// mq.push(&graph[src.x][src.y][src.z]); //initial tile - set cost on 0 and add to the queue
// graph[src.x][src.y][src.z].turns = 0;
// ui32 curDist = 0xffffffff; //total cost of path - init with max possible val graph[src.x][src.y][src.z].moveRemains = movement;
// std::queue<CGPathNode*> mq;
// std::vector<int3> neighbours; mq.push(&graph[src.x][src.y][src.z]);
// neighbours.reserve(8);
// ui32 curDist = 0xffffffff; //total cost of path - init with max possible val
// while(!mq.empty())
// { std::vector<int3> neighbours;
// CGPathNode *cp = graph[mq.front()->coord.x][mq.front()->coord.y]; neighbours.reserve(8);
// mq.pop();
// while(!mq.empty())
// //add accessible neighbouring nodes to the queue {
// getNeighbours(cp->coord, neighbours, boost::logic::indeterminate); CGPathNode *cp = mq.front();
// for(unsigned int i=0; i < neighbours.size(); i++) mq.pop();
// {
// const int3 &n = neighbours[i]; //current neighbour const TerrainTile &ct = map->getTile(cp->coord);
// CGPathNode & dp = graph[n.x][n.y][n.z]; int movement = cp->moveRemains, turn = cp->turns;
// if(!cp->moveRemains) if(!movement)
// { {
// cp->turns++; movement = hero->maxMovePoints(ct.tertype != TerrainTile::water);
// cp->moveRemains = hero->maxMovePoints( turn++;
// } }
//
// //add accessible neighbouring nodes to the queue
// if(dp.accessible != CGPathNode::BLOCKVIS) getNeighbours(ct, cp->coord, neighbours, boost::logic::indeterminate);
// { for(unsigned int i=0; i < neighbours.size(); i++)
// 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)) const int3 &n = neighbours[i]; //current neighbor
// { CGPathNode & dp = graph[n.x][n.y][n.z];
// dp.moveRemains = cp.moveRemains - cost; if( !checkForVisitableDir(cp->coord, dp.coord)
// dp.theNodeBefore = &cp; || !checkForVisitableDir(dp.coord, cp->coord)
// if(dp.accessible == CGPathNode::ACCESSIBLE) || dp.accessible == CGPathNode::BLOCKED )
// { {
// mq.push(dp); continue;
// } }
// }
// } int cost = getMovementCost(hero, cp->coord, dp.coord, movement);
// } int remains = movement - cost;
// }
// if(dp.turns==0xff //we haven't been here before
// CPathNode *curNode = &graph[dest.x][dest.y]; || dp.turns > turn
// if(!curNode->theNodeBefore) //destination is not accessible || (dp.turns >= turn && dp.moveRemains < remains)) //this route is faster
// return false; {
// dp.moveRemains = remains;
// dp.turns = turn;
// //fill ret with found path dp.theNodeBefore = cp;
// ret.nodes.clear(); if(dp.accessible == CGPathNode::ACCESSIBLE)
// while(curNode->coord != graph[src.x][src.y].coord) {
// { mq.push(&dp);
// ret.nodes.push_back(*curNode); }
// curNode = curNode->theNodeBefore; }
// } } //neighbours loop
// ret.nodes.push_back(graph[src.x][src.y]); } //queue loop
// }
// return true;
//}
bool CGameState::isVisible(int3 pos, int player) 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 bool CGameState::checkForVisitableDir(const int3 & src, const int3 & dst) const
{ {
const TerrainTile * pom = &map->getTile(dst); 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 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 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; return true;
} }
std::pair<ui32, ui32> BattleInfo::calculateDmgRange(const CStack* attacker, const CStack* defender, const CGHeroInstance * attackerHero, const CGHeroInstance * defendingHero, bool shooting, ui8 charge) std::pair<ui32, ui32> BattleInfo::calculateDmgRange(const CStack* attacker, const CStack* defender, const CGHeroInstance * attackerHero, const CGHeroInstance * defendingHero, bool shooting, ui8 charge)
{ {
int attackDefenseBonus, int attackDefenseBonus,
@ -2574,3 +2578,55 @@ int3 CPath::endPos() const
{ {
return nodes[0].coord; 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 MetaString;
struct CPack; struct CPack;
class CSpell; class CSpell;
struct TerrainTile;
namespace boost namespace boost
{ {
@ -244,13 +244,13 @@ struct CPathNode
struct CGPathNode struct CGPathNode
{ {
enum {ACCESSIBLE=1, VISITABLE, BLOCKVIS, BLOCKED}; //BLOCKVIS - visitable from neighbourign tile but not passable enum {ACCESSIBLE=1, VISITABLE, BLOCKVIS, BLOCKED}; //BLOCKVIS - visitable from neighbouring tile but not passable
ui8 land;
ui8 accessible; //the enum above ui8 accessible; //the enum above
ui8 land;
ui8 turns; ui8 turns;
ui32 moveRemains; ui32 moveRemains;
CPathNode * theNodeBefore; CGPathNode * theNodeBefore;
int3 coord; //coordiantes int3 coord; //coordinates
CGPathNode(); CGPathNode();
}; };
@ -264,13 +264,22 @@ struct DLL_EXPORT CPath
void convert(ui8 mode); //mode=0 -> from 'manifest' to 'object' 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; int3 sizes;
CGPathNode ***nodes; //[w][h][level] CGPathNode ***nodes; //[w][h][level]
void getPath(const int3 &src, const int3 &dst, CPath &out); bool getPath(const int3 &dst, CGPath &out);
CPathsInfo(const int3 &sizes); CPathsInfo(const int3 &Sizes);
~CPathsInfo(); ~CPathsInfo();
}; };
@ -321,17 +330,18 @@ public:
UpgradeInfo getUpgradeInfo(CArmedInstance *obj, int stackPos); UpgradeInfo getUpgradeInfo(CArmedInstance *obj, int stackPos);
float getMarketEfficiency(int player, int mode=0); 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 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 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(int3 pos, int player);
bool isVisible(const CGObjectInstance *obj, int player); bool isVisible(const CGObjectInstance *obj, int player);
CGameState(); //c-tor CGameState(); //c-tor
~CGameState(); //d-tor ~CGameState(); //d-tor
void getNeighbours(int3 tile, std::vector<int3> &vec, const boost::logic::tribool &onLand); void getNeighbours(const TerrainTile &srct, 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); 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 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) 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;}; SetSelection(){CPackForClient::type = 514;};
DLL_EXPORT void applyGs(CGameState *gs); DLL_EXPORT void applyGs(CGameState *gs);
bool applyGh(CGameHandler *gh); bool applyGh(CGameHandler *gh);
void applyCl(CClient *cl);
ui8 player; ui8 player;
ui32 id; ui32 id;