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