changed yeti behaviour back to Matze's version (sorry, paroneayea)
[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 static const int INITIAL_HITPOINTS = 3;
14 static const int INITIAL_BULLET_HP = 10;
15
16 Yeti::Yeti(const lisp::Lisp& reader)
17 {
18   reader.get("x", start_position.x);
19   reader.get("y", start_position.y);
20   bbox.set_size(80, 120);
21   sprite = sprite_manager->create("yeti");
22   state = INIT;
23   side = LEFT;
24   hitpoints = INITIAL_HITPOINTS;
25   bullet_hitpoints = INITIAL_BULLET_HP;
26   sound_gna = SoundManager::get()->load_sound(
27       get_resource_filename("sounds/yeti_gna.wav"));
28   sound_roar = SoundManager::get()->load_sound(
29       get_resource_filename("sounds/yeti_roar.wav"));
30 }
31
32 Yeti::~Yeti()
33 {
34   Mix_FreeChunk(sound_gna);
35 }
36
37 void
38 Yeti::active_action(float elapsed_time)
39 {
40   switch(state) {
41     case INIT:
42       break;
43     case GO_RIGHT:
44       physic.set_velocity_x(RUN_SPEED);
45       if(timer.check())
46         physic.set_velocity_y(JUMP_VEL2);
47       break;
48     case GO_LEFT:
49       physic.set_velocity_x(-RUN_SPEED);
50       if(timer.check())
51         physic.set_velocity_y(JUMP_VEL2);
52       break;
53     case ANGRY_JUMPING:
54       if(timer.check()) {
55         // jump
56         SoundManager::get()->play_sound(sound_gna);
57         physic.set_velocity_y(JUMP_VEL1);
58       }
59       break;
60     default:
61       break;
62   }
63
64   movement = physic.get_movement(elapsed_time);
65 }
66
67 void
68 Yeti::go_right()
69 {
70   // jump and move right
71   physic.set_velocity_y(JUMP_VEL1);
72   physic.set_velocity_x(RUN_SPEED);
73   state = GO_RIGHT;
74   timer.start(JUMP_TIME);
75 }
76
77 void
78 Yeti::go_left()
79 {
80   physic.set_velocity_y(JUMP_VEL1);
81   physic.set_velocity_x(-RUN_SPEED);
82   state = GO_LEFT;
83   timer.start(JUMP_TIME);
84 }
85
86 void
87 Yeti::angry_jumping()
88 {
89   jumpcount = 0;
90   timer.start(ANGRY_JUMP_WAIT);
91   state = ANGRY_JUMPING;
92   physic.set_velocity_x(0);
93 }
94
95 HitResponse
96 Yeti::collision_player(Player& player, const CollisionHit& hit)
97 {
98   if(player.is_invincible()) {
99     kill_fall();
100     return ABORT_MOVE;
101   }
102   if(hit.normal.y > .9) {
103     hitpoints--;
104     bullet_hitpoints--;
105     SoundManager::get()->play_sound(sound_roar);
106     if(collision_squished(player))
107       return ABORT_MOVE;
108     else if (hitpoints <= 0) {
109       bullet_hitpoints = 0;
110       player.kill(Player::SHRINK);
111       return FORCE_MOVE;
112     }
113   }
114   std::cout << "COLLISION - HITPOINTS: " << hitpoints << ", BULLET HP: " << bullet_hitpoints << std::endl;
115   player.kill(Player::SHRINK);
116   return FORCE_MOVE;
117 }
118
119 bool
120 Yeti::collision_squished(Player& player)
121 {
122   bool result = false;
123   player.bounce(*this);
124   if (hitpoints <= 0) {
125     bullet_hitpoints = 0;
126     //sprite->set_action("dead"); 
127     kill_squished(player);
128     result = true;
129   }
130   return result;
131 }
132
133 void
134 Yeti::write(lisp::Writer& )
135 {
136 }
137
138 void
139 Yeti::drop_stalactite()
140 {
141   YetiStalactite* nearest = 0;
142   float dist = FLT_MAX;
143
144   Sector* sector = Sector::current();
145   for(Sector::GameObjects::iterator i = sector->gameobjects.begin();
146       i != sector->gameobjects.end(); ++i) {
147     YetiStalactite* stalactite = dynamic_cast<YetiStalactite*> (*i);
148     if(stalactite && stalactite->is_hanging()) {
149       float sdist 
150         = fabsf(stalactite->get_pos().x - sector->player->get_pos().x);
151       if(sdist < dist) {
152         nearest = stalactite;
153         dist = sdist;
154       }
155     }
156   }
157
158   if(nearest)
159     nearest->start_shaking();
160 }
161
162 HitResponse
163 Yeti::collision_solid(GameObject& , const CollisionHit& hit)
164 {
165   if(fabsf(hit.normal.y) > .5) { // hit floor or roof?
166     physic.set_velocity_y(0);
167     if(state == INIT) {
168       go_right();
169     } else if(state == GO_LEFT && !timer.started()) {
170       side = LEFT;
171       angry_jumping();
172     } else if(state == GO_RIGHT && !timer.started()) {
173       side = RIGHT;
174       angry_jumping();
175     } else if(state == ANGRY_JUMPING) {
176       if(!timer.started()) {
177         // we just landed
178         jumpcount++;
179         // make a stalactite falling down and shake camera a bit
180         Sector::current()->camera->shake(.1, 0, 10);
181         drop_stalactite();
182         
183         // go to other side after 3 jumps
184         if(jumpcount == 3) {
185           if(side == LEFT)
186             go_right();
187           else
188             go_left();
189         } else {
190           // jump again
191           timer.start(ANGRY_JUMP_WAIT);
192         }
193       }
194     }
195   }
196   
197   return CONTINUE;
198 }
199
200 void
201 Yeti::kill_fall()
202 {
203   SoundManager::get()->play_sound(sound_roar);
204   bullet_hitpoints--;
205   if (bullet_hitpoints <= 0) {
206     SoundManager::get()->play_sound(IDToSound(SND_FALL), this,
207        Sector::current()->player->get_pos());
208     physic.set_velocity_y(0);
209     physic.enable_gravity(true);
210     set_state(STATE_FALLING);
211   }
212   std::cout << "KILL_FALL - HITPOINTS: " << hitpoints << ", BULLET HP: " << bullet_hitpoints << std::endl;
213 }
214
215 IMPLEMENT_FACTORY(Yeti, "yeti")