CPathfinder.cpp 28 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099
  1. #include "StdInc.h"
  2. #include "CPathfinder.h"
  3. #include "CHeroHandler.h"
  4. #include "mapping/CMap.h"
  5. #include "CGameState.h"
  6. #include "mapObjects/CGHeroInstance.h"
  7. #include "GameConstants.h"
  8. #include "CStopWatch.h"
  9. #include "CConfigHandler.h"
  10. /*
  11. * CPathfinder.cpp, part of VCMI engine
  12. *
  13. * Authors: listed in file AUTHORS in main folder
  14. *
  15. * License: GNU General Public License v2.0 or later
  16. * Full text of license available in license.txt file, in main folder
  17. *
  18. */
  19. CPathfinder::PathfinderOptions::PathfinderOptions()
  20. {
  21. useFlying = settings["pathfinder"]["layers"]["flying"].Bool();
  22. useWaterWalking = settings["pathfinder"]["layers"]["waterWalking"].Bool();
  23. useEmbarkAndDisembark = settings["pathfinder"]["layers"]["sailing"].Bool();
  24. useTeleportTwoWay = settings["pathfinder"]["teleports"]["twoWay"].Bool();
  25. useTeleportOneWay = settings["pathfinder"]["teleports"]["oneWay"].Bool();
  26. useTeleportOneWayRandom = settings["pathfinder"]["teleports"]["oneWayRandom"].Bool();
  27. useTeleportWhirlpool = settings["pathfinder"]["teleports"]["whirlpool"].Bool();
  28. useCastleGate = settings["pathfinder"]["teleports"]["castleGate"].Bool();
  29. lightweightFlyingMode = settings["pathfinder"]["lightweightFlyingMode"].Bool();
  30. oneTurnSpecialLayersLimit = settings["pathfinder"]["oneTurnSpecialLayersLimit"].Bool();
  31. originalMovementRules = settings["pathfinder"]["originalMovementRules"].Bool();
  32. }
  33. CPathfinder::CPathfinder(CPathsInfo & _out, CGameState * _gs, const CGHeroInstance * _hero)
  34. : CGameInfoCallback(_gs, boost::optional<PlayerColor>()), out(_out), hero(_hero), FoW(getPlayerTeam(hero->tempOwner)->fogOfWarMap)
  35. {
  36. assert(hero);
  37. assert(hero == getHero(hero->id));
  38. out.hero = hero;
  39. out.hpos = hero->getPosition(false);
  40. if(!isInTheMap(out.hpos)/* || !gs->map->isInTheMap(dest)*/) //check input
  41. {
  42. logGlobal->errorStream() << "CGameState::calculatePaths: Hero outside the gs->map? How dare you...";
  43. throw std::runtime_error("Wrong checksum");
  44. }
  45. hlp = make_unique<CPathfinderHelper>(hero, options);
  46. initializeGraph();
  47. neighbourTiles.reserve(8);
  48. neighbours.reserve(16);
  49. }
  50. void CPathfinder::calculatePaths()
  51. {
  52. auto passOneTurnLimitCheck = [&](bool shouldCheck) -> bool
  53. {
  54. if(options.oneTurnSpecialLayersLimit && shouldCheck)
  55. {
  56. if((cp->layer == ELayer::AIR || cp->layer == ELayer::WATER)
  57. && cp->accessible != CGPathNode::ACCESSIBLE)
  58. {
  59. return false;
  60. }
  61. }
  62. return true;
  63. };
  64. auto isBetterWay = [&](int remains, int turn) -> bool
  65. {
  66. if(dp->turns == 0xff) //we haven't been here before
  67. return true;
  68. else if(dp->turns > turn)
  69. return true;
  70. else if(dp->turns >= turn && dp->moveRemains < remains) //this route is faster
  71. return true;
  72. return false;
  73. };
  74. //logGlobal->infoStream() << boost::format("Calculating paths for hero %s (adress %d) of player %d") % hero->name % hero % hero->tempOwner;
  75. //initial tile - set cost on 0 and add to the queue
  76. CGPathNode * initialNode = out.getNode(out.hpos, hero->boat ? ELayer::SAIL : ELayer::LAND);
  77. initialNode->turns = 0;
  78. initialNode->moveRemains = hero->movement;
  79. pq.push(initialNode);
  80. while(!pq.empty())
  81. {
  82. cp = pq.top();
  83. pq.pop();
  84. cp->locked = true;
  85. int movement = cp->moveRemains, turn = cp->turns;
  86. hlp->updateTurnInfo(turn);
  87. if(!movement)
  88. {
  89. hlp->updateTurnInfo(++turn);
  90. movement = hlp->getMaxMovePoints(cp->layer);
  91. if(!passOneTurnLimitCheck(true))
  92. continue;
  93. }
  94. ct = &gs->map->getTile(cp->coord);
  95. ctObj = ct->topVisitableObj(isSourceInitialPosition());
  96. //add accessible neighbouring nodes to the queue
  97. addNeighbours();
  98. for(auto & neighbour : neighbours)
  99. {
  100. dt = &gs->map->getTile(neighbour);
  101. dtObj = dt->topVisitableObj();
  102. for(ELayer i = ELayer::LAND; i <= ELayer::AIR; i.advance(1))
  103. {
  104. if(!hlp->isLayerAvailable(i))
  105. continue;
  106. if(cp->layer != i && !isLayerTransitionPossible(i))
  107. continue;
  108. dp = out.getNode(neighbour, i);
  109. if(dp->locked)
  110. continue;
  111. if(dp->accessible == CGPathNode::NOT_SET)
  112. continue;
  113. if(cp->layer != i && !isLayerTransitionPossible())
  114. continue;
  115. if(!isMovementToDestPossible())
  116. continue;
  117. destAction = getDestAction();
  118. int cost = CPathfinderHelper::getMovementCost(hero, cp->coord, dp->coord, ct, dt, movement, hlp->getTurnInfo());
  119. int remains = movement - cost;
  120. if(destAction == CGPathNode::EMBARK || destAction == CGPathNode::DISEMBARK)
  121. {
  122. remains = hero->movementPointsAfterEmbark(movement, cost, destAction - 1, hlp->getTurnInfo());
  123. cost = movement - remains;
  124. }
  125. int turnAtNextTile = turn;
  126. if(remains < 0)
  127. {
  128. //occurs rarely, when hero with low movepoints tries to leave the road
  129. hlp->updateTurnInfo(++turnAtNextTile);
  130. int moveAtNextTile = hlp->getMaxMovePoints(i);
  131. cost = CPathfinderHelper::getMovementCost(hero, cp->coord, dp->coord, ct, dt, moveAtNextTile, hlp->getTurnInfo()); //cost must be updated, movement points changed :(
  132. remains = moveAtNextTile - cost;
  133. }
  134. if(isBetterWay(remains, turnAtNextTile)
  135. && passOneTurnLimitCheck(cp->turns != turnAtNextTile || !remains))
  136. {
  137. assert(dp != cp->theNodeBefore); //two tiles can't point to each other
  138. dp->moveRemains = remains;
  139. dp->turns = turnAtNextTile;
  140. dp->theNodeBefore = cp;
  141. dp->action = destAction;
  142. if(isMovementAfterDestPossible())
  143. pq.push(dp);
  144. }
  145. }
  146. } //neighbours loop
  147. //just add all passable teleport exits
  148. addTeleportExits();
  149. for(auto & neighbour : neighbours)
  150. {
  151. dp = out.getNode(neighbour, cp->layer);
  152. if(dp->locked)
  153. continue;
  154. if(isBetterWay(movement, turn))
  155. {
  156. dp->moveRemains = movement;
  157. dp->turns = turn;
  158. dp->theNodeBefore = cp;
  159. dp->action = CGPathNode::NORMAL;
  160. pq.push(dp);
  161. }
  162. }
  163. } //queue loop
  164. }
  165. void CPathfinder::addNeighbours()
  166. {
  167. neighbours.clear();
  168. neighbourTiles.clear();
  169. CPathfinderHelper::getNeighbours(gs->map, *ct, cp->coord, neighbourTiles, boost::logic::indeterminate, cp->layer == ELayer::SAIL);
  170. if(isSourceVisitableObj())
  171. {
  172. for(int3 tile: neighbourTiles)
  173. {
  174. if(canMoveBetween(tile, ctObj->visitablePos()))
  175. neighbours.push_back(tile);
  176. }
  177. }
  178. else
  179. vstd::concatenate(neighbours, neighbourTiles);
  180. }
  181. void CPathfinder::addTeleportExits()
  182. {
  183. neighbours.clear();
  184. if(!isSourceVisitableObj())
  185. return;
  186. const CGTeleport * objTeleport = dynamic_cast<const CGTeleport *>(ctObj);
  187. if(isAllowedTeleportEntrance(objTeleport))
  188. {
  189. for(auto objId : getTeleportChannelExits(objTeleport->channel, hero->tempOwner))
  190. {
  191. auto obj = getObj(objId);
  192. if(dynamic_cast<const CGWhirlpool *>(obj))
  193. {
  194. auto pos = obj->getBlockedPos();
  195. for(auto p : pos)
  196. {
  197. if(gs->map->getTile(p).topVisitableId() == obj->ID)
  198. neighbours.push_back(p);
  199. }
  200. }
  201. else if(CGTeleport::isExitPassable(gs, hero, obj))
  202. neighbours.push_back(obj->visitablePos());
  203. }
  204. }
  205. if(options.useCastleGate
  206. && (ctObj->ID == Obj::TOWN && ctObj->subID == ETownType::INFERNO
  207. && getPlayerRelations(hero->tempOwner, ctObj->tempOwner) != PlayerRelations::ENEMIES))
  208. {
  209. /// TODO: Find way to reuse CPlayerSpecificInfoCallback::getTownsInfo
  210. /// This may be handy if we allow to use teleportation to friendly towns
  211. auto towns = getPlayer(hero->tempOwner)->towns;
  212. for(const auto & town : towns)
  213. {
  214. if(town->id != ctObj->id && town->visitingHero == nullptr
  215. && town->hasBuilt(BuildingID::CASTLE_GATE, ETownType::INFERNO))
  216. {
  217. neighbours.push_back(town->visitablePos());
  218. }
  219. }
  220. }
  221. }
  222. bool CPathfinder::isLayerTransitionPossible(const ELayer destLayer) const
  223. {
  224. /// No layer transition allowed when previous node action is BATTLE
  225. if(cp->action == CGPathNode::BATTLE)
  226. return false;
  227. switch(cp->layer)
  228. {
  229. case ELayer::LAND:
  230. if(destLayer != ELayer::AIR)
  231. return true;
  232. if(!options.lightweightFlyingMode || isSourceInitialPosition())
  233. return true;
  234. break;
  235. case ELayer::SAIL:
  236. if(destLayer == ELayer::LAND && dt->isCoastal())
  237. return true;
  238. break;
  239. case ELayer::AIR:
  240. if(destLayer == ELayer::LAND)
  241. return true;
  242. break;
  243. case ELayer::WATER:
  244. if(destLayer == ELayer::LAND)
  245. return true;
  246. break;
  247. }
  248. return false;
  249. }
  250. bool CPathfinder::isLayerTransitionPossible() const
  251. {
  252. switch(cp->layer)
  253. {
  254. case ELayer::LAND:
  255. if(dp->layer == ELayer::SAIL)
  256. {
  257. /// Cannot enter empty water tile from land -> it has to be visitable
  258. if(dp->accessible == CGPathNode::ACCESSIBLE)
  259. return false;
  260. }
  261. break;
  262. case ELayer::SAIL:
  263. //tile must be accessible -> exception: unblocked blockvis tiles -> clear but guarded by nearby monster coast
  264. if((dp->accessible != CGPathNode::ACCESSIBLE && (dp->accessible != CGPathNode::BLOCKVIS || dt->blocked))
  265. || dt->visitable) //TODO: passableness problem -> town says it's passable (thus accessible) but we obviously can't disembark onto town gate
  266. {
  267. return false;
  268. }
  269. break;
  270. case ELayer::AIR:
  271. if(options.originalMovementRules)
  272. {
  273. if((cp->accessible != CGPathNode::ACCESSIBLE &&
  274. cp->accessible != CGPathNode::VISITABLE) &&
  275. (dp->accessible != CGPathNode::VISITABLE &&
  276. dp->accessible != CGPathNode::ACCESSIBLE))
  277. {
  278. return false;
  279. }
  280. }
  281. else if(cp->accessible != CGPathNode::ACCESSIBLE && dp->accessible != CGPathNode::ACCESSIBLE)
  282. {
  283. /// Hero that fly can only land on accessible tiles
  284. return false;
  285. }
  286. break;
  287. }
  288. return true;
  289. }
  290. bool CPathfinder::isMovementToDestPossible() const
  291. {
  292. if(dp->accessible == CGPathNode::BLOCKED)
  293. return false;
  294. switch(dp->layer)
  295. {
  296. case ELayer::LAND:
  297. if(!canMoveBetween(cp->coord, dp->coord))
  298. return false;
  299. if(isSourceGuarded())
  300. {
  301. if(!(options.originalMovementRules && cp->layer == ELayer::AIR) &&
  302. !isDestinationGuardian()) // Can step into tile of guard
  303. {
  304. return false;
  305. }
  306. }
  307. break;
  308. case ELayer::SAIL:
  309. if(!canMoveBetween(cp->coord, dp->coord))
  310. return false;
  311. if(isSourceGuarded())
  312. {
  313. // Hero embarked a boat standing on a guarded tile -> we must allow to move away from that tile
  314. if(cp->action != CGPathNode::EMBARK && !isDestinationGuardian())
  315. return false;
  316. }
  317. if(cp->layer == ELayer::LAND)
  318. {
  319. if(!isDestVisitableObj())
  320. return false;
  321. if(dtObj->ID != Obj::BOAT && dtObj->ID != Obj::HERO)
  322. return false;
  323. }
  324. else if(isDestVisitableObj() && dtObj->ID == Obj::BOAT)
  325. {
  326. /// Hero in boat can't visit empty boats
  327. return false;
  328. }
  329. break;
  330. case ELayer::WATER:
  331. if(!canMoveBetween(cp->coord, dp->coord) || dp->accessible != CGPathNode::ACCESSIBLE)
  332. return false;
  333. if(isDestinationGuarded())
  334. return false;
  335. break;
  336. }
  337. return true;
  338. }
  339. bool CPathfinder::isMovementAfterDestPossible() const
  340. {
  341. switch(destAction)
  342. {
  343. /// TODO: Investigate what kind of limitation is possible to apply on movement from visitable tiles
  344. /// Likely in many cases we don't need to add visitable tile to queue when hero don't fly
  345. case CGPathNode::VISIT:
  346. {
  347. /// For now we only add visitable tile into queue when it's teleporter that allow transit
  348. /// Movement from visitable tile when hero is standing on it is possible into any layer
  349. const CGTeleport * objTeleport = dynamic_cast<const CGTeleport *>(dtObj);
  350. if(isAllowedTeleportEntrance(objTeleport))
  351. {
  352. /// For now we'll always allow transit over teleporters
  353. /// Transit over whirlpools only allowed when hero protected
  354. return true;
  355. }
  356. else if(dtObj->ID == Obj::GARRISON || dtObj->ID == Obj::GARRISON2)
  357. {
  358. /// Transit via unguarded garrisons is always possible
  359. return true;
  360. }
  361. break;
  362. }
  363. case CGPathNode::NORMAL:
  364. return true;
  365. case CGPathNode::EMBARK:
  366. if(options.useEmbarkAndDisembark)
  367. return true;
  368. break;
  369. case CGPathNode::DISEMBARK:
  370. if(options.useEmbarkAndDisembark && !isDestinationGuarded())
  371. return true;
  372. break;
  373. case CGPathNode::BATTLE:
  374. /// Movement after BATTLE action only possible from guarded tile to guardian tile
  375. if(isDestinationGuarded())
  376. return true;
  377. break;
  378. }
  379. return false;
  380. }
  381. CGPathNode::ENodeAction CPathfinder::getDestAction() const
  382. {
  383. CGPathNode::ENodeAction action = CGPathNode::NORMAL;
  384. switch(dp->layer)
  385. {
  386. case ELayer::LAND:
  387. if(cp->layer == ELayer::SAIL)
  388. {
  389. // TODO: Handle dismebark into guarded areaa
  390. action = CGPathNode::DISEMBARK;
  391. break;
  392. }
  393. /// don't break - next case shared for both land and sail layers
  394. case ELayer::SAIL:
  395. if(isDestVisitableObj())
  396. {
  397. auto objRel = getPlayerRelations(dtObj->tempOwner, hero->tempOwner);
  398. if(dtObj->ID == Obj::BOAT)
  399. action = CGPathNode::EMBARK;
  400. else if(dtObj->ID == Obj::HERO)
  401. {
  402. if(objRel == PlayerRelations::ENEMIES)
  403. action = CGPathNode::BATTLE;
  404. else
  405. action = CGPathNode::BLOCKING_VISIT;
  406. }
  407. else if(dtObj->ID == Obj::TOWN && objRel == PlayerRelations::ENEMIES)
  408. {
  409. const CGTownInstance * townObj = dynamic_cast<const CGTownInstance *>(dtObj);
  410. if(townObj->armedGarrison())
  411. action = CGPathNode::BATTLE;
  412. }
  413. else if(dtObj->ID == Obj::GARRISON || dtObj->ID == Obj::GARRISON2)
  414. {
  415. const CGGarrison * garrisonObj = dynamic_cast<const CGGarrison *>(dtObj);
  416. if((garrisonObj->stacksCount() && objRel == PlayerRelations::ENEMIES) || isDestinationGuarded(true))
  417. action = CGPathNode::BATTLE;
  418. }
  419. else if(isDestinationGuardian())
  420. action = CGPathNode::BATTLE;
  421. else if(dtObj->blockVisit && !(options.useCastleGate && dtObj->ID == Obj::TOWN))
  422. action = CGPathNode::BLOCKING_VISIT;
  423. if(action == CGPathNode::NORMAL)
  424. {
  425. if(options.originalMovementRules && isDestinationGuarded())
  426. action = CGPathNode::BATTLE;
  427. else
  428. action = CGPathNode::VISIT;
  429. }
  430. }
  431. else if(isDestinationGuarded())
  432. action = CGPathNode::BATTLE;
  433. break;
  434. }
  435. return action;
  436. }
  437. bool CPathfinder::isSourceInitialPosition() const
  438. {
  439. return cp->coord == out.hpos;
  440. }
  441. bool CPathfinder::isSourceVisitableObj() const
  442. {
  443. return isVisitableObj(ctObj, cp->layer);
  444. }
  445. bool CPathfinder::isSourceGuarded() const
  446. {
  447. /// Hero can move from guarded tile if movement started on that tile
  448. /// It's possible at least in these cases:
  449. /// - Map start with hero on guarded tile
  450. /// - Dimention door used
  451. /// TODO: check what happen when there is several guards
  452. if(gs->guardingCreaturePosition(cp->coord).valid() && !isSourceInitialPosition())
  453. {
  454. return true;
  455. }
  456. return false;
  457. }
  458. bool CPathfinder::isDestVisitableObj() const
  459. {
  460. return isVisitableObj(dtObj, dp->layer);
  461. }
  462. bool CPathfinder::isDestinationGuarded(const bool ignoreAccessibility) const
  463. {
  464. /// isDestinationGuarded is exception needed for garrisons.
  465. /// When monster standing behind garrison it's visitable and guarded at the same time.
  466. if(gs->guardingCreaturePosition(dp->coord).valid()
  467. && (ignoreAccessibility || dp->accessible == CGPathNode::BLOCKVIS))
  468. {
  469. return true;
  470. }
  471. return false;
  472. }
  473. bool CPathfinder::isDestinationGuardian() const
  474. {
  475. return gs->guardingCreaturePosition(cp->coord) == dp->coord;
  476. }
  477. void CPathfinder::initializeGraph()
  478. {
  479. auto updateNode = [&](int3 pos, ELayer layer, const TerrainTile * tinfo)
  480. {
  481. auto node = out.getNode(pos, layer);
  482. auto accessibility = evaluateAccessibility(pos, tinfo, layer);
  483. node->update(pos, layer, accessibility);
  484. };
  485. int3 pos;
  486. for(pos.x=0; pos.x < out.sizes.x; ++pos.x)
  487. {
  488. for(pos.y=0; pos.y < out.sizes.y; ++pos.y)
  489. {
  490. for(pos.z=0; pos.z < out.sizes.z; ++pos.z)
  491. {
  492. const TerrainTile * tinfo = &gs->map->getTile(pos);
  493. switch(tinfo->terType)
  494. {
  495. case ETerrainType::ROCK:
  496. break;
  497. case ETerrainType::WATER:
  498. updateNode(pos, ELayer::SAIL, tinfo);
  499. if(options.useFlying)
  500. updateNode(pos, ELayer::AIR, tinfo);
  501. if(options.useWaterWalking)
  502. updateNode(pos, ELayer::WATER, tinfo);
  503. break;
  504. default:
  505. updateNode(pos, ELayer::LAND, tinfo);
  506. if(options.useFlying)
  507. updateNode(pos, ELayer::AIR, tinfo);
  508. break;
  509. }
  510. }
  511. }
  512. }
  513. }
  514. CGPathNode::EAccessibility CPathfinder::evaluateAccessibility(const int3 & pos, const TerrainTile * tinfo, const ELayer layer) const
  515. {
  516. if(tinfo->terType == ETerrainType::ROCK || !FoW[pos.x][pos.y][pos.z])
  517. return CGPathNode::BLOCKED;
  518. switch(layer)
  519. {
  520. case ELayer::LAND:
  521. case ELayer::SAIL:
  522. if(tinfo->visitable)
  523. {
  524. if(tinfo->visitableObjects.front()->ID == Obj::SANCTUARY && tinfo->visitableObjects.back()->ID == Obj::HERO && tinfo->visitableObjects.back()->tempOwner != hero->tempOwner) //non-owned hero stands on Sanctuary
  525. {
  526. return CGPathNode::BLOCKED;
  527. }
  528. else
  529. {
  530. for(const CGObjectInstance * obj : tinfo->visitableObjects)
  531. {
  532. if(obj->passableFor(hero->tempOwner))
  533. {
  534. return CGPathNode::ACCESSIBLE;
  535. }
  536. else if(obj->blockVisit)
  537. {
  538. return CGPathNode::BLOCKVIS;
  539. }
  540. else if(canSeeObj(obj))
  541. {
  542. return CGPathNode::VISITABLE;
  543. }
  544. }
  545. }
  546. }
  547. else if(guardingCreaturePosition(pos).valid() && !tinfo->blocked)
  548. {
  549. // Monster close by; blocked visit for battle
  550. return CGPathNode::BLOCKVIS;
  551. }
  552. else if(tinfo->blocked)
  553. return CGPathNode::BLOCKED;
  554. break;
  555. case ELayer::WATER:
  556. if(tinfo->blocked || tinfo->terType != ETerrainType::WATER)
  557. return CGPathNode::BLOCKED;
  558. break;
  559. case ELayer::AIR:
  560. if(tinfo->blocked || tinfo->terType == ETerrainType::WATER)
  561. return CGPathNode::FLYABLE;
  562. break;
  563. }
  564. return CGPathNode::ACCESSIBLE;
  565. }
  566. bool CPathfinder::isVisitableObj(const CGObjectInstance * obj, const ELayer layer) const
  567. {
  568. /// Hero can't visit objects while walking on water or flying
  569. return canSeeObj(obj) && (layer == ELayer::LAND || layer == ELayer::SAIL);
  570. }
  571. bool CPathfinder::canSeeObj(const CGObjectInstance * obj) const
  572. {
  573. /// Pathfinder should ignore placed events
  574. return obj != nullptr && obj->ID != Obj::EVENT;
  575. }
  576. bool CPathfinder::canMoveBetween(const int3 & a, const int3 & b) const
  577. {
  578. return gs->checkForVisitableDir(a, b);
  579. }
  580. bool CPathfinder::isAllowedTeleportEntrance(const CGTeleport * obj) const
  581. {
  582. if(!obj || !isTeleportEntrancePassable(obj, hero->tempOwner))
  583. return false;
  584. auto whirlpool = dynamic_cast<const CGWhirlpool *>(obj);
  585. if(whirlpool)
  586. {
  587. if(addTeleportWhirlpool(whirlpool))
  588. return true;
  589. }
  590. else if(addTeleportTwoWay(obj) || addTeleportOneWay(obj) || addTeleportOneWayRandom(obj))
  591. return true;
  592. return false;
  593. }
  594. bool CPathfinder::addTeleportTwoWay(const CGTeleport * obj) const
  595. {
  596. return options.useTeleportTwoWay && isTeleportChannelBidirectional(obj->channel, hero->tempOwner);
  597. }
  598. bool CPathfinder::addTeleportOneWay(const CGTeleport * obj) const
  599. {
  600. if(options.useTeleportOneWay && isTeleportChannelUnidirectional(obj->channel, hero->tempOwner))
  601. {
  602. auto passableExits = CGTeleport::getPassableExits(gs, hero, getTeleportChannelExits(obj->channel, hero->tempOwner));
  603. if(passableExits.size() == 1)
  604. return true;
  605. }
  606. return false;
  607. }
  608. bool CPathfinder::addTeleportOneWayRandom(const CGTeleport * obj) const
  609. {
  610. if(options.useTeleportOneWayRandom && isTeleportChannelUnidirectional(obj->channel, hero->tempOwner))
  611. {
  612. auto passableExits = CGTeleport::getPassableExits(gs, hero, getTeleportChannelExits(obj->channel, hero->tempOwner));
  613. if(passableExits.size() > 1)
  614. return true;
  615. }
  616. return false;
  617. }
  618. bool CPathfinder::addTeleportWhirlpool(const CGWhirlpool * obj) const
  619. {
  620. return options.useTeleportWhirlpool && hlp->hasBonusOfType(Bonus::WHIRLPOOL_PROTECTION) && obj;
  621. }
  622. TurnInfo::BonusCache::BonusCache(TBonusListPtr bl)
  623. {
  624. noTerrainPenalty.reserve(ETerrainType::ROCK);
  625. for(int i = 0; i < ETerrainType::ROCK; i++)
  626. {
  627. noTerrainPenalty.push_back(bl->getFirst(Selector::type(Bonus::NO_TERRAIN_PENALTY).And(Selector::subtype(i))));
  628. }
  629. freeShipBoarding = bl->getFirst(Selector::type(Bonus::FREE_SHIP_BOARDING));
  630. flyingMovement = bl->getFirst(Selector::type(Bonus::FLYING_MOVEMENT));
  631. flyingMovementVal = bl->valOfBonuses(Selector::type(Bonus::FLYING_MOVEMENT));
  632. waterWalking = bl->getFirst(Selector::type(Bonus::WATER_WALKING));
  633. waterWalkingVal = bl->valOfBonuses(Selector::type(Bonus::WATER_WALKING));
  634. }
  635. TurnInfo::TurnInfo(const CGHeroInstance * Hero, const int turn)
  636. : hero(Hero), maxMovePointsLand(-1), maxMovePointsWater(-1)
  637. {
  638. std::stringstream cachingStr;
  639. cachingStr << "days_" << turn;
  640. bonuses = hero->getAllBonuses(Selector::days(turn), nullptr, nullptr, cachingStr.str());
  641. bonusCache = make_unique<BonusCache>(bonuses);
  642. nativeTerrain = hero->getNativeTerrain();
  643. }
  644. bool TurnInfo::isLayerAvailable(const EPathfindingLayer layer) const
  645. {
  646. switch(layer)
  647. {
  648. case EPathfindingLayer::AIR:
  649. if(!hasBonusOfType(Bonus::FLYING_MOVEMENT))
  650. return false;
  651. break;
  652. case EPathfindingLayer::WATER:
  653. if(!hasBonusOfType(Bonus::WATER_WALKING))
  654. return false;
  655. break;
  656. }
  657. return true;
  658. }
  659. bool TurnInfo::hasBonusOfType(Bonus::BonusType type, int subtype) const
  660. {
  661. switch(type)
  662. {
  663. case Bonus::FREE_SHIP_BOARDING:
  664. return bonusCache->freeShipBoarding;
  665. case Bonus::FLYING_MOVEMENT:
  666. return bonusCache->flyingMovement;
  667. case Bonus::WATER_WALKING:
  668. return bonusCache->waterWalking;
  669. case Bonus::NO_TERRAIN_PENALTY:
  670. return bonusCache->noTerrainPenalty[subtype];
  671. }
  672. return bonuses->getFirst(Selector::type(type).And(Selector::subtype(subtype)));
  673. }
  674. int TurnInfo::valOfBonuses(Bonus::BonusType type, int subtype) const
  675. {
  676. switch(type)
  677. {
  678. case Bonus::FLYING_MOVEMENT:
  679. return bonusCache->flyingMovementVal;
  680. case Bonus::WATER_WALKING:
  681. return bonusCache->waterWalkingVal;
  682. }
  683. return bonuses->valOfBonuses(Selector::type(type).And(Selector::subtype(subtype)));
  684. }
  685. int TurnInfo::getMaxMovePoints(const EPathfindingLayer layer) const
  686. {
  687. if(maxMovePointsLand == -1)
  688. maxMovePointsLand = hero->maxMovePoints(true, this);
  689. if(maxMovePointsWater == -1)
  690. maxMovePointsWater = hero->maxMovePoints(false, this);
  691. return layer == EPathfindingLayer::SAIL ? maxMovePointsWater : maxMovePointsLand;
  692. }
  693. CPathfinderHelper::CPathfinderHelper(const CGHeroInstance * Hero, const CPathfinder::PathfinderOptions & Options)
  694. : turn(-1), hero(Hero), options(Options)
  695. {
  696. turnsInfo.reserve(16);
  697. updateTurnInfo();
  698. }
  699. void CPathfinderHelper::updateTurnInfo(const int Turn)
  700. {
  701. if(turn != Turn)
  702. {
  703. turn = Turn;
  704. if(turn >= turnsInfo.size())
  705. {
  706. auto ti = new TurnInfo(hero, turn);
  707. turnsInfo.push_back(ti);
  708. }
  709. }
  710. }
  711. bool CPathfinderHelper::isLayerAvailable(const EPathfindingLayer layer) const
  712. {
  713. switch(layer)
  714. {
  715. case EPathfindingLayer::AIR:
  716. if(!options.useFlying)
  717. return false;
  718. break;
  719. case EPathfindingLayer::WATER:
  720. if(!options.useWaterWalking)
  721. return false;
  722. break;
  723. }
  724. return turnsInfo[turn]->isLayerAvailable(layer);
  725. }
  726. const TurnInfo * CPathfinderHelper::getTurnInfo() const
  727. {
  728. return turnsInfo[turn];
  729. }
  730. bool CPathfinderHelper::hasBonusOfType(const Bonus::BonusType type, const int subtype) const
  731. {
  732. return turnsInfo[turn]->hasBonusOfType(type, subtype);
  733. }
  734. int CPathfinderHelper::getMaxMovePoints(const EPathfindingLayer layer) const
  735. {
  736. return turnsInfo[turn]->getMaxMovePoints(layer);
  737. }
  738. void CPathfinderHelper::getNeighbours(const CMap * map, const TerrainTile & srct, const int3 & tile, std::vector<int3> & vec, const boost::logic::tribool & onLand, const bool limitCoastSailing)
  739. {
  740. static const int3 dirs[] = {
  741. int3(-1, +1, +0), int3(0, +1, +0), int3(+1, +1, +0),
  742. int3(-1, +0, +0), /* source pos */ int3(+1, +0, +0),
  743. int3(-1, -1, +0), int3(0, -1, +0), int3(+1, -1, +0)
  744. };
  745. for(auto & dir : dirs)
  746. {
  747. const int3 hlp = tile + dir;
  748. if(!map->isInTheMap(hlp))
  749. continue;
  750. const TerrainTile & hlpt = map->getTile(hlp);
  751. if(hlpt.terType == ETerrainType::ROCK)
  752. continue;
  753. // //we cannot visit things from blocked tiles
  754. // if(srct.blocked && !srct.visitable && hlpt.visitable && srct.blockingObjects.front()->ID != HEROI_TYPE)
  755. // {
  756. // continue;
  757. // }
  758. /// Following condition let us avoid diagonal movement over coast when sailing
  759. if(srct.terType == ETerrainType::WATER && limitCoastSailing && hlpt.terType == ETerrainType::WATER && dir.x && dir.y) //diagonal move through water
  760. {
  761. int3 hlp1 = tile,
  762. hlp2 = tile;
  763. hlp1.x += dir.x;
  764. hlp2.y += dir.y;
  765. if(map->getTile(hlp1).terType != ETerrainType::WATER || map->getTile(hlp2).terType != ETerrainType::WATER)
  766. continue;
  767. }
  768. if(indeterminate(onLand) || onLand == (hlpt.terType != ETerrainType::WATER))
  769. {
  770. vec.push_back(hlp);
  771. }
  772. }
  773. }
  774. int CPathfinderHelper::getMovementCost(const CGHeroInstance * h, const int3 & src, const int3 & dst, const TerrainTile * ct, const TerrainTile * dt, const int remainingMovePoints, const TurnInfo * ti, const bool checkLast)
  775. {
  776. if(src == dst) //same tile
  777. return 0;
  778. if(!ti)
  779. ti = new TurnInfo(h);
  780. if(ct == nullptr || dt == nullptr)
  781. {
  782. ct = h->cb->getTile(src);
  783. dt = h->cb->getTile(dst);
  784. }
  785. /// TODO: by the original game rules hero shouldn't be affected by terrain penalty while flying.
  786. /// Also flying movement only has penalty when player moving over blocked tiles.
  787. /// So if you only have base flying with 40% penalty you can still ignore terrain penalty while having zero flying penalty.
  788. int ret = h->getTileCost(*dt, *ct, ti);
  789. /// Unfortunately this can't be implemented yet as server don't know when player flying and when he's not.
  790. /// Difference in cost calculation on client and server is much worse than incorrect cost.
  791. /// So this one is waiting till server going to use pathfinder rules for path validation.
  792. if(dt->blocked && ti->hasBonusOfType(Bonus::FLYING_MOVEMENT))
  793. {
  794. ret *= (100.0 + ti->valOfBonuses(Bonus::FLYING_MOVEMENT)) / 100.0;
  795. }
  796. else if(dt->terType == ETerrainType::WATER)
  797. {
  798. if(h->boat && ct->hasFavourableWinds() && dt->hasFavourableWinds()) //Favourable Winds
  799. ret *= 0.666;
  800. else if(!h->boat && ti->hasBonusOfType(Bonus::WATER_WALKING))
  801. {
  802. ret *= (100.0 + ti->valOfBonuses(Bonus::WATER_WALKING)) / 100.0;
  803. }
  804. }
  805. if(src.x != dst.x && src.y != dst.y) //it's diagonal move
  806. {
  807. int old = ret;
  808. ret *= 1.414213;
  809. //diagonal move costs too much but normal move is possible - allow diagonal move for remaining move points
  810. if(ret > remainingMovePoints && remainingMovePoints >= old)
  811. return remainingMovePoints;
  812. }
  813. /// TODO: This part need rework in order to work properly with flying and water walking
  814. /// Currently it's only work properly for normal movement or sailing
  815. int left = remainingMovePoints-ret;
  816. if(checkLast && left > 0 && remainingMovePoints-ret < 250) //it might be the last tile - if no further move possible we take all move points
  817. {
  818. std::vector<int3> vec;
  819. vec.reserve(8); //optimization
  820. getNeighbours(h->cb->gameState()->map, *dt, dst, vec, ct->terType != ETerrainType::WATER, true);
  821. for(auto & elem : vec)
  822. {
  823. int fcost = getMovementCost(h, dst, elem, nullptr, nullptr, left, ti, false);
  824. if(fcost <= left)
  825. return ret;
  826. }
  827. ret = remainingMovePoints;
  828. }
  829. return ret;
  830. }
  831. int CPathfinderHelper::getMovementCost(const CGHeroInstance * h, const int3 & dst)
  832. {
  833. return getMovementCost(h, h->visitablePos(), dst, nullptr, nullptr, h->movement);
  834. }
  835. CGPathNode::CGPathNode()
  836. : coord(int3(-1, -1, -1)), layer(ELayer::WRONG)
  837. {
  838. reset();
  839. }
  840. void CGPathNode::reset()
  841. {
  842. locked = false;
  843. accessible = NOT_SET;
  844. moveRemains = 0;
  845. turns = 255;
  846. theNodeBefore = nullptr;
  847. action = UNKNOWN;
  848. }
  849. void CGPathNode::update(const int3 & Coord, const ELayer Layer, const EAccessibility Accessible)
  850. {
  851. if(layer == ELayer::WRONG)
  852. {
  853. coord = Coord;
  854. layer = Layer;
  855. }
  856. else
  857. reset();
  858. accessible = Accessible;
  859. }
  860. bool CGPathNode::reachable() const
  861. {
  862. return turns < 255;
  863. }
  864. int3 CGPath::startPos() const
  865. {
  866. return nodes[nodes.size()-1].coord;
  867. }
  868. int3 CGPath::endPos() const
  869. {
  870. return nodes[0].coord;
  871. }
  872. void CGPath::convert(ui8 mode)
  873. {
  874. if(mode==0)
  875. {
  876. for(auto & elem : nodes)
  877. {
  878. elem.coord = CGHeroInstance::convertPosition(elem.coord,true);
  879. }
  880. }
  881. }
  882. CPathsInfo::CPathsInfo(const int3 & Sizes)
  883. : sizes(Sizes)
  884. {
  885. hero = nullptr;
  886. nodes.resize(boost::extents[sizes.x][sizes.y][sizes.z][ELayer::NUM_LAYERS]);
  887. }
  888. CPathsInfo::~CPathsInfo()
  889. {
  890. }
  891. const CGPathNode * CPathsInfo::getPathInfo(const int3 & tile) const
  892. {
  893. assert(vstd::iswithin(tile.x, 0, sizes.x));
  894. assert(vstd::iswithin(tile.y, 0, sizes.y));
  895. assert(vstd::iswithin(tile.z, 0, sizes.z));
  896. boost::unique_lock<boost::mutex> pathLock(pathMx);
  897. return getNode(tile);
  898. }
  899. bool CPathsInfo::getPath(CGPath & out, const int3 & dst) const
  900. {
  901. boost::unique_lock<boost::mutex> pathLock(pathMx);
  902. out.nodes.clear();
  903. const CGPathNode * curnode = getNode(dst);
  904. if(!curnode->theNodeBefore)
  905. return false;
  906. while(curnode)
  907. {
  908. const CGPathNode cpn = * curnode;
  909. curnode = curnode->theNodeBefore;
  910. out.nodes.push_back(cpn);
  911. }
  912. return true;
  913. }
  914. int CPathsInfo::getDistance(const int3 & tile) const
  915. {
  916. boost::unique_lock<boost::mutex> pathLock(pathMx);
  917. CGPath ret;
  918. if(getPath(ret, tile))
  919. return ret.nodes.size();
  920. else
  921. return 255;
  922. }
  923. const CGPathNode * CPathsInfo::getNode(const int3 & coord) const
  924. {
  925. auto landNode = &nodes[coord.x][coord.y][coord.z][ELayer::LAND];
  926. if(landNode->reachable())
  927. return landNode;
  928. else
  929. return &nodes[coord.x][coord.y][coord.z][ELayer::SAIL];
  930. }
  931. CGPathNode * CPathsInfo::getNode(const int3 & coord, const ELayer layer)
  932. {
  933. return &nodes[coord.x][coord.y][coord.z][layer];
  934. }