00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
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
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
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
00165
00166
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;
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
00314
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
00346 if (deactivated)
00347 apply_friction();
00348
00349
00350
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
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
00367 if (backflipping) {
00368
00369 dir = (backflip_direction == 1) ? LEFT : RIGHT;
00370 if (backflip_timer.started()) physic.set_velocity_x(100 * backflip_direction);
00371 }
00372
00373
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
00385 if(on_ground()) {
00386 jumping = false;
00387 if (backflipping && (!backflip_timer.started())) {
00388 backflipping = false;
00389 backflip_direction = 0;
00390
00391
00392 if (deactivated)
00393 do_standup();
00394 }
00395 }
00396
00397
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
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
00426 (invincible_timer.get_timeleft() > TUX_INVINCIBLE_TIME_WARNING) ?
00427
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 }
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
00494 if ( grabbed_object && grabbed_object->is_hampering() ) {
00495 ax = dirsign * WALK_ACCELERATION_X;
00496
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
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
00521 if(dirsign != 0 && fabs(vx) < WALK_SPEED) {
00522 vx = dirsign * WALK_SPEED;
00523 }
00524
00525
00526 if( speedlimit > 0 && vx * dirsign >= speedlimit ) {
00527 vx = dirsign * speedlimit;
00528 ax = 0;
00529 }
00530
00531
00532 if(on_ground() && ((vx < 0 && dirsign >0) || (vx>0 && dirsign<0))) {
00533
00534 if(fabs(vx)>SKID_XM && !skidding_timer.started()) {
00535 skidding_timer.start(SKID_TIME);
00536 sound_manager->play("sounds/skid.wav");
00537
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
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
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
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
00641 jumping = true;
00642 on_ground_flag = false;
00643 can_jump = false;
00644
00645
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
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
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
00694 if (fabs(physic.get_velocity_x()) > MAX_WALK_XM) do_jump(-580); else do_jump(-520);
00695 }
00696 }
00697
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
00710
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
00717 if(!controller->hold(Controller::DOWN)) {
00718 wants_buttjump = false;
00719 does_buttjump = false;
00720 }
00721
00722
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
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
00767 if (!backflipping) handle_horizontal_input();
00768
00769
00770 if (on_ground())
00771 can_jump = true;
00772
00773
00774 handle_vertical_input();
00775
00776
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
00787 if (controller->hold(Controller::DOWN)) {
00788 do_duck();
00789 } else {
00790 do_standup();
00791 }
00792
00793
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
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
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
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
00864 MovingObject* moving_object = dynamic_cast<MovingObject*> (portable);
00865 assert(moving_object);
00866 if(moving_object == NULL)
00867 continue;
00868
00869
00870 if(moving_object->get_group() == COLGROUP_DISABLED) continue;
00871
00872
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
00947 if (type == NO_BONUS) {
00948 return true;
00949 }
00950
00951
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
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
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
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
01066 if(dying) {
01067 sprite->set_action("gameover");
01068 }
01069 else if (growing) {
01070 sprite->set_action_continued("grow"+sa_postfix);
01071
01072
01073
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
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
01128
01129
01130
01131
01132
01133
01134
01135
01136
01137 if (safe_timer.started() && size_t(game_time*40)%2)
01138 ;
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
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
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();
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
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 );
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
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);
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
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
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
01349 if (get_pos().x < 0) {
01350
01351
01352 set_pos(Vector(0, get_pos().y));
01353 }
01354
01355 if (get_bbox().get_right() > Sector::current()->get_width()) {
01356
01357
01358 set_pos(Vector(Sector::current()->get_width() - get_bbox().get_width(), get_pos().y));
01359 }
01360
01361
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
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& )
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
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