6 by Bill Kendrick & Tobias Glaesser
7 bill@newbreedsoftware.com
8 http://www.newbreedsoftware.com/supertux/
10 April 11, 2000 - February 1st, 2004
23 #include <sys/types.h>
32 #include "high_scores.h"
40 #include "collision.h"
42 /* extern variables */
44 extern char* soundfilenames[NUM_SOUNDS];
46 /* Local variables: */
48 texture_type img_waves[3], img_water, img_pole, img_poletop, img_flag[2];
49 texture_type img_cloud[2][4];
52 char level_subset[100];
56 /* Local function prototypes: */
58 void levelintro(void);
60 void loadlevelsong(void);
61 void unloadlevelsong(void);
62 void loadshared(void);
63 void unloadshared(void);
64 void drawstatus(void);
65 void drawendscreen(void);
66 void drawresultscreen(void);
74 sprintf(str, "LEVEL %d", level);
75 text_drawf(&red_text, str, 0, 200, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
77 sprintf(str, "%s", current_level.name);
78 text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
80 sprintf(str, "TUX x %d", tux.lives);
81 text_drawf(&blue_text, str, 0, 256, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
89 void start_timers(void)
91 timer_start(&time_left,current_level.time_left*1000);
92 st_pause_ticks_init();
93 update_time = st_get_ticks();
96 void activate_bad_guys(void)
100 /* Activate bad guys: */
102 for (y = 0; y < 15; y++)
104 for (x = 0; x < current_level.width; x++)
106 if (current_level.tiles[y][x] >= '0' && current_level.tiles[y][x] <= '9')
108 add_bad_guy(x * 32, y * 32, current_level.tiles[y][x] - '0');
109 current_level.tiles[y][x] = '.';
116 /* --- GAME EVENT! --- */
118 void game_event(void)
120 while (SDL_PollEvent(&event))
124 case SDL_QUIT: /* Quit event - quit: */
127 case SDL_KEYDOWN: /* A keypress! */
128 key = event.key.keysym.sym;
130 /* Check for menu-events, if the menu is shown */
132 menu_event(&event.key.keysym);
134 if(player_keydown_event(&tux,key))
139 case SDLK_ESCAPE: /* Escape: Open/Close the menu: */
145 st_pause_ticks_stop();
150 st_pause_ticks_start();
158 case SDL_KEYUP: /* A keyrelease! */
159 key = event.key.keysym.sym;
161 if(player_keyup_event(&tux,key))
172 st_pause_ticks_stop();
177 st_pause_ticks_start();
182 if(debug_mode == YES)
183 tux.size = !tux.size;
186 if(debug_mode == YES)
190 if(debug_mode == YES)
194 if(debug_mode == YES)
198 if(debug_mode == YES)
199 timer_start(&tux.invincible_timer,TUX_INVINCIBLE_TIME);
202 if(debug_mode == YES)
206 if(debug_mode == YES)
215 case SDL_JOYAXISMOTION:
216 switch(event.jaxis.axis)
219 if (event.jaxis.value < -1024)
220 tux.input.left = DOWN;
221 else if (event.jaxis.value > 1024)
224 if (event.jaxis.value > 1024)
225 tux.input.right = DOWN;
226 else if (event.jaxis.value < -1024)
227 tux.input.right = UP;
230 if (event.jaxis.value > 1024)
231 tux.input.down = DOWN;
232 else if (event.jaxis.value < -1024)
235 /* Handle joystick for the menu */
238 if(tux.input.down == DOWN)
239 menuaction = MN_DOWN;
248 case SDL_JOYBUTTONDOWN:
249 if (event.jbutton.button == JOY_A)
251 else if (event.jbutton.button == JOY_B)
252 tux.input.fire = DOWN;
254 case SDL_JOYBUTTONUP:
255 if (event.jbutton.button == JOY_A)
257 else if (event.jbutton.button == JOY_B)
273 /* --- GAME ACTION! --- */
275 int game_action(void)
279 /* (tux_dying || next_level) */
280 if (tux.dying || next_level)
282 /* Tux either died, or reached the end of a level! */
291 /* End of a level! */
295 player_level_begin(&tux);
302 /* No more lives!? */
308 if (score > hs_score)
315 } /* if (lives < 0) */
318 /* Either way, (re-)load the (next) level... */
320 player_level_begin(&tux);
322 loadlevel(¤t_level,"default",level);
327 loadlevelgfx(¤t_level);
336 /* Handle bouncy distros: */
338 for (i = 0; i < num_bouncy_distros; i++)
340 bouncy_distro_action(&bouncy_distros[i]);
344 /* Handle broken bricks: */
346 for (i = 0; i < num_broken_bricks; i++)
348 broken_brick_action(&broken_bricks[i]);
352 /* Handle distro counting: */
354 if (counting_distros == YES)
358 if (distro_counter <= 0)
359 counting_distros = -1;
363 /* Handle bouncy bricks: */
365 for (i = 0; i < num_bouncy_bricks; i++)
367 bouncy_brick_action(&bouncy_bricks[i]);
371 /* Handle floating scores: */
373 for (i = 0; i < num_floating_scores; i++)
375 floating_score_action(&floating_scores[i]);
379 /* Handle bullets: */
381 for (i = 0; i < num_bullets; ++i)
383 bullet_action(&bullets[i]);
386 /* Handle upgrades: */
388 for (i = 0; i < num_upgrades; i++)
390 upgrade_action(&upgrades[i]);
394 /* Handle bad guys: */
396 for (i = 0; i < num_bad_guys; i++)
398 badguy_action(&bad_guys[i]);
401 /* Handle all possible collisions. */
407 /* --- GAME DRAW! --- */
415 if (tux.dying && (frame % 4) == 0)
416 clearscreen(255, 255, 255);
417 else if(timer_check(&super_bkgd_timer))
418 texture_draw(&img_super_bkgd, 0, 0, NO_UPDATE);
421 /* Draw the real background */
422 if(current_level.bkgd_image[0] != '\0')
425 texture_draw_part(&img_bkgd,s,0,0,0,img_bkgd.w - s, img_bkgd.h, NO_UPDATE);
426 texture_draw_part(&img_bkgd,0,0,screen->w - s ,0,s,img_bkgd.h, NO_UPDATE);
430 clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue);
434 /* Draw background: */
436 for (y = 0; y < 15; ++y)
438 for (x = 0; x < 21; ++x)
440 drawshape(x * 32 - ((int)scroll_x % 32), y * 32,
441 current_level.tiles[(int)y][(int)x + (int)(scroll_x / 32)]);
446 /* (Bouncy bricks): */
448 for (i = 0; i < num_bouncy_bricks; ++i)
450 bouncy_brick_draw(&bouncy_bricks[i]);
456 for (i = 0; i < num_bad_guys; ++i)
458 badguy_draw(&bad_guys[i]);
467 for (i = 0; i < num_bullets; ++i)
469 bullet_draw(&bullets[i]);
472 /* (Floating scores): */
474 for (i = 0; i < num_floating_scores; ++i)
476 floating_score_draw(&floating_scores[i]);
482 for (i = 0; i < num_upgrades; ++i)
484 upgrade_draw(&upgrades[i]);
488 /* (Bouncy distros): */
490 for (i = 0; i < num_bouncy_distros; ++i)
492 bouncy_distro_draw(&bouncy_distros[i]);
496 /* (Broken bricks): */
498 for (i = 0; i < num_broken_bricks; ++i)
500 broken_brick_draw(&broken_bricks[i]);
507 text_drawf(&red_text, "PAUSE", 0, 230, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
512 /* (Update it all!) */
519 /* --- GAME LOOP! --- */
524 /*Uint32 last_time, now_time*/
526 timer_type fps_timer, frame_timer;
530 clearscreen(0, 0, 0);
538 menumenu = MENU_GAME;
543 loadlevel(¤t_level,"default",level);
544 loadlevelgfx(¤t_level);
554 /* --- MAIN GAME LOOP!!! --- */
561 timer_init(&fps_timer);
562 timer_init(&frame_timer);
570 /* Set the time the last update and the time of the current update */
571 last_update_time = update_time;
572 update_time = st_get_ticks();
574 /* Calculate the movement-factor */
575 frame_ratio = ((double)(update_time-last_update_time))/((double)FRAME_RATE);
577 if(!timer_check(&frame_timer))
579 timer_start(&frame_timer,25);
586 tux.input.old_fire = tux.input.fire;
588 printf("%lf\n",frame_ratio);
593 /* Handle actions: */
595 if(!game_pause && !show_menu)
597 if (game_action() == 0)
599 /* == 0: no more lives */
600 /* == -1: continues */
607 if(tux.input.down == DOWN)
610 /*Draw the current scene to the screen */
611 /*If the machine running the game is too slow
612 skip the drawing of the frame (so the calculations are more precise and
613 the FPS aren't affected).*/
614 /*if( ! fps_fps < 50.0 )
617 jump = YES;*/ /*FIXME: Implement this tweak right.*/
620 /* Time stops in pause mode */
621 if(game_pause || show_menu )
626 /* Pause till next frame, if the machine running the game is too fast: */
627 /* FIXME: Works great for in OpenGl mode, where the CPU doesn't have to do that much. But
628 the results in SDL mode aren't perfect (thought the 100 FPS are reached), even on an AMD2500+. */
629 if(last_update_time >= update_time - 12 && jump != YES )
636 if (timer_check(&time_left))
638 /* are we low on time ? */
639 if ((timer_get_left(&time_left) < TIME_WARNING)
640 && (current_music != HURRYUP_MUSIC))
642 current_music = HURRYUP_MUSIC;
643 /* stop the others music, prepare to play the fast music */
652 player_kill(&tux,KILL);
655 /* Keep playing the correct music: */
657 if (!playing_music())
659 play_current_music();
662 /* Calculate frames per second */
666 fps_fps = (1000.0 / (float)timer_get_gone(&fps_timer)) * (float)fps_cnt;
668 if(!timer_check(&fps_timer))
670 timer_start(&fps_timer,1000);
676 while (!done && !quit);
690 /* Initialize the game stuff: */
699 /* Free music data for this level: */
701 void unloadlevelsong(void)
703 free_music(level_song);
704 free_music(level_song_fast);
709 void loadlevelsong(void)
713 char * song_subtitle;
715 song_path = (char *) malloc(sizeof(char) * (strlen(DATA_PREFIX) +
716 strlen(current_level.song_title) + 8));
717 sprintf(song_path, "%s/music/%s", DATA_PREFIX, current_level.song_title);
718 level_song = load_song(song_path);
722 song_path = (char *) malloc(sizeof(char) * (strlen(DATA_PREFIX) +
723 strlen(current_level.song_title) + 8 + 5));
724 song_subtitle = strdup(current_level.song_title);
725 strcpy(strstr(song_subtitle, "."), "\0");
726 sprintf(song_path, "%s/music/%s-fast%s", DATA_PREFIX, song_subtitle, strstr(current_level.song_title, "."));
727 level_song_fast = load_song(song_path);
732 /* Load graphics/sounds shared between all levels: */
734 void loadshared(void)
737 char * herring_song_path; /* for loading herring song*/
741 texture_load(&tux_right[0],DATA_PREFIX "/images/shared/tux-right-0.png", USE_ALPHA);
742 texture_load(&tux_right[1],DATA_PREFIX "/images/shared/tux-right-1.png", USE_ALPHA);
743 texture_load(&tux_right[2],DATA_PREFIX "/images/shared/tux-right-2.png", USE_ALPHA);
745 texture_load(&tux_left[0],DATA_PREFIX "/images/shared/tux-left-0.png", USE_ALPHA);
746 texture_load(&tux_left[1],DATA_PREFIX "/images/shared/tux-left-1.png", USE_ALPHA);
747 texture_load(&tux_left[2],DATA_PREFIX "/images/shared/tux-left-2.png", USE_ALPHA);
749 texture_load(&firetux_right[0],DATA_PREFIX "/images/shared/firetux-right-0.png", USE_ALPHA);
750 texture_load(&firetux_right[1],DATA_PREFIX "/images/shared/firetux-right-1.png", USE_ALPHA);
751 texture_load(&firetux_right[2],DATA_PREFIX "/images/shared/firetux-right-2.png", USE_ALPHA);
753 texture_load(&firetux_left[0],DATA_PREFIX "/images/shared/firetux-left-0.png", USE_ALPHA);
754 texture_load(&firetux_left[1],DATA_PREFIX "/images/shared/firetux-left-1.png", USE_ALPHA);
755 texture_load(&firetux_left[2],DATA_PREFIX "/images/shared/firetux-left-2.png", USE_ALPHA);
758 texture_load(&cape_right[0] ,DATA_PREFIX "/images/shared/cape-right-0.png",
761 texture_load(&cape_right[1] ,DATA_PREFIX "/images/shared/cape-right-1.png",
764 texture_load(&cape_left[0] ,DATA_PREFIX "/images/shared/cape-left-0.png",
767 texture_load(&cape_left[1] ,DATA_PREFIX "/images/shared/cape-left-1.png",
770 texture_load(&bigtux_right[0] ,DATA_PREFIX "/images/shared/bigtux-right-0.png",
773 texture_load(&bigtux_right[1] ,DATA_PREFIX "/images/shared/bigtux-right-1.png",
776 texture_load(&bigtux_right[2] ,DATA_PREFIX "/images/shared/bigtux-right-2.png",
779 texture_load(&bigtux_right_jump ,DATA_PREFIX "/images/shared/bigtux-right-jump.png", USE_ALPHA);
781 texture_load(&bigtux_left[0] ,DATA_PREFIX "/images/shared/bigtux-left-0.png",
784 texture_load(&bigtux_left[1] ,DATA_PREFIX "/images/shared/bigtux-left-1.png",
787 texture_load(&bigtux_left[2] ,DATA_PREFIX "/images/shared/bigtux-left-2.png",
790 texture_load(&bigtux_left_jump ,DATA_PREFIX "/images/shared/bigtux-left-jump.png", USE_ALPHA);
792 texture_load(&bigcape_right[0] ,DATA_PREFIX "/images/shared/bigcape-right-0.png",
795 texture_load(&bigcape_right[1] ,DATA_PREFIX "/images/shared/bigcape-right-1.png",
798 texture_load(&bigcape_left[0] ,DATA_PREFIX "/images/shared/bigcape-left-0.png",
801 texture_load(&bigcape_left[1] ,DATA_PREFIX "/images/shared/bigcape-left-1.png",
804 texture_load(&bigfiretux_right[0] ,DATA_PREFIX "/images/shared/bigfiretux-right-0.png",
807 texture_load(&bigfiretux_right[1] ,DATA_PREFIX "/images/shared/bigfiretux-right-1.png",
810 texture_load(&bigfiretux_right[2] ,DATA_PREFIX "/images/shared/bigfiretux-right-2.png",
813 texture_load(&bigfiretux_right_jump ,DATA_PREFIX "/images/shared/bigfiretux-right-jump.png", USE_ALPHA);
815 texture_load(&bigfiretux_left[0] ,DATA_PREFIX "/images/shared/bigfiretux-left-0.png",
818 texture_load(&bigfiretux_left[1] ,DATA_PREFIX "/images/shared/bigfiretux-left-1.png",
821 texture_load(&bigfiretux_left[2] ,DATA_PREFIX "/images/shared/bigfiretux-left-2.png",
824 texture_load(&bigfiretux_left_jump ,DATA_PREFIX "/images/shared/bigfiretux-left-jump.png", USE_ALPHA);
826 texture_load(&bigcape_right[0] ,DATA_PREFIX "/images/shared/bigcape-right-0.png",
829 texture_load(&bigcape_right[1] ,DATA_PREFIX "/images/shared/bigcape-right-1.png",
832 texture_load(&bigcape_left[0] ,DATA_PREFIX "/images/shared/bigcape-left-0.png",
835 texture_load(&bigcape_left[1] ,DATA_PREFIX "/images/shared/bigcape-left-1.png",
839 texture_load(&ducktux_right ,DATA_PREFIX
840 "/images/shared/ducktux-right.png",
843 texture_load(&ducktux_left ,DATA_PREFIX
844 "/images/shared/ducktux-left.png",
847 texture_load(&skidtux_right ,DATA_PREFIX
848 "/images/shared/skidtux-right.png",
851 texture_load(&skidtux_left ,DATA_PREFIX
852 "/images/shared/skidtux-left.png",
855 texture_load(&duckfiretux_right ,DATA_PREFIX
856 "/images/shared/duckfiretux-right.png",
859 texture_load(&duckfiretux_left ,DATA_PREFIX
860 "/images/shared/duckfiretux-left.png",
863 texture_load(&skidfiretux_right ,DATA_PREFIX
864 "/images/shared/skidfiretux-right.png",
867 texture_load(&skidfiretux_left ,DATA_PREFIX
868 "/images/shared/skidfiretux-left.png",
874 texture_load(&img_box_full ,DATA_PREFIX "/images/shared/box-full.png",
876 texture_load(&img_box_empty ,DATA_PREFIX "/images/shared/box-empty.png",
883 texture_load(&img_water ,DATA_PREFIX "/images/shared/water.png", IGNORE_ALPHA);
885 texture_load(&img_waves[0] ,DATA_PREFIX "/images/shared/waves-0.png",
888 texture_load(&img_waves[1] ,DATA_PREFIX "/images/shared/waves-1.png",
891 texture_load(&img_waves[2] ,DATA_PREFIX "/images/shared/waves-2.png",
897 texture_load(&img_pole ,DATA_PREFIX "/images/shared/pole.png", USE_ALPHA);
898 texture_load(&img_poletop ,DATA_PREFIX "/images/shared/poletop.png",
904 texture_load(&img_flag[0] ,DATA_PREFIX "/images/shared/flag-0.png",
906 texture_load(&img_flag[1] ,DATA_PREFIX "/images/shared/flag-1.png",
912 texture_load(&img_cloud[0][0] ,DATA_PREFIX "/images/shared/cloud-00.png",
915 texture_load(&img_cloud[0][1] ,DATA_PREFIX "/images/shared/cloud-01.png",
918 texture_load(&img_cloud[0][2] ,DATA_PREFIX "/images/shared/cloud-02.png",
921 texture_load(&img_cloud[0][3] ,DATA_PREFIX "/images/shared/cloud-03.png",
925 texture_load(&img_cloud[1][0] ,DATA_PREFIX "/images/shared/cloud-10.png",
928 texture_load(&img_cloud[1][1] ,DATA_PREFIX "/images/shared/cloud-11.png",
931 texture_load(&img_cloud[1][2] ,DATA_PREFIX "/images/shared/cloud-12.png",
934 texture_load(&img_cloud[1][3] ,DATA_PREFIX "/images/shared/cloud-13.png",
942 texture_load(&img_bsod_left[0] ,DATA_PREFIX
943 "/images/shared/bsod-left-0.png",
946 texture_load(&img_bsod_left[1] ,DATA_PREFIX
947 "/images/shared/bsod-left-1.png",
950 texture_load(&img_bsod_left[2] ,DATA_PREFIX
951 "/images/shared/bsod-left-2.png",
954 texture_load(&img_bsod_left[3] ,DATA_PREFIX
955 "/images/shared/bsod-left-3.png",
958 texture_load(&img_bsod_right[0] ,DATA_PREFIX
959 "/images/shared/bsod-right-0.png",
962 texture_load(&img_bsod_right[1] ,DATA_PREFIX
963 "/images/shared/bsod-right-1.png",
966 texture_load(&img_bsod_right[2] ,DATA_PREFIX
967 "/images/shared/bsod-right-2.png",
970 texture_load(&img_bsod_right[3] ,DATA_PREFIX
971 "/images/shared/bsod-right-3.png",
974 texture_load(&img_bsod_squished_left ,DATA_PREFIX
975 "/images/shared/bsod-squished-left.png",
978 texture_load(&img_bsod_squished_right ,DATA_PREFIX
979 "/images/shared/bsod-squished-right.png",
982 texture_load(&img_bsod_falling_left ,DATA_PREFIX
983 "/images/shared/bsod-falling-left.png",
986 texture_load(&img_bsod_falling_right ,DATA_PREFIX
987 "/images/shared/bsod-falling-right.png",
993 texture_load(&img_laptop_left[0] ,DATA_PREFIX
994 "/images/shared/laptop-left-0.png",
997 texture_load(&img_laptop_left[1] ,DATA_PREFIX
998 "/images/shared/laptop-left-1.png",
1001 texture_load(&img_laptop_left[2] ,DATA_PREFIX
1002 "/images/shared/laptop-left-2.png",
1005 texture_load(&img_laptop_right[0] ,DATA_PREFIX
1006 "/images/shared/laptop-right-0.png",
1009 texture_load(&img_laptop_right[1] ,DATA_PREFIX
1010 "/images/shared/laptop-right-1.png",
1013 texture_load(&img_laptop_right[2] ,DATA_PREFIX
1014 "/images/shared/laptop-right-2.png",
1017 texture_load(&img_laptop_flat_left ,DATA_PREFIX
1018 "/images/shared/laptop-flat-left.png",
1021 texture_load(&img_laptop_flat_right ,DATA_PREFIX
1022 "/images/shared/laptop-flat-right.png",
1025 texture_load(&img_laptop_falling_left ,DATA_PREFIX
1026 "/images/shared/laptop-falling-left.png",
1029 texture_load(&img_laptop_falling_right ,DATA_PREFIX
1030 "/images/shared/laptop-falling-right.png",
1036 texture_load(&img_money_left[0] ,DATA_PREFIX
1037 "/images/shared/bag-left-0.png",
1040 texture_load(&img_money_left[1] ,DATA_PREFIX
1041 "/images/shared/bag-left-1.png",
1044 texture_load(&img_money_right[0] ,DATA_PREFIX
1045 "/images/shared/bag-right-0.png",
1048 texture_load(&img_money_right[1] ,DATA_PREFIX
1049 "/images/shared/bag-right-1.png",
1056 texture_load(&img_mints ,DATA_PREFIX "/images/shared/mints.png", USE_ALPHA);
1057 texture_load(&img_coffee ,DATA_PREFIX "/images/shared/coffee.png", USE_ALPHA);
1062 texture_load(&img_bullet ,DATA_PREFIX "/images/shared/bullet.png", USE_ALPHA);
1064 texture_load(&img_red_glow ,DATA_PREFIX "/images/shared/red-glow.png",
1071 texture_load(&img_distro[0] ,DATA_PREFIX "/images/shared/distro-0.png",
1074 texture_load(&img_distro[1] ,DATA_PREFIX "/images/shared/distro-1.png",
1077 texture_load(&img_distro[2] ,DATA_PREFIX "/images/shared/distro-2.png",
1080 texture_load(&img_distro[3] ,DATA_PREFIX "/images/shared/distro-3.png",
1086 texture_load(&tux_life ,DATA_PREFIX "/images/shared/tux-life.png",
1091 texture_load(&img_golden_herring, DATA_PREFIX "/images/shared/golden-herring.png",
1095 /* Super background: */
1097 texture_load(&img_super_bkgd ,DATA_PREFIX "/images/shared/super-bkgd.png",
1101 /* Sound effects: */
1103 /* if (use_sound) // this will introduce SERIOUS bugs here ! because "load_sound"
1104 // initialize sounds[i] with the correct pointer's value:
1105 // NULL or something else. And it will be dangerous to
1106 // play with not-initialized pointers.
1107 // This is also true with if (use_music)
1108 Send a mail to me: neoneurone@users.sf.net, if you have another opinion. :)
1110 for (i = 0; i < NUM_SOUNDS; i++)
1111 sounds[i] = load_sound(soundfilenames[i]);
1114 herring_song_path = (char *) malloc(sizeof(char) * (strlen(DATA_PREFIX) +
1115 strlen("SALCON.MOD") + 8)); /* FIXME: We need a real herring_song! Thats a fake.:) */
1117 sprintf(herring_song_path, "%s/music/%s", DATA_PREFIX, "SALCON.MOD");
1119 herring_song = load_song(herring_song_path);
1121 free(herring_song_path);
1126 /* Free shared data: */
1128 void unloadshared(void)
1132 for (i = 0; i < 3; i++)
1134 texture_free(&tux_right[i]);
1135 texture_free(&tux_left[i]);
1136 texture_free(&bigtux_right[i]);
1137 texture_free(&bigtux_left[i]);
1140 texture_free(&bigtux_right_jump);
1141 texture_free(&bigtux_left_jump);
1143 for (i = 0; i < 2; i++)
1145 texture_free(&cape_right[i]);
1146 texture_free(&cape_left[i]);
1147 texture_free(&bigcape_right[i]);
1148 texture_free(&bigcape_left[i]);
1151 texture_free(&ducktux_left);
1152 texture_free(&ducktux_right);
1154 texture_free(&skidtux_left);
1155 texture_free(&skidtux_right);
1157 for (i = 0; i < 4; i++)
1159 texture_free(&img_bsod_left[i]);
1160 texture_free(&img_bsod_right[i]);
1163 texture_free(&img_bsod_squished_left);
1164 texture_free(&img_bsod_squished_right);
1166 texture_free(&img_bsod_falling_left);
1167 texture_free(&img_bsod_falling_right);
1169 for (i = 0; i < 3; i++)
1171 texture_free(&img_laptop_left[i]);
1172 texture_free(&img_laptop_right[i]);
1175 texture_free(&img_laptop_flat_left);
1176 texture_free(&img_laptop_flat_right);
1178 texture_free(&img_laptop_falling_left);
1179 texture_free(&img_laptop_falling_right);
1181 for (i = 0; i < 2; i++)
1183 texture_free(&img_money_left[i]);
1184 texture_free(&img_money_right[i]);
1187 texture_free(&img_box_full);
1188 texture_free(&img_box_empty);
1190 texture_free(&img_water);
1191 for (i = 0; i < 3; i++)
1192 texture_free(&img_waves[i]);
1194 texture_free(&img_pole);
1195 texture_free(&img_poletop);
1197 for (i = 0; i < 2; i++)
1198 texture_free(&img_flag[i]);
1200 texture_free(&img_mints);
1201 texture_free(&img_coffee);
1203 for (i = 0; i < 4; i++)
1205 texture_free(&img_distro[i]);
1206 texture_free(&img_cloud[0][i]);
1207 texture_free(&img_cloud[1][i]);
1210 texture_free(&img_golden_herring);
1212 for (i = 0; i < NUM_SOUNDS; i++)
1213 free_chunk(sounds[i]);
1215 /* free the herring song */
1216 free_music( herring_song );
1220 /* Draw a tile on the screen: */
1222 void drawshape(float x, float y, unsigned char c)
1226 if (c == 'X' || c == 'x')
1227 texture_draw(&img_brick[0], x, y, NO_UPDATE);
1228 else if (c == 'Y' || c == 'y')
1229 texture_draw(&img_brick[1], x, y, NO_UPDATE);
1230 else if (c == 'A' || c =='B' || c == '!')
1231 texture_draw(&img_box_full, x, y, NO_UPDATE);
1233 texture_draw(&img_box_empty, x, y, NO_UPDATE);
1234 else if (c >= 'C' && c <= 'F')
1235 texture_draw(&img_cloud[0][c - 'C'], x, y, NO_UPDATE);
1236 else if (c >= 'c' && c <= 'f')
1237 texture_draw(&img_cloud[1][c - 'c'], x, y, NO_UPDATE);
1238 else if (c >= 'G' && c <= 'J')
1239 texture_draw(&img_bkgd_tile[0][c - 'G'], x, y, NO_UPDATE);
1240 else if (c >= 'g' && c <= 'j')
1241 texture_draw(&img_bkgd_tile[1][c - 'g'], x, y, NO_UPDATE);
1243 texture_draw(&img_solid[0], x, y, NO_UPDATE);
1245 texture_draw(&img_solid[1], x, y, NO_UPDATE);
1247 texture_draw(&img_solid[2], x, y, NO_UPDATE);
1249 texture_draw(&img_solid[3], x, y, NO_UPDATE);
1253 z = (frame / 2) % 6;
1256 texture_draw(&img_distro[z], x, y, NO_UPDATE);
1258 texture_draw(&img_distro[2], x, y, NO_UPDATE);
1260 texture_draw(&img_distro[1], x, y, NO_UPDATE);
1264 z = (frame / 3) % 3;
1266 texture_draw(&img_waves[z], x, y, NO_UPDATE);
1269 texture_draw(&img_poletop, x, y, NO_UPDATE);
1272 texture_draw(&img_pole, x, y, NO_UPDATE);
1274 /* Mark this as the end position of the level! */
1280 z = (frame / 3) % 2;
1282 texture_draw(&img_flag[z], x + 16, y, NO_UPDATE);
1285 texture_draw(&img_water, x, y, NO_UPDATE);
1289 /* What shape is at some position? */
1291 unsigned char shape(float x, float y)
1300 if (yy >= 0 && yy < 15 && xx >= 0 && xx <= current_level.width)
1302 c = current_level.tiles[yy][xx];
1312 int issolid(float x, float y)
1314 if (isbrick(x, y) ||
1315 isbrick(x + 31, y) ||
1318 (shape(x, y) == '[' ||
1319 shape(x + 31, y) == '[') ||
1320 (shape(x, y) == '=' ||
1321 shape(x + 31, y) == '=') ||
1322 (shape(x, y) == ']' ||
1323 shape(x + 31, y) == ']') ||
1324 (shape(x, y) == 'A' ||
1325 shape(x + 31, y) == 'A') ||
1326 (shape(x, y) == 'B' ||
1327 shape(x + 31, y) == 'B') ||
1328 (shape(x, y) == '!' ||
1329 shape(x + 31, y) == '!') ||
1330 (shape(x, y) == 'a' ||
1331 shape(x + 31, y) == 'a'))
1340 /* Is it a brick? */
1342 int isbrick(float x, float y)
1344 if (shape(x, y) == 'X' ||
1345 shape(x, y) == 'x' ||
1346 shape(x, y) == 'Y' ||
1358 int isice(float x, float y)
1360 if (shape(x, y) == '#')
1369 /* Is it a full box? */
1371 int isfullbox(float x, float y)
1373 if (shape(x, y) == 'A' ||
1374 shape(x, y) == 'B' ||
1383 /* Break a brick: */
1385 void trybreakbrick(float x, float y)
1389 if (shape(x, y) == 'x' || shape(x, y) == 'y')
1391 /* Get a distro from it: */
1393 add_bouncy_distro(((x + 1) / 32) * 32,
1394 (int)(y / 32) * 32);
1396 if (counting_distros == NO)
1398 counting_distros = YES;
1399 distro_counter = 50;
1402 if (distro_counter <= 0)
1403 level_change(¤t_level,x, y, 'a');
1405 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1406 score = score + SCORE_DISTRO;
1411 /* Get rid of it: */
1413 level_change(¤t_level,x, y,'.');
1417 /* Replace it with broken bits: */
1419 add_broken_brick(((x + 1) / 32) * 32,
1420 (int)(y / 32) * 32);
1423 /* Get some score: */
1425 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
1426 score = score + SCORE_BRICK;
1431 /* Bounce a brick: */
1433 void bumpbrick(float x, float y)
1435 add_bouncy_brick(((int)(x + 1) / 32) * 32,
1436 (int)(y / 32) * 32);
1438 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
1444 void tryemptybox(float x, float y)
1446 if (isfullbox(x, y))
1448 if (shape(x, y) == 'A')
1450 /* Box with a distro! */
1452 add_bouncy_distro(((x + 1) / 32) * 32,
1453 (int)(y / 32) * 32 - 32);
1455 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1456 score = score + SCORE_DISTRO;
1459 else if (shape(x, y) == 'B')
1461 /* Add an upgrade! */
1463 if (tux.size == SMALL)
1465 /* Tux is small, add mints! */
1467 add_upgrade(((x + 1) / 32) * 32,
1468 (int)(y / 32) * 32 - 32,
1473 /* Tux is big, add coffee: */
1475 add_upgrade(((x + 1) / 32) * 32,
1476 (int)(y / 32) * 32 - 32,
1480 play_sound(sounds[SND_UPGRADE], SOUND_CENTER_SPEAKER);
1482 else if (shape(x, y) == '!')
1484 /* Add a golden herring */
1486 add_upgrade(((x + 1) / 32) * 32,
1487 (int)(y / 32) * 32 - 32,
1491 /* Empty the box: */
1493 level_change(¤t_level,x, y, 'a');
1498 /* Try to grab a distro: */
1500 void trygrabdistro(float x, float y, int bounciness)
1502 if (shape(x, y) == '$')
1504 level_change(¤t_level,x, y, '.');
1505 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1507 if (bounciness == BOUNCE)
1509 add_bouncy_distro(((x + 1) / 32) * 32,
1510 (int)(y / 32) * 32);
1513 score = score + SCORE_DISTRO;
1518 /* Try to bump a bad guy from below: */
1520 void trybumpbadguy(float x, float y)
1527 for (i = 0; i < num_bad_guys; i++)
1529 if (bad_guys[i].base.alive &&
1530 bad_guys[i].base.x >= x - 32 && bad_guys[i].base.x <= x + 32 &&
1531 bad_guys[i].base.y >= y - 16 && bad_guys[i].base.y <= y + 16)
1533 if (bad_guys[i].kind == BAD_BSOD ||
1534 bad_guys[i].kind == BAD_LAPTOP)
1536 bad_guys[i].dying = FALLING;
1537 bad_guys[i].base.ym = -8;
1538 play_sound(sounds[SND_FALL], SOUND_CENTER_SPEAKER);
1546 for (i = 0; i < num_upgrades; i++)
1548 if (upgrades[i].base.alive && upgrades[i].base.height == 32 &&
1549 upgrades[i].base.x >= x - 32 && upgrades[i].base.x <= x + 32 &&
1550 upgrades[i].base.y >= y - 16 && upgrades[i].base.y <= y + 16)
1552 upgrades[i].base.xm = -upgrades[i].base.xm;
1553 upgrades[i].base.ym = -8;
1554 play_sound(sounds[SND_BUMP_UPGRADE], SOUND_CENTER_SPEAKER);
1560 void drawstatus(void)
1564 sprintf(str, "%d", score);
1565 text_draw(&blue_text, "SCORE", 0, 0, 1, NO_UPDATE);
1566 text_draw(&gold_text, str, 96, 0, 1, NO_UPDATE);
1568 sprintf(str, "%d", hs_score);
1569 text_draw(&blue_text, "HIGH", 0, 20, 1, NO_UPDATE);
1570 text_draw(&gold_text, str, 96, 20, 1, NO_UPDATE);
1572 if (timer_get_left(&time_left) > TIME_WARNING || (frame % 10) < 5)
1574 sprintf(str, "%d", timer_get_left(&time_left) / 1000 );
1575 text_draw(&blue_text, "TIME", 224, 0, 1, NO_UPDATE);
1576 text_draw(&gold_text, str, 304, 0, 1, NO_UPDATE);
1579 sprintf(str, "%d", distros);
1580 text_draw(&blue_text, "DISTROS", screen->h, 0, 1, NO_UPDATE);
1581 text_draw(&gold_text, str, 608, 0, 1, NO_UPDATE);
1583 text_draw(&blue_text, "LIVES", screen->h, 20, 1, NO_UPDATE);
1587 sprintf(str, "%f", fps_fps);
1588 text_draw(&blue_text, "FPS", screen->h, 40, 1, NO_UPDATE);
1589 text_draw(&blue_text, str, screen->h + 60, 40, 1, NO_UPDATE);
1592 for(i=0; i < tux.lives; ++i)
1594 texture_draw(&tux_life,565+(18*i),20,NO_UPDATE);
1599 void drawendscreen(void)
1603 clearscreen(0, 0, 0);
1605 text_drawf(&blue_text, "GAMEOVER", 0, 200, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
1607 sprintf(str, "SCORE: %d", score);
1608 text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
1610 sprintf(str, "DISTROS: %d", distros);
1611 text_drawf(&gold_text, str, 0, 256, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
1617 void drawresultscreen(void)
1621 clearscreen(0, 0, 0);
1623 text_drawf(&red_text, "Result:", 0, 200, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
1625 sprintf(str, "SCORE: %d", score);
1626 text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
1628 sprintf(str, "DISTROS: %d", distros);
1629 text_drawf(&gold_text, str, 0, 256, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
1638 time_t current_time = time(NULL);
1639 struct tm* time_struct;
1642 time_struct = localtime(¤t_time);
1643 sprintf(savefile,"%s/%d-%d-%d-%d.save",st_save_dir,time_struct->tm_year+1900,time_struct->tm_mon,time_struct->tm_mday,time_struct->tm_hour);
1644 printf("%s",savefile);
1647 fi = fopen(savefile, "wb");
1651 fprintf(stderr, "Warning: I could not open the high score file ");
1656 fwrite(&level,4,1,fi);
1657 fwrite(&score,4,1,fi);
1658 fwrite(&distros,4,1,fi);
1659 fwrite(&tux.base.x,4,1,fi);
1660 fwrite(&tux.base.y,4,1,fi);
1661 fwrite(&scroll_x,4,1,fi);
1662 fwrite(¤t_level.time_left,4,1,fi);
1668 void loadgame(char* filename)
1672 time_t current_time = time(NULL);
1673 struct tm* time_struct;
1675 time_struct = localtime(¤t_time);
1676 sprintf(savefile,"%s/%d-%d-%d-%d.save",st_save_dir,time_struct->tm_year+1900,time_struct->tm_mon,time_struct->tm_mday,time_struct->tm_hour);
1677 printf("%s",savefile);
1680 fi = fopen(savefile, "rb");
1684 fprintf(stderr, "Warning: I could not open the high score file ");
1689 player_level_begin(&tux);
1691 loadlevel(¤t_level,"default",level);
1694 activate_bad_guys();
1696 loadlevelgfx(¤t_level);
1702 fread(&level,4,1,fi);
1703 fread(&score,4,1,fi);
1704 fread(&distros,4,1,fi);
1705 fread(&tux.base.x,4,1,fi);
1706 fread(&tux.base.y,4,1,fi);
1707 fread(&scroll_x,4,1,fi);
1708 fread(¤t_level.time_left,4,1,fi);