1// SkullyHop - A Hopping Skull
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/skullyhop.hpp"
18
19#include "audio/sound_manager.hpp"
20#include "math/random.hpp"
21#include "sprite/sprite.hpp"
22
23namespace {
24const float MIN_RECOVER_TIME = 0.1f; /**< minimum time to stand still before starting a (new) jump */
25const float MAX_RECOVER_TIME = 1.0f; /**< maximum time to stand still before starting a (new) jump */
26static const std::string SKULLYHOP_SOUND = "sounds/hop.ogg";
27}
28
29SkullyHop::SkullyHop(const ReaderMapping& reader) :
30 BadGuy(reader, "images/creatures/skullyhop/skullyhop.sprite"),
31 recover_timer(),
32 state()
33{
34 SoundManager::current()->preload( SKULLYHOP_SOUND );
35}
36
37void
38SkullyHop::initialize()
39{
40 // initial state is JUMPING, because we might start airborne
41 state = JUMPING;
42 m_sprite->set_action(m_dir == Direction::LEFT ? "jumping-left" : "jumping-right");
43}
44
45void
46SkullyHop::set_state(SkullyHopState newState)
47{
48 if (newState == STANDING) {
49 m_physic.set_velocity_x(0);
50 m_physic.set_velocity_y(0);
51 m_sprite->set_action(m_dir == Direction::LEFT ? "standing-left" : "standing-right");
52
53 float recover_time = gameRandom.randf(MIN_RECOVER_TIME,MAX_RECOVER_TIME);
54 recover_timer.start(recover_time);
55 } else
56 if (newState == CHARGING) {
57 m_sprite->set_action(m_dir == Direction::LEFT ? "charging-left" : "charging-right", 1);
58 } else
59 if (newState == JUMPING) {
60 m_sprite->set_action(m_dir == Direction::LEFT ? "jumping-left" : "jumping-right");
61const float HORIZONTAL_SPEED = 220; /**< x-speed when jumping */
62 m_physic.set_velocity_x(m_dir == Direction::LEFT ? -HORIZONTAL_SPEED : HORIZONTAL_SPEED);
63const float VERTICAL_SPEED = -450; /**< y-speed when jumping */
64 m_physic.set_velocity_y(VERTICAL_SPEED);
65 SoundManager::current()->play( SKULLYHOP_SOUND, get_pos());
66 }
67
68 state = newState;
69}
70
71bool
72SkullyHop::collision_squished(GameObject& object)
73{
74 if (m_frozen)
75 return BadGuy::collision_squished(object);
76
77 m_sprite->set_action(m_dir == Direction::LEFT ? "squished-left" : "squished-right");
78 kill_squished(object);
79 return true;
80}
81
82void
83SkullyHop::collision_solid(const CollisionHit& hit)
84{
85 if (m_frozen || BadGuy::get_state() == STATE_BURNING)
86 {
87 BadGuy::collision_solid(hit);
88 return;
89 }
90
91 // just default behaviour (i.e. stop at floor/walls) when squished
92 if (BadGuy::get_state() == STATE_SQUISHED) {
93 BadGuy::collision_solid(hit);
94 }
95
96 // ignore collisions while standing still
97 if (state != JUMPING)
98 return;
99
100 // check if we hit the floor while falling
101 if (hit.bottom && m_physic.get_velocity_y() > 0 ) {
102 set_state(STANDING);
103 }
104 // check if we hit the roof while climbing
105 if (hit.top) {
106 m_physic.set_velocity_y(0);
107 }
108
109 // check if we hit left or right while moving in either direction
110 if (hit.left || hit.right) {
111 m_dir = m_dir == Direction::LEFT ? Direction::RIGHT : Direction::LEFT;
112 m_sprite->set_action(m_dir == Direction::LEFT ? "jumping-left" : "jumping-right");
113 m_physic.set_velocity_x(-0.25f*m_physic.get_velocity_x());
114 }
115}
116
117HitResponse
118SkullyHop::collision_badguy(BadGuy& , const CollisionHit& hit)
119{
120 // behaviour for badguy collisions is the same as for collisions with solids
121 collision_solid(hit);
122
123 return CONTINUE;
124}
125
126void
127SkullyHop::active_update(float dt_sec)
128{
129 BadGuy::active_update(dt_sec);
130
131 // no change if frozen
132 if (m_frozen)
133 return;
134
135 // charge when fully recovered
136 if ((state == STANDING) && (recover_timer.check())) {
137 set_state(CHARGING);
138 return;
139 }
140
141 // jump as soon as charging animation completed
142 if ((state == CHARGING) && (m_sprite->animation_done())) {
143 set_state(JUMPING);
144 return;
145 }
146}
147
148void
149SkullyHop::unfreeze()
150{
151 BadGuy::unfreeze();
152 initialize();
153}
154
155bool
156SkullyHop::is_freezable() const
157{
158 return true;
159}
160
161/* EOF */
162