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