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->base.width = 32;
23 pplayer->base.height = 32;
25 pplayer->base.updated = SDL_GetTicks();
26 pplayer->size = SMALL;
27 pplayer->got_coffee = NO;
30 pplayer->base.y = 240;
37 pplayer->safe = TUX_SAFE_TIME;
39 pplayer->jumping = NO;
40 pplayer->skidding = 0;
42 pplayer->frame_main = 0;
46 pplayer->input.down = UP;
47 pplayer->input.fire = UP;
48 pplayer->input.left = UP;
49 pplayer->input.old_fire = UP;
50 pplayer->input.right = UP;
51 pplayer->input.up = UP;
53 timer_init(&pplayer->invincible_timer);
56 void player_level_begin(player_type* pplayer)
59 pplayer->base.y = 240;
64 void player_action(player_type* pplayer)
67 double frame_ratio = get_frame_ratio(&pplayer->base);
69 /* --- HANDLE TUX! --- */
71 player_input(pplayer);
75 pplayer->base.x= pplayer->base.x+ pplayer->base.xm * frame_ratio;
76 pplayer->base.y = pplayer->base.y + pplayer->base.ym * frame_ratio;
78 player_keep_in_bounds(pplayer);
84 if (issolid(pplayer->base.x, pplayer->base.y + 31) &&
85 !issolid(pplayer->base.x- pplayer->base.xm, pplayer->base.y + 31))
87 while (issolid(pplayer->base.x, pplayer->base.y + 31))
89 if (pplayer->base.xm < 0)
91 else if (pplayer->base.xm > 0)
98 if (issolid(pplayer->base.x, pplayer->base.y) &&
99 !issolid(pplayer->base.x- pplayer->base.xm, pplayer->base.y))
101 while (issolid(pplayer->base.x, (pplayer->base.y)))
103 if (pplayer->base.xm < 0)
105 else if (pplayer->base.xm > 0)
109 pplayer->base.xm = 0;
112 if (issolid(pplayer->base.x, pplayer->base.y + 31))
114 /* Set down properly: */
117 while (issolid(pplayer->base.x, pplayer->base.y + 31))
121 DEBUG_MSG("FIXME - UNDER certain circumstances I'm hanging in a loop here!");
123 if (pplayer->base.ym < 0)
125 else if (pplayer->base.ym > 0)
130 /* Reset score multiplier (for multi-hits): */
132 if (pplayer->base.ym > 0)
133 score_multiplier = 1;
138 pplayer->base.ym = 0;
139 pplayer->jumping = NO;
143 /* Bump into things: */
145 if (issolid(pplayer->base.x, pplayer->base.y) ||
146 (pplayer->size == BIG && !pplayer->duck &&
147 (issolid(pplayer->base.x, pplayer->base.y - 32))))
149 if (!issolid(pplayer->base.x- pplayer->base.xm, pplayer->base.y) &&
150 (pplayer->size == SMALL || pplayer->duck ||
151 !issolid(pplayer->base.x- pplayer->base.xm, pplayer->base.y - 32)))
153 pplayer->base.x = pplayer->base.x- pplayer->base.xm;
154 pplayer->base.xm = 0;
156 else if (!issolid(pplayer->base.x, pplayer->base.y - pplayer->base.ym) &&
157 (pplayer->size == SMALL || pplayer->duck ||
158 !issolid(pplayer->base.x, pplayer->base.y - 32 - pplayer->base.ym)))
160 if (pplayer->base.ym <= 0)
164 if (pplayer->size == BIG)
166 /* Break bricks and empty boxes: */
170 if (isbrick(pplayer->base.x, pplayer->base.y - 32) ||
171 isfullbox(pplayer->base.x, pplayer->base.y - 32))
173 trygrabdistro(pplayer->base.x, pplayer->base.y - 64, BOUNCE);
174 trybumpbadguy(pplayer->base.x, pplayer->base.y - 96);
176 if (isfullbox(pplayer->base.x, pplayer->base.y - 32))
178 bumpbrick(pplayer->base.x, pplayer->base.y - 32);
181 trybreakbrick(pplayer->base.x, pplayer->base.y - 32);
182 tryemptybox(pplayer->base.x, pplayer->base.y - 32);
185 if (isbrick(pplayer->base.x+ 31, pplayer->base.y - 32) ||
186 isfullbox(pplayer->base.x+ 31, pplayer->base.y - 32))
188 trygrabdistro(pplayer->base.x+ 31,
189 pplayer->base.y - 64,
191 trybumpbadguy(pplayer->base.x+ 31,
192 pplayer->base.y - 96);
194 if (isfullbox(pplayer->base.x+ 31, pplayer->base.y - 32))
196 bumpbrick(pplayer->base.x+ 31, pplayer->base.y - 32);
199 trybreakbrick(pplayer->base.x+ 31,
200 pplayer->base.y - 32);
201 tryemptybox(pplayer->base.x+ 31,
202 pplayer->base.y - 32);
207 if (isbrick(pplayer->base.x, pplayer->base.y) ||
208 isfullbox(pplayer->base.x, pplayer->base.y))
210 trygrabdistro(pplayer->base.x, pplayer->base.y - 32,BOUNCE);
211 trybumpbadguy(pplayer->base.x, pplayer->base.y - 64);
212 if (isfullbox(pplayer->base.x, pplayer->base.y))
213 bumpbrick(pplayer->base.x, pplayer->base.y);
214 trybreakbrick(pplayer->base.x, pplayer->base.y);
215 tryemptybox(pplayer->base.x, pplayer->base.y);
218 if (isbrick(pplayer->base.x+ 31, pplayer->base.y) ||
219 isfullbox(pplayer->base.x+ 31, pplayer->base.y))
221 trygrabdistro(pplayer->base.x+ 31,
222 pplayer->base.y - 32,
224 trybumpbadguy(pplayer->base.x+ 31,
225 pplayer->base.y - 64);
226 if (isfullbox(pplayer->base.x+ 31, pplayer->base.y))
227 bumpbrick(pplayer->base.x+ 31, pplayer->base.y);
228 trybreakbrick(pplayer->base.x+ 31, pplayer->base.y);
229 tryemptybox(pplayer->base.x+ 31, pplayer->base.y);
235 /* It's a brick and we're small, make the brick
236 bounce, and grab any distros above it: */
238 if (isbrick(pplayer->base.x, pplayer->base.y) ||
239 isfullbox(pplayer->base.x, pplayer->base.y))
241 trygrabdistro(pplayer->base.x, pplayer->base.y - 32,BOUNCE);
242 trybumpbadguy(pplayer->base.x, pplayer->base.y - 64);
243 bumpbrick(pplayer->base.x, pplayer->base.y);
244 tryemptybox(pplayer->base.x, pplayer->base.y);
247 if (isbrick(pplayer->base.x+ 31, pplayer->base.y) ||
248 isfullbox(pplayer->base.x+ 31, pplayer->base.y))
250 trygrabdistro(pplayer->base.x+ 31, pplayer->base.y - 32,BOUNCE);
251 trybumpbadguy(pplayer->base.x+ 31, pplayer->base.y - 64);
252 bumpbrick(pplayer->base.x+ 31, pplayer->base.y);
253 tryemptybox(pplayer->base.x+ 31, pplayer->base.y);
257 /* Get a distro from a brick? */
259 if (shape(pplayer->base.x, pplayer->base.y) == 'x' ||
260 shape(pplayer->base.x, pplayer->base.y) == 'y')
262 add_bouncy_distro(((pplayer->base.x+ 1)
264 (int)(pplayer->base.y / 32) * 32);
266 if (counting_distros == NO)
268 counting_distros = YES;
269 distro_counter = 100;
272 if (distro_counter <= 0)
273 level_change(¤t_level,pplayer->base.x, pplayer->base.y, 'a');
275 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
276 score = score + SCORE_DISTRO;
279 else if (shape(pplayer->base.x+ 31, pplayer->base.y) == 'x' ||
280 shape(pplayer->base.x+ 31, pplayer->base.y) == 'y')
282 add_bouncy_distro(((pplayer->base.x+ 1 + 31)
284 (int)(pplayer->base.y / 32) * 32);
286 if (counting_distros == NO)
288 counting_distros = YES;
289 distro_counter = 100;
292 if (distro_counter <= 0)
293 level_change(¤t_level,pplayer->base.x+ 31 + scroll_x, pplayer->base.y, 'a');
295 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
296 score = score + SCORE_DISTRO;
304 pplayer->base.y = (int)(pplayer->base.y / 32) * 32 + 30;
310 pplayer->base.y = (int)(pplayer->base.y / 32) * 32 - 32;
313 pplayer->base.ym = 0;
314 pplayer->jumping = NO;
315 /*pplayer->jump_counter = MAX_JUMP_COUNT;*/
316 /*timer_init(&pplayer->jump_timer);*/
317 timer_start(&pplayer->jump_timer,MAX_JUMP_TIME);
324 player_grabdistros(pplayer);
327 /* Slow down horizontally: */
331 if (pplayer->input.right == UP && pplayer->input.left == UP)
333 if (isice(pplayer->base.x, pplayer->base.y + 32) ||
334 !issolid(pplayer->base.x, pplayer->base.y + 32))
336 /* Slowly on ice or in air: */
338 if (pplayer->base.xm > 0)
340 else if (pplayer->base.xm < 0)
345 /* Quickly, otherwise: */
347 pplayer->base.xm = pplayer->base.xm / 2;
352 /* Drop vertically: */
354 if (!issolid(pplayer->base.x, pplayer->base.y + 32))
356 pplayer->base.ym = pplayer->base.ym + GRAVITY;
358 if (pplayer->base.ym > MAX_YM)
359 pplayer->base.ym = MAX_YM;
365 if (pplayer->safe > 0)
368 /* ---- DONE HANDLING TUX! --- */
370 /* Handle invincibility timer: */
373 if (timer_check(&pplayer->invincible_timer))
375 if (current_music == HERRING_MUSIC)
377 if (current_level.time_left <= TIME_WARNING)
379 /* stop the herring_song, prepare to play the correct
382 current_music = HURRYUP_MUSIC;
386 current_music = LEVEL_MUSIC;
388 /* stop the old music if it's being played */
394 /* Handle skidding: */
396 if (pplayer->skidding > 0)
403 if (pplayer->base.x>= endpos && endpos != 0)
410 void player_input(player_type *pplayer)
412 /* Handle key and joystick state: */
415 if (pplayer->input.right == DOWN && pplayer->input.left == UP)
417 if (pplayer->jumping == NO)
419 if (pplayer->base.xm < -SKID_XM && !pplayer->skidding &&
420 pplayer->dir == LEFT)
422 pplayer->skidding = SKID_TIME;
424 play_sound(sounds[SND_SKID], SOUND_CENTER_SPEAKER);
427 pplayer->dir = RIGHT;
430 if (pplayer->base.xm < 0 && !isice(pplayer->base.x, pplayer->base.y + 32) &&
433 pplayer->base.xm = 0;
438 if (pplayer->dir == RIGHT)
440 /* Facing the direction we're jumping? Go full-speed: */
442 if (pplayer->input.fire == UP)
444 pplayer->base.xm = pplayer->base.xm + WALK_SPEED;
446 if (pplayer->base.xm > MAX_WALK_XM)
447 pplayer->base.xm = MAX_WALK_XM;
449 else if ( pplayer->input.fire == DOWN)
451 pplayer->base.xm = pplayer->base.xm + RUN_SPEED;
453 if (pplayer->base.xm > MAX_RUN_XM)
454 pplayer->base.xm = MAX_RUN_XM;
459 /* Not facing the direction we're jumping?
462 pplayer->base.xm = pplayer->base.xm + WALK_SPEED / 2;
464 if (pplayer->base.xm > MAX_WALK_XM / 2)
465 pplayer->base.xm = MAX_WALK_XM / 2;
469 else if (pplayer->input.left == DOWN && pplayer->input.right == UP)
471 if (pplayer->jumping == NO)
473 if (pplayer->base.xm > SKID_XM && !pplayer->skidding &&
474 pplayer->dir == RIGHT)
476 pplayer->skidding = SKID_TIME;
477 play_sound(sounds[SND_SKID], SOUND_CENTER_SPEAKER);
482 if (pplayer->base.xm > 0 && !isice(pplayer->base.x, pplayer->base.y + 32) &&
485 pplayer->base.xm = 0;
490 if (pplayer->dir == LEFT)
492 /* Facing the direction we're jumping? Go full-speed: */
494 if (pplayer->input.fire == UP)
496 pplayer->base.xm = pplayer->base.xm - WALK_SPEED;
498 if (pplayer->base.xm < -MAX_WALK_XM)
499 pplayer->base.xm = -MAX_WALK_XM;
501 else if (pplayer->input.fire == DOWN)
503 pplayer->base.xm = pplayer->base.xm - RUN_SPEED;
505 if (pplayer->base.xm < -MAX_RUN_XM)
506 pplayer->base.xm = -MAX_RUN_XM;
511 /* Not facing the direction we're jumping?
514 pplayer->base.xm = pplayer->base.xm - WALK_SPEED / 2;
516 if (pplayer->base.xm < -MAX_WALK_XM / 2)
517 pplayer->base.xm = -MAX_WALK_XM / 2;
524 if ( pplayer->input.up == DOWN)
526 if(!timer_started(&pplayer->jump_timer))
528 timer_start(&pplayer->jump_timer,MAX_JUMP_TIME);
533 if (!issolid(pplayer->base.x, pplayer->base.y + 32) ||
534 pplayer->base.ym != 0)
536 /* If they're not on the ground, or are currently moving
537 vertically, don't jump! */
539 pplayer->jumping = NO;
540 timer_stop(&pplayer->jump_timer);
544 /* Make sure we're not standing back up into a solid! */
546 if (pplayer->size == SMALL || pplayer->duck == NO ||
547 !issolid(pplayer->base.x, pplayer->base.y))
549 pplayer->jumping = YES;
551 if (pplayer->size == SMALL)
552 play_sound(sounds[SND_JUMP], SOUND_CENTER_SPEAKER);
554 play_sound(sounds[SND_BIGJUMP], SOUND_CENTER_SPEAKER);
559 /* Keep jumping for a while: */
561 if (timer_check(&pplayer->jump_timer))
563 pplayer->base.ym = pplayer->base.ym - JUMP_SPEED;
567 timer_stop(&pplayer->jump_timer);
572 if (pplayer->input.fire == DOWN && pplayer->input.old_fire == UP && pplayer->got_coffee)
574 add_bullet(pplayer->base.x, pplayer->base.y, pplayer->base.xm, pplayer->dir);
580 if (pplayer->input.down == DOWN)
582 if (pplayer->size == BIG)
587 if (pplayer->size == BIG && pplayer->duck == YES)
589 /* Make sure we're not standing back up into a solid! */
591 if (!issolid(pplayer->base.x, pplayer->base.y - 32))
600 if (pplayer->input.right == UP && pplayer->input.left == UP)
602 pplayer->frame_main = 1;
607 if ((pplayer->input.fire == DOWN && (frame % 2) == 0) ||
609 pplayer->frame_main = (pplayer->frame_main + 1) % 4;
611 pplayer->frame = pplayer->frame_main;
613 if (pplayer->frame == 3)
619 void player_grabdistros(player_type *pplayer)
624 trygrabdistro(pplayer->base.x, pplayer->base.y, NO_BOUNCE);
625 trygrabdistro(pplayer->base.x+ 31, pplayer->base.y, NO_BOUNCE);
627 if (pplayer->size == BIG && !pplayer->duck)
629 trygrabdistro(pplayer->base.x, pplayer->base.y - 32, NO_BOUNCE);
630 trygrabdistro(pplayer->base.x+ 31, pplayer->base.y - 32, NO_BOUNCE);
635 /* Enough distros for a One-up? */
637 if (distros >= DISTROS_LIFEUP)
639 distros = distros - DISTROS_LIFEUP;
640 if(pplayer->lives < MAX_LIVES)
642 /*We want to hear the sound even, if MAX_LIVES is reached*/
643 play_sound(sounds[SND_LIFEUP], SOUND_CENTER_SPEAKER);
647 void player_draw(player_type* pplayer)
650 if (pplayer->safe == 0 || (frame % 2) == 0)
652 if (pplayer->size == SMALL)
654 if (timer_started(&pplayer->invincible_timer))
658 if (pplayer->dir == RIGHT)
660 texture_draw(&cape_right[frame % 2],
661 pplayer->base.x- scroll_x, pplayer->base.y,
666 texture_draw(&cape_left[frame % 2],
667 pplayer->base.x- scroll_x, pplayer->base.y,
673 if (!pplayer->got_coffee)
675 if (pplayer->dir == RIGHT)
677 texture_draw(&tux_right[pplayer->frame], pplayer->base.x- scroll_x, pplayer->base.y, NO_UPDATE);
681 texture_draw(&tux_left[pplayer->frame], pplayer->base.x- scroll_x, pplayer->base.y, NO_UPDATE);
686 /* Tux got coffee! */
688 if (pplayer->dir == RIGHT)
690 texture_draw(&firetux_right[pplayer->frame], pplayer->base.x- scroll_x, pplayer->base.y, NO_UPDATE);
694 texture_draw(&firetux_left[pplayer->frame], pplayer->base.x- scroll_x, pplayer->base.y, NO_UPDATE);
700 if (timer_started(&pplayer->invincible_timer))
704 if (pplayer->dir == RIGHT)
706 texture_draw(&bigcape_right[frame % 2],
707 pplayer->base.x- scroll_x - 8 - 16, pplayer->base.y - 32,
712 texture_draw(&bigcape_left[frame % 2],
713 pplayer->base.x-scroll_x - 8, pplayer->base.y - 32,
718 if (!pplayer->got_coffee)
722 if (!pplayer->skidding)
724 if (!pplayer->jumping || pplayer->base.ym > 0)
726 if (pplayer->dir == RIGHT)
728 texture_draw(&bigtux_right[pplayer->frame],
729 pplayer->base.x- scroll_x - 8, pplayer->base.y - 32,
734 texture_draw(&bigtux_left[pplayer->frame],
735 pplayer->base.x- scroll_x - 8, pplayer->base.y - 32,
741 if (pplayer->dir == RIGHT)
743 texture_draw(&bigtux_right_jump,
744 pplayer->base.x- scroll_x - 8, pplayer->base.y - 32,
749 texture_draw(&bigtux_left_jump,
750 pplayer->base.x- scroll_x - 8, pplayer->base.y - 32,
757 if (pplayer->dir == RIGHT)
759 texture_draw(&skidtux_right,
760 pplayer->base.x- scroll_x - 8, pplayer->base.y - 32,
765 texture_draw(&skidtux_left,
766 pplayer->base.x- scroll_x - 8, pplayer->base.y - 32,
773 if (pplayer->dir == RIGHT)
775 texture_draw(&ducktux_right, pplayer->base.x- scroll_x - 8, pplayer->base.y - 16,
780 texture_draw(&ducktux_left, pplayer->base.x- scroll_x - 8, pplayer->base.y - 16,
787 /* Tux has coffee! */
791 if (!pplayer->skidding)
793 if (!pplayer->jumping || pplayer->base.ym > 0)
795 if (pplayer->dir == RIGHT)
797 texture_draw(&bigfiretux_right[pplayer->frame],
798 pplayer->base.x- scroll_x - 8, pplayer->base.y - 32,
803 texture_draw(&bigfiretux_left[pplayer->frame],
804 pplayer->base.x- scroll_x - 8, pplayer->base.y - 32,
810 if (pplayer->dir == RIGHT)
812 texture_draw(&bigfiretux_right_jump,
813 pplayer->base.x- scroll_x - 8, pplayer->base.y - 32,
818 texture_draw(&bigfiretux_left_jump,
819 pplayer->base.x- scroll_x - 8, pplayer->base.y - 32,
826 if (pplayer->dir == RIGHT)
828 texture_draw(&skidfiretux_right,
829 pplayer->base.x- scroll_x - 8, pplayer->base.y - 32,
834 texture_draw(&skidfiretux_left,
835 pplayer->base.x- scroll_x - 8, pplayer->base.y - 32,
842 if (pplayer->dir == RIGHT)
844 texture_draw(&duckfiretux_right, pplayer->base.x- scroll_x - 8, pplayer->base.y - 16,
849 texture_draw(&duckfiretux_left, pplayer->base.x- scroll_x - 8, pplayer->base.y - 16,
859 void player_collision(player_type* pplayer, void* p_c_object, int c_object)
861 bad_guy_type* pbad_c = NULL;
867 /* Hurt the player if he just touched it: */
869 if (!pbad_c->dying && !pplayer->dying &&
871 pbad_c->mode != HELD)
873 if (pbad_c->mode == FLAT && pplayer->input.fire != DOWN)
878 play_sound(sounds[SND_KICK], SOUND_CENTER_SPEAKER);
880 if (pplayer->base.x<= pbad_c->base.x)
883 pbad_c->base.x = pbad_c->base.x + 16;
888 pbad_c->base.x = pbad_c->base.x - 16;
891 timer_start(&pbad_c->timer,5000);
893 else if (pbad_c->mode == FLAT && pplayer->input.fire == DOWN)
898 else if (pbad_c->mode == KICK)
900 if (pplayer->base.y < pbad_c->base.y - 16 &&
901 timer_started(&pbad_c->timer))
903 /* Step on (stop being kicked) */
906 play_sound(sounds[SND_STOMP], SOUND_CENTER_SPEAKER);
907 timer_start(&pbad_c->timer, 10000);
911 /* Hurt if you get hit by kicked laptop: */
913 if (timer_started(&pbad_c->timer))
915 if (!timer_started(&pplayer->invincible_timer))
917 player_kill(pplayer,SHRINK);
921 pbad_c->dying = FALLING;
922 pbad_c->base.ym = -8;
923 play_sound(sounds[SND_FALL], SOUND_CENTER_SPEAKER);
930 if (!timer_started(&pplayer->invincible_timer ))
932 player_kill(pplayer,SHRINK);
936 pbad_c->dying = FALLING;
937 pbad_c->base.ym = -8;
938 play_sound(sounds[SND_FALL], SOUND_CENTER_SPEAKER);
950 void player_kill(player_type* pplayer, int mode)
952 pplayer->base.ym = -5;
954 play_sound(sounds[SND_HURT], SOUND_CENTER_SPEAKER);
956 if (pplayer->dir == RIGHT)
957 pplayer->base.xm = -8;
958 else if (tux.dir == LEFT)
959 pplayer->base.xm = 8;
961 if (mode == SHRINK && pplayer->size == BIG)
963 if (pplayer->got_coffee)
964 pplayer->got_coffee = NO;
966 pplayer->size = SMALL;
968 pplayer->safe = TUX_SAFE_TIME;
976 void player_dying(player_type *pplayer)
978 pplayer->base.ym = pplayer->base.ym + GRAVITY;
983 player_remove_powerups(pplayer);
988 /* Remove Tux's power ups */
989 void player_remove_powerups(player_type* pplayer)
991 pplayer->got_coffee = NO;
992 pplayer->size = SMALL;
995 void player_keep_in_bounds(player_type* pplayer)
997 /* Keep tux in bounds: */
998 if (pplayer->base.x< 0)
1000 else if(pplayer->base.x< scroll_x)
1001 pplayer->base.x= scroll_x;
1002 else if (pplayer->base.x< 160 + scroll_x && scroll_x > 0 && debug_mode == YES)
1004 scroll_x = pplayer->base.x- 160;
1005 /*pplayer->base.x+= 160;*/
1011 else if (pplayer->base.x> screen->w / 2 + scroll_x && scroll_x < ((current_level.width * 32) - screen->w))
1013 /* Scroll the screen in past center: */
1015 scroll_x = pplayer->base.x- screen->w / 2;
1016 /*pplayer->base.x= 320 + scroll_x;*/
1018 if (scroll_x > ((current_level.width * 32) - screen->w))
1019 scroll_x = ((current_level.width * 32) - screen->w);
1021 else if (pplayer->base.x> 608 + scroll_x)
1023 /* ... unless there's no more to scroll! */
1025 /*pplayer->base.x= 608 + scroll_x;*/
1028 /* Keep in-bounds, vertically: */
1030 if (pplayer->base.y < 0)
1031 pplayer->base.y = 0;
1032 else if (pplayer->base.y > screen->h)
1034 player_kill(&tux,KILL);