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];
55 static int st_gl_mode;
56 static unsigned int last_update_time;
57 static unsigned int update_time;
58 static int pause_menu_frame;
61 /* Local function prototypes: */
63 void levelintro(void);
64 void loadshared(void);
65 void unloadshared(void);
66 void drawstatus(void);
67 void drawendscreen(void);
68 void drawresultscreen(void);
76 sprintf(str, "LEVEL %d", level);
77 text_drawf(&blue_text, str, 0, 200, A_HMIDDLE, A_TOP, 1);
79 sprintf(str, "%s", current_level.name.c_str());
80 text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1);
82 sprintf(str, "TUX x %d", tux.lives);
83 text_drawf(&white_text, str, 0, 256, A_HMIDDLE, A_TOP, 1);
91 void start_timers(void)
93 timer_start(&time_left,current_level.time_left*1000);
94 st_pause_ticks_init();
95 update_time = st_get_ticks();
98 void activate_bad_guys(void)
102 /* Activate bad guys: */
104 for (y = 0; y < 15; y++)
106 for (x = 0; x < current_level.width; x++)
108 if (current_level.tiles[y][x] >= '0' && current_level.tiles[y][x] <= '9')
110 add_bad_guy(x * 32, y * 32, static_cast<BadGuyKind>(current_level.tiles[y][x] - '0'));
111 current_level.tiles[y][x] = '.';
118 /* --- GAME EVENT! --- */
120 void game_event(void)
122 while (SDL_PollEvent(&event))
126 case SDL_QUIT: /* Quit event - quit: */
129 case SDL_KEYDOWN: /* A keypress! */
130 key = event.key.keysym.sym;
132 /* Check for menu-events, if the menu is shown */
134 menu_event(&event.key.keysym);
136 if(player_key_event(&tux,key,DOWN))
141 case SDLK_ESCAPE: /* Escape: Open/Close the menu: */
144 if(st_gl_mode == ST_GL_TEST)
148 Menu::set_current(game_menu);
150 st_pause_ticks_stop();
154 Menu::set_current(game_menu);
156 st_pause_ticks_start();
164 case SDL_KEYUP: /* A keyrelease! */
165 key = event.key.keysym.sym;
167 if(player_key_event(&tux,key,UP))
178 st_pause_ticks_stop();
183 st_pause_ticks_start();
190 tux.size = !tux.size;
193 tux.base.height = 64;
196 tux.base.height = 32;
213 timer_start(&tux.invincible_timer,TUX_INVINCIBLE_TIME);
233 case SDL_JOYAXISMOTION:
234 switch(event.jaxis.axis)
237 if (event.jaxis.value < -JOYSTICK_DEAD_ZONE)
239 tux.input.left = DOWN;
240 tux.input.right = UP;
242 else if (event.jaxis.value > JOYSTICK_DEAD_ZONE)
245 tux.input.right = DOWN;
249 tux.input.left = DOWN;
250 tux.input.right = DOWN;
254 if (event.jaxis.value > JOYSTICK_DEAD_ZONE)
255 tux.input.down = DOWN;
256 else if (event.jaxis.value < -JOYSTICK_DEAD_ZONE)
261 /* Handle joystick for the menu */
264 if(tux.input.down == DOWN)
265 menuaction = MENU_ACTION_DOWN;
267 menuaction = MENU_ACTION_UP;
274 case SDL_JOYBUTTONDOWN:
275 if (event.jbutton.button == JOY_A)
277 else if (event.jbutton.button == JOY_B)
278 tux.input.fire = DOWN;
280 case SDL_JOYBUTTONUP:
281 if (event.jbutton.button == JOY_A)
283 else if (event.jbutton.button == JOY_B)
287 menuaction = MENU_ACTION_HIT;
298 /* --- GAME ACTION! --- */
300 int game_action(void)
304 /* (tux_dying || next_level) */
305 if (tux.dying || next_level)
307 /* Tux either died, or reached the end of a level! */
314 /* End of a level! */
317 if(st_gl_mode != ST_GL_TEST)
324 level_free(¤t_level);
330 player_level_begin(&tux);
336 /* No more lives!? */
340 if(st_gl_mode != ST_GL_TEST)
343 if(st_gl_mode != ST_GL_TEST)
345 if (score > hs_score)
349 level_free(¤t_level);
354 } /* if (lives < 0) */
357 /* Either way, (re-)load the (next) level... */
359 player_level_begin(&tux);
361 level_free(¤t_level);
363 if (st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
365 if(level_load(¤t_level, level_subset) != 0)
370 if(level_load(¤t_level,level_subset,level) != 0)
378 level_load_gfx(¤t_level);
380 level_load_song(¤t_level);
381 if(st_gl_mode != ST_GL_TEST)
385 play_current_music();
390 /* Handle bouncy distros: */
392 for (i = 0; i < bouncy_distros.size(); i++)
394 bouncy_distro_action(&bouncy_distros[i]);
398 /* Handle broken bricks: */
400 for (i = 0; i < broken_bricks.size(); i++)
402 broken_brick_action(&broken_bricks[i]);
406 /* Handle distro counting: */
408 if (counting_distros)
412 if (distro_counter <= 0)
413 counting_distros = -1;
417 /* Handle bouncy bricks: */
419 for (i = 0; i < bouncy_bricks.size(); i++)
421 bouncy_brick_action(&bouncy_bricks[i]);
425 /* Handle floating scores: */
427 for (i = 0; i < floating_scores.size(); i++)
429 floating_score_action(&floating_scores[i]);
433 /* Handle bullets: */
435 for (i = 0; i < bullets.size(); ++i)
437 bullet_action(&bullets[i]);
440 /* Handle upgrades: */
442 for (i = 0; i < upgrades.size(); i++)
444 upgrade_action(&upgrades[i]);
448 /* Handle bad guys: */
450 for (i = 0; i < bad_guys.size(); i++)
452 bad_guys[i].action();
455 /* Handle all possible collisions. */
461 /* --- GAME DRAW! --- */
470 if (tux.dying && (frame % 4) == 0)
471 clearscreen(255, 255, 255);
472 else if(timer_check(&super_bkgd_timer))
473 texture_draw(&img_super_bkgd, 0, 0);
476 /* Draw the real background */
477 if(current_level.bkgd_image[0] != '\0')
479 s = (int)scroll_x / 30;
480 texture_draw_part(&img_bkgd,s,0,0,0,img_bkgd.w - s, img_bkgd.h);
481 texture_draw_part(&img_bkgd,0,0,screen->w - s ,0,s,img_bkgd.h);
485 clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue);
489 /* Draw background: */
491 for (y = 0; y < 15; ++y)
493 for (x = 0; x < 21; ++x)
495 drawshape(32*x - fmodf(scroll_x, 32), y * 32,
496 current_level.tiles[(int)y][(int)x + (int)(scroll_x / 32)]);
501 /* (Bouncy bricks): */
503 for (i = 0; i < bouncy_bricks.size(); ++i)
505 bouncy_brick_draw(&bouncy_bricks[i]);
511 for (i = 0; i < bad_guys.size(); ++i)
522 for (i = 0; i < bullets.size(); ++i)
524 bullet_draw(&bullets[i]);
527 /* (Floating scores): */
529 for (i = 0; i < floating_scores.size(); ++i)
531 floating_score_draw(&floating_scores[i]);
537 for (i = 0; i < upgrades.size(); ++i)
539 upgrade_draw(&upgrades[i]);
543 /* (Bouncy distros): */
545 for (i = 0; i < bouncy_distros.size(); ++i)
547 bouncy_distro_draw(&bouncy_distros[i]);
551 /* (Broken bricks): */
553 for (i = 0; i < broken_bricks.size(); ++i)
555 broken_brick_draw(&broken_bricks[i]);
564 for(i = 0; i < x; ++i)
566 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);
568 fillrect(0,0,screen->w,screen->h,rand() % 50, rand() % 50, rand() % 50, 128);
569 text_drawf(&blue_text, "PAUSE - Press 'P' To Play", 0, 230, A_HMIDDLE, A_TOP, 1);
573 menu_process_current();
575 /* (Update it all!) */
582 /* --- GAME LOOP! --- */
584 int gameloop(const char * subset, int levelnb, int mode)
586 int fps_cnt, jump, done;
587 timer_type fps_timer, frame_timer;
588 timer_init(&fps_timer, true);
589 timer_init(&frame_timer, true);
600 strcpy(level_subset,subset);
602 if (st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
604 if (level_load(¤t_level, level_subset))
609 if(level_load(¤t_level, level_subset, level) != 0)
613 level_load_gfx(¤t_level);
615 level_load_song(¤t_level);
619 if(st_gl_mode != ST_GL_TEST)
624 if(st_gl_mode == ST_GL_PLAY || st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
627 timer_init(&time_left,true);
630 if(st_gl_mode == ST_GL_LOAD_GAME)
634 /* --- MAIN GAME LOOP!!! --- */
641 timer_init(&fps_timer,true);
642 timer_init(&frame_timer,true);
647 clearscreen(0, 0, 0);
651 play_current_music();
654 while (SDL_PollEvent(&event))
662 /* Calculate the movement-factor */
663 frame_ratio = ((double)(update_time-last_update_time))/((double)FRAME_RATE);
664 if(frame_ratio > 1.5) /* Quick hack to correct the unprecise CPU clocks a little bit. */
665 frame_ratio = 1.5 + (frame_ratio - 1.5) * 0.85;
667 if(!timer_check(&frame_timer))
669 timer_start(&frame_timer,25);
675 tux.input.old_fire = tux.input.fire;
681 if(current_menu == game_menu)
683 switch (game_menu->check())
686 st_pause_ticks_stop();
689 update_load_save_game_menu(save_game_menu, false);
692 update_load_save_game_menu(load_game_menu, true);
695 st_pause_ticks_stop();
700 else if(current_menu == options_menu)
702 process_options_menu();
704 else if(current_menu == save_game_menu )
706 process_save_load_game_menu(true);
708 else if(current_menu == load_game_menu )
710 process_save_load_game_menu(false);
715 /* Handle actions: */
717 if(!game_pause && !show_menu)
719 /*float z = frame_ratio;
723 if (game_action() == 0)
725 /* == 0: no more lives */
726 /* == -1: continues */
738 if(debug_mode && debug_fps == true)
741 /*Draw the current scene to the screen */
742 /*If the machine running the game is too slow
743 skip the drawing of the frame (so the calculations are more precise and
744 the FPS aren't affected).*/
745 /*if( ! fps_fps < 50.0 )
748 jump = true;*/ /*FIXME: Implement this tweak right.*/
751 /* Time stops in pause mode */
752 if(game_pause || show_menu )
757 /* Set the time of the last update and the time of the current update */
758 last_update_time = update_time;
759 update_time = st_get_ticks();
762 /* Pause till next frame, if the machine running the game is too fast: */
763 /* FIXME: Works great for in OpenGl mode, where the CPU doesn't have to do that much. But
764 the results in SDL mode aren't perfect (thought the 100 FPS are reached), even on an AMD2500+. */
765 if(last_update_time >= update_time - 12 && !jump)
767 /*if((update_time - last_update_time) < 10)
768 SDL_Delay((11 - (update_time - last_update_time))/2);*/
774 if (timer_check(&time_left))
776 /* are we low on time ? */
777 if ((timer_get_left(&time_left) < TIME_WARNING)
778 && (get_current_music() != HURRYUP_MUSIC)) /* play the fast music */
780 set_current_music(HURRYUP_MUSIC);
781 play_current_music();
786 player_kill(&tux,KILL);
789 /* Calculate frames per second */
793 fps_fps = (1000.0 / (float)timer_get_gone(&fps_timer)) * (float)fps_cnt;
795 if(!timer_check(&fps_timer))
797 timer_start(&fps_timer,1000);
803 while (!done && !quit);
808 level_free(¤t_level);
813 game_started = false;
819 /* Load graphics/sounds shared between all levels: */
821 void loadshared(void)
826 texture_load(&tux_right[0], datadir + "/images/shared/tux-right-0.png", USE_ALPHA);
827 texture_load(&tux_right[1], datadir + "/images/shared/tux-right-1.png", USE_ALPHA);
828 texture_load(&tux_right[2], datadir + "/images/shared/tux-right-2.png", USE_ALPHA);
830 texture_load(&tux_left[0], datadir + "/images/shared/tux-left-0.png", USE_ALPHA);
831 texture_load(&tux_left[1], datadir + "/images/shared/tux-left-1.png", USE_ALPHA);
832 texture_load(&tux_left[2], datadir + "/images/shared/tux-left-2.png", USE_ALPHA);
834 texture_load(&firetux_right[0], datadir + "/images/shared/firetux-right-0.png", USE_ALPHA);
835 texture_load(&firetux_right[1], datadir + "/images/shared/firetux-right-1.png", USE_ALPHA);
836 texture_load(&firetux_right[2], datadir + "/images/shared/firetux-right-2.png", USE_ALPHA);
838 texture_load(&firetux_left[0], datadir + "/images/shared/firetux-left-0.png", USE_ALPHA);
839 texture_load(&firetux_left[1], datadir + "/images/shared/firetux-left-1.png", USE_ALPHA);
840 texture_load(&firetux_left[2], datadir + "/images/shared/firetux-left-2.png", USE_ALPHA);
843 texture_load(&cape_right[0], datadir + "/images/shared/cape-right-0.png",
846 texture_load(&cape_right[1], datadir + "/images/shared/cape-right-1.png",
849 texture_load(&cape_left[0], datadir + "/images/shared/cape-left-0.png",
852 texture_load(&cape_left[1], datadir + "/images/shared/cape-left-1.png",
855 texture_load(&bigtux_right[0], datadir + "/images/shared/bigtux-right-0.png",
858 texture_load(&bigtux_right[1], datadir + "/images/shared/bigtux-right-1.png",
861 texture_load(&bigtux_right[2], datadir + "/images/shared/bigtux-right-2.png",
864 texture_load(&bigtux_right_jump, datadir + "/images/shared/bigtux-right-jump.png", USE_ALPHA);
866 texture_load(&bigtux_left[0], datadir + "/images/shared/bigtux-left-0.png",
869 texture_load(&bigtux_left[1], datadir + "/images/shared/bigtux-left-1.png",
872 texture_load(&bigtux_left[2], datadir + "/images/shared/bigtux-left-2.png",
875 texture_load(&bigtux_left_jump, datadir + "/images/shared/bigtux-left-jump.png", USE_ALPHA);
877 texture_load(&bigcape_right[0], datadir + "/images/shared/bigcape-right-0.png",
880 texture_load(&bigcape_right[1], datadir + "/images/shared/bigcape-right-1.png",
883 texture_load(&bigcape_left[0], datadir + "/images/shared/bigcape-left-0.png",
886 texture_load(&bigcape_left[1], datadir + "/images/shared/bigcape-left-1.png",
889 texture_load(&bigfiretux_right[0], datadir + "/images/shared/bigfiretux-right-0.png",
892 texture_load(&bigfiretux_right[1], datadir + "/images/shared/bigfiretux-right-1.png",
895 texture_load(&bigfiretux_right[2], datadir + "/images/shared/bigfiretux-right-2.png",
898 texture_load(&bigfiretux_right_jump, datadir + "/images/shared/bigfiretux-right-jump.png", USE_ALPHA);
900 texture_load(&bigfiretux_left[0], datadir + "/images/shared/bigfiretux-left-0.png",
903 texture_load(&bigfiretux_left[1], datadir + "/images/shared/bigfiretux-left-1.png",
906 texture_load(&bigfiretux_left[2], datadir + "/images/shared/bigfiretux-left-2.png",
909 texture_load(&bigfiretux_left_jump, datadir + "/images/shared/bigfiretux-left-jump.png", USE_ALPHA);
911 texture_load(&bigcape_right[0], datadir + "/images/shared/bigcape-right-0.png",
914 texture_load(&bigcape_right[1], datadir + "/images/shared/bigcape-right-1.png",
917 texture_load(&bigcape_left[0], datadir + "/images/shared/bigcape-left-0.png",
920 texture_load(&bigcape_left[1], datadir + "/images/shared/bigcape-left-1.png",
924 texture_load(&ducktux_right, datadir +
925 "/images/shared/ducktux-right.png",
928 texture_load(&ducktux_left, datadir +
929 "/images/shared/ducktux-left.png",
932 texture_load(&skidtux_right, datadir +
933 "/images/shared/skidtux-right.png",
936 texture_load(&skidtux_left, datadir +
937 "/images/shared/skidtux-left.png",
940 texture_load(&duckfiretux_right, datadir +
941 "/images/shared/duckfiretux-right.png",
944 texture_load(&duckfiretux_left, datadir +
945 "/images/shared/duckfiretux-left.png",
948 texture_load(&skidfiretux_right, datadir +
949 "/images/shared/skidfiretux-right.png",
952 texture_load(&skidfiretux_left, datadir +
953 "/images/shared/skidfiretux-left.png",
959 texture_load(&img_box_full, datadir + "/images/shared/box-full.png",
961 texture_load(&img_box_empty, datadir + "/images/shared/box-empty.png",
968 texture_load(&img_water, datadir + "/images/shared/water.png", IGNORE_ALPHA);
970 texture_load(&img_waves[0], datadir + "/images/shared/waves-0.png",
973 texture_load(&img_waves[1], datadir + "/images/shared/waves-1.png",
976 texture_load(&img_waves[2], datadir + "/images/shared/waves-2.png",
982 texture_load(&img_pole, datadir + "/images/shared/pole.png", USE_ALPHA);
983 texture_load(&img_poletop, datadir + "/images/shared/poletop.png",
989 texture_load(&img_flag[0], datadir + "/images/shared/flag-0.png",
991 texture_load(&img_flag[1], datadir + "/images/shared/flag-1.png",
997 texture_load(&img_cloud[0][0], datadir + "/images/shared/cloud-00.png",
1000 texture_load(&img_cloud[0][1], datadir + "/images/shared/cloud-01.png",
1003 texture_load(&img_cloud[0][2], datadir + "/images/shared/cloud-02.png",
1006 texture_load(&img_cloud[0][3], datadir + "/images/shared/cloud-03.png",
1010 texture_load(&img_cloud[1][0], datadir + "/images/shared/cloud-10.png",
1013 texture_load(&img_cloud[1][1], datadir + "/images/shared/cloud-11.png",
1016 texture_load(&img_cloud[1][2], datadir + "/images/shared/cloud-12.png",
1019 texture_load(&img_cloud[1][3], datadir + "/images/shared/cloud-13.png",
1027 texture_load(&img_bsod_left[0], datadir +
1028 "/images/shared/bsod-left-0.png",
1031 texture_load(&img_bsod_left[1], datadir +
1032 "/images/shared/bsod-left-1.png",
1035 texture_load(&img_bsod_left[2], datadir +
1036 "/images/shared/bsod-left-2.png",
1039 texture_load(&img_bsod_left[3], datadir +
1040 "/images/shared/bsod-left-3.png",
1043 texture_load(&img_bsod_right[0], datadir +
1044 "/images/shared/bsod-right-0.png",
1047 texture_load(&img_bsod_right[1], datadir +
1048 "/images/shared/bsod-right-1.png",
1051 texture_load(&img_bsod_right[2], datadir +
1052 "/images/shared/bsod-right-2.png",
1055 texture_load(&img_bsod_right[3], datadir +
1056 "/images/shared/bsod-right-3.png",
1059 texture_load(&img_bsod_squished_left, datadir +
1060 "/images/shared/bsod-squished-left.png",
1063 texture_load(&img_bsod_squished_right, datadir +
1064 "/images/shared/bsod-squished-right.png",
1067 texture_load(&img_bsod_falling_left, datadir +
1068 "/images/shared/bsod-falling-left.png",
1071 texture_load(&img_bsod_falling_right, datadir +
1072 "/images/shared/bsod-falling-right.png",
1078 texture_load(&img_laptop_left[0], datadir +
1079 "/images/shared/laptop-left-0.png",
1082 texture_load(&img_laptop_left[1], datadir +
1083 "/images/shared/laptop-left-1.png",
1086 texture_load(&img_laptop_left[2], datadir +
1087 "/images/shared/laptop-left-2.png",
1090 texture_load(&img_laptop_right[0], datadir +
1091 "/images/shared/laptop-right-0.png",
1094 texture_load(&img_laptop_right[1], datadir +
1095 "/images/shared/laptop-right-1.png",
1098 texture_load(&img_laptop_right[2], datadir +
1099 "/images/shared/laptop-right-2.png",
1102 texture_load(&img_laptop_flat_left, datadir +
1103 "/images/shared/laptop-flat-left.png",
1106 texture_load(&img_laptop_flat_right, datadir +
1107 "/images/shared/laptop-flat-right.png",
1110 texture_load(&img_laptop_falling_left, datadir +
1111 "/images/shared/laptop-falling-left.png",
1114 texture_load(&img_laptop_falling_right, datadir +
1115 "/images/shared/laptop-falling-right.png",
1121 texture_load(&img_money_left[0], datadir +
1122 "/images/shared/bag-left-0.png",
1125 texture_load(&img_money_left[1], datadir +
1126 "/images/shared/bag-left-1.png",
1129 texture_load(&img_money_right[0], datadir +
1130 "/images/shared/bag-right-0.png",
1133 texture_load(&img_money_right[1], datadir +
1134 "/images/shared/bag-right-1.png",
1141 texture_load(&img_mints, datadir + "/images/shared/mints.png", USE_ALPHA);
1142 texture_load(&img_coffee, datadir + "/images/shared/coffee.png", USE_ALPHA);
1147 texture_load(&img_bullet, datadir + "/images/shared/bullet.png", USE_ALPHA);
1149 texture_load(&img_red_glow, datadir + "/images/shared/red-glow.png",
1156 texture_load(&img_distro[0], datadir + "/images/shared/distro-0.png",
1159 texture_load(&img_distro[1], datadir + "/images/shared/distro-1.png",
1162 texture_load(&img_distro[2], datadir + "/images/shared/distro-2.png",
1165 texture_load(&img_distro[3], datadir + "/images/shared/distro-3.png",
1171 texture_load(&tux_life, datadir + "/images/shared/tux-life.png",
1176 texture_load(&img_golden_herring, datadir + "/images/shared/golden-herring.png",
1180 /* Super background: */
1182 texture_load(&img_super_bkgd, datadir + "/images/shared/super-bkgd.png",
1186 /* Sound effects: */
1188 /* if (use_sound) // this will introduce SERIOUS bugs here ! because "load_sound"
1189 // initialize sounds[i] with the correct pointer's value:
1190 // NULL or something else. And it will be dangerous to
1191 // play with not-initialized pointers.
1192 // This is also true with if (use_music)
1193 Send a mail to me: neoneurone@users.sf.net, if you have another opinion. :)
1195 for (i = 0; i < NUM_SOUNDS; i++)
1196 sounds[i] = load_sound(datadir + soundfilenames[i]);
1199 herring_song = load_song(datadir + "/music/SALCON.MOD");
1203 /* Free shared data: */
1205 void unloadshared(void)
1209 for (i = 0; i < 3; i++)
1211 texture_free(&tux_right[i]);
1212 texture_free(&tux_left[i]);
1213 texture_free(&bigtux_right[i]);
1214 texture_free(&bigtux_left[i]);
1217 texture_free(&bigtux_right_jump);
1218 texture_free(&bigtux_left_jump);
1220 for (i = 0; i < 2; i++)
1222 texture_free(&cape_right[i]);
1223 texture_free(&cape_left[i]);
1224 texture_free(&bigcape_right[i]);
1225 texture_free(&bigcape_left[i]);
1228 texture_free(&ducktux_left);
1229 texture_free(&ducktux_right);
1231 texture_free(&skidtux_left);
1232 texture_free(&skidtux_right);
1234 for (i = 0; i < 4; i++)
1236 texture_free(&img_bsod_left[i]);
1237 texture_free(&img_bsod_right[i]);
1240 texture_free(&img_bsod_squished_left);
1241 texture_free(&img_bsod_squished_right);
1243 texture_free(&img_bsod_falling_left);
1244 texture_free(&img_bsod_falling_right);
1246 for (i = 0; i < 3; i++)
1248 texture_free(&img_laptop_left[i]);
1249 texture_free(&img_laptop_right[i]);
1252 texture_free(&img_laptop_flat_left);
1253 texture_free(&img_laptop_flat_right);
1255 texture_free(&img_laptop_falling_left);
1256 texture_free(&img_laptop_falling_right);
1258 for (i = 0; i < 2; i++)
1260 texture_free(&img_money_left[i]);
1261 texture_free(&img_money_right[i]);
1264 texture_free(&img_box_full);
1265 texture_free(&img_box_empty);
1267 texture_free(&img_water);
1268 for (i = 0; i < 3; i++)
1269 texture_free(&img_waves[i]);
1271 texture_free(&img_pole);
1272 texture_free(&img_poletop);
1274 for (i = 0; i < 2; i++)
1275 texture_free(&img_flag[i]);
1277 texture_free(&img_mints);
1278 texture_free(&img_coffee);
1280 for (i = 0; i < 4; i++)
1282 texture_free(&img_distro[i]);
1283 texture_free(&img_cloud[0][i]);
1284 texture_free(&img_cloud[1][i]);
1287 texture_free(&img_golden_herring);
1289 for (i = 0; i < NUM_SOUNDS; i++)
1290 free_chunk(sounds[i]);
1292 /* free the herring song */
1293 free_music( herring_song );
1297 /* Draw a tile on the screen: */
1299 void drawshape(float x, float y, unsigned char c)
1303 if (c == 'X' || c == 'x')
1304 texture_draw(&img_brick[0], x, y);
1305 else if (c == 'Y' || c == 'y')
1306 texture_draw(&img_brick[1], x, y);
1307 else if (c == 'A' || c =='B' || c == '!')
1308 texture_draw(&img_box_full, x, y);
1310 texture_draw(&img_box_empty, x, y);
1311 else if (c >= 'C' && c <= 'F')
1312 texture_draw(&img_cloud[0][c - 'C'], x, y);
1313 else if (c >= 'c' && c <= 'f')
1314 texture_draw(&img_cloud[1][c - 'c'], x, y);
1315 else if (c >= 'G' && c <= 'J')
1316 texture_draw(&img_bkgd_tile[0][c - 'G'], x, y);
1317 else if (c >= 'g' && c <= 'j')
1318 texture_draw(&img_bkgd_tile[1][c - 'g'], x, y);
1320 texture_draw(&img_solid[0], x, y);
1322 texture_draw(&img_solid[1], x, y);
1324 texture_draw(&img_solid[2], x, y);
1326 texture_draw(&img_solid[3], x, y);
1329 z = (frame / 2) % 6;
1332 texture_draw(&img_distro[z], x, y);
1334 texture_draw(&img_distro[2], x, y);
1336 texture_draw(&img_distro[1], x, y);
1340 z = (frame / 3) % 3;
1342 texture_draw(&img_waves[z], x, y);
1345 texture_draw(&img_poletop, x, y);
1348 texture_draw(&img_pole, x, y);
1353 z = (frame / 3) % 2;
1355 texture_draw(&img_flag[z], x + 16, y);
1358 texture_draw(&img_water, x, y);
1362 /* What shape is at some position? */
1364 unsigned char shape(float x, float y)
1373 if (yy >= 0 && yy < 15 && xx >= 0 && xx <= current_level.width)
1375 c = current_level.tiles[yy][xx];
1386 bool issolid(float x, float y)
1388 return (isbrick(x, y) ||
1390 (shape(x, y) == '[') ||
1391 (shape(x, y) == '=') ||
1392 (shape(x, y) == ']') ||
1393 (shape(x, y) == 'A') ||
1394 (shape(x, y) == 'B') ||
1395 (shape(x, y) == '!') ||
1396 (shape(x, y) == 'a'));
1399 /* Is it a brick? */
1401 bool isbrick(float x, float y)
1403 return (shape(x, y) == 'X' ||
1404 shape(x, y) == 'x' ||
1405 shape(x, y) == 'Y' ||
1406 shape(x, y) == 'y');
1412 bool isice(float x, float y)
1414 return (shape(x, y) == '#');
1417 /* Is it a full box? */
1419 bool isfullbox(float x, float y)
1421 return (shape(x, y) == 'A' ||
1422 shape(x, y) == 'B' ||
1423 shape(x, y) == '!');
1426 /* Break a brick: */
1428 void trybreakbrick(float x, float y)
1432 if (shape(x, y) == 'x' || shape(x, y) == 'y')
1434 /* Get a distro from it: */
1436 add_bouncy_distro(((int)(x + 1) / 32) * 32,
1437 (int)(y / 32) * 32);
1439 if (!counting_distros)
1441 counting_distros = true;
1442 distro_counter = 50;
1445 if (distro_counter <= 0)
1446 level_change(¤t_level,x, y, 'a');
1448 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1449 score = score + SCORE_DISTRO;
1454 /* Get rid of it: */
1456 level_change(¤t_level,x, y,'.');
1460 /* Replace it with broken bits: */
1462 add_broken_brick(((int)(x + 1) / 32) * 32,
1463 (int)(y / 32) * 32);
1466 /* Get some score: */
1468 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
1469 score = score + SCORE_BRICK;
1474 /* Bounce a brick: */
1476 void bumpbrick(float x, float y)
1478 add_bouncy_brick(((int)(x + 1) / 32) * 32,
1479 (int)(y / 32) * 32);
1481 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
1488 void tryemptybox(float x, float y, int col_side)
1490 if (!isfullbox(x, y))
1493 // according to the collision side, set the upgrade direction
1495 if(col_side == LEFT)
1502 case 'A': /* Box with a distro! */
1503 add_bouncy_distro(((int)(x + 1) / 32) * 32, (int)(y / 32) * 32 - 32);
1504 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1505 score = score + SCORE_DISTRO;
1508 case 'B': /* Add an upgrade! */
1509 if (tux.size == SMALL) /* Tux is small, add mints! */
1510 add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_MINTS);
1511 else /* Tux is big, add coffee: */
1512 add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_COFFEE);
1513 play_sound(sounds[SND_UPGRADE], SOUND_CENTER_SPEAKER);
1515 case '!': /* Add a golden herring */
1516 add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_HERRING);
1522 /* Empty the box: */
1523 level_change(¤t_level,x, y, 'a');
1527 /* Try to grab a distro: */
1529 void trygrabdistro(float x, float y, int bounciness)
1531 if (shape(x, y) == '$')
1533 level_change(¤t_level,x, y, '.');
1534 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1536 if (bounciness == BOUNCE)
1538 add_bouncy_distro(((int)(x + 1) / 32) * 32,
1539 (int)(y / 32) * 32);
1542 score = score + SCORE_DISTRO;
1547 /* Try to bump a bad guy from below: */
1549 void trybumpbadguy(float x, float y)
1554 for (i = 0; i < bad_guys.size(); i++)
1556 if (bad_guys[i].base.x >= x - 32 && bad_guys[i].base.x <= x + 32 &&
1557 bad_guys[i].base.y >= y - 16 && bad_guys[i].base.y <= y + 16)
1559 if (bad_guys[i].kind == BAD_BSOD ||
1560 bad_guys[i].kind == BAD_LAPTOP)
1562 bad_guys[i].dying = DYING_FALLING;
1563 bad_guys[i].base.ym = -8;
1564 play_sound(sounds[SND_FALL], SOUND_CENTER_SPEAKER);
1571 for (i = 0; i < upgrades.size(); i++)
1573 if (upgrades[i].base.height == 32 &&
1574 upgrades[i].base.x >= x - 32 && upgrades[i].base.x <= x + 32 &&
1575 upgrades[i].base.y >= y - 16 && upgrades[i].base.y <= y + 16)
1577 upgrades[i].base.xm = -upgrades[i].base.xm;
1578 upgrades[i].base.ym = -8;
1579 play_sound(sounds[SND_BUMP_UPGRADE], SOUND_CENTER_SPEAKER);
1585 void drawstatus(void)
1589 sprintf(str, "%d", score);
1590 text_draw(&white_text, "SCORE", 0, 0, 1);
1591 text_draw(&gold_text, str, 96, 0, 1);
1593 if(st_gl_mode != ST_GL_TEST)
1595 sprintf(str, "%d", hs_score);
1596 text_draw(&white_text, "HIGH", 0, 20, 1);
1597 text_draw(&gold_text, str, 96, 20, 1);
1601 text_draw(&white_text,"Press ESC To Return",0,20,1);
1604 if (timer_get_left(&time_left) > TIME_WARNING || (frame % 10) < 5)
1606 sprintf(str, "%d", timer_get_left(&time_left) / 1000 );
1607 text_draw(&white_text, "TIME", 224, 0, 1);
1608 text_draw(&gold_text, str, 304, 0, 1);
1611 sprintf(str, "%d", distros);
1612 text_draw(&white_text, "DISTROS", screen->h, 0, 1);
1613 text_draw(&gold_text, str, 608, 0, 1);
1615 text_draw(&white_text, "LIVES", screen->h, 20, 1);
1619 sprintf(str, "%2.1f", fps_fps);
1620 text_draw(&white_text, "FPS", screen->h, 40, 1);
1621 text_draw(&gold_text, str, screen->h + 60, 40, 1);
1624 for(int i=0; i < tux.lives; ++i)
1626 texture_draw(&tux_life,565+(18*i),20);
1631 void drawendscreen(void)
1635 clearscreen(0, 0, 0);
1637 text_drawf(&blue_text, "GAMEOVER", 0, 200, A_HMIDDLE, A_TOP, 1);
1639 sprintf(str, "SCORE: %d", score);
1640 text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1);
1642 sprintf(str, "DISTROS: %d", distros);
1643 text_drawf(&gold_text, str, 0, 256, A_HMIDDLE, A_TOP, 1);
1649 void drawresultscreen(void)
1653 clearscreen(0, 0, 0);
1655 text_drawf(&blue_text, "Result:", 0, 200, A_HMIDDLE, A_TOP, 1);
1657 sprintf(str, "SCORE: %d", score);
1658 text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1);
1660 sprintf(str, "DISTROS: %d", distros);
1661 text_drawf(&gold_text, str, 0, 256, A_HMIDDLE, A_TOP, 1);
1667 void savegame(int slot)
1669 char savefile[1024];
1673 sprintf(savefile,"%s/slot%d.save",st_save_dir,slot);
1675 fi = fopen(savefile, "wb");
1679 fprintf(stderr, "Warning: I could not open the slot file ");
1684 fputs(level_subset, fi);
1686 fwrite(&level,sizeof(int),1,fi);
1687 fwrite(&score,sizeof(int),1,fi);
1688 fwrite(&distros,sizeof(int),1,fi);
1689 fwrite(&scroll_x,sizeof(float),1,fi);
1690 fwrite(&tux,sizeof(player_type),1,fi);
1691 timer_fwrite(&tux.invincible_timer,fi);
1692 timer_fwrite(&tux.skidding_timer,fi);
1693 timer_fwrite(&tux.safe_timer,fi);
1694 timer_fwrite(&tux.frame_timer,fi);
1695 timer_fwrite(&time_left,fi);
1696 ui = st_get_ticks();
1697 fwrite(&ui,sizeof(int),1,fi);
1703 void loadgame(int slot)
1705 char savefile[1024];
1710 sprintf(savefile,"%s/slot%d.save",st_save_dir,slot);
1712 fi = fopen(savefile, "rb");
1716 fprintf(stderr, "Warning: I could not open the slot file ");
1721 fgets(str, 100, fi);
1722 strcpy(level_subset, str);
1723 level_subset[strlen(level_subset)-1] = '\0';
1724 fread(&level,sizeof(int),1,fi);
1727 level_free(¤t_level);
1728 if(level_load(¤t_level,level_subset,level) != 0)
1732 activate_bad_guys();
1734 level_load_gfx(¤t_level);
1736 level_load_song(¤t_level);
1738 update_time = st_get_ticks();
1740 fread(&score,sizeof(int),1,fi);
1741 fread(&distros,sizeof(int),1,fi);
1742 fread(&scroll_x,sizeof(float),1,fi);
1743 fread(&tux,sizeof(player_type),1,fi);
1744 timer_fread(&tux.invincible_timer,fi);
1745 timer_fread(&tux.skidding_timer,fi);
1746 timer_fread(&tux.safe_timer,fi);
1747 timer_fread(&tux.frame_timer,fi);
1748 timer_fread(&time_left,fi);
1749 fread(&ui,sizeof(int),1,fi);
1750 tux.hphysic.start_time += st_get_ticks() - ui;
1751 tux.vphysic.start_time += st_get_ticks() - ui;
1757 void slotinfo(char **pinfo, int slot)
1760 char slotfile[1024];
1764 sprintf(slotfile,"%s/slot%d.save",st_save_dir,slot);
1766 fi = fopen(slotfile, "rb");
1768 sprintf(tmp,"Slot %d - ",slot);
1776 fgets(str, 100, fi);
1777 str[strlen(str)-1] = '\0';
1779 strcat(tmp, " / Level:");
1780 fread(&slot_level,sizeof(int),1,fi);
1781 sprintf(str,"%d",slot_level);
1786 *pinfo = (char*) malloc(sizeof(char) * (strlen(tmp)+1));