ManaPlus
map.cpp
Go to the documentation of this file.
1 /*
2  * The ManaPlus Client
3  * Copyright (C) 2004-2009 The Mana World Development Team
4  * Copyright (C) 2009-2010 The Mana Developers
5  * Copyright (C) 2011-2018 The ManaPlus Developers
6  *
7  * This file is part of The ManaPlus Client.
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program. If not, see <http://www.gnu.org/licenses/>.
21  */
22 
23 #include "resources/map/map.h"
24 
25 #include "configuration.h"
26 #include "render/graphics.h"
27 #include "notifymanager.h"
28 #include "settings.h"
29 
30 #include "being/localplayer.h"
31 
33 
36 
37 #include "fs/mkdir.h"
38 
39 #include "gui/userpalette.h"
40 
41 #include "particle/particle.h"
42 
43 #include "resources/ambientlayer.h"
44 
45 #ifdef USE_OPENGL
47 #endif // USE_OPENGL
48 
50 
52 
53 #include "resources/map/location.h"
56 #include "resources/map/maplayer.h"
57 #include "resources/map/mapitem.h"
61 #include "resources/map/tileset.h"
63 
64 #ifdef USE_OPENGL
65 #include "render/renderers.h"
66 #endif // USE_OPENGL
67 
68 #include "utils/checkutils.h"
69 #include "utils/delete2.h"
70 #include "utils/dtor.h"
71 #include "utils/foreach.h"
72 #include "utils/timer.h"
73 
74 #include <sys/stat.h>
75 
76 #include <climits>
77 #include <fstream>
78 #include <queue>
79 
80 #include "debug.h"
81 
83 {
84  public:
86 
87  bool operator()(const Actor *const a,
88  const Actor *const b) const
89  {
90  if ((a == nullptr) || (b == nullptr))
91  return false;
92  return a->getSortPixelY() < b->getSortPixelY();
93  }
94 } actorCompare;
95 
96 Map::Map(const std::string &name,
97  const int width,
98  const int height,
99  const int tileWidth,
100  const int tileHeight) :
101  Properties(),
102  mWidth(width), mHeight(height),
103  mTileWidth(tileWidth), mTileHeight(tileHeight),
104  mMaxTileHeight(height),
105  mMetaTiles(new MetaTile[mWidth * mHeight]),
106  mWalkLayer(nullptr),
107  mLayers(),
108  mDrawUnderLayers(),
109  mDrawOverLayers(),
110  mTilesets(),
111  mActors(),
112  mHasWarps(false),
113  mDrawLayersFlags(MapType::NORMAL),
114  mOnClosedList(1),
115  mOnOpenList(2),
116  mBackgrounds(),
117  mForegrounds(),
118  mLastAScrollX(0.0F),
119  mLastAScrollY(0.0F),
120  mParticleEffects(),
121  mMapPortals(),
122  mTileAnimations(),
123  mName(name),
124  mOverlayDetail(config.getIntValue("OverlayDetail")),
125  mOpacity(config.getFloatValue("guialpha")),
126 #ifdef USE_OPENGL
127  mOpenGL(intToRenderType(config.getIntValue("opengl"))),
128 #else // USE_OPENGL
129  mOpenGL(RENDER_SOFTWARE),
130 #endif // USE_OPENGL
131  mPvp(0),
132  mTilesetsIndexed(false),
133  mIndexedTilesets(nullptr),
134  mIndexedTilesetsSize(0),
135  mActorFixX(0),
136  mActorFixY(0),
137  mVersion(0),
138  mSpecialLayer(new SpecialLayer("special layer", width, height)),
139  mTempLayer(new SpecialLayer("temp layer", width, height)),
140  mObjects(new ObjectsLayer(width, height)),
141  mFringeLayer(nullptr),
142  mLastX(-1),
143  mLastY(-1),
144  mLastScrollX(-1),
145  mLastScrollY(-1),
146  mDrawX(-1),
147  mDrawY(-1),
148  mDrawScrollX(-1),
149  mDrawScrollY(-1),
150  mMask(1),
151 #ifdef USE_OPENGL
152  mAtlas(nullptr),
153 #endif // USE_OPENGL
154  mHeights(nullptr),
155  mRedrawMap(true),
156  mBeingOpacity(false),
157 #ifdef USE_OPENGL
158  mCachedDraw(mOpenGL == RENDER_NORMAL_OPENGL ||
159  mOpenGL == RENDER_GLES_OPENGL ||
160  mOpenGL == RENDER_GLES2_OPENGL ||
161  mOpenGL == RENDER_MODERN_OPENGL),
162 #else // USE_OPENGL
163  mCachedDraw(false),
164 #endif // USE_OPENGL
165  mCustom(false),
166  mDrawOnlyFringe(false)
167 {
168  config.addListener("OverlayDetail", this);
169  config.addListener("guialpha", this);
170  config.addListener("beingopacity", this);
171 
172  if (mOpacity != 1.0F)
173  mBeingOpacity = config.getBoolValue("beingopacity");
174  else
175  mBeingOpacity = false;
176 }
177 
179 {
180  config.removeListeners(this);
182 
183  if (mWalkLayer != nullptr)
184  {
185  mWalkLayer->decRef();
186  mWalkLayer = nullptr;
187  }
188  mFringeLayer = nullptr;
196  delete2(mObjects);
198 #ifdef USE_OPENGL
199  if (mAtlas != nullptr)
200  {
201  mAtlas->decRef();
202  mAtlas = nullptr;
203  }
204 #endif // USE_OPENGL
205  delete2(mHeights);
206  delete [] mMetaTiles;
207 }
208 
209 void Map::optionChanged(const std::string &restrict value) restrict2
210 {
211  if (value == "OverlayDetail")
212  {
213  mOverlayDetail = config.getIntValue("OverlayDetail");
214  }
215  else if (value == "guialpha")
216  {
217  mOpacity = config.getFloatValue("guialpha");
218  if (mOpacity != 1.0F)
219  mBeingOpacity = config.getBoolValue("beingopacity");
220  else
221  mBeingOpacity = false;
222  }
223  else if (value == "beingopacity")
224  {
225  if (mOpacity != 1.0F)
226  mBeingOpacity = config.getBoolValue("beingopacity");
227  else
228  mBeingOpacity = false;
229  }
230 }
231 
233 {
234  // search for "foreground*" or "overlay*" (old term) in map properties
235  for (int i = 0; /* terminated by a break */; i++)
236  {
237  std::string name;
238  if (hasProperty(std::string("foreground").append(
239  toString(i)).append("image")))
240  {
241  name = "foreground" + toString(i);
242  }
243  else if (hasProperty(std::string("overlay").append(
244  toString(i)).append("image")))
245  {
246  name = "overlay" + toString(i);
247  }
248  else
249  {
250  break; // the FOR loop
251  }
252 
253  Image *restrict const img = Loader::getImage(
254  getProperty(name + "image", std::string()));
255  if (img != nullptr)
256  {
257  int mask = atoi(getProperty(name + "mask", std::string()).c_str());
258  if (mask == 0)
259  mask = 1;
260  const float parallax = getFloatProperty(name + "parallax", 0.0F);
261  mForegrounds.push_back(new AmbientLayer(
262  name,
263  img,
264  getFloatProperty(name + "parallaxX", parallax),
265  getFloatProperty(name + "parallaxY", parallax),
266  getFloatProperty(name + "posX", 0.0F),
267  getFloatProperty(name + "posY", 0.0F),
268  getFloatProperty(name + "scrollX", 0.0F),
269  getFloatProperty(name + "scrollY", 0.0F),
270  getBoolProperty(name + "keepratio", false),
271  mask));
272 
273  // The AmbientLayer takes control over the image.
274  img->decRef();
275  }
276  }
277 
278  // search for "background*" in map properties
279  for (int i = 0; hasProperty(std::string("background").append(
280  toString(i)).append("image")); i ++)
281  {
282  const std::string name("background" + toString(i));
283  Image *restrict const img = Loader::getImage(
284  getProperty(name + "image", std::string()));
285 
286  if (img != nullptr)
287  {
288  int mask = atoi(getProperty(name + "mask", std::string()).c_str());
289  if (mask == 0)
290  mask = 1;
291 
292  const float parallax = getFloatProperty(name + "parallax", 0.0F);
293  mBackgrounds.push_back(new AmbientLayer(
294  name,
295  img,
296  getFloatProperty(name + "parallaxX", parallax),
297  getFloatProperty(name + "parallaxY", parallax),
298  getFloatProperty(name + "posX", 0.0F),
299  getFloatProperty(name + "posY", 0.0F),
300  getFloatProperty(name + "scrollX", 0.0F),
301  getFloatProperty(name + "scrollY", 0.0F),
302  getBoolProperty(name + "keepratio", false),
303  mask));
304 
305  // The AmbientLayer takes control over the image.
306  img->decRef();
307  }
308  }
309 }
310 
311 void Map::addLayer(MapLayer *const layer) restrict2
312 {
313  mLayers.push_back(layer);
314  if (layer->isFringeLayer() && (mFringeLayer == nullptr))
315  mFringeLayer = layer;
316 }
317 
318 void Map::addTileset(Tileset *const tileset) restrict2
319 {
320  mTilesets.push_back(tileset);
321  const int height = tileset->getHeight();
322  if (height > mMaxTileHeight)
323  mMaxTileHeight = height;
324 }
325 
326 void Map::update(const int ticks) restrict2
327 {
328  // Update animated tiles
330  {
331  TileAnimation *restrict const tileAni = iAni->second;
332  if ((tileAni != nullptr) && tileAni->update(ticks))
333  mRedrawMap = true;
334  }
335 }
336 
337 void Map::draw(Graphics *restrict const graphics,
338  int scrollX, int scrollY) restrict2
339 {
340  if (localPlayer == nullptr)
341  return;
342 
343  BLOCK_START("Map::draw")
344  // Calculate range of tiles which are on-screen
345  const int endPixelY = graphics->mHeight + scrollY + mTileHeight - 1
347  const int startX = scrollX / mTileWidth - 2;
348  const int startY = scrollY / mTileHeight;
349  const int endX = (graphics->mWidth + scrollX + mTileWidth - 1)
350  / mTileWidth + 1;
351  const int endY = endPixelY / mTileHeight + 1;
352 
353  // Make sure actors are sorted ascending by Y-coordinate
354  // so that they overlap correctly
355  BLOCK_START("Map::draw sort")
356  mActors.sort(actorCompare);
357  BLOCK_END("Map::draw sort")
358 
359  // update scrolling of all ambient layers
360  updateAmbientLayers(static_cast<float>(scrollX),
361  static_cast<float>(scrollY));
362 
363  // Draw backgrounds
364  drawAmbientLayers(graphics,
367 
368  if (mDrawLayersFlags == MapType::BLACKWHITE && (userPalette != nullptr))
369  {
370  graphics->setColor(userPalette->getColorWithAlpha(
372 
373  graphics->fillRectangle(Rect(0, 0,
374  graphics->mWidth, graphics->mHeight));
375  }
376 
377 #ifdef USE_OPENGL
378  int updateFlag = 0;
379 
380  if (mCachedDraw)
381  {
382  if (mLastX != startX || mLastY != startY || mLastScrollX != scrollX
383  || mLastScrollY != scrollY)
384  { // player moving
385  mLastX = startX;
386  mLastY = startY;
387  mLastScrollX = scrollX;
388  mLastScrollY = scrollY;
389  updateFlag = 2;
390  }
391  else if (mRedrawMap || startX != mDrawX || startY != mDrawY ||
392  scrollX != mDrawScrollX || scrollY != mDrawScrollY)
393  { // player mode to new position
394  mRedrawMap = false;
395  mDrawX = startX;
396  mDrawY = startY;
397  mDrawScrollX = scrollX;
398  mDrawScrollY = scrollY;
399  updateFlag = 1;
400  }
401  }
402 #endif // USE_OPENGL
403 
404  if (mDrawOnlyFringe)
405  {
406  if (mFringeLayer != nullptr)
407  {
410  mFringeLayer->drawFringe(graphics,
411  startX, startY,
412  endX, endY,
413  scrollX, scrollY,
414  mActors);
415  }
416  }
417  else
418  {
419 #ifdef USE_OPENGL
420  if (mCachedDraw)
421  {
422  if (updateFlag != 0)
423  {
424  FOR_EACH (Layers::iterator, it, mDrawUnderLayers)
425  {
426  (*it)->updateOGL(graphics,
427  startX, startY,
428  endX, endY,
429  scrollX, scrollY);
430  }
431  FOR_EACH (Layers::iterator, it, mDrawOverLayers)
432  {
433  (*it)->updateOGL(graphics,
434  startX, startY,
435  endX, endY,
436  scrollX, scrollY);
437  }
438  }
439 
440  FOR_EACH (Layers::iterator, it, mDrawUnderLayers)
441  (*it)->drawOGL(graphics);
442 
443  if (mFringeLayer != nullptr)
444  {
447  mFringeLayer->drawFringe(graphics,
448  startX, startY,
449  endX, endY,
450  scrollX, scrollY,
451  mActors);
452  }
453 
454  FOR_EACH (Layers::iterator, it, mDrawOverLayers)
455  (*it)->drawOGL(graphics);
456  }
457  else
458 #endif // USE_OPENGL
459  {
460  FOR_EACH (Layers::iterator, it, mDrawUnderLayers)
461  {
462  (*it)->draw(graphics,
463  startX, startY,
464  endX, endY,
465  scrollX, scrollY);
466  }
467 
468  if (mFringeLayer != nullptr)
469  {
472  mFringeLayer->drawFringe(graphics,
473  startX, startY,
474  endX, endY,
475  scrollX, scrollY,
476  mActors);
477  }
478 
479  FOR_EACH (Layers::iterator, it, mDrawOverLayers)
480  {
481  (*it)->draw(graphics, startX, startY,
482  endX, endY,
483  scrollX, scrollY);
484  }
485  }
486  }
487 
488  // Don't draw if gui opacity == 1
489  if (mBeingOpacity)
490  {
491  // Draws beings with a lower opacity to make them visible
492  // even when covered by a wall or some other elements...
493  ActorsCIter ai = mActors.begin();
494  const ActorsCIter ai_end = mActors.end();
495 
496  if (mOpenGL == RENDER_SOFTWARE)
497  {
498  while (ai != ai_end)
499  {
500  if (Actor *restrict const actor = *ai)
501  {
502  const int x = actor->getTileX();
503  const int y = actor->getTileY();
504  if (x < startX || x > endX || y < startY || y > endY)
505  {
506  ++ai;
507  continue;
508  }
509  // For now, just draw actors with only one layer.
510  if (actor->getNumberOfLayers() == 1)
511  {
512  actor->setAlpha(0.3F);
513  actor->draw(graphics, -scrollX, -scrollY);
514  actor->setAlpha(1.0F);
515  }
516  }
517  ++ai;
518  }
519  }
520  else
521  {
522  while (ai != ai_end)
523  {
524  if (Actor *const actor = *ai)
525  {
526  actor->setAlpha(0.3F);
527  actor->draw(graphics, -scrollX, -scrollY);
528  actor->setAlpha(1.0F);
529  }
530  ++ai;
531  }
532  }
533  }
534 
535  drawAmbientLayers(graphics,
538  BLOCK_END("Map::draw")
539 }
540 
541 #define fillCollision(collision, color) \
542  if (x < endX && mMetaTiles[tilePtr].blockmask & (collision))\
543  {\
544  width = mapTileSize;\
545  for (int x2 = tilePtr + 1; x < endX; x2 ++)\
546  {\
547  if (!(mMetaTiles[x2].blockmask & (collision)))\
548  break;\
549  width += mapTileSize;\
550  x ++;\
551  tilePtr ++;\
552  }\
553  if (width && userPalette)\
554  {\
555  graphics->setColor(userPalette->getColorWithAlpha(\
556  UserColorId::color));\
557  graphics->fillRectangle(Rect(\
558  x0 * mTileWidth - scrollX, \
559  y * mTileHeight - scrollY, \
560  width, mapTileSize));\
561  }\
562  }\
563 
564 void Map::drawCollision(Graphics *restrict const graphics,
565  const int scrollX,
566  const int scrollY,
567  const MapTypeT drawFlags) const restrict2
568 {
569  const int endPixelY = graphics->mHeight + scrollY + mTileHeight - 1;
570  int startX = scrollX / mTileWidth;
571  int startY = scrollY / mTileHeight;
572  int endX = (graphics->mWidth + scrollX + mTileWidth - 1) / mTileWidth;
573  int endY = endPixelY / mTileHeight;
574 
575  if (startX < 0)
576  startX = 0;
577  if (startY < 0)
578  startY = 0;
579  if (endX > mWidth)
580  endX = mWidth;
581  if (endY > mHeight)
582  endY = mHeight;
583 
584  if (drawFlags < MapType::SPECIAL)
585  {
586  graphics->setColor(userPalette->getColorWithAlpha(UserColorId::NET));
587  graphics->drawNet(
588  startX * mTileWidth - scrollX,
589  startY * mTileHeight - scrollY,
590  endX * mTileWidth - scrollX,
591  endY * mTileHeight - scrollY,
593  }
594 
595  for (int y = startY; y < endY; y++)
596  {
597  const int yWidth = y * mWidth;
598  int tilePtr = startX + yWidth;
599  for (int x = startX; x < endX; x++, tilePtr++)
600  {
601  int width = 0;
602  const int x0 = x;
603 
610  }
611  }
612 }
613 
614 void Map::updateAmbientLayers(const float scrollX,
615  const float scrollY) restrict2
616 {
617  BLOCK_START("Map::updateAmbientLayers")
618  static int lastTick = tick_time;
619 
620  if (mLastAScrollX == 0.0F && mLastAScrollY == 0.0F)
621  {
622  // First call - initialisation
623  mLastAScrollX = scrollX;
624  mLastAScrollY = scrollY;
625  }
626 
627  // Update Overlays
628  const float dx = scrollX - mLastAScrollX;
629  const float dy = scrollY - mLastAScrollY;
630  const int timePassed = get_elapsed_time(lastTick);
631 
632  // need check mask to update or not to update
633 
635  {
636  AmbientLayer *const layer = *i;
637  if ((layer != nullptr) && ((layer->mMask & mMask) != 0))
638  layer->update(timePassed, dx, dy);
639  }
640 
642  {
643  AmbientLayer *const layer = *i;
644  if ((layer != nullptr) && ((layer->mMask & mMask) != 0))
645  layer->update(timePassed, dx, dy);
646  }
647 
648  mLastAScrollX = scrollX;
649  mLastAScrollY = scrollY;
650  lastTick = tick_time;
651  BLOCK_END("Map::updateAmbientLayers")
652 }
653 
655  const MapLayerPositionT type,
656  const int detail) const restrict2
657 {
658  BLOCK_START("Map::drawAmbientLayers")
659  // Detail 0 = no ambient effects except background image
660  if (detail <= 0 && type != MapLayerPosition::BACKGROUND_LAYERS)
661  {
662  BLOCK_END("Map::drawAmbientLayers")
663  return;
664  }
665 
666  // find out which layer list to draw
667  const AmbientLayerVector *restrict layers = nullptr;
668  switch (type)
669  {
671  layers = &mForegrounds;
672  break;
674  layers = &mBackgrounds;
675  break;
676  default:
677  return;
678  }
679 
680  // Draw overlays
682  {
683  const AmbientLayer *restrict const layer = *i;
684  // need check mask to draw or not to draw
685  if ((layer != nullptr) && ((layer->mMask & mMask) != 0))
686  (layer)->draw(graphics, graphics->mWidth, graphics->mHeight);
687 
688  // Detail 1: only one overlay, higher: all overlays
689  if (detail == 1)
690  break;
691  }
692  BLOCK_END("Map::drawAmbientLayers")
693 }
694 
695 const Tileset *Map::getTilesetWithGid(const int gid) const restrict2
696 {
697  if (gid >= 0 && gid < mIndexedTilesetsSize)
698  return mIndexedTilesets[gid];
699  return nullptr;
700 }
701 
702 void Map::addBlockMask(const int x, const int y,
703  const BlockTypeT type) restrict2
704 {
705  if (type == BlockType::NONE || !contains(x, y))
706  return;
707 
708  const int tileNum = x + y * mWidth;
709 
710  switch (type)
711  {
712  case BlockType::WALL:
714  break;
715  case BlockType::AIR:
716  mMetaTiles[tileNum].blockmask |= BlockMask::AIR;
717  break;
718  case BlockType::WATER:
720  break;
721  case BlockType::GROUND:
723  break;
726  break;
729  break;
732  break;
733  default:
734  case BlockType::NONE:
736  // Do nothing.
737  break;
738  }
739 }
740 
741 void Map::setBlockMask(const int x, const int y,
742  const BlockTypeT type) restrict2
743 {
744  if (type == BlockType::NONE || !contains(x, y))
745  return;
746 
747  const int tileNum = x + y * mWidth;
748 
749  switch (type)
750  {
751  case BlockType::WALL:
753  break;
754  case BlockType::AIR:
756  break;
757  case BlockType::WATER:
759  break;
760  case BlockType::GROUND:
762  break;
765  break;
768  break;
771  break;
772  default:
773  case BlockType::NONE:
775  // Do nothing.
776  break;
777  }
778 }
779 
780 bool Map::getWalk(const int x, const int y,
781  const unsigned char blockWalkMask) const restrict2
782 {
783  // You can't walk outside of the map
784  if (x < 0 || y < 0 || x >= mWidth || y >= mHeight)
785  return false;
786 
787  // Check if the tile is walkable
788  return (mMetaTiles[x + y * mWidth].blockmask & blockWalkMask) == 0;
789 }
790 
791 unsigned char Map::getBlockMask(const int x,
792  const int y) const restrict2
793 {
794  // You can't walk outside of the map
795  if (x < 0 || y < 0 || x >= mWidth || y >= mHeight)
796  return 0;
797 
798  // Check if the tile is walkable
799  return mMetaTiles[x + y * mWidth].blockmask;
800 }
801 
802 void Map::setWalk(const int x, const int y) restrict2
803 {
805 }
806 
807 bool Map::contains(const int x, const int y) const restrict2
808 {
809  return x >= 0 && y >= 0 && x < mWidth && y < mHeight;
810 }
811 
812 const MetaTile *Map::getMetaTile(const int x, const int y) const restrict2
813 {
814  return &mMetaTiles[x + y * mWidth];
815 }
816 
817 Actors::iterator Map::addActor(Actor *const actor) restrict2
818 {
819  mActors.push_front(actor);
820 // mSpritesUpdated = true;
821  return mActors.begin();
822 }
823 
824 void Map::removeActor(const Actors::iterator &restrict iterator) restrict2
825 {
826  mActors.erase(iterator);
827 // mSpritesUpdated = true;
828 }
829 
830 const std::string Map::getMusicFile() const restrict2
831 {
832  return getProperty("music", std::string());
833 }
834 
835 const std::string Map::getName() const restrict2
836 {
837  if (hasProperty("name"))
838  return getProperty("name", std::string());
839 
840  return getProperty("mapname", std::string());
841 }
842 
843 const std::string Map::getFilename() const restrict2
844 {
845  const std::string fileName = getProperty("_filename", std::string());
846  const size_t lastSlash = fileName.rfind('/') + 1;
847  return fileName.substr(lastSlash, fileName.rfind('.') - lastSlash);
848 }
849 
850 const std::string Map::getGatName() const restrict2
851 {
852  const std::string fileName = getProperty("_filename", std::string());
853  const size_t lastSlash = fileName.rfind('/') + 1;
854  return fileName.substr(lastSlash,
855  fileName.rfind('.') - lastSlash).append(".gat");
856 }
857 
858 Path Map::findPath(const int startX, const int startY,
859  const int destX, const int destY,
860  const unsigned char blockWalkMask,
861  const int maxCost) restrict2
862 {
863  BLOCK_START("Map::findPath")
864  // The basic walking cost of a tile.
865  static const int basicCost = 100;
866  const int basicCost2 = 100 * 362 / 256;
867  const float basicCostF = 100.0 * 362 / 256;
868 
869  // Path to be built up (empty by default)
870  Path path;
871 
872  if (startX >= mWidth || startY >= mHeight || startX < 0 || startY < 0)
873  {
874  BLOCK_END("Map::findPath")
875  return path;
876  }
877 
878  // Return when destination not walkable
879  if (!getWalk(destX, destY, blockWalkMask))
880  {
881  BLOCK_END("Map::findPath")
882  return path;
883  }
884 
885  // Reset starting tile's G cost to 0
886  MetaTile *const startTile = &mMetaTiles[startX + startY * mWidth];
887  if (startTile == nullptr)
888  {
889  BLOCK_END("Map::findPath")
890  return path;
891  }
892 
893  startTile->Gcost = 0;
894 
895  // Declare open list, a list with open tiles sorted on F cost
896  std::priority_queue<Location> openList;
897 
898  // Add the start point to the open list
899  openList.push(Location(startX, startY, startTile));
900 
901  bool foundPath = false;
902 
903  // Keep trying new open tiles until no more tiles to try or target found
904  while (!openList.empty() && !foundPath)
905  {
906  // Take the location with the lowest F cost from the open list.
907  const Location curr = openList.top();
908  openList.pop();
909 
910  const MetaTile *const tile = curr.tile;
911 
912  // If the tile is already on the closed list, this means it has already
913  // been processed with a shorter path to the start point (lower G cost)
914  if (tile->whichList == mOnClosedList)
915  continue;
916 
917  // Put the current tile on the closed list
918  curr.tile->whichList = mOnClosedList;
919 
920  const int curWidth = curr.y * mWidth;
921  const int tileGcost = tile->Gcost;
922 
923  // Check the adjacent tiles
924  for (int dy = -1; dy <= 1; dy++)
925  {
926  const int y = curr.y + dy;
927  if (y < 0 || y >= mHeight)
928  continue;
929 
930  const int yWidth = y * mWidth;
931  const int dy1 = std::abs(y - destY);
932 
933  for (int dx = -1; dx <= 1; dx++)
934  {
935  // Calculate location of tile to check
936  const int x = curr.x + dx;
937 
938  // Skip if if we're checking the same tile we're leaving from,
939  // or if the new location falls outside of the map boundaries
940  if ((dx == 0 && dy == 0) || x < 0 || x >= mWidth)
941  continue;
942 
943  MetaTile *const newTile = &mMetaTiles[x + yWidth];
944 
945  // Skip if the tile is on the closed list or is not walkable
946  // unless its the destination tile
947  // +++ probably here "newTile->blockmask & BlockMask::WALL"
948  // can be removed. It left here only for protect from
949  // walk on wall in any case
950  if (newTile->whichList == mOnClosedList ||
951  (((newTile->blockmask & blockWalkMask) != 0)
952  && !(x == destX && y == destY))
953  || ((newTile->blockmask & BlockMask::WALL) != 0))
954  {
955  continue;
956  }
957 
958  // When taking a diagonal step, verify that we can skip the
959  // corner.
960  if (dx != 0 && dy != 0)
961  {
962  const MetaTile *const t1 = &mMetaTiles[curr.x +
963  (curr.y + dy) * mWidth];
964  const MetaTile *const t2 = &mMetaTiles[curr.x +
965  dx + curWidth];
966 
967  // on player abilities.
968  if (((t1->blockmask | t2->blockmask) & blockWalkMask) != 0)
969  continue;
970  }
971 
972  // Calculate G cost for this route, ~sqrt(2) for moving diagonal
973  int Gcost = tileGcost + (dx == 0 || dy == 0
974  ? basicCost : basicCost2);
975 
976  /* Demote an arbitrary direction to speed pathfinding by
977  adding a defect
978  Important: as long as the total defect along any path is
979  less than the basicCost, the pathfinder will still find one
980  of the shortest paths! */
981  if (dx == 0 || dy == 0)
982  {
983  // Demote horizontal and vertical directions, so that two
984  // consecutive directions cannot have the same Fcost.
985  ++Gcost;
986  }
987 
988 /*
989  // It costs extra to walk through a being (needs to be enough
990  // to make it more attractive to walk around).
991  if (occupied(x, y))
992  {
993  Gcost += 3 * basicCost;
994  }
995 */
996 
997  // Skip if Gcost becomes too much
998  // Warning: probably not entirely accurate
999  if (maxCost > 0 && Gcost > maxCost * basicCost)
1000  continue;
1001 
1002  if (newTile->whichList != mOnOpenList)
1003  {
1004  // Found a new tile (not on open nor on closed list)
1005 
1006  /* Update Hcost of the new tile. The pathfinder does not
1007  work reliably if the heuristic cost is higher than the
1008  real cost. In particular, using Manhattan distance is
1009  forbidden here. */
1010  const int dx1 = std::abs(x - destX);
1011  newTile->Hcost = std::abs(dx1 - dy1) * basicCost +
1012  CAST_S32(static_cast<float>(std::min(dx1, dy1)) *
1013  (basicCostF));
1014 
1015  // Set the current tile as the parent of the new tile
1016  newTile->parentX = curr.x;
1017  newTile->parentY = curr.y;
1018 
1019  // Update Gcost and Fcost of new tile
1020  newTile->Gcost = Gcost;
1021  newTile->Fcost = Gcost + newTile->Hcost;
1022 
1023  if (x != destX || y != destY)
1024  {
1025  // Add this tile to the open list
1026  newTile->whichList = mOnOpenList;
1027  openList.push(Location(x, y, newTile));
1028  }
1029  else
1030  {
1031  // Target location was found
1032  foundPath = true;
1033  }
1034  }
1035  else if (Gcost < newTile->Gcost)
1036  {
1037  // Found a shorter route.
1038  // Update Gcost and Fcost of the new tile
1039  newTile->Gcost = Gcost;
1040  newTile->Fcost = Gcost + newTile->Hcost;
1041 
1042  // Set the current tile as the parent of the new tile
1043  newTile->parentX = curr.x;
1044  newTile->parentY = curr.y;
1045 
1046  // Add this tile to the open list (it's already
1047  // there, but this instance has a lower F score)
1048  openList.push(Location(x, y, newTile));
1049  }
1050  }
1051  }
1052  }
1053 
1054  // Two new values to indicate whether a tile is on the open or closed list,
1055  // this way we don't have to clear all the values between each pathfinding.
1056  if (mOnOpenList > UINT_MAX - 2)
1057  {
1058  // We reset the list memebers value.
1059  mOnClosedList = 1;
1060  mOnOpenList = 2;
1061 
1062  // Clean up the metaTiles
1063  const int size = mWidth * mHeight;
1064  for (int i = 0; i < size; ++i)
1065  mMetaTiles[i].whichList = 0;
1066  }
1067  else
1068  {
1069  mOnClosedList += 2;
1070  mOnOpenList += 2;
1071  }
1072 
1073  // If a path has been found, iterate backwards using the parent locations
1074  // to extract it.
1075  if (foundPath)
1076  {
1077  int pathX = destX;
1078  int pathY = destY;
1079 
1080  while (pathX != startX || pathY != startY)
1081  {
1082  // Add the new path node to the start of the path list
1083  path.push_front(Position(pathX, pathY));
1084 
1085  // Find out the next parent
1086  const MetaTile *const tile = &mMetaTiles[pathX + pathY * mWidth];
1087  pathX = tile->parentX;
1088  pathY = tile->parentY;
1089  }
1090  }
1091 
1092  BLOCK_END("Map::findPath")
1093  return path;
1094 }
1095 
1096 void Map::addParticleEffect(const std::string &effectFile,
1097  const int x, const int y,
1098  const int w, const int h) restrict2
1099 {
1100  ParticleEffectData newEffect(effectFile, x, y, w, h);
1101  mParticleEffects.push_back(newEffect);
1102 }
1103 
1105 {
1106  BLOCK_START("Map::initializeParticleEffects")
1107  if (particleEngine == nullptr)
1108  {
1109  BLOCK_END("Map::initializeParticleEffects")
1110  return;
1111  }
1112 
1113  if (config.getBoolValue("particleeffects"))
1114  {
1115  for (STD_VECTOR<ParticleEffectData>::const_iterator
1116  i = mParticleEffects.begin();
1117  i != mParticleEffects.end();
1118  ++i)
1119  {
1120  // +++ add z for map particle effects?
1121  Particle *const p = particleEngine->addEffect(
1122  i->file,
1123  i->x,
1124  i->y,
1125  0);
1126  if ((p != nullptr) &&
1127  i->w > 0 &&
1128  i->h > 0)
1129  {
1130  p->adjustEmitterSize(i->w, i->h);
1131  }
1132  }
1133  }
1134  BLOCK_END("Map::initializeParticleEffects")
1135 }
1136 
1138 {
1139  BLOCK_START("Map::addExtraLayer")
1140  if (mSpecialLayer == nullptr)
1141  {
1142  logger->log1("No special layer");
1143  BLOCK_END("Map::addExtraLayer")
1144  return;
1145  }
1146  const std::string mapFileName = pathJoin(getUserMapDirectory(),
1147  "extralayer.txt");
1148  logger->log("loading extra layer: " + mapFileName);
1149  struct stat statbuf;
1150  if (stat(mapFileName.c_str(), &statbuf) == 0 &&
1151  S_ISREG(statbuf.st_mode))
1152  {
1153  std::ifstream mapFile;
1154  mapFile.open(mapFileName.c_str(), std::ios::in);
1155  if (!mapFile.is_open())
1156  {
1157  mapFile.close();
1158  BLOCK_END("Map::addExtraLayer")
1159  return;
1160  }
1161  char line[201];
1162 
1163  while (mapFile.getline(line, 200))
1164  {
1165  std::string buf;
1166  std::string str = line;
1167  if (!str.empty())
1168  {
1169  std::string x;
1170  std::string y;
1171  std::string type1;
1172  std::string comment;
1173  std::stringstream ss(str);
1174  ss >> x;
1175  ss >> y;
1176  ss >> type1;
1177  ss >> comment;
1178  while (ss >> buf)
1179  comment.append(" ").append(buf);
1180 
1181  const int type = atoi(type1.c_str());
1182 
1183  if (comment.empty())
1184  {
1185  if (type < MapItemType::ARROW_UP
1186  || type > MapItemType::ARROW_RIGHT)
1187  {
1188  comment = "unknown";
1189  }
1190  }
1191  if (type == MapItemType::PORTAL)
1192  {
1193  updatePortalTile(comment,
1194  type,
1195  atoi(x.c_str()),
1196  atoi(y.c_str()),
1197  false);
1198  }
1199  else if (type == MapItemType::HOME)
1200  {
1201  updatePortalTile(comment,
1202  type,
1203  atoi(x.c_str()),
1204  atoi(y.c_str()),
1205  true);
1206  }
1207  else
1208  {
1209  addPortalTile(comment,
1210  type,
1211  atoi(x.c_str()),
1212  atoi(y.c_str()));
1213  }
1214  }
1215  }
1216  mapFile.close();
1217  }
1218  BLOCK_END("Map::addExtraLayer")
1219 }
1220 
1222 {
1223  if (mSpecialLayer == nullptr)
1224  {
1225  logger->log1("No special layer");
1226  return;
1227  }
1228  const std::string mapFileName = pathJoin(getUserMapDirectory(),
1229  "extralayer.txt");
1230  logger->log("saving extra layer: " + mapFileName);
1231 
1232  if (mkdir_r(getUserMapDirectory().c_str()) != 0)
1233  {
1234  logger->log(strprintf("%s doesn't exist and can't be created! "
1235  "Exiting.", getUserMapDirectory().c_str()));
1236  return;
1237  }
1238 
1239  std::ofstream mapFile;
1240  mapFile.open(mapFileName.c_str(), std::ios::binary);
1241  if (!mapFile.is_open())
1242  {
1243  reportAlways("Error opening file for writing: %s",
1244  mapFileName.c_str());
1245  return;
1246  }
1247 
1248  const int width = mSpecialLayer->mWidth;
1249  const int height = mSpecialLayer->mHeight;
1250 
1251  for (int x = 0; x < width; x ++)
1252  {
1253  for (int y = 0; y < height; y ++)
1254  {
1255  const MapItem *restrict const item = mSpecialLayer->getTile(x, y);
1256  if ((item != nullptr) && item->mType != MapItemType::EMPTY
1257  && item->mType != MapItemType::HOME)
1258  {
1259  mapFile << x << " " << y << " "
1260  << CAST_S32(item->mType) << " "
1261  << item->mComment << std::endl;
1262  }
1263  }
1264  }
1265  mapFile.close();
1266 }
1267 
1269 {
1271  getProperty("_realfilename", std::string()));
1272 }
1273 
1274 void Map::addRange(const std::string &restrict name,
1275  const int type,
1276  const int x, const int y,
1277  const int dx, const int dy) restrict2
1278 {
1279  if (mObjects == nullptr)
1280  return;
1281 
1282  mObjects->addObject(name, type, x / mapTileSize, y / mapTileSize,
1283  dx / mapTileSize, dy / mapTileSize);
1284 }
1285 
1286 void Map::addPortal(const std::string &restrict name,
1287  const int type,
1288  const int x, const int y,
1289  const int dx, const int dy) restrict2
1290 {
1291  addPortalTile(name, type, (x / mapTileSize) + (dx / mapTileSize / 2),
1292  (y / mapTileSize) + (dy / mapTileSize / 2));
1293 }
1294 
1295 void Map::addPortalTile(const std::string &restrict name,
1296  const int type,
1297  const int x, const int y) restrict2
1298 {
1299  if (mSpecialLayer != nullptr)
1300  {
1301  mSpecialLayer->setTile(x, y, new MapItem(type, name, x, y));
1303  }
1304 
1305  mMapPortals.push_back(new MapItem(type, name, x, y));
1306 }
1307 
1308 void Map::updatePortalTile(const std::string &restrict name,
1309  const int type,
1310  const int x, const int y,
1311  const bool addNew) restrict2
1312 {
1314  if (item != nullptr)
1315  {
1316  item->mComment = name;
1317  item->setType(type);
1318  item->mX = x;
1319  item->mY = y;
1320  if (mSpecialLayer != nullptr)
1321  {
1322  item = new MapItem(type, name, x, y);
1323  mSpecialLayer->setTile(x, y, item);
1325  }
1326  }
1327  else if (addNew)
1328  {
1329  addPortalTile(name, type, x, y);
1330  }
1331 }
1332 
1333 MapItem *Map::findPortalXY(const int x, const int y) const restrict2
1334 {
1335  FOR_EACH (STD_VECTOR<MapItem*>::const_iterator, it, mMapPortals)
1336  {
1337  if (*it == nullptr)
1338  continue;
1339 
1340  MapItem *restrict const item = *it;
1341  if (item->mX == x && item->mY == y)
1342  return item;
1343  }
1344  return nullptr;
1345 }
1346 
1348 {
1349  if (mTileAnimations.empty())
1350  return nullptr;
1351 
1352  const TileAnimationMapCIter i = mTileAnimations.find(gid);
1353  return (i == mTileAnimations.end()) ? nullptr : i->second;
1354 }
1355 
1356 void Map::setPvpMode(const int mode) restrict2
1357 {
1358  const int oldMode = mPvp;
1359 
1360  if (mode == 0)
1361  mPvp = 0;
1362  else
1363  mPvp |= mode;
1364 
1365  if (mPvp != oldMode && (localPlayer != nullptr))
1366  {
1367  switch (mPvp)
1368  {
1369  case 0:
1371  break;
1372  case 1:
1374  break;
1375  case 2:
1377  break;
1378  case 3:
1380  break;
1381  default:
1383  break;
1384  }
1385  }
1386 }
1387 
1388 std::string Map::getObjectData(const unsigned x, const unsigned y,
1389  const int type) const restrict2
1390 {
1391  if (mObjects == nullptr)
1392  return "";
1393 
1394  MapObjectList *restrict const list = mObjects->getAt(x, y);
1395  if (list == nullptr)
1396  return "";
1397 
1398  STD_VECTOR<MapObject>::const_iterator it = list->objects.begin();
1399  const STD_VECTOR<MapObject>::const_iterator it_end = list->objects.end();
1400  while (it != it_end)
1401  {
1402  if ((*it).type == type)
1403  return (*it).data;
1404  ++ it;
1405  }
1406 
1407  return "";
1408 }
1409 
1411 {
1412  if (mTilesetsIndexed)
1413  return;
1414 
1415  mTilesetsIndexed = true;
1416 
1417  const Tileset *restrict s = nullptr;
1418  size_t sSz = 0;
1419  FOR_EACH (Tilesets::const_iterator, it, mTilesets)
1420  {
1421  const size_t sz = (*it)->size();
1422  if ((s == nullptr) || CAST_SIZE(s->getFirstGid()) + sSz
1423  < CAST_SIZE((*it)->getFirstGid()) + sz)
1424  {
1425  s = *it;
1426  sSz = sz;
1427  }
1428  }
1429  if (s == nullptr)
1430  {
1432  mIndexedTilesets = nullptr;
1433  return;
1434  }
1435 
1436  const int size = CAST_S32(s->getFirstGid())
1437  + CAST_S32(s->size());
1439  mIndexedTilesets = new Tileset*[CAST_SIZE(size)];
1440  std::fill_n(mIndexedTilesets, size, static_cast<Tileset*>(nullptr));
1441 
1442  FOR_EACH (Tilesets::const_iterator, it, mTilesets)
1443  {
1444  Tileset *restrict const s2 = *it;
1445  if (s2 != nullptr)
1446  {
1447  const int start = s2->getFirstGid();
1448  const int end = start + CAST_S32(s2->size());
1449  for (int f = start; f < end; f ++)
1450  {
1451  if (f < size)
1452  mIndexedTilesets[f] = s2;
1453  }
1454  }
1455  }
1456 }
1457 
1459 {
1460  if (!mTilesetsIndexed)
1461  return;
1462 
1463  mTilesetsIndexed = false;
1464  delete [] mIndexedTilesets;
1466 }
1467 
1469 {
1470 #ifndef USE_SDL2
1471  if ((mFringeLayer == nullptr) ||
1472  mOpenGL != RENDER_SOFTWARE ||
1473  !config.getBoolValue("enableMapReduce"))
1474  {
1475  return;
1476  }
1477 
1478  int cnt = 0;
1479  for (int x = 0; x < mWidth; x ++)
1480  {
1481  for (int y = 0; y < mHeight; y ++)
1482  {
1483  bool correct(true);
1484  bool dontHaveAlpha(false);
1485 
1486  FOR_EACH (LayersCIter, layeri, mLayers)
1487  {
1488  const MapLayer *restrict const layer = *layeri;
1489  if (x >= layer->mWidth || y >= layer->mHeight)
1490  continue;
1491 
1492  // skip layers with flags
1493  if (layer->mTileCondition != -1 || layer->mMask != 1)
1494  continue;
1495 
1496  Image *restrict const img =
1497  layer->mTiles[x + y * layer->mWidth].image;
1498  if (img != nullptr)
1499  {
1500  if (img->hasAlphaChannel() && img->isAlphaCalculated())
1501  {
1502  if (!img->isAlphaVisible())
1503  {
1504  dontHaveAlpha = true;
1505  img->setAlphaVisible(false);
1506  }
1507  }
1508  else if (img->mBounds.w > mapTileSize
1509  || img->mBounds.h > mapTileSize)
1510  {
1511  correct = false;
1512  img->setAlphaVisible(true);
1513  break;
1514  }
1515  else if (!img->isHasAlphaChannel())
1516  {
1517  dontHaveAlpha = true;
1518  img->setAlphaVisible(false);
1519  }
1520  else if (img->hasAlphaChannel())
1521  {
1522  const uint8_t *restrict const arr =
1523  img->SDLgetAlphaChannel();
1524  if (arr == nullptr)
1525  continue;
1526 
1527  bool bad(false);
1528  bool stop(false);
1529  int width;
1530  const SubImage *restrict const subImg
1531  = dynamic_cast<SubImage*>(img);
1532  if (subImg != nullptr)
1533  width = subImg->mInternalBounds.w;
1534  else
1535  width = img->mBounds.w;
1536 
1537  for (int f = img->mBounds.x;
1538  f < img->mBounds.x + img->mBounds.w; f ++)
1539  {
1540  for (int d = img->mBounds.y;
1541  d < img->mBounds.y + img->mBounds.h; d ++)
1542  {
1543  const uint8_t chan = arr[f + d * width];
1544  if (chan != 255)
1545  {
1546  bad = true;
1547  stop = true;
1548  break;
1549  }
1550  }
1551  if (stop)
1552  break;
1553  }
1554  if (!bad)
1555  {
1556  dontHaveAlpha = true;
1557  img->setAlphaVisible(false);
1558  }
1559  else
1560  {
1561  img->setAlphaVisible(true);
1562  }
1563  }
1564  img->setAlphaCalculated(true);
1565  }
1566  }
1567  if (!correct || !dontHaveAlpha)
1568  continue;
1569 
1570  Layers::reverse_iterator ri = mLayers.rbegin();
1571  while (ri != mLayers.rend())
1572  {
1573  const MapLayer *restrict const layer = *ri;
1574  if (x >= layer->mWidth || y >= layer->mHeight)
1575  {
1576  ++ ri;
1577  continue;
1578  }
1579 
1580  // skip layers with flags
1581  if (layer->mTileCondition != -1 || layer->mMask != 1)
1582  {
1583  ++ ri;
1584  continue;
1585  }
1586 
1587  const Image *restrict img =
1588  layer->mTiles[x + y * layer->mWidth].image;
1589  if ((img != nullptr) && !img->isAlphaVisible())
1590  { // removing all down tiles
1591  ++ ri;
1592  while (ri != mLayers.rend())
1593  {
1594  MapLayer *restrict const layer2 = *ri;
1595  // skip layers with flags
1596  if (layer2->mTileCondition != -1 || layer2->mMask != 1)
1597  {
1598  ++ ri;
1599  continue;
1600  }
1601  const size_t pos = x + y * CAST_SIZE(layer2->mWidth);
1602  img = layer2->mTiles[pos].image;
1603  if (img != nullptr)
1604  {
1605  layer2->mTiles[pos].image = nullptr;
1606  cnt ++;
1607  }
1608  ++ ri;
1609  }
1610  break;
1611  }
1612  ++ ri;
1613  }
1614  }
1615  }
1616  logger->log("tiles reduced: %d", cnt);
1617 #endif // USE_SDL2
1618 }
1619 
1620 void Map::addHeights(const MapHeights *restrict const heights) restrict2
1621 {
1622  delete mHeights;
1623  mHeights = heights;
1624 }
1625 
1626 uint8_t Map::getHeightOffset(const int x, const int y) const restrict2
1627 {
1628  if (mHeights == nullptr)
1629  return 0;
1630  return mHeights->getHeight(x, y);
1631 }
1632 
1634 {
1635  mDrawUnderLayers.clear();
1636  mDrawOverLayers.clear();
1637 
1638  if (mDrawOnlyFringe)
1639  return;
1640 
1641  LayersCIter layers = mLayers.begin();
1642  const LayersCIter layers_end = mLayers.end();
1643  for (; layers != layers_end; ++ layers)
1644  {
1645  MapLayer *const layer = *layers;
1646  if ((layer->mMask & mMask) == 0)
1647  continue;
1648 
1649  if (layer->isFringeLayer())
1650  {
1651  ++ layers;
1652  break;
1653  }
1654 
1655  mDrawUnderLayers.push_back(layer);
1656  }
1657 
1659  return;
1660 
1661  for (; layers != layers_end; ++ layers)
1662  {
1663  MapLayer *const layer = *layers;
1664  if ((layer->mMask & mMask) == 0)
1665  continue;
1666 
1667  mDrawOverLayers.push_back(layer);
1668  }
1669 }
1670 
1671 void Map::setMask(const int mask) restrict2
1672 {
1673  if (mask != mMask)
1674  {
1675  mRedrawMap = true;
1676  mMask = mask;
1678  }
1679 }
1680 
1681 void Map::setMusicFile(const std::string &restrict file) restrict2
1682 {
1683  setProperty("music", file);
1684 }
1685 
1686 void Map::addAnimation(const int gid,
1687  TileAnimation *restrict const animation) restrict2
1688 {
1689  std::map<int, TileAnimation*>::iterator it = mTileAnimations.find(gid);
1690  if (it != mTileAnimations.end())
1691  {
1692  logger->log("duplicate map animation with gid = %d", gid);
1693  delete (*it).second;
1694  }
1695  mTileAnimations[gid] = animation;
1696 }
1697 
1699 {
1700  mDrawLayersFlags = n;
1704  {
1705  mDrawOnlyFringe = true;
1706  }
1707  else
1708  {
1709  mDrawOnlyFringe = false;
1710  }
1712  FOR_EACH (Layers::iterator, it, mLayers)
1713  {
1714  MapLayer *restrict const layer = *it;
1715  layer->setDrawLayerFlags(mDrawLayersFlags);
1716  }
1717 }
1718 
1719 void Map::setActorsFix(const int x, const int y) restrict2
1720 {
1721  mActorFixX = x;
1722  mActorFixY = y;
1723  if (mFringeLayer != nullptr)
1725 }
1726 
1728 {
1729  mRedrawMap = true;
1730 
1732  {
1733  MapLayer *restrict const layer = *it;
1734  if ((layer == nullptr) || layer->mTileCondition == -1)
1735  continue;
1736  layer->updateConditionTiles(mMetaTiles,
1737  mWidth, mHeight);
1738  }
1739 }
1740 
1742 {
1744  {
1745  MapLayer *restrict const layer = *it;
1746  if (layer != nullptr)
1747  layer->updateCache(mWidth, mHeight);
1748  }
1749 }
1750 
1752 {
1753  return static_cast<int>(sizeof(Map) +
1754  mName.capacity() +
1755  sizeof(MetaTile) * mWidth * mHeight +
1756  sizeof(MapLayer*) * (mLayers.capacity() +
1757  mDrawUnderLayers.capacity() +
1758  mDrawOverLayers.capacity()) +
1759  sizeof(Tileset*) * mTilesets.capacity() +
1760  sizeof(Actor*) * mActors.size() +
1761  sizeof(AmbientLayer*) * (mBackgrounds.capacity()
1762  + mForegrounds.capacity()) +
1763  sizeof(ParticleEffectData) * mParticleEffects.capacity() +
1764  sizeof(MapItem) * mMapPortals.capacity() +
1765  (sizeof(TileAnimation) + sizeof(int)) * mTileAnimations.size() +
1766  sizeof(Tileset*) * mIndexedTilesetsSize);
1767 }
1768 
1769 int Map::calcMemoryChilds(const int level) const
1770 {
1771  int sz = 0;
1772 
1773  if (mWalkLayer != nullptr)
1774  sz += mWalkLayer->calcMemory(level + 1);
1776  {
1777  sz += (*it)->calcMemory(level + 1);
1778  }
1779  FOR_EACH (Tilesets::const_iterator, it, mTilesets)
1780  {
1781  sz += (*it)->calcMemory(level + 1);
1782  }
1784  {
1785  sz += (*it)->calcMemory(level + 1);
1786  }
1788  {
1789  sz += (*it)->calcMemory(level + 1);
1790  }
1791  if (mSpecialLayer != nullptr)
1792  mSpecialLayer->calcMemory(level + 1);
1793  if (mTempLayer != nullptr)
1794  mTempLayer->calcMemory(level + 1);
1795  if (mObjects != nullptr)
1796  mObjects->calcMemory(level + 1);
1797  if (mHeights != nullptr)
1798  mHeights->calcMemory(level + 1);
1799  return sz;
1800 }
1801 
1802 #ifdef USE_OPENGL
1804 {
1805  if (mAtlas == nullptr)
1806  return 0;
1807  return CAST_S32(mAtlas->atlases.size());
1808 }
1809 #endif // USE_OPENGL
int mLastScrollY
Definition: map.h:486
const int mTileHeight
Definition: map.h:412
#define FOR_EACH(type, iter, array)
Definition: foreach.h:24
void addTileset(Tileset *const tileset)
Definition: map.cpp:318
void updatePortalTile(const std::string &name, const int type, const int x, const int y, const bool addNew)
Definition: map.cpp:1308
int x
Definition: location.h:57
const std::string getGatName() const
Definition: map.cpp:850
bool hasProperty(const std::string &name) const
Definition: properties.h:118
#define FOR_EACHP(type, iter, array)
Definition: foreach.h:30
MapType ::T MapTypeT
Definition: maptype.h:38
void log1(const char *const log_text)
Definition: logger.cpp:233
#define fillCollision(collision, color)
Definition: map.cpp:541
void addBlockMask(const int x, const int y, const BlockTypeT type)
Definition: map.cpp:702
void removeActor(const Actors::iterator &iterator)
Definition: map.cpp:824
volatile int tick_time
Definition: timer.cpp:52
Particle * addEffect(const std::string &particleEffectFile, const int pixelX, const int pixelY, const int rotation)
bool mDrawOnlyFringe
Definition: map.h:502
TileAnimationMap::const_iterator TileAnimationMapCIter
Definition: tileanimation.h:64
std::string getUserMapDirectory() const
Definition: map.cpp:1268
Actors::iterator addActor(Actor *const actor)
Definition: map.cpp:817
void addRange(const std::string &name, const int type, const int x, const int y, const int dx, const int dy)
Definition: map.cpp:1274
const Color & getColorWithAlpha(const UserColorIdT type)
Definition: userpalette.h:199
int Gcost
Definition: metatile.h:46
void setPvpMode(const int mode)
Definition: map.cpp:1356
AmbientLayerVector mBackgrounds
Definition: map.h:431
std::string fileName
Definition: testmain.cpp:38
void setDrawLayersFlags(const MapTypeT &n)
Definition: map.cpp:1698
int getAtlasCount() const
Definition: map.cpp:1803
int Fcost
Definition: metatile.h:45
virtual void decRef()
Definition: resource.cpp:49
void updateConditionLayers()
Definition: map.cpp:1727
int mLastX
Definition: map.h:483
const MapHeights * mHeights
Definition: map.h:497
const std::string getMusicFile() const
Definition: map.cpp:830
std::string pathJoin(std::string str1, const std::string &str2)
Tilesets mTilesets
Definition: map.h:419
Definition: rect.h:72
int mkdir_r(const char *const pathname)
Create a directory, making leading components first if necessary.
Definition: mkdir.cpp:108
int mPvp
Definition: map.h:470
WalkLayer * mWalkLayer
Definition: map.h:415
int calcMemory(const int level) const
int mDrawScrollY
Definition: map.h:491
#define BLOCK_START(name)
Definition: perfomance.h:78
std::vector< MapObject > objects
Definition: mapobjectlist.h:42
void addHeights(const MapHeights *const heights)
Definition: map.cpp:1620
const std::string getProperty(const std::string &name, const std::string &def) const
Definition: properties.h:58
MetaTile * tile
Definition: location.h:59
ParticleEngine * particleEngine
Configuration config
#define final
Definition: localconsts.h:45
SDL_Rect mInternalBounds
Definition: subimage.h:78
BlockType ::T BlockTypeT
Definition: blocktype.h:40
int mOverlayDetail
Definition: map.h:467
int mActorFixY
Definition: map.h:475
SpecialLayer * mSpecialLayer
Definition: map.h:478
int mDrawX
Definition: map.h:488
#define BLOCK_END(name)
Definition: perfomance.h:79
uint8_t getHeight(const int x, const int y) const
Definition: mapheights.h:43
void optionChanged(const std::string &value)
Definition: map.cpp:209
int getIntValue(const std::string &key) const
float getFloatValue(const std::string &key) const
float getFloatProperty(const std::string &name, const float def) const
Definition: properties.h:74
void updateAmbientLayers(const float scrollX, const float scrollY)
Definition: map.cpp:614
const Tileset * getTilesetWithGid(const int gid) const
Definition: map.cpp:695
void addLayer(MapLayer *const layer)
Definition: map.cpp:311
void setWalk(const int x, const int y)
Definition: map.cpp:802
void setBlockMask(const int x, const int y, const BlockTypeT type)
Definition: map.cpp:741
void notify(const unsigned int message)
#define delete2(var)
Definition: delete2.h:24
std::map< int, TileAnimation * > mTileAnimations
Definition: map.h:464
ObjectsLayer * mObjects
Definition: map.h:480
bool contains(const int x, const int y) const
Definition: map.cpp:807
std::vector< TextureAtlas * > atlases
Definition: atlasresource.h:51
void addObject(const std::string &name, const int type, const unsigned x, const unsigned y, unsigned dx, unsigned dy)
unsigned char getBlockMask(const int x, const int y) const
Definition: map.cpp:791
void setTile(const int x, const int y, MapItem *const item)
int Hcost
Definition: metatile.h:47
~Map()
Definition: map.cpp:178
bool mTilesetsIndexed
Definition: map.h:471
void addPortalTile(const std::string &name, const int type, const int x, const int y)
Definition: map.cpp:1295
void addListener(const std::string &key, ConfigListener *const listener)
UserPalette * userPalette
Definition: userpalette.cpp:33
void indexTilesets()
Definition: map.cpp:1410
const int mTileWidth
Definition: map.h:411
MapObjectList * getAt(const unsigned x, const unsigned y) const
Logger * logger
Definition: logger.cpp:88
void draw(Graphics *const graphics, int scrollX, int scrollY)
Definition: map.cpp:337
#define A_DEFAULT_COPY(func)
Definition: localconsts.h:40
int get_elapsed_time(const int startTime)
Definition: timer.cpp:93
void drawFringe(Graphics *const graphics, int startX, int startY, int endX, int endY, const int scrollX, const int scrollY, const Actors &actors) const
Definition: maplayer.cpp:424
std::string getObjectData(const unsigned x, const unsigned y, const int type) const
Definition: map.cpp:1388
void updateDrawLayersList()
Definition: map.cpp:1633
std::vector< MapItem * > mMapPortals
Definition: map.h:462
#define new
Definition: debug_new.h:147
Layers mLayers
Definition: map.h:416
Settings settings
Definition: settings.cpp:31
float mLastAScrollX
Definition: map.h:433
unsigned char blockmask
Definition: metatile.h:51
int mLastScrollX
Definition: map.h:485
bool getBoolValue(const std::string &key) const
void update(const int timePassed, const float dx, const float dy)
void updateCache()
#define CAST_S32
Definition: cast.h:29
void clearIndexedTilesets()
Definition: map.cpp:1458
void setActorsFix(const int y)
Definition: maplayer.h:169
std::string strprintf(const char *const format,...)
Definition: stringutils.cpp:99
void delete_all(Container &c)
Definition: dtor.h:55
Layers::const_iterator LayersCIter
Definition: map.h:62
void addPortal(const std::string &name, const int type, const int x, const int y, const int dx, const int dy)
Definition: map.cpp:1286
void setProperty(const std::string &name, const std::string &value)
Definition: properties.h:127
Image * getImage(const std::string &idPath)
Definition: imageloader.cpp:85
std::string serverConfigDir
Definition: settings.h:115
void initializeParticleEffects() const
Definition: map.cpp:1104
MapTypeT mDrawLayersFlags
Definition: map.h:424
int calcMemoryLocal() const
Definition: map.cpp:1751
void setMask(const int mask)
Definition: map.cpp:1671
int mActorFixX
Definition: map.h:474
LocalPlayer * localPlayer
const std::string getFilename() const
Definition: map.cpp:843
MapItem * getTile(const int x, const int y) const
std::string mName
Definition: map.h:466
void setTempLayer(const SpecialLayer *const val)
Definition: maplayer.h:147
AmbientLayerVector mForegrounds
Definition: map.h:432
#define nullptr
Definition: localconsts.h:44
bool mRedrawMap
Definition: map.h:498
int mIndexedTilesetsSize
Definition: map.h:473
void preCacheLayers()
Definition: map.cpp:1741
RenderType intToRenderType(const int mode)
Definition: renderers.cpp:42
void addAnimation(const int gid, TileAnimation *const animation)
Definition: map.cpp:1686
bool mCachedDraw
Definition: map.h:500
class ActorFunctuator actorCompare
int mMaxTileHeight
Definition: map.h:413
const TileAnimation * getAnimationForGid(const int gid) const
Definition: map.cpp:1347
uint8_t getHeightOffset(const int x, const int y) const
Definition: map.cpp:1626
MapItem * findPortalXY(const int x, const int y) const
Definition: map.cpp:1333
bool getWalk(const int x, const int y, const unsigned char blockWalkMask) const
Definition: map.cpp:780
const int mHeight
Definition: map.h:410
void update(const int ticks)
Definition: map.cpp:326
void saveExtraLayer() const
Definition: map.cpp:1221
const MetaTile * getMetaTile(const int x, const int y) const
Definition: map.cpp:812
void setSpecialLayer(const SpecialLayer *const val)
Definition: maplayer.h:143
int parentX
Definition: metatile.h:49
SpecialLayer * mTempLayer
Definition: map.h:479
MetaTile *const mMetaTiles
Definition: map.h:414
void addParticleEffect(const std::string &effectFile, const int x, const int y, const int w, const int h)
Definition: map.cpp:1096
std::string toString(T const &value)
converts any type to a string
Definition: catch.hpp:1774
const int mWidth
Definition: map.h:409
unsigned int mOnOpenList
Definition: map.h:428
int mDrawY
Definition: map.h:489
int mLastY
Definition: map.h:484
unsigned int mOnClosedList
Definition: map.h:427
int y
Definition: location.h:57
int parentY
Definition: metatile.h:50
void removeListeners(ConfigListener *const listener)
MapLayerPosition ::T MapLayerPositionT
Path findPath(const int startX, const int startY, const int destX, const int destY, const unsigned char blockWalkmask, const int maxCost)
Definition: map.cpp:858
void initializeAmbientLayers()
Definition: map.cpp:232
int calcMemoryChilds(const int level) const
Definition: map.cpp:1769
MapLayer * mFringeLayer
Definition: map.h:481
Definition: actor.h:40
Definition: image.h:61
float mLastAScrollY
Definition: map.h:434
std::list< Position > Path
Definition: position.h:48
const RenderType mOpenGL
Definition: map.h:469
static const int mapTileSize
Definition: map.h:26
#define restrict
Definition: localconsts.h:164
std::vector< AmbientLayer * > AmbientLayerVector
Definition: map.h:64
float mOpacity
Definition: map.h:468
Layers mDrawUnderLayers
Definition: map.h:417
#define CAST_SIZE
Definition: cast.h:33
#define CHECKLISTENERS
Definition: localconsts.h:276
void drawCollision(Graphics *const graphics, const int scrollX, const int scrollY, const MapTypeT drawFlags) const
Definition: map.cpp:564
void reduce()
Definition: map.cpp:1468
AmbientLayerVector::iterator AmbientLayerVectorIter
Definition: map.h:66
void log(const char *const log_text,...)
Definition: logger.cpp:264
Map(const std::string &name, const int width, const int height, const int tileWidth, const int tileHeight)
Definition: map.cpp:96
Actors::const_iterator ActorsCIter
Definition: actor.h:38
bool mBeingOpacity
Definition: map.h:499
int mDrawScrollX
Definition: map.h:490
Layers mDrawOverLayers
Definition: map.h:418
const std::string getName() const
Definition: map.cpp:835
Tileset ** mIndexedTilesets
Definition: map.h:472
int mMask
Definition: maplayer.h:233
bool getBoolProperty(const std::string &name, const bool def) const
Definition: properties.h:96
void setMusicFile(const std::string &file)
Definition: map.cpp:1681
std::vector< ParticleEffectData > mParticleEffects
Definition: map.h:460
void drawAmbientLayers(Graphics *const graphics, const MapLayerPositionT type, const int detail) const
Definition: map.cpp:654
AmbientLayerVector::const_iterator AmbientLayerVectorCIter
Definition: map.h:65
Actors mActors
Definition: map.h:420
#define reportAlways(...)
Definition: checkutils.h:252
AtlasResource * mAtlas
Definition: map.h:494
int mMask
Definition: map.h:492
#define restrict2
Definition: localconsts.h:165
void adjustEmitterSize(const int w, const int h)
Definition: particle.cpp:555
void setActorsFix(const int x, const int y)
Definition: map.cpp:1719
unsigned whichList
Definition: metatile.h:48
bool isFringeLayer() const
Definition: maplayer.h:140
void addExtraLayer()
Definition: map.cpp:1137