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