Started some work on the yeti boss
[supertux.git] / src / badguy / yeti.cpp
1 #include <config.h>
2
3 #include <float.h>
4 #include "yeti.h"
5 #include "object/camera.h"
6 #include "yeti_stalactite.h"
7
8 static const float JUMP_VEL1 = 250;
9 static const float JUMP_VEL2 = 700;
10 static const float RUN_SPEED = 350;
11 static const float JUMP_TIME = 1.6;
12 static const float ANGRY_JUMP_WAIT = .5;
13
14 Yeti::Yeti(const lisp::Lisp& reader)
15 {
16   reader.get("x", start_position.x);
17   reader.get("y", start_position.y);
18   bbox.set_size(80, 120);
19   sprite = sprite_manager->create("yeti");
20   state = INIT;
21   side = LEFT;
22   sound_gna = SoundManager::get()->load_sound(
23       get_resource_filename("sounds/yeti_gna.wav"));
24 }
25
26 Yeti::~Yeti()
27 {
28   Mix_FreeChunk(sound_gna);
29 }
30
31 void
32 Yeti::active_action(float elapsed_time)
33 {
34   switch(state) {
35     case INIT:
36       break;
37     case GO_RIGHT:
38       physic.set_velocity_x(RUN_SPEED);
39       if(timer.check())
40         physic.set_velocity_y(JUMP_VEL2);
41       break;
42     case GO_LEFT:
43       physic.set_velocity_x(-RUN_SPEED);
44       if(timer.check())
45         physic.set_velocity_y(JUMP_VEL2);
46       break;
47     case ANGRY_JUMPING:
48       if(timer.check()) {
49         // jump
50         SoundManager::get()->play_sound(sound_gna);
51         physic.set_velocity_y(JUMP_VEL1);
52       }
53       break;
54     default:
55       break;
56   }
57
58   movement = physic.get_movement(elapsed_time);
59 }
60
61 void
62 Yeti::go_right()
63 {
64   // jump and move right
65   physic.set_velocity_y(JUMP_VEL1);
66   physic.set_velocity_x(RUN_SPEED);
67   state = GO_RIGHT;
68   timer.start(JUMP_TIME);
69 }
70
71 void
72 Yeti::go_left()
73 {
74   physic.set_velocity_y(JUMP_VEL1);
75   physic.set_velocity_x(-RUN_SPEED);
76   state = GO_LEFT;
77   timer.start(JUMP_TIME);
78 }
79
80 void
81 Yeti::angry_jumping()
82 {
83   jumpcount = 0;
84   timer.start(ANGRY_JUMP_WAIT);
85   state = ANGRY_JUMPING;
86   physic.set_velocity_x(0);
87 }
88
89 bool
90 Yeti::collision_squished(Player& player)
91 {
92   kill_squished(player);
93   return true;
94 }
95
96 void
97 Yeti::write(lisp::Writer& )
98 {
99 }
100
101 void
102 Yeti::drop_stalactite()
103 {
104   YetiStalactite* nearest = 0;
105   float dist = FLT_MAX;
106
107   Sector* sector = Sector::current();
108   for(Sector::GameObjects::iterator i = sector->gameobjects.begin();
109       i != sector->gameobjects.end(); ++i) {
110     YetiStalactite* stalactite = dynamic_cast<YetiStalactite*> (*i);
111     if(stalactite && stalactite->is_hanging()) {
112       float sdist 
113         = fabsf(stalactite->get_pos().x - sector->player->get_pos().x);
114       if(sdist < dist) {
115         nearest = stalactite;
116         dist = sdist;
117       }
118     }
119   }
120
121   if(nearest)
122     nearest->start_shaking();
123 }
124
125 HitResponse
126 Yeti::collision_solid(GameObject& , const CollisionHit& hit)
127 {
128   if(fabsf(hit.normal.y) > .5) { // hit floor or roof?
129     physic.set_velocity_y(0);
130     if(state == INIT) {
131       go_right();
132     } else if(state == GO_LEFT && !timer.started()) {
133       side = LEFT;
134       angry_jumping();
135     } else if(state == GO_RIGHT && !timer.started()) {
136       side = RIGHT;
137       angry_jumping();
138     } else if(state == ANGRY_JUMPING) {
139       if(!timer.started()) {
140         // we just landed
141         jumpcount++;
142         // make a stalactite falling down and shake camera a bit
143         Sector::current()->camera->shake(.1, 0, 10);
144         drop_stalactite();
145         
146         // go to other side after 3 jumps
147         if(jumpcount == 3) {
148           if(side == LEFT)
149             go_right();
150           else
151             go_left();
152         } else {
153           // jump again
154           timer.start(ANGRY_JUMP_WAIT);
155         }
156       }
157     }
158   }
159   
160   return CONTINUE;
161 }
162
163 IMPLEMENT_FACTORY(Yeti, "yeti")