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