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