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)
486 for (int x = 0; x < 21; ++x)
488 drawshape(32*x - fmodf(scroll_x, 32), y * 32,
489 current_level.tiles[(int)y][(int)x + (int)(scroll_x / 32)]);
493 for (unsigned int i = 0; i < bouncy_bricks.size(); ++i)
494 bouncy_brick_draw(&bouncy_bricks[i]);
496 for (unsigned int i = 0; i < bad_guys.size(); ++i)
501 for (unsigned int i = 0; i < bullets.size(); ++i)
502 bullet_draw(&bullets[i]);
504 for (unsigned int i = 0; i < floating_scores.size(); ++i)
505 floating_score_draw(&floating_scores[i]);
507 for (unsigned int i = 0; i < upgrades.size(); ++i)
508 upgrade_draw(&upgrades[i]);
510 for (unsigned int i = 0; i < bouncy_distros.size(); ++i)
511 bouncy_distro_draw(&bouncy_distros[i]);
513 for (unsigned int i = 0; i < broken_bricks.size(); ++i)
514 broken_brick_draw(&broken_bricks[i]);
520 int x = screen->h / 20;
521 for(int i = 0; i < x; ++i)
523 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);
525 fillrect(0,0,screen->w,screen->h,rand() % 50, rand() % 50, rand() % 50, 128);
526 text_drawf(&blue_text, "PAUSE - Press 'P' To Play", 0, 230, A_HMIDDLE, A_TOP, 1);
530 menu_process_current();
532 /* (Update it all!) */
539 /* --- GAME LOOP! --- */
541 int gameloop(const char * subset, int levelnb, int mode)
543 int fps_cnt, jump, done;
544 timer_type fps_timer, frame_timer;
545 timer_init(&fps_timer, true);
546 timer_init(&frame_timer, true);
557 strcpy(level_subset,subset);
559 if (st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
561 if (level_load(¤t_level, level_subset))
566 if(level_load(¤t_level, level_subset, level) != 0)
570 level_load_gfx(¤t_level);
572 level_load_song(¤t_level);
576 if(st_gl_mode != ST_GL_TEST)
581 if(st_gl_mode == ST_GL_PLAY || st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
584 timer_init(&time_left,true);
587 if(st_gl_mode == ST_GL_LOAD_GAME)
591 /* --- MAIN GAME LOOP!!! --- */
596 global_frame_counter = 0;
598 timer_init(&fps_timer,true);
599 timer_init(&frame_timer,true);
604 clearscreen(0, 0, 0);
608 play_current_music();
611 while (SDL_PollEvent(&event))
619 /* Calculate the movement-factor */
620 frame_ratio = ((double)(update_time-last_update_time))/((double)FRAME_RATE);
621 if(frame_ratio > 1.5) /* Quick hack to correct the unprecise CPU clocks a little bit. */
622 frame_ratio = 1.5 + (frame_ratio - 1.5) * 0.85;
624 if(!timer_check(&frame_timer))
626 timer_start(&frame_timer,25);
627 ++global_frame_counter;
632 tux.input_.old_fire = tux.input_.fire;
638 if(current_menu == game_menu)
640 switch (game_menu->check())
643 st_pause_ticks_stop();
646 update_load_save_game_menu(save_game_menu, false);
649 update_load_save_game_menu(load_game_menu, true);
652 st_pause_ticks_stop();
657 else if(current_menu == options_menu)
659 process_options_menu();
661 else if(current_menu == save_game_menu )
663 process_save_load_game_menu(true);
665 else if(current_menu == load_game_menu )
667 process_save_load_game_menu(false);
672 /* Handle actions: */
674 if(!game_pause && !show_menu)
676 /*float z = frame_ratio;
680 if (game_action() == 0)
682 /* == 0: no more lives */
683 /* == -1: continues */
695 if(debug_mode && debug_fps == true)
698 /*Draw the current scene to the screen */
699 /*If the machine running the game is too slow
700 skip the drawing of the frame (so the calculations are more precise and
701 the FPS aren't affected).*/
702 /*if( ! fps_fps < 50.0 )
705 jump = true;*/ /*FIXME: Implement this tweak right.*/
708 /* Time stops in pause mode */
709 if(game_pause || show_menu )
714 /* Set the time of the last update and the time of the current update */
715 last_update_time = update_time;
716 update_time = st_get_ticks();
719 /* Pause till next frame, if the machine running the game is too fast: */
720 /* FIXME: Works great for in OpenGl mode, where the CPU doesn't have to do that much. But
721 the results in SDL mode aren't perfect (thought the 100 FPS are reached), even on an AMD2500+. */
722 if(last_update_time >= update_time - 12 && !jump)
724 /*if((update_time - last_update_time) < 10)
725 SDL_Delay((11 - (update_time - last_update_time))/2);*/
731 if (timer_check(&time_left))
733 /* are we low on time ? */
734 if ((timer_get_left(&time_left) < TIME_WARNING)
735 && (get_current_music() != HURRYUP_MUSIC)) /* play the fast music */
737 set_current_music(HURRYUP_MUSIC);
738 play_current_music();
746 /* Calculate frames per second */
750 fps_fps = (1000.0 / (float)timer_get_gone(&fps_timer)) * (float)fps_cnt;
752 if(!timer_check(&fps_timer))
754 timer_start(&fps_timer,1000);
760 while (!done && !quit);
765 level_free(¤t_level);
770 game_started = false;
776 /* Load graphics/sounds shared between all levels: */
778 void loadshared(void)
783 texture_load(&tux_right[0], datadir + "/images/shared/tux-right-0.png", USE_ALPHA);
784 texture_load(&tux_right[1], datadir + "/images/shared/tux-right-1.png", USE_ALPHA);
785 texture_load(&tux_right[2], datadir + "/images/shared/tux-right-2.png", USE_ALPHA);
787 texture_load(&tux_left[0], datadir + "/images/shared/tux-left-0.png", USE_ALPHA);
788 texture_load(&tux_left[1], datadir + "/images/shared/tux-left-1.png", USE_ALPHA);
789 texture_load(&tux_left[2], datadir + "/images/shared/tux-left-2.png", USE_ALPHA);
791 texture_load(&firetux_right[0], datadir + "/images/shared/firetux-right-0.png", USE_ALPHA);
792 texture_load(&firetux_right[1], datadir + "/images/shared/firetux-right-1.png", USE_ALPHA);
793 texture_load(&firetux_right[2], datadir + "/images/shared/firetux-right-2.png", USE_ALPHA);
795 texture_load(&firetux_left[0], datadir + "/images/shared/firetux-left-0.png", USE_ALPHA);
796 texture_load(&firetux_left[1], datadir + "/images/shared/firetux-left-1.png", USE_ALPHA);
797 texture_load(&firetux_left[2], datadir + "/images/shared/firetux-left-2.png", USE_ALPHA);
800 texture_load(&cape_right[0], datadir + "/images/shared/cape-right-0.png",
803 texture_load(&cape_right[1], datadir + "/images/shared/cape-right-1.png",
806 texture_load(&cape_left[0], datadir + "/images/shared/cape-left-0.png",
809 texture_load(&cape_left[1], datadir + "/images/shared/cape-left-1.png",
812 texture_load(&bigtux_right[0], datadir + "/images/shared/bigtux-right-0.png",
815 texture_load(&bigtux_right[1], datadir + "/images/shared/bigtux-right-1.png",
818 texture_load(&bigtux_right[2], datadir + "/images/shared/bigtux-right-2.png",
821 texture_load(&bigtux_right_jump, datadir + "/images/shared/bigtux-right-jump.png", USE_ALPHA);
823 texture_load(&bigtux_left[0], datadir + "/images/shared/bigtux-left-0.png",
826 texture_load(&bigtux_left[1], datadir + "/images/shared/bigtux-left-1.png",
829 texture_load(&bigtux_left[2], datadir + "/images/shared/bigtux-left-2.png",
832 texture_load(&bigtux_left_jump, datadir + "/images/shared/bigtux-left-jump.png", USE_ALPHA);
834 texture_load(&bigcape_right[0], datadir + "/images/shared/bigcape-right-0.png",
837 texture_load(&bigcape_right[1], datadir + "/images/shared/bigcape-right-1.png",
840 texture_load(&bigcape_left[0], datadir + "/images/shared/bigcape-left-0.png",
843 texture_load(&bigcape_left[1], datadir + "/images/shared/bigcape-left-1.png",
846 texture_load(&bigfiretux_right[0], datadir + "/images/shared/bigfiretux-right-0.png",
849 texture_load(&bigfiretux_right[1], datadir + "/images/shared/bigfiretux-right-1.png",
852 texture_load(&bigfiretux_right[2], datadir + "/images/shared/bigfiretux-right-2.png",
855 texture_load(&bigfiretux_right_jump, datadir + "/images/shared/bigfiretux-right-jump.png", USE_ALPHA);
857 texture_load(&bigfiretux_left[0], datadir + "/images/shared/bigfiretux-left-0.png",
860 texture_load(&bigfiretux_left[1], datadir + "/images/shared/bigfiretux-left-1.png",
863 texture_load(&bigfiretux_left[2], datadir + "/images/shared/bigfiretux-left-2.png",
866 texture_load(&bigfiretux_left_jump, datadir + "/images/shared/bigfiretux-left-jump.png", USE_ALPHA);
868 texture_load(&bigcape_right[0], datadir + "/images/shared/bigcape-right-0.png",
871 texture_load(&bigcape_right[1], datadir + "/images/shared/bigcape-right-1.png",
874 texture_load(&bigcape_left[0], datadir + "/images/shared/bigcape-left-0.png",
877 texture_load(&bigcape_left[1], datadir + "/images/shared/bigcape-left-1.png",
881 texture_load(&ducktux_right, datadir +
882 "/images/shared/ducktux-right.png",
885 texture_load(&ducktux_left, datadir +
886 "/images/shared/ducktux-left.png",
889 texture_load(&skidtux_right, datadir +
890 "/images/shared/skidtux-right.png",
893 texture_load(&skidtux_left, datadir +
894 "/images/shared/skidtux-left.png",
897 texture_load(&duckfiretux_right, datadir +
898 "/images/shared/duckfiretux-right.png",
901 texture_load(&duckfiretux_left, datadir +
902 "/images/shared/duckfiretux-left.png",
905 texture_load(&skidfiretux_right, datadir +
906 "/images/shared/skidfiretux-right.png",
909 texture_load(&skidfiretux_left, datadir +
910 "/images/shared/skidfiretux-left.png",
916 texture_load(&img_box_full, datadir + "/images/shared/box-full.png",
918 texture_load(&img_box_empty, datadir + "/images/shared/box-empty.png",
925 texture_load(&img_water, datadir + "/images/shared/water.png", IGNORE_ALPHA);
927 texture_load(&img_waves[0], datadir + "/images/shared/waves-0.png",
930 texture_load(&img_waves[1], datadir + "/images/shared/waves-1.png",
933 texture_load(&img_waves[2], datadir + "/images/shared/waves-2.png",
939 texture_load(&img_pole, datadir + "/images/shared/pole.png", USE_ALPHA);
940 texture_load(&img_poletop, datadir + "/images/shared/poletop.png",
946 texture_load(&img_flag[0], datadir + "/images/shared/flag-0.png",
948 texture_load(&img_flag[1], datadir + "/images/shared/flag-1.png",
954 texture_load(&img_cloud[0][0], datadir + "/images/shared/cloud-00.png",
957 texture_load(&img_cloud[0][1], datadir + "/images/shared/cloud-01.png",
960 texture_load(&img_cloud[0][2], datadir + "/images/shared/cloud-02.png",
963 texture_load(&img_cloud[0][3], datadir + "/images/shared/cloud-03.png",
967 texture_load(&img_cloud[1][0], datadir + "/images/shared/cloud-10.png",
970 texture_load(&img_cloud[1][1], datadir + "/images/shared/cloud-11.png",
973 texture_load(&img_cloud[1][2], datadir + "/images/shared/cloud-12.png",
976 texture_load(&img_cloud[1][3], datadir + "/images/shared/cloud-13.png",
984 texture_load(&img_bsod_left[0], datadir +
985 "/images/shared/bsod-left-0.png",
988 texture_load(&img_bsod_left[1], datadir +
989 "/images/shared/bsod-left-1.png",
992 texture_load(&img_bsod_left[2], datadir +
993 "/images/shared/bsod-left-2.png",
996 texture_load(&img_bsod_left[3], datadir +
997 "/images/shared/bsod-left-3.png",
1000 texture_load(&img_bsod_right[0], datadir +
1001 "/images/shared/bsod-right-0.png",
1004 texture_load(&img_bsod_right[1], datadir +
1005 "/images/shared/bsod-right-1.png",
1008 texture_load(&img_bsod_right[2], datadir +
1009 "/images/shared/bsod-right-2.png",
1012 texture_load(&img_bsod_right[3], datadir +
1013 "/images/shared/bsod-right-3.png",
1016 texture_load(&img_bsod_squished_left, datadir +
1017 "/images/shared/bsod-squished-left.png",
1020 texture_load(&img_bsod_squished_right, datadir +
1021 "/images/shared/bsod-squished-right.png",
1024 texture_load(&img_bsod_falling_left, datadir +
1025 "/images/shared/bsod-falling-left.png",
1028 texture_load(&img_bsod_falling_right, datadir +
1029 "/images/shared/bsod-falling-right.png",
1035 texture_load(&img_laptop_left[0], datadir +
1036 "/images/shared/laptop-left-0.png",
1039 texture_load(&img_laptop_left[1], datadir +
1040 "/images/shared/laptop-left-1.png",
1043 texture_load(&img_laptop_left[2], datadir +
1044 "/images/shared/laptop-left-2.png",
1047 texture_load(&img_laptop_right[0], datadir +
1048 "/images/shared/laptop-right-0.png",
1051 texture_load(&img_laptop_right[1], datadir +
1052 "/images/shared/laptop-right-1.png",
1055 texture_load(&img_laptop_right[2], datadir +
1056 "/images/shared/laptop-right-2.png",
1059 texture_load(&img_laptop_flat_left, datadir +
1060 "/images/shared/laptop-flat-left.png",
1063 texture_load(&img_laptop_flat_right, datadir +
1064 "/images/shared/laptop-flat-right.png",
1067 texture_load(&img_laptop_falling_left, datadir +
1068 "/images/shared/laptop-falling-left.png",
1071 texture_load(&img_laptop_falling_right, datadir +
1072 "/images/shared/laptop-falling-right.png",
1078 texture_load(&img_money_left[0], datadir +
1079 "/images/shared/bag-left-0.png",
1082 texture_load(&img_money_left[1], datadir +
1083 "/images/shared/bag-left-1.png",
1086 texture_load(&img_money_right[0], datadir +
1087 "/images/shared/bag-right-0.png",
1090 texture_load(&img_money_right[1], datadir +
1091 "/images/shared/bag-right-1.png",
1098 texture_load(&img_mints, datadir + "/images/shared/mints.png", USE_ALPHA);
1099 texture_load(&img_coffee, datadir + "/images/shared/coffee.png", USE_ALPHA);
1104 texture_load(&img_bullet, datadir + "/images/shared/bullet.png", USE_ALPHA);
1106 texture_load(&img_red_glow, datadir + "/images/shared/red-glow.png",
1113 texture_load(&img_distro[0], datadir + "/images/shared/distro-0.png",
1116 texture_load(&img_distro[1], datadir + "/images/shared/distro-1.png",
1119 texture_load(&img_distro[2], datadir + "/images/shared/distro-2.png",
1122 texture_load(&img_distro[3], datadir + "/images/shared/distro-3.png",
1128 texture_load(&tux_life, datadir + "/images/shared/tux-life.png",
1133 texture_load(&img_golden_herring, datadir + "/images/shared/golden-herring.png",
1137 /* Super background: */
1139 texture_load(&img_super_bkgd, datadir + "/images/shared/super-bkgd.png",
1143 /* Sound effects: */
1145 /* if (use_sound) // this will introduce SERIOUS bugs here ! because "load_sound"
1146 // initialize sounds[i] with the correct pointer's value:
1147 // NULL or something else. And it will be dangerous to
1148 // play with not-initialized pointers.
1149 // This is also true with if (use_music)
1150 Send a mail to me: neoneurone@users.sf.net, if you have another opinion. :)
1152 for (i = 0; i < NUM_SOUNDS; i++)
1153 sounds[i] = load_sound(datadir + soundfilenames[i]);
1156 herring_song = load_song(datadir + "/music/SALCON.MOD");
1160 /* Free shared data: */
1162 void unloadshared(void)
1166 for (i = 0; i < 3; i++)
1168 texture_free(&tux_right[i]);
1169 texture_free(&tux_left[i]);
1170 texture_free(&bigtux_right[i]);
1171 texture_free(&bigtux_left[i]);
1174 texture_free(&bigtux_right_jump);
1175 texture_free(&bigtux_left_jump);
1177 for (i = 0; i < 2; i++)
1179 texture_free(&cape_right[i]);
1180 texture_free(&cape_left[i]);
1181 texture_free(&bigcape_right[i]);
1182 texture_free(&bigcape_left[i]);
1185 texture_free(&ducktux_left);
1186 texture_free(&ducktux_right);
1188 texture_free(&skidtux_left);
1189 texture_free(&skidtux_right);
1191 for (i = 0; i < 4; i++)
1193 texture_free(&img_bsod_left[i]);
1194 texture_free(&img_bsod_right[i]);
1197 texture_free(&img_bsod_squished_left);
1198 texture_free(&img_bsod_squished_right);
1200 texture_free(&img_bsod_falling_left);
1201 texture_free(&img_bsod_falling_right);
1203 for (i = 0; i < 3; i++)
1205 texture_free(&img_laptop_left[i]);
1206 texture_free(&img_laptop_right[i]);
1209 texture_free(&img_laptop_flat_left);
1210 texture_free(&img_laptop_flat_right);
1212 texture_free(&img_laptop_falling_left);
1213 texture_free(&img_laptop_falling_right);
1215 for (i = 0; i < 2; i++)
1217 texture_free(&img_money_left[i]);
1218 texture_free(&img_money_right[i]);
1221 texture_free(&img_box_full);
1222 texture_free(&img_box_empty);
1224 texture_free(&img_water);
1225 for (i = 0; i < 3; i++)
1226 texture_free(&img_waves[i]);
1228 texture_free(&img_pole);
1229 texture_free(&img_poletop);
1231 for (i = 0; i < 2; i++)
1232 texture_free(&img_flag[i]);
1234 texture_free(&img_mints);
1235 texture_free(&img_coffee);
1237 for (i = 0; i < 4; i++)
1239 texture_free(&img_distro[i]);
1240 texture_free(&img_cloud[0][i]);
1241 texture_free(&img_cloud[1][i]);
1244 texture_free(&img_golden_herring);
1246 for (i = 0; i < NUM_SOUNDS; i++)
1247 free_chunk(sounds[i]);
1249 /* free the herring song */
1250 free_music( herring_song );
1254 /* Draw a tile on the screen: */
1256 void drawshape(float x, float y, unsigned char c)
1260 if (c == 'X' || c == 'x')
1261 texture_draw(&img_brick[0], x, y);
1262 else if (c == 'Y' || c == 'y')
1263 texture_draw(&img_brick[1], x, y);
1264 else if (c == 'A' || c =='B' || c == '!')
1265 texture_draw(&img_box_full, x, y);
1267 texture_draw(&img_box_empty, x, y);
1268 else if (c >= 'C' && c <= 'F')
1269 texture_draw(&img_cloud[0][c - 'C'], x, y);
1270 else if (c >= 'c' && c <= 'f')
1271 texture_draw(&img_cloud[1][c - 'c'], x, y);
1272 else if (c >= 'G' && c <= 'J')
1273 texture_draw(&img_bkgd_tile[0][c - 'G'], x, y);
1274 else if (c >= 'g' && c <= 'j')
1275 texture_draw(&img_bkgd_tile[1][c - 'g'], x, y);
1277 texture_draw(&img_solid[0], x, y);
1279 texture_draw(&img_solid[1], x, y);
1281 texture_draw(&img_solid[2], x, y);
1283 texture_draw(&img_solid[3], x, y);
1286 z = (global_frame_counter / 2) % 6;
1289 texture_draw(&img_distro[z], x, y);
1291 texture_draw(&img_distro[2], x, y);
1293 texture_draw(&img_distro[1], x, y);
1297 z = (global_frame_counter / 3) % 3;
1299 texture_draw(&img_waves[z], x, y);
1302 texture_draw(&img_poletop, x, y);
1305 texture_draw(&img_pole, x, y);
1310 z = (global_frame_counter / 3) % 2;
1312 texture_draw(&img_flag[z], x + 16, y);
1315 texture_draw(&img_water, x, y);
1319 /* What shape is at some position? */
1321 unsigned char shape(float x, float y)
1330 if (yy >= 0 && yy < 15 && xx >= 0 && xx <= current_level.width)
1332 c = current_level.tiles[yy][xx];
1343 bool issolid(float x, float y)
1345 return (isbrick(x, y) ||
1347 (shape(x, y) == '[') ||
1348 (shape(x, y) == '=') ||
1349 (shape(x, y) == ']') ||
1350 (shape(x, y) == 'A') ||
1351 (shape(x, y) == 'B') ||
1352 (shape(x, y) == '!') ||
1353 (shape(x, y) == 'a'));
1356 /* Is it a brick? */
1358 bool isbrick(float x, float y)
1360 return (shape(x, y) == 'X' ||
1361 shape(x, y) == 'x' ||
1362 shape(x, y) == 'Y' ||
1363 shape(x, y) == 'y');
1369 bool isice(float x, float y)
1371 return (shape(x, y) == '#');
1374 /* Is it a full box? */
1376 bool isfullbox(float x, float y)
1378 return (shape(x, y) == 'A' ||
1379 shape(x, y) == 'B' ||
1380 shape(x, y) == '!');
1383 /* Break a brick: */
1385 void trybreakbrick(float x, float y)
1389 if (shape(x, y) == 'x' || shape(x, y) == 'y')
1391 /* Get a distro from it: */
1393 add_bouncy_distro(((int)(x + 1) / 32) * 32,
1394 (int)(y / 32) * 32);
1396 if (!counting_distros)
1398 counting_distros = true;
1399 distro_counter = 50;
1402 if (distro_counter <= 0)
1403 level_change(¤t_level,x, y, 'a');
1405 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1406 score = score + SCORE_DISTRO;
1411 /* Get rid of it: */
1413 level_change(¤t_level,x, y,'.');
1417 /* Replace it with broken bits: */
1419 add_broken_brick(((int)(x + 1) / 32) * 32,
1420 (int)(y / 32) * 32);
1423 /* Get some score: */
1425 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
1426 score = score + SCORE_BRICK;
1431 /* Bounce a brick: */
1433 void bumpbrick(float x, float y)
1435 add_bouncy_brick(((int)(x + 1) / 32) * 32,
1436 (int)(y / 32) * 32);
1438 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
1445 void tryemptybox(float x, float y, int col_side)
1447 if (!isfullbox(x, y))
1450 // according to the collision side, set the upgrade direction
1452 if(col_side == LEFT)
1459 case 'A': /* Box with a distro! */
1460 add_bouncy_distro(((int)(x + 1) / 32) * 32, (int)(y / 32) * 32 - 32);
1461 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1462 score = score + SCORE_DISTRO;
1465 case 'B': /* Add an upgrade! */
1466 if (tux.size == SMALL) /* Tux is small, add mints! */
1467 add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_MINTS);
1468 else /* Tux is big, add coffee: */
1469 add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_COFFEE);
1470 play_sound(sounds[SND_UPGRADE], SOUND_CENTER_SPEAKER);
1472 case '!': /* Add a golden herring */
1473 add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_HERRING);
1479 /* Empty the box: */
1480 level_change(¤t_level,x, y, 'a');
1484 /* Try to grab a distro: */
1486 void trygrabdistro(float x, float y, int bounciness)
1488 if (shape(x, y) == '$')
1490 level_change(¤t_level,x, y, '.');
1491 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1493 if (bounciness == BOUNCE)
1495 add_bouncy_distro(((int)(x + 1) / 32) * 32,
1496 (int)(y / 32) * 32);
1499 score = score + SCORE_DISTRO;
1504 /* Try to bump a bad guy from below: */
1506 void trybumpbadguy(float x, float y)
1511 for (i = 0; i < bad_guys.size(); i++)
1513 if (bad_guys[i].base.x >= x - 32 && bad_guys[i].base.x <= x + 32 &&
1514 bad_guys[i].base.y >= y - 16 && bad_guys[i].base.y <= y + 16)
1516 if (bad_guys[i].kind == BAD_BSOD ||
1517 bad_guys[i].kind == BAD_LAPTOP)
1519 bad_guys[i].dying = DYING_FALLING;
1520 bad_guys[i].base.ym = -8;
1521 play_sound(sounds[SND_FALL], SOUND_CENTER_SPEAKER);
1528 for (i = 0; i < upgrades.size(); i++)
1530 if (upgrades[i].base.height == 32 &&
1531 upgrades[i].base.x >= x - 32 && upgrades[i].base.x <= x + 32 &&
1532 upgrades[i].base.y >= y - 16 && upgrades[i].base.y <= y + 16)
1534 upgrades[i].base.xm = -upgrades[i].base.xm;
1535 upgrades[i].base.ym = -8;
1536 play_sound(sounds[SND_BUMP_UPGRADE], SOUND_CENTER_SPEAKER);
1542 void drawstatus(void)
1546 sprintf(str, "%d", score);
1547 text_draw(&white_text, "SCORE", 0, 0, 1);
1548 text_draw(&gold_text, str, 96, 0, 1);
1550 if(st_gl_mode != ST_GL_TEST)
1552 sprintf(str, "%d", hs_score);
1553 text_draw(&white_text, "HIGH", 0, 20, 1);
1554 text_draw(&gold_text, str, 96, 20, 1);
1558 text_draw(&white_text,"Press ESC To Return",0,20,1);
1561 if (timer_get_left(&time_left) > TIME_WARNING || (global_frame_counter % 10) < 5)
1563 sprintf(str, "%d", timer_get_left(&time_left) / 1000 );
1564 text_draw(&white_text, "TIME", 224, 0, 1);
1565 text_draw(&gold_text, str, 304, 0, 1);
1568 sprintf(str, "%d", distros);
1569 text_draw(&white_text, "DISTROS", screen->h, 0, 1);
1570 text_draw(&gold_text, str, 608, 0, 1);
1572 text_draw(&white_text, "LIVES", screen->h, 20, 1);
1576 sprintf(str, "%2.1f", fps_fps);
1577 text_draw(&white_text, "FPS", screen->h, 40, 1);
1578 text_draw(&gold_text, str, screen->h + 60, 40, 1);
1581 for(int i=0; i < tux.lives; ++i)
1583 texture_draw(&tux_life,565+(18*i),20);
1588 void drawendscreen(void)
1592 clearscreen(0, 0, 0);
1594 text_drawf(&blue_text, "GAMEOVER", 0, 200, A_HMIDDLE, A_TOP, 1);
1596 sprintf(str, "SCORE: %d", score);
1597 text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1);
1599 sprintf(str, "DISTROS: %d", distros);
1600 text_drawf(&gold_text, str, 0, 256, A_HMIDDLE, A_TOP, 1);
1606 void drawresultscreen(void)
1610 clearscreen(0, 0, 0);
1612 text_drawf(&blue_text, "Result:", 0, 200, A_HMIDDLE, A_TOP, 1);
1614 sprintf(str, "SCORE: %d", score);
1615 text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1);
1617 sprintf(str, "DISTROS: %d", distros);
1618 text_drawf(&gold_text, str, 0, 256, A_HMIDDLE, A_TOP, 1);
1624 void savegame(int slot)
1626 char savefile[1024];
1630 sprintf(savefile,"%s/slot%d.save",st_save_dir,slot);
1632 fi = fopen(savefile, "wb");
1636 fprintf(stderr, "Warning: I could not open the slot file ");
1641 fputs(level_subset, fi);
1643 fwrite(&level,sizeof(int),1,fi);
1644 fwrite(&score,sizeof(int),1,fi);
1645 fwrite(&distros,sizeof(int),1,fi);
1646 fwrite(&scroll_x,sizeof(float),1,fi);
1647 fwrite(&tux,sizeof(Player),1,fi);
1648 timer_fwrite(&tux.invincible_timer,fi);
1649 timer_fwrite(&tux.skidding_timer,fi);
1650 timer_fwrite(&tux.safe_timer,fi);
1651 timer_fwrite(&tux.frame_timer,fi);
1652 timer_fwrite(&time_left,fi);
1653 ui = st_get_ticks();
1654 fwrite(&ui,sizeof(int),1,fi);
1660 void loadgame(int slot)
1662 char savefile[1024];
1667 sprintf(savefile,"%s/slot%d.save",st_save_dir,slot);
1669 fi = fopen(savefile, "rb");
1673 fprintf(stderr, "Warning: I could not open the slot file ");
1678 fgets(str, 100, fi);
1679 strcpy(level_subset, str);
1680 level_subset[strlen(level_subset)-1] = '\0';
1681 fread(&level,sizeof(int),1,fi);
1684 level_free(¤t_level);
1685 if(level_load(¤t_level,level_subset,level) != 0)
1689 activate_bad_guys();
1691 level_load_gfx(¤t_level);
1693 level_load_song(¤t_level);
1695 update_time = st_get_ticks();
1697 fread(&score,sizeof(int),1,fi);
1698 fread(&distros,sizeof(int),1,fi);
1699 fread(&scroll_x,sizeof(float),1,fi);
1700 fread(&tux, sizeof(Player), 1, fi);
1701 timer_fread(&tux.invincible_timer,fi);
1702 timer_fread(&tux.skidding_timer,fi);
1703 timer_fread(&tux.safe_timer,fi);
1704 timer_fread(&tux.frame_timer,fi);
1705 timer_fread(&time_left,fi);
1706 fread(&ui,sizeof(int),1,fi);
1707 tux.hphysic.start_time += st_get_ticks() - ui;
1708 tux.vphysic.start_time += st_get_ticks() - ui;
1714 void slotinfo(char **pinfo, int slot)
1717 char slotfile[1024];
1721 sprintf(slotfile,"%s/slot%d.save",st_save_dir,slot);
1723 fi = fopen(slotfile, "rb");
1725 sprintf(tmp,"Slot %d - ",slot);
1733 fgets(str, 100, fi);
1734 str[strlen(str)-1] = '\0';
1736 strcat(tmp, " / Level:");
1737 fread(&slot_level,sizeof(int),1,fi);
1738 sprintf(str,"%d",slot_level);
1743 *pinfo = (char*) malloc(sizeof(char) * (strlen(tmp)+1));