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