MapViewController.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657
  1. /*
  2. * MapViewController.cpp, part of VCMI engine
  3. *
  4. * Authors: listed in file AUTHORS in main folder
  5. *
  6. * License: GNU General Public License v2.0 or later
  7. * Full text of license available in license.txt file, in main folder
  8. *
  9. */
  10. #include "StdInc.h"
  11. #include "MapViewController.h"
  12. #include "MapRendererContext.h"
  13. #include "MapRendererContextState.h"
  14. #include "MapViewCache.h"
  15. #include "MapViewModel.h"
  16. #include "../CCallback.h"
  17. #include "../CPlayerInterface.h"
  18. #include "../adventureMap/AdventureMapInterface.h"
  19. #include "../gui/CGuiHandler.h"
  20. #include "../gui/WindowHandler.h"
  21. #include "../eventsSDL/InputHandler.h"
  22. #include "../../lib/CConfigHandler.h"
  23. #include "../../lib/StartInfo.h"
  24. #include "../../lib/mapObjects/CGHeroInstance.h"
  25. #include "../../lib/mapObjects/MiscObjects.h"
  26. #include "../../lib/pathfinder/CGPathNode.h"
  27. #include "../../lib/spells/ViewSpellInt.h"
  28. void MapViewController::setViewCenter(const int3 & position)
  29. {
  30. setViewCenter(Point(position) * model->getSingleTileSize() + model->getSingleTileSize() / 2, position.z);
  31. }
  32. void MapViewController::setViewCenter(const Point & position, int level)
  33. {
  34. Point upperLimit = Point(context->getMapSize()) * model->getSingleTileSize();
  35. Point lowerLimit = Point(0, 0);
  36. if(worldViewContext)
  37. {
  38. Point area = model->getPixelsVisibleDimensions();
  39. Point mapCenter = upperLimit / 2;
  40. Point desiredLowerLimit = lowerLimit + area / 2;
  41. Point desiredUpperLimit = upperLimit - area / 2;
  42. Point actualLowerLimit{
  43. std::min(desiredLowerLimit.x, mapCenter.x),
  44. std::min(desiredLowerLimit.y, mapCenter.y)
  45. };
  46. Point actualUpperLimit{
  47. std::max(desiredUpperLimit.x, mapCenter.x),
  48. std::max(desiredUpperLimit.y, mapCenter.y)
  49. };
  50. upperLimit = actualUpperLimit;
  51. lowerLimit = actualLowerLimit;
  52. }
  53. Point betterPosition = {std::clamp(position.x, lowerLimit.x, upperLimit.x), std::clamp(position.y, lowerLimit.y, upperLimit.y)};
  54. model->setViewCenter(betterPosition);
  55. model->setLevel(std::clamp(level, 0, context->getMapSize().z));
  56. if(adventureInt && !puzzleMapContext) // may be called before adventureInt is initialized
  57. adventureInt->onMapViewMoved(model->getTilesTotalRect(), model->getLevel());
  58. }
  59. void MapViewController::setTileSize(const Point & tileSize)
  60. {
  61. Point oldSize = model->getSingleTileSize();
  62. model->setTileSize(tileSize);
  63. double scaleChangeX = 1.0 * tileSize.x / oldSize.x;
  64. double scaleChangeY = 1.0 * tileSize.y / oldSize.y;
  65. Point newViewCenter {
  66. static_cast<int>(std::round(model->getMapViewCenter().x * scaleChangeX)),
  67. static_cast<int>(std::round(model->getMapViewCenter().y * scaleChangeY))
  68. };
  69. // force update of view center since changing tile size may invalidated it
  70. setViewCenter(newViewCenter, model->getLevel());
  71. }
  72. void MapViewController::modifyTileSize(int stepsChange)
  73. {
  74. // we want to zoom in/out in fixed 10% steps, to allow player to return back to exactly 100% zoom just by scrolling
  75. // so, zooming in for 5 steps will put game at 1.1^5 = 1.61 scale
  76. // try to determine current zooming level and change it by requested number of steps
  77. double currentZoomFactor = targetTileSize.x / static_cast<double>(defaultTileSize);
  78. double currentZoomSteps = std::round(std::log(currentZoomFactor) / std::log(1.01));
  79. double newZoomSteps = stepsChange != 0 ? currentZoomSteps + stepsChange : stepsChange;
  80. double newZoomFactor = std::pow(1.01, newZoomSteps);
  81. Point currentZoom = targetTileSize;
  82. Point desiredZoom = Point(defaultTileSize,defaultTileSize) * newZoomFactor;
  83. if (desiredZoom == currentZoom && stepsChange < 0)
  84. desiredZoom -= Point(1,1);
  85. if (desiredZoom == currentZoom && stepsChange > 0)
  86. desiredZoom += Point(1,1);
  87. Point minimal = model->getSingleTileSizeLowerLimit();
  88. Point maximal = model->getSingleTileSizeUpperLimit();
  89. Point actualZoom = {
  90. std::clamp(desiredZoom.x, minimal.x, maximal.x),
  91. std::clamp(desiredZoom.y, minimal.y, maximal.y)
  92. };
  93. if (actualZoom != currentZoom)
  94. {
  95. targetTileSize = actualZoom;
  96. if(actualZoom.x >= defaultTileSize - zoomTileDeadArea && actualZoom.x <= defaultTileSize + zoomTileDeadArea)
  97. actualZoom.x = defaultTileSize;
  98. if(actualZoom.y >= defaultTileSize - zoomTileDeadArea && actualZoom.y <= defaultTileSize + zoomTileDeadArea)
  99. actualZoom.y = defaultTileSize;
  100. bool isInDeadZone = targetTileSize != actualZoom || actualZoom == Point(defaultTileSize, defaultTileSize);
  101. if(!wasInDeadZone && isInDeadZone)
  102. GH.input().hapticFeedback();
  103. wasInDeadZone = isInDeadZone;
  104. setTileSize(actualZoom);
  105. }
  106. }
  107. MapViewController::MapViewController(std::shared_ptr<MapViewModel> model, std::shared_ptr<MapViewCache> view)
  108. : state(new MapRendererContextState())
  109. , model(std::move(model))
  110. , view(view)
  111. {
  112. adventureContext = std::make_shared<MapRendererAdventureContext>(*state);
  113. context = adventureContext;
  114. }
  115. std::shared_ptr<IMapRendererContext> MapViewController::getContext() const
  116. {
  117. return context;
  118. }
  119. void MapViewController::tick(uint32_t timeDelta)
  120. {
  121. // confirmed to match H3 for
  122. // - hero embarking on boat (500 ms)
  123. // - hero disembarking from boat (500 ms)
  124. // - TODO: picking up resources
  125. // - TODO: killing mosters
  126. // - teleporting ( 250 ms)
  127. static const double fadeOutDuration = 500;
  128. static const double fadeInDuration = 500;
  129. static const double heroTeleportDuration = 250;
  130. if(movementContext)
  131. {
  132. const auto * object = context->getObject(movementContext->target);
  133. const auto * hero = dynamic_cast<const CGHeroInstance *>(object);
  134. const auto * boat = dynamic_cast<const CGBoat *>(object);
  135. assert(boat || hero);
  136. if(!hero)
  137. hero = boat->hero;
  138. double heroMoveTime = LOCPLINT->playerID == hero->getOwner() ?
  139. settings["adventure"]["heroMoveTime"].Float() :
  140. settings["adventure"]["enemyMoveTime"].Float();
  141. movementContext->progress += timeDelta / heroMoveTime;
  142. movementContext->progress = std::min( 1.0, movementContext->progress);
  143. Point positionFrom = Point(hero->convertToVisitablePos(movementContext->tileFrom)) * model->getSingleTileSize() + model->getSingleTileSize() / 2;
  144. Point positionDest = Point(hero->convertToVisitablePos(movementContext->tileDest)) * model->getSingleTileSize() + model->getSingleTileSize() / 2;
  145. Point positionCurr = vstd::lerp(positionFrom, positionDest, movementContext->progress);
  146. setViewCenter(positionCurr, movementContext->tileDest.z);
  147. }
  148. if(teleportContext)
  149. {
  150. teleportContext->progress += timeDelta / heroTeleportDuration;
  151. teleportContext->progress = std::min( 1.0, teleportContext->progress);
  152. }
  153. if(fadingOutContext)
  154. {
  155. fadingOutContext->progress -= timeDelta / fadeOutDuration;
  156. fadingOutContext->progress = std::max( 0.0, fadingOutContext->progress);
  157. }
  158. if(fadingInContext)
  159. {
  160. fadingInContext->progress += timeDelta / fadeInDuration;
  161. fadingInContext->progress = std::min( 1.0, fadingInContext->progress);
  162. }
  163. if (adventureContext)
  164. adventureContext->animationTime += timeDelta;
  165. updateState();
  166. }
  167. void MapViewController::updateState()
  168. {
  169. if(adventureContext)
  170. {
  171. adventureContext->settingsSessionSpectate = settings["session"]["spectate"].Bool();
  172. adventureContext->settingsAdventureObjectAnimation = settings["adventure"]["objectAnimation"].Bool();
  173. adventureContext->settingsAdventureTerrainAnimation = settings["adventure"]["terrainAnimation"].Bool();
  174. adventureContext->settingShowGrid = settings["gameTweaks"]["showGrid"].Bool();
  175. adventureContext->settingShowVisitable = settings["session"]["showVisitable"].Bool();
  176. adventureContext->settingShowBlocked = settings["session"]["showBlocked"].Bool();
  177. adventureContext->settingSpellRange = settings["session"]["showSpellRange"].Bool();
  178. }
  179. }
  180. void MapViewController::afterRender()
  181. {
  182. if(movementContext)
  183. {
  184. const auto * object = context->getObject(movementContext->target);
  185. const auto * hero = dynamic_cast<const CGHeroInstance *>(object);
  186. const auto * boat = dynamic_cast<const CGBoat *>(object);
  187. assert(boat || hero);
  188. if(!hero)
  189. hero = boat->hero;
  190. if(movementContext->progress >= 0.999)
  191. {
  192. logGlobal->debug("Ending movement animation");
  193. setViewCenter(hero->getSightCenter());
  194. removeObject(context->getObject(movementContext->target));
  195. addObject(context->getObject(movementContext->target));
  196. activateAdventureContext(movementContext->animationTime);
  197. }
  198. }
  199. if(teleportContext && teleportContext->progress >= 0.999)
  200. {
  201. logGlobal->debug("Ending teleport animation");
  202. activateAdventureContext(teleportContext->animationTime);
  203. }
  204. if(fadingOutContext && fadingOutContext->progress <= 0.001)
  205. {
  206. logGlobal->debug("Ending fade out animation");
  207. removeObject(context->getObject(fadingOutContext->target));
  208. activateAdventureContext(fadingOutContext->animationTime);
  209. }
  210. if(fadingInContext && fadingInContext->progress >= 0.999)
  211. {
  212. logGlobal->debug("Ending fade in animation");
  213. activateAdventureContext(fadingInContext->animationTime);
  214. }
  215. }
  216. bool MapViewController::isEventInstant(const CGObjectInstance * obj, const PlayerColor & initiator)
  217. {
  218. if(settings["gameTweaks"]["skipAdventureMapAnimations"].Bool())
  219. return true;
  220. if (!isEventVisible(obj, initiator))
  221. return true;
  222. if (!initiator.isValidPlayer())
  223. return true; // skip effects such as new monsters on new month
  224. if(initiator != LOCPLINT->playerID && settings["adventure"]["enemyMoveTime"].Float() <= 0)
  225. return true; // instant movement speed
  226. if(initiator == LOCPLINT->playerID && settings["adventure"]["heroMoveTime"].Float() <= 0)
  227. return true; // instant movement speed
  228. return false;
  229. }
  230. bool MapViewController::isEventVisible(const CGObjectInstance * obj, const PlayerColor & initiator)
  231. {
  232. if(adventureContext == nullptr)
  233. return false;
  234. if(initiator != LOCPLINT->playerID && settings["adventure"]["enemyMoveTime"].Float() < 0)
  235. return false; // enemy move speed set to "hidden/none"
  236. if(!GH.windows().isTopWindow(adventureInt))
  237. return false;
  238. // do not focus on actions of other players except for AI with simturns off
  239. if (initiator != LOCPLINT->playerID && initiator.isValidPlayer())
  240. {
  241. if (LOCPLINT->makingTurn)
  242. return false;
  243. if (LOCPLINT->cb->getStartInfo()->playerInfos.at(initiator).isControlledByHuman() && !settings["session"]["adventureTrackHero"].Bool())
  244. return false;
  245. }
  246. if(obj->isVisitable())
  247. return context->isVisible(obj->visitablePos());
  248. else
  249. return context->isVisible(obj->pos);
  250. }
  251. bool MapViewController::isEventVisible(const CGHeroInstance * obj, const int3 & from, const int3 & dest)
  252. {
  253. if(adventureContext == nullptr)
  254. return false;
  255. if(obj->getOwner() != LOCPLINT->playerID && settings["adventure"]["enemyMoveTime"].Float() < 0)
  256. return false; // enemy move speed set to "hidden/none"
  257. if(!GH.windows().isTopWindow(adventureInt))
  258. return false;
  259. // do not focus on actions of other players except for AI with simturns off
  260. if (obj->getOwner() != LOCPLINT->playerID)
  261. {
  262. if (LOCPLINT->makingTurn)
  263. return false;
  264. if (LOCPLINT->cb->getStartInfo()->playerInfos.at(obj->getOwner()).isControlledByHuman() && !settings["session"]["adventureTrackHero"].Bool())
  265. return false;
  266. }
  267. if(context->isVisible(obj->convertToVisitablePos(from)))
  268. return true;
  269. if(context->isVisible(obj->convertToVisitablePos(dest)))
  270. return true;
  271. return false;
  272. }
  273. void MapViewController::fadeOutObject(const CGObjectInstance * obj)
  274. {
  275. logGlobal->debug("Starting fade out animation");
  276. fadingOutContext = std::make_shared<MapRendererAdventureFadingContext>(*state);
  277. fadingOutContext->animationTime = adventureContext->animationTime;
  278. adventureContext = fadingOutContext;
  279. context = fadingOutContext;
  280. const CGObjectInstance * movingObject = obj;
  281. if (obj->ID == Obj::HERO)
  282. {
  283. auto * hero = dynamic_cast<const CGHeroInstance*>(obj);
  284. if (hero->boat)
  285. movingObject = hero->boat;
  286. }
  287. fadingOutContext->target = movingObject->id;
  288. fadingOutContext->progress = 1.0;
  289. }
  290. void MapViewController::fadeInObject(const CGObjectInstance * obj)
  291. {
  292. logGlobal->debug("Starting fade in animation");
  293. fadingInContext = std::make_shared<MapRendererAdventureFadingContext>(*state);
  294. fadingInContext->animationTime = adventureContext->animationTime;
  295. adventureContext = fadingInContext;
  296. context = fadingInContext;
  297. const CGObjectInstance * movingObject = obj;
  298. if (obj->ID == Obj::HERO)
  299. {
  300. auto * hero = dynamic_cast<const CGHeroInstance*>(obj);
  301. if (hero->boat)
  302. movingObject = hero->boat;
  303. }
  304. fadingInContext->target = movingObject->id;
  305. fadingInContext->progress = 0.0;
  306. }
  307. void MapViewController::removeObject(const CGObjectInstance * obj)
  308. {
  309. if (obj->ID == Obj::BOAT)
  310. {
  311. auto * boat = dynamic_cast<const CGBoat*>(obj);
  312. if (boat->hero)
  313. {
  314. view->invalidate(context, boat->hero->id);
  315. state->removeObject(boat->hero);
  316. }
  317. }
  318. if (obj->ID == Obj::HERO)
  319. {
  320. auto * hero = dynamic_cast<const CGHeroInstance*>(obj);
  321. if (hero->boat)
  322. {
  323. view->invalidate(context, hero->boat->id);
  324. state->removeObject(hero->boat);
  325. }
  326. }
  327. view->invalidate(context, obj->id);
  328. state->removeObject(obj);
  329. }
  330. void MapViewController::addObject(const CGObjectInstance * obj)
  331. {
  332. state->addObject(obj);
  333. view->invalidate(context, obj->id);
  334. }
  335. void MapViewController::onBeforeHeroEmbark(const CGHeroInstance * obj, const int3 & from, const int3 & dest)
  336. {
  337. if(isEventVisible(obj, from, dest))
  338. {
  339. if (!isEventInstant(obj, obj->getOwner()))
  340. fadeOutObject(obj);
  341. setViewCenter(obj->getSightCenter());
  342. }
  343. else
  344. removeObject(obj);
  345. }
  346. void MapViewController::onAfterHeroEmbark(const CGHeroInstance * obj, const int3 & from, const int3 & dest)
  347. {
  348. if(isEventVisible(obj, from, dest))
  349. setViewCenter(obj->getSightCenter());
  350. }
  351. void MapViewController::onBeforeHeroDisembark(const CGHeroInstance * obj, const int3 & from, const int3 & dest)
  352. {
  353. if(isEventVisible(obj, from, dest))
  354. setViewCenter(obj->getSightCenter());
  355. }
  356. void MapViewController::onAfterHeroDisembark(const CGHeroInstance * obj, const int3 & from, const int3 & dest)
  357. {
  358. if(isEventVisible(obj, from, dest))
  359. {
  360. if (!isEventInstant(obj, obj->getOwner()))
  361. fadeInObject(obj);
  362. setViewCenter(obj->getSightCenter());
  363. }
  364. addObject(obj);
  365. }
  366. void MapViewController::onObjectFadeIn(const CGObjectInstance * obj, const PlayerColor & initiator)
  367. {
  368. assert(!hasOngoingAnimations());
  369. if(isEventVisible(obj, initiator) && !isEventInstant(obj, initiator) )
  370. fadeInObject(obj);
  371. addObject(obj);
  372. }
  373. void MapViewController::onObjectFadeOut(const CGObjectInstance * obj, const PlayerColor & initiator)
  374. {
  375. assert(!hasOngoingAnimations());
  376. if(isEventVisible(obj, initiator) && !isEventInstant(obj, initiator) )
  377. fadeOutObject(obj);
  378. else
  379. removeObject(obj);
  380. }
  381. void MapViewController::onObjectInstantAdd(const CGObjectInstance * obj, const PlayerColor & initiator)
  382. {
  383. addObject(obj);
  384. };
  385. void MapViewController::onObjectInstantRemove(const CGObjectInstance * obj, const PlayerColor & initiator)
  386. {
  387. removeObject(obj);
  388. };
  389. void MapViewController::onBeforeHeroTeleported(const CGHeroInstance * obj, const int3 & from, const int3 & dest)
  390. {
  391. assert(!hasOngoingAnimations());
  392. if(isEventVisible(obj, from, dest))
  393. {
  394. setViewCenter(obj->getSightCenter());
  395. view->createTransitionSnapshot(context);
  396. }
  397. }
  398. void MapViewController::onAfterHeroTeleported(const CGHeroInstance * obj, const int3 & from, const int3 & dest)
  399. {
  400. assert(!hasOngoingAnimations());
  401. const CGObjectInstance * movingObject = obj;
  402. if(obj->boat)
  403. movingObject = obj->boat;
  404. removeObject(movingObject);
  405. addObject(movingObject);
  406. if(isEventVisible(obj, from, dest))
  407. {
  408. logGlobal->debug("Starting teleport animation");
  409. teleportContext = std::make_shared<MapRendererAdventureTransitionContext>(*state);
  410. teleportContext->animationTime = adventureContext->animationTime;
  411. adventureContext = teleportContext;
  412. context = teleportContext;
  413. setViewCenter(movingObject->getSightCenter());
  414. }
  415. }
  416. void MapViewController::onHeroMoved(const CGHeroInstance * obj, const int3 & from, const int3 & dest)
  417. {
  418. assert(!hasOngoingAnimations());
  419. // revisiting via spacebar, no need to animate
  420. if(from == dest)
  421. return;
  422. const CGObjectInstance * movingObject = obj;
  423. if(obj->boat)
  424. movingObject = obj->boat;
  425. removeObject(movingObject);
  426. if(!isEventVisible(obj, from, dest))
  427. {
  428. addObject(movingObject);
  429. return;
  430. }
  431. double movementTime = LOCPLINT->playerID == obj->tempOwner ?
  432. settings["adventure"]["heroMoveTime"].Float() :
  433. settings["adventure"]["enemyMoveTime"].Float();
  434. if(movementTime > 1)
  435. {
  436. logGlobal->debug("Starting movement animation");
  437. movementContext = std::make_shared<MapRendererAdventureMovingContext>(*state);
  438. movementContext->animationTime = adventureContext->animationTime;
  439. adventureContext = movementContext;
  440. context = movementContext;
  441. state->addMovingObject(movingObject, from, dest);
  442. movementContext->target = movingObject->id;
  443. movementContext->tileFrom = from;
  444. movementContext->tileDest = dest;
  445. movementContext->progress = 0.0;
  446. }
  447. else // instant movement
  448. {
  449. addObject(movingObject);
  450. setViewCenter(movingObject->visitablePos());
  451. }
  452. }
  453. bool MapViewController::hasOngoingAnimations()
  454. {
  455. if(movementContext)
  456. return true;
  457. if(fadingOutContext)
  458. return true;
  459. if(fadingInContext)
  460. return true;
  461. if(teleportContext)
  462. return true;
  463. return false;
  464. }
  465. void MapViewController::activateAdventureContext(uint32_t animationTime)
  466. {
  467. resetContext();
  468. adventureContext = std::make_shared<MapRendererAdventureContext>(*state);
  469. adventureContext->animationTime = animationTime;
  470. context = adventureContext;
  471. updateState();
  472. }
  473. void MapViewController::activateAdventureContext()
  474. {
  475. activateAdventureContext(0);
  476. }
  477. void MapViewController::activateWorldViewContext()
  478. {
  479. if(worldViewContext)
  480. return;
  481. resetContext();
  482. worldViewContext = std::make_shared<MapRendererWorldViewContext>(*state);
  483. context = worldViewContext;
  484. }
  485. void MapViewController::activateSpellViewContext()
  486. {
  487. if(spellViewContext)
  488. return;
  489. resetContext();
  490. spellViewContext = std::make_shared<MapRendererSpellViewContext>(*state);
  491. worldViewContext = spellViewContext;
  492. context = spellViewContext;
  493. }
  494. void MapViewController::activatePuzzleMapContext(const int3 & grailPosition)
  495. {
  496. resetContext();
  497. puzzleMapContext = std::make_shared<MapRendererPuzzleMapContext>(*state);
  498. context = puzzleMapContext;
  499. CGPathNode fakeNode;
  500. fakeNode.coord = grailPosition;
  501. puzzleMapContext->grailPos = std::make_unique<CGPath>();
  502. // create two nodes since 1st one is normally not visible
  503. puzzleMapContext->grailPos->nodes.push_back(fakeNode);
  504. puzzleMapContext->grailPos->nodes.push_back(fakeNode);
  505. }
  506. void MapViewController::resetContext()
  507. {
  508. adventureContext.reset();
  509. movementContext.reset();
  510. fadingOutContext.reset();
  511. fadingInContext.reset();
  512. teleportContext.reset();
  513. worldViewContext.reset();
  514. spellViewContext.reset();
  515. puzzleMapContext.reset();
  516. }
  517. void MapViewController::setTerrainVisibility(bool showAllTerrain)
  518. {
  519. assert(spellViewContext);
  520. spellViewContext->showAllTerrain = showAllTerrain;
  521. }
  522. void MapViewController::setOverlayVisibility(const std::vector<ObjectPosInfo> & objectPositions)
  523. {
  524. assert(spellViewContext);
  525. spellViewContext->additionalOverlayIcons = objectPositions;
  526. }