fix tux not dying when falling out of screen in invincible mode, fix bug when creatin...
[supertux.git] / src / object / player.cpp
1 //  $Id$
2 //
3 //  SuperTux -  A Jump'n Run
4 //  Copyright (C) 2003 Tobias Glaesser <tobi.web@gmx.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  02111-1307, USA.
19 #include <config.h>
20
21 #include <typeinfo>
22 #include <cmath>
23 #include <iostream>
24 #include <cassert>
25
26 #include "gettext.hpp"
27 #include "sprite/sprite_manager.hpp"
28 #include "audio/sound_manager.hpp"
29 #include "player.hpp"
30 #include "tile.hpp"
31 #include "sprite/sprite.hpp"
32 #include "sector.hpp"
33 #include "resources.hpp"
34 #include "video/screen.hpp"
35 #include "statistics.hpp"
36 #include "game_session.hpp"
37 #include "object/tilemap.hpp"
38 #include "object/camera.hpp"
39 #include "object/particles.hpp"
40 #include "object/portable.hpp"
41 #include "object/bullet.hpp"
42 #include "trigger/trigger_base.hpp"
43 #include "control/joystickkeyboardcontroller.hpp"
44 #include "main.hpp"
45 #include "badguy/badguy.hpp"
46 #include "player_status.hpp"
47
48 static const int TILES_FOR_BUTTJUMP = 3;
49 static const float SHOOTING_TIME = .150;
50 /// time before idle animation starts
51 static const float IDLE_TIME = 2.5;
52
53 static const float WALK_ACCELERATION_X = 300;
54 static const float RUN_ACCELERATION_X = 400;
55 static const float SKID_XM = 200;
56 static const float SKID_TIME = .3;
57 static const float MAX_WALK_XM = 230;
58 static const float MAX_RUN_XM = 320;
59 static const float WALK_SPEED = 100;
60
61 static const float KICK_TIME = .3;
62
63 // growing animation
64 Surface* growingtux_left[GROWING_FRAMES];
65 Surface* growingtux_right[GROWING_FRAMES];
66
67 Surface* tux_life = 0;
68
69 TuxBodyParts* small_tux = 0;
70 TuxBodyParts* big_tux = 0;
71 TuxBodyParts* fire_tux = 0;
72 TuxBodyParts* ice_tux = 0;
73
74 void
75 TuxBodyParts::set_action(std::string action, int loops)
76 {
77   if(head != NULL)
78     head->set_action(action, loops);
79   if(body != NULL)
80     body->set_action(action, loops);
81   if(arms != NULL)
82     arms->set_action(action, loops);
83   if(feet != NULL)
84     feet->set_action(action, loops);
85 }
86
87 void
88 TuxBodyParts::draw(DrawingContext& context, const Vector& pos, int layer)
89 {
90   if(head != NULL)
91     head->draw(context, pos, layer-1);
92   if(body != NULL)
93     body->draw(context, pos, layer-3);
94   if(arms != NULL)
95     arms->draw(context, pos, layer);
96   if(feet != NULL)
97     feet->draw(context, pos, layer-2);
98 }
99
100 Player::Player(PlayerStatus* _player_status)
101   : player_status(_player_status), grabbed_object(0)
102 {
103   controller = main_controller;
104   smalltux_gameover = sprite_manager->create("smalltux-gameover");
105   smalltux_star = sprite_manager->create("smalltux-star");
106   bigtux_star = sprite_manager->create("bigtux-star");
107   init();
108 }
109
110 Player::~Player()
111 {
112   delete smalltux_gameover;
113   delete smalltux_star;
114   delete bigtux_star;
115 }
116
117 void
118 Player::init()
119 {
120   if(is_big())
121     bbox.set_size(31.8, 63.8);
122   else
123     bbox.set_size(31.8, 31.8);
124
125   dir = RIGHT;
126   old_dir = dir;
127   duck = false;
128   dead = false;
129
130   dying = false;
131   last_ground_y = 0;
132   fall_mode = ON_GROUND;
133   jumping = false;
134   can_jump = true;
135   butt_jump = false;
136   deactivated = false;
137   backflipping = false;
138   backflip_direction = 0;
139   
140   on_ground_flag = false;
141   grabbed_object = 0;
142
143   physic.reset();
144 }
145
146 void
147 Player::set_controller(Controller* controller)
148 {
149   this->controller = controller;
150 }
151
152 void
153 Player::update(float elapsed_time)
154 {
155   if(dying && dying_timer.check()) {
156     dead = true;
157     return;
158   }
159
160   // fixes the "affected even while blinking" bug
161   if (safe_timer.started() && this->get_group() != COLGROUP_MOVING_ONLY_STATIC) {
162     this->set_group(COLGROUP_MOVING_ONLY_STATIC);
163   }
164   else if (!safe_timer.started() && this->get_group() == COLGROUP_MOVING_ONLY_STATIC) {
165     this->set_group(COLGROUP_MOVING);
166   }
167
168   if(!controller->hold(Controller::ACTION) && grabbed_object) {
169     // move the grabbed object a bit away from tux
170     Vector pos = get_pos() + 
171         Vector(dir == LEFT ? -bbox.get_width()-1 : bbox.get_width()+1,
172                 bbox.get_height()*0.66666 - 32);
173     Rect dest(pos, pos + Vector(32, 32));
174     if(Sector::current()->is_free_space(dest)) {
175       MovingObject* moving_object = dynamic_cast<MovingObject*> (grabbed_object);
176       if(moving_object) {
177         moving_object->set_pos(pos);
178       } else {
179 #ifdef DEBUG
180         std::cout << "Non MovingObjetc grabbed?!?\n";
181 #endif
182       }
183       grabbed_object->ungrab(*this, dir);
184       grabbed_object = 0;
185     }
186   }
187
188   if(!dying && !deactivated)
189     handle_input();
190
191   movement = physic.get_movement(elapsed_time);
192   on_ground_flag = false;
193
194 #if 0
195   // special exception for cases where we're stuck under tiles after
196   // being ducked. In this case we drift out
197   if(!duck && on_ground() && old_base.x == base.x && old_base.y == base.y
198      && collision_object_map(base)) {
199     base.x += elapsed_time * WALK_SPEED * (dir ? 1: -1);
200     previous_base = old_base = base;
201   }
202 #endif
203
204   if(grabbed_object != 0) {
205     Vector pos = get_pos() + 
206       Vector(dir == LEFT ? -16 : 16,
207              bbox.get_height()*0.66666 - 32);
208     grabbed_object->grab(*this, pos, dir);
209   }
210 }
211
212 bool
213 Player::on_ground()
214 {
215   return on_ground_flag;
216 }
217
218 bool
219 Player::is_big()
220 {
221   if(player_status->bonus == NO_BONUS)
222     return false;
223
224   return true;
225 }
226
227 void
228 Player::handle_horizontal_input()
229 {
230   float vx = physic.get_velocity_x();
231   float vy = physic.get_velocity_y();
232   float ax = physic.get_acceleration_x();
233   float ay = physic.get_acceleration_y();
234
235   float dirsign = 0;
236   if(!duck || physic.get_velocity_y() != 0) {
237     if(controller->hold(Controller::LEFT) && !controller->hold(Controller::RIGHT)) {
238       old_dir = dir;
239       dir = LEFT;
240       dirsign = -1;
241     } else if(!controller->hold(Controller::LEFT)
242               && controller->hold(Controller::RIGHT)) {
243       old_dir = dir;
244       dir = RIGHT;
245       dirsign = 1;
246     }
247   }
248
249   if (!controller->hold(Controller::ACTION)) {
250     ax = dirsign * WALK_ACCELERATION_X;
251     // limit speed
252     if(vx >= MAX_WALK_XM && dirsign > 0) {
253       vx = MAX_WALK_XM;
254       ax = 0;
255     } else if(vx <= -MAX_WALK_XM && dirsign < 0) {
256       vx = -MAX_WALK_XM;
257       ax = 0;
258     }
259   } else {
260     ax = dirsign * RUN_ACCELERATION_X;
261     // limit speed
262     if(vx >= MAX_RUN_XM && dirsign > 0) {
263       vx = MAX_RUN_XM;
264       ax = 0;
265     } else if(vx <= -MAX_RUN_XM && dirsign < 0) {
266       vx = -MAX_RUN_XM;
267       ax = 0;
268     }
269   }
270
271   // we can reach WALK_SPEED without any acceleration
272   if(dirsign != 0 && fabs(vx) < WALK_SPEED) {
273     vx = dirsign * WALK_SPEED;
274   }
275
276   // changing directions?
277   if(on_ground() && ((vx < 0 && dirsign >0) || (vx>0 && dirsign<0))) {
278     // let's skid!
279     if(fabs(vx)>SKID_XM && !skidding_timer.started()) {
280       skidding_timer.start(SKID_TIME);
281       sound_manager->play("sounds/skid.wav");
282       // dust some particles
283       Sector::current()->add_object(
284         new Particles(
285           Vector(dir == RIGHT ? bbox.p2.x : bbox.p1.x, bbox.p2.y),
286           dir == RIGHT ? 270+20 : 90-40, dir == RIGHT ? 270+40 : 90-20,
287           Vector(280, -260), Vector(0, 300), 3, Color(.4, .4, .4), 3, .8,
288           LAYER_OBJECTS+1));
289       
290       ax *= 2.5;
291     } else {
292       ax *= 2;
293     }
294   }
295
296   // we get slower when not pressing any keys
297   if(dirsign == 0) {
298     if(fabs(vx) < WALK_SPEED) {
299       vx = 0;
300       ax = 0;
301     } else if(vx < 0) {
302       ax = WALK_ACCELERATION_X * 1.5;
303     } else {
304       ax = WALK_ACCELERATION_X * -1.5;
305     }
306   }
307
308 #if 0
309   // if we're on ice slow down acceleration or deceleration
310   if (isice(base.x, base.y + base.height))
311   {
312     /* the acceleration/deceleration rate on ice is inversely proportional to
313      * the current velocity.
314      */
315
316     // increasing 1 will increase acceleration/deceleration rate
317     // decreasing 1 will decrease acceleration/deceleration rate
318     //  must stay above zero, though
319     if (ax != 0) ax *= 1 / fabs(vx);
320   }
321 #endif
322
323   // extend/shrink tux collision rectangle so that we fall through/walk over 1
324   // tile holes
325   if(fabsf(vx) > MAX_WALK_XM) {
326     bbox.set_width(33);
327   } else {
328     bbox.set_width(31.8);
329   }
330
331   physic.set_velocity(vx, vy);
332   physic.set_acceleration(ax, ay);
333 }
334
335 void
336 Player::handle_vertical_input()
337 {
338   // set fall mode...
339   if(on_ground()) {
340     fall_mode = ON_GROUND;
341     last_ground_y = get_pos().y;
342   } else {
343     if(get_pos().y > last_ground_y)
344       fall_mode = FALLING;
345     else if(fall_mode == ON_GROUND)
346       fall_mode = JUMPING;
347   }
348
349   if(on_ground()) { /* Make sure jumping is off. */
350     jumping = false;
351     if (backflipping) {
352       backflipping = false;
353       backflip_direction = 0;
354     }
355   }
356
357   // Press jump key
358   if(controller->pressed(Controller::JUMP) && can_jump && on_ground()) {
359     if (duck) { 
360       if (physic.get_velocity_x() != 0) // only jump a little bit when running ducked
361         physic.set_velocity_y(300);
362       else { //do a backflip
363         backflipping = true;
364         physic.set_velocity_y(580);
365         backflip_timer.start(0.15);
366       }
367     }
368     else if (fabs(physic.get_velocity_x()) > MAX_WALK_XM) // jump higher if we are running
369       physic.set_velocity_y(580);
370     else
371       physic.set_velocity_y(520);
372     
373     //bbox.move(Vector(0, -1));
374     jumping = true;
375     can_jump = false;
376     if (is_big())
377       sound_manager->play("sounds/bigjump.wav");
378     else
379       sound_manager->play("sounds/jump.wav");
380   } else if(!controller->hold(Controller::JUMP)) { // Let go of jump key
381     if (!backflipping && jumping && physic.get_velocity_y() > 0) {
382       jumping = false;
383       physic.set_velocity_y(0);
384     }
385   }
386
387   /* In case the player has pressed Down while in a certain range of air,
388      enable butt jump action */
389   if (controller->hold(Controller::DOWN) && !butt_jump && !duck)
390     //if(tiles_on_air(TILES_FOR_BUTTJUMP) && jumping)
391     butt_jump = true;
392   
393   /* When Down is not held anymore, disable butt jump */
394   if(butt_jump && !controller->hold(Controller::DOWN))
395     butt_jump = false;
396   
397 #if 0
398   // Do butt jump
399   if (butt_jump && on_ground() && is_big()) {
400     // Add a smoke cloud
401     if (duck) 
402       Sector::current()->add_smoke_cloud(Vector(get_pos().x - 32, get_pos().y));
403     else 
404       Sector::current()->add_smoke_cloud(
405         Vector(get_pos().x - 32, get_pos().y + 32));
406     
407     butt_jump = false;
408     
409     // Break bricks beneath Tux
410     if(Sector::current()->trybreakbrick(
411          Vector(base.x + 1, base.y + base.height), false)
412        || Sector::current()->trybreakbrick(
413          Vector(base.x + base.width - 1, base.y + base.height), false)) {
414       physic.set_velocity_y(2);
415       butt_jump = true;
416     }
417     
418     // Kill nearby badguys
419     std::vector<GameObject*> gameobjects = Sector::current()->gameobjects;
420     for (std::vector<GameObject*>::iterator i = gameobjects.begin();
421          i != gameobjects.end();
422          i++) {
423       BadGuy* badguy = dynamic_cast<BadGuy*> (*i);
424       if(badguy) {
425         // don't kill when badguys are already dying or in a certain mode
426         if(badguy->dying == DYING_NOT && badguy->mode != BadGuy::BOMB_TICKING &&
427            badguy->mode != BadGuy::BOMB_EXPLODE) {
428           if (fabsf(base.x - badguy->base.x) < 96 &&
429               fabsf(base.y - badguy->base.y) < 64)
430             badguy->kill_me(25);
431         }
432       }
433     }
434   }
435 #endif
436
437   /** jumping is only allowed if we're about to touch ground soon and if the
438    * button has been up in between the last jump
439    */
440   // FIXME
441 #if 0
442   if ( (issolid(get_pos().x + bbox.get_width() / 2,
443           get_pos().y + bbox.get_height() + 64) ||
444         issolid(get_pos().x + 1, get_pos().y + bbox.get_height() + 64) ||
445         issolid(get_pos().x + bbox.get_width() - 1,
446           get_pos().y + bbox.get_height() + 64))
447        && jumping  == false
448        && can_jump == false
449        && input.jump && !input.old_jump)
450     {
451       can_jump = true;
452     }
453 #endif
454 }
455
456 void
457 Player::handle_input()
458 {
459   /* Handle horizontal movement: */
460   if (!backflipping) handle_horizontal_input();
461   else {
462     if (backflip_direction == 0) {
463       dir == LEFT ? backflip_direction = 1 : backflip_direction = -1;
464     }
465     else backflip_direction == 1 ? dir = LEFT : dir = RIGHT; //prevent player from changing direction when backflipping 
466     if (backflip_timer.check()) physic.set_velocity_x(100 * backflip_direction);
467   }
468
469
470   /* Jump/jumping? */
471   if (on_ground() && !controller->hold(Controller::JUMP))
472     can_jump = true;
473   handle_vertical_input();
474
475   /* Shoot! */
476   if (controller->pressed(Controller::ACTION) && player_status->bonus == FIRE_BONUS) {
477     if(Sector::current()->add_bullet(
478          get_pos() + ((dir == LEFT)? Vector(0, bbox.get_height()/2) 
479                       : Vector(32, bbox.get_height()/2)),
480          physic.get_velocity_x(), dir))
481       shooting_timer.start(SHOOTING_TIME);
482   }
483   
484   /* Duck! */
485   if (controller->hold(Controller::DOWN) && is_big() && !duck 
486       && physic.get_velocity_y() == 0 && on_ground()) {
487     duck = true;
488     bbox.move(Vector(0, 32));
489     bbox.set_height(31.8);
490   } else if(!controller->hold(Controller::DOWN) && is_big() && duck) {
491     // if we have some velocity left then check if there is space for
492     // unducking
493     bbox.move(Vector(0, -32));
494     bbox.set_height(63.8);
495     if(Sector::current()->is_free_space(bbox) || (
496         physic.get_velocity_x() > -.01 && physic.get_velocity_x() < .01
497         && physic.get_velocity_y() > -.01 && physic.get_velocity_y() < .01))
498     {
499       duck = false;
500     } else {
501       // undo the ducking changes
502       bbox.move(Vector(0, 32));
503       bbox.set_height(31.8); 
504     }
505   }
506 }
507
508 void
509 Player::set_bonus(BonusType type, bool animate)
510 {
511   if(player_status->bonus >= type)
512     return;
513   
514   if(player_status->bonus == NO_BONUS) {
515     bbox.set_height(63.8);
516     bbox.move(Vector(0, -32));
517     if(animate)
518       growing_timer.start(GROWING_TIME);
519   }
520   
521   player_status->bonus = type;
522 }
523
524 void
525 Player::kick()
526 {
527   kick_timer.start(KICK_TIME);
528 }
529
530 void
531 Player::draw(DrawingContext& context)
532 {
533   TuxBodyParts* tux_body;
534           
535   if (player_status->bonus == GROWUP_BONUS)
536     tux_body = big_tux;
537   else if (player_status->bonus == FIRE_BONUS)
538     tux_body = fire_tux;
539   else if (player_status->bonus == ICE_BONUS)
540     tux_body = ice_tux;
541   else
542     tux_body = small_tux;
543
544   int layer = LAYER_OBJECTS + 10;
545
546   /* Set Tux sprite action */
547   if (duck && is_big())
548     {
549     if(dir == LEFT)
550       tux_body->set_action("duck-left");
551     else // dir == RIGHT
552       tux_body->set_action("duck-right");
553     }
554   else if (skidding_timer.started() && !skidding_timer.check())
555     {
556     if(dir == LEFT)
557       tux_body->set_action("skid-left");
558     else // dir == RIGHT
559       tux_body->set_action("skid-right");
560     }
561   else if (kick_timer.started() && !kick_timer.check())
562     {
563     if(dir == LEFT)
564       tux_body->set_action("kick-left");
565     else // dir == RIGHT
566       tux_body->set_action("kick-right");
567     }
568   else if (butt_jump && is_big())
569     {
570     if(dir == LEFT)
571       tux_body->set_action("buttjump-left");
572     else // dir == RIGHT
573       tux_body->set_action("buttjump-right");
574     }
575   else if (physic.get_velocity_y() != 0)
576     {
577     if(dir == LEFT)
578       tux_body->set_action("jump-left");
579     else // dir == RIGHT
580       tux_body->set_action("jump-right");
581     }
582   else
583     {
584     if (fabsf(physic.get_velocity_x()) < 1.0f) // standing
585       {
586       if(dir == LEFT)
587         tux_body->set_action("stand-left");
588       else // dir == RIGHT
589         tux_body->set_action("stand-right");
590       }
591     else // moving
592       {
593       if(dir == LEFT)
594         tux_body->set_action("walk-left");
595       else // dir == RIGHT
596         tux_body->set_action("walk-right");
597       }
598     }
599
600   if(idle_timer.check())
601     {
602     if(is_big())
603       {
604       if(dir == LEFT)
605         tux_body->head->set_action("idle-left", 1);
606       else // dir == RIGHT
607         tux_body->head->set_action("idle-right", 1);
608       }
609
610     }
611
612   // Tux is holding something
613   if ((grabbed_object != 0 && physic.get_velocity_y() == 0) ||
614       (shooting_timer.get_timeleft() > 0 && !shooting_timer.check()))
615     {
616     if (duck)
617       {
618       if(dir == LEFT)
619         tux_body->arms->set_action("duck+grab-left");
620       else // dir == RIGHT
621         tux_body->arms->set_action("duck+grab-right");
622       }
623     else
624       {
625       if(dir == LEFT)
626         tux_body->arms->set_action("grab-left");
627       else // dir == RIGHT
628         tux_body->arms->set_action("grab-right");
629       }
630     }
631
632   /* Draw Tux */
633   if(dying) {
634     smalltux_gameover->draw(context, get_pos(), layer);
635   } else if(growing_timer.get_timeleft() > 0) {
636     if(!is_big())
637       {
638       if (dir == RIGHT)
639         context.draw_surface(growingtux_right[GROWING_FRAMES-1 - 
640                  int((growing_timer.get_timegone() *
641                  GROWING_FRAMES) / GROWING_TIME)], get_pos(), layer);
642       else
643         context.draw_surface(growingtux_left[GROWING_FRAMES-1 - 
644                 int((growing_timer.get_timegone() *
645                 GROWING_FRAMES) / GROWING_TIME)], get_pos(), layer);
646       }
647     else
648       {
649       if (dir == RIGHT)
650         context.draw_surface(growingtux_right[
651             int((growing_timer.get_timegone() *
652                 GROWING_FRAMES) / GROWING_TIME)], get_pos(), layer);
653       else
654         context.draw_surface(growingtux_left[
655             int((growing_timer.get_timegone() *
656                              GROWING_FRAMES) / GROWING_TIME)],
657             get_pos(), layer);
658       }
659     }
660   else if (safe_timer.started() && size_t(game_time*40)%2)
661     ;  // don't draw Tux
662   else
663     tux_body->draw(context, get_pos(), layer);
664
665   // Draw blinking star overlay
666   if (invincible_timer.started() &&
667      (invincible_timer.get_timeleft() > TUX_INVINCIBLE_TIME_WARNING
668       || size_t(game_time*20)%2)
669      && !dying)
670   {
671     if (!is_big() || duck)
672       smalltux_star->draw(context, get_pos(), layer + 5);
673     else
674       bigtux_star->draw(context, get_pos(), layer + 5);
675   } 
676 }
677
678 void
679 Player::collision_tile(uint32_t tile_attributes)
680 {
681   if(tile_attributes & Tile::HURTS)
682     kill(SHRINK);
683 }
684
685 HitResponse
686 Player::collision(GameObject& other, const CollisionHit& hit)
687 {
688   Bullet* bullet = dynamic_cast<Bullet*> (&other);
689   if(bullet) {
690     return FORCE_MOVE;
691   }
692
693   if(other.get_flags() & FLAG_PORTABLE) {
694     Portable* portable = dynamic_cast<Portable*> (&other);
695     if(portable && grabbed_object == 0 && controller->hold(Controller::ACTION)
696         && fabsf(hit.normal.x) > .9) {
697       grabbed_object = portable;
698       return CONTINUE;
699     }
700   }
701  
702   if(other.get_flags() & FLAG_SOLID) {
703     if(hit.normal.y < 0) { // landed on floor?
704       if(physic.get_velocity_y() < 0)
705         physic.set_velocity_y(0);
706       on_ground_flag = true;
707     } else if(hit.normal.y > 0) { // bumped against the roof
708       physic.set_velocity_y(.1);
709     }
710     
711     if(fabsf(hit.normal.x) > .9) { // hit on the side?
712       physic.set_velocity_x(0);
713     }
714
715     return CONTINUE;
716   }
717
718   TriggerBase* trigger = dynamic_cast<TriggerBase*> (&other);
719   if(trigger) {
720     if(controller->pressed(Controller::UP))
721       trigger->event(*this, TriggerBase::EVENT_ACTIVATE);
722
723     return FORCE_MOVE;
724   }
725
726   BadGuy* badguy = dynamic_cast<BadGuy*> (&other);
727   if(badguy != NULL)
728     return CONTINUE;
729
730 #if 0
731   MovingObject* moving_object = static_cast<MovingObject*> (&other);
732   if(moving_object->get_group() == COLGROUP_TOUCHABLE)
733     return FORCE_MOVE;
734
735   if(is_invincible())
736     return FORCE_MOVE;
737
738   return CONTINUE;
739 #endif
740   return FORCE_MOVE;
741 }
742
743 void
744 Player::make_invincible()
745 {
746   sound_manager->play("sounds/invincible.wav");
747   invincible_timer.start(TUX_INVINCIBLE_TIME);
748   Sector::current()->play_music(HERRING_MUSIC);               
749 }
750
751 /* Kill Player! */
752 void
753 Player::kill(HurtMode mode)
754 {
755   if(dying || deactivated)
756     return;
757
758   if(mode != KILL && 
759           (safe_timer.get_timeleft() > 0 || invincible_timer.get_timeleft() > 0))
760     return;                          
761   
762   sound_manager->play("sounds/hurt.wav");
763
764   physic.set_velocity_x(0);
765
766   if (mode == SHRINK && is_big())
767     {
768       if (player_status->bonus == FIRE_BONUS
769           || player_status->bonus == ICE_BONUS)
770         {
771           safe_timer.start(TUX_SAFE_TIME);
772           player_status->bonus = GROWUP_BONUS;
773         }
774       else 
775         {
776           growing_timer.start(GROWING_TIME);
777           safe_timer.start(TUX_SAFE_TIME + GROWING_TIME);
778           bbox.set_height(31.8);
779           duck = false;
780           player_status->bonus = NO_BONUS;
781         }
782     }
783   else
784     {
785       physic.enable_gravity(true);
786       physic.set_acceleration(0, 0);
787       physic.set_velocity(0, 700);
788       player_status->lives -= 1;
789       player_status->bonus = NO_BONUS;
790       dying = true;
791       dying_timer.start(3.0);
792       set_group(COLGROUP_DISABLED);
793
794       DisplayEffect* effect = new DisplayEffect();
795       effect->fade_out(3.0);
796       Sector::current()->add_object(effect);
797       sound_manager->stop_music(3.0);
798     }
799 }
800
801 void
802 Player::move(const Vector& vector)
803 {
804   bbox.set_pos(vector);
805   if(is_big())
806     bbox.set_size(31.8, 63.8);
807   else
808     bbox.set_size(31.8, 31.8);
809   on_ground_flag = false;
810   duck = false;
811   last_ground_y = vector.y;
812
813   physic.reset();
814 }
815
816 void
817 Player::check_bounds(Camera* camera)
818 {
819   /* Keep tux in bounds: */
820   if (get_pos().x < 0)
821     { // Lock Tux to the size of the level, so that he doesn't fall of
822       // on the left side
823       bbox.set_pos(Vector(0, get_pos().y));
824     }
825
826   /* Keep in-bounds, vertically: */
827   if (get_pos().y > Sector::current()->solids->get_height() * 32)
828     {
829       kill(KILL);
830       return;
831     }
832
833   bool adjust = false;
834   // can happen if back scrolling is disabled
835   if(get_pos().x < camera->get_translation().x) {
836     bbox.set_pos(Vector(camera->get_translation().x, get_pos().y));
837     adjust = true;
838   }
839   if(get_pos().x >= camera->get_translation().x + SCREEN_WIDTH - bbox.get_width())
840   {
841     bbox.set_pos(Vector(
842           camera->get_translation().x + SCREEN_WIDTH - bbox.get_width(),
843           get_pos().y));
844     adjust = true;
845   }
846
847   if(adjust) {
848     // FIXME
849 #if 0
850     // squished now?
851     if(collision_object_map(bbox)) {
852       kill(KILL);
853       return;
854     }
855 #endif
856   }
857 }
858
859 void
860 Player::bounce(BadGuy& )
861 {
862   if(controller->hold(Controller::JUMP))
863     physic.set_velocity_y(520);
864   else
865     physic.set_velocity_y(300);
866 }
867
868 //Scripting Functions Below
869
870 void
871 Player::deactivate()
872 {
873   deactivated = true;
874   physic.set_velocity_x(0);
875   physic.set_velocity_y(0);
876 }
877
878 void
879 Player::activate()
880 {
881   deactivated = false;
882 }
883
884 void Player::walk(float speed)
885 {
886   physic.set_velocity_x(speed);
887 }