CPathfinder.cpp 31 KB

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