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