added jam build system, please try it out - the advantage would be that it already...
[supertux.git] / src / 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 "app/globals.h"
27 #include "app/gettext.h"
28 #include "player.h"
29 #include "defines.h"
30 #include "scene.h"
31 #include "tile.h"
32 #include "special/sprite.h"
33 #include "sector.h"
34 #include "tilemap.h"
35 #include "camera.h"
36 #include "gameobjs.h"
37 #include "resources.h"
38 #include "video/screen.h"
39 #include "statistics.h"
40 #include "gameloop.h"
41 #include "trigger/trigger_base.h"
42
43 // behavior definitions:
44 #define TILES_FOR_BUTTJUMP 3
45 // animation times (in ms):
46 #define SHOOTING_TIME .150
47
48 // time before idle animation starts
49 #define IDLE_TIME 2.500
50
51 // growing animation
52 Surface* growingtux_left[GROWING_FRAMES];
53 Surface* growingtux_right[GROWING_FRAMES];
54
55 Surface* tux_life = 0;
56
57 Sprite* smalltux_gameover = 0;
58 Sprite* smalltux_star = 0;
59 Sprite* bigtux_star = 0;
60
61 TuxBodyParts* small_tux = 0;
62 TuxBodyParts* big_tux = 0;
63 TuxBodyParts* fire_tux = 0;
64 TuxBodyParts* ice_tux = 0;
65
66 PlayerKeymap keymap;
67
68 PlayerKeymap::PlayerKeymap()
69 {
70   keymap.up    = SDLK_UP;
71   keymap.down  = SDLK_DOWN;
72   keymap.left  = SDLK_LEFT;
73   keymap.right = SDLK_RIGHT;
74
75   keymap.power = SDLK_LCTRL;
76   keymap.jump  = SDLK_LALT;
77 }
78
79 void player_input_init(player_input_type* pplayer_input)
80 {
81   pplayer_input->up = UP;
82   pplayer_input->old_up = UP;
83   pplayer_input->down = UP;
84   pplayer_input->fire = UP;
85   pplayer_input->left = UP;
86   pplayer_input->old_fire = UP;
87   pplayer_input->right = UP;
88   pplayer_input->jump = UP;
89   pplayer_input->old_jump = UP;
90   pplayer_input->activate = UP;
91 }
92
93 void
94 TuxBodyParts::set_action(std::string action)
95 {
96   if(head != NULL)
97     head->set_action(action);
98   if(body != NULL)
99     body->set_action(action);
100   if(arms != NULL)
101     arms->set_action(action);
102   if(feet != NULL)
103     feet->set_action(action);
104 }
105
106 void
107 TuxBodyParts::one_time_animation()
108 {
109   if(head != NULL)
110     head->start_animation(1);
111   if(body != NULL)
112     body->start_animation(1);
113   if(arms != NULL)
114     arms->start_animation(1);
115   if(feet != NULL)
116     feet->start_animation(1);
117 }
118
119 void
120 TuxBodyParts::draw(DrawingContext& context, const Vector& pos, int layer,
121                   Uint32 drawing_effect)
122 {
123   if(head != NULL)
124     head->draw(context, pos, layer-1, drawing_effect);
125   if(body != NULL)
126     body->draw(context, pos, layer-3, drawing_effect);
127   if(arms != NULL)
128     arms->draw(context, pos, layer,   drawing_effect);
129   if(feet != NULL)
130     feet->draw(context, pos, layer-2, drawing_effect);
131 }
132
133 Player::Player()
134 {
135   init();
136 }
137
138 Player::~Player()
139 {
140 }
141
142 void
143 Player::init()
144 {
145   holding_something = false;
146
147   bbox.set_size(32, 32);
148
149   size = SMALL;
150   got_power = NONE_POWER;
151
152   dir = RIGHT;
153   old_dir = dir;
154   duck = false;
155   dead = false;
156
157   dying   = DYING_NOT;
158   last_ground_y = 0;
159   fall_mode = ON_GROUND;
160   jumping = false;
161   flapping = false;
162   can_jump = true;
163   can_flap = false;
164   falling_from_flap = false;
165   enable_hover = false;
166   butt_jump = false;
167   
168   flapping_velocity = 0;
169
170   // temporary to help player's choosing a flapping
171   flapping_mode = MAREK_FLAP;
172
173   // Ricardo's flapping
174   flaps_nb = 0;
175
176   on_ground_flag = false;
177
178   player_input_init(&input);
179
180   physic.reset();
181 }
182
183 int
184 Player::key_event(SDLKey key, int state)
185 {
186   idle_timer.start(IDLE_TIME, true);
187
188   if(key == keymap.right)
189     {
190       input.right = state;
191       return true;
192     }
193   else if(key == keymap.left)
194     {
195       input.left = state;
196       return true;
197     }
198   else if(key == keymap.up)
199     {
200       if(state == UP)
201         input.old_up = UP;
202       input.up = state;
203       /* Up key also opens activates stuff */
204       input.activate = state;
205       return true;
206     }
207   else if(key == keymap.down)
208     {
209       input.down = state;
210       return true;
211     }
212   else if(key == keymap.power)
213     {
214       if (state == UP)
215         input.old_fire = UP;
216       input.fire = state;
217
218       return true;
219     }
220   else if(key == keymap.jump)
221     {
222       if (state == UP)
223         input.old_jump = UP;
224       input.jump = state;
225       return true;
226     }
227   else
228     return false;
229 }
230
231 void
232 Player::level_begin()
233 {
234   move(Vector(100, 170));
235   duck = false;
236
237   dying = DYING_NOT;
238
239   player_input_init(&input);
240
241   on_ground_flag = false;
242
243   physic.reset();
244 }
245
246 PlayerStatus&
247 Player::get_status()
248 {
249   return player_status;
250 }
251
252 void
253 Player::action(float elapsed_time)
254 {
255   if(dying && dying_timer.check()) {
256     dead = true;
257     return;
258   }
259
260   if (input.fire == UP)
261     holding_something = false;
262
263   if(dying == DYING_NOT)
264     handle_input();
265
266   movement = physic.get_movement(elapsed_time);
267
268 #if 0
269       // special exception for cases where we're stuck under tiles after
270       // being ducked. In this case we drift out
271       if(!duck && on_ground() && old_base.x == base.x && old_base.y == base.y
272          && collision_object_map(base))
273         {
274           base.x += elapsed_time * WALK_SPEED * (dir ? 1: -1);
275           previous_base = old_base = base;
276         }
277
278       /* Reset score multiplier (for multi-hits): */
279       if (!invincible_timer.started())
280             {
281             if(player_status.score_multiplier > player_status.max_score_multiplier)
282               {
283               player_status.max_score_multiplier = player_status.score_multiplier;
284
285               // show a message
286               char str[124];
287               sprintf(str, _("New max combo: %d"), player_status.max_score_multiplier-1);
288               Sector::current()->add_floating_text(base, str);
289               }
290             player_status.score_multiplier = 1;
291             }
292         }
293
294     }
295 #endif
296
297   on_ground_flag = false;
298 }
299
300 bool
301 Player::on_ground()
302 {
303   return on_ground_flag;
304 }
305
306 void
307 Player::handle_horizontal_input()
308 {
309   float vx = physic.get_velocity_x();
310   float vy = physic.get_velocity_y();
311   float ax = physic.get_acceleration_x();
312   float ay = physic.get_acceleration_y();
313
314   float dirsign = 0;
315   if(input.left == DOWN && input.right == UP && (!duck || physic.get_velocity_y() != 0)) {
316       old_dir = dir;
317       dir = LEFT;
318       dirsign = -1;
319   } else if(input.left == UP && input.right == DOWN && (!duck || physic.get_velocity_y() != 0)) {
320       old_dir = dir;
321       dir = RIGHT;
322       dirsign = 1;
323   }
324
325   if (input.fire == UP) {
326       ax = dirsign * WALK_ACCELERATION_X;
327       // limit speed
328       if(vx >= MAX_WALK_XM && dirsign > 0) {
329         vx = MAX_WALK_XM;
330         ax = 0;
331       } else if(vx <= -MAX_WALK_XM && dirsign < 0) {
332         vx = -MAX_WALK_XM;
333         ax = 0;
334       }
335   } else {
336       ax = dirsign * RUN_ACCELERATION_X;
337       // limit speed
338       if(vx >= MAX_RUN_XM && dirsign > 0) {
339         vx = MAX_RUN_XM;
340         ax = 0;
341       } else if(vx <= -MAX_RUN_XM && dirsign < 0) {
342         vx = -MAX_RUN_XM;
343         ax = 0;
344       }
345   }
346
347   // we can reach WALK_SPEED without any acceleration
348   if(dirsign != 0 && fabs(vx) < WALK_SPEED) {
349     vx = dirsign * WALK_SPEED;
350   }
351
352   // changing directions?
353   if(on_ground() && ((vx < 0 && dirsign >0) || (vx>0 && dirsign<0)))
354     {
355       // let's skid!
356       if(fabs(vx)>SKID_XM && !skidding_timer.started())
357         {
358           skidding_timer.start(SKID_TIME);
359           SoundManager::get()->play_sound(IDToSound(SND_SKID));
360           // dust some partcles
361           Sector::current()->add_object(
362               new Particles(
363                 Vector(bbox.p1.x + (dir == RIGHT ? bbox.get_width() : 0),
364                 bbox.p2.y),
365               dir == RIGHT ? 270+20 : 90-40, dir == RIGHT ? 270+40 : 90-20,
366               Vector(280,-260), Vector(0,0.030), 3, Color(100,100,100), 3, .8,
367               LAYER_OBJECTS+1));
368
369           ax *= 2.5;
370         }
371       else
372         {
373           ax *= 2;
374         }
375     }
376
377   // we get slower when not pressing any keys
378   if(dirsign == 0) {
379       if(fabs(vx) < WALK_SPEED) {
380           vx = 0;
381           ax = 0;
382       } else if(vx < 0) {
383           ax = WALK_ACCELERATION_X * 1.5;
384       } else {
385           ax = WALK_ACCELERATION_X * -1.5;
386       }
387   }
388
389 #if 0
390   // if we're on ice slow down acceleration or deceleration
391   if (isice(base.x, base.y + base.height))
392   {
393     /* the acceleration/deceleration rate on ice is inversely proportional to
394      * the current velocity.
395      */
396
397     // increasing 1 will increase acceleration/deceleration rate
398     // decreasing 1 will decrease acceleration/deceleration rate
399     //  must stay above zero, though
400     if (ax != 0) ax *= 1 / fabs(vx);
401   }
402 #endif
403
404   physic.set_velocity(vx, vy);
405   physic.set_acceleration(ax, ay);
406 }
407
408 void
409 Player::handle_vertical_input()
410 {
411   // set fall mode...
412   if(on_ground()) {
413     fall_mode = ON_GROUND;
414     last_ground_y = get_pos().y;
415   } else {
416     if(get_pos().y > last_ground_y)
417       fall_mode = FALLING;
418     else if(fall_mode == ON_GROUND)
419       fall_mode = JUMPING;
420   }
421
422   if(on_ground()) { /* Make sure jumping is off. */
423     jumping = false;
424     flapping = false;
425     falling_from_flap = false;
426     if (flapping_timer.started()) {
427       flapping_timer.start(0);
428     }
429
430     physic.set_acceleration_y(0); //for flapping
431   }
432
433   // Press jump key
434   if(input.jump == DOWN && can_jump && on_ground())
435     {
436       if(duck) { // only jump a little bit when in duck mode {
437         physic.set_velocity_y(300);
438       } else {
439         // jump higher if we are running
440         if (fabs(physic.get_velocity_x()) > MAX_WALK_XM)
441           physic.set_velocity_y(580);
442         else
443           physic.set_velocity_y(520);
444       }
445
446       //bbox.move(Vector(0, -1));
447       jumping = true;
448       flapping = false;
449       can_jump = false;
450       can_flap = false;
451       flaps_nb = 0; // Ricardo's flapping
452       if (size == SMALL)
453         SoundManager::get()->play_sound(IDToSound(SND_JUMP));
454       else
455         SoundManager::get()->play_sound(IDToSound(SND_BIGJUMP));
456     }
457   // Let go of jump key
458   else if(input.jump == UP)
459     {
460       if (!flapping && !duck && !falling_from_flap && !on_ground())
461          {
462             can_flap = true;
463          }
464       if (jumping && physic.get_velocity_y() > 0)
465          {
466             jumping = false;
467             physic.set_velocity_y(0);
468          }
469     }
470
471  // temporary to help player's choosing a flapping
472  if(flapping_mode == RICARDO_FLAP)
473    {
474    // Flapping, Ricardo's version
475    // similar to SM3 Fox
476    if(input.jump == DOWN && input.old_jump == UP && can_flap &&
477      flaps_nb < 3)
478      {
479        physic.set_velocity_y(350);
480        physic.set_velocity_x(physic.get_velocity_x() * 35);
481        flaps_nb++;
482      }
483    }
484   else if(flapping_mode == MAREK_FLAP)
485    {
486    // Flapping, Marek's version
487    if (input.jump == DOWN && can_flap)
488      {
489          if (!flapping_timer.started())
490             {
491                flapping_timer.start(TUX_FLAPPING_TIME);
492                flapping_velocity = physic.get_velocity_x();
493             }
494          if (flapping_timer.check()) 
495             {
496                can_flap = false;
497                falling_from_flap = true;
498             }
499          jumping = true;
500          flapping = true;
501          if (!flapping_timer.check()) {
502            float cv = flapping_velocity * sqrt(
503                TUX_FLAPPING_TIME - flapping_timer.get_timegone() 
504                / TUX_FLAPPING_TIME);
505
506            //Handle change of direction while flapping
507            if (((dir == LEFT) && (cv > 0)) || (dir == RIGHT) && (cv < 0)) {
508              cv *= (-1);
509            }
510            physic.set_velocity_x(cv);
511            physic.set_velocity_y(
512                flapping_timer.get_timegone()/.850);
513          }
514      }
515    }
516   else if(flapping_mode == RYAN_FLAP)
517    {
518    // Flapping, Ryan's version
519    if (input.jump == DOWN && can_flap)
520      {
521          if (!flapping_timer.started())
522             {
523                flapping_timer.start(TUX_FLAPPING_TIME);
524             }
525          if (flapping_timer.check()) 
526             {
527                can_flap = false;
528                falling_from_flap = true;
529             }
530          jumping = true;
531          flapping = true;
532          if (flapping && flapping_timer.get_timegone() <= TUX_FLAPPING_TIME
533                 && physic.get_velocity_y() < 0)
534             {
535                float gravity = Sector::current()->gravity;
536                (void)gravity;
537                float xr = (fabsf(physic.get_velocity_x()) / MAX_RUN_XM);
538
539                // XXX: magic numbers. should be a percent of gravity
540                //      gravity is (by default) -0.1f
541                physic.set_acceleration_y(12 + 1*xr);
542
543 #if 0
544                // To slow down x-vel when flapping (not working)
545                if (fabsf(physic.get_velocity_x()) > MAX_WALK_XM)
546                {
547                    if (physic.get_velocity_x() < 0)
548                        physic.set_acceleration_x(1.0f);
549                    else if (physic.get_velocity_x() > 0)
550                        physic.set_acceleration_x(-1.0f);
551                }
552 #endif
553             }
554      }
555     else
556      {
557         physic.set_acceleration_y(0);
558      }
559    }
560
561    // Hover
562    //(disabled by default, use cheat code "hover" to toggle on/off)
563    //TODO: needs some tweaking, especially when used together with double jump and jumping off badguys
564    if (enable_hover && input.jump == DOWN && !jumping && !butt_jump && physic.get_velocity_y() <= 0)
565       {
566          physic.set_velocity_y(-100);
567       }
568
569 #if 0
570    /* In case the player has pressed Down while in a certain range of air,
571       enable butt jump action */
572   if (input.down == DOWN && !butt_jump && !duck)
573     if(tiles_on_air(TILES_FOR_BUTTJUMP) && jumping)
574       butt_jump = true;
575 #endif
576
577    /* When Down is not held anymore, disable butt jump */
578   if(butt_jump && input.down == UP)
579     butt_jump = false;
580
581   // Do butt jump
582   if (butt_jump && on_ground() && size == BIG)
583   {
584     // Add a smoke cloud
585     if (duck) 
586       Sector::current()->add_smoke_cloud(Vector(get_pos().x - 32, get_pos().y));
587     else 
588       Sector::current()->add_smoke_cloud(
589           Vector(get_pos().x - 32, get_pos().y + 32));
590     
591     butt_jump = false;
592
593 #if 0
594     // Break bricks beneath Tux
595     if(Sector::current()->trybreakbrick(
596           Vector(base.x + 1, base.y + base.height), false)
597         || Sector::current()->trybreakbrick(
598            Vector(base.x + base.width - 1, base.y + base.height), false))
599     {
600       physic.set_velocity_y(2);
601       butt_jump = true;
602     }
603 #endif
604
605 #if 0
606     // Kill nearby badguys
607     std::vector<GameObject*> gameobjects = Sector::current()->gameobjects;
608     for (std::vector<GameObject*>::iterator i = gameobjects.begin();
609          i != gameobjects.end();
610          i++)
611     {
612       BadGuy* badguy = dynamic_cast<BadGuy*> (*i);
613       if(badguy)
614       {
615         // don't kill when badguys are already dying or in a certain mode
616         if(badguy->dying == DYING_NOT && badguy->mode != BadGuy::BOMB_TICKING &&
617            badguy->mode != BadGuy::BOMB_EXPLODE)
618           {
619             if (fabsf(base.x - badguy->base.x) < 96 &&
620                 fabsf(base.y - badguy->base.y) < 64)
621               badguy->kill_me(25);
622           }
623       }
624     }
625 #endif
626   }
627
628   /** jumping is only allowed if we're about to touch ground soon and if the
629    * button has been up in between the last jump
630    */
631   // FIXME
632 #if 0
633   if ( (issolid(get_pos().x + bbox.get_width() / 2,
634           get_pos().y + bbox.get_height() + 64) ||
635         issolid(get_pos().x + 1, get_pos().y + bbox.get_height() + 64) ||
636         issolid(get_pos().x + bbox.get_width() - 1,
637           get_pos().y + bbox.get_height() + 64))
638        && jumping  == false
639        && can_jump == false
640        && input.jump == DOWN
641        && input.old_jump == UP)
642     {
643       can_jump = true;
644     }
645 #endif
646
647   input.old_jump = input.jump;
648 }
649
650 void
651 Player::handle_input()
652 {
653   /* Handle horizontal movement: */
654   handle_horizontal_input();
655
656   /* Jump/jumping? */
657   if (on_ground() && input.jump == UP)
658     can_jump = true;
659   handle_vertical_input();
660
661   /* Shoot! */
662   if (input.fire == DOWN && input.old_fire == UP && got_power != NONE_POWER) {
663     if(Sector::current()->add_bullet(
664           get_pos() + Vector(0, bbox.get_height()/2),
665           physic.get_velocity_x(), dir))
666       shooting_timer.start(SHOOTING_TIME);
667     input.old_fire = DOWN;
668   }
669
670   /* Duck! */
671   if (input.down == DOWN && size == BIG && !duck 
672       && physic.get_velocity_y() == 0 && on_ground())
673     {
674       duck = true;
675       bbox.move(Vector(0, 32));
676       bbox.set_height(32);
677     }
678   else if(input.down == UP && size == BIG && duck)
679     {
680       // try if we can really unduck
681       bbox.move(Vector(0, -32));
682       bbox.set_height(64);
683       duck = false;
684       // FIXME
685 #if 0
686       // when unducking in air we need some space to do so
687       if(on_ground() || !collision_object_map(bbox)) {
688         duck = false;
689       } else {
690         // undo the ducking changes
691         bbox.move(Vector(0, 32));
692         bbox.set_height(32);
693       }
694 #endif
695     }
696 }
697
698 void
699 Player::grow(bool animate)
700 {
701   if(size == BIG)
702     return;
703   
704   size = BIG;
705   bbox.set_height(64);
706   bbox.move(Vector(0, -32));
707
708   if(animate)
709     growing_timer.start(GROWING_TIME);
710 }
711
712 void
713 Player::grabdistros()
714 {
715 }
716
717 void
718 Player::draw(DrawingContext& context)
719 {
720   TuxBodyParts* tux_body;
721           
722   if (size == SMALL)
723     tux_body = small_tux;
724   else if (got_power == FIRE_POWER)
725     tux_body = fire_tux;
726   else if (got_power == ICE_POWER)
727     tux_body = ice_tux;
728   else
729     tux_body = big_tux;
730
731   int layer = LAYER_OBJECTS - 1;
732
733   /* Set Tux sprite action */
734   if (duck && size == BIG)
735     {
736     if(dir == LEFT)
737       tux_body->set_action("duck-left");
738     else // dir == RIGHT
739       tux_body->set_action("duck-right");
740     }
741   else if (skidding_timer.started() && !skidding_timer.check())
742     {
743     if(dir == LEFT)
744       tux_body->set_action("skid-left");
745     else // dir == RIGHT
746       tux_body->set_action("skid-right");
747     }
748   else if (kick_timer.started() && !kick_timer.check())
749     {
750     if(dir == LEFT)
751       tux_body->set_action("kick-left");
752     else // dir == RIGHT
753       tux_body->set_action("kick-right");
754     }
755   else if (butt_jump && size == BIG)
756     {
757     if(dir == LEFT)
758       tux_body->set_action("buttjump-left");
759     else // dir == RIGHT
760       tux_body->set_action("buttjump-right");
761     }
762   else if (physic.get_velocity_y() != 0)
763     {
764     if(dir == LEFT)
765       tux_body->set_action("jump-left");
766     else // dir == RIGHT
767       tux_body->set_action("jump-right");
768     }
769   else
770     {
771     if (fabsf(physic.get_velocity_x()) < 1.0f) // standing
772       {
773       if(dir == LEFT)
774         tux_body->set_action("stand-left");
775       else // dir == RIGHT
776         tux_body->set_action("stand-right");
777       }
778     else // moving
779       {
780       if(dir == LEFT)
781         tux_body->set_action("walk-left");
782       else // dir == RIGHT
783         tux_body->set_action("walk-right");
784       }
785     }
786
787   if(idle_timer.check())
788     {
789     if(size == BIG)
790       {
791       if(dir == LEFT)
792         tux_body->head->set_action("idle-left");
793       else // dir == RIGHT
794         tux_body->head->set_action("idle-right");
795
796       tux_body->head->start_animation(1);
797       }
798
799     }
800
801   // Tux is holding something
802   if ((holding_something && physic.get_velocity_y() == 0) ||
803       (shooting_timer.get_timeleft() > 0 && !shooting_timer.check()))
804     {
805     if (duck)
806       {
807       if(dir == LEFT)
808         tux_body->arms->set_action("duck+grab-left");
809       else // dir == RIGHT
810         tux_body->arms->set_action("duck+grab-right");
811       }
812     else
813       {
814       if(dir == LEFT)
815         tux_body->arms->set_action("grab-left");
816       else // dir == RIGHT
817         tux_body->arms->set_action("grab-right");
818       }
819     }
820
821   /* Draw Tux */
822   if (dying == DYING_SQUISHED) {
823     smalltux_gameover->draw(context, get_pos(), LAYER_FOREGROUNDTILES+1);
824   } else if(growing_timer.get_timeleft() > 0) {
825     if(size == SMALL)
826       {
827       if (dir == RIGHT)
828         context.draw_surface(growingtux_right[GROWING_FRAMES-1 - 
829                  int((growing_timer.get_timegone() *
830                  GROWING_FRAMES) / GROWING_TIME)], get_pos(), layer);
831       else
832         context.draw_surface(growingtux_left[GROWING_FRAMES-1 - 
833                 int((growing_timer.get_timegone() *
834                 GROWING_FRAMES) / GROWING_TIME)], get_pos(), layer);
835       }
836     else
837       {
838       if (dir == RIGHT)
839         context.draw_surface(growingtux_right[
840             int((growing_timer.get_timegone() *
841                 GROWING_FRAMES) / GROWING_TIME)], get_pos(), layer);
842       else
843         context.draw_surface(growingtux_left[
844             int((growing_timer.get_timegone() *
845                              GROWING_FRAMES) / GROWING_TIME)],
846             get_pos(), layer);
847       }
848     }
849   else if (safe_timer.started() && size_t(global_time*40)%2)
850     ;  // don't draw Tux
851   else
852     tux_body->draw(context, get_pos(), layer);
853
854   // Draw blinking star overlay
855   if (invincible_timer.started() &&
856      (invincible_timer.get_timeleft() > TUX_INVINCIBLE_TIME_WARNING
857       || size_t(global_time*20)%2)
858      && !dying)
859   {
860     if (size == SMALL || duck)
861       smalltux_star->draw(context, get_pos(), LAYER_OBJECTS + 2);
862     else
863       bigtux_star->draw(context, get_pos(), LAYER_OBJECTS + 2);
864   }
865  
866   if (debug_mode)
867     context.draw_filled_rect(get_pos(),
868         Vector(bbox.get_width(), bbox.get_height()),
869         Color(75,75,75, 150), LAYER_OBJECTS+1);
870 }
871
872 HitResponse
873 Player::collision(GameObject& other, const CollisionHit& hit)
874 {
875   if(dying) {
876     return FORCE_MOVE;
877   }
878
879   if(other.get_flags() & FLAG_SOLID) {
880     if(hit.normal.y < 0) { // landed on floor?
881       if (physic.get_velocity_y() < 0)
882         physic.set_velocity_y(0);
883       on_ground_flag = true;
884     } else if(hit.normal.y > 0) { // bumped against the roof
885       physic.set_velocity_y(0);
886     }
887     
888     if(hit.normal.x != 0) { // hit on the side?
889       if(hit.normal.y > 0.6) // limits the slopes we can move up...
890         physic.set_velocity_x(0);
891     }
892
893     return CONTINUE;
894   }
895
896   TriggerBase* trigger = dynamic_cast<TriggerBase*> (&other);
897   if(trigger) {
898     if(input.up == DOWN && input.old_up == UP)
899       trigger->event(*this, TriggerBase::EVENT_ACTIVATE);
900   }
901
902   return FORCE_MOVE;
903 }
904
905 void
906 Player::make_invincible()
907 {
908   SoundManager::get()->play_sound(IDToSound(SND_HERRING));
909   invincible_timer.start(TUX_INVINCIBLE_TIME);
910   Sector::current()->play_music(HERRING_MUSIC);               
911 }
912
913 /* Kill Player! */
914 void
915 Player::kill(HurtMode mode)
916 {
917   if(dying)
918     return;
919
920   if(safe_timer.get_timeleft() > 0 || invincible_timer.get_timeleft() > 0)
921     return;                          
922   
923   SoundManager::get()->play_sound(IDToSound(SND_HURT));
924
925   physic.set_velocity_x(0);
926
927   if (mode == SHRINK && size == BIG)
928     {
929       if (got_power != NONE_POWER)
930         {
931           safe_timer.start(TUX_SAFE_TIME);
932           got_power = NONE_POWER;
933         }
934       else
935         {
936           growing_timer.start(GROWING_TIME);
937           safe_timer.start(TUX_SAFE_TIME + GROWING_TIME);
938           size = SMALL;
939           bbox.set_height(32);
940           duck = false;
941         }
942     }
943   else
944     {
945       physic.enable_gravity(true);
946       physic.set_acceleration(0, 0);
947       physic.set_velocity(0, 700);
948       --player_status.lives;
949       dying = DYING_SQUISHED;
950       dying_timer.start(3.0);
951     }
952 }
953
954 /* Remove Tux's power ups */
955 void
956 Player::remove_powerups()
957 {
958   got_power = NONE_POWER;
959   size = SMALL;
960   bbox.set_height(32);
961 }
962
963 void
964 Player::move(const Vector& vector)
965 {
966   bbox.set_pos(vector);
967 }
968
969 void
970 Player::check_bounds(Camera* camera)
971 {
972   /* Keep tux in bounds: */
973   if (get_pos().x < 0)
974     { // Lock Tux to the size of the level, so that he doesn't fall of
975       // on the left side
976       bbox.set_pos(Vector(0, get_pos().y));
977     }
978
979   /* Keep in-bounds, vertically: */
980   if (get_pos().y > Sector::current()->solids->get_height() * 32)
981     {
982       kill(KILL);
983       return;
984     }
985
986   bool adjust = false;
987   // can happen if back scrolling is disabled
988   if(get_pos().x < camera->get_translation().x) {
989     bbox.set_pos(Vector(camera->get_translation().x, get_pos().y));
990     adjust = true;
991   }
992   if(get_pos().x >= camera->get_translation().x + screen->w - bbox.get_width())
993   {
994     bbox.set_pos(Vector(
995           camera->get_translation().x + screen->w - bbox.get_width(),
996           get_pos().y));
997     adjust = true;
998   }
999
1000   if(adjust) {
1001     // FIXME
1002 #if 0
1003     // squished now?
1004     if(collision_object_map(bbox)) {
1005       kill(KILL);
1006       return;
1007     }
1008 #endif
1009   }
1010 }
1011
1012 void
1013 Player::bounce(BadGuy& )
1014 {
1015   //Make sure we stopped flapping
1016   flapping = false;
1017   falling_from_flap = false;
1018   
1019   if (input.jump)
1020     physic.set_velocity_y(520);
1021   else
1022     physic.set_velocity_y(200);
1023 }
1024