52 m_mapViews.push_back(mapView);
57 const auto it = std::find(m_mapViews.begin(), m_mapViews.end(), mapView);
58 if(it != m_mapViews.end())
78 mapView->onTileUpdate(pos, thing, operation);
87 mapView->requestDrawing(pos, reDrawFlags, force, isLocalPlayer);
95 m_tileBlocks[i].clear();
102 m_tilesRect =
Rect(65534, 65534, 0, 0);
107 for(
const auto& pair : m_knownCreatures) {
111 m_knownCreatures.clear();
114 m_floorMissiles[i].clear();
121 m_animatedTexts.clear();
122 m_staticTexts.clear();
130 if(thing->isItem() || thing->isCreature() || thing->isEffect()) {
134 thing->requestDrawing(
true);
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()) {
146 for(
const auto& other : m_animatedTexts) {
147 if(other->getPosition() == pos) {
148 prevAnimatedText = other;
149 if(other->merge(animatedText)) {
157 if(prevAnimatedText) {
158 Point offset = prevAnimatedText->getOffset();
159 const float t = prevAnimatedText->getTimer().ticksElapsed();
162 offset +=
Point(0, y);
164 offset.
y = std::min<int>(offset.
y, 12);
165 animatedText->setOffset(offset);
167 m_animatedTexts.push_back(animatedText);
169 }
else if(thing->isStaticText()) {
170 thing->requestDrawing(
true);
173 for(
const auto& other : m_staticTexts) {
175 if(other->getPosition() == pos && other->addMessage(staticText->getName(), staticText->getMessageMode(), staticText->getFirstMessage())) {
180 m_staticTexts.push_back(staticText);
183 thing->setPosition(pos);
193 return tile->getThing(stackPos);
204 if(thing->isAnimatedText()) {
206 const auto it = std::find(m_animatedTexts.begin(), m_animatedTexts.end(), animatedText);
207 if(it != m_animatedTexts.end()) {
208 m_animatedTexts.erase(it);
211 }
else if(thing->isStaticText()) {
213 const auto it = std::find(m_staticTexts.begin(), m_staticTexts.end(), staticText);
214 if(it != m_staticTexts.end()) {
215 m_staticTexts.erase(it);
221 if(thing->isMissile()) {
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);
229 }
else if(
const TilePtr& tile = thing->getTile()) {
230 ret = tile->removeThing(thing);
233 if(!thing->cancelListenerPainter()) {
261 thing->static_self_cast<
Item>()->setColor(color);
262 else if(thing->isCreature()) {
263 const TilePtr& tile = thing->getTile();
269 topThing->static_self_cast<
Item>()->setColor(color);
280 else if(thing->isCreature()) {
281 const TilePtr& tile = thing->getTile();
293 for(
auto staticText : m_staticTexts) {
295 if(staticText->getPosition() == pos)
307 if(pos.
x < m_tilesRect.
left())
310 if(pos.
y < m_tilesRect.
top())
313 if(pos.
x > m_tilesRect.
right())
316 if(pos.
y > m_tilesRect.
bottom())
319 TileBlock& block = m_tileBlocks[pos.
z][getBlockIndex(pos)];
323 template <
typename... Items>
330 auto vec = { items... };
342 if(pos.
x < m_tilesRect.
left())
345 if(pos.
y < m_tilesRect.
top())
348 if(pos.
x > m_tilesRect.
right())
351 if(pos.
y > m_tilesRect.
bottom())
354 TileBlock& block = m_tileBlocks[pos.
z][getBlockIndex(pos)];
363 auto it = m_tileBlocks[pos.
z].find(getBlockIndex(pos));
364 if(it != m_tileBlocks[pos.
z].end())
365 return it->second.get(pos);
378 for(
const auto& pair : m_tileBlocks[
z]) {
382 tiles.push_back(tile);
387 for(
const auto& pair : m_tileBlocks[floor]) {
391 tiles.push_back(tile);
404 auto it = m_tileBlocks[pos.
z].find(getBlockIndex(pos));
405 if(it != m_tileBlocks[pos.
z].end()) {
416 for(
auto itt = m_staticTexts.begin(); itt != m_staticTexts.end();) {
418 if(staticText->getPosition() == pos && staticText->getMessageMode() ==
Otc::MessageNone)
419 itt = m_staticTexts.erase(itt);
428 m_zoneFlags |=
static_cast<uint32>(zone);
430 m_zoneFlags &= ~static_cast<uint32>(zone);
437 else if(m_zoneFlags == 0)
443 if((m_zoneFlags & zone) == zone)
444 m_zoneColors[zone] = color;
449 const auto it = m_zoneColors.find(flag);
450 if(it == m_zoneColors.end())
498 std::map<Position, ItemPtr> ret;
501 for(
const auto& pair : m_tileBlocks[
z]) {
504 if(
unlikely(!tile || tile->isEmpty()))
506 for(
const ItemPtr& item : tile->getItems()) {
507 if(item->getId() == clientId) {
508 ret.insert(std::make_pair(tile->getPosition(), item));
522 m_knownCreatures[creature->
getId()] = creature;
527 const auto it = m_knownCreatures.find(
id);
528 if(it == m_knownCreatures.end())
538 const auto it = m_knownCreatures.find(
id);
539 if(it != m_knownCreatures.end())
540 m_knownCreatures.erase(it);
543 void Map::removeUnawareThings()
546 for(
const auto& pair : m_knownCreatures) {
553 for(
auto it = m_staticTexts.begin(); it != m_staticTexts.end();) {
556 it = m_staticTexts.erase(it);
564 std::unordered_map<uint, TileBlock>& tileBlocks = m_tileBlocks[
z];
565 for(
auto it = tileBlocks.begin(); it != tileBlocks.end();) {
567 bool blockEmpty =
true;
571 const Position& pos = tile->getPosition();
582 tile->cancelListenerPainter();
587 it = tileBlocks.erase(it);
597 if(m_centralPosition == centralPosition)
600 m_centralPosition = centralPosition;
602 removeUnawareThings();
609 if(!localPlayer || localPlayer->
getPosition() == m_centralPosition)
612 if(tile && tile->hasThing(localPlayer))
616 const Position pos = m_centralPosition;
618 if(!localPlayer->isRemoved())
619 localPlayer->onDisappear();
620 localPlayer->setPosition(pos);
621 localPlayer->onAppear();
622 g_logger.debug(
"forced player position update");
627 mapView->onMapCenterChange(centralPosition);
649 std::vector<CreaturePtr> creatures;
660 for(
int iz = -minZRange; iz <= maxZRange; ++iz) {
661 for(
int iy = -minYRange; iy <= maxYRange; ++iy) {
662 for(
int ix = -minXRange; ix <= maxXRange; ++ix) {
668 creatures.insert(creatures.end(), tileCreatures.rbegin(), tileCreatures.rend());
686 while(tilePos.
coveredUp() && tilePos.
z >= firstFloor) {
699 while(tilePos.
coveredUp() && tilePos.
z >= firstFloor) {
703 for(
int x = 0; x < 2 && !done; ++x) {
704 for(
int y = 0; y < 2 && !done; ++y) {
726 while(groundedPos.
z != m_centralPosition.
z) {
727 if(groundedPos.
z > m_centralPosition.
z) {
728 if(groundedPos.
x == 65535 || groundedPos.
y == 65535)
732 if(groundedPos.
x == 0 || groundedPos.
y == 0)
738 return m_centralPosition.
isInRange(groundedPos, m_awareRange.
left,
746 m_awareRange = range;
747 removeUnawareThings();
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
783 return b.second < a.second;
788 std::vector<Otc::Direction>& dirs = std::get<0>(ret);
793 if(startPos == goalPos) {
798 if(startPos.
z != goalPos.
z) {
816 std::unordered_map<Position, Node*, PositionHasher> nodes;
817 std::priority_queue<std::pair<Node*, float>, std::vector<std::pair<Node*, float>>, LessNode> searchList;
819 Node* currentNode =
new Node(startPos);
820 currentNode->pos = startPos;
821 nodes[startPos] = currentNode;
822 Node* foundNode =
nullptr;
824 if(
static_cast<int>(nodes.size()) > maxComplexity) {
830 if(currentNode->pos == goalPos && (!foundNode || currentNode->cost < foundNode->cost))
831 foundNode = currentNode;
834 if(foundNode && currentNode->totalCost >= foundNode->cost)
837 for(
int i = -1; i <= 1; ++i) {
838 for(
int j = -1; j <= 1; ++j) {
842 bool wasSeen =
false;
843 bool hasCreature =
false;
844 bool isNotWalkable =
true;
845 bool isNotPathable =
true;
848 Position neighborPos = currentNode->pos.translated(i, j);
852 hasCreature = tile->hasCreature();
854 isNotPathable = !tile->isPathable();
855 speed = tile->getGroundSpeed();
862 if(isNotWalkable || isNotPathable)
867 float walkFactor = 0;
868 if(neighborPos != goalPos) {
888 const Otc::Direction walkDir = currentNode->pos.getDirectionFromPosition(neighborPos);
894 const float cost = currentNode->cost + (speed * walkFactor) / 100.0f;
897 if(nodes.find(neighborPos) == nodes.end()) {
898 neighborNode =
new Node(neighborPos);
899 nodes[neighborPos] = neighborNode;
901 neighborNode = nodes[neighborPos];
902 if(neighborNode->cost <= cost)
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));
914 if(!searchList.empty()) {
915 currentNode = searchList.top().first;
918 currentNode =
nullptr;
922 currentNode = foundNode;
924 dirs.push_back(currentNode->dir);
925 currentNode = currentNode->prev;
928 std::reverse(dirs.begin(), dirs.end());
941 mapView->resetLastCamera();