MapViewController.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535
  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 "../CPlayerInterface.h"
  17. #include "../adventureMap/CAdvMapInt.h"
  18. #include "../../lib/CConfigHandler.h"
  19. #include "../../lib/CPathfinder.h"
  20. #include "../../lib/mapObjects/CGHeroInstance.h"
  21. #include "../../lib/mapObjects/MiscObjects.h"
  22. #include "../../lib/spells/ViewSpellInt.h"
  23. void MapViewController::setViewCenter(const int3 & position)
  24. {
  25. setViewCenter(Point(position) * model->getSingleTileSize() + model->getSingleTileSize() / 2, position.z);
  26. }
  27. void MapViewController::setViewCenter(const Point & position, int level)
  28. {
  29. Point upperLimit = Point(context->getMapSize()) * model->getSingleTileSize();
  30. Point lowerLimit = Point(0, 0);
  31. if(worldViewContext)
  32. {
  33. Point area = model->getPixelsVisibleDimensions();
  34. Point mapCenter = upperLimit / 2;
  35. Point desiredLowerLimit = lowerLimit + area / 2;
  36. Point desiredUpperLimit = upperLimit - area / 2;
  37. Point actualLowerLimit{
  38. std::min(desiredLowerLimit.x, mapCenter.x),
  39. std::min(desiredLowerLimit.y, mapCenter.y)
  40. };
  41. Point actualUpperLimit{
  42. std::max(desiredUpperLimit.x, mapCenter.x),
  43. std::max(desiredUpperLimit.y, mapCenter.y)
  44. };
  45. upperLimit = actualUpperLimit;
  46. lowerLimit = actualLowerLimit;
  47. }
  48. Point betterPosition = {vstd::clamp(position.x, lowerLimit.x, upperLimit.x), vstd::clamp(position.y, lowerLimit.y, upperLimit.y)};
  49. model->setViewCenter(betterPosition);
  50. model->setLevel(vstd::clamp(level, 0, context->getMapSize().z));
  51. if(adventureInt) // may be called before adventureInt is initialized
  52. adventureInt->onMapViewMoved(model->getTilesTotalRect(), model->getLevel());
  53. }
  54. void MapViewController::setTileSize(const Point & tileSize)
  55. {
  56. model->setTileSize(tileSize);
  57. // force update of view center since changing tile size may invalidated it
  58. setViewCenter(model->getMapViewCenter(), model->getLevel());
  59. }
  60. MapViewController::MapViewController(std::shared_ptr<MapViewModel> model, std::shared_ptr<MapViewCache> view)
  61. : state(new MapRendererContextState())
  62. , model(std::move(model))
  63. , view(view)
  64. {
  65. adventureContext = std::make_shared<MapRendererAdventureContext>(*state);
  66. context = adventureContext;
  67. }
  68. std::shared_ptr<IMapRendererContext> MapViewController::getContext() const
  69. {
  70. return context;
  71. }
  72. void MapViewController::updateBefore(uint32_t timeDelta)
  73. {
  74. // confirmed to match H3 for
  75. // - hero embarking on boat (500 ms)
  76. // - hero disembarking from boat (500 ms)
  77. // - TODO: picking up resources
  78. // - TODO: killing mosters
  79. // - teleporting ( 250 ms)
  80. static const double fadeOutDuration = 500;
  81. static const double fadeInDuration = 500;
  82. static const double heroTeleportDuration = 250;
  83. if(movementContext)
  84. {
  85. const auto * object = context->getObject(movementContext->target);
  86. const auto * hero = dynamic_cast<const CGHeroInstance *>(object);
  87. const auto * boat = dynamic_cast<const CGBoat *>(object);
  88. assert(boat || hero);
  89. if(!hero)
  90. hero = boat->hero;
  91. double heroMoveTime = LOCPLINT->makingTurn ?
  92. settings["adventure"]["heroMoveTime"].Float() :
  93. settings["adventure"]["enemyMoveTime"].Float();
  94. movementContext->progress += timeDelta / heroMoveTime;
  95. movementContext->progress = std::min( 1.0, movementContext->progress);
  96. Point positionFrom = Point(hero->convertToVisitablePos(movementContext->tileFrom)) * model->getSingleTileSize() + model->getSingleTileSize() / 2;
  97. Point positionDest = Point(hero->convertToVisitablePos(movementContext->tileDest)) * model->getSingleTileSize() + model->getSingleTileSize() / 2;
  98. Point positionCurr = vstd::lerp(positionFrom, positionDest, movementContext->progress);
  99. setViewCenter(positionCurr, movementContext->tileDest.z);
  100. }
  101. if(teleportContext)
  102. {
  103. teleportContext->progress += timeDelta / heroTeleportDuration;
  104. teleportContext->progress = std::min( 1.0, teleportContext->progress);
  105. }
  106. if(fadingOutContext)
  107. {
  108. fadingOutContext->progress -= timeDelta / fadeOutDuration;
  109. fadingOutContext->progress = std::max( 0.0, fadingOutContext->progress);
  110. }
  111. if(fadingInContext)
  112. {
  113. fadingInContext->progress += timeDelta / fadeInDuration;
  114. fadingInContext->progress = std::min( 1.0, fadingInContext->progress);
  115. }
  116. if(adventureContext)
  117. {
  118. adventureContext->animationTime += timeDelta;
  119. adventureContext->settingsSessionSpectate = settings["session"]["spectate"].Bool();
  120. adventureContext->settingsAdventureObjectAnimation = settings["adventure"]["objectAnimation"].Bool();
  121. adventureContext->settingsAdventureTerrainAnimation = settings["adventure"]["terrainAnimation"].Bool();
  122. adventureContext->settingShowGrid = settings["gameTweaks"]["showGrid"].Bool();
  123. adventureContext->settingShowVisitable = settings["session"]["showVisitable"].Bool();
  124. adventureContext->settingShowBlocked = settings["session"]["showBlocked"].Bool();
  125. }
  126. }
  127. void MapViewController::updateAfter(uint32_t timeDelta)
  128. {
  129. if(movementContext)
  130. {
  131. const auto * object = context->getObject(movementContext->target);
  132. const auto * hero = dynamic_cast<const CGHeroInstance *>(object);
  133. const auto * boat = dynamic_cast<const CGBoat *>(object);
  134. assert(boat || hero);
  135. if(!hero)
  136. hero = boat->hero;
  137. if(movementContext->progress >= 1.0)
  138. {
  139. setViewCenter(hero->getSightCenter());
  140. removeObject(context->getObject(movementContext->target));
  141. addObject(context->getObject(movementContext->target));
  142. activateAdventureContext(movementContext->animationTime);
  143. }
  144. }
  145. if(teleportContext && teleportContext->progress >= 1.0)
  146. {
  147. activateAdventureContext(teleportContext->animationTime);
  148. }
  149. if(fadingOutContext && fadingOutContext->progress <= 0.0)
  150. {
  151. removeObject(context->getObject(fadingOutContext->target));
  152. activateAdventureContext(fadingOutContext->animationTime);
  153. }
  154. if(fadingInContext && fadingInContext->progress >= 1.0)
  155. {
  156. activateAdventureContext(fadingInContext->animationTime);
  157. }
  158. }
  159. bool MapViewController::isEventVisible(const CGObjectInstance * obj)
  160. {
  161. if(adventureContext == nullptr)
  162. return false;
  163. if(!LOCPLINT->makingTurn && settings["adventure"]["enemyMoveTime"].Float() < 0)
  164. return false; // enemy move speed set to "hidden/none"
  165. if(obj->isVisitable())
  166. return context->isVisible(obj->visitablePos());
  167. else
  168. return context->isVisible(obj->pos);
  169. }
  170. bool MapViewController::isEventVisible(const CGHeroInstance * obj, const int3 & from, const int3 & dest)
  171. {
  172. if(adventureContext == nullptr)
  173. return false;
  174. if(!LOCPLINT->makingTurn && settings["adventure"]["enemyMoveTime"].Float() < 0)
  175. return false; // enemy move speed set to "hidden/none"
  176. if(context->isVisible(obj->convertToVisitablePos(from)))
  177. return true;
  178. if(context->isVisible(obj->convertToVisitablePos(dest)))
  179. return true;
  180. return false;
  181. }
  182. void MapViewController::fadeOutObject(const CGObjectInstance * obj)
  183. {
  184. fadingOutContext = std::make_shared<MapRendererAdventureFadingContext>(*state);
  185. fadingOutContext->animationTime = adventureContext->animationTime;
  186. adventureContext = fadingOutContext;
  187. context = fadingOutContext;
  188. const CGObjectInstance * movingObject = obj;
  189. if (obj->ID == Obj::HERO)
  190. {
  191. auto * hero = dynamic_cast<const CGHeroInstance*>(obj);
  192. if (hero->boat)
  193. movingObject = hero->boat;
  194. }
  195. fadingOutContext->target = movingObject->id;
  196. fadingOutContext->progress = 1.0;
  197. }
  198. void MapViewController::fadeInObject(const CGObjectInstance * obj)
  199. {
  200. fadingInContext = std::make_shared<MapRendererAdventureFadingContext>(*state);
  201. fadingInContext->animationTime = adventureContext->animationTime;
  202. adventureContext = fadingInContext;
  203. context = fadingInContext;
  204. const CGObjectInstance * movingObject = obj;
  205. if (obj->ID == Obj::HERO)
  206. {
  207. auto * hero = dynamic_cast<const CGHeroInstance*>(obj);
  208. if (hero->boat)
  209. movingObject = hero->boat;
  210. }
  211. fadingInContext->target = movingObject->id;
  212. fadingInContext->progress = 0.0;
  213. }
  214. void MapViewController::removeObject(const CGObjectInstance * obj)
  215. {
  216. if (obj->ID == Obj::BOAT)
  217. {
  218. auto * boat = dynamic_cast<const CGBoat*>(obj);
  219. if (boat->hero)
  220. {
  221. view->invalidate(context, boat->hero->id);
  222. state->removeObject(boat->hero);
  223. }
  224. }
  225. if (obj->ID == Obj::HERO)
  226. {
  227. auto * hero = dynamic_cast<const CGHeroInstance*>(obj);
  228. if (hero->boat)
  229. {
  230. view->invalidate(context, hero->boat->id);
  231. state->removeObject(hero->boat);
  232. }
  233. }
  234. view->invalidate(context, obj->id);
  235. state->removeObject(obj);
  236. }
  237. void MapViewController::addObject(const CGObjectInstance * obj)
  238. {
  239. state->addObject(obj);
  240. view->invalidate(context, obj->id);
  241. }
  242. void MapViewController::onBeforeHeroEmbark(const CGHeroInstance * obj, const int3 & from, const int3 & dest)
  243. {
  244. if(isEventVisible(obj, from, dest))
  245. {
  246. fadeOutObject(obj);
  247. setViewCenter(obj->getSightCenter());
  248. }
  249. else
  250. removeObject(obj);
  251. }
  252. void MapViewController::onAfterHeroEmbark(const CGHeroInstance * obj, const int3 & from, const int3 & dest)
  253. {
  254. if(isEventVisible(obj, from, dest))
  255. setViewCenter(obj->getSightCenter());
  256. }
  257. void MapViewController::onBeforeHeroDisembark(const CGHeroInstance * obj, const int3 & from, const int3 & dest)
  258. {
  259. if(isEventVisible(obj, from, dest))
  260. setViewCenter(obj->getSightCenter());
  261. }
  262. void MapViewController::onAfterHeroDisembark(const CGHeroInstance * obj, const int3 & from, const int3 & dest)
  263. {
  264. if(isEventVisible(obj, from, dest))
  265. {
  266. fadeInObject(obj);
  267. setViewCenter(obj->getSightCenter());
  268. }
  269. addObject(obj);
  270. }
  271. void MapViewController::onObjectFadeIn(const CGObjectInstance * obj)
  272. {
  273. assert(!hasOngoingAnimations());
  274. if(isEventVisible(obj))
  275. fadeInObject(obj);
  276. addObject(obj);
  277. }
  278. void MapViewController::onObjectFadeOut(const CGObjectInstance * obj)
  279. {
  280. assert(!hasOngoingAnimations());
  281. if(isEventVisible(obj))
  282. fadeOutObject(obj);
  283. else
  284. removeObject(obj);
  285. }
  286. void MapViewController::onObjectInstantAdd(const CGObjectInstance * obj)
  287. {
  288. addObject(obj);
  289. };
  290. void MapViewController::onObjectInstantRemove(const CGObjectInstance * obj)
  291. {
  292. removeObject(obj);
  293. };
  294. void MapViewController::onBeforeHeroTeleported(const CGHeroInstance * obj, const int3 & from, const int3 & dest)
  295. {
  296. assert(!hasOngoingAnimations());
  297. if(isEventVisible(obj, from, dest))
  298. {
  299. setViewCenter(obj->getSightCenter());
  300. view->createTransitionSnapshot(context);
  301. }
  302. }
  303. void MapViewController::onAfterHeroTeleported(const CGHeroInstance * obj, const int3 & from, const int3 & dest)
  304. {
  305. assert(!hasOngoingAnimations());
  306. const CGObjectInstance * movingObject = obj;
  307. if(obj->boat)
  308. movingObject = obj->boat;
  309. removeObject(movingObject);
  310. addObject(movingObject);
  311. if(isEventVisible(obj, from, dest))
  312. {
  313. teleportContext = std::make_shared<MapRendererAdventureTransitionContext>(*state);
  314. teleportContext->animationTime = adventureContext->animationTime;
  315. adventureContext = teleportContext;
  316. context = teleportContext;
  317. setViewCenter(movingObject->getSightCenter());
  318. }
  319. }
  320. void MapViewController::onHeroMoved(const CGHeroInstance * obj, const int3 & from, const int3 & dest)
  321. {
  322. assert(!hasOngoingAnimations());
  323. // revisiting via spacebar, no need to animate
  324. if(from == dest)
  325. return;
  326. const CGObjectInstance * movingObject = obj;
  327. if(obj->boat)
  328. movingObject = obj->boat;
  329. removeObject(movingObject);
  330. if(!isEventVisible(obj, from, dest))
  331. {
  332. addObject(movingObject);
  333. return;
  334. }
  335. double movementTime = LOCPLINT->playerID == obj->tempOwner ?
  336. settings["adventure"]["heroMoveTime"].Float() :
  337. settings["adventure"]["enemyMoveTime"].Float();
  338. if(movementTime > 1)
  339. {
  340. movementContext = std::make_shared<MapRendererAdventureMovingContext>(*state);
  341. movementContext->animationTime = adventureContext->animationTime;
  342. adventureContext = movementContext;
  343. context = movementContext;
  344. state->addMovingObject(movingObject, from, dest);
  345. movementContext->target = movingObject->id;
  346. movementContext->tileFrom = from;
  347. movementContext->tileDest = dest;
  348. movementContext->progress = 0.0;
  349. }
  350. else // instant movement
  351. {
  352. addObject(movingObject);
  353. setViewCenter(movingObject->visitablePos());
  354. }
  355. }
  356. bool MapViewController::hasOngoingAnimations()
  357. {
  358. if(movementContext)
  359. return true;
  360. if(fadingOutContext)
  361. return true;
  362. if(fadingInContext)
  363. return true;
  364. if(teleportContext)
  365. return true;
  366. return false;
  367. }
  368. void MapViewController::activateAdventureContext(uint32_t animationTime)
  369. {
  370. resetContext();
  371. adventureContext = std::make_shared<MapRendererAdventureContext>(*state);
  372. adventureContext->animationTime = animationTime;
  373. context = adventureContext;
  374. }
  375. void MapViewController::activateAdventureContext()
  376. {
  377. activateAdventureContext(0);
  378. }
  379. void MapViewController::activateWorldViewContext()
  380. {
  381. if(worldViewContext)
  382. return;
  383. resetContext();
  384. worldViewContext = std::make_shared<MapRendererWorldViewContext>(*state);
  385. context = worldViewContext;
  386. }
  387. void MapViewController::activateSpellViewContext()
  388. {
  389. if(spellViewContext)
  390. return;
  391. resetContext();
  392. spellViewContext = std::make_shared<MapRendererSpellViewContext>(*state);
  393. worldViewContext = spellViewContext;
  394. context = spellViewContext;
  395. }
  396. void MapViewController::activatePuzzleMapContext(const int3 & grailPosition)
  397. {
  398. resetContext();
  399. puzzleMapContext = std::make_shared<MapRendererPuzzleMapContext>(*state);
  400. context = puzzleMapContext;
  401. CGPathNode fakeNode;
  402. fakeNode.coord = grailPosition;
  403. puzzleMapContext->grailPos = std::make_unique<CGPath>();
  404. // create two nodes since 1st one is normally not visible
  405. puzzleMapContext->grailPos->nodes.push_back(fakeNode);
  406. puzzleMapContext->grailPos->nodes.push_back(fakeNode);
  407. }
  408. void MapViewController::resetContext()
  409. {
  410. adventureContext.reset();
  411. movementContext.reset();
  412. fadingOutContext.reset();
  413. fadingInContext.reset();
  414. teleportContext.reset();
  415. worldViewContext.reset();
  416. spellViewContext.reset();
  417. puzzleMapContext.reset();
  418. }
  419. void MapViewController::setTerrainVisibility(bool showAllTerrain)
  420. {
  421. assert(spellViewContext);
  422. spellViewContext->showAllTerrain = showAllTerrain;
  423. }
  424. void MapViewController::setOverlayVisibility(const std::vector<ObjectPosInfo> & objectPositions)
  425. {
  426. assert(spellViewContext);
  427. spellViewContext->additionalOverlayIcons = objectPositions;
  428. }