2679ee7f0f4661152dd443ebfb995bf130a05413
[supertux.git] / src / badguy / skullyhop.cpp
1 //  $Id$
2 //
3 //  SkullyHop - A Hopping Skull
4 //  Copyright (C) 2006 Christoph Sommer <supertux@2006.expires.deltadevelopment.de>
5 //
6 //  This program is free software; you can redistribute it and/or
7 //  modify it under the terms of the GNU General Public License
8 //  as published by the Free Software Foundation; either version 2
9 //  of the License, or (at your option) any later version.
10 //
11 //  This program is distributed in the hope that it will be useful,
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 //  GNU General Public License for more details.
15 //
16 //  You should have received a copy of the GNU General Public License
17 //  along with this program; if not, write to the Free Software
18 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 //  02111-1307, USA.
20 #include <config.h>
21
22 #include "skullyhop.hpp"
23 #include "random_generator.hpp"
24
25 namespace {
26   const float VERTICAL_SPEED = 450;   /**< y-speed when jumping */
27   const float HORIZONTAL_SPEED = 220; /**< x-speed when jumping */
28   const float MIN_RECOVER_TIME = 0.1; /**< minimum time to stand still before starting a (new) jump */
29   const float MAX_RECOVER_TIME = 1.0; /**< maximum time to stand still before starting a (new) jump */
30 }
31
32 SkullyHop::SkullyHop(const lisp::Lisp& reader)
33 {
34   reader.get("x", start_position.x);
35   reader.get("y", start_position.y);
36   bbox.set_size(33.8, 43.8); //sprite is 34x44
37   sprite = sprite_manager->create("images/creatures/skullyhop/skullyhop.sprite");
38   has_initial_direction = false;
39 }
40
41 SkullyHop::SkullyHop(float pos_x, float pos_y, Direction d)
42 {
43   start_position.x = pos_x;
44   start_position.y = pos_y;
45   bbox.set_size(33.8, 43.8); //sprite is 34x44
46   sprite = sprite_manager->create("images/creatures/skullyhop/skullyhop.sprite");
47   has_initial_direction = true;
48   initial_direction = d;
49 }
50
51 void
52 SkullyHop::write(lisp::Writer& writer)
53 {
54   writer.start_list("skullyhop");
55   writer.write_float("x", start_position.x);
56   writer.write_float("y", start_position.y);
57   writer.end_list("skullyhop");
58 }
59
60 void
61 SkullyHop::activate()
62 {
63   if (has_initial_direction) dir = initial_direction;
64
65   // initial state is JUMPING, because we might start airborne
66   state = JUMPING;
67   sprite->set_action(dir == LEFT ? "jumping-left" : "jumping-right");
68 }
69
70 void
71 SkullyHop::set_state(SkullyHopState newState)
72 {
73   if (newState == STANDING) {
74     physic.set_velocity_x(0);
75     physic.set_velocity_y(0);
76     sprite->set_action(dir == LEFT ? "standing-left" : "standing-right");
77
78     float recover_time = systemRandom.randf(MIN_RECOVER_TIME,MAX_RECOVER_TIME);
79     recover_timer.start(recover_time);
80   } else
81   if (newState == CHARGING) {
82     sprite->set_action(dir == LEFT ? "charging-left" : "charging-right", 1);
83   } else
84   if (newState == JUMPING) {
85     sprite->set_action(dir == LEFT ? "jumping-left" : "jumping-right");
86     physic.set_velocity_x(dir == LEFT ? -HORIZONTAL_SPEED : HORIZONTAL_SPEED);
87     physic.set_velocity_y(VERTICAL_SPEED);
88   }
89
90   state = newState;
91 }
92
93 bool
94 SkullyHop::collision_squished(Player& player)
95 {
96   sprite->set_action(dir == LEFT ? "squished-left" : "squished-right");
97   kill_squished(player);
98   return true;
99 }
100
101 HitResponse
102 SkullyHop::collision_solid(GameObject& , const CollisionHit& hit)
103 {
104   // ignore collisions while standing still
105   if(state != JUMPING) return CONTINUE;
106
107   // check if we hit the floor while falling
108   if ((hit.normal.y < 0) && (physic.get_velocity_y() < 0)) {
109     set_state(STANDING);
110   }
111
112   // check if we hit the roof while climbing
113   if ((hit.normal.y > 0) && (physic.get_velocity_y() > 0)) { 
114     physic.set_velocity_y(0);
115   }
116
117   // check if we hit left or right while moving in either direction
118   if ((hit.normal.x != 0) && (physic.get_velocity_x() != 0)) {
119     dir = dir == LEFT ? RIGHT : LEFT;
120     sprite->set_action(dir == LEFT ? "jumping-left" : "jumping-right");
121     physic.set_velocity_x(-0.25*physic.get_velocity_x());
122   }
123
124   return CONTINUE;
125 }
126
127 HitResponse
128 SkullyHop::collision_badguy(BadGuy& badguy, const CollisionHit& hit)
129 {
130   // behaviour for badguy collisions is the same as for collisions with solids
131   return collision_solid(badguy, hit);
132 }
133
134 void
135 SkullyHop::active_update(float elapsed_time)
136 {
137   BadGuy::active_update(elapsed_time);
138
139   // charge when fully recovered
140   if ((state == STANDING) && (recover_timer.check())) {
141     set_state(CHARGING);
142     return;
143   }
144
145   // jump as soon as charging animation completed
146   if ((state == CHARGING) && (sprite->animation_done())) {
147     set_state(JUMPING);
148     return;
149   } 
150 }
151
152 IMPLEMENT_FACTORY(SkullyHop, "skullyhop")