1 ///////////////////////////////////////////////////////////////////////////////
2 //            Copyright (C) 2004-2011 by The Allacrost Project
3 //            Copyright (C) 2012-2016 by Bertram (Valyria Tear)
4 //                         All Rights Reserved
5 //
6 // This code is licensed under the GNU GPL version 2. It is free software
7 // and you may modify it and/or redistribute it under the terms of this license.
8 // See https://www.gnu.org/copyleft/gpl.html for details.
9 ///////////////////////////////////////////////////////////////////////////////
10 
11 /** ****************************************************************************
12 *** \file    map_zones.h
13 *** \author  Guillaume Anctil, drakkoon@allacrost.org
14 *** \author  Yohann Ferreira, yohann ferreira orange fr
15 *** \brief   Header file for map mode zones.
16 *** ***************************************************************************/
17 
18 #ifndef __MAP_ZONES_HEADER__
19 #define __MAP_ZONES_HEADER__
20 
21 #include "modes/map/map_mode.h"
22 #include "modes/map/map_object_supervisor.h"
23 
24 namespace vt_map
25 {
26 
27 namespace private_map
28 {
29 
30 class EnemySprite;
31 
32 /** ****************************************************************************
33 *** \brief Represents a zone on a map that can take any shape
34 ***
35 *** The area is made up of many ZoneSection instances, so it can be any shape
36 *** (specifically, any combination of rectangular shapes).
37 *** A MapZone by itself is not very useful, but serves as
38 *** a foundation for other zone classes which derive from it.
39 ***
40 *** \note ZoneSections in the MapZone may overlap without any problem. In general,
41 *** however, you should try to create a MapZone using as few ZoneSections as possible
42 *** to improve performance.
43 *** ***************************************************************************/
44 class MapZone
45 {
46     // This friend declaration is necessary because EnemyZone, although it derives from MapZone, also keeps a pointer
47     // to a MapZone object and needs to access the protected members and methods of this object pointer.
48     friend class EnemyZone;
49 
50 public:
51     /** \brief Constructs a map zone that is initialized with a single zone section
52     *** \param left_col The left edge of the section to add
53     *** \param right_col The right edge of the section to add
54     *** \param top_row The top edge of the section to add
55     *** \param bottom_row The bottom edge of the section to add
56     **/
57     MapZone(uint16_t left_col, uint16_t right_col, uint16_t top_row, uint16_t bottom_row);
58 
59     virtual ~MapZone();
60 
61     //! \brief A C++ wrapper made to create a new object from scripting,
62     //! without letting Lua handling the object life-cycle.
63     //! \note We don't permit luabind to use constructors here as it can't currently
64     //! give the object ownership at construction time.
65     static MapZone* Create(uint16_t left_col, uint16_t right_col, uint16_t top_row, uint16_t bottom_row);
66 
67     /** \brief Adds a new zone section to the map zone
68     *** \param left_col The left edge of the section to add
69     *** \param right_col The right edge of the section to add
70     *** \param top_row The top edge of the section to add
71     *** \param bottom_row The bottom edge of the section to add
72     ***
73     *** \note The value of left shoult be less than right, and top should be less that
74     *** bottom. If these conditions are not true, a warning will be printed and the section
75     *** will not be added.
76     **/
77     virtual void AddSection(uint16_t left_col, uint16_t right_col, uint16_t top_row, uint16_t bottom_row);
78 
79     //! \brief Updates the state of the zone
80     virtual void Update();
81 
82     /** \brief Returns true if the position coordinates are located inside the zone (inclusive to the zone boundary edges)
83     *** \param pos_x The x position to check
84     *** \param pos_y The y position to check
85     ***
86     *** \note This function ignores the fractional part of map coordinates for performance reasons. So whenever an object is being
87     *** checked as to whether or not it may be found in this zone, the floating point portion of its map coordinates are not taken
88     *** into account.
89     **/
90     bool IsInsideZone(float pos_x, float pos_y) const;
91 
92     //! \brief Draws the map zone on screen for debugging purpose
93     virtual void Draw();
94 
95     /** \brief Returns random x, y position coordinates within the zone
96     *** \param x A reference where to store the value of the x position
97     *** \param y A reference where to store the value of the y position
98     **/
99     void RandomPosition(float &x, float &y);
100 
101     //! \brief Loads the current animation file as the new interaction icon of the object.
102     void SetInteractionIcon(const std::string& animation_filename);
103 
104     //! \brief Draws the interaction icon at the top of the zone rectangle, if any.
105     void DrawInteractionIcon();
106 
107 protected:
108     //! \brief The rectangular sections which compose the map zone
109     std::vector<vt_common::Rectangle2D> _sections;
110 
111     //! \brief Interaction icon
112     vt_video::AnimatedImage* _interaction_icon;
113 
114     //! \brief Tells whether a section is on screen and place the drawing cursor in that case.
115     bool _ShouldDraw(const vt_common::Rectangle2D& section);
116 
117 private:
118     //
119     // The copy constructor and assignment operator are hidden by design
120     // to cause compilation errors when attempting to copy or assign this class.
121     //
122 
123     MapZone(const MapZone& map_zone);
124     MapZone& operator=(const MapZone& map_zone);
125 };
126 
127 /** ****************************************************************************
128 *** \brief A zone which tracks when the map camera enters or exits
129 ***
130 *** A typical use of map zones is to track when the sprite controlled by the player
131 *** (usually pointed to by the map camera) enters or exits a zone, triggering a
132 *** map event. This class makes that common case a little easier to implement in
133 *** map scripting code.
134 ***
135 *** \note An important issue to remember is that the map camera may be changed to point
136 *** at any sprite at any given time. This class is not informed of such events, therefore
137 *** a sprite may be seen as "entering" the zone
138 ***
139 *** \note This zone is less powerful than the ResidentZone class, which tracks all
140 *** sprites status relative to the zone. CameraZone is much simpler than ResidentZone
141 *** in terms of computational costs (for both processor and memory requirements) and
142 *** thus should be utilized when the additional features of ResidentZone are not required.
143 *** ***************************************************************************/
144 class CameraZone : public MapZone
145 {
146 public:
147     /** \brief Constructs a camera zone that is initialized with a single zone section
148     *** \param left_col The left edge of the section to add
149     *** \param right_col The right edge of the section to add
150     *** \param top_row The top edge of the section to add
151     *** \param bottom_row The bottom edge of the section to add
152     **/
153     CameraZone(uint16_t left_col, uint16_t right_col, uint16_t top_row, uint16_t bottom_row);
154 
~CameraZone()155     virtual ~CameraZone() override
156     {
157     }
158 
159     //! \brief A C++ wrapper made to create a new object from scripting,
160     //! without letting Lua handling the object life-cycle.
161     //! \note We don't permit luabind to use constructors here as it can't currently
162     //! give the object ownership at construction time.
163     static CameraZone* Create(uint16_t left_col, uint16_t right_col, uint16_t top_row, uint16_t bottom_row);
164 
165     //! \brief Updates the state of the zone by checking the current camera position
166     virtual void Update() override;
167 
168     //! \brief Returns true if the sprite pointed to by the camera is located within the zone
IsCameraInside()169     bool IsCameraInside() const {
170         return _camera_inside;
171     }
172 
173     //! \brief Returns true if the sprite pointed to by the camera is entering the zone
IsCameraEntering()174     bool IsCameraEntering() const {
175         return ((_camera_inside) && (_was_camera_inside == false));
176     }
177 
178     //! \brief Returns true if the sprite pointed to by the camera is leaving the zone
IsCameraExiting()179     bool IsCameraExiting() const {
180         return ((_camera_inside == false) && (_was_camera_inside));
181     }
182 
183 protected:
184     //! \brief Set to true when the sprite pointed to by the camera is inside this zone
185     bool _camera_inside;
186 
187     //! \brief Holds the previous value of _camera_inside
188     bool _was_camera_inside;
189 
190 private:
191     //
192     // The copy constructor and assignment operator are hidden by design
193     // to cause compilation errors when attempting to copy or assign this class.
194     //
195 
196     CameraZone(const CameraZone& camera_zone);
197     CameraZone& operator=(const CameraZone& camera_zone);
198 };
199 
200 
201 /** ****************************************************************************
202 *** \brief Represents an area where enemy sprites spawn and roam in.
203 ***
204 *** This zone will spawn enemy sprites somewhere within its boundaries. It also
205 *** regenerates dead enemies after a certain amount of time. The enemies can be
206 *** constrained within the zone area or be made free to roam the entire map
207 *** after spawning. If desired, the class has the option to declare seperate zones
208 *** for where enemies may spawn and where they may roam.
209 ***
210 *** \note It makes no sense to use seperate zones for spawning if the enemies are
211 *** not restrained in their roaming. If free roaming is enabled for this zone, construct
212 *** the zone sections the standard way.
213 ***
214 *** \note By default, enemies are restricted to move about within their zones and
215 *** a default regeneration timer is used. These properties can be changed after
216 *** the class object is constructed.
217 ***
218 *** \todo Consider adding a call that will disable additional enemies from spawning in
219 *** the zone, or limit the maximum number of enemies that may ever spawn in the zone.
220 *** ***************************************************************************/
221 class EnemyZone : public MapZone
222 {
223 public:
224     /** \brief Constructs an enemy zone that is initialized with a single zone section
225     *** \param left_col The left edge of the section to add
226     *** \param right_col The right edge of the section to add
227     *** \param top_row The top edge of the section to add
228     *** \param bottom_row The bottom edge of the section to add
229     **/
230     EnemyZone(uint16_t left_col, uint16_t right_col,
231               uint16_t top_row, uint16_t bottom_row);
232 
233     virtual ~EnemyZone() override;
234 
235     //! \brief A C++ wrapper made to create a new object from scripting,
236     //! without letting Lua handling the object life-cycle.
237     //! \note We don't permit luabind to use constructors here as it can't currently
238     //! give the object ownership at construction time.
239     static EnemyZone* Create(uint16_t left_col, uint16_t right_col, uint16_t top_row, uint16_t bottom_row);
240 
241     //! \brief Enables/disables the enemy zone.
SetEnabled(bool is_enabled)242     void SetEnabled(bool is_enabled) {
243         _enabled = is_enabled;
244     }
245 
246     /** \brief Adds a new enemy sprite to the zone
247     *** \param enemy A pointer to the EnemySprite object instance to add
248     *** \param count The number of copies of this enemy to add
249     **/
250     void AddEnemy(EnemySprite *enemy, uint8_t count = 1);
251 
252     /** \brief Adds a new zone section to the zone where enemies may spawn
253     *** \param left_col The left edge of the section to add
254     *** \param right_col The right edge of the section to add
255     *** \param top_row The top edge of the section to add
256     *** \param bottom_row The bottom edge of the section to add
257     ***
258     *** Calling this method automatically enables this zone to have seperate areas for spawning
259     *** and roaming. Upon successfully adding a single spawn section, enemies will no longer be
260     *** allowed to spawn in the sections added directly to the class object. Each spawn zone section
261     *** must reside completely inside a roaming zone section for it to be added successfully. The reason
262     *** for this is that we do not want to allow enemies to spawn at a location where they are "stuck" and
263     *** can't roam anywhere. And for zones that do not restrict roaming, it makes no sense to add zones
264     *** specific to spawning in the first place.
265     ***
266     *** \note The value of left shoult be less than right, and top should be less that
267     *** bottom. If these conditions are not true, a warning will be printed and the section
268     *** will not be added.
269     **/
270     void AddSpawnSection(uint16_t left_col, uint16_t right_col, uint16_t top_row, uint16_t bottom_row);
271 
272     //! \brief Decrements the number of active enemies by one
273     void EnemyDead();
274 
275     //! \brief Gradually spawns enemy sprites in the zone
276     virtual void Update() override;
277 
278     //! \brief Draw the zone on screen for debugging purpose
279     virtual void Draw() override;
280 
281     //! \brief Returns true if this zone has seperate zones for roaming and spawning
HasSeparateSpawnZone()282     bool HasSeparateSpawnZone() const {
283         return (_spawn_zone != nullptr);
284     }
285 
286     //! \name Class Member Access Functions
287     //@{
IsRoamingRestrained()288     bool IsRoamingRestrained() const {
289         return _roaming_restrained;
290     }
291 
GetSpawnTime()292     uint32_t GetSpawnTime() const {
293         return _spawn_timer.GetDuration();
294     }
295 
SetRoamingRestrained(bool restrain)296     void SetRoamingRestrained(bool restrain) {
297         _roaming_restrained = restrain;
298     }
299 
300     //! \note Calling this function will reset the elapsed spawn time
SetSpawnTime(uint32_t time)301     void SetSpawnTime(uint32_t time) {
302         _spawn_timer.Reset();
303         _spawn_timer.SetDuration(time);
304         _spawn_timer.Run();
305     }
306 
307     //! Set the number of times an enemy can spawn in this enemy zone.
SetSpawnsLeft(int32_t spawns)308     void SetSpawnsLeft(int32_t spawns)
309     { _spawns_left = spawns; }
310 
311     //! Set the number of times left an enemy can spawn in this enemy zone.
GetSpawnsLeft()312     int32_t GetSpawnsLeft() const
313     { return _spawns_left; }
314 
315     //! Decrease enemy spawns left to do. Should be triggered upon enemy death.
DecreaseSpawnsLeft()316     void DecreaseSpawnsLeft()
317     { if (_spawns_left > 0) --_spawns_left; }
318     //@}
319 
320 private:
321     //
322     // The copy constructor and assignment operator are hidden by design
323     // to cause compilation errors when attempting to copy or assign this class.
324     //
325 
326     EnemyZone(const EnemyZone& enemy_zone);
327     EnemyZone& operator=(const EnemyZone& enemy_zone);
328 
329     //! \brief Tells whether the zone is activated.
330     bool _enabled;
331 
332     //! \brief If true, enemies of this zone are not allowed
333     //! to roam outside of the zone boundaries
334     bool _roaming_restrained;
335 
336     //! \brief The number of enemies that are currently not in the DEAD state
337     uint8_t _active_enemies;
338 
339     //! \brief The number of times an enemy can (re)spawn in this enemy zone.
340     //! By default, this value is equal to -1 meaning an infinite amount of time.
341     //! This permits to set special spawn points where enemies can only be seen once,
342     //! for special bosses or puzzles.
343     int32_t _spawns_left;
344 
345     //! \brief Used for the respawning of enemies within the zone
346     vt_system::SystemTimer _spawn_timer;
347 
348     //! \brief Used to keep track of the amount of time to wait before re-spawning a dead enemy
349     vt_system::SystemTimer _dead_timer;
350 
351     //! \brief An optional zone which specifies where enemies may spawn
352     MapZone *_spawn_zone;
353 
354     /** \brief Contains all of the enemies that may exist in this zone.
355     *** \note These sprites will be deleted by the map object manager, not the destructor of this class.
356     **/
357     std::vector<EnemySprite*> _enemies;
358 
359     /** \brief Contains all of the enemies that are owned by this class.  These objects must be cleaned up by this class.
360     ***        This is a hack around a memory leak and should be addressed more formally in the future.
361     **/
362     std::vector<EnemySprite*> _enemies_owned;
363 };
364 
365 } // namespace private_map
366 
367 } // namespace vt_map
368 
369 #endif // __MAP_ZONES_HEADER__
370