CPathfinder.cpp 29 KB

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