Guest User

map.cpp

a guest
May 27th, 2016
95
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 27.61 KB | None | 0 0
  1. /*
  2.  * Copyright (c) 2010-2015 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 = 16;
  694.     range.top = 12;
  695.     range.bottom = 13;
  696.     range.right = 17;
  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. }
Add Comment
Please, Sign In to add comment