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! --- */
464 if (tux.dying && (global_frame_counter % 4) == 0)
465 clearscreen(255, 255, 255);
466 else if(timer_check(&super_bkgd_timer))
467 texture_draw(&img_super_bkgd, 0, 0);
470 /* Draw the real background */
471 if(current_level.bkgd_image[0] != '\0')
473 int s = (int)scroll_x / 30;
474 texture_draw_part(&img_bkgd,s,0,0,0,img_bkgd.w - s, img_bkgd.h);
475 texture_draw_part(&img_bkgd,0,0,screen->w - s ,0,s,img_bkgd.h);
479 clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue);
484 for (int y = 0; y < 15; ++y)
485 for (int x = 0; x < 21; ++x)
486 drawshape(32*x - fmodf(scroll_x, 32), y * 32,
487 current_level.tiles[y][x + (int)(scroll_x / 32)]);
489 for (unsigned int i = 0; i < bouncy_bricks.size(); ++i)
490 bouncy_brick_draw(&bouncy_bricks[i]);
492 for (unsigned int i = 0; i < bad_guys.size(); ++i)
497 for (unsigned int i = 0; i < bullets.size(); ++i)
498 bullet_draw(&bullets[i]);
500 for (unsigned int i = 0; i < floating_scores.size(); ++i)
501 floating_score_draw(&floating_scores[i]);
503 for (unsigned int i = 0; i < upgrades.size(); ++i)
504 upgrade_draw(&upgrades[i]);
506 for (unsigned int i = 0; i < bouncy_distros.size(); ++i)
507 bouncy_distro_draw(&bouncy_distros[i]);
509 for (unsigned int i = 0; i < broken_bricks.size(); ++i)
510 broken_brick_draw(&broken_bricks[i]);
516 int x = screen->h / 20;
517 for(int i = 0; i < x; ++i)
519 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);
521 fillrect(0,0,screen->w,screen->h,rand() % 50, rand() % 50, rand() % 50, 128);
522 text_drawf(&blue_text, "PAUSE - Press 'P' To Play", 0, 230, A_HMIDDLE, A_TOP, 1);
526 menu_process_current();
528 /* (Update it all!) */
535 /* --- GAME LOOP! --- */
537 int gameloop(const char * subset, int levelnb, int mode)
539 int fps_cnt, jump, done;
540 timer_type fps_timer, frame_timer;
541 timer_init(&fps_timer, true);
542 timer_init(&frame_timer, true);
553 strcpy(level_subset,subset);
555 if (st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
557 if (level_load(¤t_level, level_subset))
562 if(level_load(¤t_level, level_subset, level) != 0)
566 level_load_gfx(¤t_level);
568 level_load_song(¤t_level);
572 if(st_gl_mode != ST_GL_TEST)
577 if(st_gl_mode == ST_GL_PLAY || st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
580 timer_init(&time_left,true);
583 if(st_gl_mode == ST_GL_LOAD_GAME)
587 /* --- MAIN GAME LOOP!!! --- */
592 global_frame_counter = 0;
594 timer_init(&fps_timer,true);
595 timer_init(&frame_timer,true);
600 clearscreen(0, 0, 0);
604 play_current_music();
607 while (SDL_PollEvent(&event))
615 /* Calculate the movement-factor */
616 frame_ratio = ((double)(update_time-last_update_time))/((double)FRAME_RATE);
617 if(frame_ratio > 1.5) /* Quick hack to correct the unprecise CPU clocks a little bit. */
618 frame_ratio = 1.5 + (frame_ratio - 1.5) * 0.85;
620 if(!timer_check(&frame_timer))
622 timer_start(&frame_timer,25);
623 ++global_frame_counter;
628 tux.input_.old_fire = tux.input_.fire;
634 if(current_menu == game_menu)
636 switch (game_menu->check())
639 st_pause_ticks_stop();
642 update_load_save_game_menu(save_game_menu, false);
645 update_load_save_game_menu(load_game_menu, true);
648 st_pause_ticks_stop();
653 else if(current_menu == options_menu)
655 process_options_menu();
657 else if(current_menu == save_game_menu )
659 process_save_load_game_menu(true);
661 else if(current_menu == load_game_menu )
663 process_save_load_game_menu(false);
668 /* Handle actions: */
670 if(!game_pause && !show_menu)
672 /*float z = frame_ratio;
676 if (game_action() == 0)
678 /* == 0: no more lives */
679 /* == -1: continues */
691 if(debug_mode && debug_fps)
694 /*Draw the current scene to the screen */
695 /*If the machine running the game is too slow
696 skip the drawing of the frame (so the calculations are more precise and
697 the FPS aren't affected).*/
698 /*if( ! fps_fps < 50.0 )
701 jump = true;*/ /*FIXME: Implement this tweak right.*/
704 /* Time stops in pause mode */
705 if(game_pause || show_menu )
710 /* Set the time of the last update and the time of the current update */
711 last_update_time = update_time;
712 update_time = st_get_ticks();
715 /* Pause till next frame, if the machine running the game is too fast: */
716 /* FIXME: Works great for in OpenGl mode, where the CPU doesn't have to do that much. But
717 the results in SDL mode aren't perfect (thought the 100 FPS are reached), even on an AMD2500+. */
718 if(last_update_time >= update_time - 12 && !jump)
720 /*if((update_time - last_update_time) < 10)
721 SDL_Delay((11 - (update_time - last_update_time))/2);*/
727 if (timer_check(&time_left))
729 /* are we low on time ? */
730 if ((timer_get_left(&time_left) < TIME_WARNING)
731 && (get_current_music() != HURRYUP_MUSIC)) /* play the fast music */
733 set_current_music(HURRYUP_MUSIC);
734 play_current_music();
742 /* Calculate frames per second */
746 fps_fps = (1000.0 / (float)timer_get_gone(&fps_timer)) * (float)fps_cnt;
748 if(!timer_check(&fps_timer))
750 timer_start(&fps_timer,1000);
756 while (!done && !quit);
761 level_free(¤t_level);
766 game_started = false;
772 /* Load graphics/sounds shared between all levels: */
774 void loadshared(void)
779 texture_load(&tux_right[0], datadir + "/images/shared/tux-right-0.png", USE_ALPHA);
780 texture_load(&tux_right[1], datadir + "/images/shared/tux-right-1.png", USE_ALPHA);
781 texture_load(&tux_right[2], datadir + "/images/shared/tux-right-2.png", USE_ALPHA);
783 texture_load(&tux_left[0], datadir + "/images/shared/tux-left-0.png", USE_ALPHA);
784 texture_load(&tux_left[1], datadir + "/images/shared/tux-left-1.png", USE_ALPHA);
785 texture_load(&tux_left[2], datadir + "/images/shared/tux-left-2.png", USE_ALPHA);
787 texture_load(&firetux_right[0], datadir + "/images/shared/firetux-right-0.png", USE_ALPHA);
788 texture_load(&firetux_right[1], datadir + "/images/shared/firetux-right-1.png", USE_ALPHA);
789 texture_load(&firetux_right[2], datadir + "/images/shared/firetux-right-2.png", USE_ALPHA);
791 texture_load(&firetux_left[0], datadir + "/images/shared/firetux-left-0.png", USE_ALPHA);
792 texture_load(&firetux_left[1], datadir + "/images/shared/firetux-left-1.png", USE_ALPHA);
793 texture_load(&firetux_left[2], datadir + "/images/shared/firetux-left-2.png", USE_ALPHA);
796 texture_load(&cape_right[0], datadir + "/images/shared/cape-right-0.png",
799 texture_load(&cape_right[1], datadir + "/images/shared/cape-right-1.png",
802 texture_load(&cape_left[0], datadir + "/images/shared/cape-left-0.png",
805 texture_load(&cape_left[1], datadir + "/images/shared/cape-left-1.png",
808 texture_load(&bigtux_right[0], datadir + "/images/shared/bigtux-right-0.png",
811 texture_load(&bigtux_right[1], datadir + "/images/shared/bigtux-right-1.png",
814 texture_load(&bigtux_right[2], datadir + "/images/shared/bigtux-right-2.png",
817 texture_load(&bigtux_right_jump, datadir + "/images/shared/bigtux-right-jump.png", USE_ALPHA);
819 texture_load(&bigtux_left[0], datadir + "/images/shared/bigtux-left-0.png",
822 texture_load(&bigtux_left[1], datadir + "/images/shared/bigtux-left-1.png",
825 texture_load(&bigtux_left[2], datadir + "/images/shared/bigtux-left-2.png",
828 texture_load(&bigtux_left_jump, datadir + "/images/shared/bigtux-left-jump.png", USE_ALPHA);
830 texture_load(&bigcape_right[0], datadir + "/images/shared/bigcape-right-0.png",
833 texture_load(&bigcape_right[1], datadir + "/images/shared/bigcape-right-1.png",
836 texture_load(&bigcape_left[0], datadir + "/images/shared/bigcape-left-0.png",
839 texture_load(&bigcape_left[1], datadir + "/images/shared/bigcape-left-1.png",
842 texture_load(&bigfiretux_right[0], datadir + "/images/shared/bigfiretux-right-0.png",
845 texture_load(&bigfiretux_right[1], datadir + "/images/shared/bigfiretux-right-1.png",
848 texture_load(&bigfiretux_right[2], datadir + "/images/shared/bigfiretux-right-2.png",
851 texture_load(&bigfiretux_right_jump, datadir + "/images/shared/bigfiretux-right-jump.png", USE_ALPHA);
853 texture_load(&bigfiretux_left[0], datadir + "/images/shared/bigfiretux-left-0.png",
856 texture_load(&bigfiretux_left[1], datadir + "/images/shared/bigfiretux-left-1.png",
859 texture_load(&bigfiretux_left[2], datadir + "/images/shared/bigfiretux-left-2.png",
862 texture_load(&bigfiretux_left_jump, datadir + "/images/shared/bigfiretux-left-jump.png", USE_ALPHA);
864 texture_load(&bigcape_right[0], datadir + "/images/shared/bigcape-right-0.png",
867 texture_load(&bigcape_right[1], datadir + "/images/shared/bigcape-right-1.png",
870 texture_load(&bigcape_left[0], datadir + "/images/shared/bigcape-left-0.png",
873 texture_load(&bigcape_left[1], datadir + "/images/shared/bigcape-left-1.png",
877 texture_load(&ducktux_right, datadir +
878 "/images/shared/ducktux-right.png",
881 texture_load(&ducktux_left, datadir +
882 "/images/shared/ducktux-left.png",
885 texture_load(&skidtux_right, datadir +
886 "/images/shared/skidtux-right.png",
889 texture_load(&skidtux_left, datadir +
890 "/images/shared/skidtux-left.png",
893 texture_load(&duckfiretux_right, datadir +
894 "/images/shared/duckfiretux-right.png",
897 texture_load(&duckfiretux_left, datadir +
898 "/images/shared/duckfiretux-left.png",
901 texture_load(&skidfiretux_right, datadir +
902 "/images/shared/skidfiretux-right.png",
905 texture_load(&skidfiretux_left, datadir +
906 "/images/shared/skidfiretux-left.png",
912 texture_load(&img_box_full, datadir + "/images/shared/box-full.png",
914 texture_load(&img_box_empty, datadir + "/images/shared/box-empty.png",
921 texture_load(&img_water, datadir + "/images/shared/water.png", IGNORE_ALPHA);
923 texture_load(&img_waves[0], datadir + "/images/shared/waves-0.png",
926 texture_load(&img_waves[1], datadir + "/images/shared/waves-1.png",
929 texture_load(&img_waves[2], datadir + "/images/shared/waves-2.png",
935 texture_load(&img_pole, datadir + "/images/shared/pole.png", USE_ALPHA);
936 texture_load(&img_poletop, datadir + "/images/shared/poletop.png",
942 texture_load(&img_flag[0], datadir + "/images/shared/flag-0.png",
944 texture_load(&img_flag[1], datadir + "/images/shared/flag-1.png",
950 texture_load(&img_cloud[0][0], datadir + "/images/shared/cloud-00.png",
953 texture_load(&img_cloud[0][1], datadir + "/images/shared/cloud-01.png",
956 texture_load(&img_cloud[0][2], datadir + "/images/shared/cloud-02.png",
959 texture_load(&img_cloud[0][3], datadir + "/images/shared/cloud-03.png",
963 texture_load(&img_cloud[1][0], datadir + "/images/shared/cloud-10.png",
966 texture_load(&img_cloud[1][1], datadir + "/images/shared/cloud-11.png",
969 texture_load(&img_cloud[1][2], datadir + "/images/shared/cloud-12.png",
972 texture_load(&img_cloud[1][3], datadir + "/images/shared/cloud-13.png",
980 texture_load(&img_bsod_left[0], datadir +
981 "/images/shared/bsod-left-0.png",
984 texture_load(&img_bsod_left[1], datadir +
985 "/images/shared/bsod-left-1.png",
988 texture_load(&img_bsod_left[2], datadir +
989 "/images/shared/bsod-left-2.png",
992 texture_load(&img_bsod_left[3], datadir +
993 "/images/shared/bsod-left-3.png",
996 texture_load(&img_bsod_right[0], datadir +
997 "/images/shared/bsod-right-0.png",
1000 texture_load(&img_bsod_right[1], datadir +
1001 "/images/shared/bsod-right-1.png",
1004 texture_load(&img_bsod_right[2], datadir +
1005 "/images/shared/bsod-right-2.png",
1008 texture_load(&img_bsod_right[3], datadir +
1009 "/images/shared/bsod-right-3.png",
1012 texture_load(&img_bsod_squished_left, datadir +
1013 "/images/shared/bsod-squished-left.png",
1016 texture_load(&img_bsod_squished_right, datadir +
1017 "/images/shared/bsod-squished-right.png",
1020 texture_load(&img_bsod_falling_left, datadir +
1021 "/images/shared/bsod-falling-left.png",
1024 texture_load(&img_bsod_falling_right, datadir +
1025 "/images/shared/bsod-falling-right.png",
1031 texture_load(&img_laptop_left[0], datadir +
1032 "/images/shared/laptop-left-0.png",
1035 texture_load(&img_laptop_left[1], datadir +
1036 "/images/shared/laptop-left-1.png",
1039 texture_load(&img_laptop_left[2], datadir +
1040 "/images/shared/laptop-left-2.png",
1043 texture_load(&img_laptop_right[0], datadir +
1044 "/images/shared/laptop-right-0.png",
1047 texture_load(&img_laptop_right[1], datadir +
1048 "/images/shared/laptop-right-1.png",
1051 texture_load(&img_laptop_right[2], datadir +
1052 "/images/shared/laptop-right-2.png",
1055 texture_load(&img_laptop_flat_left, datadir +
1056 "/images/shared/laptop-flat-left.png",
1059 texture_load(&img_laptop_flat_right, datadir +
1060 "/images/shared/laptop-flat-right.png",
1063 texture_load(&img_laptop_falling_left, datadir +
1064 "/images/shared/laptop-falling-left.png",
1067 texture_load(&img_laptop_falling_right, datadir +
1068 "/images/shared/laptop-falling-right.png",
1074 texture_load(&img_money_left[0], datadir +
1075 "/images/shared/bag-left-0.png",
1078 texture_load(&img_money_left[1], datadir +
1079 "/images/shared/bag-left-1.png",
1082 texture_load(&img_money_right[0], datadir +
1083 "/images/shared/bag-right-0.png",
1086 texture_load(&img_money_right[1], datadir +
1087 "/images/shared/bag-right-1.png",
1094 texture_load(&img_mints, datadir + "/images/shared/mints.png", USE_ALPHA);
1095 texture_load(&img_coffee, datadir + "/images/shared/coffee.png", USE_ALPHA);
1100 texture_load(&img_bullet, datadir + "/images/shared/bullet.png", USE_ALPHA);
1102 texture_load(&img_red_glow, datadir + "/images/shared/red-glow.png",
1109 texture_load(&img_distro[0], datadir + "/images/shared/distro-0.png",
1112 texture_load(&img_distro[1], datadir + "/images/shared/distro-1.png",
1115 texture_load(&img_distro[2], datadir + "/images/shared/distro-2.png",
1118 texture_load(&img_distro[3], datadir + "/images/shared/distro-3.png",
1124 texture_load(&tux_life, datadir + "/images/shared/tux-life.png",
1129 texture_load(&img_golden_herring, datadir + "/images/shared/golden-herring.png",
1133 /* Super background: */
1135 texture_load(&img_super_bkgd, datadir + "/images/shared/super-bkgd.png",
1139 /* Sound effects: */
1141 /* if (use_sound) // this will introduce SERIOUS bugs here ! because "load_sound"
1142 // initialize sounds[i] with the correct pointer's value:
1143 // NULL or something else. And it will be dangerous to
1144 // play with not-initialized pointers.
1145 // This is also true with if (use_music)
1146 Send a mail to me: neoneurone@users.sf.net, if you have another opinion. :)
1148 for (i = 0; i < NUM_SOUNDS; i++)
1149 sounds[i] = load_sound(datadir + soundfilenames[i]);
1152 herring_song = load_song(datadir + "/music/SALCON.MOD");
1156 /* Free shared data: */
1158 void unloadshared(void)
1162 for (i = 0; i < 3; i++)
1164 texture_free(&tux_right[i]);
1165 texture_free(&tux_left[i]);
1166 texture_free(&bigtux_right[i]);
1167 texture_free(&bigtux_left[i]);
1170 texture_free(&bigtux_right_jump);
1171 texture_free(&bigtux_left_jump);
1173 for (i = 0; i < 2; i++)
1175 texture_free(&cape_right[i]);
1176 texture_free(&cape_left[i]);
1177 texture_free(&bigcape_right[i]);
1178 texture_free(&bigcape_left[i]);
1181 texture_free(&ducktux_left);
1182 texture_free(&ducktux_right);
1184 texture_free(&skidtux_left);
1185 texture_free(&skidtux_right);
1187 for (i = 0; i < 4; i++)
1189 texture_free(&img_bsod_left[i]);
1190 texture_free(&img_bsod_right[i]);
1193 texture_free(&img_bsod_squished_left);
1194 texture_free(&img_bsod_squished_right);
1196 texture_free(&img_bsod_falling_left);
1197 texture_free(&img_bsod_falling_right);
1199 for (i = 0; i < 3; i++)
1201 texture_free(&img_laptop_left[i]);
1202 texture_free(&img_laptop_right[i]);
1205 texture_free(&img_laptop_flat_left);
1206 texture_free(&img_laptop_flat_right);
1208 texture_free(&img_laptop_falling_left);
1209 texture_free(&img_laptop_falling_right);
1211 for (i = 0; i < 2; i++)
1213 texture_free(&img_money_left[i]);
1214 texture_free(&img_money_right[i]);
1217 texture_free(&img_box_full);
1218 texture_free(&img_box_empty);
1220 texture_free(&img_water);
1221 for (i = 0; i < 3; i++)
1222 texture_free(&img_waves[i]);
1224 texture_free(&img_pole);
1225 texture_free(&img_poletop);
1227 for (i = 0; i < 2; i++)
1228 texture_free(&img_flag[i]);
1230 texture_free(&img_mints);
1231 texture_free(&img_coffee);
1233 for (i = 0; i < 4; i++)
1235 texture_free(&img_distro[i]);
1236 texture_free(&img_cloud[0][i]);
1237 texture_free(&img_cloud[1][i]);
1240 texture_free(&img_golden_herring);
1242 for (i = 0; i < NUM_SOUNDS; i++)
1243 free_chunk(sounds[i]);
1245 /* free the herring song */
1246 free_music( herring_song );
1250 /* Draw a tile on the screen: */
1252 void drawshape(float x, float y, unsigned char c)
1256 if (c == 'X' || c == 'x')
1257 texture_draw(&img_brick[0], x, y);
1258 else if (c == 'Y' || c == 'y')
1259 texture_draw(&img_brick[1], x, y);
1260 else if (c == 'A' || c =='B' || c == '!')
1261 texture_draw(&img_box_full, x, y);
1263 texture_draw(&img_box_empty, x, y);
1264 else if (c >= 'C' && c <= 'F')
1265 texture_draw(&img_cloud[0][c - 'C'], x, y);
1266 else if (c >= 'c' && c <= 'f')
1267 texture_draw(&img_cloud[1][c - 'c'], x, y);
1268 else if (c >= 'G' && c <= 'J')
1269 texture_draw(&img_bkgd_tile[0][c - 'G'], x, y);
1270 else if (c >= 'g' && c <= 'j')
1271 texture_draw(&img_bkgd_tile[1][c - 'g'], x, y);
1273 texture_draw(&img_solid[0], x, y);
1275 texture_draw(&img_solid[1], x, y);
1277 texture_draw(&img_solid[2], x, y);
1279 texture_draw(&img_solid[3], x, y);
1282 z = (global_frame_counter / 2) % 6;
1285 texture_draw(&img_distro[z], x, y);
1287 texture_draw(&img_distro[2], x, y);
1289 texture_draw(&img_distro[1], x, y);
1293 z = (global_frame_counter / 3) % 3;
1295 texture_draw(&img_waves[z], x, y);
1298 texture_draw(&img_poletop, x, y);
1301 texture_draw(&img_pole, x, y);
1306 z = (global_frame_counter / 3) % 2;
1308 texture_draw(&img_flag[z], x + 16, y);
1311 texture_draw(&img_water, x, y);
1315 /* What shape is at some position? */
1317 unsigned char shape(float x, float y)
1326 if (yy >= 0 && yy < 15 && xx >= 0 && xx <= current_level.width)
1328 c = current_level.tiles[yy][xx];
1339 bool issolid(float x, float y)
1341 return (isbrick(x, y) ||
1343 (shape(x, y) == '[') ||
1344 (shape(x, y) == '=') ||
1345 (shape(x, y) == ']') ||
1346 (shape(x, y) == 'A') ||
1347 (shape(x, y) == 'B') ||
1348 (shape(x, y) == '!') ||
1349 (shape(x, y) == 'a'));
1352 /* Is it a brick? */
1354 bool isbrick(float x, float y)
1356 return (shape(x, y) == 'X' ||
1357 shape(x, y) == 'x' ||
1358 shape(x, y) == 'Y' ||
1359 shape(x, y) == 'y');
1365 bool isice(float x, float y)
1367 return (shape(x, y) == '#');
1370 /* Is it a full box? */
1372 bool isfullbox(float x, float y)
1374 return (shape(x, y) == 'A' ||
1375 shape(x, y) == 'B' ||
1376 shape(x, y) == '!');
1379 /* Break a brick: */
1381 void trybreakbrick(float x, float y)
1385 if (shape(x, y) == 'x' || shape(x, y) == 'y')
1387 /* Get a distro from it: */
1389 add_bouncy_distro(((int)(x + 1) / 32) * 32,
1390 (int)(y / 32) * 32);
1392 if (!counting_distros)
1394 counting_distros = true;
1395 distro_counter = 50;
1398 if (distro_counter <= 0)
1399 level_change(¤t_level,x, y, 'a');
1401 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1402 score = score + SCORE_DISTRO;
1407 /* Get rid of it: */
1409 level_change(¤t_level,x, y,'.');
1413 /* Replace it with broken bits: */
1415 add_broken_brick(((int)(x + 1) / 32) * 32,
1416 (int)(y / 32) * 32);
1419 /* Get some score: */
1421 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
1422 score = score + SCORE_BRICK;
1427 /* Bounce a brick: */
1429 void bumpbrick(float x, float y)
1431 add_bouncy_brick(((int)(x + 1) / 32) * 32,
1432 (int)(y / 32) * 32);
1434 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
1441 void tryemptybox(float x, float y, int col_side)
1443 if (!isfullbox(x, y))
1446 // according to the collision side, set the upgrade direction
1448 if(col_side == LEFT)
1455 case 'A': /* Box with a distro! */
1456 add_bouncy_distro(((int)(x + 1) / 32) * 32, (int)(y / 32) * 32 - 32);
1457 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1458 score = score + SCORE_DISTRO;
1461 case 'B': /* Add an upgrade! */
1462 if (tux.size == SMALL) /* Tux is small, add mints! */
1463 add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_MINTS);
1464 else /* Tux is big, add coffee: */
1465 add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_COFFEE);
1466 play_sound(sounds[SND_UPGRADE], SOUND_CENTER_SPEAKER);
1468 case '!': /* Add a golden herring */
1469 add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_HERRING);
1475 /* Empty the box: */
1476 level_change(¤t_level,x, y, 'a');
1480 /* Try to grab a distro: */
1482 void trygrabdistro(float x, float y, int bounciness)
1484 if (shape(x, y) == '$')
1486 level_change(¤t_level,x, y, '.');
1487 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1489 if (bounciness == BOUNCE)
1491 add_bouncy_distro(((int)(x + 1) / 32) * 32,
1492 (int)(y / 32) * 32);
1495 score = score + SCORE_DISTRO;
1500 /* Try to bump a bad guy from below: */
1502 void trybumpbadguy(float x, float y)
1507 for (i = 0; i < bad_guys.size(); i++)
1509 if (bad_guys[i].base.x >= x - 32 && bad_guys[i].base.x <= x + 32 &&
1510 bad_guys[i].base.y >= y - 16 && bad_guys[i].base.y <= y + 16)
1512 if (bad_guys[i].kind == BAD_BSOD ||
1513 bad_guys[i].kind == BAD_LAPTOP)
1515 bad_guys[i].dying = DYING_FALLING;
1516 bad_guys[i].base.ym = -8;
1517 play_sound(sounds[SND_FALL], SOUND_CENTER_SPEAKER);
1524 for (i = 0; i < upgrades.size(); i++)
1526 if (upgrades[i].base.height == 32 &&
1527 upgrades[i].base.x >= x - 32 && upgrades[i].base.x <= x + 32 &&
1528 upgrades[i].base.y >= y - 16 && upgrades[i].base.y <= y + 16)
1530 upgrades[i].base.xm = -upgrades[i].base.xm;
1531 upgrades[i].base.ym = -8;
1532 play_sound(sounds[SND_BUMP_UPGRADE], SOUND_CENTER_SPEAKER);
1538 void drawstatus(void)
1542 sprintf(str, "%d", score);
1543 text_draw(&white_text, "SCORE", 0, 0, 1);
1544 text_draw(&gold_text, str, 96, 0, 1);
1546 if(st_gl_mode != ST_GL_TEST)
1548 sprintf(str, "%d", hs_score);
1549 text_draw(&white_text, "HIGH", 0, 20, 1);
1550 text_draw(&gold_text, str, 96, 20, 1);
1554 text_draw(&white_text,"Press ESC To Return",0,20,1);
1557 if (timer_get_left(&time_left) > TIME_WARNING || (global_frame_counter % 10) < 5)
1559 sprintf(str, "%d", timer_get_left(&time_left) / 1000 );
1560 text_draw(&white_text, "TIME", 224, 0, 1);
1561 text_draw(&gold_text, str, 304, 0, 1);
1564 sprintf(str, "%d", distros);
1565 text_draw(&white_text, "DISTROS", screen->h, 0, 1);
1566 text_draw(&gold_text, str, 608, 0, 1);
1568 text_draw(&white_text, "LIVES", screen->h, 20, 1);
1572 sprintf(str, "%2.1f", fps_fps);
1573 text_draw(&white_text, "FPS", screen->h, 40, 1);
1574 text_draw(&gold_text, str, screen->h + 60, 40, 1);
1577 for(int i=0; i < tux.lives; ++i)
1579 texture_draw(&tux_life,565+(18*i),20);
1584 void drawendscreen(void)
1588 clearscreen(0, 0, 0);
1590 text_drawf(&blue_text, "GAMEOVER", 0, 200, A_HMIDDLE, A_TOP, 1);
1592 sprintf(str, "SCORE: %d", score);
1593 text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1);
1595 sprintf(str, "DISTROS: %d", distros);
1596 text_drawf(&gold_text, str, 0, 256, A_HMIDDLE, A_TOP, 1);
1602 void drawresultscreen(void)
1606 clearscreen(0, 0, 0);
1608 text_drawf(&blue_text, "Result:", 0, 200, A_HMIDDLE, A_TOP, 1);
1610 sprintf(str, "SCORE: %d", score);
1611 text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1);
1613 sprintf(str, "DISTROS: %d", distros);
1614 text_drawf(&gold_text, str, 0, 256, A_HMIDDLE, A_TOP, 1);
1620 void savegame(int slot)
1622 char savefile[1024];
1626 sprintf(savefile,"%s/slot%d.save",st_save_dir,slot);
1628 fi = fopen(savefile, "wb");
1632 fprintf(stderr, "Warning: I could not open the slot file ");
1637 fputs(level_subset, fi);
1639 fwrite(&level,sizeof(int),1,fi);
1640 fwrite(&score,sizeof(int),1,fi);
1641 fwrite(&distros,sizeof(int),1,fi);
1642 fwrite(&scroll_x,sizeof(float),1,fi);
1643 fwrite(&tux,sizeof(Player),1,fi);
1644 timer_fwrite(&tux.invincible_timer,fi);
1645 timer_fwrite(&tux.skidding_timer,fi);
1646 timer_fwrite(&tux.safe_timer,fi);
1647 timer_fwrite(&tux.frame_timer,fi);
1648 timer_fwrite(&time_left,fi);
1649 ui = st_get_ticks();
1650 fwrite(&ui,sizeof(int),1,fi);
1656 void loadgame(int slot)
1658 char savefile[1024];
1663 sprintf(savefile,"%s/slot%d.save",st_save_dir,slot);
1665 fi = fopen(savefile, "rb");
1669 fprintf(stderr, "Warning: I could not open the slot file ");
1674 fgets(str, 100, fi);
1675 strcpy(level_subset, str);
1676 level_subset[strlen(level_subset)-1] = '\0';
1677 fread(&level,sizeof(int),1,fi);
1680 level_free(¤t_level);
1681 if(level_load(¤t_level,level_subset,level) != 0)
1685 activate_bad_guys();
1687 level_load_gfx(¤t_level);
1689 level_load_song(¤t_level);
1691 update_time = st_get_ticks();
1693 fread(&score,sizeof(int),1,fi);
1694 fread(&distros,sizeof(int),1,fi);
1695 fread(&scroll_x,sizeof(float),1,fi);
1696 fread(&tux, sizeof(Player), 1, fi);
1697 timer_fread(&tux.invincible_timer,fi);
1698 timer_fread(&tux.skidding_timer,fi);
1699 timer_fread(&tux.safe_timer,fi);
1700 timer_fread(&tux.frame_timer,fi);
1701 timer_fread(&time_left,fi);
1702 fread(&ui,sizeof(int),1,fi);
1703 tux.hphysic.start_time += st_get_ticks() - ui;
1704 tux.vphysic.start_time += st_get_ticks() - ui;
1710 void slotinfo(char **pinfo, int slot)
1713 char slotfile[1024];
1717 sprintf(slotfile,"%s/slot%d.save",st_save_dir,slot);
1719 fi = fopen(slotfile, "rb");
1721 sprintf(tmp,"Slot %d - ",slot);
1729 fgets(str, 100, fi);
1730 str[strlen(str)-1] = '\0';
1732 strcat(tmp, " / Level:");
1733 fread(&slot_level,sizeof(int),1,fi);
1734 sprintf(str,"%d",slot_level);
1739 *pinfo = (char*) malloc(sizeof(char) * (strlen(tmp)+1));