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)
235 case SDL_JOYAXISMOTION:
236 switch(event.jaxis.axis)
239 if (event.jaxis.value < -JOYSTICK_DEAD_ZONE)
240 tux.input.left = DOWN;
241 else if (event.jaxis.value > JOYSTICK_DEAD_ZONE)
244 if (event.jaxis.value > JOYSTICK_DEAD_ZONE)
245 tux.input.right = DOWN;
246 else if (event.jaxis.value < -JOYSTICK_DEAD_ZONE)
247 tux.input.right = UP;
250 if (event.jaxis.value > JOYSTICK_DEAD_ZONE)
251 tux.input.down = DOWN;
252 else if (event.jaxis.value < -JOYSTICK_DEAD_ZONE)
255 /* Handle joystick for the menu */
258 if(tux.input.down == DOWN)
259 menuaction = MN_DOWN;
268 case SDL_JOYBUTTONDOWN:
269 if (event.jbutton.button == JOY_A)
271 else if (event.jbutton.button == JOY_B)
272 tux.input.fire = DOWN;
274 case SDL_JOYBUTTONUP:
275 if (event.jbutton.button == JOY_A)
277 else if (event.jbutton.button == JOY_B)
293 /* --- GAME ACTION! --- */
295 int game_action(void)
299 /* (tux_dying || next_level) */
300 if (tux.dying || next_level)
302 /* Tux either died, or reached the end of a level! */
309 /* End of a level! */
312 if(st_gl_mode != ST_GL_TEST)
319 level_free(¤t_level);
325 player_level_begin(&tux);
331 /* No more lives!? */
335 if(st_gl_mode != ST_GL_TEST)
338 if(st_gl_mode != ST_GL_TEST)
340 if (score > hs_score)
344 level_free(¤t_level);
349 } /* if (lives < 0) */
352 /* Either way, (re-)load the (next) level... */
354 player_level_begin(&tux);
356 level_free(¤t_level);
358 if (st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
360 if(level_load(¤t_level, level_subset) != 0)
365 if(level_load(¤t_level,level_subset,level) != 0)
373 level_load_gfx(¤t_level);
375 level_load_song(¤t_level);
376 if(st_gl_mode != ST_GL_TEST)
380 play_current_music();
385 /* Handle bouncy distros: */
387 for (i = 0; i < bouncy_distros.size(); i++)
389 bouncy_distro_action(&bouncy_distros[i]);
393 /* Handle broken bricks: */
395 for (i = 0; i < broken_bricks.size(); i++)
397 broken_brick_action(&broken_bricks[i]);
401 /* Handle distro counting: */
403 if (counting_distros == YES)
407 if (distro_counter <= 0)
408 counting_distros = -1;
412 /* Handle bouncy bricks: */
414 for (i = 0; i < bouncy_bricks.size(); i++)
416 bouncy_brick_action(&bouncy_bricks[i]);
420 /* Handle floating scores: */
422 for (i = 0; i < floating_scores.size(); i++)
424 floating_score_action(&floating_scores[i]);
428 /* Handle bullets: */
430 for (i = 0; i < bullets.size(); ++i)
432 bullet_action(&bullets[i]);
435 /* Handle upgrades: */
437 for (i = 0; i < upgrades.size(); i++)
439 upgrade_action(&upgrades[i]);
443 /* Handle bad guys: */
445 for (i = 0; i < bad_guys.size(); i++)
447 badguy_action(&bad_guys[i]);
450 /* Handle all possible collisions. */
456 /* --- GAME DRAW! --- */
464 if (tux.dying && (frame % 4) == 0)
465 clearscreen(255, 255, 255);
466 else if(timer_check(&super_bkgd_timer))
467 texture_draw(&img_super_bkgd, 0, 0, NO_UPDATE);
470 /* Draw the real background */
471 if(current_level.bkgd_image[0] != '\0')
473 s = (int)scroll_x / 30;
474 texture_draw_part(&img_bkgd,s,0,0,0,img_bkgd.w - s, img_bkgd.h, NO_UPDATE);
475 texture_draw_part(&img_bkgd,0,0,screen->w - s ,0,s,img_bkgd.h, NO_UPDATE);
479 clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue);
483 /* Draw background: */
485 for (y = 0; y < 15; ++y)
487 for (x = 0; x < 21; ++x)
489 drawshape(x * 32 - ((int)scroll_x % 32), y * 32,
490 current_level.tiles[(int)y][(int)x + (int)(scroll_x / 32)]);
495 /* (Bouncy bricks): */
497 for (i = 0; i < bouncy_bricks.size(); ++i)
499 bouncy_brick_draw(&bouncy_bricks[i]);
505 for (i = 0; i < bad_guys.size(); ++i)
507 badguy_draw(&bad_guys[i]);
516 for (i = 0; i < bullets.size(); ++i)
518 bullet_draw(&bullets[i]);
521 /* (Floating scores): */
523 for (i = 0; i < floating_scores.size(); ++i)
525 floating_score_draw(&floating_scores[i]);
531 for (i = 0; i < upgrades.size(); ++i)
533 upgrade_draw(&upgrades[i]);
537 /* (Bouncy distros): */
539 for (i = 0; i < bouncy_distros.size(); ++i)
541 bouncy_distro_draw(&bouncy_distros[i]);
545 /* (Broken bricks): */
547 for (i = 0; i < broken_bricks.size(); ++i)
549 broken_brick_draw(&broken_bricks[i]);
558 for(i = 0; i < x; ++i)
560 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);
562 fillrect(0,0,screen->w,screen->h,rand() % 50, rand() % 50, rand() % 50, 128);
563 text_drawf(&blue_text, "PAUSE - Press 'P' To Play", 0, 230, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
567 menu_process_current();
569 /* (Update it all!) */
576 /* --- GAME LOOP! --- */
578 int gameloop(const char * subset, int levelnb, int mode)
580 int fps_cnt, jump, done;
581 timer_type fps_timer, frame_timer;
582 timer_init(&fps_timer, YES);
583 timer_init(&frame_timer, YES);
594 strcpy(level_subset,subset);
596 if (st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
598 if (level_load(¤t_level, level_subset))
603 if(level_load(¤t_level, level_subset, level) != 0)
607 level_load_gfx(¤t_level);
609 level_load_song(¤t_level);
613 if(st_gl_mode != ST_GL_TEST)
618 if(st_gl_mode == ST_GL_PLAY || st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
621 timer_init(&time_left,YES);
624 if(st_gl_mode == ST_GL_LOAD_GAME)
628 /* --- MAIN GAME LOOP!!! --- */
635 timer_init(&fps_timer,YES);
636 timer_init(&frame_timer,YES);
641 clearscreen(0, 0, 0);
645 play_current_music();
648 while (SDL_PollEvent(&event))
656 /* Calculate the movement-factor */
657 frame_ratio = ((double)(update_time-last_update_time))/((double)FRAME_RATE);
658 if(frame_ratio > 1.5) /* Quick hack to correct the unprecise CPU clocks a little bit. */
659 frame_ratio = 1.5 + (frame_ratio - 1.5) * 0.85;
661 if(!timer_check(&frame_timer))
663 timer_start(&frame_timer,25);
669 tux.input.old_fire = tux.input.fire;
675 if(current_menu == &game_menu)
677 switch (menu_check(&game_menu))
680 st_pause_ticks_stop();
683 update_load_save_game_menu(&save_game_menu, NO);
686 update_load_save_game_menu(&load_game_menu, YES);
689 st_pause_ticks_stop();
694 else if(current_menu == &options_menu)
696 process_options_menu();
698 else if(current_menu == &save_game_menu )
700 process_save_load_game_menu(YES);
702 else if(current_menu == &load_game_menu )
704 process_save_load_game_menu(NO);
709 /* Handle actions: */
711 if(!game_pause && !show_menu)
713 /*float z = frame_ratio;
717 if (game_action() == 0)
719 /* == 0: no more lives */
720 /* == -1: continues */
732 if(debug_mode && debug_fps == YES)
735 /*Draw the current scene to the screen */
736 /*If the machine running the game is too slow
737 skip the drawing of the frame (so the calculations are more precise and
738 the FPS aren't affected).*/
739 /*if( ! fps_fps < 50.0 )
742 jump = YES;*/ /*FIXME: Implement this tweak right.*/
745 /* Time stops in pause mode */
746 if(game_pause || show_menu )
751 /* Set the time of the last update and the time of the current update */
752 last_update_time = update_time;
753 update_time = st_get_ticks();
756 /* Pause till next frame, if the machine running the game is too fast: */
757 /* FIXME: Works great for in OpenGl mode, where the CPU doesn't have to do that much. But
758 the results in SDL mode aren't perfect (thought the 100 FPS are reached), even on an AMD2500+. */
759 if(last_update_time >= update_time - 12 && jump != YES )
761 /*if((update_time - last_update_time) < 10)
762 SDL_Delay((11 - (update_time - last_update_time))/2);*/
768 if (timer_check(&time_left))
770 /* are we low on time ? */
771 if ((timer_get_left(&time_left) < TIME_WARNING)
772 && (get_current_music() != HURRYUP_MUSIC)) /* play the fast music */
774 set_current_music(HURRYUP_MUSIC);
775 play_current_music();
780 player_kill(&tux,KILL);
783 /* Calculate frames per second */
787 fps_fps = (1000.0 / (float)timer_get_gone(&fps_timer)) * (float)fps_cnt;
789 if(!timer_check(&fps_timer))
791 timer_start(&fps_timer,1000);
797 while (!done && !quit);
802 level_free(¤t_level);
813 /* Load graphics/sounds shared between all levels: */
815 void loadshared(void)
820 texture_load(&tux_right[0], datadir + "/images/shared/tux-right-0.png", USE_ALPHA);
821 texture_load(&tux_right[1], datadir + "/images/shared/tux-right-1.png", USE_ALPHA);
822 texture_load(&tux_right[2], datadir + "/images/shared/tux-right-2.png", USE_ALPHA);
824 texture_load(&tux_left[0], datadir + "/images/shared/tux-left-0.png", USE_ALPHA);
825 texture_load(&tux_left[1], datadir + "/images/shared/tux-left-1.png", USE_ALPHA);
826 texture_load(&tux_left[2], datadir + "/images/shared/tux-left-2.png", USE_ALPHA);
828 texture_load(&firetux_right[0], datadir + "/images/shared/firetux-right-0.png", USE_ALPHA);
829 texture_load(&firetux_right[1], datadir + "/images/shared/firetux-right-1.png", USE_ALPHA);
830 texture_load(&firetux_right[2], datadir + "/images/shared/firetux-right-2.png", USE_ALPHA);
832 texture_load(&firetux_left[0], datadir + "/images/shared/firetux-left-0.png", USE_ALPHA);
833 texture_load(&firetux_left[1], datadir + "/images/shared/firetux-left-1.png", USE_ALPHA);
834 texture_load(&firetux_left[2], datadir + "/images/shared/firetux-left-2.png", USE_ALPHA);
837 texture_load(&cape_right[0], datadir + "/images/shared/cape-right-0.png",
840 texture_load(&cape_right[1], datadir + "/images/shared/cape-right-1.png",
843 texture_load(&cape_left[0], datadir + "/images/shared/cape-left-0.png",
846 texture_load(&cape_left[1], datadir + "/images/shared/cape-left-1.png",
849 texture_load(&bigtux_right[0], datadir + "/images/shared/bigtux-right-0.png",
852 texture_load(&bigtux_right[1], datadir + "/images/shared/bigtux-right-1.png",
855 texture_load(&bigtux_right[2], datadir + "/images/shared/bigtux-right-2.png",
858 texture_load(&bigtux_right_jump, datadir + "/images/shared/bigtux-right-jump.png", USE_ALPHA);
860 texture_load(&bigtux_left[0], datadir + "/images/shared/bigtux-left-0.png",
863 texture_load(&bigtux_left[1], datadir + "/images/shared/bigtux-left-1.png",
866 texture_load(&bigtux_left[2], datadir + "/images/shared/bigtux-left-2.png",
869 texture_load(&bigtux_left_jump, datadir + "/images/shared/bigtux-left-jump.png", USE_ALPHA);
871 texture_load(&bigcape_right[0], datadir + "/images/shared/bigcape-right-0.png",
874 texture_load(&bigcape_right[1], datadir + "/images/shared/bigcape-right-1.png",
877 texture_load(&bigcape_left[0], datadir + "/images/shared/bigcape-left-0.png",
880 texture_load(&bigcape_left[1], datadir + "/images/shared/bigcape-left-1.png",
883 texture_load(&bigfiretux_right[0], datadir + "/images/shared/bigfiretux-right-0.png",
886 texture_load(&bigfiretux_right[1], datadir + "/images/shared/bigfiretux-right-1.png",
889 texture_load(&bigfiretux_right[2], datadir + "/images/shared/bigfiretux-right-2.png",
892 texture_load(&bigfiretux_right_jump, datadir + "/images/shared/bigfiretux-right-jump.png", USE_ALPHA);
894 texture_load(&bigfiretux_left[0], datadir + "/images/shared/bigfiretux-left-0.png",
897 texture_load(&bigfiretux_left[1], datadir + "/images/shared/bigfiretux-left-1.png",
900 texture_load(&bigfiretux_left[2], datadir + "/images/shared/bigfiretux-left-2.png",
903 texture_load(&bigfiretux_left_jump, datadir + "/images/shared/bigfiretux-left-jump.png", USE_ALPHA);
905 texture_load(&bigcape_right[0], datadir + "/images/shared/bigcape-right-0.png",
908 texture_load(&bigcape_right[1], datadir + "/images/shared/bigcape-right-1.png",
911 texture_load(&bigcape_left[0], datadir + "/images/shared/bigcape-left-0.png",
914 texture_load(&bigcape_left[1], datadir + "/images/shared/bigcape-left-1.png",
918 texture_load(&ducktux_right, datadir +
919 "/images/shared/ducktux-right.png",
922 texture_load(&ducktux_left, datadir +
923 "/images/shared/ducktux-left.png",
926 texture_load(&skidtux_right, datadir +
927 "/images/shared/skidtux-right.png",
930 texture_load(&skidtux_left, datadir +
931 "/images/shared/skidtux-left.png",
934 texture_load(&duckfiretux_right, datadir +
935 "/images/shared/duckfiretux-right.png",
938 texture_load(&duckfiretux_left, datadir +
939 "/images/shared/duckfiretux-left.png",
942 texture_load(&skidfiretux_right, datadir +
943 "/images/shared/skidfiretux-right.png",
946 texture_load(&skidfiretux_left, datadir +
947 "/images/shared/skidfiretux-left.png",
953 texture_load(&img_box_full, datadir + "/images/shared/box-full.png",
955 texture_load(&img_box_empty, datadir + "/images/shared/box-empty.png",
962 texture_load(&img_water, datadir + "/images/shared/water.png", IGNORE_ALPHA);
964 texture_load(&img_waves[0], datadir + "/images/shared/waves-0.png",
967 texture_load(&img_waves[1], datadir + "/images/shared/waves-1.png",
970 texture_load(&img_waves[2], datadir + "/images/shared/waves-2.png",
976 texture_load(&img_pole, datadir + "/images/shared/pole.png", USE_ALPHA);
977 texture_load(&img_poletop, datadir + "/images/shared/poletop.png",
983 texture_load(&img_flag[0], datadir + "/images/shared/flag-0.png",
985 texture_load(&img_flag[1], datadir + "/images/shared/flag-1.png",
991 texture_load(&img_cloud[0][0], datadir + "/images/shared/cloud-00.png",
994 texture_load(&img_cloud[0][1], datadir + "/images/shared/cloud-01.png",
997 texture_load(&img_cloud[0][2], datadir + "/images/shared/cloud-02.png",
1000 texture_load(&img_cloud[0][3], datadir + "/images/shared/cloud-03.png",
1004 texture_load(&img_cloud[1][0], datadir + "/images/shared/cloud-10.png",
1007 texture_load(&img_cloud[1][1], datadir + "/images/shared/cloud-11.png",
1010 texture_load(&img_cloud[1][2], datadir + "/images/shared/cloud-12.png",
1013 texture_load(&img_cloud[1][3], datadir + "/images/shared/cloud-13.png",
1021 texture_load(&img_bsod_left[0], datadir +
1022 "/images/shared/bsod-left-0.png",
1025 texture_load(&img_bsod_left[1], datadir +
1026 "/images/shared/bsod-left-1.png",
1029 texture_load(&img_bsod_left[2], datadir +
1030 "/images/shared/bsod-left-2.png",
1033 texture_load(&img_bsod_left[3], datadir +
1034 "/images/shared/bsod-left-3.png",
1037 texture_load(&img_bsod_right[0], datadir +
1038 "/images/shared/bsod-right-0.png",
1041 texture_load(&img_bsod_right[1], datadir +
1042 "/images/shared/bsod-right-1.png",
1045 texture_load(&img_bsod_right[2], datadir +
1046 "/images/shared/bsod-right-2.png",
1049 texture_load(&img_bsod_right[3], datadir +
1050 "/images/shared/bsod-right-3.png",
1053 texture_load(&img_bsod_squished_left, datadir +
1054 "/images/shared/bsod-squished-left.png",
1057 texture_load(&img_bsod_squished_right, datadir +
1058 "/images/shared/bsod-squished-right.png",
1061 texture_load(&img_bsod_falling_left, datadir +
1062 "/images/shared/bsod-falling-left.png",
1065 texture_load(&img_bsod_falling_right, datadir +
1066 "/images/shared/bsod-falling-right.png",
1072 texture_load(&img_laptop_left[0], datadir +
1073 "/images/shared/laptop-left-0.png",
1076 texture_load(&img_laptop_left[1], datadir +
1077 "/images/shared/laptop-left-1.png",
1080 texture_load(&img_laptop_left[2], datadir +
1081 "/images/shared/laptop-left-2.png",
1084 texture_load(&img_laptop_right[0], datadir +
1085 "/images/shared/laptop-right-0.png",
1088 texture_load(&img_laptop_right[1], datadir +
1089 "/images/shared/laptop-right-1.png",
1092 texture_load(&img_laptop_right[2], datadir +
1093 "/images/shared/laptop-right-2.png",
1096 texture_load(&img_laptop_flat_left, datadir +
1097 "/images/shared/laptop-flat-left.png",
1100 texture_load(&img_laptop_flat_right, datadir +
1101 "/images/shared/laptop-flat-right.png",
1104 texture_load(&img_laptop_falling_left, datadir +
1105 "/images/shared/laptop-falling-left.png",
1108 texture_load(&img_laptop_falling_right, datadir +
1109 "/images/shared/laptop-falling-right.png",
1115 texture_load(&img_money_left[0], datadir +
1116 "/images/shared/bag-left-0.png",
1119 texture_load(&img_money_left[1], datadir +
1120 "/images/shared/bag-left-1.png",
1123 texture_load(&img_money_right[0], datadir +
1124 "/images/shared/bag-right-0.png",
1127 texture_load(&img_money_right[1], datadir +
1128 "/images/shared/bag-right-1.png",
1135 texture_load(&img_mints, datadir + "/images/shared/mints.png", USE_ALPHA);
1136 texture_load(&img_coffee, datadir + "/images/shared/coffee.png", USE_ALPHA);
1141 texture_load(&img_bullet, datadir + "/images/shared/bullet.png", USE_ALPHA);
1143 texture_load(&img_red_glow, datadir + "/images/shared/red-glow.png",
1150 texture_load(&img_distro[0], datadir + "/images/shared/distro-0.png",
1153 texture_load(&img_distro[1], datadir + "/images/shared/distro-1.png",
1156 texture_load(&img_distro[2], datadir + "/images/shared/distro-2.png",
1159 texture_load(&img_distro[3], datadir + "/images/shared/distro-3.png",
1165 texture_load(&tux_life, datadir + "/images/shared/tux-life.png",
1170 texture_load(&img_golden_herring, datadir + "/images/shared/golden-herring.png",
1174 /* Super background: */
1176 texture_load(&img_super_bkgd, datadir + "/images/shared/super-bkgd.png",
1180 /* Sound effects: */
1182 /* if (use_sound) // this will introduce SERIOUS bugs here ! because "load_sound"
1183 // initialize sounds[i] with the correct pointer's value:
1184 // NULL or something else. And it will be dangerous to
1185 // play with not-initialized pointers.
1186 // This is also true with if (use_music)
1187 Send a mail to me: neoneurone@users.sf.net, if you have another opinion. :)
1189 for (i = 0; i < NUM_SOUNDS; i++)
1190 sounds[i] = load_sound(datadir + soundfilenames[i]);
1193 herring_song = load_song(datadir + "/music/SALCON.MOD");
1197 /* Free shared data: */
1199 void unloadshared(void)
1203 for (i = 0; i < 3; i++)
1205 texture_free(&tux_right[i]);
1206 texture_free(&tux_left[i]);
1207 texture_free(&bigtux_right[i]);
1208 texture_free(&bigtux_left[i]);
1211 texture_free(&bigtux_right_jump);
1212 texture_free(&bigtux_left_jump);
1214 for (i = 0; i < 2; i++)
1216 texture_free(&cape_right[i]);
1217 texture_free(&cape_left[i]);
1218 texture_free(&bigcape_right[i]);
1219 texture_free(&bigcape_left[i]);
1222 texture_free(&ducktux_left);
1223 texture_free(&ducktux_right);
1225 texture_free(&skidtux_left);
1226 texture_free(&skidtux_right);
1228 for (i = 0; i < 4; i++)
1230 texture_free(&img_bsod_left[i]);
1231 texture_free(&img_bsod_right[i]);
1234 texture_free(&img_bsod_squished_left);
1235 texture_free(&img_bsod_squished_right);
1237 texture_free(&img_bsod_falling_left);
1238 texture_free(&img_bsod_falling_right);
1240 for (i = 0; i < 3; i++)
1242 texture_free(&img_laptop_left[i]);
1243 texture_free(&img_laptop_right[i]);
1246 texture_free(&img_laptop_flat_left);
1247 texture_free(&img_laptop_flat_right);
1249 texture_free(&img_laptop_falling_left);
1250 texture_free(&img_laptop_falling_right);
1252 for (i = 0; i < 2; i++)
1254 texture_free(&img_money_left[i]);
1255 texture_free(&img_money_right[i]);
1258 texture_free(&img_box_full);
1259 texture_free(&img_box_empty);
1261 texture_free(&img_water);
1262 for (i = 0; i < 3; i++)
1263 texture_free(&img_waves[i]);
1265 texture_free(&img_pole);
1266 texture_free(&img_poletop);
1268 for (i = 0; i < 2; i++)
1269 texture_free(&img_flag[i]);
1271 texture_free(&img_mints);
1272 texture_free(&img_coffee);
1274 for (i = 0; i < 4; i++)
1276 texture_free(&img_distro[i]);
1277 texture_free(&img_cloud[0][i]);
1278 texture_free(&img_cloud[1][i]);
1281 texture_free(&img_golden_herring);
1283 for (i = 0; i < NUM_SOUNDS; i++)
1284 free_chunk(sounds[i]);
1286 /* free the herring song */
1287 free_music( herring_song );
1291 /* Draw a tile on the screen: */
1293 void drawshape(float x, float y, unsigned char c)
1297 if (c == 'X' || c == 'x')
1298 texture_draw(&img_brick[0], x, y, NO_UPDATE);
1299 else if (c == 'Y' || c == 'y')
1300 texture_draw(&img_brick[1], x, y, NO_UPDATE);
1301 else if (c == 'A' || c =='B' || c == '!')
1302 texture_draw(&img_box_full, x, y, NO_UPDATE);
1304 texture_draw(&img_box_empty, x, y, NO_UPDATE);
1305 else if (c >= 'C' && c <= 'F')
1306 texture_draw(&img_cloud[0][c - 'C'], x, y, NO_UPDATE);
1307 else if (c >= 'c' && c <= 'f')
1308 texture_draw(&img_cloud[1][c - 'c'], x, y, NO_UPDATE);
1309 else if (c >= 'G' && c <= 'J')
1310 texture_draw(&img_bkgd_tile[0][c - 'G'], x, y, NO_UPDATE);
1311 else if (c >= 'g' && c <= 'j')
1312 texture_draw(&img_bkgd_tile[1][c - 'g'], x, y, NO_UPDATE);
1314 texture_draw(&img_solid[0], x, y, NO_UPDATE);
1316 texture_draw(&img_solid[1], x, y, NO_UPDATE);
1318 texture_draw(&img_solid[2], x, y, NO_UPDATE);
1320 texture_draw(&img_solid[3], x, y, NO_UPDATE);
1324 z = (frame / 2) % 6;
1327 texture_draw(&img_distro[z], x, y, NO_UPDATE);
1329 texture_draw(&img_distro[2], x, y, NO_UPDATE);
1331 texture_draw(&img_distro[1], x, y, NO_UPDATE);
1335 z = (frame / 3) % 3;
1337 texture_draw(&img_waves[z], x, y, NO_UPDATE);
1340 texture_draw(&img_poletop, x, y, NO_UPDATE);
1343 texture_draw(&img_pole, x, y, NO_UPDATE);
1348 z = (frame / 3) % 2;
1350 texture_draw(&img_flag[z], x + 16, y, NO_UPDATE);
1353 texture_draw(&img_water, x, y, NO_UPDATE);
1357 /* What shape is at some position? */
1359 unsigned char shape(float x, float y)
1368 if (yy >= 0 && yy < 15 && xx >= 0 && xx <= current_level.width)
1370 c = current_level.tiles[yy][xx];
1381 int issolid(float x, float y)
1383 if (isbrick(x, y) ||
1385 (shape(x, y) == '[') ||
1386 (shape(x, y) == '=') ||
1387 (shape(x, y) == ']') ||
1388 (shape(x, y) == 'A') ||
1389 (shape(x, y) == 'B') ||
1390 (shape(x, y) == '!') ||
1391 (shape(x, y) == 'a'))
1400 /* Is it a brick? */
1402 int isbrick(float x, float y)
1404 if (shape(x, y) == 'X' ||
1405 shape(x, y) == 'x' ||
1406 shape(x, y) == 'Y' ||
1418 int isice(float x, float y)
1420 if (shape(x, y) == '#')
1429 /* Is it a full box? */
1431 int isfullbox(float x, float y)
1433 if (shape(x, y) == 'A' ||
1434 shape(x, y) == 'B' ||
1443 /* Break a brick: */
1445 void trybreakbrick(float x, float y)
1449 if (shape(x, y) == 'x' || shape(x, y) == 'y')
1451 /* Get a distro from it: */
1453 add_bouncy_distro(((int)(x + 1) / 32) * 32,
1454 (int)(y / 32) * 32);
1456 if (counting_distros == NO)
1458 counting_distros = YES;
1459 distro_counter = 50;
1462 if (distro_counter <= 0)
1463 level_change(¤t_level,x, y, 'a');
1465 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1466 score = score + SCORE_DISTRO;
1471 /* Get rid of it: */
1473 level_change(¤t_level,x, y,'.');
1477 /* Replace it with broken bits: */
1479 add_broken_brick(((int)(x + 1) / 32) * 32,
1480 (int)(y / 32) * 32);
1483 /* Get some score: */
1485 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
1486 score = score + SCORE_BRICK;
1491 /* Bounce a brick: */
1493 void bumpbrick(float x, float y)
1495 add_bouncy_brick(((int)(x + 1) / 32) * 32,
1496 (int)(y / 32) * 32);
1498 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
1505 void tryemptybox(float x, float y, int col_side)
1507 if (!isfullbox(x, y))
1510 // according to the collision side, set the upgrade direction
1512 if(col_side == LEFT)
1519 case 'A': /* Box with a distro! */
1520 add_bouncy_distro(((int)(x + 1) / 32) * 32, (int)(y / 32) * 32 - 32);
1521 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1522 score = score + SCORE_DISTRO;
1525 case 'B': /* Add an upgrade! */
1526 if (tux.size == SMALL) /* Tux is small, add mints! */
1527 add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_MINTS);
1528 else /* Tux is big, add coffee: */
1529 add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_COFFEE);
1530 play_sound(sounds[SND_UPGRADE], SOUND_CENTER_SPEAKER);
1532 case '!': /* Add a golden herring */
1533 add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_HERRING);
1539 /* Empty the box: */
1540 level_change(¤t_level,x, y, 'a');
1544 /* Try to grab a distro: */
1546 void trygrabdistro(float x, float y, int bounciness)
1548 if (shape(x, y) == '$')
1550 level_change(¤t_level,x, y, '.');
1551 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1553 if (bounciness == BOUNCE)
1555 add_bouncy_distro(((int)(x + 1) / 32) * 32,
1556 (int)(y / 32) * 32);
1559 score = score + SCORE_DISTRO;
1564 /* Try to bump a bad guy from below: */
1566 void trybumpbadguy(float x, float y)
1573 for (i = 0; i < bad_guys.size(); i++)
1575 if (bad_guys[i].base.x >= x - 32 && bad_guys[i].base.x <= x + 32 &&
1576 bad_guys[i].base.y >= y - 16 && bad_guys[i].base.y <= y + 16)
1578 if (bad_guys[i].kind == BAD_BSOD ||
1579 bad_guys[i].kind == BAD_LAPTOP)
1581 bad_guys[i].dying = FALLING;
1582 bad_guys[i].base.ym = -8;
1583 play_sound(sounds[SND_FALL], SOUND_CENTER_SPEAKER);
1591 for (i = 0; i < upgrades.size(); i++)
1593 if (upgrades[i].base.height == 32 &&
1594 upgrades[i].base.x >= x - 32 && upgrades[i].base.x <= x + 32 &&
1595 upgrades[i].base.y >= y - 16 && upgrades[i].base.y <= y + 16)
1597 upgrades[i].base.xm = -upgrades[i].base.xm;
1598 upgrades[i].base.ym = -8;
1599 play_sound(sounds[SND_BUMP_UPGRADE], SOUND_CENTER_SPEAKER);
1605 void drawstatus(void)
1609 sprintf(str, "%d", score);
1610 text_draw(&white_text, "SCORE", 0, 0, 1, NO_UPDATE);
1611 text_draw(&gold_text, str, 96, 0, 1, NO_UPDATE);
1613 if(st_gl_mode != ST_GL_TEST)
1615 sprintf(str, "%d", hs_score);
1616 text_draw(&white_text, "HIGH", 0, 20, 1, NO_UPDATE);
1617 text_draw(&gold_text, str, 96, 20, 1, NO_UPDATE);
1621 text_draw(&white_text,"Press ESC To Return",0,20,1, NO_UPDATE);
1624 if (timer_get_left(&time_left) > TIME_WARNING || (frame % 10) < 5)
1626 sprintf(str, "%d", timer_get_left(&time_left) / 1000 );
1627 text_draw(&white_text, "TIME", 224, 0, 1, NO_UPDATE);
1628 text_draw(&gold_text, str, 304, 0, 1, NO_UPDATE);
1631 sprintf(str, "%d", distros);
1632 text_draw(&white_text, "DISTROS", screen->h, 0, 1, NO_UPDATE);
1633 text_draw(&gold_text, str, 608, 0, 1, NO_UPDATE);
1635 text_draw(&white_text, "LIVES", screen->h, 20, 1, NO_UPDATE);
1639 sprintf(str, "%2.1f", fps_fps);
1640 text_draw(&white_text, "FPS", screen->h, 40, 1, NO_UPDATE);
1641 text_draw(&gold_text, str, screen->h + 60, 40, 1, NO_UPDATE);
1644 for(i=0; i < tux.lives; ++i)
1646 texture_draw(&tux_life,565+(18*i),20,NO_UPDATE);
1651 void drawendscreen(void)
1655 clearscreen(0, 0, 0);
1657 text_drawf(&blue_text, "GAMEOVER", 0, 200, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
1659 sprintf(str, "SCORE: %d", score);
1660 text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
1662 sprintf(str, "DISTROS: %d", distros);
1663 text_drawf(&gold_text, str, 0, 256, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
1669 void drawresultscreen(void)
1673 clearscreen(0, 0, 0);
1675 text_drawf(&blue_text, "Result:", 0, 200, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
1677 sprintf(str, "SCORE: %d", score);
1678 text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
1680 sprintf(str, "DISTROS: %d", distros);
1681 text_drawf(&gold_text, str, 0, 256, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
1687 void savegame(int slot)
1689 char savefile[1024];
1693 sprintf(savefile,"%s/slot%d.save",st_save_dir,slot);
1695 fi = fopen(savefile, "wb");
1699 fprintf(stderr, "Warning: I could not open the slot file ");
1704 fputs(level_subset, fi);
1706 fwrite(&level,sizeof(int),1,fi);
1707 fwrite(&score,sizeof(int),1,fi);
1708 fwrite(&distros,sizeof(int),1,fi);
1709 fwrite(&scroll_x,sizeof(float),1,fi);
1710 fwrite(&tux,sizeof(player_type),1,fi);
1711 timer_fwrite(&tux.invincible_timer,fi);
1712 timer_fwrite(&tux.skidding_timer,fi);
1713 timer_fwrite(&tux.safe_timer,fi);
1714 timer_fwrite(&tux.frame_timer,fi);
1715 timer_fwrite(&time_left,fi);
1716 ui = st_get_ticks();
1717 fwrite(&ui,sizeof(int),1,fi);
1723 void loadgame(int slot)
1725 char savefile[1024];
1730 sprintf(savefile,"%s/slot%d.save",st_save_dir,slot);
1732 fi = fopen(savefile, "rb");
1736 fprintf(stderr, "Warning: I could not open the slot file ");
1743 fgets(str, 100, fi);
1744 strcpy(level_subset, str);
1745 level_subset[strlen(level_subset)-1] = '\0';
1746 fread(&level,sizeof(int),1,fi);
1749 level_free(¤t_level);
1750 if(level_load(¤t_level,level_subset,level) != 0)
1754 activate_bad_guys();
1756 level_load_gfx(¤t_level);
1758 level_load_song(¤t_level);
1760 update_time = st_get_ticks();
1762 fread(&score,sizeof(int),1,fi);
1763 fread(&distros,sizeof(int),1,fi);
1764 fread(&scroll_x,sizeof(float),1,fi);
1765 fread(&tux,sizeof(player_type),1,fi);
1766 timer_fread(&tux.invincible_timer,fi);
1767 timer_fread(&tux.skidding_timer,fi);
1768 timer_fread(&tux.safe_timer,fi);
1769 timer_fread(&tux.frame_timer,fi);
1770 timer_fread(&time_left,fi);
1771 fread(&ui,sizeof(int),1,fi);
1772 tux.hphysic.start_time += st_get_ticks() - ui;
1773 tux.vphysic.start_time += st_get_ticks() - ui;
1779 void slotinfo(char **pinfo, int slot)
1782 char slotfile[1024];
1786 sprintf(slotfile,"%s/slot%d.save",st_save_dir,slot);
1788 fi = fopen(slotfile, "rb");
1790 sprintf(tmp,"Slot %d - ",slot);
1798 fgets(str, 100, fi);
1799 str[strlen(str)-1] = '\0';
1801 strcat(tmp, " / Level:");
1802 fread(&slot_level,sizeof(int),1,fi);
1803 sprintf(str,"%d",slot_level);
1808 *pinfo = (char*) malloc(sizeof(char) * (strlen(tmp)+1));