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 = false;
53 pplayer->base.y = 240;
56 pplayer->old_base = pplayer->base;
58 pplayer->duck = false;
60 pplayer->dying = DYING_NOT;
61 pplayer->jumping = false;
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,true);
78 timer_init(&pplayer->skidding_timer,true);
79 timer_init(&pplayer->safe_timer,true);
80 timer_init(&pplayer->frame_timer,true);
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,true);
127 timer_init(&pplayer->skidding_timer,true);
128 timer_init(&pplayer->safe_timer,true);
129 timer_init(&pplayer->frame_timer,true);
130 physic_init(&pplayer->hphysic);
131 physic_init(&pplayer->vphysic);
134 void player_action(player_type* pplayer)
136 bool jumped_in_solid = false;
138 /* --- HANDLE TUX! --- */
140 player_input(pplayer);
144 pplayer->previous_base = pplayer->base;
146 pplayer->base.x += pplayer->base.xm * frame_ratio;
147 pplayer->base.y += pplayer->base.ym * frame_ratio;
149 collision_swept_object_map(&pplayer->old_base,&pplayer->base);
151 player_keep_in_bounds(pplayer);
159 if( !player_on_ground(pplayer))
161 if(player_under_solid(pplayer))
163 physic_set_state(&pplayer->vphysic,PH_VT);
164 physic_set_start_vy(&pplayer->vphysic,0);
165 jumped_in_solid = true;
169 if(!physic_is_set(&pplayer->vphysic))
171 physic_set_state(&pplayer->vphysic,PH_VT);
172 physic_set_start_vy(&pplayer->vphysic,0);
175 pplayer->base.ym = physic_get_velocity(&pplayer->vphysic);
183 if (pplayer->base.ym > 0)
185 pplayer->base.y = (int)(((int)pplayer->base.y / 32) * 32);
186 pplayer->base.ym = 0;
189 physic_init(&pplayer->vphysic);
191 /* Reset score multiplier (for multi-hits): */
193 score_multiplier = 1;
196 if(jumped_in_solid == true)
199 if (isbrick(pplayer->base.x, pplayer->base.y) ||
200 isfullbox(pplayer->base.x, pplayer->base.y))
202 trygrabdistro(pplayer->base.x, pplayer->base.y - 32,BOUNCE);
203 trybumpbadguy(pplayer->base.x, pplayer->base.y - 64);
205 if(pplayer->size == BIG)
206 trybreakbrick(pplayer->base.x, pplayer->base.y);
208 bumpbrick(pplayer->base.x, pplayer->base.y);
209 tryemptybox(pplayer->base.x, pplayer->base.y, RIGHT);
212 if (isbrick(pplayer->base.x+ 31, pplayer->base.y) ||
213 isfullbox(pplayer->base.x+ 31, pplayer->base.y))
215 trygrabdistro(pplayer->base.x+ 31, pplayer->base.y - 32,BOUNCE);
216 trybumpbadguy(pplayer->base.x+ 31, pplayer->base.y - 64);
218 if(pplayer->size == BIG)
219 trybreakbrick(pplayer->base.x+ 31, pplayer->base.y);
221 bumpbrick(pplayer->base.x+ 31, pplayer->base.y);
222 tryemptybox(pplayer->base.x+ 31, pplayer->base.y, LEFT);
226 if(pplayer->size == SMALL)
228 /* Get a distro from a brick? */
230 if (shape(pplayer->base.x, pplayer->base.y) == 'x' ||
231 shape(pplayer->base.x, pplayer->base.y) == 'y')
233 add_bouncy_distro((((int)pplayer->base.x)
235 ((int)pplayer->base.y / 32) * 32);
236 if (counting_distros == false)
238 counting_distros = true;
239 distro_counter = 100;
242 if (distro_counter <= 0)
243 level_change(¤t_level,pplayer->base.x,pplayer->base.y - 1, 'a');
245 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
246 score = score + SCORE_DISTRO;
249 else if (shape(pplayer->base.x+ 31, pplayer->base.y) == 'x' ||
250 shape(pplayer->base.x+ 31, pplayer->base.y) == 'y')
252 add_bouncy_distro((((int)pplayer->base.x + 31)
254 ((int)pplayer->base.y / 32) * 32);
255 if (counting_distros == false)
257 counting_distros = true;
258 distro_counter = 100;
261 if (distro_counter <= 0)
262 level_change(¤t_level,pplayer->base.x+ 31, pplayer->base.y, 'a');
264 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
265 score = score + SCORE_DISTRO;
271 player_grabdistros(pplayer);
272 if(jumped_in_solid == true)
275 ++pplayer->old_base.y;
276 if(player_on_ground(pplayer))
278 /* Make sure jumping is off. */
279 pplayer->jumping = false;
285 timer_check(&pplayer->safe_timer);
288 /* ---- DONE HANDLING TUX! --- */
290 /* Handle invincibility timer: */
293 if (get_current_music() == HERRING_MUSIC && !timer_check(&pplayer->invincible_timer))
296 no, we are no more invincible
297 or we were not in invincible mode
298 but are we in hurry ?
302 if (timer_get_left(&time_left) < TIME_WARNING)
304 /* yes, we are in hurry
305 stop the herring_song, prepare to play the correct
308 set_current_music(HURRYUP_MUSIC);
312 set_current_music(LEVEL_MUSIC);
315 /* start playing it */
316 play_current_music();
319 /* Handle skidding: */
321 timer_check(&pplayer->skidding_timer);
325 if (pplayer->base.x >= endpos && endpos != 0)
332 bool player_on_ground(player_type *pplayer)
334 return ( issolid(pplayer->base.x + pplayer->base.width / 2, pplayer->base.y + pplayer->base.height) ||
335 issolid(pplayer->base.x + 1, pplayer->base.y + pplayer->base.height) ||
336 issolid(pplayer->base.x + pplayer->base.width - 1, pplayer->base.y + pplayer->base.height) );
339 bool player_under_solid(player_type *pplayer)
341 return ( issolid(pplayer->base.x + pplayer->base.width / 2, pplayer->base.y) ||
342 issolid(pplayer->base.x + 1, pplayer->base.y) ||
343 issolid(pplayer->base.x + pplayer->base.width - 1, pplayer->base.y) );
346 void player_handle_horizontal_input(player_type *pplayer, int dir)
349 if ((dir ? (pplayer->base.xm < -SKID_XM) : (pplayer->base.xm > SKID_XM)) && !timer_started(&pplayer->skidding_timer) &&
350 pplayer->dir == !dir && player_on_ground(pplayer))
352 timer_start(&pplayer->skidding_timer, SKID_TIME);
354 play_sound(sounds[SND_SKID], SOUND_CENTER_SPEAKER);
360 if ((dir ? (pplayer->base.xm < 0) : (pplayer->base.xm > 0)) && !isice(pplayer->base.x, pplayer->base.y + pplayer->base.height) &&
361 !timer_started(&pplayer->skidding_timer))
363 pplayer->base.xm = 0;
368 if (pplayer->dir == dir)
370 /* Facing the direction we're jumping? Go full-speed: */
372 if (pplayer->input.fire == UP)
374 pplayer->base.xm = pplayer->base.xm + ( dir ? WALK_SPEED : -WALK_SPEED) * frame_ratio;
378 if (pplayer->base.xm > MAX_WALK_XM)
379 pplayer->base.xm = MAX_WALK_XM;
383 if (pplayer->base.xm < -MAX_WALK_XM)
384 pplayer->base.xm = -MAX_WALK_XM;
387 else if ( pplayer->input.fire == DOWN)
389 pplayer->base.xm = pplayer->base.xm + ( dir ? RUN_SPEED : -RUN_SPEED) * frame_ratio;
393 if (pplayer->base.xm > MAX_RUN_XM)
394 pplayer->base.xm = MAX_RUN_XM;
398 if (pplayer->base.xm < -MAX_RUN_XM)
399 pplayer->base.xm = -MAX_RUN_XM;
404 /* Not facing the direction we're jumping?
407 pplayer->base.xm = pplayer->base.xm + ( dir ? (WALK_SPEED / 2) : -(WALK_SPEED / 2)) * frame_ratio;
411 if (pplayer->base.xm > MAX_WALK_XM / 2)
412 pplayer->base.xm = MAX_WALK_XM / 2;
416 if (pplayer->base.xm < -MAX_WALK_XM / 2)
417 pplayer->base.xm = -MAX_WALK_XM / 2;
425 void player_handle_vertical_input(player_type *pplayer)
427 if(pplayer->input.up == DOWN)
429 if (player_on_ground(pplayer))
431 if(!physic_is_set(&pplayer->vphysic))
433 physic_set_state(&pplayer->vphysic,PH_VT);
434 physic_set_start_vy(&pplayer->vphysic,5.5);
436 pplayer->jumping = true;
437 if (pplayer->size == SMALL)
438 play_sound(sounds[SND_JUMP], SOUND_CENTER_SPEAKER);
440 play_sound(sounds[SND_BIGJUMP], SOUND_CENTER_SPEAKER);
444 else if(pplayer->input.up == UP && pplayer->jumping == true)
446 if (player_on_ground(pplayer))
448 physic_init(&pplayer->vphysic);
449 pplayer->jumping = false;
453 pplayer->jumping = false;
454 if(physic_is_set(&pplayer->vphysic))
456 if(physic_get_velocity(&pplayer->vphysic) < 0.)
458 physic_set_state(&pplayer->vphysic,PH_VT);
459 physic_set_start_vy(&pplayer->vphysic,0);
464 if(!physic_is_set(&pplayer->vphysic))
466 physic_set_state(&pplayer->vphysic,PH_VT);
473 void player_input(player_type *pplayer)
475 /* Handle key and joystick state: */
477 if(pplayer->duck == false)
479 if (pplayer->input.right == DOWN && pplayer->input.left == UP)
481 player_handle_horizontal_input(pplayer,RIGHT);
483 else if (pplayer->input.left == DOWN && pplayer->input.right == UP)
485 player_handle_horizontal_input(pplayer,LEFT);
489 if(pplayer->base.xm > 0)
491 pplayer->base.xm = (int)(pplayer->base.xm - frame_ratio);
492 if(pplayer->base.xm < 0)
493 pplayer->base.xm = 0;
495 else if(pplayer->base.xm < 0)
497 pplayer->base.xm = (int)(pplayer->base.xm + frame_ratio);
498 if(pplayer->base.xm > 0)
499 pplayer->base.xm = 0;
506 if ( pplayer->input.up == DOWN || (pplayer->input.up == UP && pplayer->jumping == true))
508 player_handle_vertical_input(pplayer);
513 if (pplayer->input.fire == DOWN && pplayer->input.old_fire == UP && pplayer->got_coffee)
515 add_bullet(pplayer->base.x, pplayer->base.y, pplayer->base.xm, pplayer->dir);
521 if (pplayer->input.down == DOWN)
523 if (pplayer->size == BIG && pplayer->duck != true)
525 pplayer->duck = true;
526 pplayer->base.height = 32;
527 pplayer->base.y += 32;
532 if (pplayer->size == BIG && pplayer->duck == true)
534 /* Make sure we're not standing back up into a solid! */
535 pplayer->base.height = 64;
536 pplayer->base.y -= 32;
538 if (!collision_object_map(&pplayer->base) /*issolid(pplayer->base.x + 16, pplayer->base.y - 16)*/)
540 pplayer->duck = false;
541 pplayer->base.height = 64;
542 pplayer->old_base.y -= 32;
543 pplayer->old_base.height = 64;
547 pplayer->base.height = 32;
548 pplayer->base.y += 32;
553 pplayer->duck = false;
559 if(!timer_check(&pplayer->frame_timer))
561 timer_start(&pplayer->frame_timer,25);
562 if (pplayer->input.right == UP && pplayer->input.left == UP)
564 pplayer->frame_main = 1;
569 if ((pplayer->input.fire == DOWN && (frame % 2) == 0) ||
571 pplayer->frame_main = (pplayer->frame_main + 1) % 4;
573 pplayer->frame = pplayer->frame_main;
575 if (pplayer->frame == 3)
582 void player_grabdistros(player_type *pplayer)
587 trygrabdistro(pplayer->base.x, pplayer->base.y, NO_BOUNCE);
588 trygrabdistro(pplayer->base.x+ 31, pplayer->base.y, NO_BOUNCE);
590 trygrabdistro(pplayer->base.x, pplayer->base.y + pplayer->base.height, NO_BOUNCE);
591 trygrabdistro(pplayer->base.x+ 31, pplayer->base.y + pplayer->base.height, NO_BOUNCE);
593 if(pplayer->size == BIG)
595 trygrabdistro(pplayer->base.x, pplayer->base.y + pplayer->base.height / 2, NO_BOUNCE);
596 trygrabdistro(pplayer->base.x+ 31, pplayer->base.y + pplayer->base.height / 2, NO_BOUNCE);
602 /* Enough distros for a One-up? */
604 if (distros >= DISTROS_LIFEUP)
606 distros = distros - DISTROS_LIFEUP;
607 if(pplayer->lives < MAX_LIVES)
609 /*We want to hear the sound even, if MAX_LIVES is reached*/
610 play_sound(sounds[SND_LIFEUP], SOUND_CENTER_SPEAKER);
614 void player_draw(player_type* pplayer)
616 if (!timer_started(&pplayer->safe_timer) || (frame % 2) == 0)
618 if (pplayer->size == SMALL)
620 if (timer_started(&pplayer->invincible_timer))
624 if (pplayer->dir == RIGHT)
626 texture_draw(&cape_right[frame % 2],
627 pplayer->base.x- scroll_x, pplayer->base.y);
631 texture_draw(&cape_left[frame % 2],
632 pplayer->base.x- scroll_x, pplayer->base.y);
637 if (!pplayer->got_coffee)
639 if (pplayer->dir == RIGHT)
641 texture_draw(&tux_right[pplayer->frame], pplayer->base.x- scroll_x, pplayer->base.y);
645 texture_draw(&tux_left[pplayer->frame], pplayer->base.x- scroll_x, pplayer->base.y);
650 /* Tux got coffee! */
652 if (pplayer->dir == RIGHT)
654 texture_draw(&firetux_right[pplayer->frame], pplayer->base.x- scroll_x, pplayer->base.y);
658 texture_draw(&firetux_left[pplayer->frame], pplayer->base.x- scroll_x, pplayer->base.y);
664 if (timer_started(&pplayer->invincible_timer))
668 if (pplayer->dir == RIGHT)
670 texture_draw(&bigcape_right[frame % 2],
671 pplayer->base.x- scroll_x - 8, pplayer->base.y);
675 texture_draw(&bigcape_left[frame % 2],
676 pplayer->base.x-scroll_x - 8, pplayer->base.y);
680 if (!pplayer->got_coffee)
684 if (!timer_started(&pplayer->skidding_timer))
686 if (!pplayer->jumping || pplayer->base.ym > 0)
688 if (pplayer->dir == RIGHT)
690 texture_draw(&bigtux_right[pplayer->frame],
691 pplayer->base.x- scroll_x - 8, pplayer->base.y);
695 texture_draw(&bigtux_left[pplayer->frame],
696 pplayer->base.x- scroll_x - 8, pplayer->base.y);
701 if (pplayer->dir == RIGHT)
703 texture_draw(&bigtux_right_jump,
704 pplayer->base.x- scroll_x - 8, pplayer->base.y);
708 texture_draw(&bigtux_left_jump,
709 pplayer->base.x- scroll_x - 8, pplayer->base.y);
715 if (pplayer->dir == RIGHT)
717 texture_draw(&skidtux_right,
718 pplayer->base.x- scroll_x - 8, pplayer->base.y);
722 texture_draw(&skidtux_left,
723 pplayer->base.x- scroll_x - 8, pplayer->base.y);
729 if (pplayer->dir == RIGHT)
731 texture_draw(&ducktux_right, pplayer->base.x- scroll_x - 8, pplayer->base.y - 16);
735 texture_draw(&ducktux_left, pplayer->base.x- scroll_x - 8, pplayer->base.y - 16);
741 /* Tux has coffee! */
745 if (!timer_started(&pplayer->skidding_timer))
747 if (!pplayer->jumping || pplayer->base.ym > 0)
749 if (pplayer->dir == RIGHT)
751 texture_draw(&bigfiretux_right[pplayer->frame],
752 pplayer->base.x- scroll_x - 8, pplayer->base.y);
756 texture_draw(&bigfiretux_left[pplayer->frame],
757 pplayer->base.x- scroll_x - 8, pplayer->base.y);
762 if (pplayer->dir == RIGHT)
764 texture_draw(&bigfiretux_right_jump,
765 pplayer->base.x- scroll_x - 8, pplayer->base.y);
769 texture_draw(&bigfiretux_left_jump,
770 pplayer->base.x- scroll_x - 8, pplayer->base.y);
776 if (pplayer->dir == RIGHT)
778 texture_draw(&skidfiretux_right,
779 pplayer->base.x- scroll_x - 8, pplayer->base.y);
783 texture_draw(&skidfiretux_left,
784 pplayer->base.x- scroll_x - 8, pplayer->base.y);
790 if (pplayer->dir == RIGHT)
792 texture_draw(&duckfiretux_right, pplayer->base.x- scroll_x - 8, pplayer->base.y - 16);
796 texture_draw(&duckfiretux_left, pplayer->base.x- scroll_x - 8, pplayer->base.y - 16);
804 void player_collision(player_type* pplayer, void* p_c_object, int c_object)
806 bad_guy_type* pbad_c = NULL;
811 pbad_c = (bad_guy_type*) p_c_object;
812 /* Hurt the player if he just touched it: */
814 if (!pbad_c->dying && !pplayer->dying &&
815 !timer_started(&pplayer->safe_timer) &&
816 pbad_c->mode != HELD)
818 if (pbad_c->mode == FLAT && pplayer->input.fire != DOWN)
823 play_sound(sounds[SND_KICK], SOUND_CENTER_SPEAKER);
825 if (pplayer->base.x < pbad_c->base.x + (pbad_c->base.width/2))
828 pbad_c->base.x = pbad_c->base.x + 16;
833 pbad_c->base.x = pbad_c->base.x - 32;
836 timer_start(&pbad_c->timer,5000);
838 else if (pbad_c->mode == FLAT && pplayer->input.fire == DOWN)
843 else if (pbad_c->mode == KICK)
845 if (pplayer->base.y < pbad_c->base.y - 16 &&
846 timer_started(&pbad_c->timer))
848 /* Step on (stop being kicked) */
851 play_sound(sounds[SND_STOMP], SOUND_CENTER_SPEAKER);
852 timer_start(&pbad_c->timer, 10000);
856 /* Hurt if you get hit by kicked laptop: */
858 if (timer_started(&pbad_c->timer))
860 if (!timer_started(&pplayer->invincible_timer))
862 player_kill(pplayer,SHRINK);
866 pbad_c->dying = DYING_FALLING;
867 play_sound(sounds[SND_FALL], SOUND_CENTER_SPEAKER);
868 add_score(pbad_c->base.x - scroll_x,
870 25 * score_multiplier);
877 if (!timer_started(&pplayer->invincible_timer ))
879 player_kill(pplayer,SHRINK);
883 pbad_c->dying = DYING_FALLING;
884 play_sound(sounds[SND_FALL], SOUND_CENTER_SPEAKER);
885 add_score(pbad_c->base.x - scroll_x,
887 25 * score_multiplier);
901 void player_kill(player_type* pplayer, int mode)
903 pplayer->base.ym = -5;
905 play_sound(sounds[SND_HURT], SOUND_CENTER_SPEAKER);
907 if (pplayer->dir == RIGHT)
908 pplayer->base.xm = -8;
909 else if (pplayer->dir == LEFT)
910 pplayer->base.xm = 8;
912 if (mode == SHRINK && pplayer->size == BIG)
914 if (pplayer->got_coffee)
915 pplayer->got_coffee = false;
917 pplayer->size = SMALL;
918 pplayer->base.height = 32;
920 timer_start(&pplayer->safe_timer,TUX_SAFE_TIME);
924 pplayer->dying = DYING_SQUISHED;
928 void player_dying(player_type *pplayer)
930 pplayer->base.ym = pplayer->base.ym + gravity;
935 player_remove_powerups(pplayer);
936 pplayer->dying = DYING_NOT;
938 player_level_begin(pplayer);
942 /* Remove Tux's power ups */
943 void player_remove_powerups(player_type* pplayer)
945 pplayer->got_coffee = false;
946 pplayer->size = SMALL;
947 pplayer->base.height = 32;
950 void player_keep_in_bounds(player_type* pplayer)
952 /* Keep tux in bounds: */
953 if (pplayer->base.x< 0)
955 else if(pplayer->base.x< scroll_x)
956 pplayer->base.x= scroll_x;
957 else if (pplayer->base.x< 160 + scroll_x && scroll_x > 0 && debug_mode == true)
959 scroll_x = pplayer->base.x- 160;
960 /*pplayer->base.x+= 160;*/
966 else if (pplayer->base.x> screen->w / 2 + scroll_x && scroll_x < ((current_level.width * 32) - screen->w))
968 /* Scroll the screen in past center: */
970 scroll_x = pplayer->base.x- screen->w / 2;
971 /*pplayer->base.x= 320 + scroll_x;*/
973 if (scroll_x > ((current_level.width * 32) - screen->w))
974 scroll_x = ((current_level.width * 32) - screen->w);
976 else if (pplayer->base.x> 608 + scroll_x)
978 /* ... unless there's no more to scroll! */
980 /*pplayer->base.x= 608 + scroll_x;*/
983 /* Keep in-bounds, vertically: */
985 if (pplayer->base.y > screen->h)
987 player_kill(&tux,KILL);