From fceeb05e16db931f35478d409336ea0069c30ab5 Mon Sep 17 00:00:00 2001 From: mateuszb Date: Fri, 28 Aug 2009 09:03:58 +0000 Subject: [PATCH] * a bit of pathfinder interface redesign * a few fixes for sieges * better wall parts' positions by Ivan --- CCallback.cpp | 2 +- client/CBattleInterface.cpp | 12 ++- config/wall_pos.txt | 198 ++++++++++++++++++------------------ hch/CObjectHandler.cpp | 2 +- lib/CGameState.cpp | 145 +++++++++++++++++++++++++- lib/CGameState.h | 24 +++++ 6 files changed, 279 insertions(+), 104 deletions(-) diff --git a/CCallback.cpp b/CCallback.cpp index 21a98ec13..2aa9036a0 100644 --- a/CCallback.cpp +++ b/CCallback.cpp @@ -606,7 +606,7 @@ const CGTownInstance *CCallback::battleGetDefendedTown() if(!gs->curB || gs->curB->tid == -1) return NULL; - return gs->map->towns[gs->curB->tid]; + return static_cast(gs->map->objects[gs->curB->tid]); } ui8 CCallback::battleGetWallState(int partOfWall) diff --git a/client/CBattleInterface.cpp b/client/CBattleInterface.cpp index a4cd147d8..fcda8156e 100644 --- a/client/CBattleInterface.cpp +++ b/client/CBattleInterface.cpp @@ -3234,7 +3234,17 @@ std::string CBattleInterface::SiegeHelper::getSiegeName(ui16 what, ui16 additInf case 0: //background return "SG" + townTypeInfixes[town->town->typeID] + "BACK.BMP"; case 1: //background wall - return "SG" + townTypeInfixes[town->town->typeID] + "TPW1.BMP"; + { + switch(town->town->typeID) + { + case 5: case 4: case 1: case 6: + return "SG" + townTypeInfixes[town->town->typeID] + "TPW1.BMP"; + case 0: case 2: case 3: case 7: case 8: + return "SG" + townTypeInfixes[town->town->typeID] + "TPWL.BMP"; + default: + return ""; + } + } case 2: //keep return "SG" + townTypeInfixes[town->town->typeID] + "MAN" + addit + ".BMP"; case 3: //bottom tower diff --git a/config/wall_pos.txt b/config/wall_pos.txt index 89adbec9e..97ae6703d 100644 --- a/config/wall_pos.txt +++ b/config/wall_pos.txt @@ -1,100 +1,100 @@ //this file is a description of positions of wall parts' positions, following lines contain positions of: bottom tower, bottom wall, wall below gate, wall over gate, upper wall, upper tower, gate, gate arch, bottom static wall and upper static wall (x, y) -//castle -602 494 -557 469 -474 300 -491 188 -544 57 -567 16 -391 260 -471 164 -518 305 -500 54 -//rampart -602 494 -557 469 -474 300 -491 188 -544 57 -567 16 -391 260 -471 164 -518 305 -500 54 -//tower -602 494 -557 469 -474 300 -491 188 -544 57 -567 16 -391 260 -471 164 -518 305 -500 54 -//inferno -602 494 -557 469 -474 300 -491 188 -544 57 -567 16 -391 260 -471 164 -518 305 -500 54 -//necropolis -602 494 -557 469 -474 300 -491 188 -544 57 -567 16 -391 260 -471 164 -518 305 -500 54 -//dungeon -602 494 -557 469 -474 300 -491 188 -544 57 -567 16 -391 260 -471 164 -518 305 -500 54 -//stronghold -602 494 -557 469 -474 300 -491 188 -544 57 -567 16 -391 260 -471 164 -518 305 -500 54 -//fortress -602 494 -557 469 -474 300 -491 188 -544 57 -567 16 -391 260 -471 164 -518 305 -500 54 -//conflux -602 494 -557 469 -474 300 -491 188 -544 57 -567 16 -391 260 -471 164 -518 305 -500 54 +//Castle +601 500 +528 350 +468 291 +469 127 +523 32 +568 35 +399 274 +476 238 +511 347 +488 79 +//Rampart +593 511 +548 451 +468 309 +468 186 +529 57 +565 31 +403 271 +459 220 +509 364 +491 103 +//Tower +591 516 +547 452 +474 298 +487 190 +546 66 +579 36 +400 253 +470 187 +516 365 +513 79 +//Inferno +594 514 +560 451 +484 316 +479 151 +531 71 +568 27 +408 254 +476 221 +521 376 +501 92 +//Necropolis +591 512 +535 445 +477 323 +486 164 +542 66 +560 26 +401 262 +473 240 +508 372 +503 97 +//Dungeon +599 495 +558 448 +470 296 +476 180 +522 56 +564 15 +395 260 +470 164 +521 305 +493 53 +//Stronghold +585 508 +552 440 +482 304 +475 189 +533 69 +567 30 +407 266 +477 235 +510 380 +498 107 +//Fortress +599 505 +545 441 +486 306 +497 184 +525 80 +547 27 +392 253 +482 236 +521 382 +507 130 +//Conflux +607 505 +508 346 +467 299 +470 147 +520 41 +575 28 +408 254 +485 232 +508 346 +489 97 diff --git a/hch/CObjectHandler.cpp b/hch/CObjectHandler.cpp index 2a586a6e8..38266d232 100644 --- a/hch/CObjectHandler.cpp +++ b/hch/CObjectHandler.cpp @@ -457,7 +457,7 @@ unsigned int CGHeroInstance::getTileCost(const TerrainTile &dest, const TerrainT } else { - ret = std::max(type->heroClass->terrCosts[dest.tertype],type->heroClass->terrCosts[from.tertype]); //take cost of worse of two tiles + ret = type->heroClass->terrCosts[from.tertype]; ret = std::max(ret - 25*unsigned(getSecSkillLevel(0)), 100u); //reduce 25% of terrain penalty for each pathfinding level } return ret; diff --git a/lib/CGameState.cpp b/lib/CGameState.cpp index 6948417b8..d27d03779 100644 --- a/lib/CGameState.cpp +++ b/lib/CGameState.cpp @@ -1590,10 +1590,10 @@ 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) //it's diagonal move + if(src.x != dest.x && src.y != dest.y) //it's diagonal move { int old = ret; - ret *= 1.414; + 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) { @@ -1831,6 +1831,147 @@ 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 > > &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 mq; +// mq.push(&graph[src.x][src.y][src.z]); +// +// ui32 curDist = 0xffffffff; //total cost of path - init with max possible val +// +// std::vector 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; +//} + bool CGameState::isVisible(int3 pos, int player) { if(player == 255) //neutral player diff --git a/lib/CGameState.h b/lib/CGameState.h index 37be40dc6..016db36fd 100644 --- a/lib/CGameState.h +++ b/lib/CGameState.h @@ -241,6 +241,19 @@ struct CPathNode bool visited; }; +struct CGPathNode +{ + enum {ACCESSIBLE=1, VISITABLE, BLOCKVIS, BLOCKED}; //BLOCKVIS - visitable from neighbourign tile but not passable + ui8 land; + ui8 accessible; //the enum above + ui8 turns; + ui32 moveRemains; + CPathNode * theNodeBefore; + int3 coord; //coordiantes + CGPathNode(); +}; + + struct DLL_EXPORT CPath { std::vector nodes; //just get node by node @@ -250,6 +263,16 @@ struct DLL_EXPORT CPath void convert(ui8 mode); //mode=0 -> from 'manifest' to 'object' }; +struct CPathsInfo +{ + int3 sizes; + CGPathNode ***nodes; //[w][h][level] + + void getPath(const int3 &src, const int3 &dst, CPath &out); + CPathsInfo(const int3 &sizes); + ~CPathsInfo(); +}; + class DLL_EXPORT CGameState { public: @@ -299,6 +322,7 @@ public: 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 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 bool isVisible(int3 pos, int player); bool isVisible(const CGObjectInstance *obj, int player);