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 = false;
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();
192 tux.size = !tux.size;
195 tux.base.height = 64;
198 tux.base.height = 32;
215 timer_start(&tux.invincible_timer,TUX_INVINCIBLE_TIME);
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 = MENU_ACTION_DOWN;
261 menuaction = MENU_ACTION_UP;
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)
281 menuaction = MENU_ACTION_HIT;
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)
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, true);
584 timer_init(&frame_timer, true);
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,true);
625 if(st_gl_mode == ST_GL_LOAD_GAME)
629 /* --- MAIN GAME LOOP!!! --- */
636 timer_init(&fps_timer,true);
637 timer_init(&frame_timer,true);
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, false);
687 update_load_save_game_menu(&load_game_menu, true);
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(true);
703 else if(current_menu == &load_game_menu )
705 process_save_load_game_menu(false);
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 == true)
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 = true;*/ /*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)
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);
808 game_started = false;
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 bool issolid(float x, float y)
1384 return (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'));
1395 /* Is it a brick? */
1397 bool isbrick(float x, float y)
1399 return (shape(x, y) == 'X' ||
1400 shape(x, y) == 'x' ||
1401 shape(x, y) == 'Y' ||
1402 shape(x, y) == 'y');
1408 bool isice(float x, float y)
1410 return (shape(x, y) == '#');
1413 /* Is it a full box? */
1415 bool isfullbox(float x, float y)
1417 return (shape(x, y) == 'A' ||
1418 shape(x, y) == 'B' ||
1419 shape(x, y) == '!');
1422 /* Break a brick: */
1424 void trybreakbrick(float x, float y)
1428 if (shape(x, y) == 'x' || shape(x, y) == 'y')
1430 /* Get a distro from it: */
1432 add_bouncy_distro(((int)(x + 1) / 32) * 32,
1433 (int)(y / 32) * 32);
1435 if (!counting_distros)
1437 counting_distros = true;
1438 distro_counter = 50;
1441 if (distro_counter <= 0)
1442 level_change(¤t_level,x, y, 'a');
1444 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1445 score = score + SCORE_DISTRO;
1450 /* Get rid of it: */
1452 level_change(¤t_level,x, y,'.');
1456 /* Replace it with broken bits: */
1458 add_broken_brick(((int)(x + 1) / 32) * 32,
1459 (int)(y / 32) * 32);
1462 /* Get some score: */
1464 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
1465 score = score + SCORE_BRICK;
1470 /* Bounce a brick: */
1472 void bumpbrick(float x, float y)
1474 add_bouncy_brick(((int)(x + 1) / 32) * 32,
1475 (int)(y / 32) * 32);
1477 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
1484 void tryemptybox(float x, float y, int col_side)
1486 if (!isfullbox(x, y))
1489 // according to the collision side, set the upgrade direction
1491 if(col_side == LEFT)
1498 case 'A': /* Box with a distro! */
1499 add_bouncy_distro(((int)(x + 1) / 32) * 32, (int)(y / 32) * 32 - 32);
1500 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1501 score = score + SCORE_DISTRO;
1504 case 'B': /* Add an upgrade! */
1505 if (tux.size == SMALL) /* Tux is small, add mints! */
1506 add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_MINTS);
1507 else /* Tux is big, add coffee: */
1508 add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_COFFEE);
1509 play_sound(sounds[SND_UPGRADE], SOUND_CENTER_SPEAKER);
1511 case '!': /* Add a golden herring */
1512 add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_HERRING);
1518 /* Empty the box: */
1519 level_change(¤t_level,x, y, 'a');
1523 /* Try to grab a distro: */
1525 void trygrabdistro(float x, float y, int bounciness)
1527 if (shape(x, y) == '$')
1529 level_change(¤t_level,x, y, '.');
1530 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1532 if (bounciness == BOUNCE)
1534 add_bouncy_distro(((int)(x + 1) / 32) * 32,
1535 (int)(y / 32) * 32);
1538 score = score + SCORE_DISTRO;
1543 /* Try to bump a bad guy from below: */
1545 void trybumpbadguy(float x, float y)
1552 for (i = 0; i < bad_guys.size(); i++)
1554 if (bad_guys[i].base.x >= x - 32 && bad_guys[i].base.x <= x + 32 &&
1555 bad_guys[i].base.y >= y - 16 && bad_guys[i].base.y <= y + 16)
1557 if (bad_guys[i].kind == BAD_BSOD ||
1558 bad_guys[i].kind == BAD_LAPTOP)
1560 bad_guys[i].dying = DYING_FALLING;
1561 bad_guys[i].base.ym = -8;
1562 play_sound(sounds[SND_FALL], SOUND_CENTER_SPEAKER);
1570 for (i = 0; i < upgrades.size(); i++)
1572 if (upgrades[i].base.height == 32 &&
1573 upgrades[i].base.x >= x - 32 && upgrades[i].base.x <= x + 32 &&
1574 upgrades[i].base.y >= y - 16 && upgrades[i].base.y <= y + 16)
1576 upgrades[i].base.xm = -upgrades[i].base.xm;
1577 upgrades[i].base.ym = -8;
1578 play_sound(sounds[SND_BUMP_UPGRADE], SOUND_CENTER_SPEAKER);
1584 void drawstatus(void)
1588 sprintf(str, "%d", score);
1589 text_draw(&white_text, "SCORE", 0, 0, 1, NO_UPDATE);
1590 text_draw(&gold_text, str, 96, 0, 1, NO_UPDATE);
1592 if(st_gl_mode != ST_GL_TEST)
1594 sprintf(str, "%d", hs_score);
1595 text_draw(&white_text, "HIGH", 0, 20, 1, NO_UPDATE);
1596 text_draw(&gold_text, str, 96, 20, 1, NO_UPDATE);
1600 text_draw(&white_text,"Press ESC To Return",0,20,1, NO_UPDATE);
1603 if (timer_get_left(&time_left) > TIME_WARNING || (frame % 10) < 5)
1605 sprintf(str, "%d", timer_get_left(&time_left) / 1000 );
1606 text_draw(&white_text, "TIME", 224, 0, 1, NO_UPDATE);
1607 text_draw(&gold_text, str, 304, 0, 1, NO_UPDATE);
1610 sprintf(str, "%d", distros);
1611 text_draw(&white_text, "DISTROS", screen->h, 0, 1, NO_UPDATE);
1612 text_draw(&gold_text, str, 608, 0, 1, NO_UPDATE);
1614 text_draw(&white_text, "LIVES", screen->h, 20, 1, NO_UPDATE);
1618 sprintf(str, "%2.1f", fps_fps);
1619 text_draw(&white_text, "FPS", screen->h, 40, 1, NO_UPDATE);
1620 text_draw(&gold_text, str, screen->h + 60, 40, 1, NO_UPDATE);
1623 for(i=0; i < tux.lives; ++i)
1625 texture_draw(&tux_life,565+(18*i),20,NO_UPDATE);
1630 void drawendscreen(void)
1634 clearscreen(0, 0, 0);
1636 text_drawf(&blue_text, "GAMEOVER", 0, 200, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
1638 sprintf(str, "SCORE: %d", score);
1639 text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
1641 sprintf(str, "DISTROS: %d", distros);
1642 text_drawf(&gold_text, str, 0, 256, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
1648 void drawresultscreen(void)
1652 clearscreen(0, 0, 0);
1654 text_drawf(&blue_text, "Result:", 0, 200, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
1656 sprintf(str, "SCORE: %d", score);
1657 text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
1659 sprintf(str, "DISTROS: %d", distros);
1660 text_drawf(&gold_text, str, 0, 256, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
1666 void savegame(int slot)
1668 char savefile[1024];
1672 sprintf(savefile,"%s/slot%d.save",st_save_dir,slot);
1674 fi = fopen(savefile, "wb");
1678 fprintf(stderr, "Warning: I could not open the slot file ");
1683 fputs(level_subset, fi);
1685 fwrite(&level,sizeof(int),1,fi);
1686 fwrite(&score,sizeof(int),1,fi);
1687 fwrite(&distros,sizeof(int),1,fi);
1688 fwrite(&scroll_x,sizeof(float),1,fi);
1689 fwrite(&tux,sizeof(player_type),1,fi);
1690 timer_fwrite(&tux.invincible_timer,fi);
1691 timer_fwrite(&tux.skidding_timer,fi);
1692 timer_fwrite(&tux.safe_timer,fi);
1693 timer_fwrite(&tux.frame_timer,fi);
1694 timer_fwrite(&time_left,fi);
1695 ui = st_get_ticks();
1696 fwrite(&ui,sizeof(int),1,fi);
1702 void loadgame(int slot)
1704 char savefile[1024];
1709 sprintf(savefile,"%s/slot%d.save",st_save_dir,slot);
1711 fi = fopen(savefile, "rb");
1715 fprintf(stderr, "Warning: I could not open the slot file ");
1722 fgets(str, 100, fi);
1723 strcpy(level_subset, str);
1724 level_subset[strlen(level_subset)-1] = '\0';
1725 fread(&level,sizeof(int),1,fi);
1728 level_free(¤t_level);
1729 if(level_load(¤t_level,level_subset,level) != 0)
1733 activate_bad_guys();
1735 level_load_gfx(¤t_level);
1737 level_load_song(¤t_level);
1739 update_time = st_get_ticks();
1741 fread(&score,sizeof(int),1,fi);
1742 fread(&distros,sizeof(int),1,fi);
1743 fread(&scroll_x,sizeof(float),1,fi);
1744 fread(&tux,sizeof(player_type),1,fi);
1745 timer_fread(&tux.invincible_timer,fi);
1746 timer_fread(&tux.skidding_timer,fi);
1747 timer_fread(&tux.safe_timer,fi);
1748 timer_fread(&tux.frame_timer,fi);
1749 timer_fread(&time_left,fi);
1750 fread(&ui,sizeof(int),1,fi);
1751 tux.hphysic.start_time += st_get_ticks() - ui;
1752 tux.vphysic.start_time += st_get_ticks() - ui;
1758 void slotinfo(char **pinfo, int slot)
1761 char slotfile[1024];
1765 sprintf(slotfile,"%s/slot%d.save",st_save_dir,slot);
1767 fi = fopen(slotfile, "rb");
1769 sprintf(tmp,"Slot %d - ",slot);
1777 fgets(str, 100, fi);
1778 str[strlen(str)-1] = '\0';
1780 strcat(tmp, " / Level:");
1781 fread(&slot_level,sizeof(int),1,fi);
1782 sprintf(str,"%d",slot_level);
1787 *pinfo = (char*) malloc(sizeof(char) * (strlen(tmp)+1));