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