2 // C Implementation: player/tux
7 // Author: Tobias Glaesser <tobi.web@gmx.de> & Bill Kendrick, (C) 2004
9 // Copyright: See COPYING file that comes with this distribution
22 texture_type tux_life;
23 texture_type tux_right[3];
24 texture_type tux_left[3];
25 texture_type bigtux_right[3];
26 texture_type bigtux_left[3];
27 texture_type bigtux_right_jump;
28 texture_type bigtux_left_jump;
29 texture_type ducktux_right;
30 texture_type ducktux_left;
31 texture_type skidtux_right;
32 texture_type skidtux_left;
33 texture_type firetux_right[3];
34 texture_type firetux_left[3];
35 texture_type bigfiretux_right[3];
36 texture_type bigfiretux_left[3];
37 texture_type bigfiretux_right_jump;
38 texture_type bigfiretux_left_jump;
39 texture_type duckfiretux_right;
40 texture_type duckfiretux_left;
41 texture_type skidfiretux_right;
42 texture_type skidfiretux_left;
43 texture_type cape_right[2];
44 texture_type cape_left[2];
45 texture_type bigcape_right[2];
46 texture_type bigcape_left[2];
48 void player_input_init(player_input_type* pplayer_input)
50 pplayer_input->down = UP;
51 pplayer_input->fire = UP;
52 pplayer_input->left = UP;
53 pplayer_input->old_fire = UP;
54 pplayer_input->right = UP;
55 pplayer_input->up = UP;
67 // FIXME: Make the start position configurable via the levelfile
85 player_input_init(&input);
87 keymap.jump = SDLK_UP;
88 keymap.duck = SDLK_DOWN;
89 keymap.left = SDLK_LEFT;
90 keymap.right = SDLK_RIGHT;
91 keymap.fire = SDLK_LCTRL;
93 timer_init(&invincible_timer,true);
94 timer_init(&skidding_timer,true);
95 timer_init(&safe_timer,true);
96 timer_init(&frame_timer,true);
101 Player::key_event(SDLKey key, int state)
103 if(key == keymap.right)
108 else if(key == keymap.left)
113 else if(key == keymap.jump)
118 else if(key == keymap.duck)
123 else if(key == keymap.fire)
133 Player::level_begin()
140 previous_base = base;
144 player_input_init(&input);
146 timer_init(&invincible_timer,true);
147 timer_init(&skidding_timer,true);
148 timer_init(&safe_timer,true);
149 timer_init(&frame_timer,true);
156 bool jumped_in_solid = false;
158 /* --- HANDLE TUX! --- */
164 previous_base = base;
166 physic.apply(base.x, base.y);
171 collision_swept_object_map(&old_base,&base);
179 physic.enable_gravity(true);
183 physic.set_velocity(physic.get_velocity_x(), 0);
184 jumped_in_solid = true;
190 if (physic.get_velocity_y() < 0)
192 base.y = (int)(((int)base.y / 32) * 32);
193 physic.set_velocity(physic.get_velocity_x(), 0);
196 physic.enable_gravity(false);
197 /* Reset score multiplier (for multi-hits): */
198 score_multiplier = 1;
203 if (isbrick(base.x, base.y) ||
204 isfullbox(base.x, base.y))
206 trygrabdistro(base.x, base.y - 32,BOUNCE);
207 trybumpbadguy(base.x, base.y - 64);
209 trybreakbrick(base.x, base.y, size == SMALL);
211 bumpbrick(base.x, base.y);
212 tryemptybox(base.x, base.y, RIGHT);
215 if (isbrick(base.x+ 31, base.y) ||
216 isfullbox(base.x+ 31, base.y))
218 trygrabdistro(base.x+ 31, base.y - 32,BOUNCE);
219 trybumpbadguy(base.x+ 31, base.y - 64);
222 trybreakbrick(base.x+ 31, base.y, size == SMALL);
224 bumpbrick(base.x+ 31, base.y);
225 tryemptybox(base.x+ 31, base.y, LEFT);
237 /* Make sure jumping is off. */
244 timer_check(&safe_timer);
247 /* ---- DONE HANDLING TUX! --- */
249 /* Handle invincibility timer: */
252 if (get_current_music() == HERRING_MUSIC && !timer_check(&invincible_timer))
255 no, we are no more invincible
256 or we were not in invincible mode
257 but are we in hurry ?
261 if (timer_get_left(&time_left) < TIME_WARNING)
263 /* yes, we are in hurry
264 stop the herring_song, prepare to play the correct
267 set_current_music(HURRYUP_MUSIC);
271 set_current_music(LEVEL_MUSIC);
274 /* start playing it */
275 play_current_music();
278 /* Handle skidding: */
280 // timer_check(&skidding_timer); // disabled
284 if (base.x >= endpos && endpos != 0)
294 return ( issolid(base.x + base.width / 2, base.y + base.height) ||
295 issolid(base.x + 1, base.y + base.height) ||
296 issolid(base.x + base.width - 1, base.y + base.height) );
300 Player::under_solid()
302 return ( issolid(base.x + base.width / 2, base.y) ||
303 issolid(base.x + 1, base.y) ||
304 issolid(base.x + base.width - 1, base.y) );
308 Player::handle_horizontal_input(int newdir)
313 float vx = physic.get_velocity_x();
314 float vy = physic.get_velocity_y();
317 // skid if we're too fast
318 if(dir != newdir && on_ground() && fabs(physic.get_velocity_x()) > SKID_XM
319 && !timer_started(&skidding_timer))
321 timer_start(&skidding_timer, SKID_TIME);
322 play_sound(sounds[SND_SKID], SOUND_CENTER_SPEAKER);
326 if ((newdir ? (vx < 0) : (vx > 0)) && !isice(base.x, base.y + base.height) &&
327 !timer_started(&skidding_timer))
332 /* Facing the direction we're jumping? Go full-speed: */
333 if (input.fire == UP)
335 if(vx >= MAX_WALK_XM) {
337 physic.set_acceleration(0, 0); // enough speedup
338 } else if(vx <= -MAX_WALK_XM) {
340 physic.set_acceleration(0, 0);
342 physic.set_acceleration(newdir ? 0.02 : -0.02, 0);
343 if(fabs(vx) < 1) // set some basic run speed
344 vx = newdir ? 1 : -1;
346 vx += ( newdir ? WALK_SPEED : -WALK_SPEED) * frame_ratio;
350 if (vx > MAX_WALK_XM)
355 if (vx < -MAX_WALK_XM)
360 else if ( input.fire == DOWN)
362 if(vx >= MAX_RUN_XM) {
364 physic.set_acceleration(0, 0); // enough speedup
365 } else if(vx <= -MAX_RUN_XM) {
367 physic.set_acceleration(0, 0);
369 physic.set_acceleration(newdir ? 0.03 : -0.03, 0);
370 if(fabs(vx) < 1) // set some basic run speed
371 vx = newdir ? 1 : -1;
374 vx = vx + ( newdir ? RUN_SPEED : -RUN_SPEED) * frame_ratio;
383 if (vx < -MAX_RUN_XM)
391 /* Not facing the direction we're jumping?
393 vx = vx + ( newdir ? (WALK_SPEED / 2) : -(WALK_SPEED / 2)) * frame_ratio;
397 if (vx > MAX_WALK_XM / 2)
398 vx = MAX_WALK_XM / 2;
402 if (vx < -MAX_WALK_XM / 2)
403 vx = -MAX_WALK_XM / 2;
408 physic.set_velocity(vx, vy);
412 Player::handle_vertical_input()
419 physic.set_velocity(physic.get_velocity_x(), 5.5);
423 play_sound(sounds[SND_JUMP], SOUND_CENTER_SPEAKER);
425 play_sound(sounds[SND_BIGJUMP], SOUND_CENTER_SPEAKER);
428 else if(input.up == UP && jumping)
431 if(physic.get_velocity_y() > 0) {
432 physic.set_velocity(physic.get_velocity_x(), 0);
438 Player::handle_input()
440 /* Handle key and joystick state: */
443 if (input.right == DOWN && input.left == UP)
445 handle_horizontal_input(RIGHT);
447 else if (input.left == DOWN && input.right == UP)
449 handle_horizontal_input(LEFT);
453 float vx = physic.get_velocity_x();
454 if(fabs(vx) < 0.01) {
455 physic.set_velocity(0, physic.get_velocity_y());
456 physic.set_acceleration(0, 0);
458 physic.set_acceleration(0.1, 0);
460 physic.set_acceleration(-0.1, 0);
467 if ( input.up == DOWN || (input.up == UP && jumping))
469 handle_vertical_input();
474 if (input.fire == DOWN && input.old_fire == UP && got_coffee)
476 add_bullet(base.x, base.y, physic.get_velocity_x(), dir);
482 if (input.down == DOWN)
484 if (size == BIG && duck != true)
493 if (size == BIG && duck)
495 /* Make sure we're not standing back up into a solid! */
499 if (!collision_object_map(&base) /*issolid(base.x + 16, base.y - 16)*/)
504 old_base.height = 64;
520 if(!timer_check(&frame_timer))
522 timer_start(&frame_timer,25);
523 if (input.right == UP && input.left == UP)
530 if ((input.fire == DOWN && (global_frame_counter % 2) == 0) ||
531 (global_frame_counter % 4) == 0)
532 frame_main = (frame_main + 1) % 4;
544 Player::grabdistros()
549 trygrabdistro(base.x, base.y, NO_BOUNCE);
550 trygrabdistro(base.x+ 31, base.y, NO_BOUNCE);
552 trygrabdistro(base.x, base.y + base.height, NO_BOUNCE);
553 trygrabdistro(base.x+ 31, base.y + base.height, NO_BOUNCE);
557 trygrabdistro(base.x, base.y + base.height / 2, NO_BOUNCE);
558 trygrabdistro(base.x+ 31, base.y + base.height / 2, NO_BOUNCE);
563 /* Enough distros for a One-up? */
564 if (distros >= DISTROS_LIFEUP)
566 distros = distros - DISTROS_LIFEUP;
567 if(lives < MAX_LIVES)
569 /*We want to hear the sound even, if MAX_LIVES is reached*/
570 play_sound(sounds[SND_LIFEUP], SOUND_CENTER_SPEAKER);
577 if (!timer_started(&safe_timer) || (global_frame_counter % 2) == 0)
581 if (timer_started(&invincible_timer))
587 texture_draw(&cape_right[global_frame_counter % 2],
588 base.x- scroll_x, base.y);
592 texture_draw(&cape_left[global_frame_counter % 2],
593 base.x- scroll_x, base.y);
602 texture_draw(&tux_right[frame_], base.x- scroll_x, base.y);
606 texture_draw(&tux_left[frame_], base.x- scroll_x, base.y);
611 /* Tux got coffee! */
615 texture_draw(&firetux_right[frame_], base.x- scroll_x, base.y);
619 texture_draw(&firetux_left[frame_], base.x- scroll_x, base.y);
625 if (timer_started(&invincible_timer))
630 texture_draw(&bigcape_right[global_frame_counter % 2],
631 base.x- scroll_x - 8, base.y);
635 texture_draw(&bigcape_left[global_frame_counter % 2],
636 base.x-scroll_x - 8, base.y);
644 if (!timer_started(&skidding_timer))
646 if (!jumping || physic.get_velocity_y() > 0)
650 texture_draw(&bigtux_right[frame_],
651 base.x- scroll_x - 8, base.y);
655 texture_draw(&bigtux_left[frame_],
656 base.x- scroll_x - 8, base.y);
663 texture_draw(&bigtux_right_jump,
664 base.x- scroll_x - 8, base.y);
668 texture_draw(&bigtux_left_jump,
669 base.x- scroll_x - 8, base.y);
677 texture_draw(&skidtux_right,
678 base.x- scroll_x - 8, base.y);
682 texture_draw(&skidtux_left,
683 base.x- scroll_x - 8, base.y);
691 texture_draw(&ducktux_right, base.x- scroll_x - 8, base.y - 16);
695 texture_draw(&ducktux_left, base.x- scroll_x - 8, base.y - 16);
701 /* Tux has coffee! */
705 if (!timer_started(&skidding_timer))
707 if (!jumping || physic.get_velocity_y() > 0)
711 texture_draw(&bigfiretux_right[frame_],
712 base.x- scroll_x - 8, base.y);
716 texture_draw(&bigfiretux_left[frame_],
717 base.x- scroll_x - 8, base.y);
724 texture_draw(&bigfiretux_right_jump,
725 base.x- scroll_x - 8, base.y);
729 texture_draw(&bigfiretux_left_jump,
730 base.x- scroll_x - 8, base.y);
738 texture_draw(&skidfiretux_right,
739 base.x- scroll_x - 8, base.y);
743 texture_draw(&skidfiretux_left,
744 base.x- scroll_x - 8, base.y);
752 texture_draw(&duckfiretux_right, base.x- scroll_x - 8, base.y - 16);
756 texture_draw(&duckfiretux_left, base.x- scroll_x - 8, base.y - 16);
764 text_drawf(&gold_text,"Penguins can fly !:",0,0,A_HMIDDLE,A_VMIDDLE,1);
768 Player::collision(void* p_c_object, int c_object)
770 BadGuy* pbad_c = NULL;
775 pbad_c = (BadGuy*) p_c_object;
776 /* Hurt the player if he just touched it: */
778 if (!pbad_c->dying && !dying &&
779 !timer_started(&safe_timer) &&
780 pbad_c->mode != HELD)
782 if (pbad_c->mode == FLAT && input.fire == DOWN)
787 else if (pbad_c->mode == KICK)
789 if (base.y < pbad_c->base.y - 16)
791 /* Step on (stop being kicked) */
794 play_sound(sounds[SND_STOMP], SOUND_CENTER_SPEAKER);
798 /* Hurt if you get hit by kicked laptop: */
799 if (!timer_started(&invincible_timer))
805 pbad_c->dying = DYING_FALLING;
806 play_sound(sounds[SND_FALL], SOUND_CENTER_SPEAKER);
807 add_score(pbad_c->base.x - scroll_x,
809 25 * score_multiplier);
815 if (!timer_started(&invincible_timer ))
836 Player::kill(int mode)
838 play_sound(sounds[SND_HURT], SOUND_CENTER_SPEAKER);
840 physic.set_velocity(0, physic.get_velocity_y());
842 if (mode == SHRINK && size == BIG)
850 timer_start(&safe_timer,TUX_SAFE_TIME);
857 physic.enable_gravity(true);
858 physic.set_acceleration(0, 0);
859 physic.set_velocity(0, 7);
860 dying = DYING_SQUISHED;
874 bool Player::is_dead()
876 if(base.y > screen->h)
882 /* Remove Tux's power ups */
884 Player::remove_powerups()
892 Player::keep_in_bounds()
894 /* Keep tux in bounds: */
897 else if(base.x< scroll_x)
899 else if (base.x< 160 + scroll_x && scroll_x > 0 && debug_mode)
901 scroll_x = base.x- 160;
908 else if (base.x> screen->w / 2 + scroll_x && scroll_x < ((current_level.width * 32) - screen->w))
910 /* Scroll the screen in past center: */
912 scroll_x = base.x- screen->w / 2;
913 /*base.x= 320 + scroll_x;*/
915 if (scroll_x > ((current_level.width * 32) - screen->w))
916 scroll_x = ((current_level.width * 32) - screen->w);
918 else if (base.x> 608 + scroll_x)
920 /* ... unless there's no more to scroll! */
922 /*base.x= 608 + scroll_x;*/
925 /* Keep in-bounds, vertically: */
927 if (base.y > screen->h)