Massive copyright update. I'm sorry if I'm crediting Matze for something he didn...
[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
24 namespace {
25   const float VERTICAL_SPEED = 450;   /**< y-speed when jumping */
26   const float HORIZONTAL_SPEED = 220; /**< x-speed when jumping */
27   const float MIN_RECOVER_TIME = 0.1; /**< minimum time to stand still before starting a (new) jump */
28   const float MAX_RECOVER_TIME = 1.0; /**< maximum time to stand still before starting a (new) jump */
29 }
30
31 SkullyHop::SkullyHop(const lisp::Lisp& reader)
32 {
33   reader.get("x", start_position.x);
34   reader.get("y", start_position.y);
35   bbox.set_size(33.8, 43.8); //sprite is 34x44
36   sprite = sprite_manager->create("images/creatures/skullyhop/skullyhop.sprite");
37   has_initial_direction = false;
38 }
39
40 SkullyHop::SkullyHop(float pos_x, float pos_y, Direction d)
41 {
42   start_position.x = pos_x;
43   start_position.y = pos_y;
44   bbox.set_size(33.8, 43.8); //sprite is 34x44
45   sprite = sprite_manager->create("images/creatures/skullyhop/skullyhop.sprite");
46   has_initial_direction = true;
47   initial_direction = d;
48 }
49
50 void
51 SkullyHop::write(lisp::Writer& writer)
52 {
53   writer.start_list("skullyhop");
54   writer.write_float("x", start_position.x);
55   writer.write_float("y", start_position.y);
56   writer.end_list("skullyhop");
57 }
58
59 void
60 SkullyHop::activate()
61 {
62   if (has_initial_direction) dir = initial_direction;
63
64   // initial state is JUMPING, because we might start airborne
65   state = JUMPING;
66   sprite->set_action(dir == LEFT ? "jumping-left" : "jumping-right");
67 }
68
69 void
70 SkullyHop::set_state(SkullyHopState newState)
71 {
72   if (newState == STANDING) {
73     physic.set_velocity_x(0);
74     physic.set_velocity_y(0);
75     sprite->set_action(dir == LEFT ? "standing-left" : "standing-right");
76
77     float recover_time = MIN_RECOVER_TIME + (float)rand() / RAND_MAX * (MAX_RECOVER_TIME - MIN_RECOVER_TIME);
78     recover_timer.start(recover_time);
79   } else
80   if (newState == CHARGING) {
81     sprite->set_action(dir == LEFT ? "charging-left" : "charging-right", 1);
82   } else
83   if (newState == JUMPING) {
84     sprite->set_action(dir == LEFT ? "jumping-left" : "jumping-right");
85     physic.set_velocity_x(dir == LEFT ? -HORIZONTAL_SPEED : HORIZONTAL_SPEED);
86     physic.set_velocity_y(VERTICAL_SPEED);
87   }
88
89   state = newState;
90 }
91
92 bool
93 SkullyHop::collision_squished(Player& player)
94 {
95   sprite->set_action(dir == LEFT ? "squished-left" : "squished-right");
96   kill_squished(player);
97   return true;
98 }
99
100 HitResponse
101 SkullyHop::collision_solid(GameObject& , const CollisionHit& hit)
102 {
103   // ignore collisions while standing still
104   if(state != JUMPING) return CONTINUE;
105
106   // check if we hit the floor while falling
107   if ((hit.normal.y < 0) && (physic.get_velocity_y() < 0)) {
108     set_state(STANDING);
109   }
110
111   // check if we hit the roof while climbing
112   if ((hit.normal.y > 0) && (physic.get_velocity_y() > 0)) { 
113     physic.set_velocity_y(0);
114   }
115
116   // check if we hit left or right while moving in either direction
117   if ((hit.normal.x != 0) && (physic.get_velocity_x() != 0)) {
118     dir = dir == LEFT ? RIGHT : LEFT;
119     sprite->set_action(dir == LEFT ? "jumping-left" : "jumping-right");
120     physic.set_velocity_x(-0.25*physic.get_velocity_x());
121   }
122
123   return CONTINUE;
124 }
125
126 HitResponse
127 SkullyHop::collision_badguy(BadGuy& badguy, const CollisionHit& hit)
128 {
129   // behaviour for badguy collisions is the same as for collisions with solids
130   return collision_solid(badguy, hit);
131 }
132
133 void
134 SkullyHop::active_update(float elapsed_time)
135 {
136   BadGuy::active_update(elapsed_time);
137
138   // charge when fully recovered
139   if ((state == STANDING) && (recover_timer.check())) {
140     set_state(CHARGING);
141     return;
142   }
143
144   // jump as soon as charging animation completed
145   if ((state == CHARGING) && (sprite->animation_done())) {
146     set_state(JUMPING);
147     return;
148   } 
149 }
150
151 IMPLEMENT_FACTORY(SkullyHop, "skullyhop")