Advertisement
Guest User

Untitled

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