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