Otclient  14/8/2020
map.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2010-2020 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 
35 
37 TilePtr Map::m_nulltile;
38 
39 void Map::init()
40 {
42  m_animationFlags |= Animation_Show;
43 }
44 
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 
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 {
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();
84  m_tilesRect = Rect(65534, 65534, 0, 0);
85 }
86 
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 
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 
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 
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 
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 
363  }
364  }
365  for(auto itt = m_staticTexts.begin();itt != m_staticTexts.end();) {
366  const StaticTextPtr& staticText = *itt;
367  if(staticText->getPosition() == pos && staticText->getMessageMode() == Otc::MessageNone)
368  itt = m_staticTexts.erase(itt);
369  else
370  ++itt;
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)
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 
397 {
398  auto it = m_zoneColors.find(flag);
399  if(it == m_zoneColors.end())
400  return Color::alpha;
401  return it->second;
402 }
403 
405 {
406  if(force) {
407  if(!(m_animationFlags & Animation_Force))
408  m_animationFlags |= Animation_Force;
409  } else
410  m_animationFlags &= ~Animation_Force;
411 }
412 
414 {
415  return (m_animationFlags & Animation_Force) == Animation_Force;
416 }
417 
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 
438 {
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 
472 {
473  auto it = m_knownCreatures.find(id);
474  if(it == m_knownCreatures.end())
475  return nullptr;
476  return it->second;
477 }
478 
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 
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 
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 
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 
690 {
691  AwareRange range;
692  range.left = 8;
693  range.top = 6;
694  range.bottom = 7;
695  range.right = 9;
696  setAwareRange(range);
697 }
698 
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 
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) {
743  return ret;
744  }
745 
746  if(startPos.z != goalPos.z) {
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((flags & Otc::PathFindAllowCreatures))) {
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((flags & Otc::PathFindAllowCreatures));
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 }
Map::createTileEx
const TilePtr & createTileEx(const Position &pos, const Items &... items)
Definition: map.cpp:282
Otc::InvalidDirection
@ InvalidDirection
Definition: const.h:170
Position::isInRange
bool isInRange(const Position &pos, int xRange, int yRange) const
Definition: position.h:200
Map::setAwareRange
void setAwareRange(const AwareRange &range)
Definition: map.cpp:683
eventdispatcher.h
Map::init
void init()
Definition: map.cpp:39
MinimapTileNotPathable
@ MinimapTileNotPathable
Definition: minimap.h:38
g_map
Map g_map
Definition: map.cpp:36
Creature::getId
uint32 getId()
Definition: creature.h:81
CreatureManager::clearSpawns
void clearSpawns()
Definition: creatures.cpp:175
Color
Definition: color.h:32
Otc::PathFindAllowCreatures
@ PathFindAllowCreatures
Definition: const.h:434
Animation_Force
@ Animation_Force
Definition: map.h:97
Thing::getTile
const TilePtr & getTile()
Definition: thing.cpp:62
TPoint::y
T y
Definition: point.h:83
unlikely
#define unlikely(x)
Definition: compiler.h:71
z
gc sort z
Definition: CMakeLists.txt:176
Position::distance
float distance(const Position &pos) const
Definition: position.h:183
Position::x
int x
Definition: position.h:243
TileBlock::remove
void remove(const Position &pos)
Definition: map.h:117
g_dispatcher
EventDispatcher g_dispatcher
Definition: eventdispatcher.cpp:28
Map::cleanTexts
void cleanTexts()
Definition: map.cpp:101
Tile::isWalkable
bool isWalkable(bool ignoreCreatures=false)
Definition: tile.cpp:475
Position::isValid
bool isValid() const
Definition: position.h:182
Tile::addThing
void addThing(const ThingPtr &thing, int stackPos)
Definition: tile.cpp:166
uint32
uint32_t uint32
Definition: types.h:35
Map::isShowingAnimations
bool isShowingAnimations()
Definition: map.cpp:418
Map::setShowZone
void setShowZone(tileflags_t zone, bool show)
Definition: map.cpp:374
TownManager::clear
void clear()
Definition: towns.h:61
Map::clean
void clean()
Definition: map.cpp:72
TRect::left
T left() const
Definition: rect.h:52
AwareRange::bottom
int bottom
Definition: map.h:131
Map::getThing
ThingPtr getThing(const Position &pos, int stackPos)
Definition: map.cpp:170
StaticText
Definition: statictext.h:31
Map::cleanTile
void cleanTile(const Position &pos)
Definition: map.cpp:350
Otc::PathFindAllowNonPathable
@ PathFindAllowNonPathable
Definition: const.h:435
Map::isCompletelyCovered
bool isCompletelyCovered(const Position &pos, int firstFloor=0)
Definition: map.cpp:634
TRect::setTop
void setTop(T pos)
Definition: rect.h:76
Map::getTile
const TilePtr & getTile(const Position &pos)
Definition: map.cpp:310
TRect::bottom
T bottom() const
Definition: rect.h:55
Map::endGhostMode
void endGhostMode()
Definition: map.cpp:437
Otc::SEA_FLOOR
@ SEA_FLOOR
Definition: const.h:32
g_game
Game g_game
Definition: game.cpp:37
Point
TPoint< int > Point
Definition: point.h:86
Position::y
int y
Definition: position.h:244
Map::removeMapView
void removeMapView(const MapViewPtr &mapView)
Definition: map.cpp:55
TileBlock
Definition: map.h:101
Map::addCreature
void addCreature(const CreaturePtr &creature)
Definition: map.cpp:466
Map::getFirstAwareFloor
int getFirstAwareFloor()
Definition: map.cpp:699
TRect::setLeft
void setLeft(T pos)
Definition: rect.h:75
Map::resetAwareRange
void resetAwareRange()
Definition: map.cpp:689
MinimapTileNotWalkable
@ MinimapTileNotWalkable
Definition: minimap.h:39
Map::findPath
std::tuple< std::vector< Otc::Direction >, Otc::PathFindResult > findPath(const Position &start, const Position &goal, int maxComplexity, int flags=0)
Definition: map.cpp:715
g_creatures
CreatureManager g_creatures
Definition: creatures.cpp:30
Map::getSightSpectators
std::vector< CreaturePtr > getSightSpectators(const Position &centerPos, bool multiFloor)
Definition: map.cpp:569
Map::addMapView
void addMapView(const MapViewPtr &mapView)
Definition: map.cpp:50
Map::setZoneColor
void setZoneColor(tileflags_t zone, const Color &color)
Definition: map.cpp:390
minimap.h
Otc::NorthEast
@ NorthEast
Definition: const.h:166
Position::z
short z
Definition: position.h:245
uint16
uint16_t uint16
Definition: types.h:36
TRect::setRight
void setRight(T pos)
Definition: rect.h:77
Otc::PathFindResultImpossible
@ PathFindResultImpossible
Definition: const.h:427
Map::removeThingColor
void removeThingColor(const ThingPtr &thing)
Definition: map.cpp:237
Otc::PathFindResultOk
@ PathFindResultOk
Definition: const.h:425
Minimap::updateTile
void updateTile(const Position &pos, const TilePtr &tile)
Definition: minimap.cpp:193
Otc::Direction
Direction
Definition: const.h:161
localplayer.h
Animation_Show
@ Animation_Show
Definition: map.h:98
Minimap::getTile
const MinimapTile & getTile(const Position &pos)
Definition: minimap.cpp:214
Map::findItemsById
std::map< Position, ItemPtr > findItemsById(uint16 clientId, uint32 max)
Definition: map.cpp:442
TileBlock::create
const TilePtr & create(const Position &pos)
Definition: map.h:105
Otc::GameKeepUnawareTiles
@ GameKeepUnawareTiles
Definition: const.h:415
Map::setShowAnimations
void setShowAnimations(bool show)
Definition: map.cpp:423
mapview.h
TileBlock::getTiles
const std::array< TilePtr, BLOCK_SIZE *BLOCK_SIZE > & getTiles() const
Definition: map.h:121
Otc::PathFindAllowNonWalkable
@ PathFindAllowNonWalkable
Definition: const.h:436
Tile::getCreatures
std::vector< CreaturePtr > getCreatures()
Definition: tile.cpp:314
Position::translated
Position translated(int dx, int dy, short dz=0) const
Definition: position.h:187
Otc::MessageNone
@ MessageNone
Definition: const.h:287
TILESTATE_PROTECTIONZONE
@ TILESTATE_PROTECTIONZONE
Definition: tile.h:36
Map::getTiles
const TileList getTiles(int floor=-1)
Definition: map.cpp:320
Map::addThing
void addThing(const ThingPtr &thing, const Position &pos, int stackPos=-1)
Definition: map.cpp:107
Position
Definition: position.h:33
Map::terminate
void terminate()
Definition: map.cpp:45
Tile::isSingleDimension
bool isSingleDimension()
Definition: tile.cpp:517
TileBlock::getOrCreate
const TilePtr & getOrCreate(const Position &pos)
Definition: map.h:110
EventDispatcher::addEvent
EventPtr addEvent(const std::function< void()> &callback, bool pushFront=false)
Definition: eventdispatcher.cpp:104
Painter::resetOpacity
void resetOpacity()
Definition: painter.h:106
missile.h
Map::colorizeThing
void colorizeThing(const ThingPtr &thing, const Color &color)
Definition: map.cpp:219
Map::createTile
const TilePtr & createTile(const Position &pos)
Definition: map.cpp:265
Otc::PathFindResultSamePosition
@ PathFindResultSamePosition
Definition: const.h:426
Tile::isFullGround
bool isFullGround()
Definition: tile.cpp:503
MinimapTile::hasFlag
bool hasFlag(MinimapTileFlags flag) const
Definition: minimap.h:49
map.h
Game::getFeature
bool getFeature(Otc::GameFeature feature)
Definition: game.h:310
Otc::PathFindAllowNotSeenTiles
@ PathFindAllowNotSeenTiles
Definition: const.h:433
TILESTATE_HOUSE
@ TILESTATE_HOUSE
Definition: tile.h:44
Position::isMapPosition
bool isMapPosition() const
Definition: position.h:181
Map::removeCreatureById
void removeCreatureById(uint32 id)
Definition: map.cpp:479
Otc::MAX_Z
@ MAX_Z
Definition: const.h:33
Map::isAwareOfPosition
bool isAwareOfPosition(const Position &pos)
Definition: map.cpp:659
MinimapTile
Definition: minimap.h:43
Map::getOrCreateTile
const TilePtr & getOrCreateTile(const Position &pos)
Definition: map.cpp:294
Otc::PathFindResult
PathFindResult
Definition: const.h:424
Rect
TRect< int > Rect
Definition: rect.h:319
Otc::ANIMATED_TEXT_DURATION
@ ANIMATED_TEXT_DURATION
Definition: const.h:39
Map::getStaticText
StaticTextPtr getStaticText(const Position &pos)
Definition: map.cpp:255
Tile::isFullyOpaque
bool isFullyOpaque()
Definition: tile.cpp:511
Position::coveredDown
bool coveredDown(int n=1)
Definition: position.h:234
Map::getZoneColor
Color getZoneColor(tileflags_t flag)
Definition: map.cpp:396
AwareRange
Definition: map.h:127
Item
Definition: item.h:76
Color::alpha
static const Color alpha
Definition: color.h:100
g_towns
TownManager g_towns
Definition: towns.cpp:25
Tile::getTopThing
ThingPtr getTopThing()
Definition: tile.cpp:292
Map::notificateTileUpdate
void notificateTileUpdate(const Position &pos)
Definition: map.cpp:62
TileBlock::get
const TilePtr & get(const Position &pos)
Definition: map.h:116
TileList
std::list< TilePtr > TileList
Definition: declarations.h:86
TRect::right
T right() const
Definition: rect.h:54
Map::getSpectators
std::vector< CreaturePtr > getSpectators(const Position &centerPos, bool multiFloor)
Definition: map.cpp:574
AwareRange::left
int left
Definition: map.h:132
Missile
Definition: missile.h:31
stdext::shared_object_ptr< Tile >
tileflags_t
tileflags_t
Definition: tile.h:33
Map::isForcingAnimations
bool isForcingAnimations()
Definition: map.cpp:413
Game::getLocalPlayer
LocalPlayerPtr getLocalPlayer()
Definition: game.h:343
Map::isLookPossible
bool isLookPossible(const Position &pos)
Definition: map.cpp:615
g_minimap
Minimap g_minimap
Definition: minimap.cpp:36
Map::getSpectatorsInRangeEx
std::vector< CreaturePtr > getSpectatorsInRangeEx(const Position &centerPos, bool multiFloor, int minXRange, int maxXRange, int minYRange, int maxYRange)
Definition: map.cpp:584
g_painter
Painter * g_painter
Definition: painter.cpp:28
Map::removeThingByPos
bool removeThingByPos(const Position &pos, int stackPos)
Definition: map.cpp:212
AnimatedText
Definition: animatedtext.h:32
MinimapTile::getSpeed
int getSpeed() const
Definition: minimap.h:50
TRect::top
T top() const
Definition: rect.h:53
game.h
MinimapTileWasSeen
@ MinimapTileWasSeen
Definition: minimap.h:37
Map::beginGhostMode
void beginGhostMode(float opacity)
Definition: map.cpp:432
Map::setShowZones
void setShowZones(bool show)
Definition: map.cpp:382
Map::setCentralPosition
void setCentralPosition(const Position &centralPosition)
Definition: map.cpp:534
statictext.h
TPoint< int >
HouseManager::clear
void clear()
Definition: houses.h:100
Thing::getPosition
Position getPosition()
Definition: thing.h:45
Otc::PathFindResultNoWay
@ PathFindResultNoWay
Definition: const.h:429
Otc::AWARE_UNDEGROUND_FLOOR_RANGE
@ AWARE_UNDEGROUND_FLOOR_RANGE
Definition: const.h:35
Map::getCreatureById
CreaturePtr getCreatureById(uint32 id)
Definition: map.cpp:471
tile.h
AwareRange::top
int top
Definition: map.h:129
Map::getSpectatorsInRange
std::vector< CreaturePtr > getSpectatorsInRange(const Position &centerPos, bool multiFloor, int xRange, int yRange)
Definition: map.cpp:579
Map::removeThing
bool removeThing(const ThingPtr &thing)
Definition: map.cpp:177
AwareRange::right
int right
Definition: map.h:130
g_houses
HouseManager g_houses
Definition: houses.cpp:27
Map::cleanDynamicThings
void cleanDynamicThings()
Definition: map.cpp:87
Painter::setOpacity
virtual void setOpacity(float opacity)
Definition: painter.h:91
Map
Definition: map.h:139
Map::getLastAwareFloor
int getLastAwareFloor()
Definition: map.cpp:707
Otc::PathFindResultTooFar
@ PathFindResultTooFar
Definition: const.h:428
TRect::setBottom
void setBottom(T pos)
Definition: rect.h:78
application.h
Map::setForceShowAnimations
void setForceShowAnimations(bool force)
Definition: map.cpp:404
Map::isCovered
bool isCovered(const Position &pos, int firstFloor=0)
Definition: map.cpp:621
Tile::isLookPossible
bool isLookPossible()
Definition: tile.cpp:527
Position::coveredUp
bool coveredUp(int n=1)
Definition: position.h:225
item.h