6 by Bill Kendrick & Tobias Glaesser
7 bill@newbreedsoftware.com
8 http://www.newbreedsoftware.com/supertux/
10 April 11, 2000 - March 15, 2004
23 #include <sys/types.h>
32 #include "high_scores.h"
40 #include "collision.h"
42 /* extern variables */
44 st_level current_level;
45 int game_started = NO;
47 /* Local variables: */
49 static texture_type img_waves[3], img_water, img_pole, img_poletop, img_flag[2];
50 static texture_type img_cloud[2][4];
51 static SDL_Event event;
53 static char level_subset[100];
56 static int st_gl_mode;
57 static unsigned int last_update_time;
58 static unsigned int update_time;
59 static int pause_menu_frame;
62 /* Local function prototypes: */
64 void levelintro(void);
65 void loadshared(void);
66 void unloadshared(void);
67 void drawstatus(void);
68 void drawendscreen(void);
69 void drawresultscreen(void);
71 #define JOYSTICK_DEAD_ZONE 4096
79 sprintf(str, "LEVEL %d", level);
80 text_drawf(&blue_text, str, 0, 200, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
82 sprintf(str, "%s", current_level.name.c_str());
83 text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
85 sprintf(str, "TUX x %d", tux.lives);
86 text_drawf(&white_text, str, 0, 256, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
94 void start_timers(void)
96 timer_start(&time_left,current_level.time_left*1000);
97 st_pause_ticks_init();
98 update_time = st_get_ticks();
101 void activate_bad_guys(void)
105 /* Activate bad guys: */
107 for (y = 0; y < 15; y++)
109 for (x = 0; x < current_level.width; x++)
111 if (current_level.tiles[y][x] >= '0' && current_level.tiles[y][x] <= '9')
113 add_bad_guy(x * 32, y * 32, current_level.tiles[y][x] - '0');
114 current_level.tiles[y][x] = '.';
121 /* --- GAME EVENT! --- */
123 void game_event(void)
125 while (SDL_PollEvent(&event))
129 case SDL_QUIT: /* Quit event - quit: */
132 case SDL_KEYDOWN: /* A keypress! */
133 key = event.key.keysym.sym;
135 /* Check for menu-events, if the menu is shown */
137 menu_event(&event.key.keysym);
139 if(player_key_event(&tux,key,DOWN))
144 case SDLK_ESCAPE: /* Escape: Open/Close the menu: */
147 if(st_gl_mode == ST_GL_TEST)
151 menu_set_current(&game_menu);
153 st_pause_ticks_stop();
157 menu_set_current(&game_menu);
159 st_pause_ticks_start();
167 case SDL_KEYUP: /* A keyrelease! */
168 key = event.key.keysym.sym;
170 if(player_key_event(&tux,key,UP))
181 st_pause_ticks_stop();
186 st_pause_ticks_start();
191 if(debug_mode == YES)
193 tux.size = !tux.size;
196 tux.base.height = 64;
199 tux.base.height = 32;
203 if(debug_mode == YES)
207 if(debug_mode == YES)
211 if(debug_mode == YES)
215 if(debug_mode == YES)
216 timer_start(&tux.invincible_timer,TUX_INVINCIBLE_TIME);
219 if(debug_mode == YES)
223 if(debug_mode == YES)
237 case SDL_JOYAXISMOTION:
238 switch(event.jaxis.axis)
241 if (event.jaxis.value < -JOYSTICK_DEAD_ZONE)
242 tux.input.left = DOWN;
243 else if (event.jaxis.value > JOYSTICK_DEAD_ZONE)
246 if (event.jaxis.value > JOYSTICK_DEAD_ZONE)
247 tux.input.right = DOWN;
248 else if (event.jaxis.value < -JOYSTICK_DEAD_ZONE)
249 tux.input.right = UP;
252 if (event.jaxis.value > JOYSTICK_DEAD_ZONE)
253 tux.input.down = DOWN;
254 else if (event.jaxis.value < -JOYSTICK_DEAD_ZONE)
257 /* Handle joystick for the menu */
260 if(tux.input.down == DOWN)
261 menuaction = MN_DOWN;
270 case SDL_JOYBUTTONDOWN:
271 if (event.jbutton.button == JOY_A)
273 else if (event.jbutton.button == JOY_B)
274 tux.input.fire = DOWN;
276 case SDL_JOYBUTTONUP:
277 if (event.jbutton.button == JOY_A)
279 else if (event.jbutton.button == JOY_B)
296 /* --- GAME ACTION! --- */
298 int game_action(void)
302 /* (tux_dying || next_level) */
303 if (tux.dying || next_level)
305 /* Tux either died, or reached the end of a level! */
312 /* End of a level! */
315 if(st_gl_mode != ST_GL_TEST)
322 level_free(¤t_level);
328 player_level_begin(&tux);
334 /* No more lives!? */
338 if(st_gl_mode != ST_GL_TEST)
341 if(st_gl_mode != ST_GL_TEST)
343 if (score > hs_score)
347 level_free(¤t_level);
352 } /* if (lives < 0) */
355 /* Either way, (re-)load the (next) level... */
357 player_level_begin(&tux);
359 level_free(¤t_level);
361 if (st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
363 if(level_load(¤t_level, level_subset) != 0)
368 if(level_load(¤t_level,level_subset,level) != 0)
376 level_load_gfx(¤t_level);
378 level_load_song(¤t_level);
379 if(st_gl_mode != ST_GL_TEST)
383 play_current_music();
388 /* Handle bouncy distros: */
390 for (i = 0; i < num_bouncy_distros; i++)
392 bouncy_distro_action(&bouncy_distros[i]);
396 /* Handle broken bricks: */
398 for (i = 0; i < num_broken_bricks; i++)
400 broken_brick_action(&broken_bricks[i]);
404 /* Handle distro counting: */
406 if (counting_distros == YES)
410 if (distro_counter <= 0)
411 counting_distros = -1;
415 /* Handle bouncy bricks: */
417 for (i = 0; i < num_bouncy_bricks; i++)
419 bouncy_brick_action(&bouncy_bricks[i]);
423 /* Handle floating scores: */
425 for (i = 0; i < num_floating_scores; i++)
427 floating_score_action(&floating_scores[i]);
431 /* Handle bullets: */
433 for (i = 0; i < num_bullets; ++i)
435 bullet_action(&bullets[i]);
438 /* Handle upgrades: */
440 for (i = 0; i < num_upgrades; i++)
442 upgrade_action(&upgrades[i]);
446 /* Handle bad guys: */
448 for (i = 0; i < num_bad_guys; i++)
450 badguy_action(&bad_guys[i]);
453 /* Handle all possible collisions. */
459 /* --- GAME DRAW! --- */
467 if (tux.dying && (frame % 4) == 0)
468 clearscreen(255, 255, 255);
469 else if(timer_check(&super_bkgd_timer))
470 texture_draw(&img_super_bkgd, 0, 0, NO_UPDATE);
473 /* Draw the real background */
474 if(current_level.bkgd_image[0] != '\0')
476 s = (int)scroll_x / 30;
477 texture_draw_part(&img_bkgd,s,0,0,0,img_bkgd.w - s, img_bkgd.h, NO_UPDATE);
478 texture_draw_part(&img_bkgd,0,0,screen->w - s ,0,s,img_bkgd.h, NO_UPDATE);
482 clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue);
486 /* Draw background: */
488 for (y = 0; y < 15; ++y)
490 for (x = 0; x < 21; ++x)
492 drawshape(x * 32 - ((int)scroll_x % 32), y * 32,
493 current_level.tiles[(int)y][(int)x + (int)(scroll_x / 32)]);
498 /* (Bouncy bricks): */
500 for (i = 0; i < num_bouncy_bricks; ++i)
502 bouncy_brick_draw(&bouncy_bricks[i]);
508 for (i = 0; i < num_bad_guys; ++i)
510 badguy_draw(&bad_guys[i]);
519 for (i = 0; i < num_bullets; ++i)
521 bullet_draw(&bullets[i]);
524 /* (Floating scores): */
526 for (i = 0; i < num_floating_scores; ++i)
528 floating_score_draw(&floating_scores[i]);
534 for (i = 0; i < num_upgrades; ++i)
536 upgrade_draw(&upgrades[i]);
540 /* (Bouncy distros): */
542 for (i = 0; i < num_bouncy_distros; ++i)
544 bouncy_distro_draw(&bouncy_distros[i]);
548 /* (Broken bricks): */
550 for (i = 0; i < num_broken_bricks; ++i)
552 broken_brick_draw(&broken_bricks[i]);
561 for(i = 0; i < x; ++i)
563 fillrect(i % 2 ? (pause_menu_frame * i)%screen->w : -((pause_menu_frame * i)%screen->w) ,(i*20+pause_menu_frame)%screen->h,screen->w,10,20,20,20, rand() % 20 + 1);
565 fillrect(0,0,screen->w,screen->h,rand() % 50, rand() % 50, rand() % 50, 128);
566 text_drawf(&blue_text, "PAUSE - Press 'P' To Play", 0, 230, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
570 menu_process_current();
572 /* (Update it all!) */
579 /* --- GAME LOOP! --- */
581 int gameloop(const char * subset, int levelnb, int mode)
583 int fps_cnt, jump, done;
584 timer_type fps_timer, frame_timer;
585 timer_init(&fps_timer, YES);
586 timer_init(&frame_timer, YES);
597 strcpy(level_subset,subset);
599 if (st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
601 if (level_load(¤t_level, level_subset))
606 if(level_load(¤t_level, level_subset, level) != 0)
610 level_load_gfx(¤t_level);
612 level_load_song(¤t_level);
616 if(st_gl_mode != ST_GL_TEST)
621 if(st_gl_mode == ST_GL_PLAY || st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
624 timer_init(&time_left,YES);
627 if(st_gl_mode == ST_GL_LOAD_GAME)
631 /* --- MAIN GAME LOOP!!! --- */
638 timer_init(&fps_timer,YES);
639 timer_init(&frame_timer,YES);
644 clearscreen(0, 0, 0);
648 play_current_music();
651 while (SDL_PollEvent(&event))
659 /* Calculate the movement-factor */
660 frame_ratio = ((double)(update_time-last_update_time))/((double)FRAME_RATE);
661 if(frame_ratio > 1.5) /* Quick hack to correct the unprecise CPU clocks a little bit. */
662 frame_ratio = 1.5 + (frame_ratio - 1.5) * 0.85;
664 if(!timer_check(&frame_timer))
666 timer_start(&frame_timer,25);
672 tux.input.old_fire = tux.input.fire;
678 if(current_menu == &game_menu)
680 switch (menu_check(&game_menu))
683 st_pause_ticks_stop();
686 update_load_save_game_menu(&save_game_menu, NO);
689 update_load_save_game_menu(&load_game_menu, YES);
692 st_pause_ticks_stop();
697 else if(current_menu == &options_menu)
699 process_options_menu();
701 else if(current_menu == &save_game_menu )
703 process_save_load_game_menu(YES);
705 else if(current_menu == &load_game_menu )
707 process_save_load_game_menu(NO);
712 /* Handle actions: */
714 if(!game_pause && !show_menu)
716 /*float z = frame_ratio;
720 if (game_action() == 0)
722 /* == 0: no more lives */
723 /* == -1: continues */
735 if(debug_mode && debug_fps == YES)
738 /*Draw the current scene to the screen */
739 /*If the machine running the game is too slow
740 skip the drawing of the frame (so the calculations are more precise and
741 the FPS aren't affected).*/
742 /*if( ! fps_fps < 50.0 )
745 jump = YES;*/ /*FIXME: Implement this tweak right.*/
748 /* Time stops in pause mode */
749 if(game_pause || show_menu )
754 /* Set the time of the last update and the time of the current update */
755 last_update_time = update_time;
756 update_time = st_get_ticks();
759 /* Pause till next frame, if the machine running the game is too fast: */
760 /* FIXME: Works great for in OpenGl mode, where the CPU doesn't have to do that much. But
761 the results in SDL mode aren't perfect (thought the 100 FPS are reached), even on an AMD2500+. */
762 if(last_update_time >= update_time - 12 && jump != YES )
764 /*if((update_time - last_update_time) < 10)
765 SDL_Delay((11 - (update_time - last_update_time))/2);*/
771 if (timer_check(&time_left))
773 /* are we low on time ? */
774 if ((timer_get_left(&time_left) < TIME_WARNING)
775 && (get_current_music() != HURRYUP_MUSIC)) /* play the fast music */
777 set_current_music(HURRYUP_MUSIC);
778 play_current_music();
783 player_kill(&tux,KILL);
786 /* Calculate frames per second */
790 fps_fps = (1000.0 / (float)timer_get_gone(&fps_timer)) * (float)fps_cnt;
792 if(!timer_check(&fps_timer))
794 timer_start(&fps_timer,1000);
800 while (!done && !quit);
805 level_free(¤t_level);
816 /* Load graphics/sounds shared between all levels: */
818 void loadshared(void)
823 texture_load(&tux_right[0], datadir + "/images/shared/tux-right-0.png", USE_ALPHA);
824 texture_load(&tux_right[1], datadir + "/images/shared/tux-right-1.png", USE_ALPHA);
825 texture_load(&tux_right[2], datadir + "/images/shared/tux-right-2.png", USE_ALPHA);
827 texture_load(&tux_left[0], datadir + "/images/shared/tux-left-0.png", USE_ALPHA);
828 texture_load(&tux_left[1], datadir + "/images/shared/tux-left-1.png", USE_ALPHA);
829 texture_load(&tux_left[2], datadir + "/images/shared/tux-left-2.png", USE_ALPHA);
831 texture_load(&firetux_right[0], datadir + "/images/shared/firetux-right-0.png", USE_ALPHA);
832 texture_load(&firetux_right[1], datadir + "/images/shared/firetux-right-1.png", USE_ALPHA);
833 texture_load(&firetux_right[2], datadir + "/images/shared/firetux-right-2.png", USE_ALPHA);
835 texture_load(&firetux_left[0], datadir + "/images/shared/firetux-left-0.png", USE_ALPHA);
836 texture_load(&firetux_left[1], datadir + "/images/shared/firetux-left-1.png", USE_ALPHA);
837 texture_load(&firetux_left[2], datadir + "/images/shared/firetux-left-2.png", USE_ALPHA);
840 texture_load(&cape_right[0], datadir + "/images/shared/cape-right-0.png",
843 texture_load(&cape_right[1], datadir + "/images/shared/cape-right-1.png",
846 texture_load(&cape_left[0], datadir + "/images/shared/cape-left-0.png",
849 texture_load(&cape_left[1], datadir + "/images/shared/cape-left-1.png",
852 texture_load(&bigtux_right[0], datadir + "/images/shared/bigtux-right-0.png",
855 texture_load(&bigtux_right[1], datadir + "/images/shared/bigtux-right-1.png",
858 texture_load(&bigtux_right[2], datadir + "/images/shared/bigtux-right-2.png",
861 texture_load(&bigtux_right_jump, datadir + "/images/shared/bigtux-right-jump.png", USE_ALPHA);
863 texture_load(&bigtux_left[0], datadir + "/images/shared/bigtux-left-0.png",
866 texture_load(&bigtux_left[1], datadir + "/images/shared/bigtux-left-1.png",
869 texture_load(&bigtux_left[2], datadir + "/images/shared/bigtux-left-2.png",
872 texture_load(&bigtux_left_jump, datadir + "/images/shared/bigtux-left-jump.png", USE_ALPHA);
874 texture_load(&bigcape_right[0], datadir + "/images/shared/bigcape-right-0.png",
877 texture_load(&bigcape_right[1], datadir + "/images/shared/bigcape-right-1.png",
880 texture_load(&bigcape_left[0], datadir + "/images/shared/bigcape-left-0.png",
883 texture_load(&bigcape_left[1], datadir + "/images/shared/bigcape-left-1.png",
886 texture_load(&bigfiretux_right[0], datadir + "/images/shared/bigfiretux-right-0.png",
889 texture_load(&bigfiretux_right[1], datadir + "/images/shared/bigfiretux-right-1.png",
892 texture_load(&bigfiretux_right[2], datadir + "/images/shared/bigfiretux-right-2.png",
895 texture_load(&bigfiretux_right_jump, datadir + "/images/shared/bigfiretux-right-jump.png", USE_ALPHA);
897 texture_load(&bigfiretux_left[0], datadir + "/images/shared/bigfiretux-left-0.png",
900 texture_load(&bigfiretux_left[1], datadir + "/images/shared/bigfiretux-left-1.png",
903 texture_load(&bigfiretux_left[2], datadir + "/images/shared/bigfiretux-left-2.png",
906 texture_load(&bigfiretux_left_jump, datadir + "/images/shared/bigfiretux-left-jump.png", USE_ALPHA);
908 texture_load(&bigcape_right[0], datadir + "/images/shared/bigcape-right-0.png",
911 texture_load(&bigcape_right[1], datadir + "/images/shared/bigcape-right-1.png",
914 texture_load(&bigcape_left[0], datadir + "/images/shared/bigcape-left-0.png",
917 texture_load(&bigcape_left[1], datadir + "/images/shared/bigcape-left-1.png",
921 texture_load(&ducktux_right, datadir +
922 "/images/shared/ducktux-right.png",
925 texture_load(&ducktux_left, datadir +
926 "/images/shared/ducktux-left.png",
929 texture_load(&skidtux_right, datadir +
930 "/images/shared/skidtux-right.png",
933 texture_load(&skidtux_left, datadir +
934 "/images/shared/skidtux-left.png",
937 texture_load(&duckfiretux_right, datadir +
938 "/images/shared/duckfiretux-right.png",
941 texture_load(&duckfiretux_left, datadir +
942 "/images/shared/duckfiretux-left.png",
945 texture_load(&skidfiretux_right, datadir +
946 "/images/shared/skidfiretux-right.png",
949 texture_load(&skidfiretux_left, datadir +
950 "/images/shared/skidfiretux-left.png",
956 texture_load(&img_box_full, datadir + "/images/shared/box-full.png",
958 texture_load(&img_box_empty, datadir + "/images/shared/box-empty.png",
965 texture_load(&img_water, datadir + "/images/shared/water.png", IGNORE_ALPHA);
967 texture_load(&img_waves[0], datadir + "/images/shared/waves-0.png",
970 texture_load(&img_waves[1], datadir + "/images/shared/waves-1.png",
973 texture_load(&img_waves[2], datadir + "/images/shared/waves-2.png",
979 texture_load(&img_pole, datadir + "/images/shared/pole.png", USE_ALPHA);
980 texture_load(&img_poletop, datadir + "/images/shared/poletop.png",
986 texture_load(&img_flag[0], datadir + "/images/shared/flag-0.png",
988 texture_load(&img_flag[1], datadir + "/images/shared/flag-1.png",
994 texture_load(&img_cloud[0][0], datadir + "/images/shared/cloud-00.png",
997 texture_load(&img_cloud[0][1], datadir + "/images/shared/cloud-01.png",
1000 texture_load(&img_cloud[0][2], datadir + "/images/shared/cloud-02.png",
1003 texture_load(&img_cloud[0][3], datadir + "/images/shared/cloud-03.png",
1007 texture_load(&img_cloud[1][0], datadir + "/images/shared/cloud-10.png",
1010 texture_load(&img_cloud[1][1], datadir + "/images/shared/cloud-11.png",
1013 texture_load(&img_cloud[1][2], datadir + "/images/shared/cloud-12.png",
1016 texture_load(&img_cloud[1][3], datadir + "/images/shared/cloud-13.png",
1024 texture_load(&img_bsod_left[0], datadir +
1025 "/images/shared/bsod-left-0.png",
1028 texture_load(&img_bsod_left[1], datadir +
1029 "/images/shared/bsod-left-1.png",
1032 texture_load(&img_bsod_left[2], datadir +
1033 "/images/shared/bsod-left-2.png",
1036 texture_load(&img_bsod_left[3], datadir +
1037 "/images/shared/bsod-left-3.png",
1040 texture_load(&img_bsod_right[0], datadir +
1041 "/images/shared/bsod-right-0.png",
1044 texture_load(&img_bsod_right[1], datadir +
1045 "/images/shared/bsod-right-1.png",
1048 texture_load(&img_bsod_right[2], datadir +
1049 "/images/shared/bsod-right-2.png",
1052 texture_load(&img_bsod_right[3], datadir +
1053 "/images/shared/bsod-right-3.png",
1056 texture_load(&img_bsod_squished_left, datadir +
1057 "/images/shared/bsod-squished-left.png",
1060 texture_load(&img_bsod_squished_right, datadir +
1061 "/images/shared/bsod-squished-right.png",
1064 texture_load(&img_bsod_falling_left, datadir +
1065 "/images/shared/bsod-falling-left.png",
1068 texture_load(&img_bsod_falling_right, datadir +
1069 "/images/shared/bsod-falling-right.png",
1075 texture_load(&img_laptop_left[0], datadir +
1076 "/images/shared/laptop-left-0.png",
1079 texture_load(&img_laptop_left[1], datadir +
1080 "/images/shared/laptop-left-1.png",
1083 texture_load(&img_laptop_left[2], datadir +
1084 "/images/shared/laptop-left-2.png",
1087 texture_load(&img_laptop_right[0], datadir +
1088 "/images/shared/laptop-right-0.png",
1091 texture_load(&img_laptop_right[1], datadir +
1092 "/images/shared/laptop-right-1.png",
1095 texture_load(&img_laptop_right[2], datadir +
1096 "/images/shared/laptop-right-2.png",
1099 texture_load(&img_laptop_flat_left, datadir +
1100 "/images/shared/laptop-flat-left.png",
1103 texture_load(&img_laptop_flat_right, datadir +
1104 "/images/shared/laptop-flat-right.png",
1107 texture_load(&img_laptop_falling_left, datadir +
1108 "/images/shared/laptop-falling-left.png",
1111 texture_load(&img_laptop_falling_right, datadir +
1112 "/images/shared/laptop-falling-right.png",
1118 texture_load(&img_money_left[0], datadir +
1119 "/images/shared/bag-left-0.png",
1122 texture_load(&img_money_left[1], datadir +
1123 "/images/shared/bag-left-1.png",
1126 texture_load(&img_money_right[0], datadir +
1127 "/images/shared/bag-right-0.png",
1130 texture_load(&img_money_right[1], datadir +
1131 "/images/shared/bag-right-1.png",
1138 texture_load(&img_mints, datadir + "/images/shared/mints.png", USE_ALPHA);
1139 texture_load(&img_coffee, datadir + "/images/shared/coffee.png", USE_ALPHA);
1144 texture_load(&img_bullet, datadir + "/images/shared/bullet.png", USE_ALPHA);
1146 texture_load(&img_red_glow, datadir + "/images/shared/red-glow.png",
1153 texture_load(&img_distro[0], datadir + "/images/shared/distro-0.png",
1156 texture_load(&img_distro[1], datadir + "/images/shared/distro-1.png",
1159 texture_load(&img_distro[2], datadir + "/images/shared/distro-2.png",
1162 texture_load(&img_distro[3], datadir + "/images/shared/distro-3.png",
1168 texture_load(&tux_life, datadir + "/images/shared/tux-life.png",
1173 texture_load(&img_golden_herring, datadir + "/images/shared/golden-herring.png",
1177 /* Super background: */
1179 texture_load(&img_super_bkgd, datadir + "/images/shared/super-bkgd.png",
1183 /* Sound effects: */
1185 /* if (use_sound) // this will introduce SERIOUS bugs here ! because "load_sound"
1186 // initialize sounds[i] with the correct pointer's value:
1187 // NULL or something else. And it will be dangerous to
1188 // play with not-initialized pointers.
1189 // This is also true with if (use_music)
1190 Send a mail to me: neoneurone@users.sf.net, if you have another opinion. :)
1192 for (i = 0; i < NUM_SOUNDS; i++)
1193 sounds[i] = load_sound(soundfilenames[i]);
1196 herring_song = load_song(datadir + "/music/SALCON.MOD");
1200 /* Free shared data: */
1202 void unloadshared(void)
1206 for (i = 0; i < 3; i++)
1208 texture_free(&tux_right[i]);
1209 texture_free(&tux_left[i]);
1210 texture_free(&bigtux_right[i]);
1211 texture_free(&bigtux_left[i]);
1214 texture_free(&bigtux_right_jump);
1215 texture_free(&bigtux_left_jump);
1217 for (i = 0; i < 2; i++)
1219 texture_free(&cape_right[i]);
1220 texture_free(&cape_left[i]);
1221 texture_free(&bigcape_right[i]);
1222 texture_free(&bigcape_left[i]);
1225 texture_free(&ducktux_left);
1226 texture_free(&ducktux_right);
1228 texture_free(&skidtux_left);
1229 texture_free(&skidtux_right);
1231 for (i = 0; i < 4; i++)
1233 texture_free(&img_bsod_left[i]);
1234 texture_free(&img_bsod_right[i]);
1237 texture_free(&img_bsod_squished_left);
1238 texture_free(&img_bsod_squished_right);
1240 texture_free(&img_bsod_falling_left);
1241 texture_free(&img_bsod_falling_right);
1243 for (i = 0; i < 3; i++)
1245 texture_free(&img_laptop_left[i]);
1246 texture_free(&img_laptop_right[i]);
1249 texture_free(&img_laptop_flat_left);
1250 texture_free(&img_laptop_flat_right);
1252 texture_free(&img_laptop_falling_left);
1253 texture_free(&img_laptop_falling_right);
1255 for (i = 0; i < 2; i++)
1257 texture_free(&img_money_left[i]);
1258 texture_free(&img_money_right[i]);
1261 texture_free(&img_box_full);
1262 texture_free(&img_box_empty);
1264 texture_free(&img_water);
1265 for (i = 0; i < 3; i++)
1266 texture_free(&img_waves[i]);
1268 texture_free(&img_pole);
1269 texture_free(&img_poletop);
1271 for (i = 0; i < 2; i++)
1272 texture_free(&img_flag[i]);
1274 texture_free(&img_mints);
1275 texture_free(&img_coffee);
1277 for (i = 0; i < 4; i++)
1279 texture_free(&img_distro[i]);
1280 texture_free(&img_cloud[0][i]);
1281 texture_free(&img_cloud[1][i]);
1284 texture_free(&img_golden_herring);
1286 for (i = 0; i < NUM_SOUNDS; i++)
1287 free_chunk(sounds[i]);
1289 /* free the herring song */
1290 free_music( herring_song );
1294 /* Draw a tile on the screen: */
1296 void drawshape(float x, float y, unsigned char c)
1300 if (c == 'X' || c == 'x')
1301 texture_draw(&img_brick[0], x, y, NO_UPDATE);
1302 else if (c == 'Y' || c == 'y')
1303 texture_draw(&img_brick[1], x, y, NO_UPDATE);
1304 else if (c == 'A' || c =='B' || c == '!')
1305 texture_draw(&img_box_full, x, y, NO_UPDATE);
1307 texture_draw(&img_box_empty, x, y, NO_UPDATE);
1308 else if (c >= 'C' && c <= 'F')
1309 texture_draw(&img_cloud[0][c - 'C'], x, y, NO_UPDATE);
1310 else if (c >= 'c' && c <= 'f')
1311 texture_draw(&img_cloud[1][c - 'c'], x, y, NO_UPDATE);
1312 else if (c >= 'G' && c <= 'J')
1313 texture_draw(&img_bkgd_tile[0][c - 'G'], x, y, NO_UPDATE);
1314 else if (c >= 'g' && c <= 'j')
1315 texture_draw(&img_bkgd_tile[1][c - 'g'], x, y, NO_UPDATE);
1317 texture_draw(&img_solid[0], x, y, NO_UPDATE);
1319 texture_draw(&img_solid[1], x, y, NO_UPDATE);
1321 texture_draw(&img_solid[2], x, y, NO_UPDATE);
1323 texture_draw(&img_solid[3], x, y, NO_UPDATE);
1327 z = (frame / 2) % 6;
1330 texture_draw(&img_distro[z], x, y, NO_UPDATE);
1332 texture_draw(&img_distro[2], x, y, NO_UPDATE);
1334 texture_draw(&img_distro[1], x, y, NO_UPDATE);
1338 z = (frame / 3) % 3;
1340 texture_draw(&img_waves[z], x, y, NO_UPDATE);
1343 texture_draw(&img_poletop, x, y, NO_UPDATE);
1346 texture_draw(&img_pole, x, y, NO_UPDATE);
1351 z = (frame / 3) % 2;
1353 texture_draw(&img_flag[z], x + 16, y, NO_UPDATE);
1356 texture_draw(&img_water, x, y, NO_UPDATE);
1360 /* What shape is at some position? */
1362 unsigned char shape(float x, float y)
1371 if (yy >= 0 && yy < 15 && xx >= 0 && xx <= current_level.width)
1373 c = current_level.tiles[yy][xx];
1384 int issolid(float x, float y)
1386 if (isbrick(x, y) ||
1388 (shape(x, y) == '[') ||
1389 (shape(x, y) == '=') ||
1390 (shape(x, y) == ']') ||
1391 (shape(x, y) == 'A') ||
1392 (shape(x, y) == 'B') ||
1393 (shape(x, y) == '!') ||
1394 (shape(x, y) == 'a'))
1403 /* Is it a brick? */
1405 int isbrick(float x, float y)
1407 if (shape(x, y) == 'X' ||
1408 shape(x, y) == 'x' ||
1409 shape(x, y) == 'Y' ||
1421 int isice(float x, float y)
1423 if (shape(x, y) == '#')
1432 /* Is it a full box? */
1434 int isfullbox(float x, float y)
1436 if (shape(x, y) == 'A' ||
1437 shape(x, y) == 'B' ||
1446 /* Break a brick: */
1448 void trybreakbrick(float x, float y)
1452 if (shape(x, y) == 'x' || shape(x, y) == 'y')
1454 /* Get a distro from it: */
1456 add_bouncy_distro(((int)(x + 1) / 32) * 32,
1457 (int)(y / 32) * 32);
1459 if (counting_distros == NO)
1461 counting_distros = YES;
1462 distro_counter = 50;
1465 if (distro_counter <= 0)
1466 level_change(¤t_level,x, y, 'a');
1468 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1469 score = score + SCORE_DISTRO;
1474 /* Get rid of it: */
1476 level_change(¤t_level,x, y,'.');
1480 /* Replace it with broken bits: */
1482 add_broken_brick(((int)(x + 1) / 32) * 32,
1483 (int)(y / 32) * 32);
1486 /* Get some score: */
1488 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
1489 score = score + SCORE_BRICK;
1494 /* Bounce a brick: */
1496 void bumpbrick(float x, float y)
1498 add_bouncy_brick(((int)(x + 1) / 32) * 32,
1499 (int)(y / 32) * 32);
1501 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
1508 void tryemptybox(float x, float y, int col_side)
1510 if (!isfullbox(x, y))
1513 // according to the collision side, set the upgrade direction
1515 if(col_side == LEFT)
1522 case 'A': /* Box with a distro! */
1523 add_bouncy_distro(((int)(x + 1) / 32) * 32, (int)(y / 32) * 32 - 32);
1524 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1525 score = score + SCORE_DISTRO;
1528 case 'B': /* Add an upgrade! */
1529 if (tux.size == SMALL) /* Tux is small, add mints! */
1530 add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_MINTS);
1531 else /* Tux is big, add coffee: */
1532 add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_COFFEE);
1533 play_sound(sounds[SND_UPGRADE], SOUND_CENTER_SPEAKER);
1535 case '!': /* Add a golden herring */
1536 add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_HERRING);
1542 /* Empty the box: */
1543 level_change(¤t_level,x, y, 'a');
1547 /* Try to grab a distro: */
1549 void trygrabdistro(float x, float y, int bounciness)
1551 if (shape(x, y) == '$')
1553 level_change(¤t_level,x, y, '.');
1554 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1556 if (bounciness == BOUNCE)
1558 add_bouncy_distro(((int)(x + 1) / 32) * 32,
1559 (int)(y / 32) * 32);
1562 score = score + SCORE_DISTRO;
1567 /* Try to bump a bad guy from below: */
1569 void trybumpbadguy(float x, float y)
1576 for (i = 0; i < num_bad_guys; i++)
1578 if (bad_guys[i].base.alive &&
1579 bad_guys[i].base.x >= x - 32 && bad_guys[i].base.x <= x + 32 &&
1580 bad_guys[i].base.y >= y - 16 && bad_guys[i].base.y <= y + 16)
1582 if (bad_guys[i].kind == BAD_BSOD ||
1583 bad_guys[i].kind == BAD_LAPTOP)
1585 bad_guys[i].dying = FALLING;
1586 bad_guys[i].base.ym = -8;
1587 play_sound(sounds[SND_FALL], SOUND_CENTER_SPEAKER);
1595 for (i = 0; i < num_upgrades; i++)
1597 if (upgrades[i].base.alive && upgrades[i].base.height == 32 &&
1598 upgrades[i].base.x >= x - 32 && upgrades[i].base.x <= x + 32 &&
1599 upgrades[i].base.y >= y - 16 && upgrades[i].base.y <= y + 16)
1601 upgrades[i].base.xm = -upgrades[i].base.xm;
1602 upgrades[i].base.ym = -8;
1603 play_sound(sounds[SND_BUMP_UPGRADE], SOUND_CENTER_SPEAKER);
1609 void drawstatus(void)
1613 sprintf(str, "%d", score);
1614 text_draw(&white_text, "SCORE", 0, 0, 1, NO_UPDATE);
1615 text_draw(&gold_text, str, 96, 0, 1, NO_UPDATE);
1617 if(st_gl_mode != ST_GL_TEST)
1619 sprintf(str, "%d", hs_score);
1620 text_draw(&white_text, "HIGH", 0, 20, 1, NO_UPDATE);
1621 text_draw(&gold_text, str, 96, 20, 1, NO_UPDATE);
1625 text_draw(&white_text,"Press ESC To Return",0,20,1, NO_UPDATE);
1628 if (timer_get_left(&time_left) > TIME_WARNING || (frame % 10) < 5)
1630 sprintf(str, "%d", timer_get_left(&time_left) / 1000 );
1631 text_draw(&white_text, "TIME", 224, 0, 1, NO_UPDATE);
1632 text_draw(&gold_text, str, 304, 0, 1, NO_UPDATE);
1635 sprintf(str, "%d", distros);
1636 text_draw(&white_text, "DISTROS", screen->h, 0, 1, NO_UPDATE);
1637 text_draw(&gold_text, str, 608, 0, 1, NO_UPDATE);
1639 text_draw(&white_text, "LIVES", screen->h, 20, 1, NO_UPDATE);
1643 sprintf(str, "%2.1f", fps_fps);
1644 text_draw(&white_text, "FPS", screen->h, 40, 1, NO_UPDATE);
1645 text_draw(&gold_text, str, screen->h + 60, 40, 1, NO_UPDATE);
1648 for(i=0; i < tux.lives; ++i)
1650 texture_draw(&tux_life,565+(18*i),20,NO_UPDATE);
1655 void drawendscreen(void)
1659 clearscreen(0, 0, 0);
1661 text_drawf(&blue_text, "GAMEOVER", 0, 200, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
1663 sprintf(str, "SCORE: %d", score);
1664 text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
1666 sprintf(str, "DISTROS: %d", distros);
1667 text_drawf(&gold_text, str, 0, 256, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
1673 void drawresultscreen(void)
1677 clearscreen(0, 0, 0);
1679 text_drawf(&blue_text, "Result:", 0, 200, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
1681 sprintf(str, "SCORE: %d", score);
1682 text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
1684 sprintf(str, "DISTROS: %d", distros);
1685 text_drawf(&gold_text, str, 0, 256, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
1691 void savegame(int slot)
1693 char savefile[1024];
1697 sprintf(savefile,"%s/slot%d.save",st_save_dir,slot);
1699 fi = fopen(savefile, "wb");
1703 fprintf(stderr, "Warning: I could not open the slot file ");
1708 fputs(level_subset, fi);
1710 fwrite(&level,sizeof(int),1,fi);
1711 fwrite(&score,sizeof(int),1,fi);
1712 fwrite(&distros,sizeof(int),1,fi);
1713 fwrite(&scroll_x,sizeof(float),1,fi);
1714 fwrite(&tux,sizeof(player_type),1,fi);
1715 timer_fwrite(&tux.invincible_timer,fi);
1716 timer_fwrite(&tux.skidding_timer,fi);
1717 timer_fwrite(&tux.safe_timer,fi);
1718 timer_fwrite(&tux.frame_timer,fi);
1719 timer_fwrite(&time_left,fi);
1720 ui = st_get_ticks();
1721 fwrite(&ui,sizeof(int),1,fi);
1727 void loadgame(int slot)
1729 char savefile[1024];
1734 sprintf(savefile,"%s/slot%d.save",st_save_dir,slot);
1736 fi = fopen(savefile, "rb");
1740 fprintf(stderr, "Warning: I could not open the slot file ");
1747 fgets(str, 100, fi);
1748 strcpy(level_subset, str);
1749 level_subset[strlen(level_subset)-1] = '\0';
1750 fread(&level,sizeof(int),1,fi);
1753 level_free(¤t_level);
1754 if(level_load(¤t_level,level_subset,level) != 0)
1758 activate_bad_guys();
1760 level_load_gfx(¤t_level);
1762 level_load_song(¤t_level);
1764 update_time = st_get_ticks();
1766 fread(&score,sizeof(int),1,fi);
1767 fread(&distros,sizeof(int),1,fi);
1768 fread(&scroll_x,sizeof(float),1,fi);
1769 fread(&tux,sizeof(player_type),1,fi);
1770 timer_fread(&tux.invincible_timer,fi);
1771 timer_fread(&tux.skidding_timer,fi);
1772 timer_fread(&tux.safe_timer,fi);
1773 timer_fread(&tux.frame_timer,fi);
1774 timer_fread(&time_left,fi);
1775 fread(&ui,sizeof(int),1,fi);
1776 tux.hphysic.start_time += st_get_ticks() - ui;
1777 tux.vphysic.start_time += st_get_ticks() - ui;
1783 void slotinfo(char **pinfo, int slot)
1786 char slotfile[1024];
1790 sprintf(slotfile,"%s/slot%d.save",st_save_dir,slot);
1792 fi = fopen(slotfile, "rb");
1794 sprintf(tmp,"Slot %d - ",slot);
1802 fgets(str, 100, fi);
1803 str[strlen(str)-1] = '\0';
1805 strcat(tmp, " / Level:");
1806 fread(&slot_level,sizeof(int),1,fi);
1807 sprintf(str,"%d",slot_level);
1812 *pinfo = (char*) malloc(sizeof(char) * (strlen(tmp)+1));