//#define SWIMMING
static const int TILES_FOR_BUTTJUMP = 3;
+static const float BUTTJUMP_MIN_VELOCITY_Y = 400.0f;
static const float SHOOTING_TIME = .150f;
/// time before idle animation starts
static const float IDLE_TIME = 2.5f;
/** acceleration in horizontal direction when walking
- * (all acceleratiosn are in pixel/s^2) */
+ * (all accelerations are in pixel/s^2) */
static const float WALK_ACCELERATION_X = 300;
/** acceleration in horizontal direction when running */
static const float RUN_ACCELERATION_X = 400;
static const float SKID_TIME = .3f;
/** maximum walk velocity (pixel/s) */
static const float MAX_WALK_XM = 230;
-/** maximum run velcoity (pixel/s) */
+/** maximum run velocity (pixel/s) */
static const float MAX_RUN_XM = 320;
/** maximum horizontal climb velocity */
static const float MAX_CLIMB_XM = 48;
/** if Tux cannot unduck for this long, he will get hurt */
static const float UNDUCK_HURT_TIME = 0.25f;
+/** gravity is higher after the jump key is released before
+ the apex of the jump is reached */
+static const float JUMP_EARLY_APEX_FACTOR = 3.0;
namespace{
bool no_water = true;
controller = main_controller;
scripting_controller = new CodeController();
sprite = sprite_manager->create("images/creatures/tux/tux.sprite");
- smalltux_gameover = sprite_manager->create("images/creatures/tux_small/smalltux-gameover.sprite");
- smalltux_star = sprite_manager->create("images/creatures/tux_small/smalltux-star.sprite");
- bigtux_star = sprite_manager->create("images/creatures/tux_big/bigtux-star.sprite");
airarrow.reset(new Surface("images/engine/hud/airarrow.png"));
sound_manager->preload("sounds/bigjump.wav");
sound_manager->preload("sounds/hurt.wav");
sound_manager->preload("sounds/skid.wav");
sound_manager->preload("sounds/flip.wav");
- sound_manager->preload("sounds/invincible.wav");
+ sound_manager->preload("sounds/invincible_start.ogg");
sound_manager->preload("sounds/splash.ogg");
- sound_manager->preload("sounds/shoot.wav");
init();
}
{
if (climbing) stop_climbing(*climbing);
delete sprite;
- delete smalltux_gameover;
- delete smalltux_star;
- delete bigtux_star;
delete scripting_controller;
}
dead = false;
dying = false;
- peeking = AUTO;
+ peekingX = AUTO;
+ peekingY = AUTO;
last_ground_y = 0;
fall_mode = ON_GROUND;
jumping = false;
+ jump_early_apex = false;
can_jump = true;
- butt_jump = false;
+ wants_buttjump = false;
+ does_buttjump = false;
growing = false;
deactivated = false;
backflipping = false;
Vector paccel = Vector(0, 0);
// draw bright sparkle when there is lots of time left, dark sparkle when invincibility is about to end
if (invincible_timer.get_timeleft() > TUX_INVINCIBLE_TIME_WARNING) {
- // make every other a longer sparkle to make trail a bit fuzzy
- if (size_t(game_time*20)%2) {
- Sector::current()->add_object(new SpriteParticle("images/objects/particles/sparkle.sprite", "small", ppos, ANCHOR_MIDDLE, pspeed, paccel, LAYER_OBJECTS+1+5));
- } else {
- Sector::current()->add_object(new SpriteParticle("images/objects/particles/sparkle.sprite", "medium", ppos, ANCHOR_MIDDLE, pspeed, paccel, LAYER_OBJECTS+1+5));
- }
+ // make every other a longer sparkle to make trail a bit fuzzy
+ if (size_t(game_time*20)%2) {
+ Sector::current()->add_object(new SpriteParticle("images/objects/particles/sparkle.sprite", "small", ppos, ANCHOR_MIDDLE, pspeed, paccel, LAYER_OBJECTS+1+5));
+ } else {
+ Sector::current()->add_object(new SpriteParticle("images/objects/particles/sparkle.sprite", "medium", ppos, ANCHOR_MIDDLE, pspeed, paccel, LAYER_OBJECTS+1+5));
+ }
} else {
Sector::current()->add_object(new SpriteParticle("images/objects/particles/sparkle.sprite", "dark", ppos, ANCHOR_MIDDLE, pspeed, paccel, LAYER_OBJECTS+1+5));
}
return;
if (!on_ground())
return;
+ if (does_buttjump)
+ return;
if (adjust_height(31.8f)) {
duck = true;
}
void
+Player::early_jump_apex() {
+ if(jump_early_apex) {
+ return;
+ }
+ jump_early_apex = true;
+ physic.set_gravity(physic.get_gravity() * JUMP_EARLY_APEX_FACTOR);
+};
+
+void
+Player::do_jump_apex() {
+ if(!jump_early_apex) {
+ return;
+ }
+ jump_early_apex = false;
+ physic.set_gravity(physic.get_gravity() / JUMP_EARLY_APEX_FACTOR);
+}
+
+void
Player::handle_vertical_input()
{
// Press jump key
else if(!controller->hold(Controller::JUMP)) {
if (!backflipping && jumping && physic.get_velocity_y() < 0) {
jumping = false;
- physic.set_velocity_y(0);
+ early_jump_apex();
}
}
+ if(jump_early_apex && physic.get_velocity_y() >= 0) {
+ do_jump_apex();
+ }
+
/* In case the player has pressed Down while in a certain range of air,
enable butt jump action */
- if (controller->hold(Controller::DOWN) && !butt_jump && !duck && is_big() && jumping) {
- butt_jump = true;
+ if (controller->hold(Controller::DOWN) && !duck && is_big() && !on_ground()) {
+ wants_buttjump = true;
+ if (physic.get_velocity_y() >= BUTTJUMP_MIN_VELOCITY_Y) does_buttjump = true;
}
/* When Down is not held anymore, disable butt jump */
- if(butt_jump && !controller->hold(Controller::DOWN))
- butt_jump = false;
+ if(!controller->hold(Controller::DOWN)) {
+ wants_buttjump = false;
+ does_buttjump = false;
+ }
// swimming
physic.set_acceleration_y(0);
/* Peeking */
if( controller->released( Controller::PEEK_LEFT ) ) {
- peeking = AUTO;
+ peekingX = AUTO;
}
if( controller->released( Controller::PEEK_RIGHT ) ) {
- peeking = AUTO;
+ peekingX = AUTO;
}
- if( controller->released( Controller::UP ) ) {
- peeking = AUTO;
+ if( controller->released( Controller::PEEK_UP ) ) {
+ peekingY = AUTO;
}
- if( controller->released( Controller::DOWN ) ) {
- peeking = AUTO;
+ if( controller->released( Controller::PEEK_DOWN ) ) {
+ peekingY = AUTO;
}
if( controller->pressed( Controller::PEEK_LEFT ) ) {
- peeking = LEFT;
+ peekingX = LEFT;
}
if( controller->pressed( Controller::PEEK_RIGHT ) ) {
- peeking = RIGHT;
- }
- if( controller->pressed( Controller::UP ) ) {
- peeking = UP;
+ peekingX = RIGHT;
}
- if( controller->pressed( Controller::DOWN ) ) {
- peeking = DOWN;
+ if(!backflipping && !jumping && on_ground()) {
+ if( controller->pressed( Controller::PEEK_UP ) ) {
+ peekingY = UP;
+ } else if( controller->pressed( Controller::PEEK_DOWN ) ) {
+ peekingY = DOWN;
+ }
}
/* Handle horizontal movement: */
if (climbing) stop_climbing(*climbing);
}
+ if (type == NO_BONUS) {
+ if (does_buttjump) does_buttjump = false;
+ }
+
if ((type == NO_BONUS) || (type == GROWUP_BONUS)) {
if ((player_status->bonus == FIRE_BONUS) && (animate)) {
// visually lose helmet
if (player_status->bonus == GROWUP_BONUS)
sa_prefix = "big";
else if (player_status->bonus == FIRE_BONUS)
- sa_prefix = "big";
+ sa_prefix = "fire";
else if (player_status->bonus == ICE_BONUS)
- sa_prefix = "big";
+ sa_prefix = "ice";
else
sa_prefix = "small";
/* Set Tux sprite action */
if (growing) {
+ sprite->set_action_continued((dir == LEFT)?"grow-left":"grow-right");
// while growing, do not change action
// do_duck() will take care of cancelling growing manually
// update() will take care of cancelling when growing completed
else if (kick_timer.started() && !kick_timer.check()) {
sprite->set_action(sa_prefix+((dir == LEFT)?"-kick-left":"-kick-right"));
}
- else if (butt_jump && is_big()) {
+ else if ((wants_buttjump || does_buttjump) && is_big()) {
sprite->set_action(sa_prefix+((dir == LEFT)?"-buttjump-left":"-buttjump-right"));
}
else if (!on_ground()) {
}
*/
- /* Draw Tux */
if(dying) {
- smalltux_gameover->draw(context, get_pos(), LAYER_FLOATINGOBJECTS + 1);
+ sprite->set_action("gameover");
}
- else if (safe_timer.started() && size_t(game_time*40)%2)
+
+ /* Draw Tux */
+ if (safe_timer.started() && size_t(game_time*40)%2)
; // don't draw Tux
else {
sprite->draw(context, get_pos(), LAYER_OBJECTS + 1);
on_ground_flag = true;
floor_normal = hit.slope_normal;
+
+ // Butt Jump landed
+ if (does_buttjump) {
+ does_buttjump = false;
+ physic.set_velocity_y(-300);
+ on_ground_flag = false;
+ Sector::current()->add_object(new Particles(
+ Vector(get_bbox().p2.x, get_bbox().p2.y),
+ 270+20, 270+40,
+ Vector(280, -260), Vector(0, 300), 3, Color(.4f, .4f, .4f), 3, .8f,
+ LAYER_OBJECTS+1));
+ Sector::current()->add_object(new Particles(
+ Vector(get_bbox().p1.x, get_bbox().p2.y),
+ 90-40, 90-20,
+ Vector(280, -260), Vector(0, 300), 3, Color(.4f, .4f, .4f), 3, .8f,
+ LAYER_OBJECTS+1));
+ }
+
} else if(hit.top) {
if(physic.get_velocity_y() < 0)
physic.set_velocity_y(.2f);
void
Player::make_invincible()
{
- sound_manager->play("sounds/invincible.wav");
+ sound_manager->play("sounds/invincible_start.ogg");
invincible_timer.start(TUX_INVINCIBLE_TIME);
Sector::current()->play_music(HERRING_MUSIC);
}
if(!completely && (safe_timer.started() || invincible_timer.started()))
return;
+ growing = false;
+
sound_manager->play("sounds/hurt.wav");
if (climbing) stop_climbing(*climbing);
safe_timer.start(TUX_SAFE_TIME /* + GROWING_TIME */);
adjust_height(30.8f);
duck = false;
+ backflipping = false;
set_bonus(NO_BONUS, true);
} else if(player_status->bonus == NO_BONUS) {
safe_timer.start(TUX_SAFE_TIME);
physic.set_velocity_y(std::max(physic.get_velocity_y() + velocity.y, end_speed.y));
}
+Vector
+Player::get_velocity()
+{
+ return physic.get_velocity();
+}
+
void
Player::bounce(BadGuy& )
{