src/object/player.cpp

Go to the documentation of this file.
00001 //  SuperTux
00002 //  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
00003 //
00004 //  This program is free software; you can redistribute it and/or
00005 //  modify it under the terms of the GNU General Public License
00006 //  as published by the Free Software Foundation; either version 2
00007 //  of the License, or (at your option) any later version.
00008 //
00009 //  This program is distributed in the hope that it will be useful,
00010 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 //  GNU General Public License for more details.
00013 //
00014 //  You should have received a copy of the GNU General Public License
00015 //  along with this program; if not, write to the Free Software
00016 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00017 
00018 #include "object/player.hpp"
00019 
00020 #include "audio/sound_manager.hpp"
00021 #include "badguy/badguy.hpp"
00022 #include "control/joystickkeyboardcontroller.hpp"
00023 #include "math/random_generator.hpp"
00024 #include "object/bullet.hpp"
00025 #include "object/camera.hpp"
00026 #include "object/display_effect.hpp"
00027 #include "object/falling_coin.hpp"
00028 #include "object/particles.hpp"
00029 #include "object/portable.hpp"
00030 #include "object/sprite_particle.hpp"
00031 #include "scripting/squirrel_util.hpp"
00032 #include "supertux/game_session.hpp"
00033 #include "supertux/globals.hpp"
00034 #include "supertux/sector.hpp"
00035 #include "supertux/tile.hpp"
00036 #include "trigger/climbable.hpp"
00037 
00038 #include <math.h>
00039 
00040 //#define SWIMMING
00041 
00042 namespace {
00043 static const int TILES_FOR_BUTTJUMP = 3;
00044 static const float BUTTJUMP_MIN_VELOCITY_Y = 400.0f;
00045 static const float SHOOTING_TIME = .150f;
00046 
00048 static const unsigned int IDLE_STAGE_COUNT = 5;
00054 static const int IDLE_TIME[] = { 5000, 0, 2500, 0, 2500 };
00056 static const std::string IDLE_STAGES[] =
00057 { "stand",
00058   "idle",
00059   "stand",
00060   "idle",
00061   "stand" };
00062 
00065 static const float WALK_ACCELERATION_X = 300;
00067 static const float RUN_ACCELERATION_X = 400;
00069 static const float SKID_XM = 200;
00071 static const float SKID_TIME = .3f;
00073 static const float MAX_WALK_XM = 230;
00075 static const float MAX_RUN_XM = 320;
00077 static const float MAX_CLIMB_XM = 48;
00079 static const float MAX_CLIMB_YM = 128;
00081 static const float WALK_SPEED = 100;
00082 
00084 static const float NORMAL_FRICTION_MULTIPLIER = 1.5f;
00086 static const float ICE_FRICTION_MULTIPLIER = 0.1f;
00087 static const float ICE_ACCELERATION_MULTIPLIER = 0.25f;
00088 
00090 static const float KICK_TIME = .3f;
00092 static const float CHEER_TIME = 1.0f;
00093 
00095 static const float UNDUCK_HURT_TIME = 0.25f;
00098 static const float JUMP_EARLY_APEX_FACTOR = 3.0;
00099 
00100 static const float JUMP_GRACE_TIME = 0.25f; 
00102 /* Tux's collision rectangle */
00103 static const float TUX_WIDTH = 31.8f;
00104 static const float RUNNING_TUX_WIDTH = 34;
00105 static const float SMALL_TUX_HEIGHT = 30.8f;
00106 static const float BIG_TUX_HEIGHT = 62.8f;
00107 static const float DUCKED_TUX_HEIGHT = 31.8f;
00108 
00109 bool no_water = true;
00110 }
00111 
00112 Player::Player(PlayerStatus* _player_status, const std::string& name) :
00113   deactivated(),
00114   controller(),
00115   scripting_controller(0), 
00116   player_status(_player_status), 
00117   duck(),
00118   dead(),
00119   dying(),
00120   backflipping(),
00121   backflip_direction(),
00122   peekingX(),
00123   peekingY(),
00124   swimming(),
00125   speedlimit(),
00126   scripting_controller_old(0),
00127   jump_early_apex(),
00128   on_ice(),
00129   ice_this_frame(),
00130   dir(),
00131   old_dir(),
00132   last_ground_y(),
00133   fall_mode(),
00134   on_ground_flag(),
00135   jumping(),
00136   can_jump(),
00137   jump_button_timer(), 
00138   wants_buttjump(),
00139   does_buttjump(),
00140   invincible_timer(),
00141   skidding_timer(),
00142   safe_timer(),
00143   kick_timer(),
00144   shooting_timer(),
00145   dying_timer(),
00146   growing(),
00147   backflip_timer(),
00148   physic(),
00149   visible(),
00150   grabbed_object(NULL), 
00151   sprite(),
00152   airarrow(),
00153   floor_normal(),
00154   ghost_mode(false), 
00155   edit_mode(false), 
00156   unduck_hurt_timer(),
00157   idle_timer(),
00158   idle_stage(0),
00159   climbing(0)
00160 {
00161   this->name = name;
00162   controller = g_jk_controller->get_main_controller();
00163   scripting_controller.reset(new CodeController());
00164   // if/when we have complete penny gfx, we can
00165   // load those instead of Tux's sprite in the
00166   // constructor
00167   sprite = sprite_manager->create("images/creatures/tux/tux.sprite");
00168   airarrow = Surface::create("images/engine/hud/airarrow.png");
00169   idle_timer.start(IDLE_TIME[0]/1000.0f);
00170 
00171   sound_manager->preload("sounds/bigjump.wav");
00172   sound_manager->preload("sounds/jump.wav");
00173   sound_manager->preload("sounds/hurt.wav");
00174   sound_manager->preload("sounds/kill.wav");
00175   sound_manager->preload("sounds/skid.wav");
00176   sound_manager->preload("sounds/flip.wav");
00177   sound_manager->preload("sounds/invincible_start.ogg");
00178   sound_manager->preload("sounds/splash.ogg");
00179 
00180   init();
00181 }
00182 
00183 Player::~Player()
00184 {
00185   if (climbing) stop_climbing(*climbing);
00186 }
00187 
00188 void
00189 Player::init()
00190 {
00191   if(is_big())
00192     set_size(TUX_WIDTH, BIG_TUX_HEIGHT);
00193   else
00194     set_size(TUX_WIDTH, SMALL_TUX_HEIGHT);
00195 
00196   dir = RIGHT;
00197   old_dir = dir;
00198   duck = false;
00199   dead = false;
00200 
00201   dying = false;
00202   winning = false;
00203   peekingX = AUTO;
00204   peekingY = AUTO;
00205   last_ground_y = 0;
00206   fall_mode = ON_GROUND;
00207   jumping = false;
00208   jump_early_apex = false;
00209   can_jump = true;
00210   wants_buttjump = false;
00211   does_buttjump = false;
00212   growing = false;
00213   deactivated = false;
00214   backflipping = false;
00215   backflip_direction = 0;
00216   visible = true;
00217   swimming = false;
00218   on_ice = false;
00219   ice_this_frame = false;
00220   speedlimit = 0; //no special limit
00221 
00222   on_ground_flag = false;
00223   grabbed_object = NULL;
00224 
00225   climbing = 0;
00226 
00227   physic.reset();
00228 }
00229 
00230 void
00231 Player::expose(HSQUIRRELVM vm, SQInteger table_idx)
00232 {
00233   if (name.empty())
00234     return;
00235 
00236   scripting::expose_object(vm, table_idx, dynamic_cast<scripting::Player *>(this), name, false);
00237 }
00238 
00239 void
00240 Player::unexpose(HSQUIRRELVM vm, SQInteger table_idx)
00241 {
00242   if (name.empty())
00243     return;
00244 
00245   scripting::unexpose_object(vm, table_idx, name);
00246 }
00247 
00248 float
00249 Player::get_speedlimit()
00250 {
00251   return speedlimit;
00252 }
00253 
00254 void
00255 Player::set_speedlimit(float newlimit)
00256 {
00257   speedlimit=newlimit;
00258 }
00259 
00260 void
00261 Player::set_controller(Controller* controller)
00262 {
00263   this->controller = controller;
00264 }
00265 
00266 void
00267 Player::set_winning()
00268 {
00269   if( ! is_winning() ){
00270     winning = true;
00271     invincible_timer.start(10000.0f);
00272   }
00273 }
00274 
00275 void 
00276 Player::use_scripting_controller(bool use_or_release)
00277 {
00278   if ((use_or_release == true) && (controller != scripting_controller.get())) {
00279     scripting_controller_old = get_controller();
00280     set_controller(scripting_controller.get());
00281   }
00282   if ((use_or_release == false) && (controller == scripting_controller.get())) {
00283     set_controller(scripting_controller_old);
00284     scripting_controller_old = 0;
00285   }
00286 }
00287 
00288 void 
00289 Player::do_scripting_controller(std::string control, bool pressed)
00290 {
00291   for(int i = 0; Controller::controlNames[i] != 0; ++i) {
00292     if(control == std::string(Controller::controlNames[i])) {
00293       scripting_controller->press(Controller::Control(i), pressed);
00294     }
00295   }
00296 }
00297 
00298 bool
00299 Player::adjust_height(float new_height)
00300 {
00301   Rectf bbox2 = bbox;
00302   bbox2.move(Vector(0, bbox.get_height() - new_height));
00303   bbox2.set_height(new_height);
00304 
00305 
00306   if(new_height > bbox.get_height()) {
00307     Rectf additional_space = bbox2;
00308     additional_space.set_height(new_height - bbox.get_height());
00309     if(!Sector::current()->is_free_of_statics(additional_space, this, true))
00310       return false;
00311   }
00312 
00313   // adjust bbox accordingly
00314   // note that we use members of moving_object for this, so we can run this during CD, too
00315   set_pos(bbox2.p1);
00316   set_size(bbox2.get_width(), bbox2.get_height());
00317   return true;
00318 }
00319 
00320 void
00321 Player::trigger_sequence(std::string sequence_name)
00322 {
00323   if (climbing) stop_climbing(*climbing);
00324   backflipping = false;
00325   backflip_direction = 0;
00326   GameSession::current()->start_sequence(sequence_name);
00327 }
00328 
00329 void
00330 Player::update(float elapsed_time)
00331 {
00332   if( no_water ){
00333     swimming = false;
00334   }
00335   no_water = true;
00336 
00337   if(dying && dying_timer.check()) {
00338     dead = true;
00339     return;
00340   }
00341 
00342   if(!dying && !deactivated)
00343     handle_input();
00344 
00345   // handle_input() calls apply_friction() when Tux is not walking, so we'll have to do this ourselves
00346   if (deactivated)
00347     apply_friction();
00348 
00349   // extend/shrink tux collision rectangle so that we fall through/walk over 1
00350   // tile holes
00351   if(fabsf(physic.get_velocity_x()) > MAX_WALK_XM) {
00352     set_width(RUNNING_TUX_WIDTH);
00353   } else {
00354     set_width(TUX_WIDTH);
00355   }
00356 
00357   // on downward slopes, adjust vertical velocity so tux walks smoothly down
00358   if (on_ground()) {
00359     if(floor_normal.y != 0) {
00360       if ((floor_normal.x * physic.get_velocity_x()) >= 0) {
00361         physic.set_velocity_y(250);
00362       }
00363     }
00364   }
00365 
00366   // handle backflipping
00367   if (backflipping) {
00368     //prevent player from changing direction when backflipping
00369     dir = (backflip_direction == 1) ? LEFT : RIGHT;
00370     if (backflip_timer.started()) physic.set_velocity_x(100 * backflip_direction);
00371   }
00372 
00373   // set fall mode...
00374   if(on_ground()) {
00375     fall_mode = ON_GROUND;
00376     last_ground_y = get_pos().y;
00377   } else {
00378     if(get_pos().y > last_ground_y)
00379       fall_mode = FALLING;
00380     else if(fall_mode == ON_GROUND)
00381       fall_mode = JUMPING;
00382   }
00383 
00384   // check if we landed
00385   if(on_ground()) {
00386     jumping = false;
00387     if (backflipping && (!backflip_timer.started())) {
00388       backflipping = false;
00389       backflip_direction = 0;
00390 
00391       // if controls are currently deactivated, we take care of standing up ourselves
00392       if (deactivated)
00393         do_standup();
00394     }
00395   }
00396 
00397   // calculate movement for this frame
00398   movement = physic.get_movement(elapsed_time);
00399 
00400   if(grabbed_object != NULL && !dying) {
00401     position_grabbed_object();
00402   }
00403 
00404   if(grabbed_object != NULL && dying){
00405     grabbed_object->ungrab(*this, dir);
00406     grabbed_object = NULL;
00407   }
00408 
00409   if(!ice_this_frame && on_ground())
00410     on_ice = false;
00411 
00412   on_ground_flag = false;
00413   ice_this_frame = false;
00414 
00415   // when invincible, spawn particles
00416   if (invincible_timer.started())
00417   {
00418     if (graphicsRandom.rand(0, 2) == 0) {
00419       float px = graphicsRandom.randf(bbox.p1.x+0, bbox.p2.x-0);
00420       float py = graphicsRandom.randf(bbox.p1.y+0, bbox.p2.y-0);
00421       Vector ppos = Vector(px, py);
00422       Vector pspeed = Vector(0, 0);
00423       Vector paccel = Vector(0, 0);
00424       Sector::current()->add_object(new SpriteParticle("images/objects/particles/sparkle.sprite", 
00425                                                        // draw bright sparkle when there is lots of time left, dark sparkle when invincibility is about to end
00426                                                        (invincible_timer.get_timeleft() > TUX_INVINCIBLE_TIME_WARNING) ?
00427                                                        // make every other a longer sparkle to make trail a bit fuzzy
00428                                                        (size_t(game_time*20)%2) ? "small" : "medium"
00429                                                        :
00430                                                        "dark", ppos, ANCHOR_MIDDLE, pspeed, paccel, LAYER_OBJECTS+1+5));
00431     }
00432   }
00433 
00434   if (growing) {
00435     if (sprite->animation_done()) growing = false;
00436   }
00437 
00438 }
00439 
00440 bool
00441 Player::on_ground()
00442 {
00443   return on_ground_flag;
00444 }
00445 
00446 bool
00447 Player::is_big()
00448 {
00449   if(player_status->bonus == NO_BONUS)
00450     return false;
00451 
00452   return true;
00453 }
00454 
00455 void
00456 Player::apply_friction()
00457 {
00458   if ((on_ground()) && (fabs(physic.get_velocity_x()) < WALK_SPEED)) {
00459     physic.set_velocity_x(0);
00460     physic.set_acceleration_x(0);
00461   } else {
00462     float friction = WALK_ACCELERATION_X * (on_ice ? ICE_FRICTION_MULTIPLIER : NORMAL_FRICTION_MULTIPLIER);
00463     if(physic.get_velocity_x() < 0) {
00464       physic.set_acceleration_x(friction);
00465     } else if(physic.get_velocity_x() > 0) {
00466       physic.set_acceleration_x(-friction);
00467     } // no friction for physic.get_velocity_x() == 0
00468   }
00469 }
00470 
00471 void
00472 Player::handle_horizontal_input()
00473 {
00474   float vx = physic.get_velocity_x();
00475   float vy = physic.get_velocity_y();
00476   float ax = physic.get_acceleration_x();
00477   float ay = physic.get_acceleration_y();
00478 
00479   float dirsign = 0;
00480   if(!duck || physic.get_velocity_y() != 0) {
00481     if(controller->hold(Controller::LEFT) && !controller->hold(Controller::RIGHT)) {
00482       old_dir = dir;
00483       dir = LEFT;
00484       dirsign = -1;
00485     } else if(!controller->hold(Controller::LEFT)
00486               && controller->hold(Controller::RIGHT)) {
00487       old_dir = dir;
00488       dir = RIGHT;
00489       dirsign = 1;
00490     }
00491   }
00492 
00493   // do not run if we're holding something which slows us down
00494   if ( grabbed_object && grabbed_object->is_hampering() ) {
00495     ax = dirsign * WALK_ACCELERATION_X;
00496     // limit speed
00497     if(vx >= MAX_WALK_XM && dirsign > 0) {
00498       vx = MAX_WALK_XM;
00499       ax = 0;
00500     } else if(vx <= -MAX_WALK_XM && dirsign < 0) {
00501       vx = -MAX_WALK_XM;
00502       ax = 0;
00503     }
00504   } else {
00505     if( vx * dirsign < MAX_WALK_XM ) {
00506       ax = dirsign * WALK_ACCELERATION_X;
00507     } else {
00508       ax = dirsign * RUN_ACCELERATION_X;
00509     }
00510     // limit speed
00511     if(vx >= MAX_RUN_XM && dirsign > 0) {
00512       vx = MAX_RUN_XM;
00513       ax = 0;
00514     } else if(vx <= -MAX_RUN_XM && dirsign < 0) {
00515       vx = -MAX_RUN_XM;
00516       ax = 0;
00517     }
00518   }
00519 
00520   // we can reach WALK_SPEED without any acceleration
00521   if(dirsign != 0 && fabs(vx) < WALK_SPEED) {
00522     vx = dirsign * WALK_SPEED;
00523   }
00524 
00525   //Check speedlimit.
00526   if( speedlimit > 0 &&  vx * dirsign >= speedlimit ) {
00527     vx = dirsign * speedlimit;
00528     ax = 0;
00529   }
00530 
00531   // changing directions?
00532   if(on_ground() && ((vx < 0 && dirsign >0) || (vx>0 && dirsign<0))) {
00533     // let's skid!
00534     if(fabs(vx)>SKID_XM && !skidding_timer.started()) {
00535       skidding_timer.start(SKID_TIME);
00536       sound_manager->play("sounds/skid.wav");
00537       // dust some particles
00538       Sector::current()->add_object(
00539         new Particles(
00540           Vector(dir == RIGHT ? get_bbox().p2.x : get_bbox().p1.x, get_bbox().p2.y),
00541           dir == RIGHT ? 270+20 : 90-40, dir == RIGHT ? 270+40 : 90-20,
00542           Vector(280, -260), Vector(0, 300), 3, Color(.4f, .4f, .4f), 3, .8f,
00543           LAYER_OBJECTS+1));
00544 
00545       ax *= 2.5;
00546     } else {
00547       ax *= 2;
00548     }
00549   }
00550 
00551   if(on_ice) {
00552     ax *= ICE_ACCELERATION_MULTIPLIER;
00553   }
00554 
00555   physic.set_velocity(vx, vy);
00556   physic.set_acceleration(ax, ay);
00557 
00558   // we get slower when not pressing any keys
00559   if(dirsign == 0) {
00560     apply_friction();
00561   }
00562 
00563 }
00564 
00565 void
00566 Player::do_cheer()
00567 {
00568   do_duck();
00569   do_backflip();
00570   do_standup();
00571 }
00572 
00573 void
00574 Player::do_duck() {
00575   if (duck)
00576     return;
00577   if (!is_big())
00578     return;
00579 
00580   if (physic.get_velocity_y() != 0)
00581     return;
00582   if (!on_ground())
00583     return;
00584   if (does_buttjump)
00585     return;
00586 
00587   if (adjust_height(DUCKED_TUX_HEIGHT)) {
00588     duck = true;
00589     growing = false;
00590     unduck_hurt_timer.stop();
00591   } else {
00592     // FIXME: what now?
00593   }
00594 }
00595 
00596 void
00597 Player::do_standup() {
00598   if (!duck)
00599     return;
00600   if (!is_big())
00601     return;
00602   if (backflipping)
00603     return;
00604 
00605   if (adjust_height(BIG_TUX_HEIGHT)) {
00606     duck = false;
00607     unduck_hurt_timer.stop();
00608   } else {
00609     // if timer is not already running, start it.
00610     if (unduck_hurt_timer.get_period() == 0) {
00611       unduck_hurt_timer.start(UNDUCK_HURT_TIME);
00612     }
00613     else if (unduck_hurt_timer.check()) {
00614       kill(false);
00615     }
00616   }
00617 
00618 }
00619 
00620 void
00621 Player::do_backflip() {
00622   if (!duck)
00623     return;
00624   if (!on_ground())
00625     return;
00626 
00627   backflip_direction = (dir == LEFT)?(+1):(-1);
00628   backflipping = true;
00629   do_jump(-580);
00630   sound_manager->play("sounds/flip.wav");
00631   backflip_timer.start(0.15f);
00632 }
00633 
00634 void
00635 Player::do_jump(float yspeed) {
00636   if (!on_ground())
00637     return;
00638 
00639   physic.set_velocity_y(yspeed);
00640   //bbox.move(Vector(0, -1));
00641   jumping = true;
00642   on_ground_flag = false;
00643   can_jump = false;
00644 
00645   // play sound
00646   if (is_big()) {
00647     sound_manager->play("sounds/bigjump.wav");
00648   } else {
00649     sound_manager->play("sounds/jump.wav");
00650   }
00651 }
00652 
00653 void
00654 Player::early_jump_apex() 
00655 {
00656   if (!jump_early_apex)
00657   {
00658     jump_early_apex = true;
00659     physic.set_gravity_modifier(JUMP_EARLY_APEX_FACTOR);
00660   }
00661 }
00662 
00663 void
00664 Player::do_jump_apex()
00665 {
00666   if (jump_early_apex)
00667   {
00668     jump_early_apex = false;
00669     physic.set_gravity_modifier(1.0f);
00670   }
00671 }
00672 
00673 void
00674 Player::handle_vertical_input()
00675 {
00676   // Press jump key
00677   if(controller->pressed(Controller::JUMP)) jump_button_timer.start(JUMP_GRACE_TIME);
00678   if(controller->hold(Controller::JUMP) && jump_button_timer.started() && can_jump) {
00679     jump_button_timer.stop();
00680     if (duck) {
00681       // when running, only jump a little bit; else do a backflip
00682       if ((physic.get_velocity_x() != 0) || 
00683           (controller->hold(Controller::LEFT)) || 
00684           (controller->hold(Controller::RIGHT))) 
00685       {
00686         do_jump(-300);
00687       }
00688       else 
00689       {
00690         do_backflip();
00691       }
00692     } else {
00693       // jump a bit higher if we are running; else do a normal jump
00694       if (fabs(physic.get_velocity_x()) > MAX_WALK_XM) do_jump(-580); else do_jump(-520);
00695     }
00696   }
00697   // Let go of jump key
00698   else if(!controller->hold(Controller::JUMP)) {
00699     if (!backflipping && jumping && physic.get_velocity_y() < 0) {
00700       jumping = false;
00701       early_jump_apex();
00702     }
00703   }
00704 
00705   if(jump_early_apex && physic.get_velocity_y() >= 0) {
00706     do_jump_apex();
00707   }
00708 
00709   /* In case the player has pressed Down while in a certain range of air,
00710      enable butt jump action */
00711   if (controller->hold(Controller::DOWN) && !duck && is_big() && !on_ground()) {
00712     wants_buttjump = true;
00713     if (physic.get_velocity_y() >= BUTTJUMP_MIN_VELOCITY_Y) does_buttjump = true;
00714   }
00715 
00716   /* When Down is not held anymore, disable butt jump */
00717   if(!controller->hold(Controller::DOWN)) {
00718     wants_buttjump = false;
00719     does_buttjump = false;
00720   }
00721 
00722   // swimming
00723   physic.set_acceleration_y(0);
00724 #ifdef SWIMMING
00725   if (swimming) {
00726     if (controller->hold(Controller::UP) || controller->hold(Controller::JUMP))
00727       physic.set_acceleration_y(-2000);
00728     physic.set_velocity_y(physic.get_velocity_y() * 0.94);
00729   }
00730 #endif
00731 }
00732 
00733 void
00734 Player::handle_input()
00735 {
00736   if (ghost_mode) {
00737     handle_input_ghost();
00738     return;
00739   }
00740   if (climbing) {
00741     handle_input_climbing();
00742     return;
00743   }
00744 
00745   /* Peeking */
00746   if( controller->released( Controller::PEEK_LEFT ) || controller->released( Controller::PEEK_RIGHT ) ) {
00747     peekingX = AUTO;
00748   }
00749   if( controller->released( Controller::PEEK_UP ) || controller->released( Controller::PEEK_DOWN ) ) {
00750     peekingY = AUTO;
00751   }
00752   if( controller->pressed( Controller::PEEK_LEFT ) ) {
00753     peekingX = LEFT;
00754   }
00755   if( controller->pressed( Controller::PEEK_RIGHT ) ) {
00756     peekingX = RIGHT;
00757   }
00758   if(!backflipping && !jumping && on_ground()) {
00759     if( controller->pressed( Controller::PEEK_UP ) ) {
00760       peekingY = UP;
00761     } else if( controller->pressed( Controller::PEEK_DOWN ) ) {
00762       peekingY = DOWN;
00763     }
00764   }
00765 
00766   /* Handle horizontal movement: */
00767   if (!backflipping) handle_horizontal_input();
00768 
00769   /* Jump/jumping? */
00770   if (on_ground())
00771     can_jump = true;
00772 
00773   /* Handle vertical movement: */
00774   handle_vertical_input();
00775 
00776   /* Shoot! */
00777   if (controller->pressed(Controller::ACTION) && (player_status->bonus == FIRE_BONUS || player_status->bonus == ICE_BONUS)) {
00778     if(Sector::current()->add_bullet(
00779          get_pos() + ((dir == LEFT)? Vector(0, bbox.get_height()/2)
00780                       : Vector(32, bbox.get_height()/2)),
00781          player_status,
00782          physic.get_velocity_x(), dir))
00783       shooting_timer.start(SHOOTING_TIME);
00784   }
00785 
00786   /* Duck or Standup! */
00787   if (controller->hold(Controller::DOWN)) {
00788     do_duck();
00789   } else {
00790     do_standup();
00791   }
00792 
00793   /* grabbing */
00794   try_grab();
00795 
00796   if(!controller->hold(Controller::ACTION) && grabbed_object) {
00797     MovingObject* moving_object = dynamic_cast<MovingObject*> (grabbed_object);
00798     if(moving_object) {
00799       // move the grabbed object a bit away from tux
00800       Rectf grabbed_bbox = moving_object->get_bbox();
00801       Rectf dest;
00802       dest.p2.y = bbox.get_top() + bbox.get_height()*0.66666;
00803       dest.p1.y = dest.p2.y - grabbed_bbox.get_height();
00804       if(dir == LEFT) {
00805         dest.p2.x = bbox.get_left() - 1;
00806         dest.p1.x = dest.p2.x - grabbed_bbox.get_width();
00807       } else {
00808         dest.p1.x = bbox.get_right() + 1;
00809         dest.p2.x = dest.p1.x + grabbed_bbox.get_width();
00810       }
00811       if(Sector::current()->is_free_of_movingstatics(dest)) {
00812         moving_object->set_pos(dest.p1);
00813         if(controller->hold(Controller::UP)) {
00814           grabbed_object->ungrab(*this, UP);
00815         } else {
00816           grabbed_object->ungrab(*this, dir);
00817         }
00818         grabbed_object = NULL;
00819       }
00820     } else {
00821       log_debug << "Non MovingObject grabbed?!?" << std::endl;
00822     }
00823   }
00824 }
00825 
00826 void
00827 Player::position_grabbed_object()
00828 {
00829   MovingObject* moving_object = dynamic_cast<MovingObject*>(grabbed_object);
00830   assert(moving_object);
00831 
00832   // Position where we will hold the lower-inner corner
00833   Vector pos(get_bbox().get_left() + get_bbox().get_width()/2,
00834       get_bbox().get_top() + get_bbox().get_height()*0.66666);
00835 
00836   // Adjust to find the grabbed object's upper-left corner
00837   if (dir == LEFT)
00838     pos.x -= moving_object->get_bbox().get_width();
00839   pos.y -= moving_object->get_bbox().get_height();
00840 
00841   grabbed_object->grab(*this, pos, dir);
00842 }
00843 
00844 void
00845 Player::try_grab()
00846 {
00847   if(controller->hold(Controller::ACTION) && !grabbed_object
00848      && !duck) {
00849     Sector* sector = Sector::current();
00850     Vector pos;
00851     if(dir == LEFT) {
00852       pos = Vector(bbox.get_left() - 5, bbox.get_bottom() - 16);
00853     } else {
00854       pos = Vector(bbox.get_right() + 5, bbox.get_bottom() - 16);
00855     }
00856 
00857     for(Sector::Portables::iterator i = sector->portables.begin();
00858         i != sector->portables.end(); ++i) {
00859       Portable* portable = *i;
00860       if(!portable->is_portable())
00861         continue;
00862 
00863       // make sure the Portable is a MovingObject
00864       MovingObject* moving_object = dynamic_cast<MovingObject*> (portable);
00865       assert(moving_object);
00866       if(moving_object == NULL)
00867         continue;
00868 
00869       // make sure the Portable isn't currently non-solid
00870       if(moving_object->get_group() == COLGROUP_DISABLED) continue;
00871 
00872       // check if we are within reach
00873       if(moving_object->get_bbox().contains(pos)) {
00874         if (climbing) stop_climbing(*climbing);
00875         grabbed_object = portable;
00876         position_grabbed_object();
00877         break;
00878       }
00879     }
00880   }
00881 }
00882 
00883 void
00884 Player::handle_input_ghost()
00885 {
00886   float vx = 0;
00887   float vy = 0;
00888   if (controller->hold(Controller::LEFT)) {
00889     dir = LEFT;
00890     vx -= MAX_RUN_XM * 2;
00891   }
00892   if (controller->hold(Controller::RIGHT)) {
00893     dir = RIGHT;
00894     vx += MAX_RUN_XM * 2;
00895   }
00896   if ((controller->hold(Controller::UP)) || (controller->hold(Controller::JUMP))) {
00897     vy -= MAX_RUN_XM * 2;
00898   }
00899   if (controller->hold(Controller::DOWN)) {
00900     vy += MAX_RUN_XM * 2;
00901   }
00902   if (controller->hold(Controller::ACTION)) {
00903     set_ghost_mode(false);
00904   }
00905   physic.set_velocity(vx, vy);
00906   physic.set_acceleration(0, 0);
00907 }
00908 
00909 void
00910 Player::add_coins(int count)
00911 {
00912   player_status->add_coins(count);
00913 }
00914 
00915 int
00916 Player::get_coins()
00917 {
00918   return player_status->coins;
00919 }
00920 
00921 bool
00922 Player::add_bonus(const std::string& bonustype)
00923 {
00924   BonusType type = NO_BONUS;
00925 
00926   if(bonustype == "grow") {
00927     type = GROWUP_BONUS;
00928   } else if(bonustype == "fireflower") {
00929     type = FIRE_BONUS;
00930   } else if(bonustype == "iceflower") {
00931     type = ICE_BONUS;
00932   } else if(bonustype == "none") {
00933     type = NO_BONUS;
00934   } else {
00935     std::ostringstream msg;
00936     msg << "Unknown bonus type "  << bonustype;
00937     throw std::runtime_error(msg.str());
00938   }
00939 
00940   return add_bonus(type);
00941 }
00942 
00943 bool
00944 Player::add_bonus(BonusType type, bool animate)
00945 {
00946   // always ignore NO_BONUS
00947   if (type == NO_BONUS) {
00948     return true;
00949   }
00950 
00951   // ignore GROWUP_BONUS if we're already big
00952   if (type == GROWUP_BONUS) {
00953     if (player_status->bonus == GROWUP_BONUS)
00954       return true;
00955     if (player_status->bonus == FIRE_BONUS)
00956       return true;
00957     if (player_status->bonus == ICE_BONUS)
00958       return true;
00959   }
00960 
00961   return set_bonus(type, animate);
00962 }
00963 
00964 bool
00965 Player::set_bonus(BonusType type, bool animate)
00966 {
00967   if((player_status->bonus == NO_BONUS) && (type != NO_BONUS)) {
00968     if (!adjust_height(BIG_TUX_HEIGHT)) {
00969       printf("can't adjust\n");
00970       return false;
00971     }
00972     if(animate) {
00973       growing = true;
00974       sprite->set_action((dir == LEFT)?"grow-left":"grow-right", 1);
00975     }
00976     if (climbing) stop_climbing(*climbing);
00977   }
00978 
00979   if (type == NO_BONUS) {
00980     if (does_buttjump) does_buttjump = false;
00981   }
00982 
00983   if ((type == NO_BONUS) || (type == GROWUP_BONUS)) {
00984     if ((player_status->bonus == FIRE_BONUS) && (animate)) {
00985       // visually lose helmet
00986       Vector ppos = Vector((bbox.p1.x + bbox.p2.x) / 2, bbox.p1.y);
00987       Vector pspeed = Vector(((dir==LEFT) ? +100 : -100), -300);
00988       Vector paccel = Vector(0, 1000);
00989       std::string action = (dir==LEFT)?"left":"right";
00990       Sector::current()->add_object(new SpriteParticle("images/objects/particles/firetux-helmet.sprite", action, ppos, ANCHOR_TOP, pspeed, paccel, LAYER_OBJECTS-1));
00991       if (climbing) stop_climbing(*climbing);
00992     }
00993     if ((player_status->bonus == ICE_BONUS) && (animate)) {
00994       // visually lose cap
00995       Vector ppos = Vector((bbox.p1.x + bbox.p2.x) / 2, bbox.p1.y);
00996       Vector pspeed = Vector(((dir==LEFT) ? +100 : -100), -300);
00997       Vector paccel = Vector(0, 1000);
00998       std::string action = (dir==LEFT)?"left":"right";
00999       Sector::current()->add_object(new SpriteParticle("images/objects/particles/icetux-cap.sprite", action, ppos, ANCHOR_TOP, pspeed, paccel, LAYER_OBJECTS-1));
01000       if (climbing) stop_climbing(*climbing);
01001     }
01002     player_status->max_fire_bullets = 0;
01003     player_status->max_ice_bullets = 0;
01004   }
01005   if (type == FIRE_BONUS) player_status->max_fire_bullets++;
01006   if (type == ICE_BONUS) player_status->max_ice_bullets++;
01007 
01008   player_status->bonus = type;
01009   return true;
01010 }
01011 
01012 void
01013 Player::set_visible(bool visible)
01014 {
01015   this->visible = visible;
01016   if( visible )
01017     set_group(COLGROUP_MOVING);
01018   else
01019     set_group(COLGROUP_DISABLED);
01020 }
01021 
01022 bool
01023 Player::get_visible()
01024 {
01025   return visible;
01026 }
01027 
01028 void
01029 Player::kick()
01030 {
01031   kick_timer.start(KICK_TIME);
01032 }
01033 
01034 void
01035 Player::draw(DrawingContext& context)
01036 {
01037   if(!visible)
01038     return;
01039 
01040   // if Tux is above camera, draw little "air arrow" to show where he is x-wise
01041   if (Sector::current() && Sector::current()->camera && (get_bbox().p2.y - 16 < Sector::current()->camera->get_translation().y)) {
01042     float px = get_pos().x + (get_bbox().p2.x - get_bbox().p1.x - airarrow.get()->get_width()) / 2;
01043     float py = Sector::current()->camera->get_translation().y;
01044     py += std::min(((py - (get_bbox().p2.y + 16)) / 4), 16.0f);
01045     context.draw_surface(airarrow, Vector(px, py), LAYER_HUD - 1);
01046   }
01047 
01048   std::string sa_prefix = "";
01049   std::string sa_postfix = "";
01050 
01051   if (player_status->bonus == GROWUP_BONUS)
01052     sa_prefix = "big";
01053   else if (player_status->bonus == FIRE_BONUS)
01054     sa_prefix = "fire";
01055   else if (player_status->bonus == ICE_BONUS)
01056     sa_prefix = "ice";
01057   else
01058     sa_prefix = "small";
01059 
01060   if(dir == LEFT)
01061     sa_postfix = "-left";
01062   else
01063     sa_postfix = "-right";
01064 
01065   /* Set Tux sprite action */
01066   if(dying) {
01067     sprite->set_action("gameover");
01068   }
01069   else if (growing) {
01070     sprite->set_action_continued("grow"+sa_postfix);
01071     // while growing, do not change action
01072     // do_duck() will take care of cancelling growing manually
01073     // update() will take care of cancelling when growing completed
01074   }
01075   else if (climbing) {
01076     sprite->set_action(sa_prefix+"-skid"+sa_postfix);
01077   }
01078   else if (backflipping) {
01079     sprite->set_action(sa_prefix+"-backflip"+sa_postfix);
01080   }
01081   else if (duck && is_big()) {
01082     sprite->set_action(sa_prefix+"-duck"+sa_postfix);
01083   }
01084   else if (skidding_timer.started() && !skidding_timer.check()) {
01085     sprite->set_action(sa_prefix+"-skid"+sa_postfix);
01086   }
01087   else if (kick_timer.started() && !kick_timer.check()) {
01088     sprite->set_action(sa_prefix+"-kick"+sa_postfix);
01089   }
01090   else if ((wants_buttjump || does_buttjump) && is_big()) {
01091     sprite->set_action(sa_prefix+"-buttjump"+sa_postfix);
01092   }
01093   else if (!on_ground()) {
01094     sprite->set_action(sa_prefix+"-jump"+sa_postfix);
01095   }
01096   else {
01097     if (fabsf(physic.get_velocity_x()) < 1.0f) {
01098       // Determine which idle stage we're at
01099       if (sprite->get_action().find("-stand-") == std::string::npos && sprite->get_action().find("-idle-") == std::string::npos) {
01100         idle_stage = 0;
01101         idle_timer.start(IDLE_TIME[idle_stage]/1000.0f);
01102 
01103         sprite->set_action_continued(sa_prefix+("-" + IDLE_STAGES[idle_stage])+sa_postfix);
01104       }
01105       else if (idle_timer.check() || (IDLE_TIME[idle_stage] == 0 && sprite->animation_done())) {
01106         idle_stage++;
01107         if (idle_stage >= IDLE_STAGE_COUNT)
01108           idle_stage = 1;
01109 
01110         idle_timer.start(IDLE_TIME[idle_stage]/1000.0f);
01111 
01112         if (IDLE_TIME[idle_stage] == 0)
01113           sprite->set_action(sa_prefix+("-" + IDLE_STAGES[idle_stage])+sa_postfix, 1);
01114         else
01115           sprite->set_action(sa_prefix+("-" + IDLE_STAGES[idle_stage])+sa_postfix);
01116       }
01117       else {
01118         sprite->set_action_continued(sa_prefix+("-" + IDLE_STAGES[idle_stage])+sa_postfix);
01119       }
01120     }
01121     else {
01122       sprite->set_action(sa_prefix+"-walk"+sa_postfix);
01123     }
01124   }
01125 
01126   /*
01127   // Tux is holding something
01128   if ((grabbed_object != 0 && physic.get_velocity_y() == 0) ||
01129   (shooting_timer.get_timeleft() > 0 && !shooting_timer.check())) {
01130   if (duck) {
01131   } else {
01132   }
01133   }
01134   */
01135 
01136   /* Draw Tux */
01137   if (safe_timer.started() && size_t(game_time*40)%2)
01138     ;  // don't draw Tux
01139   else {
01140     sprite->draw(context, get_pos(), LAYER_OBJECTS + 1);
01141   }
01142 
01143 }
01144 
01145 void
01146 Player::collision_tile(uint32_t tile_attributes)
01147 {
01148   if(tile_attributes & Tile::HURTS)
01149     kill(false);
01150 
01151 #ifdef SWIMMING
01152   if( swimming ){
01153     if( tile_attributes & Tile::WATER ){
01154       no_water = false;
01155     } else {
01156       swimming = false;
01157     }
01158   } else {
01159     if( tile_attributes & Tile::WATER ){
01160       swimming = true;
01161       no_water = false;
01162       sound_manager->play( "sounds/splash.ogg" );
01163     }
01164   }
01165 #endif
01166 
01167   if(tile_attributes & Tile::ICE) {
01168     ice_this_frame = true;
01169     on_ice = true;
01170   }
01171 }
01172 
01173 void
01174 Player::collision_solid(const CollisionHit& hit)
01175 {
01176   if(hit.bottom) {
01177     if(physic.get_velocity_y() > 0)
01178       physic.set_velocity_y(0);
01179 
01180     on_ground_flag = true;
01181     floor_normal = hit.slope_normal;
01182 
01183     // Butt Jump landed    
01184     if (does_buttjump) {
01185       does_buttjump = false;
01186       physic.set_velocity_y(-300);
01187       on_ground_flag = false;
01188       Sector::current()->add_object(new Particles(
01189                                       Vector(get_bbox().p2.x, get_bbox().p2.y),
01190                                       270+20, 270+40,
01191                                       Vector(280, -260), Vector(0, 300), 3, Color(.4f, .4f, .4f), 3, .8f,
01192                                       LAYER_OBJECTS+1));
01193       Sector::current()->add_object(new Particles(
01194                                       Vector(get_bbox().p1.x, get_bbox().p2.y),
01195                                       90-40, 90-20,
01196                                       Vector(280, -260), Vector(0, 300), 3, Color(.4f, .4f, .4f), 3, .8f,
01197                                       LAYER_OBJECTS+1));
01198       Sector::current()->camera->shake(.1f, 0, 5);
01199     }
01200 
01201   } else if(hit.top) {
01202     if(physic.get_velocity_y() < 0)
01203       physic.set_velocity_y(.2f);
01204   }
01205 
01206   if(hit.left || hit.right) {
01207     physic.set_velocity_x(0);
01208   }
01209 
01210   // crushed?
01211   if(hit.crush) {
01212     if(hit.left || hit.right) {
01213       kill(true);
01214     } else if(hit.top || hit.bottom) {
01215       kill(false);
01216     }
01217   }
01218 }
01219 
01220 HitResponse
01221 Player::collision(GameObject& other, const CollisionHit& hit)
01222 {
01223   Bullet* bullet = dynamic_cast<Bullet*> (&other);
01224   if(bullet) {
01225     return FORCE_MOVE;
01226   }
01227 
01228   Player* player = dynamic_cast<Player*> (&other);
01229   if(player) {
01230     return ABORT_MOVE;
01231   }
01232 
01233   if(hit.left || hit.right) {
01234     try_grab(); //grab objects right now, in update it will be too late
01235   }
01236   assert(dynamic_cast<MovingObject*> (&other) != NULL);
01237   MovingObject* moving_object = static_cast<MovingObject*> (&other);
01238   if(moving_object->get_group() == COLGROUP_TOUCHABLE) {
01239     TriggerBase* trigger = dynamic_cast<TriggerBase*> (&other);
01240     if(trigger) {
01241       if(controller->pressed(Controller::UP))
01242         trigger->event(*this, TriggerBase::EVENT_ACTIVATE);
01243     }
01244 
01245     return FORCE_MOVE;
01246   }
01247 
01248   BadGuy* badguy = dynamic_cast<BadGuy*> (&other);
01249   if(badguy != NULL) {
01250     if(safe_timer.started() || invincible_timer.started())
01251       return FORCE_MOVE;
01252 
01253     return CONTINUE;
01254   }
01255 
01256   return CONTINUE;
01257 }
01258 
01259 void
01260 Player::make_invincible()
01261 {
01262   sound_manager->play("sounds/invincible_start.ogg");
01263   invincible_timer.start(TUX_INVINCIBLE_TIME);
01264   Sector::current()->play_music(HERRING_MUSIC);
01265 }
01266 
01267 /* Kill Player! */
01268 void
01269 Player::kill(bool completely)
01270 {
01271   if(dying || deactivated || is_winning() )
01272     return;
01273 
01274   if(!completely && (safe_timer.started() || invincible_timer.started()))
01275     return;
01276 
01277   growing = false;
01278 
01279   if (climbing) stop_climbing(*climbing);
01280 
01281   physic.set_velocity_x(0);
01282 
01283   if(!completely && is_big()) {
01284     sound_manager->play("sounds/hurt.wav");
01285 
01286     if(player_status->bonus == FIRE_BONUS
01287        || player_status->bonus == ICE_BONUS) {
01288       safe_timer.start(TUX_SAFE_TIME);
01289       set_bonus(GROWUP_BONUS, true);
01290     } else if(player_status->bonus == GROWUP_BONUS) {
01291       safe_timer.start(TUX_SAFE_TIME /* + GROWING_TIME */);
01292       adjust_height(SMALL_TUX_HEIGHT);
01293       duck = false;
01294       backflipping = false;
01295       set_bonus(NO_BONUS, true);
01296     } else if(player_status->bonus == NO_BONUS) {
01297       safe_timer.start(TUX_SAFE_TIME);
01298       adjust_height(SMALL_TUX_HEIGHT);
01299       duck = false;
01300     }
01301   } else {
01302     sound_manager->play("sounds/kill.wav");
01303 
01304     // do not die when in edit mode
01305     if (edit_mode) {
01306       set_ghost_mode(true);
01307       return;
01308     }
01309 
01310     physic.enable_gravity(true);
01311     physic.set_gravity_modifier(1.0f); // Undo jump_early_apex
01312     safe_timer.stop();
01313     invincible_timer.stop();
01314     physic.set_acceleration(0, 0);
01315     physic.set_velocity(0, -700);
01316     set_bonus(NO_BONUS, true);
01317     dying = true;
01318     dying_timer.start(3.0);
01319     set_group(COLGROUP_DISABLED);
01320 
01321     // TODO: need nice way to handle players dying in co-op mode
01322     Sector::current()->effect->fade_out(3.0);
01323     sound_manager->stop_music(3.0);
01324   }
01325 }
01326 
01327 void
01328 Player::move(const Vector& vector)
01329 {
01330   set_pos(vector);
01331 
01332   // Reset size to get correct hitbox if Tux was eg. ducked before moving
01333   if(is_big())
01334     set_size(TUX_WIDTH, BIG_TUX_HEIGHT);
01335   else
01336     set_size(TUX_WIDTH, SMALL_TUX_HEIGHT);
01337   duck = false;
01338   backflipping = false;
01339   last_ground_y = vector.y;
01340   if (climbing) stop_climbing(*climbing);
01341 
01342   physic.reset();
01343 }
01344 
01345 void
01346 Player::check_bounds()
01347 {
01348   /* Keep tux in sector bounds: */
01349   if (get_pos().x < 0) {
01350     // Lock Tux to the size of the level, so that he doesn't fall off
01351     // the left side
01352     set_pos(Vector(0, get_pos().y));
01353   }
01354 
01355   if (get_bbox().get_right() > Sector::current()->get_width()) {
01356     // Lock Tux to the size of the level, so that he doesn't fall off
01357     // the right side
01358     set_pos(Vector(Sector::current()->get_width() - get_bbox().get_width(), get_pos().y));
01359   }
01360 
01361   /* fallen out of the level? */
01362   if ((get_pos().y > Sector::current()->get_height()) && (!ghost_mode)) {
01363     kill(true);
01364     return;
01365   }
01366 }
01367 
01368 void
01369 Player::add_velocity(const Vector& velocity)
01370 {
01371   physic.set_velocity(physic.get_velocity() + velocity);
01372 }
01373 
01374 void
01375 Player::add_velocity(const Vector& velocity, const Vector& end_speed)
01376 {
01377   if (end_speed.x > 0)
01378     physic.set_velocity_x(std::min(physic.get_velocity_x() + velocity.x, end_speed.x));
01379   if (end_speed.x < 0)
01380     physic.set_velocity_x(std::max(physic.get_velocity_x() + velocity.x, end_speed.x));
01381   if (end_speed.y > 0)
01382     physic.set_velocity_y(std::min(physic.get_velocity_y() + velocity.y, end_speed.y));
01383   if (end_speed.y < 0)
01384     physic.set_velocity_y(std::max(physic.get_velocity_y() + velocity.y, end_speed.y));
01385 }
01386 
01387 Vector 
01388 Player::get_velocity()
01389 {
01390   return physic.get_velocity();
01391 }
01392 
01393 void
01394 Player::bounce(BadGuy& )
01395 {
01396   if(controller->hold(Controller::JUMP))
01397     physic.set_velocity_y(-520);
01398   else
01399     physic.set_velocity_y(-300);
01400 }
01401 
01402 //scripting Functions Below
01403 
01404 void
01405 Player::deactivate()
01406 {
01407   if (deactivated)
01408     return;
01409   deactivated = true;
01410   physic.set_velocity_x(0);
01411   physic.set_velocity_y(0);
01412   physic.set_acceleration_x(0);
01413   physic.set_acceleration_y(0);
01414   if (climbing) stop_climbing(*climbing);
01415 }
01416 
01417 void
01418 Player::activate()
01419 {
01420   if (!deactivated)
01421     return;
01422   deactivated = false;
01423 }
01424 
01425 void Player::walk(float speed)
01426 {
01427   physic.set_velocity_x(speed);
01428 }
01429 
01430 void
01431 Player::set_ghost_mode(bool enable)
01432 {
01433   if (ghost_mode == enable)
01434     return;
01435 
01436   if (climbing) stop_climbing(*climbing);
01437 
01438   if (enable) {
01439     ghost_mode = true;
01440     set_group(COLGROUP_DISABLED);
01441     physic.enable_gravity(false);
01442     log_debug << "You feel lightheaded. Use movement controls to float around, press ACTION to scare badguys." << std::endl;
01443   } else {
01444     ghost_mode = false;
01445     set_group(COLGROUP_MOVING);
01446     physic.enable_gravity(true);
01447     log_debug << "You feel solid again." << std::endl;
01448   }
01449 }
01450 
01451 void
01452 Player::set_edit_mode(bool enable)
01453 {
01454   edit_mode = enable;
01455 }
01456 
01457 void 
01458 Player::start_climbing(Climbable& climbable)
01459 {
01460   if (climbing == &climbable) return;
01461 
01462   climbing = &climbable;
01463   physic.enable_gravity(false);
01464   physic.set_velocity(0, 0);
01465   physic.set_acceleration(0, 0);
01466 }
01467 
01468 void 
01469 Player::stop_climbing(Climbable& /*climbable*/)
01470 {
01471   if (!climbing) return;
01472 
01473   climbing = 0;
01474 
01475   if (grabbed_object) {    
01476     grabbed_object->ungrab(*this, dir);
01477     grabbed_object = NULL;
01478   }
01479 
01480   physic.enable_gravity(true);
01481   physic.set_velocity(0, 0);
01482   physic.set_acceleration(0, 0);
01483 
01484   if ((controller->hold(Controller::JUMP)) || (controller->hold(Controller::UP))) {
01485     on_ground_flag = true;
01486     // TODO: This won't help. Why?
01487     do_jump(-300);
01488   }
01489 }
01490 
01491 void
01492 Player::handle_input_climbing()
01493 {
01494   if (!climbing) {
01495     log_warning << "handle_input_climbing called with climbing set to 0. Input handling skipped" << std::endl;
01496     return;
01497   }
01498 
01499   float vx = 0;
01500   float vy = 0;
01501   if (controller->hold(Controller::LEFT)) {
01502     dir = LEFT;
01503     vx -= MAX_CLIMB_XM;
01504   }
01505   if (controller->hold(Controller::RIGHT)) {
01506     dir = RIGHT;
01507     vx += MAX_CLIMB_XM;
01508   }
01509   if (controller->hold(Controller::UP)) {
01510     vy -= MAX_CLIMB_YM;
01511   }
01512   if (controller->hold(Controller::DOWN)) {
01513     vy += MAX_CLIMB_YM;
01514   }
01515   if (controller->hold(Controller::JUMP)) {
01516     if (can_jump) {
01517       stop_climbing(*climbing);
01518       return;
01519     }  
01520   } else {
01521     can_jump = true;
01522   }
01523   if (controller->hold(Controller::ACTION)) {
01524     stop_climbing(*climbing);
01525     return;
01526   }
01527   physic.set_velocity(vx, vy);
01528   physic.set_acceleration(0, 0);
01529 }
01530 
01531 /* EOF */

Generated on Mon Jun 9 03:38:20 2014 for SuperTux by  doxygen 1.5.1