1// SuperTux - WalkingBadguy
2// Copyright (C) 2006 Christoph Sommer <christoph.sommer@2006.expires.deltadevelopment.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#include "badguy/walking_badguy.hpp"
18
19#include <math.h>
20
21#include "sprite/sprite.hpp"
22
23WalkingBadguy::WalkingBadguy(const Vector& pos,
24 const std::string& sprite_name_,
25 const std::string& walk_left_action_,
26 const std::string& walk_right_action_,
27 int layer_,
28 const std::string& light_sprite_name) :
29 BadGuy(pos, sprite_name_, layer_, light_sprite_name),
30 walk_left_action(walk_left_action_),
31 walk_right_action(walk_right_action_),
32 walk_speed(80),
33 max_drop_height(-1),
34 turn_around_timer(),
35 turn_around_counter()
36{
37}
38
39WalkingBadguy::WalkingBadguy(const Vector& pos,
40 Direction direction,
41 const std::string& sprite_name_,
42 const std::string& walk_left_action_,
43 const std::string& walk_right_action_,
44 int layer_,
45 const std::string& light_sprite_name) :
46 BadGuy(pos, direction, sprite_name_, layer_, light_sprite_name),
47 walk_left_action(walk_left_action_),
48 walk_right_action(walk_right_action_),
49 walk_speed(80),
50 max_drop_height(-1),
51 turn_around_timer(),
52 turn_around_counter()
53{
54}
55
56WalkingBadguy::WalkingBadguy(const ReaderMapping& reader,
57 const std::string& sprite_name_,
58 const std::string& walk_left_action_,
59 const std::string& walk_right_action_,
60 int layer_,
61 const std::string& light_sprite_name) :
62 BadGuy(reader, sprite_name_, layer_, light_sprite_name),
63 walk_left_action(walk_left_action_),
64 walk_right_action(walk_right_action_),
65 walk_speed(80),
66 max_drop_height(-1),
67 turn_around_timer(),
68 turn_around_counter()
69{
70}
71
72void
73WalkingBadguy::initialize()
74{
75 if (m_frozen)
76 return;
77 m_sprite->set_action(m_dir == Direction::LEFT ? walk_left_action : walk_right_action);
78 m_col.m_bbox.set_size(m_sprite->get_current_hitbox_width(), m_sprite->get_current_hitbox_height());
79 m_physic.set_velocity_x(m_dir == Direction::LEFT ? -walk_speed : walk_speed);
80 m_physic.set_acceleration_x (0.0);
81}
82
83void
84WalkingBadguy::set_walk_speed (float ws)
85{
86 walk_speed = fabsf(ws);
87 /* physic.set_velocity_x(dir == LEFT ? -walk_speed : walk_speed); */
88}
89
90void
91WalkingBadguy::add_velocity (const Vector& velocity)
92{
93 m_physic.set_velocity(m_physic.get_velocity() + velocity);
94}
95
96void
97WalkingBadguy::active_update(float dt_sec, float dest_x_velocity)
98{
99 BadGuy::active_update(dt_sec);
100
101 float current_x_velocity = m_physic.get_velocity_x ();
102
103 if (m_frozen)
104 {
105 m_physic.set_velocity_x (0.0);
106 m_physic.set_acceleration_x (0.0);
107 }
108 /* We're very close to our target speed. Just set it to avoid oscillation */
109 else if ((current_x_velocity > (dest_x_velocity - 5.0f)) &&
110 (current_x_velocity < (dest_x_velocity + 5.0f)))
111 {
112 m_physic.set_velocity_x (dest_x_velocity);
113 m_physic.set_acceleration_x (0.0);
114 }
115 /* Check if we're going too slow or even in the wrong direction */
116 else if (((dest_x_velocity <= 0.0f) && (current_x_velocity > dest_x_velocity)) ||
117 ((dest_x_velocity > 0.0f) && (current_x_velocity < dest_x_velocity)))
118 {
119 /* acceleration == walk-speed => it will take one second to get from zero
120 * to full speed. */
121 m_physic.set_acceleration_x (dest_x_velocity);
122 }
123 /* Check if we're going too fast */
124 else if (((dest_x_velocity <= 0.0f) && (current_x_velocity < dest_x_velocity)) ||
125 ((dest_x_velocity > 0.0f) && (current_x_velocity > dest_x_velocity)))
126 {
127 /* acceleration == walk-speed => it will take one second to get twice the
128 * speed to normal speed. */
129 m_physic.set_acceleration_x ((-1.f) * dest_x_velocity);
130 }
131 else
132 {
133 /* The above should have covered all cases. */
134 assert(false);
135 }
136
137 if (max_drop_height > -1) {
138 if (on_ground() && might_fall(max_drop_height+1))
139 {
140 turn_around();
141 }
142 }
143
144 if ((m_dir == Direction::LEFT) && (m_physic.get_velocity_x () > 0.0f)) {
145 m_dir = Direction::RIGHT;
146 set_action (walk_right_action, /* loops = */ -1);
147 }
148 else if ((m_dir == Direction::RIGHT) && (m_physic.get_velocity_x () < 0.0f)) {
149 m_dir = Direction::LEFT;
150 set_action (walk_left_action, /* loops = */ -1);
151 }
152}
153
154void
155WalkingBadguy::active_update(float dt_sec)
156{
157 active_update (dt_sec, (m_dir == Direction::LEFT) ? -walk_speed : +walk_speed);
158}
159
160void
161WalkingBadguy::collision_solid(const CollisionHit& hit)
162{
163
164 update_on_ground_flag(hit);
165
166 if (hit.top) {
167 if (m_physic.get_velocity_y() < 0) m_physic.set_velocity_y(0);
168 }
169 if (hit.bottom) {
170 if (m_physic.get_velocity_y() > 0) m_physic.set_velocity_y(0);
171 }
172
173 if ((hit.left && (m_dir == Direction::LEFT)) || (hit.right && (m_dir == Direction::RIGHT))) {
174 turn_around();
175 }
176
177}
178
179HitResponse
180WalkingBadguy::collision_badguy(BadGuy& , const CollisionHit& hit)
181{
182 if (hit.top) {
183 return FORCE_MOVE;
184 }
185
186 if ((hit.left && (m_dir == Direction::LEFT)) || (hit.right && (m_dir == Direction::RIGHT))) {
187 turn_around();
188 }
189
190 return CONTINUE;
191}
192
193void
194WalkingBadguy::turn_around()
195{
196 if (m_frozen)
197 return;
198 m_dir = m_dir == Direction::LEFT ? Direction::RIGHT : Direction::LEFT;
199 if (get_state() == STATE_INIT || get_state() == STATE_INACTIVE || get_state() == STATE_ACTIVE) {
200 m_sprite->set_action(m_dir == Direction::LEFT ? walk_left_action : walk_right_action);
201 }
202 m_physic.set_velocity_x(-m_physic.get_velocity_x());
203 m_physic.set_acceleration_x (-m_physic.get_acceleration_x ());
204
205 // if we get dizzy, we fall off the screen
206 if (turn_around_timer.started()) {
207 if (turn_around_counter++ > 10) kill_fall();
208 } else {
209 turn_around_timer.start(1);
210 turn_around_counter = 0;
211 }
212
213}
214
215void
216WalkingBadguy::freeze()
217{
218 BadGuy::freeze();
219 m_physic.set_velocity_x(0);
220}
221
222void
223WalkingBadguy::unfreeze()
224{
225 BadGuy::unfreeze();
226 WalkingBadguy::initialize();
227}
228
229float
230WalkingBadguy::get_velocity_y() const
231{
232 return m_physic.get_velocity_y();
233}
234
235void
236WalkingBadguy::set_velocity_y(float vy)
237{
238 m_physic.set_velocity_y(vy);
239}
240
241/* EOF */
242