1// SuperTux
2// Copyright (C) 2006 Matthias Braun <matze@braunis.de>
3//
4// This program 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// This program 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
15// along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17#ifndef HEADER_SUPERTUX_BADGUY_BADGUY_HPP
18#define HEADER_SUPERTUX_BADGUY_BADGUY_HPP
19
20#include "editor/object_option.hpp"
21#include "object/moving_sprite.hpp"
22#include "supertux/direction.hpp"
23#include "supertux/physic.hpp"
24#include "supertux/timer.hpp"
25
26class Dispenser;
27class Player;
28class Bullet;
29
30/** Base class for moving sprites that can hurt the Player. */
31class BadGuy : public MovingSprite
32{
33public:
34 BadGuy(const Vector& pos, const std::string& sprite_name, int layer = LAYER_OBJECTS,
35 const std::string& light_sprite_name = "images/objects/lightmap_light/lightmap_light-medium.sprite");
36 BadGuy(const Vector& pos, Direction direction, const std::string& sprite_name, int layer = LAYER_OBJECTS,
37 const std::string& light_sprite_name = "images/objects/lightmap_light/lightmap_light-medium.sprite");
38 BadGuy(const ReaderMapping& reader, const std::string& sprite_name, int layer = LAYER_OBJECTS,
39 const std::string& light_sprite_name = "images/objects/lightmap_light/lightmap_light-medium.sprite");
40
41 /** Called when the badguy is drawn. The default implementation
42 simply draws the badguy sprite on screen */
43 virtual void draw(DrawingContext& context) override;
44
45 /** Called each frame. The default implementation checks badguy
46 state and calls active_update and inactive_update */
47 virtual void update(float dt_sec) override;
48
49 virtual std::string get_class() const override { return "badguy"; }
50 virtual std::string get_display_name() const override { return _("Badguy"); }
51
52 virtual ObjectSettings get_settings() override;
53 virtual void after_editor_set() override;
54
55 /** Called when a collision with another object occurred. The
56 default implementation calls collision_player, collision_solid,
57 collision_badguy and collision_squished */
58 virtual HitResponse collision(GameObject& other, const CollisionHit& hit) override;
59
60 /** Called when a collision with tile with special attributes
61 occurred */
62 virtual void collision_tile(uint32_t tile_attributes) override;
63
64 /** Set the badguy to kill/falling state, which makes him falling of
65 the screen (his sprite is turned upside-down) */
66 virtual void kill_fall();
67
68 /** Call this, if you use custom kill_fall() or kill_squashed(GameObject& object) */
69 virtual void run_dead_script();
70
71 /** True if this badguy can break bricks or open bonusblocks in his
72 current form. */
73 virtual bool can_break() const { return false; }
74
75 Vector get_start_position() const { return m_start_position; }
76 void set_start_position(const Vector& vec) { m_start_position = vec; }
77
78 /** Called when hit by a fire bullet, and is_flammable() returns true */
79 virtual void ignite();
80
81 /** Called to revert a badguy when is_ignited() returns true */
82 virtual void extinguish();
83
84 /** Returns whether to call ignite() when a badguy gets hit by a fire bullet */
85 virtual bool is_flammable() const;
86
87 /** Returns whether this badguys is currently on fire */
88 bool is_ignited() const;
89
90 /** Called when hit by an ice bullet, and is_freezable() returns true. */
91 virtual void freeze();
92
93 /** Called to unfreeze the badguy. */
94 virtual void unfreeze();
95
96 virtual bool is_freezable() const;
97
98 /** Return true if this badguy can be hurt by tiles
99 with the attribute "hurts" */
100 virtual bool is_hurtable() const { return true; }
101
102 bool is_frozen() const;
103
104 bool is_in_water() const;
105
106 /** Get melting particle sprite filename */
107 virtual std::string get_water_sprite() const {
108 return "images/objects/water_drop/water_drop.sprite";
109 }
110
111 /** Sets the dispenser that spawns this badguy.
112 @param parent The dispenser */
113 void set_parent_dispenser(Dispenser* parent) { m_parent_dispenser = parent; }
114
115 /** Returns the dispenser this badguys was spawned by */
116 Dispenser* get_parent_dispenser() const { return m_parent_dispenser; }
117
118protected:
119 enum State {
120 STATE_INIT,
121 STATE_INACTIVE,
122 STATE_ACTIVE,
123 STATE_SQUISHED,
124 STATE_FALLING,
125 STATE_BURNING,
126 STATE_MELTING,
127 STATE_GROUND_MELTING,
128 STATE_INSIDE_MELTING,
129 STATE_GEAR
130 };
131
132protected:
133 /** Called when the badguy collided with a player */
134 virtual HitResponse collision_player(Player& player, const CollisionHit& hit);
135
136 /** Called when the badguy collided with solid ground */
137 virtual void collision_solid(const CollisionHit& hit) override;
138
139 /** Called when the badguy collided with another badguy */
140 virtual HitResponse collision_badguy(BadGuy& other, const CollisionHit& hit);
141
142 /** Called when the player hit the badguy from above. You should
143 return true if the badguy was squished, false if squishing
144 wasn't possible */
145 virtual bool collision_squished(GameObject& object);
146
147 /** Called when the badguy collided with a bullet */
148 virtual HitResponse collision_bullet(Bullet& bullet, const CollisionHit& hit);
149
150 /** called each frame when the badguy is activated. */
151 virtual void active_update(float dt_sec);
152
153 /** called each frame when the badguy is not activated. */
154 virtual void inactive_update(float dt_sec);
155
156 /** called immediately before the first call to initialize */
157 virtual void initialize();
158
159 /** called when the badguy has been activated. (As a side effect the
160 dir variable might have been changed so that it faces towards
161 the player. */
162 virtual void activate();
163
164 /** called when the badguy has been deactivated */
165 virtual void deactivate();
166
167 void kill_squished(GameObject& object);
168
169 void set_state(State state);
170 State get_state() const { return m_state; }
171
172 bool check_state_timer() {
173 return m_state_timer.check();
174 }
175
176 /** returns a pointer to the nearest player or 0 if no player is available */
177 Player* get_nearest_player() const;
178
179 /** initial position of the enemy. Also the position where enemy
180 respawns when after being deactivated. */
181 bool is_offscreen() const;
182
183 /** Returns true if we might soon fall at least @c height
184 pixels. Minimum value for height is 1 pixel */
185 bool might_fall(int height = 1) const;
186
187 /** Get Direction from String. */
188 Direction str2dir(const std::string& dir_str) const;
189
190 /** Update on_ground_flag judging by solid collision @c hit. This
191 gets called from the base implementation of collision_solid, so
192 call this when overriding collision_solid's default
193 behaviour. */
194 void update_on_ground_flag(const CollisionHit& hit);
195
196 /** Returns true if we touched ground in the past frame This only
197 works if update_on_ground_flag() gets called in
198 collision_solid. */
199 bool on_ground() const;
200
201 /** Returns floor normal stored the last time when
202 update_on_ground_flag was called and we touched something solid
203 from above. */
204 Vector get_floor_normal() const;
205
206 /** Returns true if we were in STATE_ACTIVE at the beginning of the
207 last call to update() */
208 bool is_active() const;
209
210 /** changes colgroup_active. Also calls set_group when badguy is in STATE_ACTIVE */
211 void set_colgroup_active(CollisionGroup group);
212
213private:
214 void try_activate();
215
216protected:
217 Physic m_physic;
218
219public:
220 /** Count this badguy to the statistics? This value should not be
221 changed during runtime. */
222 bool m_countMe;
223
224protected:
225 /** true if initialize() has already been called */
226 bool m_is_initialized;
227
228 Vector m_start_position;
229
230 /** The direction we currently face in */
231 Direction m_dir;
232
233 /** The direction we initially faced in */
234 Direction m_start_dir;
235
236 bool m_frozen;
237 bool m_ignited; /**< true if this badguy is currently on fire */
238 bool m_in_water; /** < true if the badguy is currently in water */
239
240 std::string m_dead_script; /**< script to execute when badguy is killed */
241
242 float m_melting_time;
243
244 SpritePtr m_lightsprite;
245 bool m_glowing;
246
247private:
248 State m_state;
249
250 /** true if state was STATE_ACTIVE at the beginning of the last call
251 to update() */
252 bool m_is_active_flag;
253
254 Timer m_state_timer;
255
256 /** true if we touched something solid from above and
257 update_on_ground_flag was called last frame */
258 bool m_on_ground_flag;
259
260 /** floor normal stored the last time when update_on_ground_flag was
261 called and we touched something solid from above */
262 Vector m_floor_normal;
263
264 /** CollisionGroup the badguy should be in while active */
265 CollisionGroup m_colgroup_active;
266
267 /** If this badguy was dispensed from a dispenser,
268 save the dispenser here. */
269 Dispenser* m_parent_dispenser;
270
271private:
272 BadGuy(const BadGuy&) = delete;
273 BadGuy& operator=(const BadGuy&) = delete;
274};
275
276#endif
277
278/* EOF */
279