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