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  std::min(dx1, dy1) * (basicCostF);
1013 
1014  // Set the current tile as the parent of the new tile
1015  newTile->parentX = curr.x;
1016  newTile->parentY = curr.y;
1017 
1018  // Update Gcost and Fcost of new tile
1019  newTile->Gcost = Gcost;
1020  newTile->Fcost = Gcost + newTile->Hcost;
1021 
1022  if (x != destX || y != destY)
1023  {
1024  // Add this tile to the open list
1025  newTile->whichList = mOnOpenList;
1026  openList.push(Location(x, y, newTile));
1027  }
1028  else
1029  {
1030  // Target location was found
1031  foundPath = true;
1032  }
1033  }
1034  else if (Gcost < newTile->Gcost)
1035  {
1036  // Found a shorter route.
1037  // Update Gcost and Fcost of the new tile
1038  newTile->Gcost = Gcost;
1039  newTile->Fcost = Gcost + newTile->Hcost;
1040 
1041  // Set the current tile as the parent of the new tile
1042  newTile->parentX = curr.x;
1043  newTile->parentY = curr.y;
1044 
1045  // Add this tile to the open list (it's already
1046  // there, but this instance has a lower F score)
1047  openList.push(Location(x, y, newTile));
1048  }
1049  }
1050  }
1051  }
1052 
1053  // Two new values to indicate whether a tile is on the open or closed list,
1054  // this way we don't have to clear all the values between each pathfinding.
1055  if (mOnOpenList > UINT_MAX - 2)
1056  {
1057  // We reset the list memebers value.
1058  mOnClosedList = 1;
1059  mOnOpenList = 2;
1060 
1061  // Clean up the metaTiles
1062  const int size = mWidth * mHeight;
1063  for (int i = 0; i < size; ++i)
1064  mMetaTiles[i].whichList = 0;
1065  }
1066  else
1067  {
1068  mOnClosedList += 2;
1069  mOnOpenList += 2;
1070  }
1071 
1072  // If a path has been found, iterate backwards using the parent locations
1073  // to extract it.
1074  if (foundPath)
1075  {
1076  int pathX = destX;
1077  int pathY = destY;
1078 
1079  while (pathX != startX || pathY != startY)
1080  {
1081  // Add the new path node to the start of the path list
1082  path.push_front(Position(pathX, pathY));
1083 
1084  // Find out the next parent
1085  const MetaTile *const tile = &mMetaTiles[pathX + pathY * mWidth];
1086  pathX = tile->parentX;
1087  pathY = tile->parentY;
1088  }
1089  }
1090 
1091  BLOCK_END("Map::findPath")
1092  return path;
1093 }
1094 
1095 void Map::addParticleEffect(const std::string &effectFile,
1096  const int x, const int y,
1097  const int w, const int h) restrict2
1098 {
1099  ParticleEffectData newEffect(effectFile, x, y, w, h);
1100  mParticleEffects.push_back(newEffect);
1101 }
1102 
1104 {
1105  BLOCK_START("Map::initializeParticleEffects")
1106  if (particleEngine == nullptr)
1107  {
1108  BLOCK_END("Map::initializeParticleEffects")
1109  return;
1110  }
1111 
1112  if (config.getBoolValue("particleeffects"))
1113  {
1114  for (STD_VECTOR<ParticleEffectData>::const_iterator
1115  i = mParticleEffects.begin();
1116  i != mParticleEffects.end();
1117  ++i)
1118  {
1119  // +++ add z for map particle effects?
1120  Particle *const p = particleEngine->addEffect(
1121  i->file,
1122  i->x,
1123  i->y,
1124  0);
1125  if ((p != nullptr) &&
1126  i->w > 0 &&
1127  i->h > 0)
1128  {
1129  p->adjustEmitterSize(i->w, i->h);
1130  }
1131  }
1132  }
1133  BLOCK_END("Map::initializeParticleEffects")
1134 }
1135 
1137 {
1138  BLOCK_START("Map::addExtraLayer")
1139  if (mSpecialLayer == nullptr)
1140  {
1141  logger->log1("No special layer");
1142  BLOCK_END("Map::addExtraLayer")
1143  return;
1144  }
1145  const std::string mapFileName = pathJoin(getUserMapDirectory(),
1146  "extralayer.txt");
1147  logger->log("loading extra layer: " + mapFileName);
1148  struct stat statbuf;
1149  if (stat(mapFileName.c_str(), &statbuf) == 0 &&
1150  S_ISREG(statbuf.st_mode))
1151  {
1152  std::ifstream mapFile;
1153  mapFile.open(mapFileName.c_str(), std::ios::in);
1154  if (!mapFile.is_open())
1155  {
1156  mapFile.close();
1157  BLOCK_END("Map::addExtraLayer")
1158  return;
1159  }
1160  char line[201];
1161 
1162  while (mapFile.getline(line, 200))
1163  {
1164  std::string buf;
1165  std::string str = line;
1166  if (!str.empty())
1167  {
1168  std::string x;
1169  std::string y;
1170  std::string type1;
1171  std::string comment;
1172  std::stringstream ss(str);
1173  ss >> x;
1174  ss >> y;
1175  ss >> type1;
1176  ss >> comment;
1177  while (ss >> buf)
1178  comment.append(" ").append(buf);
1179 
1180  const int type = atoi(type1.c_str());
1181 
1182  if (comment.empty())
1183  {
1184  if (type < MapItemType::ARROW_UP
1185  || type > MapItemType::ARROW_RIGHT)
1186  {
1187  comment = "unknown";
1188  }
1189  }
1190  if (type == MapItemType::PORTAL)
1191  {
1192  updatePortalTile(comment,
1193  type,
1194  atoi(x.c_str()),
1195  atoi(y.c_str()),
1196  false);
1197  }
1198  else if (type == MapItemType::HOME)
1199  {
1200  updatePortalTile(comment,
1201  type,
1202  atoi(x.c_str()),
1203  atoi(y.c_str()),
1204  true);
1205  }
1206  else
1207  {
1208  addPortalTile(comment,
1209  type,
1210  atoi(x.c_str()),
1211  atoi(y.c_str()));
1212  }
1213  }
1214  }
1215  mapFile.close();
1216  }
1217  BLOCK_END("Map::addExtraLayer")
1218 }
1219 
1221 {
1222  if (mSpecialLayer == nullptr)
1223  {
1224  logger->log1("No special layer");
1225  return;
1226  }
1227  const std::string mapFileName = pathJoin(getUserMapDirectory(),
1228  "extralayer.txt");
1229  logger->log("saving extra layer: " + mapFileName);
1230 
1231  if (mkdir_r(getUserMapDirectory().c_str()) != 0)
1232  {
1233  logger->log(strprintf("%s doesn't exist and can't be created! "
1234  "Exiting.", getUserMapDirectory().c_str()));
1235  return;
1236  }
1237 
1238  std::ofstream mapFile;
1239  mapFile.open(mapFileName.c_str(), std::ios::binary);
1240  if (!mapFile.is_open())
1241  {
1242  reportAlways("Error opening file for writing: %s",
1243  mapFileName.c_str());
1244  return;
1245  }
1246 
1247  const int width = mSpecialLayer->mWidth;
1248  const int height = mSpecialLayer->mHeight;
1249 
1250  for (int x = 0; x < width; x ++)
1251  {
1252  for (int y = 0; y < height; y ++)
1253  {
1254  const MapItem *restrict const item = mSpecialLayer->getTile(x, y);
1255  if ((item != nullptr) && item->mType != MapItemType::EMPTY
1256  && item->mType != MapItemType::HOME)
1257  {
1258  mapFile << x << " " << y << " "
1259  << CAST_S32(item->mType) << " "
1260  << item->mComment << std::endl;
1261  }
1262  }
1263  }
1264  mapFile.close();
1265 }
1266 
1268 {
1270  getProperty("_realfilename", std::string()));
1271 }
1272 
1273 void Map::addRange(const std::string &restrict name,
1274  const int type,
1275  const int x, const int y,
1276  const int dx, const int dy) restrict2
1277 {
1278  if (mObjects == nullptr)
1279  return;
1280 
1281  mObjects->addObject(name, type, x / mapTileSize, y / mapTileSize,
1282  dx / mapTileSize, dy / mapTileSize);
1283 }
1284 
1285 void Map::addPortal(const std::string &restrict name,
1286  const int type,
1287  const int x, const int y,
1288  const int dx, const int dy) restrict2
1289 {
1290  addPortalTile(name, type, (x / mapTileSize) + (dx / mapTileSize / 2),
1291  (y / mapTileSize) + (dy / mapTileSize / 2));
1292 }
1293 
1294 void Map::addPortalTile(const std::string &restrict name,
1295  const int type,
1296  const int x, const int y) restrict2
1297 {
1298  if (mSpecialLayer != nullptr)
1299  {
1300  mSpecialLayer->setTile(x, y, new MapItem(type, name, x, y));
1302  }
1303 
1304  mMapPortals.push_back(new MapItem(type, name, x, y));
1305 }
1306 
1307 void Map::updatePortalTile(const std::string &restrict name,
1308  const int type,
1309  const int x, const int y,
1310  const bool addNew) restrict2
1311 {
1313  if (item != nullptr)
1314  {
1315  item->mComment = name;
1316  item->setType(type);
1317  item->mX = x;
1318  item->mY = y;
1319  if (mSpecialLayer != nullptr)
1320  {
1321  item = new MapItem(type, name, x, y);
1322  mSpecialLayer->setTile(x, y, item);
1324  }
1325  }
1326  else if (addNew)
1327  {
1328  addPortalTile(name, type, x, y);
1329  }
1330 }
1331 
1332 MapItem *Map::findPortalXY(const int x, const int y) const restrict2
1333 {
1334  FOR_EACH (STD_VECTOR<MapItem*>::const_iterator, it, mMapPortals)
1335  {
1336  if (*it == nullptr)
1337  continue;
1338 
1339  MapItem *restrict const item = *it;
1340  if (item->mX == x && item->mY == y)
1341  return item;
1342  }
1343  return nullptr;
1344 }
1345 
1347 {
1348  if (mTileAnimations.empty())
1349  return nullptr;
1350 
1351  const TileAnimationMapCIter i = mTileAnimations.find(gid);
1352  return (i == mTileAnimations.end()) ? nullptr : i->second;
1353 }
1354 
1355 void Map::setPvpMode(const int mode) restrict2
1356 {
1357  const int oldMode = mPvp;
1358 
1359  if (mode == 0)
1360  mPvp = 0;
1361  else
1362  mPvp |= mode;
1363 
1364  if (mPvp != oldMode && (localPlayer != nullptr))
1365  {
1366  switch (mPvp)
1367  {
1368  case 0:
1370  break;
1371  case 1:
1373  break;
1374  case 2:
1376  break;
1377  case 3:
1379  break;
1380  default:
1382  break;
1383  }
1384  }
1385 }
1386 
1387 std::string Map::getObjectData(const unsigned x, const unsigned y,
1388  const int type) const restrict2
1389 {
1390  if (mObjects == nullptr)
1391  return "";
1392 
1393  MapObjectList *restrict const list = mObjects->getAt(x, y);
1394  if (list == nullptr)
1395  return "";
1396 
1397  STD_VECTOR<MapObject>::const_iterator it = list->objects.begin();
1398  const STD_VECTOR<MapObject>::const_iterator it_end = list->objects.end();
1399  while (it != it_end)
1400  {
1401  if ((*it).type == type)
1402  return (*it).data;
1403  ++ it;
1404  }
1405 
1406  return "";
1407 }
1408 
1410 {
1411  if (mTilesetsIndexed)
1412  return;
1413 
1414  mTilesetsIndexed = true;
1415 
1416  const Tileset *restrict s = nullptr;
1417  size_t sSz = 0;
1418  FOR_EACH (Tilesets::const_iterator, it, mTilesets)
1419  {
1420  const size_t sz = (*it)->size();
1421  if ((s == nullptr) || CAST_SIZE(s->getFirstGid()) + sSz
1422  < CAST_SIZE((*it)->getFirstGid()) + sz)
1423  {
1424  s = *it;
1425  sSz = sz;
1426  }
1427  }
1428  if (s == nullptr)
1429  {
1431  mIndexedTilesets = nullptr;
1432  return;
1433  }
1434 
1435  const int size = CAST_S32(s->getFirstGid())
1436  + CAST_S32(s->size());
1438  mIndexedTilesets = new Tileset*[CAST_SIZE(size)];
1439  std::fill_n(mIndexedTilesets, size, static_cast<Tileset*>(nullptr));
1440 
1441  FOR_EACH (Tilesets::const_iterator, it, mTilesets)
1442  {
1443  Tileset *restrict const s2 = *it;
1444  if (s2 != nullptr)
1445  {
1446  const int start = s2->getFirstGid();
1447  const int end = start + CAST_S32(s2->size());
1448  for (int f = start; f < end; f ++)
1449  {
1450  if (f < size)
1451  mIndexedTilesets[f] = s2;
1452  }
1453  }
1454  }
1455 }
1456 
1458 {
1459  if (!mTilesetsIndexed)
1460  return;
1461 
1462  mTilesetsIndexed = false;
1463  delete [] mIndexedTilesets;
1465 }
1466 
1468 {
1469 #ifndef USE_SDL2
1470  if ((mFringeLayer == nullptr) ||
1471  mOpenGL != RENDER_SOFTWARE ||
1472  !config.getBoolValue("enableMapReduce"))
1473  {
1474  return;
1475  }
1476 
1477  int cnt = 0;
1478  for (int x = 0; x < mWidth; x ++)
1479  {
1480  for (int y = 0; y < mHeight; y ++)
1481  {
1482  bool correct(true);
1483  bool dontHaveAlpha(false);
1484 
1485  FOR_EACH (LayersCIter, layeri, mLayers)
1486  {
1487  const MapLayer *restrict const layer = *layeri;
1488  if (x >= layer->mWidth || y >= layer->mHeight)
1489  continue;
1490 
1491  // skip layers with flags
1492  if (layer->mTileCondition != -1 || layer->mMask != 1)
1493  continue;
1494 
1495  Image *restrict const img =
1496  layer->mTiles[x + y * layer->mWidth].image;
1497  if (img != nullptr)
1498  {
1499  if (img->hasAlphaChannel() && img->isAlphaCalculated())
1500  {
1501  if (!img->isAlphaVisible())
1502  {
1503  dontHaveAlpha = true;
1504  img->setAlphaVisible(false);
1505  }
1506  }
1507  else if (img->mBounds.w > mapTileSize
1508  || img->mBounds.h > mapTileSize)
1509  {
1510  correct = false;
1511  img->setAlphaVisible(true);
1512  break;
1513  }
1514  else if (!img->isHasAlphaChannel())
1515  {
1516  dontHaveAlpha = true;
1517  img->setAlphaVisible(false);
1518  }
1519  else if (img->hasAlphaChannel())
1520  {
1521  const uint8_t *restrict const arr =
1522  img->SDLgetAlphaChannel();
1523  if (arr == nullptr)
1524  continue;
1525 
1526  bool bad(false);
1527  bool stop(false);
1528  int width;
1529  const SubImage *restrict const subImg
1530  = dynamic_cast<SubImage*>(img);
1531  if (subImg != nullptr)
1532  width = subImg->mInternalBounds.w;
1533  else
1534  width = img->mBounds.w;
1535 
1536  for (int f = img->mBounds.x;
1537  f < img->mBounds.x + img->mBounds.w; f ++)
1538  {
1539  for (int d = img->mBounds.y;
1540  d < img->mBounds.y + img->mBounds.h; d ++)
1541  {
1542  const uint8_t chan = arr[f + d * width];
1543  if (chan != 255)
1544  {
1545  bad = true;
1546  stop = true;
1547  break;
1548  }
1549  }
1550  if (stop)
1551  break;
1552  }
1553  if (!bad)
1554  {
1555  dontHaveAlpha = true;
1556  img->setAlphaVisible(false);
1557  }
1558  else
1559  {
1560  img->setAlphaVisible(true);
1561  }
1562  }
1563  img->setAlphaCalculated(true);
1564  }
1565  }
1566  if (!correct || !dontHaveAlpha)
1567  continue;
1568 
1569  Layers::reverse_iterator ri = mLayers.rbegin();
1570  while (ri != mLayers.rend())
1571  {
1572  const MapLayer *restrict const layer = *ri;
1573  if (x >= layer->mWidth || y >= layer->mHeight)
1574  {
1575  ++ ri;
1576  continue;
1577  }
1578 
1579  // skip layers with flags
1580  if (layer->mTileCondition != -1 || layer->mMask != 1)
1581  {
1582  ++ ri;
1583  continue;
1584  }
1585 
1586  const Image *restrict img =
1587  layer->mTiles[x + y * layer->mWidth].image;
1588  if ((img != nullptr) && !img->isAlphaVisible())
1589  { // removing all down tiles
1590  ++ ri;
1591  while (ri != mLayers.rend())
1592  {
1593  MapLayer *restrict const layer2 = *ri;
1594  // skip layers with flags
1595  if (layer2->mTileCondition != -1 || layer2->mMask != 1)
1596  {
1597  ++ ri;
1598  continue;
1599  }
1600  const size_t pos = CAST_SIZE(
1601  x + y * 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:1307
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:1267
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:1273
const Color & getColorWithAlpha(const UserColorIdT type)
Definition: userpalette.h:199
int Gcost
Definition: metatile.h:46
void setPvpMode(const int mode)
Definition: map.cpp:1355
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:1294
void addListener(const std::string &key, ConfigListener *const listener)
UserPalette * userPalette
Definition: userpalette.cpp:33
void indexTilesets()
Definition: map.cpp:1409
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:431
std::string getObjectData(const unsigned x, const unsigned y, const int type) const
Definition: map.cpp:1387
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:1457
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: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:1285
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:114
void initializeParticleEffects() const
Definition: map.cpp:1103
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:143
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:1346
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:1332
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:1220
const MetaTile * getMetaTile(const int x, const int y) const
Definition: map.cpp:812
void setSpecialLayer(const SpecialLayer *const val)
Definition: maplayer.h:140
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:1095
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:176
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:305
void drawCollision(Graphics *const graphics, const int scrollX, const int scrollY, const MapTypeT drawFlags) const
Definition: map.cpp:564
void reduce()
Definition: map.cpp:1467
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:221
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:177
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:137
void addExtraLayer()
Definition: map.cpp:1136