6 by Bill Kendrick & Tobias Glaesser
7 bill@newbreedsoftware.com
8 http://www.newbreedsoftware.com/supertux/
10 April 11, 2000 - March 15, 2004
22 #include <sys/types.h>
31 #include "high_scores.h"
39 #include "collision.h"
41 /* extern variables */
43 st_level current_level;
44 int game_started = NO;
46 /* Local variables: */
48 static texture_type img_waves[3], img_water, img_pole, img_poletop, img_flag[2];
49 static texture_type img_cloud[2][4];
50 static SDL_Event event;
52 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);
70 #define JOYSTICK_DEAD_ZONE 4096
78 sprintf(str, "LEVEL %d", level);
79 text_drawf(&blue_text, str, 0, 200, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
81 sprintf(str, "%s", current_level.name.c_str());
82 text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
84 sprintf(str, "TUX x %d", tux.lives);
85 text_drawf(&white_text, str, 0, 256, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
93 void start_timers(void)
95 timer_start(&time_left,current_level.time_left*1000);
96 st_pause_ticks_init();
97 update_time = st_get_ticks();
100 void activate_bad_guys(void)
104 /* Activate bad guys: */
106 for (y = 0; y < 15; y++)
108 for (x = 0; x < current_level.width; x++)
110 if (current_level.tiles[y][x] >= '0' && current_level.tiles[y][x] <= '9')
112 add_bad_guy(x * 32, y * 32, current_level.tiles[y][x] - '0');
113 current_level.tiles[y][x] = '.';
120 /* --- GAME EVENT! --- */
122 void game_event(void)
124 while (SDL_PollEvent(&event))
128 case SDL_QUIT: /* Quit event - quit: */
131 case SDL_KEYDOWN: /* A keypress! */
132 key = event.key.keysym.sym;
134 /* Check for menu-events, if the menu is shown */
136 menu_event(&event.key.keysym);
138 if(player_key_event(&tux,key,DOWN))
143 case SDLK_ESCAPE: /* Escape: Open/Close the menu: */
146 if(st_gl_mode == ST_GL_TEST)
150 menu_set_current(&game_menu);
152 st_pause_ticks_stop();
156 menu_set_current(&game_menu);
158 st_pause_ticks_start();
166 case SDL_KEYUP: /* A keyrelease! */
167 key = event.key.keysym.sym;
169 if(player_key_event(&tux,key,UP))
180 st_pause_ticks_stop();
185 st_pause_ticks_start();
190 if(debug_mode == YES)
192 tux.size = !tux.size;
195 tux.base.height = 64;
198 tux.base.height = 32;
202 if(debug_mode == YES)
206 if(debug_mode == YES)
210 if(debug_mode == YES)
214 if(debug_mode == YES)
215 timer_start(&tux.invincible_timer,TUX_INVINCIBLE_TIME);
218 if(debug_mode == YES)
222 if(debug_mode == YES)
236 case SDL_JOYAXISMOTION:
237 switch(event.jaxis.axis)
240 if (event.jaxis.value < -JOYSTICK_DEAD_ZONE)
241 tux.input.left = DOWN;
242 else if (event.jaxis.value > JOYSTICK_DEAD_ZONE)
245 if (event.jaxis.value > JOYSTICK_DEAD_ZONE)
246 tux.input.right = DOWN;
247 else if (event.jaxis.value < -JOYSTICK_DEAD_ZONE)
248 tux.input.right = UP;
251 if (event.jaxis.value > JOYSTICK_DEAD_ZONE)
252 tux.input.down = DOWN;
253 else if (event.jaxis.value < -JOYSTICK_DEAD_ZONE)
256 /* Handle joystick for the menu */
259 if(tux.input.down == DOWN)
260 menuaction = MN_DOWN;
269 case SDL_JOYBUTTONDOWN:
270 if (event.jbutton.button == JOY_A)
272 else if (event.jbutton.button == JOY_B)
273 tux.input.fire = DOWN;
275 case SDL_JOYBUTTONUP:
276 if (event.jbutton.button == JOY_A)
278 else if (event.jbutton.button == JOY_B)
295 /* --- GAME ACTION! --- */
297 int game_action(void)
301 /* (tux_dying || next_level) */
302 if (tux.dying || next_level)
304 /* Tux either died, or reached the end of a level! */
311 /* End of a level! */
314 if(st_gl_mode != ST_GL_TEST)
321 level_free(¤t_level);
327 player_level_begin(&tux);
333 /* No more lives!? */
337 if(st_gl_mode != ST_GL_TEST)
340 if(st_gl_mode != ST_GL_TEST)
342 if (score > hs_score)
346 level_free(¤t_level);
351 } /* if (lives < 0) */
354 /* Either way, (re-)load the (next) level... */
356 player_level_begin(&tux);
358 level_free(¤t_level);
360 if (st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
362 if(level_load(¤t_level, level_subset) != 0)
367 if(level_load(¤t_level,level_subset,level) != 0)
375 level_load_gfx(¤t_level);
377 level_load_song(¤t_level);
378 if(st_gl_mode != ST_GL_TEST)
382 play_current_music();
387 /* Handle bouncy distros: */
389 for (i = 0; i < num_bouncy_distros; i++)
391 bouncy_distro_action(&bouncy_distros[i]);
395 /* Handle broken bricks: */
397 for (i = 0; i < num_broken_bricks; i++)
399 broken_brick_action(&broken_bricks[i]);
403 /* Handle distro counting: */
405 if (counting_distros == YES)
409 if (distro_counter <= 0)
410 counting_distros = -1;
414 /* Handle bouncy bricks: */
416 for (i = 0; i < num_bouncy_bricks; i++)
418 bouncy_brick_action(&bouncy_bricks[i]);
422 /* Handle floating scores: */
424 for (i = 0; i < num_floating_scores; i++)
426 floating_score_action(&floating_scores[i]);
430 /* Handle bullets: */
432 for (i = 0; i < num_bullets; ++i)
434 bullet_action(&bullets[i]);
437 /* Handle upgrades: */
439 for (i = 0; i < num_upgrades; i++)
441 upgrade_action(&upgrades[i]);
445 /* Handle bad guys: */
447 for (i = 0; i < num_bad_guys; i++)
449 badguy_action(&bad_guys[i]);
452 /* Handle all possible collisions. */
458 /* --- GAME DRAW! --- */
466 if (tux.dying && (frame % 4) == 0)
467 clearscreen(255, 255, 255);
468 else if(timer_check(&super_bkgd_timer))
469 texture_draw(&img_super_bkgd, 0, 0, NO_UPDATE);
472 /* Draw the real background */
473 if(current_level.bkgd_image[0] != '\0')
475 s = (int)scroll_x / 30;
476 texture_draw_part(&img_bkgd,s,0,0,0,img_bkgd.w - s, img_bkgd.h, NO_UPDATE);
477 texture_draw_part(&img_bkgd,0,0,screen->w - s ,0,s,img_bkgd.h, NO_UPDATE);
481 clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue);
485 /* Draw background: */
487 for (y = 0; y < 15; ++y)
489 for (x = 0; x < 21; ++x)
491 drawshape(x * 32 - ((int)scroll_x % 32), y * 32,
492 current_level.tiles[(int)y][(int)x + (int)(scroll_x / 32)]);
497 /* (Bouncy bricks): */
499 for (i = 0; i < num_bouncy_bricks; ++i)
501 bouncy_brick_draw(&bouncy_bricks[i]);
507 for (i = 0; i < num_bad_guys; ++i)
509 badguy_draw(&bad_guys[i]);
518 for (i = 0; i < num_bullets; ++i)
520 bullet_draw(&bullets[i]);
523 /* (Floating scores): */
525 for (i = 0; i < num_floating_scores; ++i)
527 floating_score_draw(&floating_scores[i]);
533 for (i = 0; i < num_upgrades; ++i)
535 upgrade_draw(&upgrades[i]);
539 /* (Bouncy distros): */
541 for (i = 0; i < num_bouncy_distros; ++i)
543 bouncy_distro_draw(&bouncy_distros[i]);
547 /* (Broken bricks): */
549 for (i = 0; i < num_broken_bricks; ++i)
551 broken_brick_draw(&broken_bricks[i]);
560 for(i = 0; i < x; ++i)
562 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);
564 fillrect(0,0,screen->w,screen->h,rand() % 50, rand() % 50, rand() % 50, 128);
565 text_drawf(&blue_text, "PAUSE - Press 'P' To Play", 0, 230, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
569 menu_process_current();
571 /* (Update it all!) */
578 /* --- GAME LOOP! --- */
580 int gameloop(const char * subset, int levelnb, int mode)
582 int fps_cnt, jump, done;
583 timer_type fps_timer, frame_timer;
584 timer_init(&fps_timer, YES);
585 timer_init(&frame_timer, YES);
596 strcpy(level_subset,subset);
598 if (st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
600 if (level_load(¤t_level, level_subset))
605 if(level_load(¤t_level, level_subset, level) != 0)
609 level_load_gfx(¤t_level);
611 level_load_song(¤t_level);
615 if(st_gl_mode != ST_GL_TEST)
620 if(st_gl_mode == ST_GL_PLAY || st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
623 timer_init(&time_left,YES);
626 if(st_gl_mode == ST_GL_LOAD_GAME)
630 /* --- MAIN GAME LOOP!!! --- */
637 timer_init(&fps_timer,YES);
638 timer_init(&frame_timer,YES);
643 clearscreen(0, 0, 0);
647 play_current_music();
650 while (SDL_PollEvent(&event))
658 /* Calculate the movement-factor */
659 frame_ratio = ((double)(update_time-last_update_time))/((double)FRAME_RATE);
660 if(frame_ratio > 1.5) /* Quick hack to correct the unprecise CPU clocks a little bit. */
661 frame_ratio = 1.5 + (frame_ratio - 1.5) * 0.85;
663 if(!timer_check(&frame_timer))
665 timer_start(&frame_timer,25);
671 tux.input.old_fire = tux.input.fire;
677 if(current_menu == &game_menu)
679 switch (menu_check(&game_menu))
682 st_pause_ticks_stop();
685 update_load_save_game_menu(&save_game_menu, NO);
688 update_load_save_game_menu(&load_game_menu, YES);
691 st_pause_ticks_stop();
696 else if(current_menu == &options_menu)
698 process_options_menu();
700 else if(current_menu == &save_game_menu )
702 process_save_load_game_menu(YES);
704 else if(current_menu == &load_game_menu )
706 process_save_load_game_menu(NO);
711 /* Handle actions: */
713 if(!game_pause && !show_menu)
715 /*float z = frame_ratio;
719 if (game_action() == 0)
721 /* == 0: no more lives */
722 /* == -1: continues */
734 if(debug_mode && debug_fps == YES)
737 /*Draw the current scene to the screen */
738 /*If the machine running the game is too slow
739 skip the drawing of the frame (so the calculations are more precise and
740 the FPS aren't affected).*/
741 /*if( ! fps_fps < 50.0 )
744 jump = YES;*/ /*FIXME: Implement this tweak right.*/
747 /* Time stops in pause mode */
748 if(game_pause || show_menu )
753 /* Set the time of the last update and the time of the current update */
754 last_update_time = update_time;
755 update_time = st_get_ticks();
758 /* Pause till next frame, if the machine running the game is too fast: */
759 /* FIXME: Works great for in OpenGl mode, where the CPU doesn't have to do that much. But
760 the results in SDL mode aren't perfect (thought the 100 FPS are reached), even on an AMD2500+. */
761 if(last_update_time >= update_time - 12 && jump != YES )
763 /*if((update_time - last_update_time) < 10)
764 SDL_Delay((11 - (update_time - last_update_time))/2);*/
770 if (timer_check(&time_left))
772 /* are we low on time ? */
773 if ((timer_get_left(&time_left) < TIME_WARNING)
774 && (get_current_music() != HURRYUP_MUSIC)) /* play the fast music */
776 set_current_music(HURRYUP_MUSIC);
777 play_current_music();
782 player_kill(&tux,KILL);
785 /* Calculate frames per second */
789 fps_fps = (1000.0 / (float)timer_get_gone(&fps_timer)) * (float)fps_cnt;
791 if(!timer_check(&fps_timer))
793 timer_start(&fps_timer,1000);
799 while (!done && !quit);
804 level_free(¤t_level);
815 /* Load graphics/sounds shared between all levels: */
817 void loadshared(void)
822 texture_load(&tux_right[0], datadir + "/images/shared/tux-right-0.png", USE_ALPHA);
823 texture_load(&tux_right[1], datadir + "/images/shared/tux-right-1.png", USE_ALPHA);
824 texture_load(&tux_right[2], datadir + "/images/shared/tux-right-2.png", USE_ALPHA);
826 texture_load(&tux_left[0], datadir + "/images/shared/tux-left-0.png", USE_ALPHA);
827 texture_load(&tux_left[1], datadir + "/images/shared/tux-left-1.png", USE_ALPHA);
828 texture_load(&tux_left[2], datadir + "/images/shared/tux-left-2.png", USE_ALPHA);
830 texture_load(&firetux_right[0], datadir + "/images/shared/firetux-right-0.png", USE_ALPHA);
831 texture_load(&firetux_right[1], datadir + "/images/shared/firetux-right-1.png", USE_ALPHA);
832 texture_load(&firetux_right[2], datadir + "/images/shared/firetux-right-2.png", USE_ALPHA);
834 texture_load(&firetux_left[0], datadir + "/images/shared/firetux-left-0.png", USE_ALPHA);
835 texture_load(&firetux_left[1], datadir + "/images/shared/firetux-left-1.png", USE_ALPHA);
836 texture_load(&firetux_left[2], datadir + "/images/shared/firetux-left-2.png", USE_ALPHA);
839 texture_load(&cape_right[0], datadir + "/images/shared/cape-right-0.png",
842 texture_load(&cape_right[1], datadir + "/images/shared/cape-right-1.png",
845 texture_load(&cape_left[0], datadir + "/images/shared/cape-left-0.png",
848 texture_load(&cape_left[1], datadir + "/images/shared/cape-left-1.png",
851 texture_load(&bigtux_right[0], datadir + "/images/shared/bigtux-right-0.png",
854 texture_load(&bigtux_right[1], datadir + "/images/shared/bigtux-right-1.png",
857 texture_load(&bigtux_right[2], datadir + "/images/shared/bigtux-right-2.png",
860 texture_load(&bigtux_right_jump, datadir + "/images/shared/bigtux-right-jump.png", USE_ALPHA);
862 texture_load(&bigtux_left[0], datadir + "/images/shared/bigtux-left-0.png",
865 texture_load(&bigtux_left[1], datadir + "/images/shared/bigtux-left-1.png",
868 texture_load(&bigtux_left[2], datadir + "/images/shared/bigtux-left-2.png",
871 texture_load(&bigtux_left_jump, datadir + "/images/shared/bigtux-left-jump.png", USE_ALPHA);
873 texture_load(&bigcape_right[0], datadir + "/images/shared/bigcape-right-0.png",
876 texture_load(&bigcape_right[1], datadir + "/images/shared/bigcape-right-1.png",
879 texture_load(&bigcape_left[0], datadir + "/images/shared/bigcape-left-0.png",
882 texture_load(&bigcape_left[1], datadir + "/images/shared/bigcape-left-1.png",
885 texture_load(&bigfiretux_right[0], datadir + "/images/shared/bigfiretux-right-0.png",
888 texture_load(&bigfiretux_right[1], datadir + "/images/shared/bigfiretux-right-1.png",
891 texture_load(&bigfiretux_right[2], datadir + "/images/shared/bigfiretux-right-2.png",
894 texture_load(&bigfiretux_right_jump, datadir + "/images/shared/bigfiretux-right-jump.png", USE_ALPHA);
896 texture_load(&bigfiretux_left[0], datadir + "/images/shared/bigfiretux-left-0.png",
899 texture_load(&bigfiretux_left[1], datadir + "/images/shared/bigfiretux-left-1.png",
902 texture_load(&bigfiretux_left[2], datadir + "/images/shared/bigfiretux-left-2.png",
905 texture_load(&bigfiretux_left_jump, datadir + "/images/shared/bigfiretux-left-jump.png", USE_ALPHA);
907 texture_load(&bigcape_right[0], datadir + "/images/shared/bigcape-right-0.png",
910 texture_load(&bigcape_right[1], datadir + "/images/shared/bigcape-right-1.png",
913 texture_load(&bigcape_left[0], datadir + "/images/shared/bigcape-left-0.png",
916 texture_load(&bigcape_left[1], datadir + "/images/shared/bigcape-left-1.png",
920 texture_load(&ducktux_right, datadir +
921 "/images/shared/ducktux-right.png",
924 texture_load(&ducktux_left, datadir +
925 "/images/shared/ducktux-left.png",
928 texture_load(&skidtux_right, datadir +
929 "/images/shared/skidtux-right.png",
932 texture_load(&skidtux_left, datadir +
933 "/images/shared/skidtux-left.png",
936 texture_load(&duckfiretux_right, datadir +
937 "/images/shared/duckfiretux-right.png",
940 texture_load(&duckfiretux_left, datadir +
941 "/images/shared/duckfiretux-left.png",
944 texture_load(&skidfiretux_right, datadir +
945 "/images/shared/skidfiretux-right.png",
948 texture_load(&skidfiretux_left, datadir +
949 "/images/shared/skidfiretux-left.png",
955 texture_load(&img_box_full, datadir + "/images/shared/box-full.png",
957 texture_load(&img_box_empty, datadir + "/images/shared/box-empty.png",
964 texture_load(&img_water, datadir + "/images/shared/water.png", IGNORE_ALPHA);
966 texture_load(&img_waves[0], datadir + "/images/shared/waves-0.png",
969 texture_load(&img_waves[1], datadir + "/images/shared/waves-1.png",
972 texture_load(&img_waves[2], datadir + "/images/shared/waves-2.png",
978 texture_load(&img_pole, datadir + "/images/shared/pole.png", USE_ALPHA);
979 texture_load(&img_poletop, datadir + "/images/shared/poletop.png",
985 texture_load(&img_flag[0], datadir + "/images/shared/flag-0.png",
987 texture_load(&img_flag[1], datadir + "/images/shared/flag-1.png",
993 texture_load(&img_cloud[0][0], datadir + "/images/shared/cloud-00.png",
996 texture_load(&img_cloud[0][1], datadir + "/images/shared/cloud-01.png",
999 texture_load(&img_cloud[0][2], datadir + "/images/shared/cloud-02.png",
1002 texture_load(&img_cloud[0][3], datadir + "/images/shared/cloud-03.png",
1006 texture_load(&img_cloud[1][0], datadir + "/images/shared/cloud-10.png",
1009 texture_load(&img_cloud[1][1], datadir + "/images/shared/cloud-11.png",
1012 texture_load(&img_cloud[1][2], datadir + "/images/shared/cloud-12.png",
1015 texture_load(&img_cloud[1][3], datadir + "/images/shared/cloud-13.png",
1023 texture_load(&img_bsod_left[0], datadir +
1024 "/images/shared/bsod-left-0.png",
1027 texture_load(&img_bsod_left[1], datadir +
1028 "/images/shared/bsod-left-1.png",
1031 texture_load(&img_bsod_left[2], datadir +
1032 "/images/shared/bsod-left-2.png",
1035 texture_load(&img_bsod_left[3], datadir +
1036 "/images/shared/bsod-left-3.png",
1039 texture_load(&img_bsod_right[0], datadir +
1040 "/images/shared/bsod-right-0.png",
1043 texture_load(&img_bsod_right[1], datadir +
1044 "/images/shared/bsod-right-1.png",
1047 texture_load(&img_bsod_right[2], datadir +
1048 "/images/shared/bsod-right-2.png",
1051 texture_load(&img_bsod_right[3], datadir +
1052 "/images/shared/bsod-right-3.png",
1055 texture_load(&img_bsod_squished_left, datadir +
1056 "/images/shared/bsod-squished-left.png",
1059 texture_load(&img_bsod_squished_right, datadir +
1060 "/images/shared/bsod-squished-right.png",
1063 texture_load(&img_bsod_falling_left, datadir +
1064 "/images/shared/bsod-falling-left.png",
1067 texture_load(&img_bsod_falling_right, datadir +
1068 "/images/shared/bsod-falling-right.png",
1074 texture_load(&img_laptop_left[0], datadir +
1075 "/images/shared/laptop-left-0.png",
1078 texture_load(&img_laptop_left[1], datadir +
1079 "/images/shared/laptop-left-1.png",
1082 texture_load(&img_laptop_left[2], datadir +
1083 "/images/shared/laptop-left-2.png",
1086 texture_load(&img_laptop_right[0], datadir +
1087 "/images/shared/laptop-right-0.png",
1090 texture_load(&img_laptop_right[1], datadir +
1091 "/images/shared/laptop-right-1.png",
1094 texture_load(&img_laptop_right[2], datadir +
1095 "/images/shared/laptop-right-2.png",
1098 texture_load(&img_laptop_flat_left, datadir +
1099 "/images/shared/laptop-flat-left.png",
1102 texture_load(&img_laptop_flat_right, datadir +
1103 "/images/shared/laptop-flat-right.png",
1106 texture_load(&img_laptop_falling_left, datadir +
1107 "/images/shared/laptop-falling-left.png",
1110 texture_load(&img_laptop_falling_right, datadir +
1111 "/images/shared/laptop-falling-right.png",
1117 texture_load(&img_money_left[0], datadir +
1118 "/images/shared/bag-left-0.png",
1121 texture_load(&img_money_left[1], datadir +
1122 "/images/shared/bag-left-1.png",
1125 texture_load(&img_money_right[0], datadir +
1126 "/images/shared/bag-right-0.png",
1129 texture_load(&img_money_right[1], datadir +
1130 "/images/shared/bag-right-1.png",
1137 texture_load(&img_mints, datadir + "/images/shared/mints.png", USE_ALPHA);
1138 texture_load(&img_coffee, datadir + "/images/shared/coffee.png", USE_ALPHA);
1143 texture_load(&img_bullet, datadir + "/images/shared/bullet.png", USE_ALPHA);
1145 texture_load(&img_red_glow, datadir + "/images/shared/red-glow.png",
1152 texture_load(&img_distro[0], datadir + "/images/shared/distro-0.png",
1155 texture_load(&img_distro[1], datadir + "/images/shared/distro-1.png",
1158 texture_load(&img_distro[2], datadir + "/images/shared/distro-2.png",
1161 texture_load(&img_distro[3], datadir + "/images/shared/distro-3.png",
1167 texture_load(&tux_life, datadir + "/images/shared/tux-life.png",
1172 texture_load(&img_golden_herring, datadir + "/images/shared/golden-herring.png",
1176 /* Super background: */
1178 texture_load(&img_super_bkgd, datadir + "/images/shared/super-bkgd.png",
1182 /* Sound effects: */
1184 /* if (use_sound) // this will introduce SERIOUS bugs here ! because "load_sound"
1185 // initialize sounds[i] with the correct pointer's value:
1186 // NULL or something else. And it will be dangerous to
1187 // play with not-initialized pointers.
1188 // This is also true with if (use_music)
1189 Send a mail to me: neoneurone@users.sf.net, if you have another opinion. :)
1191 for (i = 0; i < NUM_SOUNDS; i++)
1192 sounds[i] = load_sound(datadir + soundfilenames[i]);
1195 herring_song = load_song(datadir + "/music/SALCON.MOD");
1199 /* Free shared data: */
1201 void unloadshared(void)
1205 for (i = 0; i < 3; i++)
1207 texture_free(&tux_right[i]);
1208 texture_free(&tux_left[i]);
1209 texture_free(&bigtux_right[i]);
1210 texture_free(&bigtux_left[i]);
1213 texture_free(&bigtux_right_jump);
1214 texture_free(&bigtux_left_jump);
1216 for (i = 0; i < 2; i++)
1218 texture_free(&cape_right[i]);
1219 texture_free(&cape_left[i]);
1220 texture_free(&bigcape_right[i]);
1221 texture_free(&bigcape_left[i]);
1224 texture_free(&ducktux_left);
1225 texture_free(&ducktux_right);
1227 texture_free(&skidtux_left);
1228 texture_free(&skidtux_right);
1230 for (i = 0; i < 4; i++)
1232 texture_free(&img_bsod_left[i]);
1233 texture_free(&img_bsod_right[i]);
1236 texture_free(&img_bsod_squished_left);
1237 texture_free(&img_bsod_squished_right);
1239 texture_free(&img_bsod_falling_left);
1240 texture_free(&img_bsod_falling_right);
1242 for (i = 0; i < 3; i++)
1244 texture_free(&img_laptop_left[i]);
1245 texture_free(&img_laptop_right[i]);
1248 texture_free(&img_laptop_flat_left);
1249 texture_free(&img_laptop_flat_right);
1251 texture_free(&img_laptop_falling_left);
1252 texture_free(&img_laptop_falling_right);
1254 for (i = 0; i < 2; i++)
1256 texture_free(&img_money_left[i]);
1257 texture_free(&img_money_right[i]);
1260 texture_free(&img_box_full);
1261 texture_free(&img_box_empty);
1263 texture_free(&img_water);
1264 for (i = 0; i < 3; i++)
1265 texture_free(&img_waves[i]);
1267 texture_free(&img_pole);
1268 texture_free(&img_poletop);
1270 for (i = 0; i < 2; i++)
1271 texture_free(&img_flag[i]);
1273 texture_free(&img_mints);
1274 texture_free(&img_coffee);
1276 for (i = 0; i < 4; i++)
1278 texture_free(&img_distro[i]);
1279 texture_free(&img_cloud[0][i]);
1280 texture_free(&img_cloud[1][i]);
1283 texture_free(&img_golden_herring);
1285 for (i = 0; i < NUM_SOUNDS; i++)
1286 free_chunk(sounds[i]);
1288 /* free the herring song */
1289 free_music( herring_song );
1293 /* Draw a tile on the screen: */
1295 void drawshape(float x, float y, unsigned char c)
1299 if (c == 'X' || c == 'x')
1300 texture_draw(&img_brick[0], x, y, NO_UPDATE);
1301 else if (c == 'Y' || c == 'y')
1302 texture_draw(&img_brick[1], x, y, NO_UPDATE);
1303 else if (c == 'A' || c =='B' || c == '!')
1304 texture_draw(&img_box_full, x, y, NO_UPDATE);
1306 texture_draw(&img_box_empty, x, y, NO_UPDATE);
1307 else if (c >= 'C' && c <= 'F')
1308 texture_draw(&img_cloud[0][c - 'C'], x, y, NO_UPDATE);
1309 else if (c >= 'c' && c <= 'f')
1310 texture_draw(&img_cloud[1][c - 'c'], x, y, NO_UPDATE);
1311 else if (c >= 'G' && c <= 'J')
1312 texture_draw(&img_bkgd_tile[0][c - 'G'], x, y, NO_UPDATE);
1313 else if (c >= 'g' && c <= 'j')
1314 texture_draw(&img_bkgd_tile[1][c - 'g'], x, y, NO_UPDATE);
1316 texture_draw(&img_solid[0], x, y, NO_UPDATE);
1318 texture_draw(&img_solid[1], x, y, NO_UPDATE);
1320 texture_draw(&img_solid[2], x, y, NO_UPDATE);
1322 texture_draw(&img_solid[3], x, y, NO_UPDATE);
1326 z = (frame / 2) % 6;
1329 texture_draw(&img_distro[z], x, y, NO_UPDATE);
1331 texture_draw(&img_distro[2], x, y, NO_UPDATE);
1333 texture_draw(&img_distro[1], x, y, NO_UPDATE);
1337 z = (frame / 3) % 3;
1339 texture_draw(&img_waves[z], x, y, NO_UPDATE);
1342 texture_draw(&img_poletop, x, y, NO_UPDATE);
1345 texture_draw(&img_pole, x, y, NO_UPDATE);
1350 z = (frame / 3) % 2;
1352 texture_draw(&img_flag[z], x + 16, y, NO_UPDATE);
1355 texture_draw(&img_water, x, y, NO_UPDATE);
1359 /* What shape is at some position? */
1361 unsigned char shape(float x, float y)
1370 if (yy >= 0 && yy < 15 && xx >= 0 && xx <= current_level.width)
1372 c = current_level.tiles[yy][xx];
1383 int issolid(float x, float y)
1385 if (isbrick(x, y) ||
1387 (shape(x, y) == '[') ||
1388 (shape(x, y) == '=') ||
1389 (shape(x, y) == ']') ||
1390 (shape(x, y) == 'A') ||
1391 (shape(x, y) == 'B') ||
1392 (shape(x, y) == '!') ||
1393 (shape(x, y) == 'a'))
1402 /* Is it a brick? */
1404 int isbrick(float x, float y)
1406 if (shape(x, y) == 'X' ||
1407 shape(x, y) == 'x' ||
1408 shape(x, y) == 'Y' ||
1420 int isice(float x, float y)
1422 if (shape(x, y) == '#')
1431 /* Is it a full box? */
1433 int isfullbox(float x, float y)
1435 if (shape(x, y) == 'A' ||
1436 shape(x, y) == 'B' ||
1445 /* Break a brick: */
1447 void trybreakbrick(float x, float y)
1451 if (shape(x, y) == 'x' || shape(x, y) == 'y')
1453 /* Get a distro from it: */
1455 add_bouncy_distro(((int)(x + 1) / 32) * 32,
1456 (int)(y / 32) * 32);
1458 if (counting_distros == NO)
1460 counting_distros = YES;
1461 distro_counter = 50;
1464 if (distro_counter <= 0)
1465 level_change(¤t_level,x, y, 'a');
1467 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1468 score = score + SCORE_DISTRO;
1473 /* Get rid of it: */
1475 level_change(¤t_level,x, y,'.');
1479 /* Replace it with broken bits: */
1481 add_broken_brick(((int)(x + 1) / 32) * 32,
1482 (int)(y / 32) * 32);
1485 /* Get some score: */
1487 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
1488 score = score + SCORE_BRICK;
1493 /* Bounce a brick: */
1495 void bumpbrick(float x, float y)
1497 add_bouncy_brick(((int)(x + 1) / 32) * 32,
1498 (int)(y / 32) * 32);
1500 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
1507 void tryemptybox(float x, float y, int col_side)
1509 if (!isfullbox(x, y))
1512 // according to the collision side, set the upgrade direction
1514 if(col_side == LEFT)
1521 case 'A': /* Box with a distro! */
1522 add_bouncy_distro(((int)(x + 1) / 32) * 32, (int)(y / 32) * 32 - 32);
1523 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1524 score = score + SCORE_DISTRO;
1527 case 'B': /* Add an upgrade! */
1528 if (tux.size == SMALL) /* Tux is small, add mints! */
1529 add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_MINTS);
1530 else /* Tux is big, add coffee: */
1531 add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_COFFEE);
1532 play_sound(sounds[SND_UPGRADE], SOUND_CENTER_SPEAKER);
1534 case '!': /* Add a golden herring */
1535 add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_HERRING);
1541 /* Empty the box: */
1542 level_change(¤t_level,x, y, 'a');
1546 /* Try to grab a distro: */
1548 void trygrabdistro(float x, float y, int bounciness)
1550 if (shape(x, y) == '$')
1552 level_change(¤t_level,x, y, '.');
1553 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1555 if (bounciness == BOUNCE)
1557 add_bouncy_distro(((int)(x + 1) / 32) * 32,
1558 (int)(y / 32) * 32);
1561 score = score + SCORE_DISTRO;
1566 /* Try to bump a bad guy from below: */
1568 void trybumpbadguy(float x, float y)
1575 for (i = 0; i < num_bad_guys; i++)
1577 if (bad_guys[i].base.alive &&
1578 bad_guys[i].base.x >= x - 32 && bad_guys[i].base.x <= x + 32 &&
1579 bad_guys[i].base.y >= y - 16 && bad_guys[i].base.y <= y + 16)
1581 if (bad_guys[i].kind == BAD_BSOD ||
1582 bad_guys[i].kind == BAD_LAPTOP)
1584 bad_guys[i].dying = FALLING;
1585 bad_guys[i].base.ym = -8;
1586 play_sound(sounds[SND_FALL], SOUND_CENTER_SPEAKER);
1594 for (i = 0; i < num_upgrades; i++)
1596 if (upgrades[i].base.alive && upgrades[i].base.height == 32 &&
1597 upgrades[i].base.x >= x - 32 && upgrades[i].base.x <= x + 32 &&
1598 upgrades[i].base.y >= y - 16 && upgrades[i].base.y <= y + 16)
1600 upgrades[i].base.xm = -upgrades[i].base.xm;
1601 upgrades[i].base.ym = -8;
1602 play_sound(sounds[SND_BUMP_UPGRADE], SOUND_CENTER_SPEAKER);
1608 void drawstatus(void)
1612 sprintf(str, "%d", score);
1613 text_draw(&white_text, "SCORE", 0, 0, 1, NO_UPDATE);
1614 text_draw(&gold_text, str, 96, 0, 1, NO_UPDATE);
1616 if(st_gl_mode != ST_GL_TEST)
1618 sprintf(str, "%d", hs_score);
1619 text_draw(&white_text, "HIGH", 0, 20, 1, NO_UPDATE);
1620 text_draw(&gold_text, str, 96, 20, 1, NO_UPDATE);
1624 text_draw(&white_text,"Press ESC To Return",0,20,1, NO_UPDATE);
1627 if (timer_get_left(&time_left) > TIME_WARNING || (frame % 10) < 5)
1629 sprintf(str, "%d", timer_get_left(&time_left) / 1000 );
1630 text_draw(&white_text, "TIME", 224, 0, 1, NO_UPDATE);
1631 text_draw(&gold_text, str, 304, 0, 1, NO_UPDATE);
1634 sprintf(str, "%d", distros);
1635 text_draw(&white_text, "DISTROS", screen->h, 0, 1, NO_UPDATE);
1636 text_draw(&gold_text, str, 608, 0, 1, NO_UPDATE);
1638 text_draw(&white_text, "LIVES", screen->h, 20, 1, NO_UPDATE);
1642 sprintf(str, "%2.1f", fps_fps);
1643 text_draw(&white_text, "FPS", screen->h, 40, 1, NO_UPDATE);
1644 text_draw(&gold_text, str, screen->h + 60, 40, 1, NO_UPDATE);
1647 for(i=0; i < tux.lives; ++i)
1649 texture_draw(&tux_life,565+(18*i),20,NO_UPDATE);
1654 void drawendscreen(void)
1658 clearscreen(0, 0, 0);
1660 text_drawf(&blue_text, "GAMEOVER", 0, 200, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
1662 sprintf(str, "SCORE: %d", score);
1663 text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
1665 sprintf(str, "DISTROS: %d", distros);
1666 text_drawf(&gold_text, str, 0, 256, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
1672 void drawresultscreen(void)
1676 clearscreen(0, 0, 0);
1678 text_drawf(&blue_text, "Result:", 0, 200, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
1680 sprintf(str, "SCORE: %d", score);
1681 text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
1683 sprintf(str, "DISTROS: %d", distros);
1684 text_drawf(&gold_text, str, 0, 256, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
1690 void savegame(int slot)
1692 char savefile[1024];
1696 sprintf(savefile,"%s/slot%d.save",st_save_dir,slot);
1698 fi = fopen(savefile, "wb");
1702 fprintf(stderr, "Warning: I could not open the slot file ");
1707 fputs(level_subset, fi);
1709 fwrite(&level,sizeof(int),1,fi);
1710 fwrite(&score,sizeof(int),1,fi);
1711 fwrite(&distros,sizeof(int),1,fi);
1712 fwrite(&scroll_x,sizeof(float),1,fi);
1713 fwrite(&tux,sizeof(player_type),1,fi);
1714 timer_fwrite(&tux.invincible_timer,fi);
1715 timer_fwrite(&tux.skidding_timer,fi);
1716 timer_fwrite(&tux.safe_timer,fi);
1717 timer_fwrite(&tux.frame_timer,fi);
1718 timer_fwrite(&time_left,fi);
1719 ui = st_get_ticks();
1720 fwrite(&ui,sizeof(int),1,fi);
1726 void loadgame(int slot)
1728 char savefile[1024];
1733 sprintf(savefile,"%s/slot%d.save",st_save_dir,slot);
1735 fi = fopen(savefile, "rb");
1739 fprintf(stderr, "Warning: I could not open the slot file ");
1746 fgets(str, 100, fi);
1747 strcpy(level_subset, str);
1748 level_subset[strlen(level_subset)-1] = '\0';
1749 fread(&level,sizeof(int),1,fi);
1752 level_free(¤t_level);
1753 if(level_load(¤t_level,level_subset,level) != 0)
1757 activate_bad_guys();
1759 level_load_gfx(¤t_level);
1761 level_load_song(¤t_level);
1763 update_time = st_get_ticks();
1765 fread(&score,sizeof(int),1,fi);
1766 fread(&distros,sizeof(int),1,fi);
1767 fread(&scroll_x,sizeof(float),1,fi);
1768 fread(&tux,sizeof(player_type),1,fi);
1769 timer_fread(&tux.invincible_timer,fi);
1770 timer_fread(&tux.skidding_timer,fi);
1771 timer_fread(&tux.safe_timer,fi);
1772 timer_fread(&tux.frame_timer,fi);
1773 timer_fread(&time_left,fi);
1774 fread(&ui,sizeof(int),1,fi);
1775 tux.hphysic.start_time += st_get_ticks() - ui;
1776 tux.vphysic.start_time += st_get_ticks() - ui;
1782 void slotinfo(char **pinfo, int slot)
1785 char slotfile[1024];
1789 sprintf(slotfile,"%s/slot%d.save",st_save_dir,slot);
1791 fi = fopen(slotfile, "rb");
1793 sprintf(tmp,"Slot %d - ",slot);
1801 fgets(str, 100, fi);
1802 str[strlen(str)-1] = '\0';
1804 strcat(tmp, " / Level:");
1805 fread(&slot_level,sizeof(int),1,fi);
1806 sprintf(str,"%d",slot_level);
1811 *pinfo = (char*) malloc(sizeof(char) * (strlen(tmp)+1));