MapRendererContext.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600
  1. /*
  2. * MapRendererContextState.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 "MapRendererContext.h"
  12. #include "MapRendererContextState.h"
  13. #include "mapHandler.h"
  14. #include "../../CCallback.h"
  15. #include "../CGameInfo.h"
  16. #include "../CPlayerInterface.h"
  17. #include "../PlayerLocalState.h"
  18. #include "../../lib/Point.h"
  19. #include "../../lib/mapObjects/CGHeroInstance.h"
  20. #include "../../lib/mapObjects/MiscObjects.h"
  21. #include "../../lib/spells/CSpellHandler.h"
  22. #include "../../lib/mapping/CMap.h"
  23. #include "../../lib/pathfinder/CGPathNode.h"
  24. MapRendererBaseContext::MapRendererBaseContext(const MapRendererContextState & viewState)
  25. : viewState(viewState)
  26. {
  27. }
  28. uint32_t MapRendererBaseContext::getObjectRotation(ObjectInstanceID objectID) const
  29. {
  30. const CGObjectInstance * obj = getObject(objectID);
  31. if(obj->ID == Obj::HERO)
  32. {
  33. const auto * hero = dynamic_cast<const CGHeroInstance *>(obj);
  34. return hero->moveDir;
  35. }
  36. if(obj->ID == Obj::BOAT)
  37. {
  38. const auto * boat = dynamic_cast<const CGBoat *>(obj);
  39. if(boat->hero)
  40. return boat->hero->moveDir;
  41. return boat->direction;
  42. }
  43. return 0;
  44. }
  45. int3 MapRendererBaseContext::getMapSize() const
  46. {
  47. return LOCPLINT->cb->getMapSize();
  48. }
  49. bool MapRendererBaseContext::isInMap(const int3 & coordinates) const
  50. {
  51. return LOCPLINT->cb->isInTheMap(coordinates);
  52. }
  53. bool MapRendererBaseContext::isVisible(const int3 & coordinates) const
  54. {
  55. if(settingsSessionSpectate)
  56. return LOCPLINT->cb->isInTheMap(coordinates);
  57. else
  58. return LOCPLINT->cb->isVisible(coordinates);
  59. }
  60. bool MapRendererBaseContext::isActiveHero(const CGObjectInstance * obj) const
  61. {
  62. if(obj->ID == Obj::HERO)
  63. {
  64. assert(dynamic_cast<const CGHeroInstance *>(obj) != nullptr);
  65. if(LOCPLINT->localState->getCurrentHero() != nullptr)
  66. {
  67. if(obj->id == LOCPLINT->localState->getCurrentHero()->id)
  68. return true;
  69. }
  70. }
  71. return false;
  72. }
  73. bool MapRendererBaseContext::tileAnimated(const int3 & coordinates) const
  74. {
  75. return false;
  76. }
  77. const TerrainTile & MapRendererBaseContext::getMapTile(const int3 & coordinates) const
  78. {
  79. return CGI->mh->getMap()->getTile(coordinates);
  80. }
  81. const MapRendererBaseContext::MapObjectsList & MapRendererBaseContext::getObjects(const int3 & coordinates) const
  82. {
  83. assert(isInMap(coordinates));
  84. return viewState.objects[coordinates.z][coordinates.x][coordinates.y];
  85. }
  86. const CGObjectInstance * MapRendererBaseContext::getObject(ObjectInstanceID objectID) const
  87. {
  88. return CGI->mh->getMap()->objects.at(objectID.getNum());
  89. }
  90. const CGPath * MapRendererBaseContext::currentPath() const
  91. {
  92. return nullptr;
  93. }
  94. size_t MapRendererBaseContext::objectGroupIndex(ObjectInstanceID objectID) const
  95. {
  96. static const std::array<size_t, 9> idleGroups = {0, 13, 0, 1, 2, 3, 4, 15, 14};
  97. return idleGroups[getObjectRotation(objectID)];
  98. }
  99. Point MapRendererBaseContext::objectImageOffset(ObjectInstanceID objectID, const int3 & coordinates) const
  100. {
  101. const CGObjectInstance * object = getObject(objectID);
  102. int3 offsetTiles(object->anchorPos() - coordinates);
  103. return Point(offsetTiles) * Point(32, 32);
  104. }
  105. double MapRendererBaseContext::objectTransparency(ObjectInstanceID objectID, const int3 & coordinates) const
  106. {
  107. const CGObjectInstance * object = getObject(objectID);
  108. if(object->ID == Obj::HERO)
  109. {
  110. const auto * hero = dynamic_cast<const CGHeroInstance *>(object);
  111. if(hero->inTownGarrison)
  112. return 0;
  113. if(hero->boat)
  114. return 0;
  115. }
  116. return 1;
  117. }
  118. size_t MapRendererBaseContext::objectImageIndex(ObjectInstanceID objectID, size_t groupSize) const
  119. {
  120. return 0;
  121. }
  122. size_t MapRendererBaseContext::terrainImageIndex(size_t groupSize) const
  123. {
  124. return 0;
  125. }
  126. size_t MapRendererBaseContext::overlayImageIndex(const int3 & coordinates) const
  127. {
  128. return std::numeric_limits<size_t>::max();
  129. }
  130. std::string MapRendererBaseContext::overlayText(const int3 & coordinates) const
  131. {
  132. return {};
  133. }
  134. ColorRGBA MapRendererBaseContext::overlayTextColor(const int3 & coordinates) const
  135. {
  136. return {};
  137. }
  138. double MapRendererBaseContext::viewTransitionProgress() const
  139. {
  140. return 0;
  141. }
  142. bool MapRendererBaseContext::filterGrayscale() const
  143. {
  144. return false;
  145. }
  146. bool MapRendererBaseContext::showRoads() const
  147. {
  148. return true;
  149. }
  150. bool MapRendererBaseContext::showRivers() const
  151. {
  152. return true;
  153. }
  154. bool MapRendererBaseContext::showBorder() const
  155. {
  156. return false;
  157. }
  158. bool MapRendererBaseContext::showImageOverlay() const
  159. {
  160. return false;
  161. }
  162. bool MapRendererBaseContext::showTextOverlay() const
  163. {
  164. return false;
  165. }
  166. bool MapRendererBaseContext::showGrid() const
  167. {
  168. return false;
  169. }
  170. bool MapRendererBaseContext::showVisitable() const
  171. {
  172. return false;
  173. }
  174. bool MapRendererBaseContext::showBlocked() const
  175. {
  176. return false;
  177. }
  178. bool MapRendererBaseContext::showSpellRange(const int3 & position) const
  179. {
  180. return false;
  181. }
  182. MapRendererAdventureContext::MapRendererAdventureContext(const MapRendererContextState & viewState)
  183. : MapRendererBaseContext(viewState)
  184. {
  185. }
  186. const CGPath * MapRendererAdventureContext::currentPath() const
  187. {
  188. const auto * hero = LOCPLINT->localState->getCurrentHero();
  189. if(!hero)
  190. return nullptr;
  191. if(!LOCPLINT->localState->hasPath(hero))
  192. return nullptr;
  193. return &LOCPLINT->localState->getPath(hero);
  194. }
  195. size_t MapRendererAdventureContext::objectImageIndex(ObjectInstanceID objectID, size_t groupSize) const
  196. {
  197. assert(groupSize > 0);
  198. if(!settingsAdventureObjectAnimation)
  199. return 0;
  200. if(groupSize == 0)
  201. return 0;
  202. // usign objectID for frameCounter to add pseudo-random element per-object.
  203. // Without it, animation of multiple visible objects of the same type will always be in sync
  204. size_t baseFrameTime = 180;
  205. size_t frameCounter = animationTime / baseFrameTime + objectID.getNum();
  206. size_t frameIndex = frameCounter % groupSize;
  207. return frameIndex;
  208. }
  209. size_t MapRendererAdventureContext::terrainImageIndex(size_t groupSize) const
  210. {
  211. if(!settingsAdventureTerrainAnimation)
  212. return 0;
  213. size_t baseFrameTime = 180;
  214. size_t frameCounter = animationTime / baseFrameTime;
  215. size_t frameIndex = frameCounter % groupSize;
  216. return frameIndex;
  217. }
  218. std::string MapRendererAdventureContext::overlayText(const int3 & coordinates) const
  219. {
  220. if(!isVisible(coordinates))
  221. return {};
  222. const auto & tile = getMapTile(coordinates);
  223. if (!tile.visitable)
  224. return {};
  225. return tile.visitableObjects.back()->getObjectName();
  226. }
  227. ColorRGBA MapRendererAdventureContext::overlayTextColor(const int3 & coordinates) const
  228. {
  229. if(!isVisible(coordinates))
  230. return {};
  231. const auto & tile = getMapTile(coordinates);
  232. if (!tile.visitable)
  233. return {};
  234. const auto * object = tile.visitableObjects.back();
  235. if (object->getOwner() == LOCPLINT->playerID)
  236. return { 0, 192, 0};
  237. if (LOCPLINT->cb->getPlayerRelations(object->getOwner(), LOCPLINT->playerID) == PlayerRelations::ALLIES)
  238. return { 0, 128, 255};
  239. if (object->getOwner().isValidPlayer())
  240. return { 255, 0, 0};
  241. if (object->ID == MapObjectID::MONSTER)
  242. return { 255, 0, 0};
  243. auto hero = LOCPLINT->localState->getCurrentHero();
  244. if (hero)
  245. {
  246. if (object->wasVisited(hero))
  247. return { 160, 160, 160 };
  248. }
  249. else
  250. {
  251. if (object->wasVisited(LOCPLINT->playerID))
  252. return { 160, 160, 160 };
  253. }
  254. return { 255, 192, 0 };
  255. }
  256. bool MapRendererAdventureContext::showBorder() const
  257. {
  258. return true;
  259. }
  260. bool MapRendererAdventureContext::showGrid() const
  261. {
  262. return settingShowGrid;
  263. }
  264. bool MapRendererAdventureContext::showVisitable() const
  265. {
  266. return settingShowVisitable;
  267. }
  268. bool MapRendererAdventureContext::showBlocked() const
  269. {
  270. return settingShowBlocked;
  271. }
  272. bool MapRendererAdventureContext::showTextOverlay() const
  273. {
  274. return settingTextOverlay;
  275. }
  276. bool MapRendererAdventureContext::showSpellRange(const int3 & position) const
  277. {
  278. if (!settingSpellRange)
  279. return false;
  280. auto hero = LOCPLINT->localState->getCurrentHero();
  281. if (!hero)
  282. return false;
  283. return !isInScreenRange(hero->getSightCenter(), position);
  284. }
  285. MapRendererAdventureTransitionContext::MapRendererAdventureTransitionContext(const MapRendererContextState & viewState)
  286. : MapRendererAdventureContext(viewState)
  287. {
  288. }
  289. double MapRendererAdventureTransitionContext::viewTransitionProgress() const
  290. {
  291. return progress;
  292. }
  293. MapRendererAdventureFadingContext::MapRendererAdventureFadingContext(const MapRendererContextState & viewState)
  294. : MapRendererAdventureContext(viewState)
  295. {
  296. }
  297. bool MapRendererAdventureFadingContext::tileAnimated(const int3 & coordinates) const
  298. {
  299. if(!isInMap(coordinates))
  300. return false;
  301. auto objects = getObjects(coordinates);
  302. if(vstd::contains(objects, target))
  303. return true;
  304. return false;
  305. }
  306. double MapRendererAdventureFadingContext::objectTransparency(ObjectInstanceID objectID, const int3 & coordinates) const
  307. {
  308. if(objectID == target)
  309. return progress;
  310. return MapRendererAdventureContext::objectTransparency(objectID, coordinates);
  311. }
  312. MapRendererAdventureMovingContext::MapRendererAdventureMovingContext(const MapRendererContextState & viewState)
  313. : MapRendererAdventureContext(viewState)
  314. {
  315. }
  316. size_t MapRendererAdventureMovingContext::objectGroupIndex(ObjectInstanceID objectID) const
  317. {
  318. if(target == objectID)
  319. {
  320. static const std::array<size_t, 9> moveGroups = {0, 10, 5, 6, 7, 8, 9, 12, 11};
  321. return moveGroups[getObjectRotation(objectID)];
  322. }
  323. return MapRendererAdventureContext::objectGroupIndex(objectID);
  324. }
  325. bool MapRendererAdventureMovingContext::tileAnimated(const int3 & coordinates) const
  326. {
  327. if(!isInMap(coordinates))
  328. return false;
  329. auto objects = getObjects(coordinates);
  330. if(vstd::contains(objects, target))
  331. return true;
  332. return false;
  333. }
  334. Point MapRendererAdventureMovingContext::objectImageOffset(ObjectInstanceID objectID, const int3 & coordinates) const
  335. {
  336. if(target == objectID)
  337. {
  338. int3 offsetTilesFrom = tileFrom - coordinates;
  339. int3 offsetTilesDest = tileDest - coordinates;
  340. Point offsetPixelsFrom = Point(offsetTilesFrom) * Point(32, 32);
  341. Point offsetPixelsDest = Point(offsetTilesDest) * Point(32, 32);
  342. Point result = vstd::lerp(offsetPixelsFrom, offsetPixelsDest, progress);
  343. return result;
  344. }
  345. return MapRendererAdventureContext::objectImageOffset(objectID, coordinates);
  346. }
  347. size_t MapRendererAdventureMovingContext::objectImageIndex(ObjectInstanceID objectID, size_t groupSize) const
  348. {
  349. if(target != objectID)
  350. return MapRendererAdventureContext::objectImageIndex(objectID, groupSize);
  351. int32_t baseFrameTime = 50;
  352. size_t frameCounter = animationTime / baseFrameTime;
  353. size_t frameIndex = frameCounter % groupSize;
  354. return frameIndex;
  355. }
  356. size_t MapRendererWorldViewContext::selectOverlayImageForObject(const ObjectPosInfo & object) const
  357. {
  358. size_t ownerIndex = PlayerColor::PLAYER_LIMIT.getNum() * static_cast<size_t>(EWorldViewIcon::ICONS_PER_PLAYER);
  359. if(object.owner.isValidPlayer())
  360. ownerIndex = object.owner.getNum() * static_cast<size_t>(EWorldViewIcon::ICONS_PER_PLAYER);
  361. switch(object.id)
  362. {
  363. case Obj::MONOLITH_ONE_WAY_ENTRANCE:
  364. case Obj::MONOLITH_ONE_WAY_EXIT:
  365. case Obj::MONOLITH_TWO_WAY:
  366. return ownerIndex + static_cast<size_t>(EWorldViewIcon::TELEPORT);
  367. case Obj::SUBTERRANEAN_GATE:
  368. return ownerIndex + static_cast<size_t>(EWorldViewIcon::GATE);
  369. case Obj::ARTIFACT:
  370. return ownerIndex + static_cast<size_t>(EWorldViewIcon::ARTIFACT);
  371. case Obj::TOWN:
  372. return ownerIndex + static_cast<size_t>(EWorldViewIcon::TOWN);
  373. case Obj::HERO:
  374. return ownerIndex + static_cast<size_t>(EWorldViewIcon::HERO);
  375. case Obj::MINE:
  376. return ownerIndex + static_cast<size_t>(EWorldViewIcon::MINE_WOOD) + object.subId;
  377. case Obj::RESOURCE:
  378. return ownerIndex + static_cast<size_t>(EWorldViewIcon::RES_WOOD) + object.subId;
  379. }
  380. return std::numeric_limits<size_t>::max();
  381. }
  382. MapRendererWorldViewContext::MapRendererWorldViewContext(const MapRendererContextState & viewState)
  383. : MapRendererBaseContext(viewState)
  384. {
  385. }
  386. bool MapRendererWorldViewContext::showImageOverlay() const
  387. {
  388. return true;
  389. }
  390. size_t MapRendererWorldViewContext::overlayImageIndex(const int3 & coordinates) const
  391. {
  392. if(!isVisible(coordinates))
  393. return std::numeric_limits<size_t>::max();
  394. for(const auto & objectID : getObjects(coordinates))
  395. {
  396. const auto * object = getObject(objectID);
  397. if(!object->visitableAt(coordinates))
  398. continue;
  399. ObjectPosInfo info(object);
  400. size_t iconIndex = selectOverlayImageForObject(info);
  401. if(iconIndex != std::numeric_limits<size_t>::max())
  402. return iconIndex;
  403. }
  404. return std::numeric_limits<size_t>::max();
  405. }
  406. MapRendererSpellViewContext::MapRendererSpellViewContext(const MapRendererContextState & viewState)
  407. : MapRendererWorldViewContext(viewState)
  408. {
  409. }
  410. double MapRendererSpellViewContext::objectTransparency(ObjectInstanceID objectID, const int3 & coordinates) const
  411. {
  412. if(showAllTerrain)
  413. {
  414. if(getObject(objectID)->isVisitable() && !MapRendererWorldViewContext::isVisible(coordinates))
  415. return 0;
  416. }
  417. return MapRendererWorldViewContext::objectTransparency(objectID, coordinates);
  418. }
  419. bool MapRendererSpellViewContext::isVisible(const int3 & coordinates) const
  420. {
  421. if(showAllTerrain)
  422. return isInMap(coordinates);
  423. return MapRendererBaseContext::isVisible(coordinates);
  424. }
  425. size_t MapRendererSpellViewContext::overlayImageIndex(const int3 & coordinates) const
  426. {
  427. for(const auto & entry : additionalOverlayIcons)
  428. {
  429. if(entry.pos != coordinates)
  430. continue;
  431. size_t iconIndex = selectOverlayImageForObject(entry);
  432. if(iconIndex != std::numeric_limits<size_t>::max())
  433. return iconIndex;
  434. }
  435. return MapRendererWorldViewContext::overlayImageIndex(coordinates);
  436. }
  437. MapRendererPuzzleMapContext::MapRendererPuzzleMapContext(const MapRendererContextState & viewState)
  438. : MapRendererBaseContext(viewState)
  439. {
  440. }
  441. MapRendererPuzzleMapContext::~MapRendererPuzzleMapContext() = default;
  442. const CGPath * MapRendererPuzzleMapContext::currentPath() const
  443. {
  444. return grailPos.get();
  445. }
  446. double MapRendererPuzzleMapContext::objectTransparency(ObjectInstanceID objectID, const int3 & coordinates) const
  447. {
  448. const auto * object = getObject(objectID);
  449. if(!object)
  450. return 0;
  451. if(object->isVisitable())
  452. return 0;
  453. if(object->ID == Obj::HOLE)
  454. return 0;
  455. return MapRendererBaseContext::objectTransparency(objectID, coordinates);
  456. }
  457. bool MapRendererPuzzleMapContext::isVisible(const int3 & coordinates) const
  458. {
  459. return LOCPLINT->cb->isInTheMap(coordinates);
  460. }
  461. bool MapRendererPuzzleMapContext::filterGrayscale() const
  462. {
  463. return true;
  464. }
  465. bool MapRendererPuzzleMapContext::showRoads() const
  466. {
  467. return false;
  468. }
  469. bool MapRendererPuzzleMapContext::showRivers() const
  470. {
  471. return false;
  472. }