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 = false;
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);
77 sprintf(str, "LEVEL %d", level);
78 text_drawf(&blue_text, str, 0, 200, A_HMIDDLE, A_TOP, 1);
80 sprintf(str, "%s", current_level.name.c_str());
81 text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1);
83 sprintf(str, "TUX x %d", tux.lives);
84 text_drawf(&white_text, str, 0, 256, A_HMIDDLE, A_TOP, 1);
92 void start_timers(void)
94 timer_start(&time_left,current_level.time_left*1000);
95 st_pause_ticks_init();
96 update_time = st_get_ticks();
99 void activate_bad_guys(void)
103 /* Activate bad guys: */
105 for (y = 0; y < 15; y++)
107 for (x = 0; x < current_level.width; x++)
109 if (current_level.tiles[y][x] >= '0' && current_level.tiles[y][x] <= '9')
111 add_bad_guy(x * 32, y * 32, current_level.tiles[y][x] - '0');
112 current_level.tiles[y][x] = '.';
119 /* --- GAME EVENT! --- */
121 void game_event(void)
123 while (SDL_PollEvent(&event))
127 case SDL_QUIT: /* Quit event - quit: */
130 case SDL_KEYDOWN: /* A keypress! */
131 key = event.key.keysym.sym;
133 /* Check for menu-events, if the menu is shown */
135 menu_event(&event.key.keysym);
137 if(player_key_event(&tux,key,DOWN))
142 case SDLK_ESCAPE: /* Escape: Open/Close the menu: */
145 if(st_gl_mode == ST_GL_TEST)
149 Menu::set_current(game_menu);
151 st_pause_ticks_stop();
155 Menu::set_current(game_menu);
157 st_pause_ticks_start();
165 case SDL_KEYUP: /* A keyrelease! */
166 key = event.key.keysym.sym;
168 if(player_key_event(&tux,key,UP))
179 st_pause_ticks_stop();
184 st_pause_ticks_start();
191 tux.size = !tux.size;
194 tux.base.height = 64;
197 tux.base.height = 32;
214 timer_start(&tux.invincible_timer,TUX_INVINCIBLE_TIME);
234 case SDL_JOYAXISMOTION:
235 switch(event.jaxis.axis)
238 if (event.jaxis.value < -JOYSTICK_DEAD_ZONE)
240 tux.input.left = DOWN;
241 tux.input.right = UP;
243 else if (event.jaxis.value > JOYSTICK_DEAD_ZONE)
246 tux.input.right = DOWN;
250 tux.input.left = DOWN;
251 tux.input.right = DOWN;
255 if (event.jaxis.value > JOYSTICK_DEAD_ZONE)
256 tux.input.down = DOWN;
257 else if (event.jaxis.value < -JOYSTICK_DEAD_ZONE)
262 /* Handle joystick for the menu */
265 if(tux.input.down == DOWN)
266 menuaction = MENU_ACTION_DOWN;
268 menuaction = MENU_ACTION_UP;
275 case SDL_JOYBUTTONDOWN:
276 if (event.jbutton.button == JOY_A)
278 else if (event.jbutton.button == JOY_B)
279 tux.input.fire = DOWN;
281 case SDL_JOYBUTTONUP:
282 if (event.jbutton.button == JOY_A)
284 else if (event.jbutton.button == JOY_B)
288 menuaction = MENU_ACTION_HIT;
299 /* --- GAME ACTION! --- */
301 int game_action(void)
305 /* (tux_dying || next_level) */
306 if (tux.dying || next_level)
308 /* Tux either died, or reached the end of a level! */
315 /* End of a level! */
318 if(st_gl_mode != ST_GL_TEST)
325 level_free(¤t_level);
331 player_level_begin(&tux);
337 /* No more lives!? */
341 if(st_gl_mode != ST_GL_TEST)
344 if(st_gl_mode != ST_GL_TEST)
346 if (score > hs_score)
350 level_free(¤t_level);
355 } /* if (lives < 0) */
358 /* Either way, (re-)load the (next) level... */
360 player_level_begin(&tux);
362 level_free(¤t_level);
364 if (st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
366 if(level_load(¤t_level, level_subset) != 0)
371 if(level_load(¤t_level,level_subset,level) != 0)
379 level_load_gfx(¤t_level);
381 level_load_song(¤t_level);
382 if(st_gl_mode != ST_GL_TEST)
386 play_current_music();
391 /* Handle bouncy distros: */
393 for (i = 0; i < bouncy_distros.size(); i++)
395 bouncy_distro_action(&bouncy_distros[i]);
399 /* Handle broken bricks: */
401 for (i = 0; i < broken_bricks.size(); i++)
403 broken_brick_action(&broken_bricks[i]);
407 /* Handle distro counting: */
409 if (counting_distros)
413 if (distro_counter <= 0)
414 counting_distros = -1;
418 /* Handle bouncy bricks: */
420 for (i = 0; i < bouncy_bricks.size(); i++)
422 bouncy_brick_action(&bouncy_bricks[i]);
426 /* Handle floating scores: */
428 for (i = 0; i < floating_scores.size(); i++)
430 floating_score_action(&floating_scores[i]);
434 /* Handle bullets: */
436 for (i = 0; i < bullets.size(); ++i)
438 bullet_action(&bullets[i]);
441 /* Handle upgrades: */
443 for (i = 0; i < upgrades.size(); i++)
445 upgrade_action(&upgrades[i]);
449 /* Handle bad guys: */
451 for (i = 0; i < bad_guys.size(); i++)
453 badguy_action(&bad_guys[i]);
456 /* Handle all possible collisions. */
462 /* --- GAME DRAW! --- */
471 if (tux.dying && (frame % 4) == 0)
472 clearscreen(255, 255, 255);
473 else if(timer_check(&super_bkgd_timer))
474 texture_draw(&img_super_bkgd, 0, 0);
477 /* Draw the real background */
478 if(current_level.bkgd_image[0] != '\0')
480 s = (int)scroll_x / 30;
481 texture_draw_part(&img_bkgd,s,0,0,0,img_bkgd.w - s, img_bkgd.h);
482 texture_draw_part(&img_bkgd,0,0,screen->w - s ,0,s,img_bkgd.h);
486 clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue);
490 /* Draw background: */
492 for (y = 0; y < 15; ++y)
494 for (x = 0; x < 21; ++x)
496 drawshape(32*x - fmodf(scroll_x, 32), y * 32,
497 current_level.tiles[(int)y][(int)x + (int)(scroll_x / 32)]);
502 /* (Bouncy bricks): */
504 for (i = 0; i < bouncy_bricks.size(); ++i)
506 bouncy_brick_draw(&bouncy_bricks[i]);
512 for (i = 0; i < bad_guys.size(); ++i)
514 badguy_draw(&bad_guys[i]);
523 for (i = 0; i < bullets.size(); ++i)
525 bullet_draw(&bullets[i]);
528 /* (Floating scores): */
530 for (i = 0; i < floating_scores.size(); ++i)
532 floating_score_draw(&floating_scores[i]);
538 for (i = 0; i < upgrades.size(); ++i)
540 upgrade_draw(&upgrades[i]);
544 /* (Bouncy distros): */
546 for (i = 0; i < bouncy_distros.size(); ++i)
548 bouncy_distro_draw(&bouncy_distros[i]);
552 /* (Broken bricks): */
554 for (i = 0; i < broken_bricks.size(); ++i)
556 broken_brick_draw(&broken_bricks[i]);
565 for(i = 0; i < x; ++i)
567 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);
569 fillrect(0,0,screen->w,screen->h,rand() % 50, rand() % 50, rand() % 50, 128);
570 text_drawf(&blue_text, "PAUSE - Press 'P' To Play", 0, 230, A_HMIDDLE, A_TOP, 1);
574 menu_process_current();
576 /* (Update it all!) */
583 /* --- GAME LOOP! --- */
585 int gameloop(const char * subset, int levelnb, int mode)
587 int fps_cnt, jump, done;
588 timer_type fps_timer, frame_timer;
589 timer_init(&fps_timer, true);
590 timer_init(&frame_timer, true);
601 strcpy(level_subset,subset);
603 if (st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
605 if (level_load(¤t_level, level_subset))
610 if(level_load(¤t_level, level_subset, level) != 0)
614 level_load_gfx(¤t_level);
616 level_load_song(¤t_level);
620 if(st_gl_mode != ST_GL_TEST)
625 if(st_gl_mode == ST_GL_PLAY || st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
628 timer_init(&time_left,true);
631 if(st_gl_mode == ST_GL_LOAD_GAME)
635 /* --- MAIN GAME LOOP!!! --- */
642 timer_init(&fps_timer,true);
643 timer_init(&frame_timer,true);
648 clearscreen(0, 0, 0);
652 play_current_music();
655 while (SDL_PollEvent(&event))
663 /* Calculate the movement-factor */
664 frame_ratio = ((double)(update_time-last_update_time))/((double)FRAME_RATE);
665 if(frame_ratio > 1.5) /* Quick hack to correct the unprecise CPU clocks a little bit. */
666 frame_ratio = 1.5 + (frame_ratio - 1.5) * 0.85;
668 if(!timer_check(&frame_timer))
670 timer_start(&frame_timer,25);
676 tux.input.old_fire = tux.input.fire;
682 if(current_menu == game_menu)
684 switch (game_menu->check())
687 st_pause_ticks_stop();
690 update_load_save_game_menu(save_game_menu, false);
693 update_load_save_game_menu(load_game_menu, true);
696 st_pause_ticks_stop();
701 else if(current_menu == options_menu)
703 process_options_menu();
705 else if(current_menu == save_game_menu )
707 process_save_load_game_menu(true);
709 else if(current_menu == load_game_menu )
711 process_save_load_game_menu(false);
716 /* Handle actions: */
718 if(!game_pause && !show_menu)
720 /*float z = frame_ratio;
724 if (game_action() == 0)
726 /* == 0: no more lives */
727 /* == -1: continues */
739 if(debug_mode && debug_fps == true)
742 /*Draw the current scene to the screen */
743 /*If the machine running the game is too slow
744 skip the drawing of the frame (so the calculations are more precise and
745 the FPS aren't affected).*/
746 /*if( ! fps_fps < 50.0 )
749 jump = true;*/ /*FIXME: Implement this tweak right.*/
752 /* Time stops in pause mode */
753 if(game_pause || show_menu )
758 /* Set the time of the last update and the time of the current update */
759 last_update_time = update_time;
760 update_time = st_get_ticks();
763 /* Pause till next frame, if the machine running the game is too fast: */
764 /* FIXME: Works great for in OpenGl mode, where the CPU doesn't have to do that much. But
765 the results in SDL mode aren't perfect (thought the 100 FPS are reached), even on an AMD2500+. */
766 if(last_update_time >= update_time - 12 && !jump)
768 /*if((update_time - last_update_time) < 10)
769 SDL_Delay((11 - (update_time - last_update_time))/2);*/
775 if (timer_check(&time_left))
777 /* are we low on time ? */
778 if ((timer_get_left(&time_left) < TIME_WARNING)
779 && (get_current_music() != HURRYUP_MUSIC)) /* play the fast music */
781 set_current_music(HURRYUP_MUSIC);
782 play_current_music();
787 player_kill(&tux,KILL);
790 /* Calculate frames per second */
794 fps_fps = (1000.0 / (float)timer_get_gone(&fps_timer)) * (float)fps_cnt;
796 if(!timer_check(&fps_timer))
798 timer_start(&fps_timer,1000);
804 while (!done && !quit);
809 level_free(¤t_level);
814 game_started = false;
820 /* Load graphics/sounds shared between all levels: */
822 void loadshared(void)
827 texture_load(&tux_right[0], datadir + "/images/shared/tux-right-0.png", USE_ALPHA);
828 texture_load(&tux_right[1], datadir + "/images/shared/tux-right-1.png", USE_ALPHA);
829 texture_load(&tux_right[2], datadir + "/images/shared/tux-right-2.png", USE_ALPHA);
831 texture_load(&tux_left[0], datadir + "/images/shared/tux-left-0.png", USE_ALPHA);
832 texture_load(&tux_left[1], datadir + "/images/shared/tux-left-1.png", USE_ALPHA);
833 texture_load(&tux_left[2], datadir + "/images/shared/tux-left-2.png", USE_ALPHA);
835 texture_load(&firetux_right[0], datadir + "/images/shared/firetux-right-0.png", USE_ALPHA);
836 texture_load(&firetux_right[1], datadir + "/images/shared/firetux-right-1.png", USE_ALPHA);
837 texture_load(&firetux_right[2], datadir + "/images/shared/firetux-right-2.png", USE_ALPHA);
839 texture_load(&firetux_left[0], datadir + "/images/shared/firetux-left-0.png", USE_ALPHA);
840 texture_load(&firetux_left[1], datadir + "/images/shared/firetux-left-1.png", USE_ALPHA);
841 texture_load(&firetux_left[2], datadir + "/images/shared/firetux-left-2.png", USE_ALPHA);
844 texture_load(&cape_right[0], datadir + "/images/shared/cape-right-0.png",
847 texture_load(&cape_right[1], datadir + "/images/shared/cape-right-1.png",
850 texture_load(&cape_left[0], datadir + "/images/shared/cape-left-0.png",
853 texture_load(&cape_left[1], datadir + "/images/shared/cape-left-1.png",
856 texture_load(&bigtux_right[0], datadir + "/images/shared/bigtux-right-0.png",
859 texture_load(&bigtux_right[1], datadir + "/images/shared/bigtux-right-1.png",
862 texture_load(&bigtux_right[2], datadir + "/images/shared/bigtux-right-2.png",
865 texture_load(&bigtux_right_jump, datadir + "/images/shared/bigtux-right-jump.png", USE_ALPHA);
867 texture_load(&bigtux_left[0], datadir + "/images/shared/bigtux-left-0.png",
870 texture_load(&bigtux_left[1], datadir + "/images/shared/bigtux-left-1.png",
873 texture_load(&bigtux_left[2], datadir + "/images/shared/bigtux-left-2.png",
876 texture_load(&bigtux_left_jump, datadir + "/images/shared/bigtux-left-jump.png", USE_ALPHA);
878 texture_load(&bigcape_right[0], datadir + "/images/shared/bigcape-right-0.png",
881 texture_load(&bigcape_right[1], datadir + "/images/shared/bigcape-right-1.png",
884 texture_load(&bigcape_left[0], datadir + "/images/shared/bigcape-left-0.png",
887 texture_load(&bigcape_left[1], datadir + "/images/shared/bigcape-left-1.png",
890 texture_load(&bigfiretux_right[0], datadir + "/images/shared/bigfiretux-right-0.png",
893 texture_load(&bigfiretux_right[1], datadir + "/images/shared/bigfiretux-right-1.png",
896 texture_load(&bigfiretux_right[2], datadir + "/images/shared/bigfiretux-right-2.png",
899 texture_load(&bigfiretux_right_jump, datadir + "/images/shared/bigfiretux-right-jump.png", USE_ALPHA);
901 texture_load(&bigfiretux_left[0], datadir + "/images/shared/bigfiretux-left-0.png",
904 texture_load(&bigfiretux_left[1], datadir + "/images/shared/bigfiretux-left-1.png",
907 texture_load(&bigfiretux_left[2], datadir + "/images/shared/bigfiretux-left-2.png",
910 texture_load(&bigfiretux_left_jump, datadir + "/images/shared/bigfiretux-left-jump.png", USE_ALPHA);
912 texture_load(&bigcape_right[0], datadir + "/images/shared/bigcape-right-0.png",
915 texture_load(&bigcape_right[1], datadir + "/images/shared/bigcape-right-1.png",
918 texture_load(&bigcape_left[0], datadir + "/images/shared/bigcape-left-0.png",
921 texture_load(&bigcape_left[1], datadir + "/images/shared/bigcape-left-1.png",
925 texture_load(&ducktux_right, datadir +
926 "/images/shared/ducktux-right.png",
929 texture_load(&ducktux_left, datadir +
930 "/images/shared/ducktux-left.png",
933 texture_load(&skidtux_right, datadir +
934 "/images/shared/skidtux-right.png",
937 texture_load(&skidtux_left, datadir +
938 "/images/shared/skidtux-left.png",
941 texture_load(&duckfiretux_right, datadir +
942 "/images/shared/duckfiretux-right.png",
945 texture_load(&duckfiretux_left, datadir +
946 "/images/shared/duckfiretux-left.png",
949 texture_load(&skidfiretux_right, datadir +
950 "/images/shared/skidfiretux-right.png",
953 texture_load(&skidfiretux_left, datadir +
954 "/images/shared/skidfiretux-left.png",
960 texture_load(&img_box_full, datadir + "/images/shared/box-full.png",
962 texture_load(&img_box_empty, datadir + "/images/shared/box-empty.png",
969 texture_load(&img_water, datadir + "/images/shared/water.png", IGNORE_ALPHA);
971 texture_load(&img_waves[0], datadir + "/images/shared/waves-0.png",
974 texture_load(&img_waves[1], datadir + "/images/shared/waves-1.png",
977 texture_load(&img_waves[2], datadir + "/images/shared/waves-2.png",
983 texture_load(&img_pole, datadir + "/images/shared/pole.png", USE_ALPHA);
984 texture_load(&img_poletop, datadir + "/images/shared/poletop.png",
990 texture_load(&img_flag[0], datadir + "/images/shared/flag-0.png",
992 texture_load(&img_flag[1], datadir + "/images/shared/flag-1.png",
998 texture_load(&img_cloud[0][0], datadir + "/images/shared/cloud-00.png",
1001 texture_load(&img_cloud[0][1], datadir + "/images/shared/cloud-01.png",
1004 texture_load(&img_cloud[0][2], datadir + "/images/shared/cloud-02.png",
1007 texture_load(&img_cloud[0][3], datadir + "/images/shared/cloud-03.png",
1011 texture_load(&img_cloud[1][0], datadir + "/images/shared/cloud-10.png",
1014 texture_load(&img_cloud[1][1], datadir + "/images/shared/cloud-11.png",
1017 texture_load(&img_cloud[1][2], datadir + "/images/shared/cloud-12.png",
1020 texture_load(&img_cloud[1][3], datadir + "/images/shared/cloud-13.png",
1028 texture_load(&img_bsod_left[0], datadir +
1029 "/images/shared/bsod-left-0.png",
1032 texture_load(&img_bsod_left[1], datadir +
1033 "/images/shared/bsod-left-1.png",
1036 texture_load(&img_bsod_left[2], datadir +
1037 "/images/shared/bsod-left-2.png",
1040 texture_load(&img_bsod_left[3], datadir +
1041 "/images/shared/bsod-left-3.png",
1044 texture_load(&img_bsod_right[0], datadir +
1045 "/images/shared/bsod-right-0.png",
1048 texture_load(&img_bsod_right[1], datadir +
1049 "/images/shared/bsod-right-1.png",
1052 texture_load(&img_bsod_right[2], datadir +
1053 "/images/shared/bsod-right-2.png",
1056 texture_load(&img_bsod_right[3], datadir +
1057 "/images/shared/bsod-right-3.png",
1060 texture_load(&img_bsod_squished_left, datadir +
1061 "/images/shared/bsod-squished-left.png",
1064 texture_load(&img_bsod_squished_right, datadir +
1065 "/images/shared/bsod-squished-right.png",
1068 texture_load(&img_bsod_falling_left, datadir +
1069 "/images/shared/bsod-falling-left.png",
1072 texture_load(&img_bsod_falling_right, datadir +
1073 "/images/shared/bsod-falling-right.png",
1079 texture_load(&img_laptop_left[0], datadir +
1080 "/images/shared/laptop-left-0.png",
1083 texture_load(&img_laptop_left[1], datadir +
1084 "/images/shared/laptop-left-1.png",
1087 texture_load(&img_laptop_left[2], datadir +
1088 "/images/shared/laptop-left-2.png",
1091 texture_load(&img_laptop_right[0], datadir +
1092 "/images/shared/laptop-right-0.png",
1095 texture_load(&img_laptop_right[1], datadir +
1096 "/images/shared/laptop-right-1.png",
1099 texture_load(&img_laptop_right[2], datadir +
1100 "/images/shared/laptop-right-2.png",
1103 texture_load(&img_laptop_flat_left, datadir +
1104 "/images/shared/laptop-flat-left.png",
1107 texture_load(&img_laptop_flat_right, datadir +
1108 "/images/shared/laptop-flat-right.png",
1111 texture_load(&img_laptop_falling_left, datadir +
1112 "/images/shared/laptop-falling-left.png",
1115 texture_load(&img_laptop_falling_right, datadir +
1116 "/images/shared/laptop-falling-right.png",
1122 texture_load(&img_money_left[0], datadir +
1123 "/images/shared/bag-left-0.png",
1126 texture_load(&img_money_left[1], datadir +
1127 "/images/shared/bag-left-1.png",
1130 texture_load(&img_money_right[0], datadir +
1131 "/images/shared/bag-right-0.png",
1134 texture_load(&img_money_right[1], datadir +
1135 "/images/shared/bag-right-1.png",
1142 texture_load(&img_mints, datadir + "/images/shared/mints.png", USE_ALPHA);
1143 texture_load(&img_coffee, datadir + "/images/shared/coffee.png", USE_ALPHA);
1148 texture_load(&img_bullet, datadir + "/images/shared/bullet.png", USE_ALPHA);
1150 texture_load(&img_red_glow, datadir + "/images/shared/red-glow.png",
1157 texture_load(&img_distro[0], datadir + "/images/shared/distro-0.png",
1160 texture_load(&img_distro[1], datadir + "/images/shared/distro-1.png",
1163 texture_load(&img_distro[2], datadir + "/images/shared/distro-2.png",
1166 texture_load(&img_distro[3], datadir + "/images/shared/distro-3.png",
1172 texture_load(&tux_life, datadir + "/images/shared/tux-life.png",
1177 texture_load(&img_golden_herring, datadir + "/images/shared/golden-herring.png",
1181 /* Super background: */
1183 texture_load(&img_super_bkgd, datadir + "/images/shared/super-bkgd.png",
1187 /* Sound effects: */
1189 /* if (use_sound) // this will introduce SERIOUS bugs here ! because "load_sound"
1190 // initialize sounds[i] with the correct pointer's value:
1191 // NULL or something else. And it will be dangerous to
1192 // play with not-initialized pointers.
1193 // This is also true with if (use_music)
1194 Send a mail to me: neoneurone@users.sf.net, if you have another opinion. :)
1196 for (i = 0; i < NUM_SOUNDS; i++)
1197 sounds[i] = load_sound(datadir + soundfilenames[i]);
1200 herring_song = load_song(datadir + "/music/SALCON.MOD");
1204 /* Free shared data: */
1206 void unloadshared(void)
1210 for (i = 0; i < 3; i++)
1212 texture_free(&tux_right[i]);
1213 texture_free(&tux_left[i]);
1214 texture_free(&bigtux_right[i]);
1215 texture_free(&bigtux_left[i]);
1218 texture_free(&bigtux_right_jump);
1219 texture_free(&bigtux_left_jump);
1221 for (i = 0; i < 2; i++)
1223 texture_free(&cape_right[i]);
1224 texture_free(&cape_left[i]);
1225 texture_free(&bigcape_right[i]);
1226 texture_free(&bigcape_left[i]);
1229 texture_free(&ducktux_left);
1230 texture_free(&ducktux_right);
1232 texture_free(&skidtux_left);
1233 texture_free(&skidtux_right);
1235 for (i = 0; i < 4; i++)
1237 texture_free(&img_bsod_left[i]);
1238 texture_free(&img_bsod_right[i]);
1241 texture_free(&img_bsod_squished_left);
1242 texture_free(&img_bsod_squished_right);
1244 texture_free(&img_bsod_falling_left);
1245 texture_free(&img_bsod_falling_right);
1247 for (i = 0; i < 3; i++)
1249 texture_free(&img_laptop_left[i]);
1250 texture_free(&img_laptop_right[i]);
1253 texture_free(&img_laptop_flat_left);
1254 texture_free(&img_laptop_flat_right);
1256 texture_free(&img_laptop_falling_left);
1257 texture_free(&img_laptop_falling_right);
1259 for (i = 0; i < 2; i++)
1261 texture_free(&img_money_left[i]);
1262 texture_free(&img_money_right[i]);
1265 texture_free(&img_box_full);
1266 texture_free(&img_box_empty);
1268 texture_free(&img_water);
1269 for (i = 0; i < 3; i++)
1270 texture_free(&img_waves[i]);
1272 texture_free(&img_pole);
1273 texture_free(&img_poletop);
1275 for (i = 0; i < 2; i++)
1276 texture_free(&img_flag[i]);
1278 texture_free(&img_mints);
1279 texture_free(&img_coffee);
1281 for (i = 0; i < 4; i++)
1283 texture_free(&img_distro[i]);
1284 texture_free(&img_cloud[0][i]);
1285 texture_free(&img_cloud[1][i]);
1288 texture_free(&img_golden_herring);
1290 for (i = 0; i < NUM_SOUNDS; i++)
1291 free_chunk(sounds[i]);
1293 /* free the herring song */
1294 free_music( herring_song );
1298 /* Draw a tile on the screen: */
1300 void drawshape(float x, float y, unsigned char c)
1304 if (c == 'X' || c == 'x')
1305 texture_draw(&img_brick[0], x, y);
1306 else if (c == 'Y' || c == 'y')
1307 texture_draw(&img_brick[1], x, y);
1308 else if (c == 'A' || c =='B' || c == '!')
1309 texture_draw(&img_box_full, x, y);
1311 texture_draw(&img_box_empty, x, y);
1312 else if (c >= 'C' && c <= 'F')
1313 texture_draw(&img_cloud[0][c - 'C'], x, y);
1314 else if (c >= 'c' && c <= 'f')
1315 texture_draw(&img_cloud[1][c - 'c'], x, y);
1316 else if (c >= 'G' && c <= 'J')
1317 texture_draw(&img_bkgd_tile[0][c - 'G'], x, y);
1318 else if (c >= 'g' && c <= 'j')
1319 texture_draw(&img_bkgd_tile[1][c - 'g'], x, y);
1321 texture_draw(&img_solid[0], x, y);
1323 texture_draw(&img_solid[1], x, y);
1325 texture_draw(&img_solid[2], x, y);
1327 texture_draw(&img_solid[3], x, y);
1330 z = (frame / 2) % 6;
1333 texture_draw(&img_distro[z], x, y);
1335 texture_draw(&img_distro[2], x, y);
1337 texture_draw(&img_distro[1], x, y);
1341 z = (frame / 3) % 3;
1343 texture_draw(&img_waves[z], x, y);
1346 texture_draw(&img_poletop, x, y);
1349 texture_draw(&img_pole, x, y);
1354 z = (frame / 3) % 2;
1356 texture_draw(&img_flag[z], x + 16, y);
1359 texture_draw(&img_water, x, y);
1363 /* What shape is at some position? */
1365 unsigned char shape(float x, float y)
1374 if (yy >= 0 && yy < 15 && xx >= 0 && xx <= current_level.width)
1376 c = current_level.tiles[yy][xx];
1387 bool issolid(float x, float y)
1389 return (isbrick(x, y) ||
1391 (shape(x, y) == '[') ||
1392 (shape(x, y) == '=') ||
1393 (shape(x, y) == ']') ||
1394 (shape(x, y) == 'A') ||
1395 (shape(x, y) == 'B') ||
1396 (shape(x, y) == '!') ||
1397 (shape(x, y) == 'a'));
1400 /* Is it a brick? */
1402 bool isbrick(float x, float y)
1404 return (shape(x, y) == 'X' ||
1405 shape(x, y) == 'x' ||
1406 shape(x, y) == 'Y' ||
1407 shape(x, y) == 'y');
1413 bool isice(float x, float y)
1415 return (shape(x, y) == '#');
1418 /* Is it a full box? */
1420 bool isfullbox(float x, float y)
1422 return (shape(x, y) == 'A' ||
1423 shape(x, y) == 'B' ||
1424 shape(x, y) == '!');
1427 /* Break a brick: */
1429 void trybreakbrick(float x, float y)
1433 if (shape(x, y) == 'x' || shape(x, y) == 'y')
1435 /* Get a distro from it: */
1437 add_bouncy_distro(((int)(x + 1) / 32) * 32,
1438 (int)(y / 32) * 32);
1440 if (!counting_distros)
1442 counting_distros = true;
1443 distro_counter = 50;
1446 if (distro_counter <= 0)
1447 level_change(¤t_level,x, y, 'a');
1449 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1450 score = score + SCORE_DISTRO;
1455 /* Get rid of it: */
1457 level_change(¤t_level,x, y,'.');
1461 /* Replace it with broken bits: */
1463 add_broken_brick(((int)(x + 1) / 32) * 32,
1464 (int)(y / 32) * 32);
1467 /* Get some score: */
1469 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
1470 score = score + SCORE_BRICK;
1475 /* Bounce a brick: */
1477 void bumpbrick(float x, float y)
1479 add_bouncy_brick(((int)(x + 1) / 32) * 32,
1480 (int)(y / 32) * 32);
1482 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
1489 void tryemptybox(float x, float y, int col_side)
1491 if (!isfullbox(x, y))
1494 // according to the collision side, set the upgrade direction
1496 if(col_side == LEFT)
1503 case 'A': /* Box with a distro! */
1504 add_bouncy_distro(((int)(x + 1) / 32) * 32, (int)(y / 32) * 32 - 32);
1505 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1506 score = score + SCORE_DISTRO;
1509 case 'B': /* Add an upgrade! */
1510 if (tux.size == SMALL) /* Tux is small, add mints! */
1511 add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_MINTS);
1512 else /* Tux is big, add coffee: */
1513 add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_COFFEE);
1514 play_sound(sounds[SND_UPGRADE], SOUND_CENTER_SPEAKER);
1516 case '!': /* Add a golden herring */
1517 add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_HERRING);
1523 /* Empty the box: */
1524 level_change(¤t_level,x, y, 'a');
1528 /* Try to grab a distro: */
1530 void trygrabdistro(float x, float y, int bounciness)
1532 if (shape(x, y) == '$')
1534 level_change(¤t_level,x, y, '.');
1535 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1537 if (bounciness == BOUNCE)
1539 add_bouncy_distro(((int)(x + 1) / 32) * 32,
1540 (int)(y / 32) * 32);
1543 score = score + SCORE_DISTRO;
1548 /* Try to bump a bad guy from below: */
1550 void trybumpbadguy(float x, float y)
1555 for (i = 0; i < bad_guys.size(); i++)
1557 if (bad_guys[i].base.x >= x - 32 && bad_guys[i].base.x <= x + 32 &&
1558 bad_guys[i].base.y >= y - 16 && bad_guys[i].base.y <= y + 16)
1560 if (bad_guys[i].kind == BAD_BSOD ||
1561 bad_guys[i].kind == BAD_LAPTOP)
1563 bad_guys[i].dying = DYING_FALLING;
1564 bad_guys[i].base.ym = -8;
1565 play_sound(sounds[SND_FALL], SOUND_CENTER_SPEAKER);
1572 for (i = 0; i < upgrades.size(); i++)
1574 if (upgrades[i].base.height == 32 &&
1575 upgrades[i].base.x >= x - 32 && upgrades[i].base.x <= x + 32 &&
1576 upgrades[i].base.y >= y - 16 && upgrades[i].base.y <= y + 16)
1578 upgrades[i].base.xm = -upgrades[i].base.xm;
1579 upgrades[i].base.ym = -8;
1580 play_sound(sounds[SND_BUMP_UPGRADE], SOUND_CENTER_SPEAKER);
1586 void drawstatus(void)
1590 sprintf(str, "%d", score);
1591 text_draw(&white_text, "SCORE", 0, 0, 1);
1592 text_draw(&gold_text, str, 96, 0, 1);
1594 if(st_gl_mode != ST_GL_TEST)
1596 sprintf(str, "%d", hs_score);
1597 text_draw(&white_text, "HIGH", 0, 20, 1);
1598 text_draw(&gold_text, str, 96, 20, 1);
1602 text_draw(&white_text,"Press ESC To Return",0,20,1);
1605 if (timer_get_left(&time_left) > TIME_WARNING || (frame % 10) < 5)
1607 sprintf(str, "%d", timer_get_left(&time_left) / 1000 );
1608 text_draw(&white_text, "TIME", 224, 0, 1);
1609 text_draw(&gold_text, str, 304, 0, 1);
1612 sprintf(str, "%d", distros);
1613 text_draw(&white_text, "DISTROS", screen->h, 0, 1);
1614 text_draw(&gold_text, str, 608, 0, 1);
1616 text_draw(&white_text, "LIVES", screen->h, 20, 1);
1620 sprintf(str, "%2.1f", fps_fps);
1621 text_draw(&white_text, "FPS", screen->h, 40, 1);
1622 text_draw(&gold_text, str, screen->h + 60, 40, 1);
1625 for(i=0; i < tux.lives; ++i)
1627 texture_draw(&tux_life,565+(18*i),20);
1632 void drawendscreen(void)
1636 clearscreen(0, 0, 0);
1638 text_drawf(&blue_text, "GAMEOVER", 0, 200, A_HMIDDLE, A_TOP, 1);
1640 sprintf(str, "SCORE: %d", score);
1641 text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1);
1643 sprintf(str, "DISTROS: %d", distros);
1644 text_drawf(&gold_text, str, 0, 256, A_HMIDDLE, A_TOP, 1);
1650 void drawresultscreen(void)
1654 clearscreen(0, 0, 0);
1656 text_drawf(&blue_text, "Result:", 0, 200, A_HMIDDLE, A_TOP, 1);
1658 sprintf(str, "SCORE: %d", score);
1659 text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1);
1661 sprintf(str, "DISTROS: %d", distros);
1662 text_drawf(&gold_text, str, 0, 256, A_HMIDDLE, A_TOP, 1);
1668 void savegame(int slot)
1670 char savefile[1024];
1674 sprintf(savefile,"%s/slot%d.save",st_save_dir,slot);
1676 fi = fopen(savefile, "wb");
1680 fprintf(stderr, "Warning: I could not open the slot file ");
1685 fputs(level_subset, fi);
1687 fwrite(&level,sizeof(int),1,fi);
1688 fwrite(&score,sizeof(int),1,fi);
1689 fwrite(&distros,sizeof(int),1,fi);
1690 fwrite(&scroll_x,sizeof(float),1,fi);
1691 fwrite(&tux,sizeof(player_type),1,fi);
1692 timer_fwrite(&tux.invincible_timer,fi);
1693 timer_fwrite(&tux.skidding_timer,fi);
1694 timer_fwrite(&tux.safe_timer,fi);
1695 timer_fwrite(&tux.frame_timer,fi);
1696 timer_fwrite(&time_left,fi);
1697 ui = st_get_ticks();
1698 fwrite(&ui,sizeof(int),1,fi);
1704 void loadgame(int slot)
1706 char savefile[1024];
1711 sprintf(savefile,"%s/slot%d.save",st_save_dir,slot);
1713 fi = fopen(savefile, "rb");
1717 fprintf(stderr, "Warning: I could not open the slot file ");
1722 fgets(str, 100, fi);
1723 strcpy(level_subset, str);
1724 level_subset[strlen(level_subset)-1] = '\0';
1725 fread(&level,sizeof(int),1,fi);
1728 level_free(¤t_level);
1729 if(level_load(¤t_level,level_subset,level) != 0)
1733 activate_bad_guys();
1735 level_load_gfx(¤t_level);
1737 level_load_song(¤t_level);
1739 update_time = st_get_ticks();
1741 fread(&score,sizeof(int),1,fi);
1742 fread(&distros,sizeof(int),1,fi);
1743 fread(&scroll_x,sizeof(float),1,fi);
1744 fread(&tux,sizeof(player_type),1,fi);
1745 timer_fread(&tux.invincible_timer,fi);
1746 timer_fread(&tux.skidding_timer,fi);
1747 timer_fread(&tux.safe_timer,fi);
1748 timer_fread(&tux.frame_timer,fi);
1749 timer_fread(&time_left,fi);
1750 fread(&ui,sizeof(int),1,fi);
1751 tux.hphysic.start_time += st_get_ticks() - ui;
1752 tux.vphysic.start_time += st_get_ticks() - ui;
1758 void slotinfo(char **pinfo, int slot)
1761 char slotfile[1024];
1765 sprintf(slotfile,"%s/slot%d.save",st_save_dir,slot);
1767 fi = fopen(slotfile, "rb");
1769 sprintf(tmp,"Slot %d - ",slot);
1777 fgets(str, 100, fi);
1778 str[strlen(str)-1] = '\0';
1780 strcat(tmp, " / Level:");
1781 fread(&slot_level,sizeof(int),1,fi);
1782 sprintf(str,"%d",slot_level);
1787 *pinfo = (char*) malloc(sizeof(char) * (strlen(tmp)+1));