1 /*
2  * Copyright (C) 2006-2019 Christopho, Solarus - http://www.solarus-games.org
3  *
4  * Solarus is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * Solarus is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program. If not, see <http://www.gnu.org/licenses/>.
16  */
17 #include "solarus/core/Debug.h"
18 #include "solarus/core/MapData.h"
19 #include "solarus/entities/EntityTypeInfo.h"
20 #include "solarus/lua/LuaTools.h"
21 #include <ostream>
22 #include <sstream>
23 
24 namespace Solarus {
25 
26 /**
27  * \brief Creates an empty map data object.
28  */
MapData()29 MapData::MapData():
30     min_layer(0),
31     max_layer(-1),
32     size(0, 0),
33     world(),
34     location(0, 0),
35     floor(NO_FLOOR),
36     tileset_id(),
37     music_id("none"),
38     entities(),
39     named_entities() {
40 
41   set_min_layer(0);
42   set_max_layer(0);
43 }
44 
45 /**
46  * \brief Returns the size of the map.
47  * \return The map size in pixels.
48  */
get_size() const49 Size MapData::get_size() const {
50   return size;
51 }
52 
53 /**
54  * \brief Sets the size of the map.
55  * \param size The map size in pixels.
56  */
set_size(const Size & size)57 void MapData::set_size(const Size& size) {
58   this->size = size;
59 }
60 
61 /**
62  * \brief Returns the location of this map in its world.
63  * \return The location of the upper-left corner of the map in pixels.
64  */
get_location() const65 Point MapData::get_location() const {
66   return location;
67 }
68 
69 /**
70  * \brief Sets the location of this map in its world.
71  * \param location The location of the upper-left corner of the map in pixels.
72  */
set_location(const Point & location)73 void MapData::set_location(const Point& location) {
74   this->location = location;
75 }
76 
77 /**
78  * \brief Returns the lowest layer of the map.
79  * \return The lowest layer.
80  */
get_min_layer() const81 int MapData::get_min_layer() const {
82   return min_layer;
83 }
84 
85 /**
86  * \brief Changes the lowest layer of the map.
87  * \param min_layer The new lowest layer.
88  * If you increase it, entities in removed layers are destroyed.
89  */
set_min_layer(int min_layer)90 void MapData::set_min_layer(int min_layer) {
91 
92   Debug::check_assertion(min_layer <= 0, "The min layer should be lower than or equal to 0");
93 
94   if (min_layer == this->min_layer) {
95     // No change.
96     return;
97   }
98 
99   if (min_layer > this->min_layer) {
100     // Removing some layers: entities may be removed.
101     for (int layer = this->min_layer; layer < min_layer; ++layer) {
102 
103       // Update the entities by layer structure.
104       entities.erase(layer);
105 
106       // Update the entities by name structure.
107       for (const EntityData& entity : entities[layer].entities) {
108         if (entity.has_name()) {
109           named_entities.erase(entity.get_name());
110         }
111       }
112     }
113   }
114   else {
115     // Adding layers.
116     for (int layer = this->min_layer - 1; layer >= min_layer; --layer) {
117       entities.emplace(layer, EntityDataList());
118     }
119   }
120 
121   this->min_layer = min_layer;
122 }
123 
124 /**
125  * \brief Returns the highest layer of the map.
126  * \return The highest layer.
127  */
get_max_layer() const128 int MapData::get_max_layer() const {
129   return max_layer;
130 }
131 
132 /**
133  * \brief Changes the highest layer of the map.
134  * \param max_layer The new highest layer.
135  * If you decrease it, entities in removed layers are destroyed.
136  */
set_max_layer(int max_layer)137 void MapData::set_max_layer(int max_layer) {
138 
139   Debug::check_assertion(max_layer >= 0, "The max layer should be higher than or equal to 0");
140 
141   if (max_layer == this->max_layer) {
142     // No change.
143     return;
144   }
145 
146   if (max_layer < this->max_layer) {
147     // Removing some layers: entities may be removed.
148     for (int layer = this->max_layer; layer > max_layer; --layer) {
149 
150       // Update the entities by layer structure.
151       entities.erase(layer);
152 
153       // Update the entities by name structure.
154       for (const EntityData& entity : entities[layer].entities) {
155         if (entity.has_name()) {
156           named_entities.erase(entity.get_name());
157         }
158       }
159     }
160   }
161   else {
162     // Adding layers.
163     for (int layer = this->max_layer + 1; layer <= max_layer; ++layer) {
164       entities.emplace(layer, EntityDataList());
165     }
166   }
167 
168   this->max_layer = max_layer;
169 }
170 
171 /**
172  * \brief Returns whether the specified layer exists in the map.
173  * \param layer The layer to check.
174  * \return \c true if the layer is >= 0 and < get_num_layers().
175  */
is_valid_layer(int layer) const176 bool MapData::is_valid_layer(int layer) const {
177 
178   return layer >= get_min_layer() && layer <= get_max_layer();
179 }
180 
181 /**
182  * \brief Returns whether this map is in a world.
183  * \return \c true if the map is in a world.
184  */
has_world() const185 bool MapData::has_world() const {
186   return !world.empty();
187 }
188 
189 /**
190  * \brief Returns the world this maps belongs to.
191  * \return The world or an empty string.
192  */
get_world() const193 const std::string& MapData::get_world() const {
194   return world;
195 }
196 
197 /**
198  * \brief Sets the world this maps belongs to.
199  * \param world The world or an empty string.
200  */
set_world(const std::string & world)201 void MapData::set_world(const std::string& world) {
202   this->world = world;
203 }
204 
205 /**
206  * \brief Returns whether this map has a floor number.
207  * \return \c true if the map has a floor number.
208  */
has_floor() const209 bool MapData::has_floor() const {
210   return floor != NO_FLOOR;
211 }
212 
213 /**
214  * \brief Returns the floor number of this map.
215  * \return The floor number or Map::NO_FLOOR.
216  */
get_floor() const217 int MapData::get_floor() const {
218   return floor;
219 }
220 
221 /**
222  * \brief Sets the floor number of this map.
223  * \param floor The floor number or Map::NO_FLOOR.
224  */
set_floor(int floor)225 void MapData::set_floor(int floor) {
226   this->floor = floor;
227 }
228 
229 /**
230  * \brief Returns the tileset used to draw this map.
231  * \return The tileset id.
232  * An empty string means that the tileset is not set yet.
233  */
get_tileset_id() const234 const std::string& MapData::get_tileset_id() const {
235   return tileset_id;
236 }
237 
238 /**
239  * \brief Sets the tileset used to draw this map.
240  * \param tileset_id The tileset id.
241  * An empty string means that the tileset is not set yet.
242  */
set_tileset_id(const std::string & tileset_id)243 void MapData::set_tileset_id(const std::string& tileset_id) {
244   this->tileset_id = tileset_id;
245 }
246 
247 /**
248  * \brief Returns whether a music is set.
249  * \return \c true if the music id is not "none".
250  */
has_music() const251 bool MapData::has_music() const {
252   return music_id != "none";
253 }
254 
255 /**
256  * \brief Returns the music played on this map.
257  * \return The music id or "none" or "same".
258  */
get_music_id() const259 const std::string& MapData::get_music_id() const {
260   return music_id;
261 }
262 
263 /**
264  * \brief Sets the music played on this map.
265  * \param music_id The music id or "none" or "same".
266  */
set_music_id(const std::string & music_id)267 void MapData::set_music_id(const std::string& music_id) {
268   this->music_id = music_id;
269 }
270 
271 /**
272  * \brief Returns the total number of entities on this map.
273  * \return The number of entities.
274  */
get_num_entities() const275 int MapData::get_num_entities() const {
276 
277   int num_entities = 0;
278   for (int layer = get_min_layer(); layer <= get_max_layer(); ++layer) {
279     num_entities += get_num_entities(layer);
280   }
281 
282   return num_entities;
283 }
284 
285 /**
286  * \brief Returns the number of entities on a layer of this map.
287  * \param layer A layer.
288  * \return The number of entities on that layer.
289  */
get_num_entities(int layer) const290 int MapData::get_num_entities(int layer) const {
291   return get_entities(layer).size();
292 }
293 
294 /**
295  * \brief Returns the number of tiles on a layer of this map.
296  * \param layer A layer.
297  * \return The number of tiles on that layer.
298  */
get_num_tiles(int layer) const299 int MapData::get_num_tiles(int layer) const {
300 
301   Debug::check_assertion(is_valid_layer(layer), "Invalid layer");
302 
303   return entities.at(layer).num_tiles;
304 }
305 
306 /**
307  * \brief Returns the number of dynamic entities on a layer of this map.
308  * \param layer A layer.
309  * \return The number of dynamic entities on that layer.
310  */
get_num_dynamic_entities(int layer) const311 int MapData::get_num_dynamic_entities(int layer) const {
312   return get_num_entities(layer) - get_num_tiles(layer);
313 }
314 
315 /**
316  * \brief Returns the entities on a layer of this map.
317  * \param layer A layer.
318  * \return The entities on that layer.
319  */
get_entities(int layer) const320 const std::deque<EntityData>& MapData::get_entities(int layer) const {
321 
322   Debug::check_assertion(is_valid_layer(layer), "Invalid layer");
323 
324   return entities.at(layer).entities;
325 }
326 
327 /**
328  * \overload
329  *
330  * Non-const version.
331  */
get_entities(int layer)332 std::deque<EntityData>& MapData::get_entities(int layer) {
333 
334   Debug::check_assertion(is_valid_layer(layer), "Invalid layer");
335 
336   return entities.at(layer).entities;
337 }
338 
339 /**
340  * \brief Changes the layer of an entity.
341  * \param src_index The current index of the entity to change.
342  * \param dst_layer The new layer to set.
343  * \return The new index of the entity.
344  */
set_entity_layer(const EntityIndex & src_index,int dst_layer)345 EntityIndex MapData::set_entity_layer(const EntityIndex& src_index, int dst_layer) {
346 
347   Debug::check_assertion(is_valid_layer(dst_layer), "Invalid layer in MapData::set_entity_layer()");
348 
349   int src_layer = src_index.layer;
350   if (dst_layer == src_index.layer) {
351     // No change.
352     return src_index;
353   }
354 
355   // Update the entity itself, but also entities and named_entities.
356   const auto& src_it = get_entities(src_layer).begin() + src_index.order;
357   EntityData& entity = *src_it;
358   entity.set_layer(dst_layer);
359 
360   // Insert on top of existing entities in the destination layer.
361   const bool dynamic = entity.is_dynamic();
362   int dst_order = dynamic ? get_num_entities(dst_layer) : get_num_tiles(dst_layer);
363   EntityIndex dst_index(dst_layer, dst_order);
364 
365   if (entity.has_name()) {
366     named_entities[entity.get_name()] = dst_index;
367   }
368 
369   auto dst_it = get_entities(dst_layer).begin() + dst_order;
370   get_entities(dst_layer).insert(dst_it, entity);
371   get_entities(src_layer).erase(src_it);  // Erase after insert because entity is a ref.
372 
373   if (!dynamic) {
374     // The tile count has changed.
375     ++entities[dst_layer].num_tiles;
376     --entities[src_layer].num_tiles;
377   }
378 
379   return dst_index;
380 }
381 
382 /**
383  * \brief Changes the order of an entity in its layer.
384  * \param src_index The current index of the entity to change.
385  * \param dst_order The new order to set.
386  * It must be valid: in particular, tiles must remain before dynamic entities.
387  */
set_entity_order(const EntityIndex & src_index,int dst_order)388 void MapData::set_entity_order(const EntityIndex& src_index, int dst_order) {
389 
390   int layer = src_index.layer;
391   int src_order = src_index.order;
392 
393   if (dst_order == src_order) {
394     // No change.
395     return;
396   }
397 
398   EntityData entity = get_entity(src_index);  // Make a copy.
399   bool dynamic = entity.is_dynamic();
400   int min_order = dynamic ? get_num_tiles(layer) : 0;
401   int max_order = dynamic ? (get_num_entities(layer) - 1) : (get_num_tiles(layer) - 1);
402 
403   Debug::check_assertion(dst_order >= min_order, "Entity order out of range (lower than min)");
404   Debug::check_assertion(dst_order <= max_order, "Entity order out of range (higher than max)");
405 
406   std::deque<EntityData>& entities = get_entities(layer);
407 
408   // Update entities and named_entities.
409   auto src_it = entities.begin() + src_order;
410 
411   if (entity.has_name()) {
412     named_entities[entity.get_name()] = { layer, dst_order };
413   }
414 
415   entities.erase(src_it);
416   auto dst_it = entities.begin() + dst_order;
417   entities.insert(dst_it, entity);
418 
419   if (dst_order < src_order) {
420     // Moving downwards.
421     // Indexes between dst_order exclusive and src_order inclusive get incremented.
422     for (int i = dst_order + 1;
423         i <= src_order;
424         ++i
425     ) {
426       const EntityData& current_entity = get_entity({ layer, i });
427       const std::string& name = current_entity.get_name();
428       if (!name.empty() && name != entity.get_name()) {
429         EntityIndex& index = named_entities[name];
430         ++index.order;
431       }
432     }
433   }
434   else {
435     // Moving upwards.
436     // Indexes between src_order inclusive and dst_order exclusive get decremented.
437     for (int i = src_order;
438         i < dst_order;
439         ++i
440     ) {
441       const EntityData& current_entity = get_entity({ layer, i });
442       const std::string& name = current_entity.get_name();
443       if (!name.empty() && name != entity.get_name()) {
444         EntityIndex& index = named_entities[name];
445         --index.order;
446       }
447     }
448   }
449 }
450 
451 /**
452  * \brief Brings an entity to the front on its layer.
453  *
454  * If it is a tile, it will still be below all dynamic entities.
455  *
456  * \param index Index of the entity on the map.
457  * \return The new index of the entity.
458  */
bring_entity_to_front(const EntityIndex & index)459 EntityIndex MapData::bring_entity_to_front(const EntityIndex& index) {
460 
461   const EntityData& entity = get_entity(index);
462   int bound = entity.is_dynamic() ? get_num_entities(index.layer) : get_num_tiles(index.layer);
463 
464   EntityIndex dst_index(index.layer, bound - 1);
465   Debug::check_assertion(index.order <= dst_index.order, "Entity index out of range");
466   if (dst_index.order == index.order) {
467     // Already to the front.
468     return index;
469   }
470 
471   set_entity_order(index, dst_index.order);
472   return dst_index;
473 }
474 
475 /**
476  * \brief Brings an entity to the back on its layer.
477  *
478  * If it is a dynamic entity, it will still be above all tiles.
479  *
480  * \param index Index of the entity on the map.
481  * \return The new index of the entity.
482  */
bring_entity_to_back(const EntityIndex & index)483 EntityIndex MapData::bring_entity_to_back(const EntityIndex& index) {
484 
485   const EntityData& entity = get_entity(index);
486   int bound = entity.is_dynamic() ? get_num_tiles(index.layer) : 0;
487 
488   EntityIndex dst_index(index.layer, bound);
489   Debug::check_assertion(index.order >= dst_index.order, "Entity index out of range");
490   if (dst_index.order == index.order) {
491     // Already to the back.
492     return index;
493   }
494 
495   set_entity_order(index, dst_index.order);
496   return dst_index;
497 }
498 
499 /**
500  * \brief Returns whether there is an entity at the given index.
501  * \param index An index.
502  * \return \c true if there is an entity at this index.
503  */
entity_exists(const EntityIndex & index) const504 bool MapData::entity_exists(const EntityIndex& index) const {
505 
506   return index.order >= 0 &&
507       index.order < get_num_entities(index.layer);
508 }
509 
510 /**
511  * \brief Returns the entity at the given index.
512  * \param index Index of the entity to get on the map.
513  * \return The entity data.
514  * The object remains valid until entities are added or removed.
515  */
get_entity(const EntityIndex & index) const516 const EntityData& MapData::get_entity(const EntityIndex& index) const {
517 
518   Debug::check_assertion(entity_exists(index),
519       "Entity index out of range"
520   );
521 
522   return get_entities(index.layer)[index.order];
523 }
524 
525 /**
526  * \brief Returns the entity at the given layer and index.
527  *
528  * Non-const version.
529  *
530  * \param index Index of the entity to get on the map.
531  * \return The entity data.
532  * The object remains valid until entities are added or removed.
533  */
get_entity(const EntityIndex & index)534 EntityData& MapData::get_entity(const EntityIndex& index) {
535 
536   Debug::check_assertion(entity_exists(index),
537       "Entity index out of range"
538   );
539 
540   return get_entities(index.layer)[index.order];
541 }
542 
543 /**
544  * \brief Returns the layer and index of an entity given its name.
545  * \param name Name of the entity to get.
546  * \return The layer and index of this entity.
547  * Returns an invalid index if there is no such entity.
548  */
get_entity_index(const std::string & name) const549 EntityIndex MapData::get_entity_index(const std::string& name) const {
550 
551   const auto& it = named_entities.find(name);
552 
553   if (it == named_entities.end()) {
554     return EntityIndex();
555   }
556 
557   return it->second;
558 }
559 
560 /**
561  * \brief Returns an entity given its name.
562  * \param name Name of the entity to get.
563  * \return The entity or nullptr if there is no such entity.
564  * The object remains valid until entities are added or removed.
565  */
get_entity_by_name(const std::string & name) const566 const EntityData* MapData::get_entity_by_name(const std::string& name) const {
567 
568   const EntityIndex& index = get_entity_index(name);
569   if (!index.is_valid()) {
570     // No such entity.
571     return nullptr;
572   }
573   return &get_entity(index);
574 }
575 
576 /**
577  * \brief Returns an entity given its name.
578  *
579  * Non-const version. Ownership of the pointer remains to MapData.
580  *
581  * \param name Name of the entity to get.
582  * \return The entity or nullptr if there is no such entity.
583  * The object remains valid until entities are added or removed.
584  */
get_entity_by_name(const std::string & name)585 EntityData* MapData::get_entity_by_name(const std::string& name) {
586 
587   const EntityIndex& index = get_entity_index(name);
588   if (!index.is_valid()) {
589     // No such entity.
590     return nullptr;
591   }
592   return &get_entity(index);
593 }
594 
595 /**
596  * \brief Returns whether there exists an entity with the specified name.
597  * \param name The name to check.
598  * \return \c true if there exists an entity with this name on the map.
599  */
entity_exists(const std::string & name) const600 bool MapData::entity_exists(const std::string& name) const {
601 
602   return named_entities.find(name) != named_entities.end();
603 }
604 
605 /**
606  * \brief Returns all entities that have a name on the map.
607  * \return The named entities.
608  */
get_named_entities_indexes() const609 const std::map<std::string, EntityIndex>& MapData::get_named_entities_indexes() const {
610   return named_entities;
611 }
612 
613 /**
614  * \brief Changes the name of an entity.
615  * \param index Index of the entity on the map.
616  * \param name The new name. An empty string means no name.
617  * \return \c true in case of success, \c false if the name was already used.
618  */
set_entity_name(const EntityIndex & index,const std::string & name)619 bool MapData::set_entity_name(const EntityIndex& index, const std::string& name) {
620 
621   EntityData& entity = get_entity(index);
622   const std::string& old_name = entity.get_name();
623 
624   if (name == old_name) {
625     // Nothing to do.
626     return true;
627   }
628 
629   if (!name.empty()) {
630     if (entity_exists(name)) {
631       // This name is already used by another entity.
632       return false;
633     }
634   }
635 
636   // Do the change.
637   entity.set_name(name);
638 
639   if (!old_name.empty()) {
640     named_entities.erase(old_name);
641   }
642 
643   if (!name.empty()) {
644     named_entities[name] = index;
645   }
646 
647   return false;
648 }
649 
650 /**
651  * \brief Adds an entity to the map.
652  *
653  * The entity will be added in front of other ones that are on the same layer.
654  * Use insert_entity() if you want to insert it at a specific index.
655  *
656  * If the new entity has a name, it should be unique on the map.
657  *
658  * \param entity The information of an entity.
659  * \return The index of this entity on the map.
660  * Returns an invalid index in case of failure, that is,
661  * if the name was already in use or if the entity type or layer is illegal.
662  */
add_entity(const EntityData & entity)663 EntityIndex MapData::add_entity(const EntityData& entity) {
664 
665   if (!is_valid_layer(entity.get_layer())) {
666     // Illegal layer.
667     return EntityIndex();
668   }
669 
670   // Compute the appropriate index.
671   int layer = entity.get_layer();
672   int bound = entity.is_dynamic() ? get_num_entities(layer) : get_num_tiles(layer);
673   EntityIndex index = { layer, bound };
674 
675   // Insert the entity there.
676   if (!insert_entity(entity, index)) {
677     // Failure.
678     return EntityIndex();
679   }
680   return index;
681 }
682 
683 /**
684  * \brief Adds an entity to the map at the specified index.
685  *
686  * If the new entity has a name, it should be unique on the map.
687  *
688  * \param entity The information of an entity.
689  * \param index The index this entity should have on the map.
690  * \return \c false in case of failure, that is,
691  * if the name was already in use, if the entity type is illegal
692  * or if the index was out of range.
693  */
insert_entity(const EntityData & entity,const EntityIndex & index)694 bool MapData::insert_entity(const EntityData& entity, const EntityIndex& index) {
695 
696   if (!EntityTypeInfo::can_be_stored_in_map_file(entity.get_type())) {
697     // Illegal type of entity in a map file.
698     return false;
699   }
700 
701   const int layer = index.layer;
702   int order = index.order;
703   bool dynamic = entity.is_dynamic();
704   int min_order = dynamic ? get_num_tiles(layer) : 0;
705   int max_order = dynamic ? get_num_entities(layer) : get_num_tiles(layer);
706 
707   if (order < min_order || order > max_order) {
708     // Index out of range.
709     return false;
710   }
711 
712   if (entity.has_name()) {
713     if (entity_exists(entity.get_name())) {
714       // This name is already used by another entity.
715       return false;
716     }
717 
718     named_entities.emplace(entity.get_name(), index);
719   }
720 
721   if (!dynamic) {
722     ++this->entities[layer].num_tiles;
723   }
724 
725   std::deque<EntityData>& entities = get_entities(layer);
726   auto it = entities.begin() + order;
727   entities.emplace(it, entity);
728 
729   // Indexes after this one get shifted.
730   for (it = entities.begin() + order + 1;
731       it != entities.end();
732       ++it
733   ) {
734     const EntityData& current_entity = *it;
735     const std::string& name = current_entity.get_name();
736     if (!name.empty()) {
737       EntityIndex& index = named_entities[name];
738       ++index.order;
739     }
740   }
741 
742   return true;
743 }
744 
745 /**
746  * \brief Removes an entity from the map.
747  * \param index Index of the entity on the map.
748  * \return \c false in case of failure, that is,
749  * if the index is out of range.
750  */
remove_entity(const EntityIndex & index)751 bool MapData::remove_entity(const EntityIndex& index) {
752 
753   if (!entity_exists(index)) {
754     return false;
755   }
756 
757   int layer = index.layer;
758   int order = index.order;
759   const EntityData& entity = get_entity(index);
760   bool dynamic = entity.is_dynamic();
761 
762   if (entity.has_name()) {
763     named_entities.erase(entity.get_name());
764   }
765 
766   if (!dynamic) {
767     --this->entities[layer].num_tiles;
768   }
769 
770   std::deque<EntityData>& entities = get_entities(layer);
771   auto it = entities.begin() + order;
772   entities.erase(it);
773 
774   // Indexes after this one get shifted.
775   for (it = entities.begin() + order;
776       it != entities.end();
777       ++it) {
778     const EntityData& current_entity = *it;
779     const std::string& name = current_entity.get_name();
780     if (!name.empty()) {
781       EntityIndex& index = named_entities[name];
782       --index.order;
783     }
784   }
785   return true;
786 }
787 
788 namespace {
789 
790 /**
791  * \brief Implementation of all entity creation functions for the map data file.
792  *
793  * The type of entity to create is indicated by the first upvalue.
794  * It will be added to the MapData.
795  */
l_add_entity(lua_State * l)796 int l_add_entity(lua_State* l) {
797 
798   return LuaTools::exception_boundary_handle(l, [&] {
799 
800     // Retrieve the map data to build.
801     lua_getfield(l, LUA_REGISTRYINDEX, "map");
802     MapData& map = *static_cast<MapData*>(lua_touserdata(l, -1));
803     lua_pop(l, 1);
804 
805     // Get the type of entity to create.
806     EntityType type = LuaTools::check_enum<EntityType>(
807         l, lua_upvalueindex(1)
808     );
809     const EntityData& entity = EntityData::check_entity_data(l, 1, type);
810 
811     if (!map.is_valid_layer(entity.get_layer())) {
812       std::ostringstream oss;
813       oss << "Invalid layer: " << entity.get_layer();
814       LuaTools::error(l, oss.str());
815     }
816 
817     EntityIndex index = map.add_entity(entity);
818     if (!index.is_valid()) {
819       LuaTools::error(l, "Failed to add entity");
820     }
821 
822     return 0;
823   });
824 }
825 
826 /**
827  * \brief Implementation of the properties() function of the Lua map data file.
828  *
829  * Reads the properties of the map: location, size, tileset, music, etc.
830  *
831  * \param l The Lua state that is calling this function.
832  * \return Number of values to return to Lua.
833  */
l_properties(lua_State * l)834 int l_properties(lua_State* l) {
835 
836   return LuaTools::exception_boundary_handle(l, [&] {
837 
838     // Retrieve the map data to build.
839     lua_getfield(l, LUA_REGISTRYINDEX, "map");
840     MapData& map = *static_cast<MapData*>(lua_touserdata(l, -1));
841     lua_pop(l, 1);
842 
843     // Retrieve the map properties from the table parameter.
844     LuaTools::check_type(l, 1, LUA_TTABLE);
845 
846     const int x = LuaTools::opt_int_field(l, 1, "x", 0);
847     const int y = LuaTools::opt_int_field(l, 1, "y", 0);
848     const int width = LuaTools::check_int_field(l, 1, "width");
849     const int height = LuaTools::check_int_field(l, 1, "height");
850     const int min_layer = LuaTools::check_int_field(l, 1, "min_layer");
851     const int max_layer = LuaTools::check_int_field(l, 1, "max_layer");
852     const std::string& world = LuaTools::opt_string_field(l, 1 , "world", "");
853     const int floor = LuaTools::opt_int_field(l, 1, "floor", MapData::NO_FLOOR);
854     const std::string& tileset_id = LuaTools::check_string_field(l, 1, "tileset");
855     const std::string& music_id = LuaTools::opt_string_field(l, 1, "music", "none");
856 
857     if (min_layer > 0) {
858       LuaTools::arg_error(l, 1, "min_layer must be lower than or equal to 0");
859     }
860     if (max_layer < 0) {
861       LuaTools::arg_error(l, 1, "max_layer must be higher than or equal to 0");
862     }
863 
864     // Initialize the map data.
865     map.set_location({ x, y });
866     map.set_size({ width, height });
867     map.set_min_layer(min_layer);
868     map.set_max_layer(max_layer);
869     map.set_music_id(music_id);
870     map.set_world(world);
871     map.set_floor(floor);
872     map.set_tileset_id(tileset_id);
873 
874     // Properties are set: we now allow the data file to declare entities.
875 
876     for (const auto& kvp : EntityData::get_entity_type_descriptions()) {
877       const std::string& type_name = enum_to_name(kvp.first);
878       lua_pushstring(l, type_name.c_str());
879       lua_pushcclosure(l, l_add_entity, 1);
880       lua_setglobal(l, type_name.c_str());
881     }
882 
883     return 0;
884   });
885 }
886 
887 }  // Anonymous namespace
888 
889 /**
890  * \copydoc LuaData::import_from_lua
891  */
import_from_lua(lua_State * l)892 bool MapData::import_from_lua(lua_State* l) {
893 
894   lua_pushlightuserdata(l, this);
895   lua_setfield(l, LUA_REGISTRYINDEX, "map");
896   lua_register(l, "properties", l_properties);
897   if (lua_pcall(l, 0, 0, 0) != 0) {
898     Debug::error(std::string("Failed to load map: ") + lua_tostring(l, -1));
899     lua_pop(l, 1);
900     return false;
901   }
902 
903   return true;
904 }
905 
906 /**
907  * \copydoc LuaData::export_to_lua
908  */
export_to_lua(std::ostream & out) const909 bool MapData::export_to_lua(std::ostream& out) const {
910 
911   // Write map properties.
912   out << "properties{\n"
913       << "  x = " << get_location().x << ",\n"
914       << "  y = " << get_location().y << ",\n"
915       << "  width = " << get_size().width << ",\n"
916       << "  height = " << get_size().height << ",\n"
917       << "  min_layer = " << get_min_layer() << ",\n"
918       << "  max_layer = " << get_max_layer() << ",\n";
919   if (has_world()) {
920     out << "  world = \"" << escape_string(get_world()) << "\",\n";
921   }
922   if (has_floor()) {
923     out << "  floor = " << get_floor() << ",\n";
924   }
925   out << "  tileset = \"" << escape_string(get_tileset_id()) << "\",\n";
926   if (has_music()) {
927     out << "  music = \"" << escape_string(get_music_id()) << "\",\n";
928   }
929   out << "}\n\n";
930 
931   for (const auto& kvp : entities) {
932     const EntityDataList& layer_entities = kvp.second;
933     for (const EntityData& entity_data : layer_entities.entities) {
934       bool success = entity_data.export_to_lua(out);
935       Debug::check_assertion(success, "Entity export failed");
936     }
937   }
938 
939   return true;
940 }
941 
942 }  // namespace Solarus
943 
944