1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-24 22:14:36 +02:00

REMOVED FILES: CPatgFinder.h/cpp

Updated project files for MSVC and automake (I hope I didn't break it)
* Refactored pathfinding and integrated into CGameState. 
* Fixed issues with wrong calculating movement cost at server side
* Hero infowindow won't be redrawed each time experience changes
* Removed memory leaks with CPaths-s
* Support for Sign objects
* Bumped savegame formt version to ensure old not compatible saves won't be readed
* Spellscrolls will disappear on visit (won't be treated as spellbooks anymore)
This commit is contained in:
Michał W. Urbańczyk 2009-03-19 14:17:19 +00:00
parent a0057c5014
commit 516b1e2b00
22 changed files with 299 additions and 344 deletions

View File

@ -6,7 +6,6 @@
#include "CGameInfo.h"
#include "CHeroWindow.h"
#include "CMessage.h"
#include "CPathfinder.h"
#include "CPlayerInterface.h"
#include "SDL_Extensions.h"
#include "client/CBitmapHandler.h"
@ -491,10 +490,11 @@ endchkpt:
int3 bufpos = currentHero->getPosition(false);
if (mres)
{
CPath * path;
path = CGI->pathf->getPath(bufpos, mp, currentHero);
//assign
currentPath = LOCPLINT->adventureInt->heroList.items[LOCPLINT->adventureInt->heroList.selected].second = path;
CPath *& pathForCurhero = LOCPLINT->adventureInt->heroList.items[LOCPLINT->adventureInt->heroList.selected].second;
if(pathForCurhero)
delete pathForCurhero;
currentPath = pathForCurhero = LOCPLINT->cb->getPath(bufpos, mp, currentHero);;
}
return;
}

View File

@ -3,7 +3,6 @@
#include "CCallback.h"
#include "CGameInfo.h"
#include "CGameState.h"
#include "CPathfinder.h"
#include "CPlayerInterface.h"
#include "CPlayerInterface.h"
#include "client/Client.h"
@ -670,4 +669,10 @@ const TerrainTile * CCallback::getTileInfo( int3 tile ) const
int CCallback::canBuildStructure( const CGTownInstance *t, int ID )
{
return gs->canBuildStructure(t,ID);
}
CPath * CCallback::getPath( int3 src, int3 dest, const CGHeroInstance * hero )
{
boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
return gs->getPath(src,dest,hero);
}

View File

@ -74,6 +74,7 @@ public:
virtual std::vector<const CGHeroInstance *> getAvailableHeroes(const CGTownInstance * town) const =0; //heroes that can be recruited
virtual const TerrainTile * getTileInfo(int3 tile) const = 0;
virtual int canBuildStructure(const CGTownInstance *t, int ID) =0;//// 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
virtual CPath * getPath(int3 src, int3 dest, const CGHeroInstance * hero)=0;
//battle
virtual int battleGetBattlefieldType()=0; // 1. sand/shore 2. sand/mesas 3. dirt/birches 4. dirt/hills 5. dirt/pines 6. grass/hills 7. grass/pines 8. lava 9. magic plains 10. snow/mountains 11. snow/trees 12. subterranean 13. swamp/trees 14. fiery fields 15. rock lands 16. magic clouds 17. lucid pools 18. holy ground 19. clover field 20. evil fog 21. "favourable winds" text on magic plains background 22. cursed ground 23. rough 24. ship to ship 25. ship
@ -164,6 +165,7 @@ public:
std::vector<const CGHeroInstance *> getAvailableHeroes(const CGTownInstance * town) const; //heroes that can be recruited
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
CPath * getPath(int3 src, int3 dest, const CGHeroInstance * hero);
//battle
int battleGetBattlefieldType(); // 1. sand/shore 2. sand/mesas 3. dirt/birches 4. dirt/hills 5. dirt/pines 6. grass/hills 7. grass/pines 8. lava 9. magic plains 10. snow/mountains 11. snow/trees 12. subterranean 13. swamp/trees 14. fiery fields 15. rock lands 16. magic clouds 17. lucid pools 18. holy ground 19. clover field 20. evil fog 21. "favourable winds" text on magic plains background 22. cursed ground 23. rough 24. ship to ship 25. ship

View File

@ -1,22 +1,7 @@
#define VCMI_DLL
#include "stdafx.h"
#include "CConsoleHandler.h"
#include "CAdvmapInterface.h"
#include "CCastleInterface.h"
#include "CPlayerInterface.h"
#include "CGameInfo.h"
#include "global.h"
#include "CGameState.h"
#include "CCallback.h"
#include "CPathfinder.h"
#include "mapHandler.h"
#include <sstream>
#include "SDL_Extensions.h"
#include "hch/CHeroHandler.h"
#include "hch/CLodHandler.h"
#include <boost/algorithm/string.hpp>
#include "boost/function.hpp"
#include <boost/thread.hpp>
#ifdef _WIN32
#include <windows.h>

View File

@ -57,7 +57,6 @@ public:
CLodHandler * bitmaph;
CGeneralTextHandler * generaltexth;
CConsoleHandler * consoleh;
CPathfinder * pathf;
CCursorHandler * curh;
CScreenHandler * screenh;

View File

@ -56,7 +56,10 @@ public:
void applyOnGS(CGameState *gs, void *pack) const
{
T *ptr = static_cast<T*>(pack);
while(!gs->mx->try_lock())
boost::this_thread::sleep(boost::posix_time::milliseconds(50)); //give other threads time to finish
ptr->applyGs(gs);
gs->mx->unlock();
}
};
@ -1352,7 +1355,7 @@ void CGameState::loadTownDInfos()
}
}
void CGameState::getNeighbours(int3 tile, std::vector<int3> &vec, bool onLand)
void CGameState::getNeighbours(int3 tile, std::vector<int3> &vec, const boost::logic::tribool &onLand)
{
vec.clear();
int3 hlp;
@ -1415,10 +1418,11 @@ int CGameState::getMovementCost(const CGHeroInstance *h, int3 src, int3 dest, in
//get basic cost
int ret = h->getTileCost(d,s);
if(src.x!=dest.x && src.y!=dest.y) //diagonal move costs too much but normal move is possible
if(src.x!=dest.x && src.y!=dest.y) //it's diagonal move
{
int old = ret;
ret *= 1.414;
//diagonal move costs too much but normal move is possible - allow diagonal move
if(ret > remainingMovePoints && remainingMovePoints > old)
{
return remainingMovePoints;
@ -1509,6 +1513,160 @@ PlayerState * CGameState::getPlayer( ui8 color )
}
}
CPath * CGameState::getPath(int3 src, int3 dest, const CGHeroInstance * hero)
{
if(!map->isInTheMap(src) || !map->isInTheMap(dest)) //check input
return NULL;
int3 hpos = hero->getPosition(false);
tribool blockLandSea; //true - blocks sea, false - blocks land, indeterminate - allows all
if (!hero->canWalkOnSea())
blockLandSea = (map->getTile(hpos).tertype != water); //block land if hero is on water and vice versa
else
blockLandSea = boost::logic::indeterminate;
//graph initialization
std::vector< std::vector<CPathNode> > graph;
graph.resize(map->width);
for(size_t i=0; i<graph.size(); ++i)
{
graph[i].resize(map->height);
for(size_t j=0; j<graph[i].size(); ++j)
{
const TerrainTile *tinfo = &map->terrain[i][j][src.z];
CPathNode &node = graph[i][j];
node.accesible = !tinfo->blocked;
if(i==dest.x && j==dest.y && tinfo->visitable)
{
node.accesible = true; //for allowing visiting objects
}
node.dist = -1;
node.theNodeBefore = NULL;
node.visited = false;
node.coord.x = i;
node.coord.y = j;
node.coord.z = dest.z;
if ((tinfo->tertype == rock) //it's rock
|| ((blockLandSea) && (tinfo->tertype == water)) //it's sea and we cannot walk on sea
|| ((!blockLandSea) && (tinfo->tertype != water)) //it's land and we cannot walk on land
|| !getPlayer(hero->tempOwner)->fogOfWarMap[i][j][src.z] //tile is covered by the FoW
)
{
node.accesible = false;
}
}
}
//graph initialized
//initial tile - set cost on 0 and add to the queue
graph[src.x][src.y].dist = 0;
std::queue<CPathNode> mq;
mq.push(graph[src.x][src.y]);
ui32 curDist = 0xffffffff; //total cost of path - init with max possible val
std::vector<int3> neighbours;
neighbours.reserve(8);
while(!mq.empty())
{
CPathNode &cp = graph[mq.front().coord.x][mq.front().coord.y];
mq.pop();
if (cp.coord == dest) //it's destination tile
{
if (cp.dist < curDist) //that path is better than previous one
curDist = cp.dist;
continue;
}
else
{
if (cp.dist > curDist) //it's not dest and current length is greater than cost of already found path
continue;
}
//add accessible neighbouring nodes to the queue
getNeighbours(cp.coord,neighbours,blockLandSea);
for(int i=0; i < neighbours.size(); i++)
{
CPathNode & dp = graph[neighbours[i].x][neighbours[i].y];
if(dp.accesible)
{
int cost = getMovementCost(hero,cp.coord,dp.coord,hero->movement - cp.dist);
if((dp.dist==-1 || (dp.dist > cp.dist + cost)) && dp.accesible && checkForVisitableDir(cp.coord, dp.coord) && checkForVisitableDir(dp.coord, cp.coord))
{
dp.dist = cp.dist + cost;
dp.theNodeBefore = &cp;
mq.push(dp);
}
}
}
}
CPathNode *curNode = &graph[dest.x][dest.y];
if(!curNode->theNodeBefore) //destination is not accessible
return NULL;
CPath * ret = new CPath;
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 ret;
}
bool CGameState::checkForVisitableDir(const int3 & src, const int3 & dst) const
{
const TerrainTile * pom = &map->getTile(dst);
for(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
continue;
CGDefInfo * di = pom->visitableObjects[b]->defInfo;
if( (dst.x == src.x-1 && dst.y == src.y-1) && !(di->visitDir & (1<<4)) )
{
return false;
}
if( (dst.x == src.x && dst.y == src.y-1) && !(di->visitDir & (1<<5)) )
{
return false;
}
if( (dst.x == src.x+1 && dst.y == src.y-1) && !(di->visitDir & (1<<6)) )
{
return false;
}
if( (dst.x == src.x+1 && dst.y == src.y) && !(di->visitDir & (1<<7)) )
{
return false;
}
if( (dst.x == src.x+1 && dst.y == src.y+1) && !(di->visitDir & (1<<0)) )
{
return false;
}
if( (dst.x == src.x && dst.y == src.y+1) && !(di->visitDir & (1<<1)) )
{
return false;
}
if( (dst.x == src.x-1 && dst.y == src.y+1) && !(di->visitDir & (1<<2)) )
{
return false;
}
if( (dst.x == src.x-1 && dst.y == src.y) && !(di->visitDir & (1<<3)) )
{
return false;
}
}
return true;
}
int BattleInfo::calculateDmg(const CStack* attacker, const CStack* defender, const CGHeroInstance * attackerHero, const CGHeroInstance * defendingHero, bool shooting)
{
int attackerAttackBonus = attacker->creature->attack + (attackerHero ? attackerHero->getPrimSkillLevel(0) : 0);
@ -1765,3 +1923,23 @@ std::vector<CStack> BattleInfo::getStackQueue()
}
return ret;
}
int3 CPath::startPos()
{
return int3(nodes[nodes.size()-1].coord.x,nodes[nodes.size()-1].coord.y,nodes[nodes.size()-1].coord.z);
}
void CPath::convert(ui8 mode) //mode=0 -> from 'manifest' to 'object'
{
if (mode==0)
{
for (int i=0;i<nodes.size();i++)
{
nodes[i].coord = CGHeroInstance::convertPosition(nodes[i].coord,true);
}
}
}
int3 CPath::endPos()
{
return int3(nodes[0].coord.x,nodes[0].coord.y,nodes[0].coord.z);
}

View File

@ -197,6 +197,24 @@ struct UpgradeInfo
UpgradeInfo(){oldID = -1;};
};
struct CPathNode
{
bool accesible; //true if a hero can be on this node
int dist; //distance from the first node of searching; -1 is infinity
CPathNode * theNodeBefore;
int3 coord; //coordiantes
bool visited;
};
struct DLL_EXPORT CPath
{
std::vector<CPathNode> nodes; //just get node by node
int3 startPos(); // start point
int3 endPos(); //destination point
void convert(ui8 mode); //mode=0 -> from 'manifest' to 'object'
};
class DLL_EXPORT CGameState
{
public:
@ -242,10 +260,12 @@ 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
CPath * getPath(int3 src, int3 dest, const CGHeroInstance * hero); //calculates path between src and dest; returns pointer to newly allocated CPath or NULL if path does not exists
CGameState();
~CGameState();
void getNeighbours(int3 tile, std::vector<int3> &vec, bool onLand);
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);
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)
@ -276,7 +296,6 @@ public:
}
friend class CCallback;
friend class CPathfinder;;
friend class CLuaCallback;
friend class CClient;
friend void initGameState(Mapa * map, CGameInfo * cgi);

View File

@ -20,7 +20,6 @@
#include "CCastleInterface.h"
#include "CConsoleHandler.h"
#include "CCursorHandler.h"
#include "CPathfinder.h"
#include "CGameState.h"
#include "CCallback.h"
#include "CPlayerInterface.h"
@ -122,10 +121,7 @@ int main(int argc, char** argv)
cgi->curh = new CCursorHandler;
cgi->curh->initCursor();
cgi->curh->show();
tlog0<<"\tScreen handler: "<<pomtime.getDif()<<std::endl;
cgi->pathf = new CPathfinder();
tlog0<<"\tPathfinder: "<<pomtime.getDif()<<std::endl;
tlog0<<"Preparing first handlers: "<<tmh.getDif()<<std::endl;
tlog0<<"Screen handler: "<<pomtime.getDif()<<std::endl;
pomtime.getDif();
graphics = new Graphics();
graphics->loadHeroAnim();

View File

@ -1,234 +0,0 @@
#include "stdafx.h"
#include "global.h"
#include "CPathfinder.h"
#include "CGameInfo.h"
#include "hch/CAmbarCendamo.h"
#include "mapHandler.h"
#include "CGameState.h"
#include "hch/CObjectHandler.h"
#include "hch/CDefObjInfoHandler.h"
using namespace boost::logic;
int3 CPath::startPos()
{
return int3(nodes[nodes.size()-1].coord.x,nodes[nodes.size()-1].coord.y,nodes[nodes.size()-1].coord.z);
}
int3 CPath::endPos()
{
return int3(nodes[0].coord.x,nodes[0].coord.y,nodes[0].coord.z);
}
CPath * CPathfinder::getPath(int3 src, int3 dest, const CGHeroInstance * hero, unsigned char type) //TODO: test it (seems to be finished, but relies on unwritten functions :()
{
//check input
if ((src.x < 0)||(src.y < 0)||(src.z < 0)||(dest.x < 0)||(dest.y < 0)||(dest.z < 0))
{
return NULL;
}
if ((src.x >= CGI->mh->sizes.x)||(src.y >= CGI->mh->sizes.y)||(src.z >= CGI->mh->sizes.z)
||(dest.x >= CGI->mh->sizes.x)||(dest.y >= CGI->mh->sizes.y)||(dest.z >= CGI->mh->sizes.z))
{
return NULL;
}
int3 hpos = hero->getPosition(false);
tribool blockLandSea; //true - blocks sea, false - blocks land, indeterminate - allows all
if (!hero->canWalkOnSea())
{
if (CGI->mh->ttiles[hpos.x][hpos.y][hpos.z].tileInfo->tertype==water)
blockLandSea=false;
else
blockLandSea=true;
}
else
{
blockLandSea = indeterminate;
}
//graph initialization
graph.resize(CGI->mh->sizes.x);
for(size_t i=0; i<graph.size(); ++i)
{
graph[i].resize(CGI->mh->sizes.y);
for(size_t j=0; j<graph[i].size(); ++j)
{
graph[i][j].accesible = !CGI->mh->ttiles[i][j][src.z].tileInfo->blocked;
if(i==dest.x && j==dest.y && CGI->mh->ttiles[i][j][src.z].tileInfo->visitable)
{
graph[i][j].accesible = true; //for allowing visiting objects
}
graph[i][j].dist = -1;
graph[i][j].theNodeBefore = NULL;
graph[i][j].visited = false;
graph[i][j].coord.x = i;
graph[i][j].coord.y = j;
graph[i][j].coord.z = dest.z;
if (CGI->mh->ttiles[i][j][src.z].tileInfo->tertype==rock)
{
graph[i][j].accesible = false;
}
if ((blockLandSea) && (CGI->mh->ttiles[i][j][src.z].tileInfo->tertype==water))
{
graph[i][j].accesible = false;
}
else if ((!blockLandSea) && (CGI->mh->ttiles[i][j][src.z].tileInfo->tertype!=water))
{
graph[i][j].accesible = false;
}
if(graph[i][j].accesible)
{
graph[i][j].accesible = CGI->state->players[hero->tempOwner].fogOfWarMap[i][j][src.z];
}
}
}
//graph initialized
graph[src.x][src.y].dist = 0;
std::queue<CPathNode> mq;
mq.push(graph[src.x][src.y]);
unsigned int curDist = 4000000000; //XXX 2 147 483 648 // only in C90 //but numeric limit shows 0-4294967295...confused
while(!mq.empty())
{
CPathNode cp = mq.front();
mq.pop();
if ((cp.coord.x == dest.x) && (cp.coord.y==dest.y))
{
if (cp.dist < curDist)
curDist=cp.dist;
}
else
{
if (cp.dist > curDist)
continue;
}
if(cp.coord.x>0)
{
CPathNode & dp = graph[cp.coord.x-1][cp.coord.y];
processNode(dp, hero, mq, cp, src, false);
}
if(cp.coord.y>0)
{
CPathNode & dp = graph[cp.coord.x][cp.coord.y-1];
processNode(dp, hero, mq, cp, src, false);
}
if(cp.coord.x>0 && cp.coord.y>0)
{
CPathNode & dp = graph[cp.coord.x-1][cp.coord.y-1];
processNode(dp, hero, mq, cp, src, true);
}
if(cp.coord.x<graph.size()-1)
{
CPathNode & dp = graph[cp.coord.x+1][cp.coord.y];
processNode(dp, hero, mq, cp, src, false);
}
if(cp.coord.y<graph[0].size()-1)
{
CPathNode & dp = graph[cp.coord.x][cp.coord.y+1];
processNode(dp, hero, mq, cp, src, false);
}
if(cp.coord.x<graph.size()-1 && cp.coord.y<graph[0].size()-1)
{
CPathNode & dp = graph[cp.coord.x+1][cp.coord.y+1];
processNode(dp, hero, mq, cp, src, true);
}
if(cp.coord.x>0 && cp.coord.y<graph[0].size()-1)
{
CPathNode & dp = graph[cp.coord.x-1][cp.coord.y+1];
processNode(dp, hero, mq, cp, src, true);
}
if(cp.coord.x<graph.size()-1 && cp.coord.y>0)
{
CPathNode & dp = graph[cp.coord.x+1][cp.coord.y-1];
processNode(dp, hero, mq, cp, src, true);
}
}
CPathNode curNode = graph[dest.x][dest.y];
if(!curNode.theNodeBefore)
return NULL;
CPath * ret = new CPath;
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 ret;
}
void CPathfinder::convertPath(CPath * path, unsigned int mode) //mode=0 -> from 'manifest' to 'object'
{
if (mode==0)
{
for (int i=0;i<path->nodes.size();i++)
{
path->nodes[i].coord = CGHeroInstance::convertPosition(path->nodes[i].coord,true);
}
}
}
void CPathfinder::processNode(CPathNode & dp, const CGHeroInstance * hero, std::queue<CPathNode> & mq, const CPathNode & cp, const int3 & src, bool diagonal)
{
const TerrainTile * tinfo = CGI->mh->ttiles[dp.coord.x][dp.coord.y][src.z].tileInfo;
int cost = CGI->state->getMovementCost(hero,cp.coord,dp.coord,hero->movement - cp.dist);
if((dp.dist==-1 || (dp.dist > cp.dist + cost)) && dp.accesible && checkForVisitableDir(cp.coord, dp.coord) && checkForVisitableDir(dp.coord, cp.coord))
{
dp.dist = cp.dist + cost;
dp.theNodeBefore = &graph[cp.coord.x][cp.coord.y];
mq.push(dp);
}
}
bool CPathfinder::checkForVisitableDir(const int3 & src, const int3 & dst) const
{
for(int b=0; b<CGI->mh->ttiles[dst.x][dst.y][dst.z].tileInfo->visitableObjects.size(); ++b) //checking destination tile
{
const TerrainTile * pom = CGI->mh->ttiles[dst.x][dst.y][dst.z].tileInfo;
if(!vstd::contains(pom->blockingObjects, pom->visitableObjects[b]))
continue;
CGDefInfo * di = pom->visitableObjects[b]->defInfo;
if( (dst.x == src.x-1 && dst.y == src.y-1) && !(di->visitDir & (1<<4)) )
{
return false;
}
if( (dst.x == src.x && dst.y == src.y-1) && !(di->visitDir & (1<<5)) )
{
return false;
}
if( (dst.x == src.x+1 && dst.y == src.y-1) && !(di->visitDir & (1<<6)) )
{
return false;
}
if( (dst.x == src.x+1 && dst.y == src.y) && !(di->visitDir & (1<<7)) )
{
return false;
}
if( (dst.x == src.x+1 && dst.y == src.y+1) && !(di->visitDir & (1<<0)) )
{
return false;
}
if( (dst.x == src.x && dst.y == src.y+1) && !(di->visitDir & (1<<1)) )
{
return false;
}
if( (dst.x == src.x-1 && dst.y == src.y+1) && !(di->visitDir & (1<<2)) )
{
return false;
}
if( (dst.x == src.x-1 && dst.y == src.y) && !(di->visitDir & (1<<3)) )
{
return false;
}
}
return true;
}

View File

@ -1,43 +0,0 @@
#ifndef __CPATHFINDER_H__
#define __CPATHFINDER_H__
#include "global.h"
#include <queue>
#include <vector>
class CGHeroInstance;
struct CPathNode
{
bool accesible; //true if a hero can be on this node
int dist; //distance from the first node of searching; -1 is infinity
CPathNode * theNodeBefore;
int3 coord; //coordiantes
bool visited;
};
struct CPath
{
std::vector<CPathNode> nodes; //just get node by node
int3 startPos(); // start point
int3 endPos(); //destination point
};
/**
* main pathfinder class
*/
class CPathfinder
{
private:
std::vector< std::vector<CPathNode> > graph;
void processNode(CPathNode & dp, const CGHeroInstance * hero, std::queue<CPathNode> & mq, const CPathNode & cp, const int3 & src, bool diagonal); //helper function for getPath
bool checkForVisitableDir(const int3 & src, const int3 & dst) const;
public:
CPath * getPath(int3 src, int3 dest, const CGHeroInstance * hero, unsigned char type=0); //calculates path between src and dest; returns pointer to CPath or NULL if path does not exists; type - type of calculation: 0 - positions are normal positions of hero; 1 - given places are tiles blocked by hero
CPath * getPath(const int3 & src, const int3 & dest, const CGHeroInstance * hero, int (*getDist)(int3 & a, int3 & b), unsigned char type=0); //calculates path between src and dest; returns pointer to CPath or NULL if path does not exists; uses getDist to calculate distance; type - type of calculation: 0 - positions are normal positions of hero; 1 - given places are tiles blocked by hero
static void convertPath(CPath * path, unsigned int mode); //mode=0 -> from 'manifest' to 'object'
};
#endif // __CPATHFINDER_H__

View File

@ -7,7 +7,6 @@
#include "CGameInfo.h"
#include "CHeroWindow.h"
#include "CMessage.h"
#include "CPathfinder.h"
#include "CPlayerInterface.h"
//#include "SDL_Extensions.h"
#include "SDL_Extensions.h"
@ -1799,10 +1798,10 @@ SDL_Surface * CPlayerInterface::infoWin(const CGObjectInstance * specific) //spe
return graphics->drawTownInfoWin((const CGTownInstance *)adventureInt->selection);
}
default:
tlog1 << "Strange... selection is neither hero nor town\n";
return NULL;
}
}
return NULL;
}
void CPlayerInterface::handleMouseMotion(SDL_Event *sEvent)
@ -1969,6 +1968,8 @@ int3 CPlayerInterface::repairScreenPos(int3 pos)
}
void CPlayerInterface::heroPrimarySkillChanged(const CGHeroInstance * hero, int which, int val)
{
if(which >= PRIMARY_SKILLS) //no need to redraw infowin if this is experience (exp is treated as prim skill with id==4)
return;
boost::unique_lock<boost::recursive_mutex> un(*pim);
redrawHeroWin(hero);
}
@ -2482,6 +2483,11 @@ void CPlayerInterface::heroBonusChanged( const CGHeroInstance *hero, const HeroB
void CPlayerInterface::redrawHeroWin(const CGHeroInstance * hero)
{
if(!vstd::contains(graphics->heroWins,hero->subID))
{
tlog1 << "Cannot redraw infowindow for hero with subID=" << hero->subID << " - not present in our map\n";
return;
}
SDL_FreeSurface(graphics->heroWins[hero->subID]);
graphics->heroWins[hero->subID] = infoWin(hero);
if (adventureInt->selection == hero)
@ -2490,12 +2496,11 @@ void CPlayerInterface::redrawHeroWin(const CGHeroInstance * hero)
bool CPlayerInterface::moveHero( const CGHeroInstance *h, CPath * path )
{
bool result = false;
if (!h || !path)
return false; //can't find hero
CPathfinder::convertPath(path,0);
bool result = false;
path->convert(0);
stillMoveHero = true;
for(int i=path->nodes.size()-1; i>0; i--)
@ -2637,7 +2642,8 @@ void CHeroList::select(int which)
//recalculationg path in case of something has changed on map
if(items[which].second)
{
CPath * newPath = CGI->pathf->getPath(items[which].second->startPos(), items[which].second->endPos(), items[which].first);
CPath * newPath = LOCPLINT->cb->getPath(items[which].second->startPos(), items[which].second->endPos(), items[which].first);
delete items[which].second;
LOCPLINT->adventureInt->terrain.currentPath = items[which].second = newPath;
}
else

View File

@ -1,4 +1,4 @@
0.7 -> 0.71 (as for r754)
0.7 -> 0.71 (as for r765)
GENERAL:
* fixed scrolling behind window problem (now it's possible to scroll with CTRL + arrows)
* morale/luck system and corresponding sec. skills supported
@ -25,6 +25,7 @@ ADVENTURE INTERFACE:
* new movement cost calculation algorithm
* fixed sight radious calculation
* it's possible to stop hero movement
* faster minimap refreshing
BATTLES:
* partial support for battle obstacles
@ -37,6 +38,7 @@ BATTLES:
* blue glowing border around hovered creature
* made animation on battlefield more smooth
* standing stacks have more static animation
* probably fixed problem with displaying corpses on battlefield
* fixes for two-hex creatures actions
* fixed hero casting spell animation
* corrected stack death animation
@ -62,6 +64,7 @@ TOWN INTERFACE:
* fixed crash occuring when clicking on hero portrait in Tavern Window, minor improvements for Tavern Window
* proper updating resdatabar after building structure in town or buying creatures (non 800x600 res)
* fixed blinking resdatabar in town screen when buying (800x600)
* fixed horde buildings displaying in town hall
PREGAME:
@ -86,6 +89,9 @@ New objects supported:
* Temple
* Watering Hole
* Fountain of Youth
* support for Redwood Observatory
* support for Shrine of Magic Incantation / Gesture / Thought
* support for Sign / Ocean Bottle
AI PLAYER:
Minor improvements and fixes.

View File

@ -112,15 +112,18 @@ void CClient::run()
CPack *pack;
while(1)
{
tlog5 << "Listening... ";
*serv >> pack;
tlog5 << "Received server message of type " << typeid(*pack).name() << std::endl;
tlog5 << "\treceived server message of type " << typeid(*pack).name() << std::endl;
CBaseForCLApply *apply = applier->apps[typeList.getTypeID(pack)];
if(apply)
{
apply->applyOnClBefore(this,pack);
tlog5 << "\tMade first apply on cl\n";
gs->apply(pack);
tlog5 << "\tApplied on gs\n";
apply->applyOnClAfter(this,pack);
tlog5 << "Message successfully applied!\n";
tlog5 << "\tMade second apply on cl\n";
}
else
{
@ -171,7 +174,7 @@ void CClient::load( const std::string & fname )
for(std::map<ui8,CGameInterface *>::iterator i = playerint.begin(); i!=playerint.end(); i++)
{
delete i->second; //delete player interfaces
}
}
tlog0 <<"Deleting old data: "<<tmh.getDif()<<std::endl;
char portc[10];

View File

@ -24,7 +24,6 @@ vcmiclient_SOURCES = \
../CMessage.cpp \
../CMT.cpp \
../hch/CMusicHandler.cpp \
../CPathfinder.cpp \
../CPlayerInterface.cpp \
../CPreGame.cpp \
../hch/CSndHandler.cpp \
@ -56,7 +55,6 @@ vcmiclient_SOURCES = \
../CMessage.h \
../hch/CMusicHandler.h \
../hch/CObjectHandler.h \
../CPathfinder.h \
../CPlayerInterface.h \
../CPreGame.h \
../hch/CSndHandler.h \

View File

@ -36,7 +36,13 @@ void SetResource::applyCl( CClient *cl )
void SetPrimSkill::applyCl( CClient *cl )
{
cl->playerint[GS(cl)->getHero(id)->tempOwner]->heroPrimarySkillChanged(GS(cl)->getHero(id),which,val);
const CGHeroInstance *h = GS(cl)->getHero(id);
if(!h)
{
tlog1 << "Cannot find hero with ID " << id << std::endl;
return;
}
INTERFACE_CALL_IF_PRESENT(h->tempOwner,heroPrimarySkillChanged,h,which,val);
}
void SetSecSkill::applyCl( CClient *cl )

View File

@ -338,10 +338,6 @@
RelativePath="..\hch\CMusicHandler.cpp"
>
</File>
<File
RelativePath="..\CPathfinder.cpp"
>
</File>
<File
RelativePath="..\CPlayerInterface.cpp"
>
@ -476,10 +472,6 @@
RelativePath="..\hch\CObjectHandler.h"
>
</File>
<File
RelativePath="..\CPathfinder.h"
>
</File>
<File
RelativePath="..\CPlayerInterface.h"
>

View File

@ -257,6 +257,15 @@ void CGeneralTextHandler::load()
restypes.push_back(temp);
}
tlog5 << "\t\tReading RANDSIGN \n";
buf = bitmaph->getTextFile("RANDSIGN.TXT");
it=0;
while (it<buf.length()-1)
{
loadToIt(temp,buf,it,3);
randsign.push_back(temp);
}
tlog5 << "\t\tReading ZCRGN1 \n";
buf = bitmaph->getTextFile("ZCRGN1.TXT");
it=0;

View File

@ -45,6 +45,7 @@ public:
std::vector<std::string> advobtxt;
std::vector<std::string> xtrainfo;
std::vector<std::string> restypes;
std::vector<std::string> randsign;
std::vector<std::pair<std::string,std::string> > mines; //first - name; second - event description
//sec skills

View File

@ -1493,14 +1493,17 @@ void CGArtifact::onHeroVisit( const CGHeroInstance * h ) const
{
if(!army.slots.size())
{
InfoWindow iw;
iw.player = h->tempOwner;
iw.components.push_back(Component(4,subID,0,0));
if(message.length())
iw.text << message;
else
iw.text << std::pair<ui8,ui32>(12,subID);
cb->showInfoDialog(&iw);
if(ID == 5)
{
InfoWindow iw;
iw.player = h->tempOwner;
iw.components.push_back(Component(4,subID,0,0));
if(message.length())
iw.text << message;
else
iw.text << std::pair<ui8,ui32>(12,subID);
cb->showInfoDialog(&iw);
}
pick(h);
}
else
@ -1521,7 +1524,14 @@ void CGArtifact::onHeroVisit( const CGHeroInstance * h ) const
void CGArtifact::pick(const CGHeroInstance * h) const
{
cb->giveHeroArtifact(subID,h->id,-2);
if(ID == 5) //Artifact
{
cb->giveHeroArtifact(subID,h->id,-2);
}
else if(ID == 93) // Spell scroll
{
//TODO: support for the spell scroll
}
cb->removeObject(id);
}
@ -1996,3 +2006,18 @@ const std::string & CGShrine::getHoverText() const
}
return hoverName;
}
void CGSignBottle::initObj()
{
//if no text is set than we pick random from the predefined ones
if(!message.size())
message = VLC->generaltexth->randsign[ran()%VLC->generaltexth->randsign.size()];
}
void CGSignBottle::onHeroVisit( const CGHeroInstance * h ) const
{
InfoWindow iw;
iw.player = h->getOwner();
iw.text << message;
cb->showInfoDialog(&iw);
}

View File

@ -420,10 +420,12 @@ public:
class DLL_EXPORT CGSignBottle : public CGObjectInstance //signs and ocean bottles
{
//TODO: generate default message if sign is 'empty'
public:
std::string message;
void onHeroVisit(const CGHeroInstance * h) const;
void initObj();
template <typename Handler> void serialize(Handler &h, const int version)
{
h & static_cast<CGObjectInstance&>(*this);

View File

@ -19,7 +19,7 @@
#include <boost/mpl/identity.hpp>
#include <boost/type_traits/is_array.hpp>
const ui32 version = 703;
const ui32 version = 704;
class CConnection;
namespace mpl = boost::mpl;

View File

@ -1162,7 +1162,7 @@ void CGameHandler::moveHero(si32 hid, int3 dst, ui8 instant, ui8 asker)
tlog5 << "Player " <<int(asker) << " wants to move hero "<< hid << " from "<< h->pos << " to " << dst << std::endl;
int3 hmpos = dst + int3(-1,0,0);
TerrainTile t = gs->map->terrain[hmpos.x][hmpos.y][hmpos.z];
int cost = gs->getMovementCost(h,h->pos,dst,h->movement);
int cost = gs->getMovementCost(h,h->getPosition(false),CGHeroInstance::convertPosition(dst,false),h->movement);
//result structure for start - movement failed, no move points used
TryMoveHero tmh;
@ -1993,11 +1993,11 @@ void CGameHandler::makeBattleAction( BattleAction &ba )
if( !(
(BattleInfo::mutualPosition(curpos, enemypos) >= 0) //front <=> front
|| (curStack->creature->isDoubleWide() //back <=> front
&& BattleInfo::mutualPosition(curpos + (curStack->attackerOwned ? -1 : 1), enemypos) >= 0)
&& BattleInfo::mutualPosition(curpos + (curStack->attackerOwned ? -1 : 1), enemypos) >= 0)
|| (stackAtEnd->creature->isDoubleWide() //front <=> back
&& BattleInfo::mutualPosition(curpos, enemypos + (stackAtEnd->attackerOwned ? -1 : 1)) >= 0)
&& BattleInfo::mutualPosition(curpos, enemypos + (stackAtEnd->attackerOwned ? -1 : 1)) >= 0)
|| (stackAtEnd->creature->isDoubleWide() && curStack->creature->isDoubleWide()//back <=> back
&& BattleInfo::mutualPosition(curpos + (curStack->attackerOwned ? -1 : 1), enemypos + (stackAtEnd->attackerOwned ? -1 : 1)) >= 0)
&& BattleInfo::mutualPosition(curpos + (curStack->attackerOwned ? -1 : 1), enemypos + (stackAtEnd->attackerOwned ? -1 : 1)) >= 0)
)
)
{