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 #ifndef SOLARUS_MAP_H
18 #define SOLARUS_MAP_H
19 
20 #include "solarus/core/Common.h"
21 #include "solarus/core/Debug.h"
22 #include "solarus/core/MapData.h"
23 #include "solarus/core/Rectangle.h"
24 #include "solarus/entities/CameraPtr.h"
25 #include "solarus/entities/Entities.h"
26 #include "solarus/entities/Ground.h"
27 #include "solarus/entities/TilePattern.h"
28 #include "solarus/entities/Tileset.h"
29 #include "solarus/graphics/SurfacePtr.h"
30 #include "solarus/graphics/Transition.h"
31 #include "solarus/lua/ExportableToLua.h"
32 
33 namespace Solarus {
34 
35 class Destination;
36 class InputEvent;
37 class LuaContext;
38 class Tileset;
39 class Sprite;
40 
41 /**
42  * \brief Represents a map where the game can take place.
43  *
44  * A map is a game scene. It contains various information, including:
45  * - its dimensions,
46  * - the tileset,
47  * - the tiles and the other entities placed on the map,
48  * - the ground of each 8x8 square,
49  * - the background music.
50  */
51 class SOLARUS_API Map: public ExportableToLua {
52 
53   public:
54 
55     // creation and destruction
56     explicit Map(const std::string& id);
57 
58     // map properties
59     const std::string& get_id() const;
60     const Tileset& get_tileset() const;
61     const std::string& get_tileset_id() const;
62     void set_tileset(const std::string& tileset_id);
63     const std::string& get_music_id() const;
64     bool has_world() const;
65     const std::string& get_world() const;
66     void set_world(const std::string& world);
67     bool has_floor() const;
68     int get_floor() const;
69     void set_floor(int floor);
70     const Rectangle& get_location() const;
71 
72     Size get_size() const;
73     int get_width() const;
74     int get_height() const;
75     int get_width8() const;
76     int get_height8() const;
77 
78     int get_min_layer() const;
79     int get_max_layer() const;
80     bool is_valid_layer(int layer) const;
81 
82     // camera
83     const CameraPtr& get_camera() const;
84     SurfacePtr get_camera_surface();  // TODO remove
85 
86     // loading
87     bool is_loaded() const;
88     void load(Game& game);
89     void unload();
90     Game& get_game();
91     const std::shared_ptr<Savegame>& get_savegame();
92     bool is_game_running() const;
93     LuaContext& get_lua_context();
94     virtual const std::string& get_lua_type_name() const override;
95 
96     void notify_opening_transition_finished();
97 
98     // entities
99     Entities& get_entities();
100     const Entities& get_entities() const;
101 
102     // presence of the hero
103     bool is_started() const;
104     void start();
105     void leave();
106 
107     // current destination point
108     void set_destination(const std::string& destination_name);
109     const std::string& get_destination_name() const;
110     std::shared_ptr<Destination> get_destination();
111     int get_destination_side() const;
112 
113     // collisions with obstacles (checked before a move)
114     bool test_collision_with_border(int x, int y) const;
115     bool test_collision_with_border(const Point& point) const;
116     bool test_collision_with_border(const Rectangle& collision_box) const;
117     bool test_collision_with_ground(
118         int layer,
119         int x,
120         int y,
121         const Entity& entity_to_check,
122         bool& found_diagonal_wall
123     ) const;
124     bool test_collision_with_entities(
125         int layer,
126         const Rectangle& collision_box,
127         Entity& entity_to_check
128     );
129     bool test_collision_with_obstacles(
130         int layer,
131         const Rectangle& collision_box,
132         Entity& entity_to_check
133     );
134     bool test_collision_with_obstacles(
135         int layer,
136         int x,
137         int y,
138         Entity& entity_to_check
139     );
140     bool test_collision_with_obstacles(
141         int layer,
142         const Point& point,
143         Entity& entity_to_check
144     );
145     bool has_empty_ground(
146         int layer,
147         const Rectangle& collision_box
148     ) const;
149 
150     Ground get_ground(
151         int layer,
152         int x,
153         int y,
154         const Entity* entity_to_check
155     ) const;
156     Ground get_ground(
157         int layer,
158         const Point& xy,
159         const Entity* entity_to_check
160     ) const;
161     Ground get_ground_from_entity(const Entity& entity, int x, int y) const;
162     Ground get_ground_from_entity(const Entity& entity, const Point& xy) const;
163 
164     // collisions with detectors (checked after a move)
165     void check_collision_with_detectors(Entity& entity);
166     void check_collision_with_detectors(Entity& entity, Sprite& sprite);
167     void check_collision_from_detector(Entity& detector);
168     void check_collision_from_detector(Entity& detector, Sprite& detector_sprite);
169 
170     // main loop
171     bool notify_input(const InputEvent& event);
172     void update();
173     bool is_suspended() const;
174     void check_suspended();
175     void draw();
176     void draw_visual(Drawable& drawable, const Point& xy,
177                      const Rectangle& clipping_area);
178     void draw_visual(Drawable& drawable, const Point& xy);
179     void draw_visual(Drawable& drawable, int x, int y);
180     void draw_visual(Drawable& drawable, int x, int y,
181                      const Rectangle& clipping_area);
182 
183   private:
184 
185     void set_suspended(bool suspended);
186     void build_background_surface();
187     void build_foreground_surface();
188     void draw_background(const SurfacePtr& dst_surface);
189     void draw_foreground(const SurfacePtr& dst_surface);
190 
191     // map properties
192 
193     std::shared_ptr<Savegame>
194         savegame;                 /**< The savegame associated to the game.
195                                    * Persists even after the game is destroyed. */
196     std::string id;               /**< Id of this map. */
197 
198     int width8;                   /**< Map width in 8x8 squares (width8 = get_width() / 8). */
199     int height8;                  /**< Map height in 8x8 squares (height8 = get_height() / 8). */
200     int min_layer;                /**< Lowest layer of the map (0 or less). */
201     int max_layer;                /**< Highest layer of the map (0 or more). */
202 
203     std::string tileset_id;       /**< Id of the current tileset. */
204     Tileset* tileset;             /**< Tileset of the map: every tile of this map
205                                    * is extracted from this tileset. */
206 
207     std::string music_id;         /**< Id of the current music of the map:
208                                    * can be a valid music, Music::none or Music::unchanged. */
209 
210     std::string world;            /**< Name of the context where this map is. When changing context,
211                                    * the savegame starting position is set and crystal switches are reset. */
212 
213     int floor;                    /**< The floor where this map is (possibly MapData::NO_FLOOR). */
214 
215     Rectangle location;           /**< Location of the map in its context: the width and height fields
216                                    * indicate the map size in pixel, and the x and y field indicate the position.
217                                    * This is used to correctly scroll between adjacent maps. */
218 
219     // Quest screen
220     SurfacePtr
221         background_surface;       /**< A surface filled with the background color of the tileset. */
222     SurfacePtr
223         foreground_surface;       /**< A surface with black bars when the map is smaller than the screen. */
224 
225     // map state
226     bool loaded;                  /**< Whether the loading phase is done. */
227     bool started;                 /**< Whether this map is the current map. */
228     std::string destination_name; /**< Current destination point on the map,
229                                    * or "_same" to keep the hero's coordinates,
230                                    * or "_side0", "_side1", "_side2" or "_side3"
231                                    * to place the hero on a side of the map,
232                                    * or an empty string to use the one saved. */
233 
234     std::unique_ptr<Entities>
235         entities;                 /**< The entities on the map. */
236     bool suspended;               /**< Whether the game is suspended. */
237 };
238 
239 /**
240  * \brief Tests whether a point is outside the map area.
241  * \param x x of the point to check.
242  * \param y y of the point to check.
243  * \return true if this point is outside the map area.
244  */
test_collision_with_border(int x,int y)245 inline bool Map::test_collision_with_border(int x, int y) const {
246 
247   return (x < 0 || y < 0 || x >= location.get_width() || y >= location.get_height());
248 }
249 
250 /**
251  * \brief Tests whether a point is outside the map area.
252  * \param point point to check.
253  * \return true if this point is outside the map area.
254  */
test_collision_with_border(const Point & point)255 inline bool Map::test_collision_with_border(const Point& point) const {
256 
257   return test_collision_with_border(point.x, point.y);
258 }
259 
260 /**
261  * \brief Returns the tileset associated to this map.
262  * \return The tileset.
263  */
get_tileset()264 inline const Tileset& Map::get_tileset() const {
265 
266   SOLARUS_ASSERT(tileset != nullptr,
267       std::string("Missing tileset in map '") + get_id() + "'"
268   );
269   return *tileset;
270 }
271 
272 /**
273  * \brief Returns the entities of the map.
274  *
275  * This function should not be called before the map is loaded into a game.
276  *
277  * \return The entities of the map.
278  */
get_entities()279 inline const Entities& Map::get_entities() const {
280   return *entities;
281 }
282 
283 /**
284  * \overload Non-const version.
285  */
get_entities()286 inline Entities& Map::get_entities() {
287   return *entities;
288 }
289 
290 /**
291  * \brief Returns the camera of the map.
292  * \return The camera, or nullptr if there is no camera.
293  */
get_camera()294 inline const CameraPtr& Map::get_camera() const {
295 
296   return get_entities().get_camera();
297 }
298 
299 }
300 
301 #endif
302 
303