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! --- */
465 if (tux.dying && (frame % 4) == 0)
466 clearscreen(255, 255, 255);
467 else if(timer_check(&super_bkgd_timer))
468 texture_draw(&img_super_bkgd, 0, 0, NO_UPDATE);
471 /* Draw the real background */
472 if(current_level.bkgd_image[0] != '\0')
474 s = (int)scroll_x / 30;
475 texture_draw_part(&img_bkgd,s,0,0,0,img_bkgd.w - s, img_bkgd.h, NO_UPDATE);
476 texture_draw_part(&img_bkgd,0,0,screen->w - s ,0,s,img_bkgd.h, NO_UPDATE);
480 clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue);
484 /* Draw background: */
486 for (y = 0; y < 15; ++y)
488 for (x = 0; x < 21; ++x)
490 drawshape(x * 32 - ((int)scroll_x % 32), y * 32,
491 current_level.tiles[(int)y][(int)x + (int)(scroll_x / 32)]);
496 /* (Bouncy bricks): */
498 for (i = 0; i < bouncy_bricks.size(); ++i)
500 bouncy_brick_draw(&bouncy_bricks[i]);
506 for (i = 0; i < bad_guys.size(); ++i)
508 badguy_draw(&bad_guys[i]);
517 for (i = 0; i < bullets.size(); ++i)
519 bullet_draw(&bullets[i]);
522 /* (Floating scores): */
524 for (i = 0; i < floating_scores.size(); ++i)
526 floating_score_draw(&floating_scores[i]);
532 for (i = 0; i < upgrades.size(); ++i)
534 upgrade_draw(&upgrades[i]);
538 /* (Bouncy distros): */
540 for (i = 0; i < bouncy_distros.size(); ++i)
542 bouncy_distro_draw(&bouncy_distros[i]);
546 /* (Broken bricks): */
548 for (i = 0; i < broken_bricks.size(); ++i)
550 broken_brick_draw(&broken_bricks[i]);
559 for(i = 0; i < x; ++i)
561 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);
563 fillrect(0,0,screen->w,screen->h,rand() % 50, rand() % 50, rand() % 50, 128);
564 text_drawf(&blue_text, "PAUSE - Press 'P' To Play", 0, 230, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
568 menu_process_current();
570 /* (Update it all!) */
577 /* --- GAME LOOP! --- */
579 int gameloop(const char * subset, int levelnb, int mode)
581 int fps_cnt, jump, done;
582 timer_type fps_timer, frame_timer;
583 timer_init(&fps_timer, YES);
584 timer_init(&frame_timer, YES);
595 strcpy(level_subset,subset);
597 if (st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
599 if (level_load(¤t_level, level_subset))
604 if(level_load(¤t_level, level_subset, level) != 0)
608 level_load_gfx(¤t_level);
610 level_load_song(¤t_level);
614 if(st_gl_mode != ST_GL_TEST)
619 if(st_gl_mode == ST_GL_PLAY || st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
622 timer_init(&time_left,YES);
625 if(st_gl_mode == ST_GL_LOAD_GAME)
629 /* --- MAIN GAME LOOP!!! --- */
636 timer_init(&fps_timer,YES);
637 timer_init(&frame_timer,YES);
642 clearscreen(0, 0, 0);
646 play_current_music();
649 while (SDL_PollEvent(&event))
657 /* Calculate the movement-factor */
658 frame_ratio = ((double)(update_time-last_update_time))/((double)FRAME_RATE);
659 if(frame_ratio > 1.5) /* Quick hack to correct the unprecise CPU clocks a little bit. */
660 frame_ratio = 1.5 + (frame_ratio - 1.5) * 0.85;
662 if(!timer_check(&frame_timer))
664 timer_start(&frame_timer,25);
670 tux.input.old_fire = tux.input.fire;
676 if(current_menu == &game_menu)
678 switch (menu_check(&game_menu))
681 st_pause_ticks_stop();
684 update_load_save_game_menu(&save_game_menu, NO);
687 update_load_save_game_menu(&load_game_menu, YES);
690 st_pause_ticks_stop();
695 else if(current_menu == &options_menu)
697 process_options_menu();
699 else if(current_menu == &save_game_menu )
701 process_save_load_game_menu(YES);
703 else if(current_menu == &load_game_menu )
705 process_save_load_game_menu(NO);
710 /* Handle actions: */
712 if(!game_pause && !show_menu)
714 /*float z = frame_ratio;
718 if (game_action() == 0)
720 /* == 0: no more lives */
721 /* == -1: continues */
733 if(debug_mode && debug_fps == YES)
736 /*Draw the current scene to the screen */
737 /*If the machine running the game is too slow
738 skip the drawing of the frame (so the calculations are more precise and
739 the FPS aren't affected).*/
740 /*if( ! fps_fps < 50.0 )
743 jump = YES;*/ /*FIXME: Implement this tweak right.*/
746 /* Time stops in pause mode */
747 if(game_pause || show_menu )
752 /* Set the time of the last update and the time of the current update */
753 last_update_time = update_time;
754 update_time = st_get_ticks();
757 /* Pause till next frame, if the machine running the game is too fast: */
758 /* FIXME: Works great for in OpenGl mode, where the CPU doesn't have to do that much. But
759 the results in SDL mode aren't perfect (thought the 100 FPS are reached), even on an AMD2500+. */
760 if(last_update_time >= update_time - 12 && jump != YES )
762 /*if((update_time - last_update_time) < 10)
763 SDL_Delay((11 - (update_time - last_update_time))/2);*/
769 if (timer_check(&time_left))
771 /* are we low on time ? */
772 if ((timer_get_left(&time_left) < TIME_WARNING)
773 && (get_current_music() != HURRYUP_MUSIC)) /* play the fast music */
775 set_current_music(HURRYUP_MUSIC);
776 play_current_music();
781 player_kill(&tux,KILL);
784 /* Calculate frames per second */
788 fps_fps = (1000.0 / (float)timer_get_gone(&fps_timer)) * (float)fps_cnt;
790 if(!timer_check(&fps_timer))
792 timer_start(&fps_timer,1000);
798 while (!done && !quit);
803 level_free(¤t_level);
814 /* Load graphics/sounds shared between all levels: */
816 void loadshared(void)
821 texture_load(&tux_right[0], datadir + "/images/shared/tux-right-0.png", USE_ALPHA);
822 texture_load(&tux_right[1], datadir + "/images/shared/tux-right-1.png", USE_ALPHA);
823 texture_load(&tux_right[2], datadir + "/images/shared/tux-right-2.png", USE_ALPHA);
825 texture_load(&tux_left[0], datadir + "/images/shared/tux-left-0.png", USE_ALPHA);
826 texture_load(&tux_left[1], datadir + "/images/shared/tux-left-1.png", USE_ALPHA);
827 texture_load(&tux_left[2], datadir + "/images/shared/tux-left-2.png", USE_ALPHA);
829 texture_load(&firetux_right[0], datadir + "/images/shared/firetux-right-0.png", USE_ALPHA);
830 texture_load(&firetux_right[1], datadir + "/images/shared/firetux-right-1.png", USE_ALPHA);
831 texture_load(&firetux_right[2], datadir + "/images/shared/firetux-right-2.png", USE_ALPHA);
833 texture_load(&firetux_left[0], datadir + "/images/shared/firetux-left-0.png", USE_ALPHA);
834 texture_load(&firetux_left[1], datadir + "/images/shared/firetux-left-1.png", USE_ALPHA);
835 texture_load(&firetux_left[2], datadir + "/images/shared/firetux-left-2.png", USE_ALPHA);
838 texture_load(&cape_right[0], datadir + "/images/shared/cape-right-0.png",
841 texture_load(&cape_right[1], datadir + "/images/shared/cape-right-1.png",
844 texture_load(&cape_left[0], datadir + "/images/shared/cape-left-0.png",
847 texture_load(&cape_left[1], datadir + "/images/shared/cape-left-1.png",
850 texture_load(&bigtux_right[0], datadir + "/images/shared/bigtux-right-0.png",
853 texture_load(&bigtux_right[1], datadir + "/images/shared/bigtux-right-1.png",
856 texture_load(&bigtux_right[2], datadir + "/images/shared/bigtux-right-2.png",
859 texture_load(&bigtux_right_jump, datadir + "/images/shared/bigtux-right-jump.png", USE_ALPHA);
861 texture_load(&bigtux_left[0], datadir + "/images/shared/bigtux-left-0.png",
864 texture_load(&bigtux_left[1], datadir + "/images/shared/bigtux-left-1.png",
867 texture_load(&bigtux_left[2], datadir + "/images/shared/bigtux-left-2.png",
870 texture_load(&bigtux_left_jump, datadir + "/images/shared/bigtux-left-jump.png", USE_ALPHA);
872 texture_load(&bigcape_right[0], datadir + "/images/shared/bigcape-right-0.png",
875 texture_load(&bigcape_right[1], datadir + "/images/shared/bigcape-right-1.png",
878 texture_load(&bigcape_left[0], datadir + "/images/shared/bigcape-left-0.png",
881 texture_load(&bigcape_left[1], datadir + "/images/shared/bigcape-left-1.png",
884 texture_load(&bigfiretux_right[0], datadir + "/images/shared/bigfiretux-right-0.png",
887 texture_load(&bigfiretux_right[1], datadir + "/images/shared/bigfiretux-right-1.png",
890 texture_load(&bigfiretux_right[2], datadir + "/images/shared/bigfiretux-right-2.png",
893 texture_load(&bigfiretux_right_jump, datadir + "/images/shared/bigfiretux-right-jump.png", USE_ALPHA);
895 texture_load(&bigfiretux_left[0], datadir + "/images/shared/bigfiretux-left-0.png",
898 texture_load(&bigfiretux_left[1], datadir + "/images/shared/bigfiretux-left-1.png",
901 texture_load(&bigfiretux_left[2], datadir + "/images/shared/bigfiretux-left-2.png",
904 texture_load(&bigfiretux_left_jump, datadir + "/images/shared/bigfiretux-left-jump.png", USE_ALPHA);
906 texture_load(&bigcape_right[0], datadir + "/images/shared/bigcape-right-0.png",
909 texture_load(&bigcape_right[1], datadir + "/images/shared/bigcape-right-1.png",
912 texture_load(&bigcape_left[0], datadir + "/images/shared/bigcape-left-0.png",
915 texture_load(&bigcape_left[1], datadir + "/images/shared/bigcape-left-1.png",
919 texture_load(&ducktux_right, datadir +
920 "/images/shared/ducktux-right.png",
923 texture_load(&ducktux_left, datadir +
924 "/images/shared/ducktux-left.png",
927 texture_load(&skidtux_right, datadir +
928 "/images/shared/skidtux-right.png",
931 texture_load(&skidtux_left, datadir +
932 "/images/shared/skidtux-left.png",
935 texture_load(&duckfiretux_right, datadir +
936 "/images/shared/duckfiretux-right.png",
939 texture_load(&duckfiretux_left, datadir +
940 "/images/shared/duckfiretux-left.png",
943 texture_load(&skidfiretux_right, datadir +
944 "/images/shared/skidfiretux-right.png",
947 texture_load(&skidfiretux_left, datadir +
948 "/images/shared/skidfiretux-left.png",
954 texture_load(&img_box_full, datadir + "/images/shared/box-full.png",
956 texture_load(&img_box_empty, datadir + "/images/shared/box-empty.png",
963 texture_load(&img_water, datadir + "/images/shared/water.png", IGNORE_ALPHA);
965 texture_load(&img_waves[0], datadir + "/images/shared/waves-0.png",
968 texture_load(&img_waves[1], datadir + "/images/shared/waves-1.png",
971 texture_load(&img_waves[2], datadir + "/images/shared/waves-2.png",
977 texture_load(&img_pole, datadir + "/images/shared/pole.png", USE_ALPHA);
978 texture_load(&img_poletop, datadir + "/images/shared/poletop.png",
984 texture_load(&img_flag[0], datadir + "/images/shared/flag-0.png",
986 texture_load(&img_flag[1], datadir + "/images/shared/flag-1.png",
992 texture_load(&img_cloud[0][0], datadir + "/images/shared/cloud-00.png",
995 texture_load(&img_cloud[0][1], datadir + "/images/shared/cloud-01.png",
998 texture_load(&img_cloud[0][2], datadir + "/images/shared/cloud-02.png",
1001 texture_load(&img_cloud[0][3], datadir + "/images/shared/cloud-03.png",
1005 texture_load(&img_cloud[1][0], datadir + "/images/shared/cloud-10.png",
1008 texture_load(&img_cloud[1][1], datadir + "/images/shared/cloud-11.png",
1011 texture_load(&img_cloud[1][2], datadir + "/images/shared/cloud-12.png",
1014 texture_load(&img_cloud[1][3], datadir + "/images/shared/cloud-13.png",
1022 texture_load(&img_bsod_left[0], datadir +
1023 "/images/shared/bsod-left-0.png",
1026 texture_load(&img_bsod_left[1], datadir +
1027 "/images/shared/bsod-left-1.png",
1030 texture_load(&img_bsod_left[2], datadir +
1031 "/images/shared/bsod-left-2.png",
1034 texture_load(&img_bsod_left[3], datadir +
1035 "/images/shared/bsod-left-3.png",
1038 texture_load(&img_bsod_right[0], datadir +
1039 "/images/shared/bsod-right-0.png",
1042 texture_load(&img_bsod_right[1], datadir +
1043 "/images/shared/bsod-right-1.png",
1046 texture_load(&img_bsod_right[2], datadir +
1047 "/images/shared/bsod-right-2.png",
1050 texture_load(&img_bsod_right[3], datadir +
1051 "/images/shared/bsod-right-3.png",
1054 texture_load(&img_bsod_squished_left, datadir +
1055 "/images/shared/bsod-squished-left.png",
1058 texture_load(&img_bsod_squished_right, datadir +
1059 "/images/shared/bsod-squished-right.png",
1062 texture_load(&img_bsod_falling_left, datadir +
1063 "/images/shared/bsod-falling-left.png",
1066 texture_load(&img_bsod_falling_right, datadir +
1067 "/images/shared/bsod-falling-right.png",
1073 texture_load(&img_laptop_left[0], datadir +
1074 "/images/shared/laptop-left-0.png",
1077 texture_load(&img_laptop_left[1], datadir +
1078 "/images/shared/laptop-left-1.png",
1081 texture_load(&img_laptop_left[2], datadir +
1082 "/images/shared/laptop-left-2.png",
1085 texture_load(&img_laptop_right[0], datadir +
1086 "/images/shared/laptop-right-0.png",
1089 texture_load(&img_laptop_right[1], datadir +
1090 "/images/shared/laptop-right-1.png",
1093 texture_load(&img_laptop_right[2], datadir +
1094 "/images/shared/laptop-right-2.png",
1097 texture_load(&img_laptop_flat_left, datadir +
1098 "/images/shared/laptop-flat-left.png",
1101 texture_load(&img_laptop_flat_right, datadir +
1102 "/images/shared/laptop-flat-right.png",
1105 texture_load(&img_laptop_falling_left, datadir +
1106 "/images/shared/laptop-falling-left.png",
1109 texture_load(&img_laptop_falling_right, datadir +
1110 "/images/shared/laptop-falling-right.png",
1116 texture_load(&img_money_left[0], datadir +
1117 "/images/shared/bag-left-0.png",
1120 texture_load(&img_money_left[1], datadir +
1121 "/images/shared/bag-left-1.png",
1124 texture_load(&img_money_right[0], datadir +
1125 "/images/shared/bag-right-0.png",
1128 texture_load(&img_money_right[1], datadir +
1129 "/images/shared/bag-right-1.png",
1136 texture_load(&img_mints, datadir + "/images/shared/mints.png", USE_ALPHA);
1137 texture_load(&img_coffee, datadir + "/images/shared/coffee.png", USE_ALPHA);
1142 texture_load(&img_bullet, datadir + "/images/shared/bullet.png", USE_ALPHA);
1144 texture_load(&img_red_glow, datadir + "/images/shared/red-glow.png",
1151 texture_load(&img_distro[0], datadir + "/images/shared/distro-0.png",
1154 texture_load(&img_distro[1], datadir + "/images/shared/distro-1.png",
1157 texture_load(&img_distro[2], datadir + "/images/shared/distro-2.png",
1160 texture_load(&img_distro[3], datadir + "/images/shared/distro-3.png",
1166 texture_load(&tux_life, datadir + "/images/shared/tux-life.png",
1171 texture_load(&img_golden_herring, datadir + "/images/shared/golden-herring.png",
1175 /* Super background: */
1177 texture_load(&img_super_bkgd, datadir + "/images/shared/super-bkgd.png",
1181 /* Sound effects: */
1183 /* if (use_sound) // this will introduce SERIOUS bugs here ! because "load_sound"
1184 // initialize sounds[i] with the correct pointer's value:
1185 // NULL or something else. And it will be dangerous to
1186 // play with not-initialized pointers.
1187 // This is also true with if (use_music)
1188 Send a mail to me: neoneurone@users.sf.net, if you have another opinion. :)
1190 for (i = 0; i < NUM_SOUNDS; i++)
1191 sounds[i] = load_sound(datadir + soundfilenames[i]);
1194 herring_song = load_song(datadir + "/music/SALCON.MOD");
1198 /* Free shared data: */
1200 void unloadshared(void)
1204 for (i = 0; i < 3; i++)
1206 texture_free(&tux_right[i]);
1207 texture_free(&tux_left[i]);
1208 texture_free(&bigtux_right[i]);
1209 texture_free(&bigtux_left[i]);
1212 texture_free(&bigtux_right_jump);
1213 texture_free(&bigtux_left_jump);
1215 for (i = 0; i < 2; i++)
1217 texture_free(&cape_right[i]);
1218 texture_free(&cape_left[i]);
1219 texture_free(&bigcape_right[i]);
1220 texture_free(&bigcape_left[i]);
1223 texture_free(&ducktux_left);
1224 texture_free(&ducktux_right);
1226 texture_free(&skidtux_left);
1227 texture_free(&skidtux_right);
1229 for (i = 0; i < 4; i++)
1231 texture_free(&img_bsod_left[i]);
1232 texture_free(&img_bsod_right[i]);
1235 texture_free(&img_bsod_squished_left);
1236 texture_free(&img_bsod_squished_right);
1238 texture_free(&img_bsod_falling_left);
1239 texture_free(&img_bsod_falling_right);
1241 for (i = 0; i < 3; i++)
1243 texture_free(&img_laptop_left[i]);
1244 texture_free(&img_laptop_right[i]);
1247 texture_free(&img_laptop_flat_left);
1248 texture_free(&img_laptop_flat_right);
1250 texture_free(&img_laptop_falling_left);
1251 texture_free(&img_laptop_falling_right);
1253 for (i = 0; i < 2; i++)
1255 texture_free(&img_money_left[i]);
1256 texture_free(&img_money_right[i]);
1259 texture_free(&img_box_full);
1260 texture_free(&img_box_empty);
1262 texture_free(&img_water);
1263 for (i = 0; i < 3; i++)
1264 texture_free(&img_waves[i]);
1266 texture_free(&img_pole);
1267 texture_free(&img_poletop);
1269 for (i = 0; i < 2; i++)
1270 texture_free(&img_flag[i]);
1272 texture_free(&img_mints);
1273 texture_free(&img_coffee);
1275 for (i = 0; i < 4; i++)
1277 texture_free(&img_distro[i]);
1278 texture_free(&img_cloud[0][i]);
1279 texture_free(&img_cloud[1][i]);
1282 texture_free(&img_golden_herring);
1284 for (i = 0; i < NUM_SOUNDS; i++)
1285 free_chunk(sounds[i]);
1287 /* free the herring song */
1288 free_music( herring_song );
1292 /* Draw a tile on the screen: */
1294 void drawshape(float x, float y, unsigned char c)
1298 if (c == 'X' || c == 'x')
1299 texture_draw(&img_brick[0], x, y, NO_UPDATE);
1300 else if (c == 'Y' || c == 'y')
1301 texture_draw(&img_brick[1], x, y, NO_UPDATE);
1302 else if (c == 'A' || c =='B' || c == '!')
1303 texture_draw(&img_box_full, x, y, NO_UPDATE);
1305 texture_draw(&img_box_empty, x, y, NO_UPDATE);
1306 else if (c >= 'C' && c <= 'F')
1307 texture_draw(&img_cloud[0][c - 'C'], x, y, NO_UPDATE);
1308 else if (c >= 'c' && c <= 'f')
1309 texture_draw(&img_cloud[1][c - 'c'], x, y, NO_UPDATE);
1310 else if (c >= 'G' && c <= 'J')
1311 texture_draw(&img_bkgd_tile[0][c - 'G'], x, y, NO_UPDATE);
1312 else if (c >= 'g' && c <= 'j')
1313 texture_draw(&img_bkgd_tile[1][c - 'g'], x, y, NO_UPDATE);
1315 texture_draw(&img_solid[0], x, y, NO_UPDATE);
1317 texture_draw(&img_solid[1], x, y, NO_UPDATE);
1319 texture_draw(&img_solid[2], x, y, NO_UPDATE);
1321 texture_draw(&img_solid[3], x, y, NO_UPDATE);
1325 z = (frame / 2) % 6;
1328 texture_draw(&img_distro[z], x, y, NO_UPDATE);
1330 texture_draw(&img_distro[2], x, y, NO_UPDATE);
1332 texture_draw(&img_distro[1], x, y, NO_UPDATE);
1336 z = (frame / 3) % 3;
1338 texture_draw(&img_waves[z], x, y, NO_UPDATE);
1341 texture_draw(&img_poletop, x, y, NO_UPDATE);
1344 texture_draw(&img_pole, x, y, NO_UPDATE);
1349 z = (frame / 3) % 2;
1351 texture_draw(&img_flag[z], x + 16, y, NO_UPDATE);
1354 texture_draw(&img_water, x, y, NO_UPDATE);
1358 /* What shape is at some position? */
1360 unsigned char shape(float x, float y)
1369 if (yy >= 0 && yy < 15 && xx >= 0 && xx <= current_level.width)
1371 c = current_level.tiles[yy][xx];
1382 int issolid(float x, float y)
1384 if (isbrick(x, y) ||
1386 (shape(x, y) == '[') ||
1387 (shape(x, y) == '=') ||
1388 (shape(x, y) == ']') ||
1389 (shape(x, y) == 'A') ||
1390 (shape(x, y) == 'B') ||
1391 (shape(x, y) == '!') ||
1392 (shape(x, y) == 'a'))
1401 /* Is it a brick? */
1403 int isbrick(float x, float y)
1405 if (shape(x, y) == 'X' ||
1406 shape(x, y) == 'x' ||
1407 shape(x, y) == 'Y' ||
1419 int isice(float x, float y)
1421 if (shape(x, y) == '#')
1430 /* Is it a full box? */
1432 int isfullbox(float x, float y)
1434 if (shape(x, y) == 'A' ||
1435 shape(x, y) == 'B' ||
1444 /* Break a brick: */
1446 void trybreakbrick(float x, float y)
1450 if (shape(x, y) == 'x' || shape(x, y) == 'y')
1452 /* Get a distro from it: */
1454 add_bouncy_distro(((int)(x + 1) / 32) * 32,
1455 (int)(y / 32) * 32);
1457 if (counting_distros == NO)
1459 counting_distros = YES;
1460 distro_counter = 50;
1463 if (distro_counter <= 0)
1464 level_change(¤t_level,x, y, 'a');
1466 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1467 score = score + SCORE_DISTRO;
1472 /* Get rid of it: */
1474 level_change(¤t_level,x, y,'.');
1478 /* Replace it with broken bits: */
1480 add_broken_brick(((int)(x + 1) / 32) * 32,
1481 (int)(y / 32) * 32);
1484 /* Get some score: */
1486 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
1487 score = score + SCORE_BRICK;
1492 /* Bounce a brick: */
1494 void bumpbrick(float x, float y)
1496 add_bouncy_brick(((int)(x + 1) / 32) * 32,
1497 (int)(y / 32) * 32);
1499 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
1506 void tryemptybox(float x, float y, int col_side)
1508 if (!isfullbox(x, y))
1511 // according to the collision side, set the upgrade direction
1513 if(col_side == LEFT)
1520 case 'A': /* Box with a distro! */
1521 add_bouncy_distro(((int)(x + 1) / 32) * 32, (int)(y / 32) * 32 - 32);
1522 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1523 score = score + SCORE_DISTRO;
1526 case 'B': /* Add an upgrade! */
1527 if (tux.size == SMALL) /* Tux is small, add mints! */
1528 add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_MINTS);
1529 else /* Tux is big, add coffee: */
1530 add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_COFFEE);
1531 play_sound(sounds[SND_UPGRADE], SOUND_CENTER_SPEAKER);
1533 case '!': /* Add a golden herring */
1534 add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_HERRING);
1540 /* Empty the box: */
1541 level_change(¤t_level,x, y, 'a');
1545 /* Try to grab a distro: */
1547 void trygrabdistro(float x, float y, int bounciness)
1549 if (shape(x, y) == '$')
1551 level_change(¤t_level,x, y, '.');
1552 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1554 if (bounciness == BOUNCE)
1556 add_bouncy_distro(((int)(x + 1) / 32) * 32,
1557 (int)(y / 32) * 32);
1560 score = score + SCORE_DISTRO;
1565 /* Try to bump a bad guy from below: */
1567 void trybumpbadguy(float x, float y)
1574 for (i = 0; i < bad_guys.size(); i++)
1576 if (bad_guys[i].base.x >= x - 32 && bad_guys[i].base.x <= x + 32 &&
1577 bad_guys[i].base.y >= y - 16 && bad_guys[i].base.y <= y + 16)
1579 if (bad_guys[i].kind == BAD_BSOD ||
1580 bad_guys[i].kind == BAD_LAPTOP)
1582 bad_guys[i].dying = FALLING;
1583 bad_guys[i].base.ym = -8;
1584 play_sound(sounds[SND_FALL], SOUND_CENTER_SPEAKER);
1592 for (i = 0; i < upgrades.size(); i++)
1594 if (upgrades[i].base.height == 32 &&
1595 upgrades[i].base.x >= x - 32 && upgrades[i].base.x <= x + 32 &&
1596 upgrades[i].base.y >= y - 16 && upgrades[i].base.y <= y + 16)
1598 upgrades[i].base.xm = -upgrades[i].base.xm;
1599 upgrades[i].base.ym = -8;
1600 play_sound(sounds[SND_BUMP_UPGRADE], SOUND_CENTER_SPEAKER);
1606 void drawstatus(void)
1610 sprintf(str, "%d", score);
1611 text_draw(&white_text, "SCORE", 0, 0, 1, NO_UPDATE);
1612 text_draw(&gold_text, str, 96, 0, 1, NO_UPDATE);
1614 if(st_gl_mode != ST_GL_TEST)
1616 sprintf(str, "%d", hs_score);
1617 text_draw(&white_text, "HIGH", 0, 20, 1, NO_UPDATE);
1618 text_draw(&gold_text, str, 96, 20, 1, NO_UPDATE);
1622 text_draw(&white_text,"Press ESC To Return",0,20,1, NO_UPDATE);
1625 if (timer_get_left(&time_left) > TIME_WARNING || (frame % 10) < 5)
1627 sprintf(str, "%d", timer_get_left(&time_left) / 1000 );
1628 text_draw(&white_text, "TIME", 224, 0, 1, NO_UPDATE);
1629 text_draw(&gold_text, str, 304, 0, 1, NO_UPDATE);
1632 sprintf(str, "%d", distros);
1633 text_draw(&white_text, "DISTROS", screen->h, 0, 1, NO_UPDATE);
1634 text_draw(&gold_text, str, 608, 0, 1, NO_UPDATE);
1636 text_draw(&white_text, "LIVES", screen->h, 20, 1, NO_UPDATE);
1640 sprintf(str, "%2.1f", fps_fps);
1641 text_draw(&white_text, "FPS", screen->h, 40, 1, NO_UPDATE);
1642 text_draw(&gold_text, str, screen->h + 60, 40, 1, NO_UPDATE);
1645 for(i=0; i < tux.lives; ++i)
1647 texture_draw(&tux_life,565+(18*i),20,NO_UPDATE);
1652 void drawendscreen(void)
1656 clearscreen(0, 0, 0);
1658 text_drawf(&blue_text, "GAMEOVER", 0, 200, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
1660 sprintf(str, "SCORE: %d", score);
1661 text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
1663 sprintf(str, "DISTROS: %d", distros);
1664 text_drawf(&gold_text, str, 0, 256, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
1670 void drawresultscreen(void)
1674 clearscreen(0, 0, 0);
1676 text_drawf(&blue_text, "Result:", 0, 200, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
1678 sprintf(str, "SCORE: %d", score);
1679 text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
1681 sprintf(str, "DISTROS: %d", distros);
1682 text_drawf(&gold_text, str, 0, 256, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
1688 void savegame(int slot)
1690 char savefile[1024];
1694 sprintf(savefile,"%s/slot%d.save",st_save_dir,slot);
1696 fi = fopen(savefile, "wb");
1700 fprintf(stderr, "Warning: I could not open the slot file ");
1705 fputs(level_subset, fi);
1707 fwrite(&level,sizeof(int),1,fi);
1708 fwrite(&score,sizeof(int),1,fi);
1709 fwrite(&distros,sizeof(int),1,fi);
1710 fwrite(&scroll_x,sizeof(float),1,fi);
1711 fwrite(&tux,sizeof(player_type),1,fi);
1712 timer_fwrite(&tux.invincible_timer,fi);
1713 timer_fwrite(&tux.skidding_timer,fi);
1714 timer_fwrite(&tux.safe_timer,fi);
1715 timer_fwrite(&tux.frame_timer,fi);
1716 timer_fwrite(&time_left,fi);
1717 ui = st_get_ticks();
1718 fwrite(&ui,sizeof(int),1,fi);
1724 void loadgame(int slot)
1726 char savefile[1024];
1731 sprintf(savefile,"%s/slot%d.save",st_save_dir,slot);
1733 fi = fopen(savefile, "rb");
1737 fprintf(stderr, "Warning: I could not open the slot file ");
1744 fgets(str, 100, fi);
1745 strcpy(level_subset, str);
1746 level_subset[strlen(level_subset)-1] = '\0';
1747 fread(&level,sizeof(int),1,fi);
1750 level_free(¤t_level);
1751 if(level_load(¤t_level,level_subset,level) != 0)
1755 activate_bad_guys();
1757 level_load_gfx(¤t_level);
1759 level_load_song(¤t_level);
1761 update_time = st_get_ticks();
1763 fread(&score,sizeof(int),1,fi);
1764 fread(&distros,sizeof(int),1,fi);
1765 fread(&scroll_x,sizeof(float),1,fi);
1766 fread(&tux,sizeof(player_type),1,fi);
1767 timer_fread(&tux.invincible_timer,fi);
1768 timer_fread(&tux.skidding_timer,fi);
1769 timer_fread(&tux.safe_timer,fi);
1770 timer_fread(&tux.frame_timer,fi);
1771 timer_fread(&time_left,fi);
1772 fread(&ui,sizeof(int),1,fi);
1773 tux.hphysic.start_time += st_get_ticks() - ui;
1774 tux.vphysic.start_time += st_get_ticks() - ui;
1780 void slotinfo(char **pinfo, int slot)
1783 char slotfile[1024];
1787 sprintf(slotfile,"%s/slot%d.save",st_save_dir,slot);
1789 fi = fopen(slotfile, "rb");
1791 sprintf(tmp,"Slot %d - ",slot);
1799 fgets(str, 100, fi);
1800 str[strlen(str)-1] = '\0';
1802 strcat(tmp, " / Level:");
1803 fread(&slot_level,sizeof(int),1,fi);
1804 sprintf(str,"%d",slot_level);
1809 *pinfo = (char*) malloc(sizeof(char) * (strlen(tmp)+1));