2 // C Implementation: player/tux
7 // Author: Tobias Glaesser <tobi.web@gmx.de>, (C) 2004
9 // Copyright: See COPYING file that comes with this distribution
20 void player_init(player_type* pplayer)
22 pplayer->it.alive = NULL;
23 pplayer->it.x = &pplayer->x;
24 pplayer->it.y = &pplayer->y;
25 pplayer->it.width = &pplayer->width;
26 pplayer->it.height = &pplayer->height;
27 pplayer->it.updated = &pplayer->updated;
32 pplayer->updated = SDL_GetTicks();
33 pplayer->size = SMALL;
34 pplayer->got_coffee = NO;
44 pplayer->safe = TUX_SAFE_TIME;
46 pplayer->jumping = NO;
47 pplayer->skidding = 0;
49 pplayer->frame_main = 0;
53 pplayer->input.down = UP;
54 pplayer->input.fire = UP;
55 pplayer->input.left = UP;
56 pplayer->input.old_fire = UP;
57 pplayer->input.right = UP;
58 pplayer->input.up = UP;
60 timer_init(&pplayer->invincible_timer);
63 void player_level_begin(player_type* pplayer)
71 void player_action(player_type* pplayer)
74 double frame_ratio = get_frame_ratio(&pplayer->it);
76 /* --- HANDLE TUX! --- */
78 player_input(pplayer);
82 pplayer->x = pplayer->x + pplayer->xm * frame_ratio;
83 pplayer->y = pplayer->y + pplayer->ym * frame_ratio;
85 player_keep_in_bounds(pplayer);
91 if (issolid(pplayer->x, pplayer->y + 31) &&
92 !issolid(pplayer->x - pplayer->xm, pplayer->y + 31))
94 while (issolid(pplayer->x, pplayer->y + 31))
98 else if (pplayer->xm > 0)
105 if (issolid(pplayer->x, pplayer->y) &&
106 !issolid(pplayer->x - pplayer->xm, pplayer->y))
108 while (issolid(pplayer->x, (pplayer->y)))
112 else if (pplayer->xm > 0)
119 if (issolid(pplayer->x, pplayer->y + 31))
121 /* Set down properly: */
124 while (issolid(pplayer->x, pplayer->y + 31))
128 DEBUG_MSG("FIXME - UNDER certain circumstances I'm hanging in a loop here!");
132 else if (pplayer->ym > 0)
137 /* Reset score multiplier (for multi-hits): */
140 score_multiplier = 1;
146 pplayer->jumping = NO;
150 /* Bump into things: */
152 if (issolid(pplayer->x, pplayer->y) ||
153 (pplayer->size == BIG && !pplayer->duck &&
154 (issolid(pplayer->x, pplayer->y - 32))))
156 if (!issolid(pplayer->x - pplayer->xm, pplayer->y) &&
157 (pplayer->size == SMALL || pplayer->duck ||
158 !issolid(pplayer->x - pplayer->xm, pplayer->y - 32)))
160 pplayer->x = pplayer->x - pplayer->xm;
163 else if (!issolid(pplayer->x, pplayer->y - pplayer->ym) &&
164 (pplayer->size == SMALL || pplayer->duck ||
165 !issolid(pplayer->x, pplayer->y - 32 - pplayer->ym)))
167 if (pplayer->ym <= 0)
171 if (pplayer->size == BIG)
173 /* Break bricks and empty boxes: */
177 if (isbrick(pplayer->x, pplayer->y - 32) ||
178 isfullbox(pplayer->x, pplayer->y - 32))
180 trygrabdistro(pplayer->x, pplayer->y - 64, BOUNCE);
181 trybumpbadguy(pplayer->x, pplayer->y - 96);
183 if (isfullbox(pplayer->x, pplayer->y - 32))
185 bumpbrick(pplayer->x, pplayer->y - 32);
188 trybreakbrick(pplayer->x, pplayer->y - 32);
189 tryemptybox(pplayer->x, pplayer->y - 32);
192 if (isbrick(pplayer->x + 31, pplayer->y - 32) ||
193 isfullbox(pplayer->x + 31, pplayer->y - 32))
195 trygrabdistro(pplayer->x + 31,
198 trybumpbadguy(pplayer->x + 31,
201 if (isfullbox(pplayer->x + 31, pplayer->y - 32))
203 bumpbrick(pplayer->x + 31, pplayer->y - 32);
206 trybreakbrick(pplayer->x + 31,
208 tryemptybox(pplayer->x + 31,
214 if (isbrick(pplayer->x, pplayer->y) ||
215 isfullbox(pplayer->x, pplayer->y))
217 trygrabdistro(pplayer->x, pplayer->y - 32,BOUNCE);
218 trybumpbadguy(pplayer->x, pplayer->y - 64);
219 if (isfullbox(pplayer->x, pplayer->y))
220 bumpbrick(pplayer->x, pplayer->y);
221 trybreakbrick(pplayer->x, pplayer->y);
222 tryemptybox(pplayer->x, pplayer->y);
225 if (isbrick(pplayer->x + 31, pplayer->y) ||
226 isfullbox(pplayer->x + 31, pplayer->y))
228 trygrabdistro(pplayer->x + 31,
231 trybumpbadguy(pplayer->x + 31,
233 if (isfullbox(pplayer->x + 31, pplayer->y))
234 bumpbrick(pplayer->x + 31, pplayer->y);
235 trybreakbrick(pplayer->x + 31, pplayer->y);
236 tryemptybox(pplayer->x + 31, pplayer->y);
242 /* It's a brick and we're small, make the brick
243 bounce, and grab any distros above it: */
245 if (isbrick(pplayer->x, pplayer->y) ||
246 isfullbox(pplayer->x, pplayer->y))
248 trygrabdistro(pplayer->x, pplayer->y - 32,BOUNCE);
249 trybumpbadguy(pplayer->x, pplayer->y - 64);
250 bumpbrick(pplayer->x, pplayer->y);
251 tryemptybox(pplayer->x, pplayer->y);
254 if (isbrick(pplayer->x + 31, pplayer->y) ||
255 isfullbox(pplayer->x + 31, pplayer->y))
257 trygrabdistro(pplayer->x + 31, pplayer->y - 32,BOUNCE);
258 trybumpbadguy(pplayer->x + 31, pplayer->y - 64);
259 bumpbrick(pplayer->x + 31, pplayer->y);
260 tryemptybox(pplayer->x + 31, pplayer->y);
264 /* Get a distro from a brick? */
266 if (shape(pplayer->x, pplayer->y) == 'x' ||
267 shape(pplayer->x, pplayer->y) == 'y')
269 add_bouncy_distro(((pplayer->x + 1)
271 (int)(pplayer->y / 32) * 32);
273 if (counting_distros == NO)
275 counting_distros = YES;
276 distro_counter = 100;
279 if (distro_counter <= 0)
280 level_change(¤t_level,pplayer->x, pplayer->y, 'a');
282 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
283 score = score + SCORE_DISTRO;
286 else if (shape(pplayer->x + 31, pplayer->y) == 'x' ||
287 shape(pplayer->x + 31, pplayer->y) == 'y')
289 add_bouncy_distro(((pplayer->x + 1 + 31)
291 (int)(pplayer->y / 32) * 32);
293 if (counting_distros == NO)
295 counting_distros = YES;
296 distro_counter = 100;
299 if (distro_counter <= 0)
300 level_change(¤t_level,pplayer->x + 31 + scroll_x, pplayer->y, 'a');
302 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
303 score = score + SCORE_DISTRO;
311 pplayer->y = (int)(pplayer->y / 32) * 32 + 30;
317 pplayer->y = (int)(pplayer->y / 32) * 32 - 32;
321 pplayer->jumping = NO;
322 /*pplayer->jump_counter = MAX_JUMP_COUNT;*/
323 /*timer_init(&pplayer->jump_timer);*/
324 timer_start(&pplayer->jump_timer,MAX_JUMP_TIME);
331 player_grabdistros(pplayer);
334 /* Slow down horizontally: */
338 if (pplayer->input.right == UP && pplayer->input.left == UP)
340 if (isice(pplayer->x, pplayer->y + 32) ||
341 !issolid(pplayer->x, pplayer->y + 32))
343 /* Slowly on ice or in air: */
347 else if (pplayer->xm < 0)
352 /* Quickly, otherwise: */
354 pplayer->xm = pplayer->xm / 2;
359 /* Drop vertically: */
361 if (!issolid(pplayer->x, pplayer->y + 32))
363 pplayer->ym = pplayer->ym + GRAVITY;
365 if (pplayer->ym > MAX_YM)
366 pplayer->ym = MAX_YM;
372 if (pplayer->safe > 0)
375 /* ---- DONE HANDLING TUX! --- */
377 /* Handle invincibility timer: */
380 if (timer_check(&pplayer->invincible_timer))
382 if (current_music == HERRING_MUSIC)
384 if (current_level.time_left <= TIME_WARNING)
386 /* stop the herring_song, prepare to play the correct
389 current_music = HURRYUP_MUSIC;
393 current_music = LEVEL_MUSIC;
395 /* stop the old music if it's being played */
401 /* Handle skidding: */
403 if (pplayer->skidding > 0)
410 if (pplayer->x >= endpos && endpos != 0)
417 void player_input(player_type *pplayer)
419 /* Handle key and joystick state: */
422 if (pplayer->input.right == DOWN && pplayer->input.left == UP)
424 if (pplayer->jumping == NO)
426 if (pplayer->xm < -SKID_XM && !pplayer->skidding &&
427 pplayer->dir == LEFT)
429 pplayer->skidding = SKID_TIME;
431 play_sound(sounds[SND_SKID], SOUND_CENTER_SPEAKER);
434 pplayer->dir = RIGHT;
437 if (pplayer->xm < 0 && !isice(pplayer->x, pplayer->y + 32) &&
445 if (pplayer->dir == RIGHT)
447 /* Facing the direction we're jumping? Go full-speed: */
449 if (pplayer->input.fire == UP)
451 pplayer->xm = pplayer->xm + RUN_SPEED;
453 if (pplayer->xm > MAX_RUN_XM)
454 pplayer->xm = MAX_RUN_XM;
456 else if ( pplayer->input.fire == DOWN)
458 pplayer->xm = pplayer->xm + WALK_SPEED;
460 if (pplayer->xm > MAX_WALK_XM)
461 pplayer->xm = MAX_WALK_XM;
466 /* Not facing the direction we're jumping?
469 pplayer->xm = pplayer->xm + WALK_SPEED / 2;
471 if (pplayer->xm > MAX_WALK_XM / 2)
472 pplayer->xm = MAX_WALK_XM / 2;
476 else if (pplayer->input.left == DOWN && pplayer->input.right == UP)
478 if (pplayer->jumping == NO)
480 if (pplayer->xm > SKID_XM && !pplayer->skidding &&
481 pplayer->dir == RIGHT)
483 pplayer->skidding = SKID_TIME;
484 play_sound(sounds[SND_SKID], SOUND_CENTER_SPEAKER);
489 if (pplayer->xm > 0 && !isice(pplayer->x, pplayer->y + 32) &&
497 if (pplayer->dir == LEFT)
499 /* Facing the direction we're jumping? Go full-speed: */
501 if (pplayer->input.fire == UP)
503 pplayer->xm = pplayer->xm - RUN_SPEED;
505 if (pplayer->xm < -MAX_RUN_XM)
506 pplayer->xm = -MAX_RUN_XM;
508 else if (pplayer->input.fire == DOWN)
510 pplayer->xm = pplayer->xm - WALK_SPEED;
512 if (pplayer->xm < -MAX_WALK_XM)
513 pplayer->xm = -MAX_WALK_XM;
518 /* Not facing the direction we're jumping?
521 pplayer->xm = pplayer->xm - WALK_SPEED / 2;
523 if (pplayer->xm < -MAX_WALK_XM / 2)
524 pplayer->xm = -MAX_WALK_XM / 2;
531 if ( pplayer->input.up == DOWN)
533 if(!timer_started(&pplayer->jump_timer))
535 timer_start(&pplayer->jump_timer,MAX_JUMP_TIME);
540 if (!issolid(pplayer->x, pplayer->y + 32) ||
543 /* If they're not on the ground, or are currently moving
544 vertically, don't jump! */
546 pplayer->jumping = NO;
547 timer_stop(&pplayer->jump_timer);
551 /* Make sure we're not standing back up into a solid! */
553 if (pplayer->size == SMALL || pplayer->duck == NO ||
554 !issolid(pplayer->x, pplayer->y))
556 pplayer->jumping = YES;
558 if (pplayer->size == SMALL)
559 play_sound(sounds[SND_JUMP], SOUND_CENTER_SPEAKER);
561 play_sound(sounds[SND_BIGJUMP], SOUND_CENTER_SPEAKER);
566 /* Keep jumping for a while: */
568 if (timer_check(&pplayer->jump_timer))
570 pplayer->ym = pplayer->ym - JUMP_SPEED;
574 timer_stop(&pplayer->jump_timer);
579 if (pplayer->input.fire == DOWN && pplayer->input.old_fire == UP && pplayer->got_coffee)
581 add_bullet(pplayer->x, pplayer->y, pplayer->xm, pplayer->dir);
587 if (pplayer->input.down == DOWN)
589 if (pplayer->size == BIG)
594 if (pplayer->size == BIG && pplayer->duck == YES)
596 /* Make sure we're not standing back up into a solid! */
598 if (!issolid(pplayer->x, pplayer->y - 32))
607 if (pplayer->input.right == UP && pplayer->input.left == UP)
609 pplayer->frame_main = 1;
614 if ((pplayer->input.fire == DOWN && (frame % 2) == 0) ||
616 pplayer->frame_main = (pplayer->frame_main + 1) % 4;
618 pplayer->frame = pplayer->frame_main;
620 if (pplayer->frame == 3)
626 void player_grabdistros(player_type *pplayer)
631 trygrabdistro(pplayer->x , pplayer->y, NO_BOUNCE);
632 trygrabdistro(pplayer->x + 31, pplayer->y, NO_BOUNCE);
634 if (pplayer->size == BIG && !pplayer->duck)
636 trygrabdistro(pplayer->x, pplayer->y - 32, NO_BOUNCE);
637 trygrabdistro(pplayer->x + 31, pplayer->y - 32, NO_BOUNCE);
642 /* Enough distros for a One-up? */
644 if (distros >= DISTROS_LIFEUP)
646 distros = distros - DISTROS_LIFEUP;
647 if(pplayer->lives < MAX_LIVES)
649 /*We want to hear the sound even, if MAX_LIVES is reached*/
650 play_sound(sounds[SND_LIFEUP], SOUND_CENTER_SPEAKER);
654 void player_draw(player_type* pplayer)
657 if (pplayer->safe == 0 || (frame % 2) == 0)
659 if (pplayer->size == SMALL)
661 if (timer_started(&pplayer->invincible_timer))
665 if (pplayer->dir == RIGHT)
667 texture_draw(&cape_right[frame % 2],
668 pplayer->x - scroll_x, pplayer->y,
673 texture_draw(&cape_left[frame % 2],
674 pplayer->x - scroll_x, pplayer->y,
680 if (!pplayer->got_coffee)
682 if (pplayer->dir == RIGHT)
684 texture_draw(&tux_right[pplayer->frame], pplayer->x - scroll_x, pplayer->y, NO_UPDATE);
688 texture_draw(&tux_left[pplayer->frame], pplayer->x - scroll_x, pplayer->y, NO_UPDATE);
693 /* Tux got coffee! */
695 if (pplayer->dir == RIGHT)
697 texture_draw(&firetux_right[pplayer->frame], pplayer->x - scroll_x, pplayer->y, NO_UPDATE);
701 texture_draw(&firetux_left[pplayer->frame], pplayer->x - scroll_x, pplayer->y, NO_UPDATE);
707 if (timer_started(&pplayer->invincible_timer))
711 if (pplayer->dir == RIGHT)
713 texture_draw(&bigcape_right[frame % 2],
714 pplayer->x - scroll_x - 8 - 16, pplayer->y - 32,
719 texture_draw(&bigcape_left[frame % 2],
720 pplayer->x -scroll_x - 8, pplayer->y - 32,
725 if (!pplayer->got_coffee)
729 if (!pplayer->skidding)
731 if (!pplayer->jumping || pplayer->ym > 0)
733 if (pplayer->dir == RIGHT)
735 texture_draw(&bigtux_right[pplayer->frame],
736 pplayer->x - scroll_x - 8, pplayer->y - 32,
741 texture_draw(&bigtux_left[pplayer->frame],
742 pplayer->x - scroll_x - 8, pplayer->y - 32,
748 if (pplayer->dir == RIGHT)
750 texture_draw(&bigtux_right_jump,
751 pplayer->x - scroll_x - 8, pplayer->y - 32,
756 texture_draw(&bigtux_left_jump,
757 pplayer->x - scroll_x - 8, pplayer->y - 32,
764 if (pplayer->dir == RIGHT)
766 texture_draw(&skidtux_right,
767 pplayer->x - scroll_x - 8, pplayer->y - 32,
772 texture_draw(&skidtux_left,
773 pplayer->x - scroll_x - 8, pplayer->y - 32,
780 if (pplayer->dir == RIGHT)
782 texture_draw(&ducktux_right, pplayer->x - scroll_x - 8, pplayer->y - 16,
787 texture_draw(&ducktux_left, pplayer->x - scroll_x - 8, pplayer->y - 16,
794 /* Tux has coffee! */
798 if (!pplayer->skidding)
800 if (!pplayer->jumping || pplayer->ym > 0)
802 if (pplayer->dir == RIGHT)
804 texture_draw(&bigfiretux_right[pplayer->frame],
805 pplayer->x - scroll_x - 8, pplayer->y - 32,
810 texture_draw(&bigfiretux_left[pplayer->frame],
811 pplayer->x - scroll_x - 8, pplayer->y - 32,
817 if (pplayer->dir == RIGHT)
819 texture_draw(&bigfiretux_right_jump,
820 pplayer->x - scroll_x - 8, pplayer->y - 32,
825 texture_draw(&bigfiretux_left_jump,
826 pplayer->x - scroll_x - 8, pplayer->y - 32,
833 if (pplayer->dir == RIGHT)
835 texture_draw(&skidfiretux_right,
836 pplayer->x - scroll_x - 8, pplayer->y - 32,
841 texture_draw(&skidfiretux_left,
842 pplayer->x - scroll_x - 8, pplayer->y - 32,
849 if (pplayer->dir == RIGHT)
851 texture_draw(&duckfiretux_right, pplayer->x - scroll_x - 8, pplayer->y - 16,
856 texture_draw(&duckfiretux_left, pplayer->x - scroll_x - 8, pplayer->y - 16,
866 void player_collision(player_type* pplayer, void* p_c_object, int c_object)
868 bad_guy_type* pbad_c = NULL;
874 /* Hurt the player if he just touched it: */
876 if (!pbad_c->dying && !pplayer->dying &&
878 pbad_c->mode != HELD)
880 if (pbad_c->mode == FLAT && pplayer->input.fire != DOWN)
885 play_sound(sounds[SND_KICK], SOUND_CENTER_SPEAKER);
887 if (pplayer->x <= pbad_c->x)
890 pbad_c->x = pbad_c->x + 16;
895 pbad_c->x = pbad_c->x - 16;
898 timer_start(&pbad_c->timer,5000);
900 else if (pbad_c->mode == FLAT && pplayer->input.fire == DOWN)
905 else if (pbad_c->mode == KICK)
907 if (pplayer->y < pbad_c->y - 16 &&
908 timer_started(&pbad_c->timer))
910 /* Step on (stop being kicked) */
913 play_sound(sounds[SND_STOMP], SOUND_CENTER_SPEAKER);
914 timer_start(&pbad_c->timer, 10000);
918 /* Hurt if you get hit by kicked laptop: */
920 if (timer_started(&pbad_c->timer))
922 if (!timer_started(&pplayer->invincible_timer))
924 player_kill(pplayer,SHRINK);
928 pbad_c->dying = FALLING;
930 play_sound(sounds[SND_FALL], SOUND_CENTER_SPEAKER);
937 if (!timer_started(&pplayer->invincible_timer ))
939 player_kill(pplayer,SHRINK);
943 pbad_c->dying = FALLING;
945 play_sound(sounds[SND_FALL], SOUND_CENTER_SPEAKER);
957 void player_kill(player_type* pplayer, int mode)
961 play_sound(sounds[SND_HURT], SOUND_CENTER_SPEAKER);
963 if (pplayer->dir == RIGHT)
965 else if (tux.dir == LEFT)
968 if (mode == SHRINK && pplayer->size == BIG)
970 if (pplayer->got_coffee)
971 pplayer->got_coffee = NO;
973 pplayer->size = SMALL;
975 pplayer->safe = TUX_SAFE_TIME;
983 void player_dying(player_type *pplayer)
985 pplayer->ym = pplayer->ym + GRAVITY;
990 player_remove_powerups(pplayer);
995 /* Remove Tux's power ups */
996 void player_remove_powerups(player_type* pplayer)
998 pplayer->got_coffee = NO;
999 pplayer->size = SMALL;
1002 void player_keep_in_bounds(player_type* pplayer)
1004 /* Keep tux in bounds: */
1007 else if(pplayer->x < scroll_x)
1008 pplayer->x = scroll_x;
1009 else if (pplayer->x < 160 + scroll_x && scroll_x > 0 && debug_mode == YES)
1011 scroll_x = pplayer->x - 160;
1012 /*pplayer->x += 160;*/
1018 else if (pplayer->x > screen->w / 2 + scroll_x && scroll_x < ((current_level.width * 32) - screen->w))
1020 /* Scroll the screen in past center: */
1022 scroll_x = pplayer->x - screen->w / 2;
1023 /*pplayer->x = 320 + scroll_x;*/
1025 if (scroll_x > ((current_level.width * 32) - screen->w))
1026 scroll_x = ((current_level.width * 32) - screen->w);
1028 else if (pplayer->x > 608 + scroll_x)
1030 /* ... unless there's no more to scroll! */
1032 /*pplayer->x = 608 + scroll_x;*/
1035 /* Keep in-bounds, vertically: */
1039 else if (pplayer->y > screen->h)
1041 player_kill(&tux,KILL);