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(tux.key_event(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(tux.key_event(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)
244 tux.input_.left = UP;
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)
257 tux.input_.down = UP;
259 tux.input_.down = UP;
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)
276 tux.input_.up = DOWN;
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)
284 tux.input_.fire = UP;
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);
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... */
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: */
391 for (i = 0; i < bouncy_distros.size(); i++)
393 bouncy_distro_action(&bouncy_distros[i]);
397 /* Handle broken bricks: */
398 for (i = 0; i < broken_bricks.size(); i++)
400 broken_brick_action(&broken_bricks[i]);
404 /* Handle distro counting: */
406 if (counting_distros)
410 if (distro_counter <= 0)
411 counting_distros = -1;
415 /* Handle bouncy bricks: */
417 for (i = 0; i < bouncy_bricks.size(); i++)
419 bouncy_brick_action(&bouncy_bricks[i]);
423 /* Handle floating scores: */
425 for (i = 0; i < floating_scores.size(); i++)
427 floating_score_action(&floating_scores[i]);
431 /* Handle bullets: */
433 for (i = 0; i < bullets.size(); ++i)
435 bullet_action(&bullets[i]);
438 /* Handle upgrades: */
440 for (i = 0; i < upgrades.size(); i++)
442 upgrade_action(&upgrades[i]);
446 /* Handle bad guys: */
448 for (i = 0; i < bad_guys.size(); i++)
450 bad_guys[i].action();
453 /* Handle all possible collisions. */
459 /* --- GAME DRAW! --- */
468 if (tux.dying && (global_frame_counter % 4) == 0)
469 clearscreen(255, 255, 255);
470 else if(timer_check(&super_bkgd_timer))
471 texture_draw(&img_super_bkgd, 0, 0);
474 /* Draw the real background */
475 if(current_level.bkgd_image[0] != '\0')
477 s = (int)scroll_x / 30;
478 texture_draw_part(&img_bkgd,s,0,0,0,img_bkgd.w - s, img_bkgd.h);
479 texture_draw_part(&img_bkgd,0,0,screen->w - s ,0,s,img_bkgd.h);
483 clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue);
487 /* Draw background: */
489 for (y = 0; y < 15; ++y)
491 for (x = 0; x < 21; ++x)
493 drawshape(32*x - fmodf(scroll_x, 32), y * 32,
494 current_level.tiles[(int)y][(int)x + (int)(scroll_x / 32)]);
499 /* (Bouncy bricks): */
501 for (i = 0; i < bouncy_bricks.size(); ++i)
503 bouncy_brick_draw(&bouncy_bricks[i]);
508 for (i = 0; i < bad_guys.size(); ++i)
517 for (i = 0; i < bullets.size(); ++i)
519 bullet_draw(&bullets[i]);
522 /* (Floating scores): */
523 for (i = 0; i < floating_scores.size(); ++i)
525 floating_score_draw(&floating_scores[i]);
530 for (i = 0; i < upgrades.size(); ++i)
532 upgrade_draw(&upgrades[i]);
536 /* (Bouncy distros): */
537 for (i = 0; i < bouncy_distros.size(); ++i)
539 bouncy_distro_draw(&bouncy_distros[i]);
543 /* (Broken bricks): */
544 for (i = 0; i < broken_bricks.size(); ++i)
546 broken_brick_draw(&broken_bricks[i]);
554 for(i = 0; i < x; ++i)
556 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);
558 fillrect(0,0,screen->w,screen->h,rand() % 50, rand() % 50, rand() % 50, 128);
559 text_drawf(&blue_text, "PAUSE - Press 'P' To Play", 0, 230, A_HMIDDLE, A_TOP, 1);
563 menu_process_current();
565 /* (Update it all!) */
572 /* --- GAME LOOP! --- */
574 int gameloop(const char * subset, int levelnb, int mode)
576 int fps_cnt, jump, done;
577 timer_type fps_timer, frame_timer;
578 timer_init(&fps_timer, true);
579 timer_init(&frame_timer, true);
590 strcpy(level_subset,subset);
592 if (st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
594 if (level_load(¤t_level, level_subset))
599 if(level_load(¤t_level, level_subset, level) != 0)
603 level_load_gfx(¤t_level);
605 level_load_song(¤t_level);
609 if(st_gl_mode != ST_GL_TEST)
614 if(st_gl_mode == ST_GL_PLAY || st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
617 timer_init(&time_left,true);
620 if(st_gl_mode == ST_GL_LOAD_GAME)
624 /* --- MAIN GAME LOOP!!! --- */
629 global_frame_counter = 0;
631 timer_init(&fps_timer,true);
632 timer_init(&frame_timer,true);
637 clearscreen(0, 0, 0);
641 play_current_music();
644 while (SDL_PollEvent(&event))
652 /* Calculate the movement-factor */
653 frame_ratio = ((double)(update_time-last_update_time))/((double)FRAME_RATE);
654 if(frame_ratio > 1.5) /* Quick hack to correct the unprecise CPU clocks a little bit. */
655 frame_ratio = 1.5 + (frame_ratio - 1.5) * 0.85;
657 if(!timer_check(&frame_timer))
659 timer_start(&frame_timer,25);
660 ++global_frame_counter;
665 tux.input_.old_fire = tux.input_.fire;
671 if(current_menu == game_menu)
673 switch (game_menu->check())
676 st_pause_ticks_stop();
679 update_load_save_game_menu(save_game_menu, false);
682 update_load_save_game_menu(load_game_menu, true);
685 st_pause_ticks_stop();
690 else if(current_menu == options_menu)
692 process_options_menu();
694 else if(current_menu == save_game_menu )
696 process_save_load_game_menu(true);
698 else if(current_menu == load_game_menu )
700 process_save_load_game_menu(false);
705 /* Handle actions: */
707 if(!game_pause && !show_menu)
709 /*float z = frame_ratio;
713 if (game_action() == 0)
715 /* == 0: no more lives */
716 /* == -1: continues */
728 if(debug_mode && debug_fps == true)
731 /*Draw the current scene to the screen */
732 /*If the machine running the game is too slow
733 skip the drawing of the frame (so the calculations are more precise and
734 the FPS aren't affected).*/
735 /*if( ! fps_fps < 50.0 )
738 jump = true;*/ /*FIXME: Implement this tweak right.*/
741 /* Time stops in pause mode */
742 if(game_pause || show_menu )
747 /* Set the time of the last update and the time of the current update */
748 last_update_time = update_time;
749 update_time = st_get_ticks();
752 /* Pause till next frame, if the machine running the game is too fast: */
753 /* FIXME: Works great for in OpenGl mode, where the CPU doesn't have to do that much. But
754 the results in SDL mode aren't perfect (thought the 100 FPS are reached), even on an AMD2500+. */
755 if(last_update_time >= update_time - 12 && !jump)
757 /*if((update_time - last_update_time) < 10)
758 SDL_Delay((11 - (update_time - last_update_time))/2);*/
764 if (timer_check(&time_left))
766 /* are we low on time ? */
767 if ((timer_get_left(&time_left) < TIME_WARNING)
768 && (get_current_music() != HURRYUP_MUSIC)) /* play the fast music */
770 set_current_music(HURRYUP_MUSIC);
771 play_current_music();
779 /* Calculate frames per second */
783 fps_fps = (1000.0 / (float)timer_get_gone(&fps_timer)) * (float)fps_cnt;
785 if(!timer_check(&fps_timer))
787 timer_start(&fps_timer,1000);
793 while (!done && !quit);
798 level_free(¤t_level);
803 game_started = false;
809 /* Load graphics/sounds shared between all levels: */
811 void loadshared(void)
816 texture_load(&tux_right[0], datadir + "/images/shared/tux-right-0.png", USE_ALPHA);
817 texture_load(&tux_right[1], datadir + "/images/shared/tux-right-1.png", USE_ALPHA);
818 texture_load(&tux_right[2], datadir + "/images/shared/tux-right-2.png", USE_ALPHA);
820 texture_load(&tux_left[0], datadir + "/images/shared/tux-left-0.png", USE_ALPHA);
821 texture_load(&tux_left[1], datadir + "/images/shared/tux-left-1.png", USE_ALPHA);
822 texture_load(&tux_left[2], datadir + "/images/shared/tux-left-2.png", USE_ALPHA);
824 texture_load(&firetux_right[0], datadir + "/images/shared/firetux-right-0.png", USE_ALPHA);
825 texture_load(&firetux_right[1], datadir + "/images/shared/firetux-right-1.png", USE_ALPHA);
826 texture_load(&firetux_right[2], datadir + "/images/shared/firetux-right-2.png", USE_ALPHA);
828 texture_load(&firetux_left[0], datadir + "/images/shared/firetux-left-0.png", USE_ALPHA);
829 texture_load(&firetux_left[1], datadir + "/images/shared/firetux-left-1.png", USE_ALPHA);
830 texture_load(&firetux_left[2], datadir + "/images/shared/firetux-left-2.png", USE_ALPHA);
833 texture_load(&cape_right[0], datadir + "/images/shared/cape-right-0.png",
836 texture_load(&cape_right[1], datadir + "/images/shared/cape-right-1.png",
839 texture_load(&cape_left[0], datadir + "/images/shared/cape-left-0.png",
842 texture_load(&cape_left[1], datadir + "/images/shared/cape-left-1.png",
845 texture_load(&bigtux_right[0], datadir + "/images/shared/bigtux-right-0.png",
848 texture_load(&bigtux_right[1], datadir + "/images/shared/bigtux-right-1.png",
851 texture_load(&bigtux_right[2], datadir + "/images/shared/bigtux-right-2.png",
854 texture_load(&bigtux_right_jump, datadir + "/images/shared/bigtux-right-jump.png", USE_ALPHA);
856 texture_load(&bigtux_left[0], datadir + "/images/shared/bigtux-left-0.png",
859 texture_load(&bigtux_left[1], datadir + "/images/shared/bigtux-left-1.png",
862 texture_load(&bigtux_left[2], datadir + "/images/shared/bigtux-left-2.png",
865 texture_load(&bigtux_left_jump, datadir + "/images/shared/bigtux-left-jump.png", USE_ALPHA);
867 texture_load(&bigcape_right[0], datadir + "/images/shared/bigcape-right-0.png",
870 texture_load(&bigcape_right[1], datadir + "/images/shared/bigcape-right-1.png",
873 texture_load(&bigcape_left[0], datadir + "/images/shared/bigcape-left-0.png",
876 texture_load(&bigcape_left[1], datadir + "/images/shared/bigcape-left-1.png",
879 texture_load(&bigfiretux_right[0], datadir + "/images/shared/bigfiretux-right-0.png",
882 texture_load(&bigfiretux_right[1], datadir + "/images/shared/bigfiretux-right-1.png",
885 texture_load(&bigfiretux_right[2], datadir + "/images/shared/bigfiretux-right-2.png",
888 texture_load(&bigfiretux_right_jump, datadir + "/images/shared/bigfiretux-right-jump.png", USE_ALPHA);
890 texture_load(&bigfiretux_left[0], datadir + "/images/shared/bigfiretux-left-0.png",
893 texture_load(&bigfiretux_left[1], datadir + "/images/shared/bigfiretux-left-1.png",
896 texture_load(&bigfiretux_left[2], datadir + "/images/shared/bigfiretux-left-2.png",
899 texture_load(&bigfiretux_left_jump, datadir + "/images/shared/bigfiretux-left-jump.png", USE_ALPHA);
901 texture_load(&bigcape_right[0], datadir + "/images/shared/bigcape-right-0.png",
904 texture_load(&bigcape_right[1], datadir + "/images/shared/bigcape-right-1.png",
907 texture_load(&bigcape_left[0], datadir + "/images/shared/bigcape-left-0.png",
910 texture_load(&bigcape_left[1], datadir + "/images/shared/bigcape-left-1.png",
914 texture_load(&ducktux_right, datadir +
915 "/images/shared/ducktux-right.png",
918 texture_load(&ducktux_left, datadir +
919 "/images/shared/ducktux-left.png",
922 texture_load(&skidtux_right, datadir +
923 "/images/shared/skidtux-right.png",
926 texture_load(&skidtux_left, datadir +
927 "/images/shared/skidtux-left.png",
930 texture_load(&duckfiretux_right, datadir +
931 "/images/shared/duckfiretux-right.png",
934 texture_load(&duckfiretux_left, datadir +
935 "/images/shared/duckfiretux-left.png",
938 texture_load(&skidfiretux_right, datadir +
939 "/images/shared/skidfiretux-right.png",
942 texture_load(&skidfiretux_left, datadir +
943 "/images/shared/skidfiretux-left.png",
949 texture_load(&img_box_full, datadir + "/images/shared/box-full.png",
951 texture_load(&img_box_empty, datadir + "/images/shared/box-empty.png",
958 texture_load(&img_water, datadir + "/images/shared/water.png", IGNORE_ALPHA);
960 texture_load(&img_waves[0], datadir + "/images/shared/waves-0.png",
963 texture_load(&img_waves[1], datadir + "/images/shared/waves-1.png",
966 texture_load(&img_waves[2], datadir + "/images/shared/waves-2.png",
972 texture_load(&img_pole, datadir + "/images/shared/pole.png", USE_ALPHA);
973 texture_load(&img_poletop, datadir + "/images/shared/poletop.png",
979 texture_load(&img_flag[0], datadir + "/images/shared/flag-0.png",
981 texture_load(&img_flag[1], datadir + "/images/shared/flag-1.png",
987 texture_load(&img_cloud[0][0], datadir + "/images/shared/cloud-00.png",
990 texture_load(&img_cloud[0][1], datadir + "/images/shared/cloud-01.png",
993 texture_load(&img_cloud[0][2], datadir + "/images/shared/cloud-02.png",
996 texture_load(&img_cloud[0][3], datadir + "/images/shared/cloud-03.png",
1000 texture_load(&img_cloud[1][0], datadir + "/images/shared/cloud-10.png",
1003 texture_load(&img_cloud[1][1], datadir + "/images/shared/cloud-11.png",
1006 texture_load(&img_cloud[1][2], datadir + "/images/shared/cloud-12.png",
1009 texture_load(&img_cloud[1][3], datadir + "/images/shared/cloud-13.png",
1017 texture_load(&img_bsod_left[0], datadir +
1018 "/images/shared/bsod-left-0.png",
1021 texture_load(&img_bsod_left[1], datadir +
1022 "/images/shared/bsod-left-1.png",
1025 texture_load(&img_bsod_left[2], datadir +
1026 "/images/shared/bsod-left-2.png",
1029 texture_load(&img_bsod_left[3], datadir +
1030 "/images/shared/bsod-left-3.png",
1033 texture_load(&img_bsod_right[0], datadir +
1034 "/images/shared/bsod-right-0.png",
1037 texture_load(&img_bsod_right[1], datadir +
1038 "/images/shared/bsod-right-1.png",
1041 texture_load(&img_bsod_right[2], datadir +
1042 "/images/shared/bsod-right-2.png",
1045 texture_load(&img_bsod_right[3], datadir +
1046 "/images/shared/bsod-right-3.png",
1049 texture_load(&img_bsod_squished_left, datadir +
1050 "/images/shared/bsod-squished-left.png",
1053 texture_load(&img_bsod_squished_right, datadir +
1054 "/images/shared/bsod-squished-right.png",
1057 texture_load(&img_bsod_falling_left, datadir +
1058 "/images/shared/bsod-falling-left.png",
1061 texture_load(&img_bsod_falling_right, datadir +
1062 "/images/shared/bsod-falling-right.png",
1068 texture_load(&img_laptop_left[0], datadir +
1069 "/images/shared/laptop-left-0.png",
1072 texture_load(&img_laptop_left[1], datadir +
1073 "/images/shared/laptop-left-1.png",
1076 texture_load(&img_laptop_left[2], datadir +
1077 "/images/shared/laptop-left-2.png",
1080 texture_load(&img_laptop_right[0], datadir +
1081 "/images/shared/laptop-right-0.png",
1084 texture_load(&img_laptop_right[1], datadir +
1085 "/images/shared/laptop-right-1.png",
1088 texture_load(&img_laptop_right[2], datadir +
1089 "/images/shared/laptop-right-2.png",
1092 texture_load(&img_laptop_flat_left, datadir +
1093 "/images/shared/laptop-flat-left.png",
1096 texture_load(&img_laptop_flat_right, datadir +
1097 "/images/shared/laptop-flat-right.png",
1100 texture_load(&img_laptop_falling_left, datadir +
1101 "/images/shared/laptop-falling-left.png",
1104 texture_load(&img_laptop_falling_right, datadir +
1105 "/images/shared/laptop-falling-right.png",
1111 texture_load(&img_money_left[0], datadir +
1112 "/images/shared/bag-left-0.png",
1115 texture_load(&img_money_left[1], datadir +
1116 "/images/shared/bag-left-1.png",
1119 texture_load(&img_money_right[0], datadir +
1120 "/images/shared/bag-right-0.png",
1123 texture_load(&img_money_right[1], datadir +
1124 "/images/shared/bag-right-1.png",
1131 texture_load(&img_mints, datadir + "/images/shared/mints.png", USE_ALPHA);
1132 texture_load(&img_coffee, datadir + "/images/shared/coffee.png", USE_ALPHA);
1137 texture_load(&img_bullet, datadir + "/images/shared/bullet.png", USE_ALPHA);
1139 texture_load(&img_red_glow, datadir + "/images/shared/red-glow.png",
1146 texture_load(&img_distro[0], datadir + "/images/shared/distro-0.png",
1149 texture_load(&img_distro[1], datadir + "/images/shared/distro-1.png",
1152 texture_load(&img_distro[2], datadir + "/images/shared/distro-2.png",
1155 texture_load(&img_distro[3], datadir + "/images/shared/distro-3.png",
1161 texture_load(&tux_life, datadir + "/images/shared/tux-life.png",
1166 texture_load(&img_golden_herring, datadir + "/images/shared/golden-herring.png",
1170 /* Super background: */
1172 texture_load(&img_super_bkgd, datadir + "/images/shared/super-bkgd.png",
1176 /* Sound effects: */
1178 /* if (use_sound) // this will introduce SERIOUS bugs here ! because "load_sound"
1179 // initialize sounds[i] with the correct pointer's value:
1180 // NULL or something else. And it will be dangerous to
1181 // play with not-initialized pointers.
1182 // This is also true with if (use_music)
1183 Send a mail to me: neoneurone@users.sf.net, if you have another opinion. :)
1185 for (i = 0; i < NUM_SOUNDS; i++)
1186 sounds[i] = load_sound(datadir + soundfilenames[i]);
1189 herring_song = load_song(datadir + "/music/SALCON.MOD");
1193 /* Free shared data: */
1195 void unloadshared(void)
1199 for (i = 0; i < 3; i++)
1201 texture_free(&tux_right[i]);
1202 texture_free(&tux_left[i]);
1203 texture_free(&bigtux_right[i]);
1204 texture_free(&bigtux_left[i]);
1207 texture_free(&bigtux_right_jump);
1208 texture_free(&bigtux_left_jump);
1210 for (i = 0; i < 2; i++)
1212 texture_free(&cape_right[i]);
1213 texture_free(&cape_left[i]);
1214 texture_free(&bigcape_right[i]);
1215 texture_free(&bigcape_left[i]);
1218 texture_free(&ducktux_left);
1219 texture_free(&ducktux_right);
1221 texture_free(&skidtux_left);
1222 texture_free(&skidtux_right);
1224 for (i = 0; i < 4; i++)
1226 texture_free(&img_bsod_left[i]);
1227 texture_free(&img_bsod_right[i]);
1230 texture_free(&img_bsod_squished_left);
1231 texture_free(&img_bsod_squished_right);
1233 texture_free(&img_bsod_falling_left);
1234 texture_free(&img_bsod_falling_right);
1236 for (i = 0; i < 3; i++)
1238 texture_free(&img_laptop_left[i]);
1239 texture_free(&img_laptop_right[i]);
1242 texture_free(&img_laptop_flat_left);
1243 texture_free(&img_laptop_flat_right);
1245 texture_free(&img_laptop_falling_left);
1246 texture_free(&img_laptop_falling_right);
1248 for (i = 0; i < 2; i++)
1250 texture_free(&img_money_left[i]);
1251 texture_free(&img_money_right[i]);
1254 texture_free(&img_box_full);
1255 texture_free(&img_box_empty);
1257 texture_free(&img_water);
1258 for (i = 0; i < 3; i++)
1259 texture_free(&img_waves[i]);
1261 texture_free(&img_pole);
1262 texture_free(&img_poletop);
1264 for (i = 0; i < 2; i++)
1265 texture_free(&img_flag[i]);
1267 texture_free(&img_mints);
1268 texture_free(&img_coffee);
1270 for (i = 0; i < 4; i++)
1272 texture_free(&img_distro[i]);
1273 texture_free(&img_cloud[0][i]);
1274 texture_free(&img_cloud[1][i]);
1277 texture_free(&img_golden_herring);
1279 for (i = 0; i < NUM_SOUNDS; i++)
1280 free_chunk(sounds[i]);
1282 /* free the herring song */
1283 free_music( herring_song );
1287 /* Draw a tile on the screen: */
1289 void drawshape(float x, float y, unsigned char c)
1293 if (c == 'X' || c == 'x')
1294 texture_draw(&img_brick[0], x, y);
1295 else if (c == 'Y' || c == 'y')
1296 texture_draw(&img_brick[1], x, y);
1297 else if (c == 'A' || c =='B' || c == '!')
1298 texture_draw(&img_box_full, x, y);
1300 texture_draw(&img_box_empty, x, y);
1301 else if (c >= 'C' && c <= 'F')
1302 texture_draw(&img_cloud[0][c - 'C'], x, y);
1303 else if (c >= 'c' && c <= 'f')
1304 texture_draw(&img_cloud[1][c - 'c'], x, y);
1305 else if (c >= 'G' && c <= 'J')
1306 texture_draw(&img_bkgd_tile[0][c - 'G'], x, y);
1307 else if (c >= 'g' && c <= 'j')
1308 texture_draw(&img_bkgd_tile[1][c - 'g'], x, y);
1310 texture_draw(&img_solid[0], x, y);
1312 texture_draw(&img_solid[1], x, y);
1314 texture_draw(&img_solid[2], x, y);
1316 texture_draw(&img_solid[3], x, y);
1319 z = (global_frame_counter / 2) % 6;
1322 texture_draw(&img_distro[z], x, y);
1324 texture_draw(&img_distro[2], x, y);
1326 texture_draw(&img_distro[1], x, y);
1330 z = (global_frame_counter / 3) % 3;
1332 texture_draw(&img_waves[z], x, y);
1335 texture_draw(&img_poletop, x, y);
1338 texture_draw(&img_pole, x, y);
1343 z = (global_frame_counter / 3) % 2;
1345 texture_draw(&img_flag[z], x + 16, y);
1348 texture_draw(&img_water, x, y);
1352 /* What shape is at some position? */
1354 unsigned char shape(float x, float y)
1363 if (yy >= 0 && yy < 15 && xx >= 0 && xx <= current_level.width)
1365 c = current_level.tiles[yy][xx];
1376 bool issolid(float x, float y)
1378 return (isbrick(x, y) ||
1380 (shape(x, y) == '[') ||
1381 (shape(x, y) == '=') ||
1382 (shape(x, y) == ']') ||
1383 (shape(x, y) == 'A') ||
1384 (shape(x, y) == 'B') ||
1385 (shape(x, y) == '!') ||
1386 (shape(x, y) == 'a'));
1389 /* Is it a brick? */
1391 bool isbrick(float x, float y)
1393 return (shape(x, y) == 'X' ||
1394 shape(x, y) == 'x' ||
1395 shape(x, y) == 'Y' ||
1396 shape(x, y) == 'y');
1402 bool isice(float x, float y)
1404 return (shape(x, y) == '#');
1407 /* Is it a full box? */
1409 bool isfullbox(float x, float y)
1411 return (shape(x, y) == 'A' ||
1412 shape(x, y) == 'B' ||
1413 shape(x, y) == '!');
1416 /* Break a brick: */
1418 void trybreakbrick(float x, float y)
1422 if (shape(x, y) == 'x' || shape(x, y) == 'y')
1424 /* Get a distro from it: */
1426 add_bouncy_distro(((int)(x + 1) / 32) * 32,
1427 (int)(y / 32) * 32);
1429 if (!counting_distros)
1431 counting_distros = true;
1432 distro_counter = 50;
1435 if (distro_counter <= 0)
1436 level_change(¤t_level,x, y, 'a');
1438 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1439 score = score + SCORE_DISTRO;
1444 /* Get rid of it: */
1446 level_change(¤t_level,x, y,'.');
1450 /* Replace it with broken bits: */
1452 add_broken_brick(((int)(x + 1) / 32) * 32,
1453 (int)(y / 32) * 32);
1456 /* Get some score: */
1458 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
1459 score = score + SCORE_BRICK;
1464 /* Bounce a brick: */
1466 void bumpbrick(float x, float y)
1468 add_bouncy_brick(((int)(x + 1) / 32) * 32,
1469 (int)(y / 32) * 32);
1471 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
1478 void tryemptybox(float x, float y, int col_side)
1480 if (!isfullbox(x, y))
1483 // according to the collision side, set the upgrade direction
1485 if(col_side == LEFT)
1492 case 'A': /* Box with a distro! */
1493 add_bouncy_distro(((int)(x + 1) / 32) * 32, (int)(y / 32) * 32 - 32);
1494 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1495 score = score + SCORE_DISTRO;
1498 case 'B': /* Add an upgrade! */
1499 if (tux.size == SMALL) /* Tux is small, add mints! */
1500 add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_MINTS);
1501 else /* Tux is big, add coffee: */
1502 add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_COFFEE);
1503 play_sound(sounds[SND_UPGRADE], SOUND_CENTER_SPEAKER);
1505 case '!': /* Add a golden herring */
1506 add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_HERRING);
1512 /* Empty the box: */
1513 level_change(¤t_level,x, y, 'a');
1517 /* Try to grab a distro: */
1519 void trygrabdistro(float x, float y, int bounciness)
1521 if (shape(x, y) == '$')
1523 level_change(¤t_level,x, y, '.');
1524 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1526 if (bounciness == BOUNCE)
1528 add_bouncy_distro(((int)(x + 1) / 32) * 32,
1529 (int)(y / 32) * 32);
1532 score = score + SCORE_DISTRO;
1537 /* Try to bump a bad guy from below: */
1539 void trybumpbadguy(float x, float y)
1544 for (i = 0; i < bad_guys.size(); i++)
1546 if (bad_guys[i].base.x >= x - 32 && bad_guys[i].base.x <= x + 32 &&
1547 bad_guys[i].base.y >= y - 16 && bad_guys[i].base.y <= y + 16)
1549 if (bad_guys[i].kind == BAD_BSOD ||
1550 bad_guys[i].kind == BAD_LAPTOP)
1552 bad_guys[i].dying = DYING_FALLING;
1553 bad_guys[i].base.ym = -8;
1554 play_sound(sounds[SND_FALL], SOUND_CENTER_SPEAKER);
1561 for (i = 0; i < upgrades.size(); i++)
1563 if (upgrades[i].base.height == 32 &&
1564 upgrades[i].base.x >= x - 32 && upgrades[i].base.x <= x + 32 &&
1565 upgrades[i].base.y >= y - 16 && upgrades[i].base.y <= y + 16)
1567 upgrades[i].base.xm = -upgrades[i].base.xm;
1568 upgrades[i].base.ym = -8;
1569 play_sound(sounds[SND_BUMP_UPGRADE], SOUND_CENTER_SPEAKER);
1575 void drawstatus(void)
1579 sprintf(str, "%d", score);
1580 text_draw(&white_text, "SCORE", 0, 0, 1);
1581 text_draw(&gold_text, str, 96, 0, 1);
1583 if(st_gl_mode != ST_GL_TEST)
1585 sprintf(str, "%d", hs_score);
1586 text_draw(&white_text, "HIGH", 0, 20, 1);
1587 text_draw(&gold_text, str, 96, 20, 1);
1591 text_draw(&white_text,"Press ESC To Return",0,20,1);
1594 if (timer_get_left(&time_left) > TIME_WARNING || (global_frame_counter % 10) < 5)
1596 sprintf(str, "%d", timer_get_left(&time_left) / 1000 );
1597 text_draw(&white_text, "TIME", 224, 0, 1);
1598 text_draw(&gold_text, str, 304, 0, 1);
1601 sprintf(str, "%d", distros);
1602 text_draw(&white_text, "DISTROS", screen->h, 0, 1);
1603 text_draw(&gold_text, str, 608, 0, 1);
1605 text_draw(&white_text, "LIVES", screen->h, 20, 1);
1609 sprintf(str, "%2.1f", fps_fps);
1610 text_draw(&white_text, "FPS", screen->h, 40, 1);
1611 text_draw(&gold_text, str, screen->h + 60, 40, 1);
1614 for(int i=0; i < tux.lives; ++i)
1616 texture_draw(&tux_life,565+(18*i),20);
1621 void drawendscreen(void)
1625 clearscreen(0, 0, 0);
1627 text_drawf(&blue_text, "GAMEOVER", 0, 200, A_HMIDDLE, A_TOP, 1);
1629 sprintf(str, "SCORE: %d", score);
1630 text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1);
1632 sprintf(str, "DISTROS: %d", distros);
1633 text_drawf(&gold_text, str, 0, 256, A_HMIDDLE, A_TOP, 1);
1639 void drawresultscreen(void)
1643 clearscreen(0, 0, 0);
1645 text_drawf(&blue_text, "Result:", 0, 200, A_HMIDDLE, A_TOP, 1);
1647 sprintf(str, "SCORE: %d", score);
1648 text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1);
1650 sprintf(str, "DISTROS: %d", distros);
1651 text_drawf(&gold_text, str, 0, 256, A_HMIDDLE, A_TOP, 1);
1657 void savegame(int slot)
1659 char savefile[1024];
1663 sprintf(savefile,"%s/slot%d.save",st_save_dir,slot);
1665 fi = fopen(savefile, "wb");
1669 fprintf(stderr, "Warning: I could not open the slot file ");
1674 fputs(level_subset, fi);
1676 fwrite(&level,sizeof(int),1,fi);
1677 fwrite(&score,sizeof(int),1,fi);
1678 fwrite(&distros,sizeof(int),1,fi);
1679 fwrite(&scroll_x,sizeof(float),1,fi);
1680 fwrite(&tux,sizeof(Player),1,fi);
1681 timer_fwrite(&tux.invincible_timer,fi);
1682 timer_fwrite(&tux.skidding_timer,fi);
1683 timer_fwrite(&tux.safe_timer,fi);
1684 timer_fwrite(&tux.frame_timer,fi);
1685 timer_fwrite(&time_left,fi);
1686 ui = st_get_ticks();
1687 fwrite(&ui,sizeof(int),1,fi);
1693 void loadgame(int slot)
1695 char savefile[1024];
1700 sprintf(savefile,"%s/slot%d.save",st_save_dir,slot);
1702 fi = fopen(savefile, "rb");
1706 fprintf(stderr, "Warning: I could not open the slot file ");
1711 fgets(str, 100, fi);
1712 strcpy(level_subset, str);
1713 level_subset[strlen(level_subset)-1] = '\0';
1714 fread(&level,sizeof(int),1,fi);
1717 level_free(¤t_level);
1718 if(level_load(¤t_level,level_subset,level) != 0)
1722 activate_bad_guys();
1724 level_load_gfx(¤t_level);
1726 level_load_song(¤t_level);
1728 update_time = st_get_ticks();
1730 fread(&score,sizeof(int),1,fi);
1731 fread(&distros,sizeof(int),1,fi);
1732 fread(&scroll_x,sizeof(float),1,fi);
1733 fread(&tux, sizeof(Player), 1, fi);
1734 timer_fread(&tux.invincible_timer,fi);
1735 timer_fread(&tux.skidding_timer,fi);
1736 timer_fread(&tux.safe_timer,fi);
1737 timer_fread(&tux.frame_timer,fi);
1738 timer_fread(&time_left,fi);
1739 fread(&ui,sizeof(int),1,fi);
1740 tux.hphysic.start_time += st_get_ticks() - ui;
1741 tux.vphysic.start_time += st_get_ticks() - ui;
1747 void slotinfo(char **pinfo, int slot)
1750 char slotfile[1024];
1754 sprintf(slotfile,"%s/slot%d.save",st_save_dir,slot);
1756 fi = fopen(slotfile, "rb");
1758 sprintf(tmp,"Slot %d - ",slot);
1766 fgets(str, 100, fi);
1767 str[strlen(str)-1] = '\0';
1769 strcat(tmp, " / Level:");
1770 fread(&slot_level,sizeof(int),1,fi);
1771 sprintf(str,"%d",slot_level);
1776 *pinfo = (char*) malloc(sizeof(char) * (strlen(tmp)+1));