Support for idle animations. Idle stage sprite names must be 'stand', 'idle', 'idle...
[supertux.git] / src / object / player.cpp
1 //  $Id$
2 //
3 //  SuperTux
4 //  Copyright (C) 2006 Matthias Braun <matze@braunis.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 "statistics.hpp"
35 #include "game_session.hpp"
36 #include "object/tilemap.hpp"
37 #include "object/camera.hpp"
38 #include "object/particles.hpp"
39 #include "object/portable.hpp"
40 #include "object/bullet.hpp"
41 #include "trigger/trigger_base.hpp"
42 #include "control/joystickkeyboardcontroller.hpp"
43 #include "scripting/squirrel_util.hpp"
44 #include "main.hpp"
45 #include "platform.hpp"
46 #include "badguy/badguy.hpp"
47 #include "player_status.hpp"
48 #include "log.hpp"
49 #include "falling_coin.hpp"
50 #include "random_generator.hpp"
51 #include "object/sprite_particle.hpp"
52 #include "trigger/climbable.hpp"
53
54 //#define SWIMMING
55
56 namespace {
57   static const int TILES_FOR_BUTTJUMP = 3;
58   static const float BUTTJUMP_MIN_VELOCITY_Y = 400.0f;
59   static const float SHOOTING_TIME = .150f;
60
61   /** number of idle stages, including standing */
62   static const unsigned int IDLE_STAGE_COUNT = 5;
63   /**
64    * how long to play each idle animation in milliseconds
65    * '0' means the sprite action is played once before moving onto the next
66    * animation
67    */
68   static const int IDLE_TIME[] = { 5000, 0, 2500, 0, 2500 };
69   /** idle stages */
70   static const std::string IDLE_STAGES[] =
71     { "stand",
72       "idle",
73       "stand",
74       "idle",
75       "stand" };
76
77   /** acceleration in horizontal direction when walking
78    * (all accelerations are in  pixel/s^2) */
79   static const float WALK_ACCELERATION_X = 300;
80   /** acceleration in horizontal direction when running */ 
81   static const float RUN_ACCELERATION_X = 400;
82   /** acceleration when skidding */
83   static const float SKID_XM = 200;
84   /** time of skidding in seconds */
85   static const float SKID_TIME = .3f;
86   /** maximum walk velocity (pixel/s) */
87   static const float MAX_WALK_XM = 230;
88   /** maximum run velocity (pixel/s) */
89   static const float MAX_RUN_XM = 320;
90   /** maximum horizontal climb velocity */
91   static const float MAX_CLIMB_XM = 48;
92   /** maximum vertical climb velocity */
93   static const float MAX_CLIMB_YM = 128;
94   /** instant velocity when tux starts to walk */
95   static const float WALK_SPEED = 100;
96
97   /** time of the kick (kicking mriceblock) animation */
98   static const float KICK_TIME = .3f;
99   /** time of tux cheering (currently unused) */
100   static const float CHEER_TIME = 1.0f;
101
102   /** if Tux cannot unduck for this long, he will get hurt */
103   static const float UNDUCK_HURT_TIME = 0.25f;
104   /** gravity is higher after the jump key is released before
105       the apex of the jump is reached */
106   static const float JUMP_EARLY_APEX_FACTOR = 3.0;
107
108   bool no_water = true;
109 }
110
111 Player::Player(PlayerStatus* _player_status, const std::string& name)
112   : scripting_controller(0), 
113     player_status(_player_status), 
114     scripting_controller_old(0),
115     grabbed_object(NULL), ghost_mode(false), edit_mode(false), idle_stage(0),
116     climbing(0)
117 {
118   this->name = name;
119   controller = main_controller;
120   scripting_controller = new CodeController();
121   sprite = sprite_manager->create("images/creatures/tux/tux.sprite");
122   airarrow.reset(new Surface("images/engine/hud/airarrow.png"));
123   idle_timer.start(IDLE_TIME[0]/1000.0f);
124
125   sound_manager->preload("sounds/bigjump.wav");
126   sound_manager->preload("sounds/jump.wav");
127   sound_manager->preload("sounds/hurt.wav");
128   sound_manager->preload("sounds/skid.wav");
129   sound_manager->preload("sounds/flip.wav");
130   sound_manager->preload("sounds/invincible_start.ogg");
131   sound_manager->preload("sounds/splash.ogg");
132
133   init();
134 }
135
136 Player::~Player()
137 {
138   if (climbing) stop_climbing(*climbing);
139   delete sprite;
140   delete scripting_controller;
141 }
142
143 void
144 Player::init()
145 {
146   if(is_big())
147     set_size(31.8f, 62.8f);
148   else
149     set_size(31.8f, 30.8f);
150
151   dir = RIGHT;
152   old_dir = dir;
153   duck = false;
154   dead = false;
155
156   dying = false;
157   peekingX = AUTO;
158   peekingY = AUTO;
159   last_ground_y = 0;
160   fall_mode = ON_GROUND;
161   jumping = false;
162   jump_early_apex = false;
163   can_jump = true;
164   wants_buttjump = false;
165   does_buttjump = false;
166   growing = false;
167   deactivated = false;
168   backflipping = false;
169   backflip_direction = 0;
170   visible = true;
171   swimming = false;
172   speedlimit = 0; //no special limit
173
174   on_ground_flag = false;
175   grabbed_object = NULL;
176
177   climbing = 0;
178
179   physic.reset();
180 }
181
182 void
183 Player::expose(HSQUIRRELVM vm, SQInteger table_idx)
184 {
185   if (name.empty())
186     return;
187
188   Scripting::expose_object(vm, table_idx, dynamic_cast<Scripting::Player *>(this), name, false);
189 }
190
191 void
192 Player::unexpose(HSQUIRRELVM vm, SQInteger table_idx)
193 {
194   if (name.empty())
195     return;
196
197   Scripting::unexpose_object(vm, table_idx, name);
198 }
199
200 float
201 Player::get_speedlimit()
202 {
203   return speedlimit;
204 }
205
206 void
207 Player::set_speedlimit(float newlimit)
208 {
209   speedlimit=newlimit;
210 }
211
212 void
213 Player::set_controller(Controller* controller)
214 {
215   this->controller = controller;
216 }
217
218 void 
219 Player::use_scripting_controller(bool use_or_release)
220 {
221   if ((use_or_release == true) && (controller != scripting_controller)) {
222     scripting_controller_old = get_controller();
223     set_controller(scripting_controller);
224   }
225   if ((use_or_release == false) && (controller == scripting_controller)) {
226     set_controller(scripting_controller_old);
227     scripting_controller_old = 0;
228   }
229 }
230
231 void 
232 Player::do_scripting_controller(std::string control, bool pressed)
233 {
234   for(int i = 0; Controller::controlNames[i] != 0; ++i) {
235     if(control == std::string(Controller::controlNames[i])) {
236       scripting_controller->press(Controller::Control(i), pressed);
237     }
238   }
239 }
240
241 bool
242 Player::adjust_height(float new_height)
243 {
244   Rect bbox2 = bbox;
245   bbox2.move(Vector(0, bbox.get_height() - new_height));
246   bbox2.set_height(new_height);
247
248   if(new_height > bbox.get_height()) {
249     Rect additional_space = bbox2;
250     additional_space.set_height(new_height - bbox.get_height());
251     if(!Sector::current()->is_free_of_statics(additional_space, this, true))
252       return false;
253   }
254
255   // adjust bbox accordingly
256   // note that we use members of moving_object for this, so we can run this during CD, too
257   set_pos(bbox2.p1);
258   set_size(bbox2.get_width(), bbox2.get_height());
259   return true;
260 }
261
262 void
263 Player::trigger_sequence(std::string sequence_name)
264 {
265   if (climbing) stop_climbing(*climbing);
266   GameSession::current()->start_sequence(sequence_name);
267 }
268
269 void
270 Player::update(float elapsed_time)
271 {
272   if( no_water ){
273     swimming = false;
274   }
275   no_water = true;
276
277   if(dying && dying_timer.check()) {
278     dead = true;
279     return;
280   }
281
282   if(!dying && !deactivated)
283     handle_input();
284
285   // handle_input() calls apply_friction() when Tux is not walking, so we'll have to do this ourselves
286   if (deactivated)
287     apply_friction();
288
289   // extend/shrink tux collision rectangle so that we fall through/walk over 1
290   // tile holes
291   if(fabsf(physic.get_velocity_x()) > MAX_WALK_XM) {
292     set_width(34);
293   } else {
294     set_width(31.8f);
295   }
296
297   // on downward slopes, adjust vertical velocity so tux walks smoothly down
298   if (on_ground()) {
299     if(floor_normal.y != 0) {
300       if ((floor_normal.x * physic.get_velocity_x()) >= 0) {
301         physic.set_velocity_y(250);
302       }
303     }
304   }
305
306   // handle backflipping
307   if (backflipping) {
308     //prevent player from changing direction when backflipping
309     dir = (backflip_direction == 1) ? LEFT : RIGHT;
310     if (backflip_timer.started()) physic.set_velocity_x(100 * backflip_direction);
311   }
312
313   // set fall mode...
314   if(on_ground()) {
315     fall_mode = ON_GROUND;
316     last_ground_y = get_pos().y;
317   } else {
318     if(get_pos().y > last_ground_y)
319       fall_mode = FALLING;
320     else if(fall_mode == ON_GROUND)
321       fall_mode = JUMPING;
322   }
323
324   // check if we landed
325   if(on_ground()) {
326     jumping = false;
327     if (backflipping && (!backflip_timer.started())) {
328       backflipping = false;
329       backflip_direction = 0;
330
331       // if controls are currently deactivated, we take care of standing up ourselves
332       if (deactivated)
333         do_standup();
334     }
335   }
336
337   // calculate movement for this frame
338   movement = physic.get_movement(elapsed_time);
339
340   if(grabbed_object != NULL && !dying) {
341     Vector pos = get_pos() +
342       Vector(dir == LEFT ? -16 : 16, get_bbox().get_height()*0.66666 - 32);
343     grabbed_object->grab(*this, pos, dir);
344   }
345
346   if(grabbed_object != NULL && dying){
347     grabbed_object->ungrab(*this, dir);
348     grabbed_object = NULL;
349   }
350
351   on_ground_flag = false;
352
353   // when invincible, spawn particles
354   if (invincible_timer.started() && !dying)
355   {
356     if (systemRandom.rand(0, 2) == 0) {
357       float px = systemRandom.randf(bbox.p1.x+0, bbox.p2.x-0);
358       float py = systemRandom.randf(bbox.p1.y+0, bbox.p2.y-0);
359       Vector ppos = Vector(px, py);
360       Vector pspeed = Vector(0, 0);
361       Vector paccel = Vector(0, 0);
362       // draw bright sparkle when there is lots of time left, dark sparkle when invincibility is about to end
363       if (invincible_timer.get_timeleft() > TUX_INVINCIBLE_TIME_WARNING) {
364         // make every other a longer sparkle to make trail a bit fuzzy
365         if (size_t(game_time*20)%2) {
366           Sector::current()->add_object(new SpriteParticle("images/objects/particles/sparkle.sprite", "small", ppos, ANCHOR_MIDDLE, pspeed, paccel, LAYER_OBJECTS+1+5));
367         } else {
368           Sector::current()->add_object(new SpriteParticle("images/objects/particles/sparkle.sprite", "medium", ppos, ANCHOR_MIDDLE, pspeed, paccel, LAYER_OBJECTS+1+5));
369         }
370       } else {
371         Sector::current()->add_object(new SpriteParticle("images/objects/particles/sparkle.sprite", "dark", ppos, ANCHOR_MIDDLE, pspeed, paccel, LAYER_OBJECTS+1+5));
372       }
373     }
374   }
375
376   if (growing) {
377     if (sprite->animation_done()) growing = false;
378   }
379
380 }
381
382 bool
383 Player::on_ground()
384 {
385   return on_ground_flag;
386 }
387
388 bool
389 Player::is_big()
390 {
391   if(player_status->bonus == NO_BONUS)
392     return false;
393
394   return true;
395 }
396
397 void
398 Player::apply_friction()
399 {
400   if ((on_ground()) && (fabs(physic.get_velocity_x()) < WALK_SPEED)) {
401     physic.set_velocity_x(0);
402     physic.set_acceleration_x(0);
403   } else if(physic.get_velocity_x() < 0) {
404     physic.set_acceleration_x(WALK_ACCELERATION_X * 1.5);
405     } else if(physic.get_velocity_x() > 0) {
406     physic.set_acceleration_x(WALK_ACCELERATION_X * -1.5);
407   }
408 }
409
410 void
411 Player::handle_horizontal_input()
412 {
413   float vx = physic.get_velocity_x();
414   float vy = physic.get_velocity_y();
415   float ax = physic.get_acceleration_x();
416   float ay = physic.get_acceleration_y();
417
418   float dirsign = 0;
419   if(!duck || physic.get_velocity_y() != 0) {
420     if(controller->hold(Controller::LEFT) && !controller->hold(Controller::RIGHT)) {
421       old_dir = dir;
422       dir = LEFT;
423       dirsign = -1;
424     } else if(!controller->hold(Controller::LEFT)
425               && controller->hold(Controller::RIGHT)) {
426       old_dir = dir;
427       dir = RIGHT;
428       dirsign = 1;
429     }
430   }
431
432   // do not run if action key is pressed or we're holding something
433   // so tux can only walk while shooting
434   if ( controller->hold(Controller::ACTION) || grabbed_object ) {
435     ax = dirsign * WALK_ACCELERATION_X;
436     // limit speed
437     if(vx >= MAX_WALK_XM && dirsign > 0) {
438       vx = MAX_WALK_XM;
439       ax = 0;
440     } else if(vx <= -MAX_WALK_XM && dirsign < 0) {
441       vx = -MAX_WALK_XM;
442       ax = 0;
443     }
444   } else {
445     if( vx * dirsign < MAX_WALK_XM ) {
446       ax = dirsign * WALK_ACCELERATION_X;
447     } else {
448       ax = dirsign * RUN_ACCELERATION_X;
449     }
450     // limit speed
451     if(vx >= MAX_RUN_XM && dirsign > 0) {
452       vx = MAX_RUN_XM;
453       ax = 0;
454     } else if(vx <= -MAX_RUN_XM && dirsign < 0) {
455       vx = -MAX_RUN_XM;
456       ax = 0;
457     }
458   }
459
460   // we can reach WALK_SPEED without any acceleration
461   if(dirsign != 0 && fabs(vx) < WALK_SPEED) {
462     vx = dirsign * WALK_SPEED;
463   }
464
465   //Check speedlimit.
466   if( speedlimit > 0 &&  vx * dirsign >= speedlimit ) {
467       vx = dirsign * speedlimit;
468       ax = 0;
469   }
470
471   // changing directions?
472   if(on_ground() && ((vx < 0 && dirsign >0) || (vx>0 && dirsign<0))) {
473     // let's skid!
474     if(fabs(vx)>SKID_XM && !skidding_timer.started()) {
475       skidding_timer.start(SKID_TIME);
476       sound_manager->play("sounds/skid.wav");
477       // dust some particles
478       Sector::current()->add_object(
479         new Particles(
480           Vector(dir == RIGHT ? get_bbox().p2.x : get_bbox().p1.x, get_bbox().p2.y),
481           dir == RIGHT ? 270+20 : 90-40, dir == RIGHT ? 270+40 : 90-20,
482           Vector(280, -260), Vector(0, 300), 3, Color(.4f, .4f, .4f), 3, .8f,
483           LAYER_OBJECTS+1));
484
485       ax *= 2.5;
486     } else {
487       ax *= 2;
488     }
489   }
490
491   physic.set_velocity(vx, vy);
492   physic.set_acceleration(ax, ay);
493
494   // we get slower when not pressing any keys
495   if(dirsign == 0) {
496     apply_friction();
497   }
498
499 }
500
501 void
502 Player::do_cheer()
503 {
504   do_duck();
505   do_backflip();
506   do_standup();
507 }
508
509 void
510 Player::do_duck() {
511   if (duck)
512     return;
513   if (!is_big())
514     return;
515
516   if (physic.get_velocity_y() != 0)
517     return;
518   if (!on_ground())
519     return;
520   if (does_buttjump)
521     return;
522
523   if (adjust_height(31.8f)) {
524     duck = true;
525     growing = false;
526     unduck_hurt_timer.stop();
527   } else {
528     // FIXME: what now?
529   }
530 }
531
532 void
533 Player::do_standup() {
534   if (!duck)
535     return;
536   if (!is_big())
537     return;
538   if (backflipping)
539     return;
540
541   if (adjust_height(63.8f)) {
542     duck = false;
543     unduck_hurt_timer.stop();
544   } else {
545     // if timer is not already running, start it.
546     if (unduck_hurt_timer.get_period() == 0) {
547       unduck_hurt_timer.start(UNDUCK_HURT_TIME);
548     }
549     else if (unduck_hurt_timer.check()) {
550       kill(false);
551     }
552   }
553
554 }
555
556 void
557 Player::do_backflip() {
558   if (!duck)
559     return;
560   if (!on_ground())
561     return;
562
563   backflip_direction = (dir == LEFT)?(+1):(-1);
564   backflipping = true;
565   do_jump(-580);
566   sound_manager->play("sounds/flip.wav");
567   backflip_timer.start(0.15f);
568 }
569
570 void
571 Player::do_jump(float yspeed) {
572   if (!on_ground())
573     return;
574
575   physic.set_velocity_y(yspeed);
576   //bbox.move(Vector(0, -1));
577   jumping = true;
578   on_ground_flag = false;
579   can_jump = false;
580
581   // play sound
582   if (is_big()) {
583     sound_manager->play("sounds/bigjump.wav");
584   } else {
585     sound_manager->play("sounds/jump.wav");
586   }
587 }
588
589 void
590 Player::early_jump_apex() {
591   if(jump_early_apex) {
592     return;
593   }
594   jump_early_apex = true;
595   physic.set_gravity(physic.get_gravity() * JUMP_EARLY_APEX_FACTOR);
596 };
597
598 void
599 Player::do_jump_apex() {
600   if(!jump_early_apex) {
601     return;
602   }
603   jump_early_apex = false;
604   physic.set_gravity(physic.get_gravity() / JUMP_EARLY_APEX_FACTOR);
605 }
606
607 void
608 Player::handle_vertical_input()
609 {
610   // Press jump key
611   if(controller->pressed(Controller::JUMP) && (can_jump)) {
612     if (duck) {
613       // when running, only jump a little bit; else do a backflip
614       if ((physic.get_velocity_x() != 0) || (controller->hold(Controller::LEFT)) || (controller->hold(Controller::RIGHT))) do_jump(-300); else do_backflip();
615     } else {
616       // jump a bit higher if we are running; else do a normal jump
617       if (fabs(physic.get_velocity_x()) > MAX_WALK_XM) do_jump(-580); else do_jump(-520);
618     }
619   }
620   // Let go of jump key
621   else if(!controller->hold(Controller::JUMP)) {
622     if (!backflipping && jumping && physic.get_velocity_y() < 0) {
623       jumping = false;
624       early_jump_apex();
625     }
626   }
627
628   if(jump_early_apex && physic.get_velocity_y() >= 0) {
629     do_jump_apex();
630   }
631
632   /* In case the player has pressed Down while in a certain range of air,
633      enable butt jump action */
634   if (controller->hold(Controller::DOWN) && !duck && is_big() && !on_ground()) {
635     wants_buttjump = true;
636     if (physic.get_velocity_y() >= BUTTJUMP_MIN_VELOCITY_Y) does_buttjump = true;
637   }
638
639   /* When Down is not held anymore, disable butt jump */
640   if(!controller->hold(Controller::DOWN)) {
641     wants_buttjump = false;
642     does_buttjump = false;
643   }
644
645   // swimming
646   physic.set_acceleration_y(0);
647 #ifdef SWIMMING
648   if (swimming) {
649     if (controller->hold(Controller::UP) || controller->hold(Controller::JUMP))
650       physic.set_acceleration_y(-2000);
651     physic.set_velocity_y(physic.get_velocity_y() * 0.94);
652   }
653 #endif
654 }
655
656 void
657 Player::handle_input()
658 {
659   if (ghost_mode) {
660     handle_input_ghost();
661     return;
662   }
663   if (climbing) {
664     handle_input_climbing();
665     return;
666   }
667
668   /* Peeking */
669   if( controller->released( Controller::PEEK_LEFT ) ) {
670     peekingX = AUTO;
671   }
672   if( controller->released( Controller::PEEK_RIGHT ) ) {
673     peekingX = AUTO;
674   }
675   if( controller->released( Controller::PEEK_UP ) ) {
676     peekingY = AUTO;
677   }
678   if( controller->released( Controller::PEEK_DOWN ) ) {
679     peekingY = AUTO;
680   }
681   if( controller->pressed( Controller::PEEK_LEFT ) ) {
682     peekingX = LEFT;
683   }
684   if( controller->pressed( Controller::PEEK_RIGHT ) ) {
685     peekingX = RIGHT;
686   }
687   if(!backflipping && !jumping && on_ground()) {
688     if( controller->pressed( Controller::PEEK_UP ) ) {
689       peekingY = UP;
690     } else if( controller->pressed( Controller::PEEK_DOWN ) ) {
691       peekingY = DOWN;
692     }
693   }
694
695   /* Handle horizontal movement: */
696   if (!backflipping) handle_horizontal_input();
697
698   /* Jump/jumping? */
699   if (on_ground() && !controller->hold(Controller::JUMP))
700     can_jump = true;
701
702   /* Handle vertical movement: */
703   handle_vertical_input();
704
705   /* Shoot! */
706   if (controller->pressed(Controller::ACTION) && (player_status->bonus == FIRE_BONUS || player_status->bonus == ICE_BONUS)) {
707     if(Sector::current()->add_bullet(
708          get_pos() + ((dir == LEFT)? Vector(0, bbox.get_height()/2)
709                       : Vector(32, bbox.get_height()/2)),
710          physic.get_velocity_x(), dir))
711       shooting_timer.start(SHOOTING_TIME);
712   }
713
714   /* Duck or Standup! */
715   if (controller->hold(Controller::DOWN)) {
716     do_duck();
717   } else {
718     do_standup();
719   }
720
721   /* grabbing */
722   try_grab();
723
724   if(!controller->hold(Controller::ACTION) && grabbed_object) {
725     // move the grabbed object a bit away from tux
726     Vector pos = get_pos() +
727         Vector(dir == LEFT ? -bbox.get_width()-1 : bbox.get_width()+1,
728                 bbox.get_height()*0.66666 - 32);
729     Rect dest(pos, pos + Vector(32, 32));
730     if(Sector::current()->is_free_of_movingstatics(dest)) {
731       MovingObject* moving_object = dynamic_cast<MovingObject*> (grabbed_object);
732       if(moving_object) {
733         moving_object->set_pos(pos);
734       } else {
735         log_debug << "Non MovingObject grabbed?!?" << std::endl;
736       }
737       if(controller->hold(Controller::UP)) {
738         grabbed_object->ungrab(*this, UP);
739       } else {
740         grabbed_object->ungrab(*this, dir);
741       }
742       grabbed_object = NULL;
743     }
744   }
745 }
746
747 void
748 Player::try_grab()
749 {
750   if(controller->hold(Controller::ACTION) && !grabbed_object
751       && !duck) {
752   Sector* sector = Sector::current();
753     Vector pos;
754     if(dir == LEFT) {
755       pos = Vector(bbox.get_left() - 5, bbox.get_bottom() - 16);
756     } else {
757       pos = Vector(bbox.get_right() + 5, bbox.get_bottom() - 16);
758     }
759
760     for(Sector::Portables::iterator i = sector->portables.begin();
761         i != sector->portables.end(); ++i) {
762       Portable* portable = *i;
763       if(!portable->is_portable())
764         continue;
765
766       // make sure the Portable is a MovingObject
767       MovingObject* moving_object = dynamic_cast<MovingObject*> (portable);
768       assert(moving_object);
769       if(moving_object == NULL)
770         continue;
771
772       // make sure the Portable isn't currently non-solid
773       if(moving_object->get_group() == COLGROUP_DISABLED) continue;
774
775       // check if we are within reach
776       if(moving_object->get_bbox().contains(pos)) {
777         if (climbing) stop_climbing(*climbing);
778         grabbed_object = portable;
779         grabbed_object->grab(*this, get_pos(), dir);
780         break;
781       }
782     }
783   }
784 }
785
786 void
787 Player::handle_input_ghost()
788 {
789   float vx = 0;
790   float vy = 0;
791   if (controller->hold(Controller::LEFT)) {
792     dir = LEFT;
793     vx -= MAX_RUN_XM * 2;
794   }
795   if (controller->hold(Controller::RIGHT)) {
796     dir = RIGHT;
797     vx += MAX_RUN_XM * 2;
798   }
799   if ((controller->hold(Controller::UP)) || (controller->hold(Controller::JUMP))) {
800     vy -= MAX_RUN_XM * 2;
801   }
802   if (controller->hold(Controller::DOWN)) {
803     vy += MAX_RUN_XM * 2;
804   }
805   if (controller->hold(Controller::ACTION)) {
806     set_ghost_mode(false);
807   }
808   physic.set_velocity(vx, vy);
809   physic.set_acceleration(0, 0);
810 }
811
812 void
813 Player::add_coins(int count)
814 {
815   player_status->add_coins(count);
816 }
817
818 int
819 Player::get_coins()
820 {
821   return player_status->coins;
822 }
823
824 bool
825 Player::add_bonus(const std::string& bonustype)
826 {
827   BonusType type = NO_BONUS;
828
829   if(bonustype == "grow") {
830     type = GROWUP_BONUS;
831   } else if(bonustype == "fireflower") {
832     type = FIRE_BONUS;
833   } else if(bonustype == "iceflower") {
834     type = ICE_BONUS;
835   } else if(bonustype == "none") {
836     type = NO_BONUS;
837   } else {
838     std::ostringstream msg;
839     msg << "Unknown bonus type "  << bonustype;
840     throw std::runtime_error(msg.str());
841   }
842
843   return add_bonus(type);
844 }
845
846 bool
847 Player::add_bonus(BonusType type, bool animate)
848 {
849   // always ignore NO_BONUS
850   if (type == NO_BONUS) {
851     return true;
852   }
853
854   // ignore GROWUP_BONUS if we're already big
855   if (type == GROWUP_BONUS) {
856     if (player_status->bonus == GROWUP_BONUS)
857       return true;
858     if (player_status->bonus == FIRE_BONUS)
859       return true;
860     if (player_status->bonus == ICE_BONUS)
861       return true;
862   }
863
864   return set_bonus(type, animate);
865 }
866
867 bool
868 Player::set_bonus(BonusType type, bool animate)
869 {
870   if(player_status->bonus == NO_BONUS) {
871     if (!adjust_height(62.8f)) {
872       printf("can't adjust\n");
873       return false;
874     }
875     if(animate) {
876       growing = true;
877       sprite->set_action((dir == LEFT)?"grow-left":"grow-right", 1);
878     }
879     if (climbing) stop_climbing(*climbing);
880   }
881
882   if (type == NO_BONUS) {
883     if (does_buttjump) does_buttjump = false;
884   }
885
886   if ((type == NO_BONUS) || (type == GROWUP_BONUS)) {
887     if ((player_status->bonus == FIRE_BONUS) && (animate)) {
888       // visually lose helmet
889       Vector ppos = Vector((bbox.p1.x + bbox.p2.x) / 2, bbox.p1.y);
890       Vector pspeed = Vector(((dir==LEFT) ? +100 : -100), -300);
891       Vector paccel = Vector(0, 1000);
892       std::string action = (dir==LEFT)?"left":"right";
893       Sector::current()->add_object(new SpriteParticle("images/objects/particles/firetux-helmet.sprite", action, ppos, ANCHOR_TOP, pspeed, paccel, LAYER_OBJECTS-1));
894       if (climbing) stop_climbing(*climbing);
895     }
896     if ((player_status->bonus == ICE_BONUS) && (animate)) {
897       // visually lose cap
898       Vector ppos = Vector((bbox.p1.x + bbox.p2.x) / 2, bbox.p1.y);
899       Vector pspeed = Vector(((dir==LEFT) ? +100 : -100), -300);
900       Vector paccel = Vector(0, 1000);
901       std::string action = (dir==LEFT)?"left":"right";
902       Sector::current()->add_object(new SpriteParticle("images/objects/particles/icetux-cap.sprite", action, ppos, ANCHOR_TOP, pspeed, paccel, LAYER_OBJECTS-1));
903       if (climbing) stop_climbing(*climbing);
904     }
905     player_status->max_fire_bullets = 0;
906     player_status->max_ice_bullets = 0;
907   }
908   if (type == FIRE_BONUS) player_status->max_fire_bullets++;
909   if (type == ICE_BONUS) player_status->max_ice_bullets++;
910
911   player_status->bonus = type;
912   return true;
913 }
914
915 void
916 Player::set_visible(bool visible)
917 {
918   this->visible = visible;
919   if( visible )
920     set_group(COLGROUP_MOVING);
921   else
922     set_group(COLGROUP_DISABLED);
923 }
924
925 bool
926 Player::get_visible()
927 {
928   return visible;
929 }
930
931 void
932 Player::kick()
933 {
934   kick_timer.start(KICK_TIME);
935 }
936
937 void
938 Player::draw(DrawingContext& context)
939 {
940   if(!visible)
941     return;
942
943   // if Tux is above camera, draw little "air arrow" to show where he is x-wise
944   if (Sector::current() && Sector::current()->camera && (get_bbox().p2.y - 16 < Sector::current()->camera->get_translation().y)) {
945     float px = get_pos().x + (get_bbox().p2.x - get_bbox().p1.x - airarrow.get()->get_width()) / 2;
946     float py = Sector::current()->camera->get_translation().y;
947     py += std::min(((py - (get_bbox().p2.y + 16)) / 4), 16.0f);
948     context.draw_surface(airarrow.get(), Vector(px, py), LAYER_HUD - 1);
949   }
950
951   std::string sa_prefix = "";
952   if (player_status->bonus == GROWUP_BONUS)
953     sa_prefix = "big";
954   else if (player_status->bonus == FIRE_BONUS)
955     sa_prefix = "fire";
956   else if (player_status->bonus == ICE_BONUS)
957     sa_prefix = "ice";
958   else
959     sa_prefix = "small";
960
961   /* Set Tux sprite action */
962   if(dying) {
963     sprite->set_action("gameover");
964   }
965   else if (growing) {
966     sprite->set_action_continued((dir == LEFT)?"grow-left":"grow-right");
967     // while growing, do not change action
968     // do_duck() will take care of cancelling growing manually
969     // update() will take care of cancelling when growing completed
970   }
971   else if (climbing) {
972     sprite->set_action(sa_prefix+((dir == LEFT)?"-skid-left":"-skid-right"));
973   }
974   else if (backflipping) {
975     sprite->set_action(sa_prefix+((dir == LEFT)?"-backflip-left":"-backflip-right"));
976   }
977   else if (duck && is_big()) {
978     sprite->set_action(sa_prefix+((dir == LEFT)?"-duck-left":"-duck-right"));
979   }
980   else if (skidding_timer.started() && !skidding_timer.check()) {
981     sprite->set_action(sa_prefix+((dir == LEFT)?"-skid-left":"-skid-right"));
982   }
983   else if (kick_timer.started() && !kick_timer.check()) {
984     sprite->set_action(sa_prefix+((dir == LEFT)?"-kick-left":"-kick-right"));
985   }
986   else if ((wants_buttjump || does_buttjump) && is_big()) {
987     sprite->set_action(sa_prefix+((dir == LEFT)?"-buttjump-left":"-buttjump-right"));
988   }
989   else if (!on_ground()) {
990     sprite->set_action(sa_prefix+((dir == LEFT)?"-jump-left":"-jump-right"));
991   }
992   else {
993     if (fabsf(physic.get_velocity_x()) < 1.0f) {
994       // Determine which idle stage we're at
995       if (sprite->get_action().find("-stand-") == std::string::npos && sprite->get_action().find("-idle-") == std::string::npos) {
996         idle_stage = 0;
997         idle_timer.start(IDLE_TIME[idle_stage]/1000.0f);
998
999         sprite->set_action_continued(sa_prefix+((dir == LEFT)?"-" + IDLE_STAGES[idle_stage] + "-left":"-" + IDLE_STAGES[idle_stage] + "-right"));
1000       }
1001       else if (idle_timer.check() || (IDLE_TIME[idle_stage] == 0 && sprite->animation_done())) {
1002         idle_stage++;
1003         if (idle_stage >= IDLE_STAGE_COUNT)
1004             idle_stage = 1;
1005
1006         idle_timer.start(IDLE_TIME[idle_stage]/1000.0f);
1007
1008         if (IDLE_TIME[idle_stage] == 0)
1009           sprite->set_action(sa_prefix+((dir == LEFT)?"-" + IDLE_STAGES[idle_stage] + "-left":"-" + IDLE_STAGES[idle_stage] + "-right"), 1);
1010         else
1011           sprite->set_action(sa_prefix+((dir == LEFT)?"-" + IDLE_STAGES[idle_stage] + "-left":"-" + IDLE_STAGES[idle_stage] + "-right"));
1012       }
1013     }
1014     else {
1015       sprite->set_action(sa_prefix+((dir == LEFT)?"-walk-left":"-walk-right"));
1016     }
1017   }
1018
1019
1020 /*
1021   // Tux is holding something
1022   if ((grabbed_object != 0 && physic.get_velocity_y() == 0) ||
1023       (shooting_timer.get_timeleft() > 0 && !shooting_timer.check())) {
1024     if (duck) {
1025     } else {
1026     }
1027   }
1028 */
1029
1030   /* Draw Tux */
1031   if (safe_timer.started() && size_t(game_time*40)%2)
1032     ;  // don't draw Tux
1033   else {
1034     sprite->draw(context, get_pos(), LAYER_OBJECTS + 1);
1035   }
1036
1037 }
1038
1039 void
1040 Player::collision_tile(uint32_t tile_attributes)
1041 {
1042   if(tile_attributes & Tile::HURTS)
1043     kill(false);
1044
1045 #ifdef SWIMMING
1046   if( swimming ){
1047     if( tile_attributes & Tile::WATER ){
1048       no_water = false;
1049     } else {
1050       swimming = false;
1051     }
1052   } else {
1053     if( tile_attributes & Tile::WATER ){
1054       swimming = true;
1055       no_water = false;
1056       sound_manager->play( "sounds/splash.ogg" );
1057     }
1058   }
1059 #endif
1060 }
1061
1062 void
1063 Player::collision_solid(const CollisionHit& hit)
1064 {
1065   if(hit.bottom) {
1066     if(physic.get_velocity_y() > 0)
1067       physic.set_velocity_y(0);
1068
1069     on_ground_flag = true;
1070     floor_normal = hit.slope_normal;
1071
1072     // Butt Jump landed    
1073     if (does_buttjump) {
1074       does_buttjump = false;
1075       physic.set_velocity_y(-300);
1076       on_ground_flag = false;
1077       Sector::current()->add_object(new Particles(
1078           Vector(get_bbox().p2.x, get_bbox().p2.y),
1079           270+20, 270+40,
1080           Vector(280, -260), Vector(0, 300), 3, Color(.4f, .4f, .4f), 3, .8f,
1081           LAYER_OBJECTS+1));
1082       Sector::current()->add_object(new Particles(
1083           Vector(get_bbox().p1.x, get_bbox().p2.y),
1084           90-40, 90-20,
1085           Vector(280, -260), Vector(0, 300), 3, Color(.4f, .4f, .4f), 3, .8f,
1086           LAYER_OBJECTS+1));
1087     }
1088
1089   } else if(hit.top) {
1090     if(physic.get_velocity_y() < 0)
1091       physic.set_velocity_y(.2f);
1092   }
1093
1094   if(hit.left || hit.right) {
1095     physic.set_velocity_x(0);
1096   }
1097
1098   // crushed?
1099   if(hit.crush) {
1100     if(hit.left || hit.right) {
1101       kill(true);
1102     } else if(hit.top || hit.bottom) {
1103       kill(false);
1104     }
1105   }
1106 }
1107
1108 HitResponse
1109 Player::collision(GameObject& other, const CollisionHit& hit)
1110 {
1111   Bullet* bullet = dynamic_cast<Bullet*> (&other);
1112   if(bullet) {
1113     return FORCE_MOVE;
1114   }
1115
1116   if(hit.left || hit.right) {
1117     try_grab(); //grab objects right now, in update it will be too late
1118   }
1119 #ifdef DEBUG
1120   assert(dynamic_cast<MovingObject*> (&other) != NULL);
1121 #endif
1122   MovingObject* moving_object = static_cast<MovingObject*> (&other);
1123   if(moving_object->get_group() == COLGROUP_TOUCHABLE) {
1124     TriggerBase* trigger = dynamic_cast<TriggerBase*> (&other);
1125     if(trigger) {
1126       if(controller->pressed(Controller::UP))
1127         trigger->event(*this, TriggerBase::EVENT_ACTIVATE);
1128     }
1129
1130     return FORCE_MOVE;
1131   }
1132
1133   BadGuy* badguy = dynamic_cast<BadGuy*> (&other);
1134   if(badguy != NULL) {
1135     if(safe_timer.started() || invincible_timer.started())
1136       return FORCE_MOVE;
1137
1138     return CONTINUE;
1139   }
1140
1141   return CONTINUE;
1142 }
1143
1144 void
1145 Player::make_invincible()
1146 {
1147   sound_manager->play("sounds/invincible_start.ogg");
1148   invincible_timer.start(TUX_INVINCIBLE_TIME);
1149   Sector::current()->play_music(HERRING_MUSIC);
1150 }
1151
1152 /* Kill Player! */
1153 void
1154 Player::kill(bool completely)
1155 {
1156   if(dying || deactivated)
1157     return;
1158
1159   if(!completely && (safe_timer.started() || invincible_timer.started()))
1160     return;
1161
1162   growing = false;
1163
1164   sound_manager->play("sounds/hurt.wav");
1165
1166   if (climbing) stop_climbing(*climbing);
1167
1168   physic.set_velocity_x(0);
1169
1170   if(!completely && is_big()) {
1171     if(player_status->bonus == FIRE_BONUS
1172         || player_status->bonus == ICE_BONUS) {
1173       safe_timer.start(TUX_SAFE_TIME);
1174       set_bonus(GROWUP_BONUS, true);
1175     } else if(player_status->bonus == GROWUP_BONUS) {
1176       safe_timer.start(TUX_SAFE_TIME /* + GROWING_TIME */);
1177       adjust_height(30.8f);
1178       duck = false;
1179       backflipping = false;
1180       set_bonus(NO_BONUS, true);
1181     } else if(player_status->bonus == NO_BONUS) {
1182       safe_timer.start(TUX_SAFE_TIME);
1183       adjust_height(30.8f);
1184       duck = false;
1185     }
1186   } else {
1187
1188     // do not die when in edit mode
1189     if (edit_mode) {
1190       set_ghost_mode(true);
1191       return;
1192     }
1193
1194     if (player_status->coins >= 25 && !GameSession::current()->get_reset_point_sectorname().empty())
1195     {
1196       for (int i = 0; i < 5; i++)
1197       {
1198         // the numbers: starting x, starting y, velocity y
1199         Sector::current()->add_object(new FallingCoin(get_pos() +
1200               Vector(systemRandom.rand(5), systemRandom.rand(-32,18)),
1201               systemRandom.rand(-100,100)));
1202       }
1203       player_status->coins -= std::max(player_status->coins/10, 25);
1204     }
1205     else
1206     {
1207       GameSession::current()->set_reset_point("", Vector());
1208     }
1209     physic.enable_gravity(true);
1210     physic.set_acceleration(0, 0);
1211     physic.set_velocity(0, -700);
1212     set_bonus(NO_BONUS, true);
1213     dying = true;
1214     dying_timer.start(3.0);
1215     set_group(COLGROUP_DISABLED);
1216
1217     DisplayEffect* effect = new DisplayEffect();
1218     effect->fade_out(3.0);
1219     Sector::current()->add_object(effect);
1220     sound_manager->stop_music(3.0);
1221   }
1222 }
1223
1224 void
1225 Player::move(const Vector& vector)
1226 {
1227   set_pos(vector);
1228
1229   // TODO: do we need the following? Seems irrelevant to moving the player
1230   if(is_big())
1231     set_size(31.8f, 63.8f);
1232   else
1233     set_size(31.8f, 31.8f);
1234   duck = false;
1235   last_ground_y = vector.y;
1236   if (climbing) stop_climbing(*climbing);
1237
1238   physic.reset();
1239 }
1240
1241 void
1242 Player::check_bounds(Camera* camera)
1243 {
1244   /* Keep tux in bounds: */
1245   if (get_pos().x < 0) {
1246     // Lock Tux to the size of the level, so that he doesn't fall of
1247     // on the left side
1248     set_pos(Vector(0, get_pos().y));
1249   }
1250
1251   /* fallen out of the level? */
1252   if ((get_pos().y > Sector::current()->get_height()) && (!ghost_mode)) {
1253     kill(true);
1254     return;
1255   }
1256
1257   // can happen if back scrolling is disabled
1258   if(get_pos().x < camera->get_translation().x) {
1259     set_pos(Vector(camera->get_translation().x, get_pos().y));
1260   }
1261   if(get_pos().x >= camera->get_translation().x + SCREEN_WIDTH - bbox.get_width())
1262   {
1263     set_pos(Vector(
1264           camera->get_translation().x + SCREEN_WIDTH - bbox.get_width(),
1265           get_pos().y));
1266   }
1267 }
1268
1269 void
1270 Player::add_velocity(const Vector& velocity)
1271 {
1272   physic.set_velocity(physic.get_velocity() + velocity);
1273 }
1274
1275 void
1276 Player::add_velocity(const Vector& velocity, const Vector& end_speed)
1277 {
1278   if (end_speed.x > 0)
1279     physic.set_velocity_x(std::min(physic.get_velocity_x() + velocity.x, end_speed.x));
1280   if (end_speed.x < 0)
1281     physic.set_velocity_x(std::max(physic.get_velocity_x() + velocity.x, end_speed.x));
1282   if (end_speed.y > 0)
1283     physic.set_velocity_y(std::min(physic.get_velocity_y() + velocity.y, end_speed.y));
1284   if (end_speed.y < 0)
1285     physic.set_velocity_y(std::max(physic.get_velocity_y() + velocity.y, end_speed.y));
1286 }
1287
1288 Vector 
1289 Player::get_velocity()
1290 {
1291   return physic.get_velocity();
1292 }
1293
1294 void
1295 Player::bounce(BadGuy& )
1296 {
1297   if(controller->hold(Controller::JUMP))
1298     physic.set_velocity_y(-520);
1299   else
1300     physic.set_velocity_y(-300);
1301 }
1302
1303 //Scripting Functions Below
1304
1305 void
1306 Player::deactivate()
1307 {
1308   if (deactivated)
1309     return;
1310   deactivated = true;
1311   physic.set_velocity_x(0);
1312   physic.set_velocity_y(0);
1313   physic.set_acceleration_x(0);
1314   physic.set_acceleration_y(0);
1315   if (climbing) stop_climbing(*climbing);
1316 }
1317
1318 void
1319 Player::activate()
1320 {
1321   if (!deactivated)
1322     return;
1323   deactivated = false;
1324 }
1325
1326 void Player::walk(float speed)
1327 {
1328   physic.set_velocity_x(speed);
1329 }
1330
1331 void
1332 Player::set_ghost_mode(bool enable)
1333 {
1334   if (ghost_mode == enable)
1335     return;
1336
1337   if (climbing) stop_climbing(*climbing);
1338
1339   if (enable) {
1340     ghost_mode = true;
1341     set_group(COLGROUP_DISABLED);
1342     physic.enable_gravity(false);
1343     log_debug << "You feel lightheaded. Use movement controls to float around, press ACTION to scare badguys." << std::endl;
1344   } else {
1345     ghost_mode = false;
1346     set_group(COLGROUP_MOVING);
1347     physic.enable_gravity(true);
1348     log_debug << "You feel solid again." << std::endl;
1349   }
1350 }
1351
1352
1353 void
1354 Player::set_edit_mode(bool enable)
1355 {
1356   edit_mode = enable;
1357 }
1358
1359 void 
1360 Player::start_climbing(Climbable& climbable)
1361 {
1362   if (climbing == &climbable) return;
1363
1364   climbing = &climbable;
1365   physic.enable_gravity(false);
1366   physic.set_velocity(0, 0);
1367   physic.set_acceleration(0, 0);
1368 }
1369
1370 void 
1371 Player::stop_climbing(Climbable& /*climbable*/)
1372 {
1373   if (!climbing) return;
1374
1375   climbing = 0;
1376
1377   if (grabbed_object) {    
1378     grabbed_object->ungrab(*this, dir);
1379     grabbed_object = NULL;
1380   }
1381
1382   physic.enable_gravity(true);
1383   physic.set_velocity(0, 0);
1384   physic.set_acceleration(0, 0);
1385
1386   if ((controller->hold(Controller::JUMP)) || (controller->hold(Controller::UP))) {
1387     on_ground_flag = true;
1388     // TODO: This won't help. Why?
1389     do_jump(-300);
1390   }
1391 }
1392
1393 void
1394 Player::handle_input_climbing()
1395 {
1396   if (!climbing) {
1397     log_warning << "handle_input_climbing called with climbing set to 0. Input handling skipped" << std::endl;
1398     return;
1399   }
1400
1401   float vx = 0;
1402   float vy = 0;
1403   if (controller->hold(Controller::LEFT)) {
1404     dir = LEFT;
1405     vx -= MAX_CLIMB_XM;
1406   }
1407   if (controller->hold(Controller::RIGHT)) {
1408     dir = RIGHT;
1409     vx += MAX_CLIMB_XM;
1410   }
1411   if (controller->hold(Controller::UP)) {
1412     vy -= MAX_CLIMB_YM;
1413   }
1414   if (controller->hold(Controller::DOWN)) {
1415     vy += MAX_CLIMB_YM;
1416   }
1417   if (controller->hold(Controller::JUMP)) {
1418     if (can_jump) {
1419       stop_climbing(*climbing);
1420       return;
1421     }  
1422   } else {
1423     can_jump = true;
1424   }
1425   if (controller->hold(Controller::ACTION)) {
1426     stop_climbing(*climbing);
1427     return;
1428   }
1429   physic.set_velocity(vx, vy);
1430   physic.set_acceleration(0, 0);
1431 }
1432
1433