Tequilaribs

map.cpp

Jun 20th, 2018
95
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 27.66 KB | None | 0 0
  1. /*
  2. * Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient>
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a copy
  5. * of this software and associated documentation files (the "Software"), to deal
  6. * in the Software without restriction, including without limitation the rights
  7. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. * copies of the Software, and to permit persons to whom the Software is
  9. * furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in
  12. * all copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. * THE SOFTWARE.
  21. */
  22.  
  23. #include "map.h"
  24. #include "game.h"
  25. #include "localplayer.h"
  26. #include "tile.h"
  27. #include "item.h"
  28. #include "missile.h"
  29. #include "statictext.h"
  30. #include "mapview.h"
  31. #include "minimap.h"
  32.  
  33. #include <framework/core/eventdispatcher.h>
  34. #include <framework/core/application.h>
  35.  
  36. Map g_map;
  37. TilePtr Map::m_nulltile;
  38.  
  39. void Map::init()
  40. {
  41. resetAwareRange();
  42. m_animationFlags |= Animation_Show;
  43. }
  44.  
  45. void Map::terminate()
  46. {
  47. clean();
  48. }
  49.  
  50. void Map::addMapView(const MapViewPtr& mapView)
  51. {
  52. m_mapViews.push_back(mapView);
  53. }
  54.  
  55. void Map::removeMapView(const MapViewPtr& mapView)
  56. {
  57. auto it = std::find(m_mapViews.begin(), m_mapViews.end(), mapView);
  58. if(it != m_mapViews.end())
  59. m_mapViews.erase(it);
  60. }
  61.  
  62. void Map::notificateTileUpdate(const Position& pos)
  63. {
  64. if(!pos.isMapPosition())
  65. return;
  66.  
  67. for(const MapViewPtr& mapView : m_mapViews)
  68. mapView->onTileUpdate(pos);
  69. g_minimap.updateTile(pos, getTile(pos));
  70. }
  71.  
  72. void Map::clean()
  73. {
  74. cleanDynamicThings();
  75.  
  76. for(int i=0;i<=Otc::MAX_Z;++i)
  77. m_tileBlocks[i].clear();
  78.  
  79. m_waypoints.clear();
  80.  
  81. g_towns.clear();
  82. g_houses.clear();
  83. g_creatures.clearSpawns();
  84. m_tilesRect = Rect(65534, 65534, 0, 0);
  85. }
  86.  
  87. void Map::cleanDynamicThings()
  88. {
  89. for(const auto& pair : m_knownCreatures) {
  90. const CreaturePtr& creature = pair.second;
  91. removeThing(creature);
  92. }
  93. m_knownCreatures.clear();
  94.  
  95. for(int i=0;i<=Otc::MAX_Z;++i)
  96. m_floorMissiles[i].clear();
  97.  
  98. cleanTexts();
  99. }
  100.  
  101. void Map::cleanTexts()
  102. {
  103. m_animatedTexts.clear();
  104. m_staticTexts.clear();
  105. }
  106.  
  107. void Map::addThing(const ThingPtr& thing, const Position& pos, int stackPos)
  108. {
  109. if(!thing)
  110. return;
  111.  
  112. if(thing->isItem() || thing->isCreature() || thing->isEffect()) {
  113. const TilePtr& tile = getOrCreateTile(pos);
  114. if(tile)
  115. tile->addThing(thing, stackPos);
  116. } else {
  117. if(thing->isMissile()) {
  118. m_floorMissiles[pos.z].push_back(thing->static_self_cast<Missile>());
  119. } else if(thing->isAnimatedText()) {
  120. // this code will stack animated texts of the same color
  121. AnimatedTextPtr animatedText = thing->static_self_cast<AnimatedText>();
  122. AnimatedTextPtr prevAnimatedText;
  123. bool merged = false;
  124. for(auto other : m_animatedTexts) {
  125. if(other->getPosition() == pos) {
  126. prevAnimatedText = other;
  127. if(other->merge(animatedText)) {
  128. merged = true;
  129. break;
  130. }
  131. }
  132. }
  133. if(!merged) {
  134. if(prevAnimatedText) {
  135. Point offset = prevAnimatedText->getOffset();
  136. float t = prevAnimatedText->getTimer().ticksElapsed();
  137. if(t < Otc::ANIMATED_TEXT_DURATION / 4.0) { // didnt move 12 pixels
  138. int y = 12 - 48 * t / (float)Otc::ANIMATED_TEXT_DURATION;
  139. offset += Point(0, y);
  140. }
  141. offset.y = std::min<int>(offset.y, 12);
  142. animatedText->setOffset(offset);
  143. }
  144. m_animatedTexts.push_back(animatedText);
  145. }
  146. } else if(thing->isStaticText()) {
  147. StaticTextPtr staticText = thing->static_self_cast<StaticText>();
  148. bool mustAdd = true;
  149. for(auto other : m_staticTexts) {
  150. // try to combine messages
  151. if(other->getPosition() == pos && other->addMessage(staticText->getName(), staticText->getMessageMode(), staticText->getFirstMessage())) {
  152. mustAdd = false;
  153. break;
  154. }
  155. }
  156.  
  157. if(mustAdd)
  158. m_staticTexts.push_back(staticText);
  159. else
  160. return;
  161. }
  162.  
  163. thing->setPosition(pos);
  164. thing->onAppear();
  165. }
  166.  
  167. notificateTileUpdate(pos);
  168. }
  169.  
  170. ThingPtr Map::getThing(const Position& pos, int stackPos)
  171. {
  172. if(TilePtr tile = getTile(pos))
  173. return tile->getThing(stackPos);
  174. return nullptr;
  175. }
  176.  
  177. bool Map::removeThing(const ThingPtr& thing)
  178. {
  179. if(!thing)
  180. return false;
  181.  
  182. bool ret = false;
  183. if(thing->isMissile()) {
  184. MissilePtr missile = thing->static_self_cast<Missile>();
  185. int z = missile->getPosition().z;
  186. auto it = std::find(m_floorMissiles[z].begin(), m_floorMissiles[z].end(), missile);
  187. if(it != m_floorMissiles[z].end()) {
  188. m_floorMissiles[z].erase(it);
  189. ret = true;
  190. }
  191. } else if(thing->isAnimatedText()) {
  192. AnimatedTextPtr animatedText = thing->static_self_cast<AnimatedText>();
  193. auto it = std::find(m_animatedTexts.begin(), m_animatedTexts.end(), animatedText);
  194. if(it != m_animatedTexts.end()) {
  195. m_animatedTexts.erase(it);
  196. ret = true;
  197. }
  198. } else if(thing->isStaticText()) {
  199. StaticTextPtr staticText = thing->static_self_cast<StaticText>();
  200. auto it = std::find(m_staticTexts.begin(), m_staticTexts.end(), staticText);
  201. if(it != m_staticTexts.end()) {
  202. m_staticTexts.erase(it);
  203. ret = true;
  204. }
  205. } else if(const TilePtr& tile = thing->getTile())
  206. ret = tile->removeThing(thing);
  207.  
  208. notificateTileUpdate(thing->getPosition());
  209. return ret;
  210. }
  211.  
  212. bool Map::removeThingByPos(const Position& pos, int stackPos)
  213. {
  214. if(TilePtr tile = getTile(pos))
  215. return removeThing(tile->getThing(stackPos));
  216. return false;
  217. }
  218.  
  219. void Map::colorizeThing(const ThingPtr& thing, const Color& color)
  220. {
  221. if(!thing)
  222. return;
  223.  
  224. if(thing->isItem())
  225. thing->static_self_cast<Item>()->setColor(color);
  226. else if(thing->isCreature()) {
  227. const TilePtr& tile = thing->getTile();
  228. assert(tile);
  229.  
  230. const ThingPtr& topThing = tile->getTopThing();
  231. assert(topThing);
  232.  
  233. topThing->static_self_cast<Item>()->setColor(color);
  234. }
  235. }
  236.  
  237. void Map::removeThingColor(const ThingPtr& thing)
  238. {
  239. if(!thing)
  240. return;
  241.  
  242. if(thing->isItem())
  243. thing->static_self_cast<Item>()->setColor(Color::alpha);
  244. else if(thing->isCreature()) {
  245. const TilePtr& tile = thing->getTile();
  246. assert(tile);
  247.  
  248. const ThingPtr& topThing = tile->getTopThing();
  249. assert(topThing);
  250.  
  251. topThing->static_self_cast<Item>()->setColor(Color::alpha);
  252. }
  253. }
  254.  
  255. StaticTextPtr Map::getStaticText(const Position& pos)
  256. {
  257. for(auto staticText : m_staticTexts) {
  258. // try to combine messages
  259. if(staticText->getPosition() == pos)
  260. return staticText;
  261. }
  262. return nullptr;
  263. }
  264.  
  265. const TilePtr& Map::createTile(const Position& pos)
  266. {
  267. if(!pos.isMapPosition())
  268. return m_nulltile;
  269. if(pos.x < m_tilesRect.left())
  270. m_tilesRect.setLeft(pos.x);
  271. if(pos.y < m_tilesRect.top())
  272. m_tilesRect.setTop(pos.y);
  273. if(pos.x > m_tilesRect.right())
  274. m_tilesRect.setRight(pos.x);
  275. if(pos.y > m_tilesRect.bottom())
  276. m_tilesRect.setBottom(pos.y);
  277. TileBlock& block = m_tileBlocks[pos.z][getBlockIndex(pos)];
  278. return block.create(pos);
  279. }
  280.  
  281. template <typename... Items>
  282. const TilePtr& Map::createTileEx(const Position& pos, const Items&... items)
  283. {
  284. if(!pos.isValid())
  285. return m_nulltile;
  286. const TilePtr& tile = getOrCreateTile(pos);
  287. auto vec = {items...};
  288. for(auto it : vec)
  289. addThing(it, pos);
  290.  
  291. return tile;
  292. }
  293.  
  294. const TilePtr& Map::getOrCreateTile(const Position& pos)
  295. {
  296. if(!pos.isMapPosition())
  297. return m_nulltile;
  298. if(pos.x < m_tilesRect.left())
  299. m_tilesRect.setLeft(pos.x);
  300. if(pos.y < m_tilesRect.top())
  301. m_tilesRect.setTop(pos.y);
  302. if(pos.x > m_tilesRect.right())
  303. m_tilesRect.setRight(pos.x);
  304. if(pos.y > m_tilesRect.bottom())
  305. m_tilesRect.setBottom(pos.y);
  306. TileBlock& block = m_tileBlocks[pos.z][getBlockIndex(pos)];
  307. return block.getOrCreate(pos);
  308. }
  309.  
  310. const TilePtr& Map::getTile(const Position& pos)
  311. {
  312. if(!pos.isMapPosition())
  313. return m_nulltile;
  314. auto it = m_tileBlocks[pos.z].find(getBlockIndex(pos));
  315. if(it != m_tileBlocks[pos.z].end())
  316. return it->second.get(pos);
  317. return m_nulltile;
  318. }
  319.  
  320. const TileList Map::getTiles(int floor/* = -1*/)
  321. {
  322. TileList tiles;
  323. if(floor > Otc::MAX_Z) {
  324. return tiles;
  325. }
  326. else if(floor < 0) {
  327. // Search all floors
  328. for(uint8_t z = 0; z <= Otc::MAX_Z; ++z) {
  329. for(const auto& pair : m_tileBlocks[z]) {
  330. const TileBlock& block = pair.second;
  331. for(const TilePtr& tile : block.getTiles()) {
  332. if(tile != nullptr)
  333. tiles.push_back(tile);
  334. }
  335. }
  336. }
  337. }
  338. else {
  339. for(const auto& pair : m_tileBlocks[floor]) {
  340. const TileBlock& block = pair.second;
  341. for(const TilePtr& tile : block.getTiles()) {
  342. if(tile != nullptr)
  343. tiles.push_back(tile);
  344. }
  345. }
  346. }
  347. return tiles;
  348. }
  349.  
  350. void Map::cleanTile(const Position& pos)
  351. {
  352. if(!pos.isMapPosition())
  353. return;
  354. auto it = m_tileBlocks[pos.z].find(getBlockIndex(pos));
  355. if(it != m_tileBlocks[pos.z].end()) {
  356. TileBlock& block = it->second;
  357. if(const TilePtr& tile = block.get(pos)) {
  358. tile->clean();
  359. if(tile->canErase())
  360. block.remove(pos);
  361.  
  362. notificateTileUpdate(pos);
  363. }
  364. }
  365. for(auto it = m_staticTexts.begin();it != m_staticTexts.end();) {
  366. const StaticTextPtr& staticText = *it;
  367. if(staticText->getPosition() == pos && staticText->getMessageMode() == Otc::MessageNone)
  368. it = m_staticTexts.erase(it);
  369. else
  370. ++it;
  371. }
  372. }
  373.  
  374. void Map::setShowZone(tileflags_t zone, bool show)
  375. {
  376. if(show)
  377. m_zoneFlags |= (uint32)zone;
  378. else
  379. m_zoneFlags &= ~(uint32)zone;
  380. }
  381.  
  382. void Map::setShowZones(bool show)
  383. {
  384. if(!show)
  385. m_zoneFlags = 0;
  386. else if(m_zoneFlags == 0)
  387. m_zoneFlags = TILESTATE_HOUSE | TILESTATE_PROTECTIONZONE;
  388. }
  389.  
  390. void Map::setZoneColor(tileflags_t zone, const Color& color)
  391. {
  392. if((m_zoneFlags & zone) == zone)
  393. m_zoneColors[zone] = color;
  394. }
  395.  
  396. Color Map::getZoneColor(tileflags_t flag)
  397. {
  398. auto it = m_zoneColors.find(flag);
  399. if(it == m_zoneColors.end())
  400. return Color::alpha;
  401. return it->second;
  402. }
  403.  
  404. void Map::setForceShowAnimations(bool force)
  405. {
  406. if(force) {
  407. if(!(m_animationFlags & Animation_Force))
  408. m_animationFlags |= Animation_Force;
  409. } else
  410. m_animationFlags &= ~Animation_Force;
  411. }
  412.  
  413. bool Map::isForcingAnimations()
  414. {
  415. return (m_animationFlags & Animation_Force) == Animation_Force;
  416. }
  417.  
  418. bool Map::isShowingAnimations()
  419. {
  420. return (m_animationFlags & Animation_Show) == Animation_Show;
  421. }
  422.  
  423. void Map::setShowAnimations(bool show)
  424. {
  425. if(show) {
  426. if(!(m_animationFlags & Animation_Show))
  427. m_animationFlags |= Animation_Show;
  428. } else
  429. m_animationFlags &= ~Animation_Show;
  430. }
  431.  
  432. void Map::beginGhostMode(float opacity)
  433. {
  434. g_painter->setOpacity(opacity);
  435. }
  436.  
  437. void Map::endGhostMode()
  438. {
  439. g_painter->resetOpacity();
  440. }
  441.  
  442. std::map<Position, ItemPtr> Map::findItemsById(uint16 clientId, uint32 max)
  443. {
  444. std::map<Position, ItemPtr> ret;
  445. uint32 count = 0;
  446. for(uint8_t z = 0; z <= Otc::MAX_Z; ++z) {
  447. for(const auto& pair : m_tileBlocks[z]) {
  448. const TileBlock& block = pair.second;
  449. for(const TilePtr& tile : block.getTiles()) {
  450. if(unlikely(!tile || tile->isEmpty()))
  451. continue;
  452. for(const ItemPtr& item : tile->getItems()) {
  453. if(item->getId() == clientId) {
  454. ret.insert(std::make_pair(tile->getPosition(), item));
  455. if(++count >= max)
  456. break;
  457. }
  458. }
  459. }
  460. }
  461. }
  462.  
  463. return ret;
  464. }
  465.  
  466. void Map::addCreature(const CreaturePtr& creature)
  467. {
  468. m_knownCreatures[creature->getId()] = creature;
  469. }
  470.  
  471. CreaturePtr Map::getCreatureById(uint32 id)
  472. {
  473. auto it = m_knownCreatures.find(id);
  474. if(it == m_knownCreatures.end())
  475. return nullptr;
  476. return it->second;
  477. }
  478.  
  479. void Map::removeCreatureById(uint32 id)
  480. {
  481. if(id == 0)
  482. return;
  483.  
  484. auto it = m_knownCreatures.find(id);
  485. if(it != m_knownCreatures.end())
  486. m_knownCreatures.erase(it);
  487. }
  488.  
  489. void Map::removeUnawareThings()
  490. {
  491. // remove creatures from tiles that we are not aware of anymore
  492. for(const auto& pair : m_knownCreatures) {
  493. const CreaturePtr& creature = pair.second;
  494. if(!isAwareOfPosition(creature->getPosition()))
  495. removeThing(creature);
  496. }
  497.  
  498. // remove static texts from tiles that we are not aware anymore
  499. for(auto it = m_staticTexts.begin(); it != m_staticTexts.end();) {
  500. const StaticTextPtr& staticText = *it;
  501. if(staticText->getMessageMode() == Otc::MessageNone && !isAwareOfPosition(staticText->getPosition()))
  502. it = m_staticTexts.erase(it);
  503. else
  504. ++it;
  505. }
  506.  
  507. if(!g_game.getFeature(Otc::GameKeepUnawareTiles)) {
  508. // remove tiles that we are not aware anymore
  509. for(int z = 0; z <= Otc::MAX_Z; ++z) {
  510. std::unordered_map<uint, TileBlock>& tileBlocks = m_tileBlocks[z];
  511. for(auto it = tileBlocks.begin(); it != tileBlocks.end();) {
  512. TileBlock& block = (*it).second;
  513. bool blockEmpty = true;
  514. for(const TilePtr& tile : block.getTiles()) {
  515. if(!tile)
  516. continue;
  517.  
  518. const Position& pos = tile->getPosition();
  519. if(!isAwareOfPosition(pos))
  520. block.remove(pos);
  521. else
  522. blockEmpty = false;
  523. }
  524.  
  525. if(blockEmpty)
  526. it = tileBlocks.erase(it);
  527. else
  528. ++it;
  529. }
  530. }
  531. }
  532. }
  533.  
  534. void Map::setCentralPosition(const Position& centralPosition)
  535. {
  536. if(m_centralPosition == centralPosition)
  537. return;
  538.  
  539. m_centralPosition = centralPosition;
  540.  
  541. removeUnawareThings();
  542.  
  543. // this fixes local player position when the local player is removed from the map,
  544. // the local player is removed from the map when there are too many creatures on his tile,
  545. // so there is no enough stackpos to the server send him
  546. g_dispatcher.addEvent([this] {
  547. LocalPlayerPtr localPlayer = g_game.getLocalPlayer();
  548. if(!localPlayer || localPlayer->getPosition() == m_centralPosition)
  549. return;
  550. TilePtr tile = localPlayer->getTile();
  551. if(tile && tile->hasThing(localPlayer))
  552. return;
  553.  
  554. Position oldPos = localPlayer->getPosition();
  555. Position pos = m_centralPosition;
  556. if(oldPos != pos) {
  557. if(!localPlayer->isRemoved())
  558. localPlayer->onDisappear();
  559. localPlayer->setPosition(pos);
  560. localPlayer->onAppear();
  561. g_logger.debug("forced player position update");
  562. }
  563. });
  564.  
  565. for(const MapViewPtr& mapView : m_mapViews)
  566. mapView->onMapCenterChange(centralPosition);
  567. }
  568.  
  569. std::vector<CreaturePtr> Map::getSightSpectators(const Position& centerPos, bool multiFloor)
  570. {
  571. return getSpectatorsInRangeEx(centerPos, multiFloor, m_awareRange.left - 1, m_awareRange.right - 2, m_awareRange.top - 1, m_awareRange.bottom - 2);
  572. }
  573.  
  574. std::vector<CreaturePtr> Map::getSpectators(const Position& centerPos, bool multiFloor)
  575. {
  576. return getSpectatorsInRangeEx(centerPos, multiFloor, m_awareRange.left, m_awareRange.right, m_awareRange.top, m_awareRange.bottom);
  577. }
  578.  
  579. std::vector<CreaturePtr> Map::getSpectatorsInRange(const Position& centerPos, bool multiFloor, int xRange, int yRange)
  580. {
  581. return getSpectatorsInRangeEx(centerPos, multiFloor, xRange, xRange, yRange, yRange);
  582. }
  583.  
  584. std::vector<CreaturePtr> Map::getSpectatorsInRangeEx(const Position& centerPos, bool multiFloor, int minXRange, int maxXRange, int minYRange, int maxYRange)
  585. {
  586. int minZRange = 0;
  587. int maxZRange = 0;
  588. std::vector<CreaturePtr> creatures;
  589.  
  590. if(multiFloor) {
  591. minZRange = 0;
  592. maxZRange = Otc::MAX_Z;
  593. }
  594.  
  595. //TODO: optimize
  596. //TODO: get creatures from other floors corretly
  597. //TODO: delivery creatures in distance order
  598.  
  599. for(int iz=-minZRange; iz<=maxZRange; ++iz) {
  600. for(int iy=-minYRange; iy<=maxYRange; ++iy) {
  601. for(int ix=-minXRange; ix<=maxXRange; ++ix) {
  602. TilePtr tile = getTile(centerPos.translated(ix,iy,iz));
  603. if(!tile)
  604. continue;
  605.  
  606. auto tileCreatures = tile->getCreatures();
  607. creatures.insert(creatures.end(), tileCreatures.rbegin(), tileCreatures.rend());
  608. }
  609. }
  610. }
  611.  
  612. return creatures;
  613. }
  614.  
  615. bool Map::isLookPossible(const Position& pos)
  616. {
  617. TilePtr tile = getTile(pos);
  618. return tile && tile->isLookPossible();
  619. }
  620.  
  621. bool Map::isCovered(const Position& pos, int firstFloor)
  622. {
  623. // check for tiles on top of the postion
  624. Position tilePos = pos;
  625. while(tilePos.coveredUp() && tilePos.z >= firstFloor) {
  626. TilePtr tile = getTile(tilePos);
  627. // the below tile is covered when the above tile has a full ground
  628. if(tile && tile->isFullGround())
  629. return true;
  630. }
  631. return false;
  632. }
  633.  
  634. bool Map::isCompletelyCovered(const Position& pos, int firstFloor)
  635. {
  636. const TilePtr& checkTile = getTile(pos);
  637. Position tilePos = pos;
  638. while(tilePos.coveredUp() && tilePos.z >= firstFloor) {
  639. bool covered = true;
  640. bool done = false;
  641. // check in 2x2 range tiles that has no transparent pixels
  642. for(int x=0;x<2 && !done;++x) {
  643. for(int y=0;y<2 && !done;++y) {
  644. const TilePtr& tile = getTile(tilePos.translated(-x, -y));
  645. if(!tile || !tile->isFullyOpaque()) {
  646. covered = false;
  647. done = true;
  648. } else if(x==0 && y==0 && (!checkTile || checkTile->isSingleDimension())) {
  649. done = true;
  650. }
  651. }
  652. }
  653. if(covered)
  654. return true;
  655. }
  656. return false;
  657. }
  658.  
  659. bool Map::isAwareOfPosition(const Position& pos)
  660. {
  661. if(pos.z < getFirstAwareFloor() || pos.z > getLastAwareFloor())
  662. return false;
  663.  
  664. Position groundedPos = pos;
  665. while(groundedPos.z != m_centralPosition.z) {
  666. if(groundedPos.z > m_centralPosition.z) {
  667. if(groundedPos.x == 65535 || groundedPos.y == 65535) // When pos == 65535,65535,15 we cant go up to 65536,65536,14
  668. break;
  669. groundedPos.coveredUp();
  670. }
  671. else {
  672. if(groundedPos.x == 0 || groundedPos.y == 0) // When pos == 0,0,0 we cant go down to -1,-1,1
  673. break;
  674. groundedPos.coveredDown();
  675. }
  676. }
  677. return m_centralPosition.isInRange(groundedPos, m_awareRange.left,
  678. m_awareRange.right,
  679. m_awareRange.top,
  680. m_awareRange.bottom);
  681. }
  682.  
  683. void Map::setAwareRange(const AwareRange& range)
  684. {
  685. m_awareRange = range;
  686. removeUnawareThings();
  687. }
  688.  
  689. void Map::resetAwareRange()
  690. {
  691. AwareRange range;
  692. range.left = 14; //Change this to = maxClientViewportX
  693. range.top = 12; //Change this to = maxClientViewportY
  694. range.bottom = range.top+1;
  695. range.right = range.left+1;
  696. setAwareRange(range);
  697. }
  698.  
  699. int Map::getFirstAwareFloor()
  700. {
  701. if(m_centralPosition.z > Otc::SEA_FLOOR)
  702. return m_centralPosition.z-Otc::AWARE_UNDEGROUND_FLOOR_RANGE;
  703. else
  704. return 0;
  705. }
  706.  
  707. int Map::getLastAwareFloor()
  708. {
  709. if(m_centralPosition.z > Otc::SEA_FLOOR)
  710. return std::min<int>(m_centralPosition.z+Otc::AWARE_UNDEGROUND_FLOOR_RANGE, (int)Otc::MAX_Z);
  711. else
  712. return Otc::SEA_FLOOR;
  713. }
  714.  
  715. std::tuple<std::vector<Otc::Direction>, Otc::PathFindResult> Map::findPath(const Position& startPos, const Position& goalPos, int maxComplexity, int flags)
  716. {
  717. // pathfinding using A* search algorithm
  718. // as described in http://en.wikipedia.org/wiki/A*_search_algorithm
  719.  
  720. struct Node {
  721. Node(const Position& pos) : cost(0), totalCost(0), pos(pos), prev(nullptr), dir(Otc::InvalidDirection) { }
  722. float cost;
  723. float totalCost;
  724. Position pos;
  725. Node *prev;
  726. Otc::Direction dir;
  727. };
  728.  
  729. struct LessNode : std::binary_function<std::pair<Node*, float>, std::pair<Node*, float>, bool> {
  730. bool operator()(std::pair<Node*, float> a, std::pair<Node*, float> b) const {
  731. return b.second < a.second;
  732. }
  733. };
  734.  
  735. std::tuple<std::vector<Otc::Direction>, Otc::PathFindResult> ret;
  736. std::vector<Otc::Direction>& dirs = std::get<0>(ret);
  737. Otc::PathFindResult& result = std::get<1>(ret);
  738.  
  739. result = Otc::PathFindResultNoWay;
  740.  
  741. if(startPos == goalPos) {
  742. result = Otc::PathFindResultSamePosition;
  743. return ret;
  744. }
  745.  
  746. if(startPos.z != goalPos.z) {
  747. result = Otc::PathFindResultImpossible;
  748. return ret;
  749. }
  750.  
  751. // check the goal pos is walkable
  752. if(g_map.isAwareOfPosition(goalPos)) {
  753. const TilePtr goalTile = getTile(goalPos);
  754. if(!goalTile || !goalTile->isWalkable()) {
  755. return ret;
  756. }
  757. }
  758. else {
  759. const MinimapTile& goalTile = g_minimap.getTile(goalPos);
  760. if(goalTile.hasFlag(MinimapTileNotWalkable)) {
  761. return ret;
  762. }
  763. }
  764.  
  765. std::unordered_map<Position, Node*, PositionHasher> nodes;
  766. std::priority_queue<std::pair<Node*, float>, std::vector<std::pair<Node*, float>>, LessNode> searchList;
  767.  
  768. Node *currentNode = new Node(startPos);
  769. currentNode->pos = startPos;
  770. nodes[startPos] = currentNode;
  771. Node *foundNode = nullptr;
  772. while(currentNode) {
  773. if((int)nodes.size() > maxComplexity) {
  774. result = Otc::PathFindResultTooFar;
  775. break;
  776. }
  777.  
  778. // path found
  779. if(currentNode->pos == goalPos && (!foundNode || currentNode->cost < foundNode->cost))
  780. foundNode = currentNode;
  781.  
  782. // cost too high
  783. if(foundNode && currentNode->totalCost >= foundNode->cost)
  784. break;
  785.  
  786. for(int i=-1;i<=1;++i) {
  787. for(int j=-1;j<=1;++j) {
  788. if(i == 0 && j == 0)
  789. continue;
  790.  
  791. bool wasSeen = false;
  792. bool hasCreature = false;
  793. bool isNotWalkable = true;
  794. bool isNotPathable = true;
  795. int speed = 100;
  796.  
  797. Position neighborPos = currentNode->pos.translated(i, j);
  798. if(g_map.isAwareOfPosition(neighborPos)) {
  799. wasSeen = true;
  800. if(const TilePtr& tile = getTile(neighborPos)) {
  801. hasCreature = tile->hasCreature();
  802. isNotWalkable = !tile->isWalkable();
  803. isNotPathable = !tile->isPathable();
  804. speed = tile->getGroundSpeed();
  805. }
  806. } else {
  807. const MinimapTile& mtile = g_minimap.getTile(neighborPos);
  808. wasSeen = mtile.hasFlag(MinimapTileWasSeen);
  809. isNotWalkable = mtile.hasFlag(MinimapTileNotWalkable);
  810. isNotPathable = mtile.hasFlag(MinimapTileNotPathable);
  811. if(isNotWalkable || isNotPathable)
  812. wasSeen = true;
  813. speed = mtile.getSpeed();
  814. }
  815.  
  816. float walkFactor = 0;
  817. if(neighborPos != goalPos) {
  818. if(!(flags & Otc::PathFindAllowNotSeenTiles) && !wasSeen)
  819. continue;
  820. if(wasSeen) {
  821. if(!(flags & Otc::PathFindAllowCreatures) && hasCreature)
  822. continue;
  823. if(!(flags & Otc::PathFindAllowNonPathable) && isNotPathable)
  824. continue;
  825. if(!(flags & Otc::PathFindAllowNonWalkable) && isNotWalkable)
  826. continue;
  827. }
  828. } else {
  829. if(!(flags & Otc::PathFindAllowNotSeenTiles) && !wasSeen)
  830. continue;
  831. if(wasSeen) {
  832. if(!(flags & Otc::PathFindAllowNonWalkable) && isNotWalkable)
  833. continue;
  834. }
  835. }
  836.  
  837. Otc::Direction walkDir = currentNode->pos.getDirectionFromPosition(neighborPos);
  838. if(walkDir >= Otc::NorthEast)
  839. walkFactor += 3.0f;
  840. else
  841. walkFactor += 1.0f;
  842.  
  843. float cost = currentNode->cost + (speed * walkFactor) / 100.0f;
  844.  
  845. Node *neighborNode;
  846. if(nodes.find(neighborPos) == nodes.end()) {
  847. neighborNode = new Node(neighborPos);
  848. nodes[neighborPos] = neighborNode;
  849. } else {
  850. neighborNode = nodes[neighborPos];
  851. if(neighborNode->cost <= cost)
  852. continue;
  853. }
  854.  
  855. neighborNode->prev = currentNode;
  856. neighborNode->cost = cost;
  857. neighborNode->totalCost = neighborNode->cost + neighborPos.distance(goalPos);
  858. neighborNode->dir = walkDir;
  859. searchList.push(std::make_pair(neighborNode, neighborNode->totalCost));
  860. }
  861. }
  862.  
  863. if(!searchList.empty()) {
  864. currentNode = searchList.top().first;
  865. searchList.pop();
  866. } else
  867. currentNode = nullptr;
  868. }
  869.  
  870. if(foundNode) {
  871. currentNode = foundNode;
  872. while(currentNode) {
  873. dirs.push_back(currentNode->dir);
  874. currentNode = currentNode->prev;
  875. }
  876. dirs.pop_back();
  877. std::reverse(dirs.begin(), dirs.end());
  878. result = Otc::PathFindResultOk;
  879. }
  880.  
  881. for(auto it : nodes)
  882. delete it.second;
  883.  
  884. return ret;
  885. }
Add Comment
Please, Sign In to add comment