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
20 texture_type tux_life,
21 tux_right[3], tux_left[3],
22 bigtux_right[3], bigtux_left[3],
23 bigtux_right_jump, bigtux_left_jump,
24 ducktux_right, ducktux_left,
25 skidtux_right, skidtux_left,
26 firetux_right[3], firetux_left[3],
27 bigfiretux_right[3], bigfiretux_left[3],
28 bigfiretux_right_jump, bigfiretux_left_jump,
29 duckfiretux_right, duckfiretux_left,
30 skidfiretux_right, skidfiretux_left,
31 cape_right[2], cape_left[2],
32 bigcape_right[2], bigcape_left[2];
34 void player_input_init(player_input_type* pplayer_input)
36 pplayer_input->down = UP;
37 pplayer_input->fire = UP;
38 pplayer_input->left = UP;
39 pplayer_input->old_fire = UP;
40 pplayer_input->right = UP;
41 pplayer_input->up = UP;
44 void player_init(player_type* pplayer)
46 pplayer->base.width = 32;
47 pplayer->base.height = 32;
49 pplayer->size = SMALL;
50 pplayer->got_coffee = NO;
53 pplayer->base.y = 240;
56 pplayer->old_base = pplayer->base;
61 pplayer->jumping = NO;
63 pplayer->frame_main = 0;
69 player_input_init(&pplayer->input);
71 pplayer->keymap.jump = SDLK_UP;
72 pplayer->keymap.duck = SDLK_DOWN;
73 pplayer->keymap.left = SDLK_LEFT;
74 pplayer->keymap.right = SDLK_RIGHT;
75 pplayer->keymap.fire = SDLK_LCTRL;
77 timer_init(&pplayer->invincible_timer,YES);
78 timer_init(&pplayer->skidding_timer,YES);
79 timer_init(&pplayer->safe_timer,YES);
80 timer_init(&pplayer->frame_timer,YES);
81 physic_init(&pplayer->hphysic);
82 physic_init(&pplayer->vphysic);
85 int player_key_event(player_type* pplayer, SDLKey key, int state)
87 if(key == pplayer->keymap.right)
89 pplayer->input.right = state;
92 else if( key == pplayer->keymap.left)
94 pplayer->input.left = state;
97 else if(key == pplayer->keymap.jump)
99 pplayer->input.up = state;
102 else if(key == pplayer->keymap.duck)
104 pplayer->input.down = state;
107 else if(key == pplayer->keymap.fire)
109 pplayer->input.fire = state;
116 void player_level_begin(player_type* pplayer)
119 pplayer->base.y = 240;
120 pplayer->base.xm = 0;
121 pplayer->base.ym = 0;
122 pplayer->old_base = pplayer->base;
124 player_input_init(&pplayer->input);
126 timer_init(&pplayer->invincible_timer,YES);
127 timer_init(&pplayer->skidding_timer,YES);
128 timer_init(&pplayer->safe_timer,YES);
129 timer_init(&pplayer->frame_timer,YES);
130 physic_init(&pplayer->hphysic);
131 physic_init(&pplayer->vphysic);
134 void player_action(player_type* pplayer)
136 int i, jumped_in_solid;
137 jumped_in_solid = NO;
139 /* --- HANDLE TUX! --- */
141 player_input(pplayer);
145 pplayer->base.x += pplayer->base.xm * frame_ratio;
146 pplayer->base.y += pplayer->base.ym * frame_ratio;
148 collision_swept_object_map(&pplayer->old_base,&pplayer->base);
150 player_keep_in_bounds(pplayer);
158 if( !player_on_ground(pplayer))
160 if(player_under_solid(pplayer))
162 physic_set_state(&pplayer->vphysic,PH_VT);
163 physic_set_start_vy(&pplayer->vphysic,0);
164 jumped_in_solid = YES;
168 if(!physic_is_set(&pplayer->vphysic))
170 physic_set_state(&pplayer->vphysic,PH_VT);
171 physic_set_start_vy(&pplayer->vphysic,0);
174 pplayer->base.ym = physic_get_velocity(&pplayer->vphysic);
182 if (pplayer->base.ym > 0)
184 pplayer->base.y = (int)(((int)pplayer->base.y / 32) * 32);
185 pplayer->base.ym = 0;
188 physic_init(&pplayer->vphysic);
192 if(jumped_in_solid == YES)
195 if (isbrick(pplayer->base.x, pplayer->base.y) ||
196 isfullbox(pplayer->base.x, pplayer->base.y))
198 trygrabdistro(pplayer->base.x, pplayer->base.y - 32,BOUNCE);
199 trybumpbadguy(pplayer->base.x, pplayer->base.y - 64);
201 if(pplayer->size == BIG)
202 trybreakbrick(pplayer->base.x, pplayer->base.y);
204 bumpbrick(pplayer->base.x, pplayer->base.y);
205 tryemptybox(pplayer->base.x, pplayer->base.y);
208 if (isbrick(pplayer->base.x+ 31, pplayer->base.y) ||
209 isfullbox(pplayer->base.x+ 31, pplayer->base.y))
211 trygrabdistro(pplayer->base.x+ 31, pplayer->base.y - 32,BOUNCE);
212 trybumpbadguy(pplayer->base.x+ 31, pplayer->base.y - 64);
214 if(pplayer->size == BIG)
215 trybreakbrick(pplayer->base.x+ 31, pplayer->base.y);
217 bumpbrick(pplayer->base.x+ 31, pplayer->base.y);
218 tryemptybox(pplayer->base.x+ 31, pplayer->base.y);
222 if(pplayer->size == SMALL)
224 /* Get a distro from a brick? */
226 if (shape(pplayer->base.x, pplayer->base.y) == 'x' ||
227 shape(pplayer->base.x, pplayer->base.y) == 'y')
229 add_bouncy_distro((((int)pplayer->base.x)
231 ((int)pplayer->base.y / 32) * 32);
232 if (counting_distros == NO)
234 counting_distros = YES;
235 distro_counter = 100;
238 if (distro_counter <= 0)
239 level_change(¤t_level,pplayer->base.x,pplayer->base.y - 1, 'a');
241 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
242 score = score + SCORE_DISTRO;
245 else if (shape(pplayer->base.x+ 31, pplayer->base.y) == 'x' ||
246 shape(pplayer->base.x+ 31, pplayer->base.y) == 'y')
248 add_bouncy_distro((((int)pplayer->base.x + 31)
250 ((int)pplayer->base.y / 32) * 32);
251 if (counting_distros == NO)
253 counting_distros = YES;
254 distro_counter = 100;
257 if (distro_counter <= 0)
258 level_change(¤t_level,pplayer->base.x+ 31, pplayer->base.y, 'a');
260 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
261 score = score + SCORE_DISTRO;
267 player_grabdistros(pplayer);
268 if(jumped_in_solid == YES)
271 ++pplayer->old_base.y;
272 if(player_on_ground(pplayer))
274 /* Make sure jumping is off. */
275 pplayer->jumping = NO;
279 /* Reset score multiplier (for multi-hits): */
281 if (pplayer->base.ym > 2)
282 score_multiplier = 1;
286 timer_check(&pplayer->safe_timer);
289 /* ---- DONE HANDLING TUX! --- */
291 /* Handle invincibility timer: */
294 if (get_current_music() == HERRING_MUSIC && !timer_check(&pplayer->invincible_timer))
297 no, we are no more invincible
298 or we were not in invincible mode
299 but are we in hurry ?
303 if (timer_get_left(&time_left) < TIME_WARNING)
305 /* yes, we are in hurry
306 stop the herring_song, prepare to play the correct
309 set_current_music(HURRYUP_MUSIC);
313 set_current_music(LEVEL_MUSIC);
316 /* start playing it */
317 play_current_music();
320 /* Handle skidding: */
322 timer_check(&pplayer->skidding_timer);
326 if (pplayer->base.x - scroll_x >= endpos && endpos != 0)
333 int player_on_ground(player_type *pplayer)
335 if( issolid(pplayer->base.x + pplayer->base.width / 2, pplayer->base.y + pplayer->base.height) ||
336 issolid(pplayer->base.x + 1, pplayer->base.y + pplayer->base.height) ||
337 issolid(pplayer->base.x + pplayer->base.width - 1, pplayer->base.y + pplayer->base.height) )
347 int player_under_solid(player_type *pplayer)
349 if( issolid(pplayer->base.x + pplayer->base.width / 2, pplayer->base.y) ||
350 issolid(pplayer->base.x + 1, pplayer->base.y) ||
351 issolid(pplayer->base.x + pplayer->base.width - 1, pplayer->base.y) )
361 void player_handle_horizontal_input(player_type *pplayer, int dir)
363 if (pplayer->jumping == NO)
365 if ((dir ? (pplayer->base.xm < -SKID_XM) : (pplayer->base.xm > SKID_XM)) && !timer_started(&pplayer->skidding_timer) &&
366 pplayer->dir == !dir)
368 timer_start(&pplayer->skidding_timer, SKID_TIME);
370 play_sound(sounds[SND_SKID], SOUND_CENTER_SPEAKER);
376 if ((dir ? (pplayer->base.xm < 0) : (pplayer->base.xm > 0)) && !isice(pplayer->base.x, pplayer->base.y + pplayer->base.height) &&
377 !timer_started(&pplayer->skidding_timer))
379 pplayer->base.xm = 0;
384 if (pplayer->dir == dir)
386 /* Facing the direction we're jumping? Go full-speed: */
388 if (pplayer->input.fire == UP)
390 pplayer->base.xm = pplayer->base.xm + ( dir ? WALK_SPEED : -WALK_SPEED) * frame_ratio;
394 if (pplayer->base.xm > MAX_WALK_XM)
395 pplayer->base.xm = MAX_WALK_XM;
399 if (pplayer->base.xm < -MAX_WALK_XM)
400 pplayer->base.xm = -MAX_WALK_XM;
403 else if ( pplayer->input.fire == DOWN)
405 pplayer->base.xm = pplayer->base.xm + ( dir ? RUN_SPEED : -RUN_SPEED) * frame_ratio;
409 if (pplayer->base.xm > MAX_RUN_XM)
410 pplayer->base.xm = MAX_RUN_XM;
414 if (pplayer->base.xm < -MAX_RUN_XM)
415 pplayer->base.xm = -MAX_RUN_XM;
420 /* Not facing the direction we're jumping?
423 pplayer->base.xm = pplayer->base.xm + ( dir ? (WALK_SPEED / 2) : -(WALK_SPEED / 2)) * frame_ratio;
427 if (pplayer->base.xm > MAX_WALK_XM / 2)
428 pplayer->base.xm = MAX_WALK_XM / 2;
432 if (pplayer->base.xm < -MAX_WALK_XM / 2)
433 pplayer->base.xm = -MAX_WALK_XM / 2;
441 void player_handle_vertical_input(player_type *pplayer)
443 if(pplayer->input.up == DOWN)
445 if (player_on_ground(pplayer))
447 if(!physic_is_set(&pplayer->vphysic))
449 physic_set_state(&pplayer->vphysic,PH_VT);
450 physic_set_start_vy(&pplayer->vphysic,5.5);
452 pplayer->jumping = YES;
453 if (pplayer->size == SMALL)
454 play_sound(sounds[SND_JUMP], SOUND_CENTER_SPEAKER);
456 play_sound(sounds[SND_BIGJUMP], SOUND_CENTER_SPEAKER);
460 else if(pplayer->input.up == UP && pplayer->jumping == YES)
462 if (player_on_ground(pplayer))
464 physic_init(&pplayer->vphysic);
465 pplayer->jumping == NO;
469 pplayer->jumping = NO;
470 if(physic_is_set(&pplayer->vphysic))
472 if(physic_get_velocity(&pplayer->vphysic) < 0.)
474 physic_set_state(&pplayer->vphysic,PH_VT);
475 physic_set_start_vy(&pplayer->vphysic,0);
480 if(!physic_is_set(&pplayer->vphysic))
482 physic_set_state(&pplayer->vphysic,PH_VT);
489 void player_input(player_type *pplayer)
491 /* Handle key and joystick state: */
493 if(pplayer->duck == NO)
495 if (pplayer->input.right == DOWN && pplayer->input.left == UP)
497 player_handle_horizontal_input(pplayer,RIGHT);
499 else if (pplayer->input.left == DOWN && pplayer->input.right == UP)
501 player_handle_horizontal_input(pplayer,LEFT);
505 if(pplayer->base.xm > 0)
507 pplayer->base.xm = (int)(pplayer->base.xm - frame_ratio);
508 if(pplayer->base.xm < 0)
509 pplayer->base.xm = 0;
511 else if(pplayer->base.xm < 0)
513 pplayer->base.xm = (int)(pplayer->base.xm + frame_ratio);
514 if(pplayer->base.xm > 0)
515 pplayer->base.xm = 0;
522 if ( pplayer->input.up == DOWN || (pplayer->input.up == UP && pplayer->jumping == YES))
524 player_handle_vertical_input(pplayer);
529 if (pplayer->input.fire == DOWN && pplayer->input.old_fire == UP && pplayer->got_coffee)
531 add_bullet(pplayer->base.x, pplayer->base.y, pplayer->base.xm, pplayer->dir);
537 if (pplayer->input.down == DOWN)
539 if (pplayer->size == BIG && pplayer->duck != YES)
542 pplayer->base.height = 32;
543 pplayer->base.y += 32;
548 if (pplayer->size == BIG && pplayer->duck == YES)
550 /* Make sure we're not standing back up into a solid! */
551 pplayer->base.height = 64;
552 pplayer->base.y -= 32;
554 if (!collision_object_map(&pplayer->base) /*issolid(pplayer->base.x + 16, pplayer->base.y - 16)*/)
557 pplayer->base.height = 64;
558 pplayer->old_base.y -= 32;
559 pplayer->old_base.height = 64;
563 pplayer->base.height = 32;
564 pplayer->base.y += 32;
575 if(!timer_check(&pplayer->frame_timer))
577 timer_start(&pplayer->frame_timer,25);
578 if (pplayer->input.right == UP && pplayer->input.left == UP)
580 pplayer->frame_main = 1;
585 if ((pplayer->input.fire == DOWN && (frame % 2) == 0) ||
587 pplayer->frame_main = (pplayer->frame_main + 1) % 4;
589 pplayer->frame = pplayer->frame_main;
591 if (pplayer->frame == 3)
598 void player_grabdistros(player_type *pplayer)
603 trygrabdistro(pplayer->base.x, pplayer->base.y, NO_BOUNCE);
604 trygrabdistro(pplayer->base.x+ 31, pplayer->base.y, NO_BOUNCE);
606 trygrabdistro(pplayer->base.x, pplayer->base.y + pplayer->base.height, NO_BOUNCE);
607 trygrabdistro(pplayer->base.x+ 31, pplayer->base.y + pplayer->base.height, NO_BOUNCE);
609 if(pplayer->size == BIG)
611 trygrabdistro(pplayer->base.x, pplayer->base.y + pplayer->base.height / 2, NO_BOUNCE);
612 trygrabdistro(pplayer->base.x+ 31, pplayer->base.y + pplayer->base.height / 2, NO_BOUNCE);
618 /* Enough distros for a One-up? */
620 if (distros >= DISTROS_LIFEUP)
622 distros = distros - DISTROS_LIFEUP;
623 if(pplayer->lives < MAX_LIVES)
625 /*We want to hear the sound even, if MAX_LIVES is reached*/
626 play_sound(sounds[SND_LIFEUP], SOUND_CENTER_SPEAKER);
630 void player_draw(player_type* pplayer)
632 if (!timer_started(&pplayer->safe_timer) || (frame % 2) == 0)
634 if (pplayer->size == SMALL)
636 if (timer_started(&pplayer->invincible_timer))
640 if (pplayer->dir == RIGHT)
642 texture_draw(&cape_right[frame % 2],
643 pplayer->base.x- scroll_x, pplayer->base.y,
648 texture_draw(&cape_left[frame % 2],
649 pplayer->base.x- scroll_x, pplayer->base.y,
655 if (!pplayer->got_coffee)
657 if (pplayer->dir == RIGHT)
659 texture_draw(&tux_right[pplayer->frame], pplayer->base.x- scroll_x, pplayer->base.y, NO_UPDATE);
663 texture_draw(&tux_left[pplayer->frame], pplayer->base.x- scroll_x, pplayer->base.y, NO_UPDATE);
668 /* Tux got coffee! */
670 if (pplayer->dir == RIGHT)
672 texture_draw(&firetux_right[pplayer->frame], pplayer->base.x- scroll_x, pplayer->base.y, NO_UPDATE);
676 texture_draw(&firetux_left[pplayer->frame], pplayer->base.x- scroll_x, pplayer->base.y, NO_UPDATE);
682 if (timer_started(&pplayer->invincible_timer))
686 if (pplayer->dir == RIGHT)
688 texture_draw(&bigcape_right[frame % 2],
689 pplayer->base.x- scroll_x - 8, pplayer->base.y,
694 texture_draw(&bigcape_left[frame % 2],
695 pplayer->base.x-scroll_x - 8, pplayer->base.y,
700 if (!pplayer->got_coffee)
704 if (!timer_started(&pplayer->skidding_timer))
706 if (!pplayer->jumping || pplayer->base.ym > 0)
708 if (pplayer->dir == RIGHT)
710 texture_draw(&bigtux_right[pplayer->frame],
711 pplayer->base.x- scroll_x - 8, pplayer->base.y,
716 texture_draw(&bigtux_left[pplayer->frame],
717 pplayer->base.x- scroll_x - 8, pplayer->base.y,
723 if (pplayer->dir == RIGHT)
725 texture_draw(&bigtux_right_jump,
726 pplayer->base.x- scroll_x - 8, pplayer->base.y,
731 texture_draw(&bigtux_left_jump,
732 pplayer->base.x- scroll_x - 8, pplayer->base.y,
739 if (pplayer->dir == RIGHT)
741 texture_draw(&skidtux_right,
742 pplayer->base.x- scroll_x - 8, pplayer->base.y,
747 texture_draw(&skidtux_left,
748 pplayer->base.x- scroll_x - 8, pplayer->base.y,
755 if (pplayer->dir == RIGHT)
757 texture_draw(&ducktux_right, pplayer->base.x- scroll_x - 8, pplayer->base.y - 16,
762 texture_draw(&ducktux_left, pplayer->base.x- scroll_x - 8, pplayer->base.y - 16,
769 /* Tux has coffee! */
773 if (!timer_started(&pplayer->skidding_timer))
775 if (!pplayer->jumping || pplayer->base.ym > 0)
777 if (pplayer->dir == RIGHT)
779 texture_draw(&bigfiretux_right[pplayer->frame],
780 pplayer->base.x- scroll_x - 8, pplayer->base.y,
785 texture_draw(&bigfiretux_left[pplayer->frame],
786 pplayer->base.x- scroll_x - 8, pplayer->base.y,
792 if (pplayer->dir == RIGHT)
794 texture_draw(&bigfiretux_right_jump,
795 pplayer->base.x- scroll_x - 8, pplayer->base.y,
800 texture_draw(&bigfiretux_left_jump,
801 pplayer->base.x- scroll_x - 8, pplayer->base.y,
808 if (pplayer->dir == RIGHT)
810 texture_draw(&skidfiretux_right,
811 pplayer->base.x- scroll_x - 8, pplayer->base.y,
816 texture_draw(&skidfiretux_left,
817 pplayer->base.x- scroll_x - 8, pplayer->base.y,
824 if (pplayer->dir == RIGHT)
826 texture_draw(&duckfiretux_right, pplayer->base.x- scroll_x - 8, pplayer->base.y - 16,
831 texture_draw(&duckfiretux_left, pplayer->base.x- scroll_x - 8, pplayer->base.y - 16,
840 void player_collision(player_type* pplayer, void* p_c_object, int c_object)
842 bad_guy_type* pbad_c = NULL;
847 pbad_c = (bad_guy_type*) p_c_object;
848 /* Hurt the player if he just touched it: */
850 if (!pbad_c->dying && !pplayer->dying &&
851 !timer_started(&pplayer->safe_timer) &&
852 pbad_c->mode != HELD)
854 if (pbad_c->mode == FLAT && pplayer->input.fire != DOWN)
859 play_sound(sounds[SND_KICK], SOUND_CENTER_SPEAKER);
861 if (pplayer->base.x<= pbad_c->base.x)
864 pbad_c->base.x = pbad_c->base.x + 16;
869 pbad_c->base.x = pbad_c->base.x - 32;
872 timer_start(&pbad_c->timer,5000);
874 else if (pbad_c->mode == FLAT && pplayer->input.fire == DOWN)
879 else if (pbad_c->mode == KICK)
881 if (pplayer->base.y < pbad_c->base.y - 16 &&
882 timer_started(&pbad_c->timer))
884 /* Step on (stop being kicked) */
887 play_sound(sounds[SND_STOMP], SOUND_CENTER_SPEAKER);
888 timer_start(&pbad_c->timer, 10000);
892 /* Hurt if you get hit by kicked laptop: */
894 if (timer_started(&pbad_c->timer))
896 if (!timer_started(&pplayer->invincible_timer))
898 player_kill(pplayer,SHRINK);
902 pbad_c->dying = FALLING;
903 physic_set_state(&pplayer->vphysic,PH_VT);
904 physic_set_start_vy(&pplayer->vphysic,-2.);
905 play_sound(sounds[SND_FALL], SOUND_CENTER_SPEAKER);
912 if (!timer_started(&pplayer->invincible_timer ))
914 player_kill(pplayer,SHRINK);
918 pbad_c->dying = FALLING;
919 physic_set_state(&pplayer->vphysic,PH_VT);
920 physic_set_start_vy(&pplayer->vphysic,-2.);
921 play_sound(sounds[SND_FALL], SOUND_CENTER_SPEAKER);
935 void player_kill(player_type* pplayer, int mode)
937 pplayer->base.ym = -5;
939 play_sound(sounds[SND_HURT], SOUND_CENTER_SPEAKER);
941 if (pplayer->dir == RIGHT)
942 pplayer->base.xm = -8;
943 else if (pplayer->dir == LEFT)
944 pplayer->base.xm = 8;
946 if (mode == SHRINK && pplayer->size == BIG)
948 if (pplayer->got_coffee)
949 pplayer->got_coffee = NO;
951 pplayer->size = SMALL;
952 pplayer->base.height = 32;
954 timer_start(&pplayer->safe_timer,TUX_SAFE_TIME);
962 void player_dying(player_type *pplayer)
964 pplayer->base.ym = pplayer->base.ym + gravity;
969 player_remove_powerups(pplayer);
972 player_level_begin(pplayer);
976 /* Remove Tux's power ups */
977 void player_remove_powerups(player_type* pplayer)
979 pplayer->got_coffee = NO;
980 pplayer->size = SMALL;
981 pplayer->base.height = 32;
984 void player_keep_in_bounds(player_type* pplayer)
986 /* Keep tux in bounds: */
987 if (pplayer->base.x< 0)
989 else if(pplayer->base.x< scroll_x)
990 pplayer->base.x= scroll_x;
991 else if (pplayer->base.x< 160 + scroll_x && scroll_x > 0 && debug_mode == YES)
993 scroll_x = pplayer->base.x- 160;
994 /*pplayer->base.x+= 160;*/
1000 else if (pplayer->base.x> screen->w / 2 + scroll_x && scroll_x < ((current_level.width * 32) - screen->w))
1002 /* Scroll the screen in past center: */
1004 scroll_x = pplayer->base.x- screen->w / 2;
1005 /*pplayer->base.x= 320 + scroll_x;*/
1007 if (scroll_x > ((current_level.width * 32) - screen->w))
1008 scroll_x = ((current_level.width * 32) - screen->w);
1010 else if (pplayer->base.x> 608 + scroll_x)
1012 /* ... unless there's no more to scroll! */
1014 /*pplayer->base.x= 608 + scroll_x;*/
1017 /* Keep in-bounds, vertically: */
1019 if (pplayer->base.y > screen->h)
1021 player_kill(&tux,KILL);