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:
parent
c1b112d266
commit
ca7ee8936c
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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;};
|
||||
|
@ -64,6 +64,7 @@ class KeyInterested;
|
||||
class MotionInterested;
|
||||
class TimeInterested;
|
||||
class IShowable;
|
||||
struct CPathsInfo;
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user