6 by Bill Kendrick & Tobias Glaesser
7 bill@newbreedsoftware.com
8 http://www.newbreedsoftware.com/supertux/
10 April 11, 2000 - March 15, 2004
23 #include <sys/types.h>
32 #include "high_scores.h"
40 #include "collision.h"
42 /* extern variables */
44 st_level current_level;
45 int game_started = NO;
47 /* Local variables: */
49 static texture_type img_waves[3], img_water, img_pole, img_poletop, img_flag[2];
50 static texture_type img_cloud[2][4];
51 static SDL_Event event;
53 static char level_subset[100];
56 static int st_gl_mode;
57 static unsigned int last_update_time;
58 static unsigned int update_time;
59 static int pause_menu_frame;
62 /* Local function prototypes: */
64 void levelintro(void);
65 void loadshared(void);
66 void unloadshared(void);
67 void drawstatus(void);
68 void drawendscreen(void);
69 void drawresultscreen(void);
71 #define JOYSTICK_DEAD_ZONE 4096
79 sprintf(str, "LEVEL %d", level);
80 text_drawf(&blue_text, str, 0, 200, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
82 sprintf(str, "%s", current_level.name);
83 text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
85 sprintf(str, "TUX x %d", tux.lives);
86 text_drawf(&white_text, str, 0, 256, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
94 void start_timers(void)
96 timer_start(&time_left,current_level.time_left*1000);
97 st_pause_ticks_init();
98 update_time = st_get_ticks();
101 void activate_bad_guys(void)
105 /* Activate bad guys: */
107 for (y = 0; y < 15; y++)
109 for (x = 0; x < current_level.width; x++)
111 if (current_level.tiles[y][x] >= '0' && current_level.tiles[y][x] <= '9')
113 add_bad_guy(x * 32, y * 32, current_level.tiles[y][x] - '0');
114 current_level.tiles[y][x] = '.';
121 /* --- GAME EVENT! --- */
123 void game_event(void)
125 while (SDL_PollEvent(&event))
129 case SDL_QUIT: /* Quit event - quit: */
132 case SDL_KEYDOWN: /* A keypress! */
133 key = event.key.keysym.sym;
135 /* Check for menu-events, if the menu is shown */
137 menu_event(&event.key.keysym);
139 if(player_key_event(&tux,key,DOWN))
144 case SDLK_ESCAPE: /* Escape: Open/Close the menu: */
147 if(st_gl_mode == ST_GL_TEST)
151 menu_set_current(&game_menu);
153 st_pause_ticks_stop();
157 menu_set_current(&game_menu);
159 st_pause_ticks_start();
167 case SDL_KEYUP: /* A keyrelease! */
168 key = event.key.keysym.sym;
170 if(player_key_event(&tux,key,UP))
181 st_pause_ticks_stop();
186 st_pause_ticks_start();
191 if(debug_mode == YES)
193 tux.size = !tux.size;
196 tux.base.height = 64;
199 tux.base.height = 32;
203 if(debug_mode == YES)
207 if(debug_mode == YES)
211 if(debug_mode == YES)
215 if(debug_mode == YES)
216 timer_start(&tux.invincible_timer,TUX_INVINCIBLE_TIME);
219 if(debug_mode == YES)
223 if(debug_mode == YES)
237 case SDL_JOYAXISMOTION:
238 switch(event.jaxis.axis)
241 if (event.jaxis.value < -JOYSTICK_DEAD_ZONE)
242 tux.input.left = DOWN;
243 else if (event.jaxis.value > JOYSTICK_DEAD_ZONE)
246 if (event.jaxis.value > JOYSTICK_DEAD_ZONE)
247 tux.input.right = DOWN;
248 else if (event.jaxis.value < -JOYSTICK_DEAD_ZONE)
249 tux.input.right = UP;
252 if (event.jaxis.value > JOYSTICK_DEAD_ZONE)
253 tux.input.down = DOWN;
254 else if (event.jaxis.value < -JOYSTICK_DEAD_ZONE)
257 /* Handle joystick for the menu */
260 if(tux.input.down == DOWN)
261 menuaction = MN_DOWN;
270 case SDL_JOYBUTTONDOWN:
271 if (event.jbutton.button == JOY_A)
273 else if (event.jbutton.button == JOY_B)
274 tux.input.fire = DOWN;
276 case SDL_JOYBUTTONUP:
277 if (event.jbutton.button == JOY_A)
279 else if (event.jbutton.button == JOY_B)
296 /* --- GAME ACTION! --- */
298 int game_action(void)
302 /* (tux_dying || next_level) */
303 if (tux.dying || next_level)
305 /* Tux either died, or reached the end of a level! */
312 /* End of a level! */
315 if(st_gl_mode != ST_GL_TEST)
322 level_free(¤t_level);
328 player_level_begin(&tux);
334 /* No more lives!? */
338 if(st_gl_mode != ST_GL_TEST)
341 if(st_gl_mode != ST_GL_TEST)
343 if (score > hs_score)
347 level_free(¤t_level);
352 } /* if (lives < 0) */
355 /* Either way, (re-)load the (next) level... */
357 player_level_begin(&tux);
359 level_free(¤t_level);
361 if (st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
363 if(level_load(¤t_level, level_subset) != 0)
368 if(level_load(¤t_level,level_subset,level) != 0)
376 level_load_gfx(¤t_level);
378 level_load_song(¤t_level);
379 if(st_gl_mode != ST_GL_TEST)
383 play_current_music();
388 /* Handle bouncy distros: */
390 for (i = 0; i < num_bouncy_distros; i++)
392 bouncy_distro_action(&bouncy_distros[i]);
396 /* Handle broken bricks: */
398 for (i = 0; i < num_broken_bricks; i++)
400 broken_brick_action(&broken_bricks[i]);
404 /* Handle distro counting: */
406 if (counting_distros == YES)
410 if (distro_counter <= 0)
411 counting_distros = -1;
415 /* Handle bouncy bricks: */
417 for (i = 0; i < num_bouncy_bricks; i++)
419 bouncy_brick_action(&bouncy_bricks[i]);
423 /* Handle floating scores: */
425 for (i = 0; i < num_floating_scores; i++)
427 floating_score_action(&floating_scores[i]);
431 /* Handle bullets: */
433 for (i = 0; i < num_bullets; ++i)
435 bullet_action(&bullets[i]);
438 /* Handle upgrades: */
440 for (i = 0; i < num_upgrades; i++)
442 upgrade_action(&upgrades[i]);
446 /* Handle bad guys: */
448 for (i = 0; i < num_bad_guys; i++)
450 badguy_action(&bad_guys[i]);
453 /* Handle all possible collisions. */
459 /* --- GAME DRAW! --- */
467 if (tux.dying && (frame % 4) == 0)
468 clearscreen(255, 255, 255);
469 else if(timer_check(&super_bkgd_timer))
470 texture_draw(&img_super_bkgd, 0, 0, NO_UPDATE);
473 /* Draw the real background */
474 if(current_level.bkgd_image[0] != '\0')
476 s = (int)scroll_x / 30;
477 texture_draw_part(&img_bkgd,s,0,0,0,img_bkgd.w - s, img_bkgd.h, NO_UPDATE);
478 texture_draw_part(&img_bkgd,0,0,screen->w - s ,0,s,img_bkgd.h, NO_UPDATE);
482 clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue);
486 /* Draw background: */
488 for (y = 0; y < 15; ++y)
490 for (x = 0; x < 21; ++x)
492 drawshape(x * 32 - ((int)scroll_x % 32), y * 32,
493 current_level.tiles[(int)y][(int)x + (int)(scroll_x / 32)]);
498 /* (Bouncy bricks): */
500 for (i = 0; i < num_bouncy_bricks; ++i)
502 bouncy_brick_draw(&bouncy_bricks[i]);
508 for (i = 0; i < num_bad_guys; ++i)
510 badguy_draw(&bad_guys[i]);
519 for (i = 0; i < num_bullets; ++i)
521 bullet_draw(&bullets[i]);
524 /* (Floating scores): */
526 for (i = 0; i < num_floating_scores; ++i)
528 floating_score_draw(&floating_scores[i]);
534 for (i = 0; i < num_upgrades; ++i)
536 upgrade_draw(&upgrades[i]);
540 /* (Bouncy distros): */
542 for (i = 0; i < num_bouncy_distros; ++i)
544 bouncy_distro_draw(&bouncy_distros[i]);
548 /* (Broken bricks): */
550 for (i = 0; i < num_broken_bricks; ++i)
552 broken_brick_draw(&broken_bricks[i]);
561 for(i = 0; i < x; ++i)
563 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);
565 fillrect(0,0,screen->w,screen->h,rand() % 50, rand() % 50, rand() % 50, 128);
566 text_drawf(&blue_text, "PAUSE - Press 'P' To Play", 0, 230, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
570 menu_process_current();
572 /* (Update it all!) */
579 /* --- GAME LOOP! --- */
581 int gameloop(char * subset, int levelnb, int mode)
583 int fps_cnt, jump, done;
584 timer_type fps_timer, frame_timer;
585 timer_init(&fps_timer, YES);
586 timer_init(&frame_timer, YES);
597 strcpy(level_subset,subset);
599 if (st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
601 if (level_load(¤t_level, level_subset))
606 if(level_load(¤t_level, level_subset, level) != 0)
610 level_load_gfx(¤t_level);
612 level_load_song(¤t_level);
616 if(st_gl_mode != ST_GL_TEST)
621 if(st_gl_mode == ST_GL_PLAY || st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
624 timer_init(&time_left,YES);
627 if(st_gl_mode == ST_GL_LOAD_GAME)
631 /* --- MAIN GAME LOOP!!! --- */
638 timer_init(&fps_timer,YES);
639 timer_init(&frame_timer,YES);
644 clearscreen(0, 0, 0);
648 play_current_music();
651 while (SDL_PollEvent(&event))
659 /* Calculate the movement-factor */
660 frame_ratio = ((double)(update_time-last_update_time))/((double)FRAME_RATE);
661 if(frame_ratio > 1.5) /* Quick hack to correct the unprecise CPU clocks a little bit. */
662 frame_ratio = 1.5 + (frame_ratio - 1.5) * 0.85;
664 if(!timer_check(&frame_timer))
666 timer_start(&frame_timer,25);
672 tux.input.old_fire = tux.input.fire;
678 if(current_menu == &game_menu)
680 switch (menu_check(&game_menu))
683 st_pause_ticks_stop();
686 update_load_save_game_menu(&save_game_menu, NO);
689 update_load_save_game_menu(&load_game_menu, YES);
692 st_pause_ticks_stop();
697 else if(current_menu == &options_menu)
699 process_options_menu();
701 else if(current_menu == &save_game_menu )
703 process_save_load_game_menu(YES);
705 else if(current_menu == &load_game_menu )
707 process_save_load_game_menu(NO);
712 /* Handle actions: */
714 if(!game_pause && !show_menu)
716 /*float z = frame_ratio;
720 if (game_action() == 0)
722 /* == 0: no more lives */
723 /* == -1: continues */
735 if(debug_mode && debug_fps == YES)
738 /*Draw the current scene to the screen */
739 /*If the machine running the game is too slow
740 skip the drawing of the frame (so the calculations are more precise and
741 the FPS aren't affected).*/
742 /*if( ! fps_fps < 50.0 )
745 jump = YES;*/ /*FIXME: Implement this tweak right.*/
748 /* Time stops in pause mode */
749 if(game_pause || show_menu )
754 /* Set the time of the last update and the time of the current update */
755 last_update_time = update_time;
756 update_time = st_get_ticks();
759 /* Pause till next frame, if the machine running the game is too fast: */
760 /* FIXME: Works great for in OpenGl mode, where the CPU doesn't have to do that much. But
761 the results in SDL mode aren't perfect (thought the 100 FPS are reached), even on an AMD2500+. */
762 if(last_update_time >= update_time - 12 && jump != YES )
764 /*if((update_time - last_update_time) < 10)
765 SDL_Delay((11 - (update_time - last_update_time))/2);*/
771 if (timer_check(&time_left))
773 /* are we low on time ? */
774 if ((timer_get_left(&time_left) < TIME_WARNING)
775 && (get_current_music() != HURRYUP_MUSIC)) /* play the fast music */
777 set_current_music(HURRYUP_MUSIC);
778 play_current_music();
783 player_kill(&tux,KILL);
786 /* Calculate frames per second */
790 fps_fps = (1000.0 / (float)timer_get_gone(&fps_timer)) * (float)fps_cnt;
792 if(!timer_check(&fps_timer))
794 timer_start(&fps_timer,1000);
800 while (!done && !quit);
805 level_free(¤t_level);
816 /* Load graphics/sounds shared between all levels: */
818 void loadshared(void)
821 char * herring_song_path; /* for loading herring song*/
825 texture_load(&tux_right[0],DATA_PREFIX "/images/shared/tux-right-0.png", USE_ALPHA);
826 texture_load(&tux_right[1],DATA_PREFIX "/images/shared/tux-right-1.png", USE_ALPHA);
827 texture_load(&tux_right[2],DATA_PREFIX "/images/shared/tux-right-2.png", USE_ALPHA);
829 texture_load(&tux_left[0],DATA_PREFIX "/images/shared/tux-left-0.png", USE_ALPHA);
830 texture_load(&tux_left[1],DATA_PREFIX "/images/shared/tux-left-1.png", USE_ALPHA);
831 texture_load(&tux_left[2],DATA_PREFIX "/images/shared/tux-left-2.png", USE_ALPHA);
833 texture_load(&firetux_right[0],DATA_PREFIX "/images/shared/firetux-right-0.png", USE_ALPHA);
834 texture_load(&firetux_right[1],DATA_PREFIX "/images/shared/firetux-right-1.png", USE_ALPHA);
835 texture_load(&firetux_right[2],DATA_PREFIX "/images/shared/firetux-right-2.png", USE_ALPHA);
837 texture_load(&firetux_left[0],DATA_PREFIX "/images/shared/firetux-left-0.png", USE_ALPHA);
838 texture_load(&firetux_left[1],DATA_PREFIX "/images/shared/firetux-left-1.png", USE_ALPHA);
839 texture_load(&firetux_left[2],DATA_PREFIX "/images/shared/firetux-left-2.png", USE_ALPHA);
842 texture_load(&cape_right[0] ,DATA_PREFIX "/images/shared/cape-right-0.png",
845 texture_load(&cape_right[1] ,DATA_PREFIX "/images/shared/cape-right-1.png",
848 texture_load(&cape_left[0] ,DATA_PREFIX "/images/shared/cape-left-0.png",
851 texture_load(&cape_left[1] ,DATA_PREFIX "/images/shared/cape-left-1.png",
854 texture_load(&bigtux_right[0] ,DATA_PREFIX "/images/shared/bigtux-right-0.png",
857 texture_load(&bigtux_right[1] ,DATA_PREFIX "/images/shared/bigtux-right-1.png",
860 texture_load(&bigtux_right[2] ,DATA_PREFIX "/images/shared/bigtux-right-2.png",
863 texture_load(&bigtux_right_jump ,DATA_PREFIX "/images/shared/bigtux-right-jump.png", USE_ALPHA);
865 texture_load(&bigtux_left[0] ,DATA_PREFIX "/images/shared/bigtux-left-0.png",
868 texture_load(&bigtux_left[1] ,DATA_PREFIX "/images/shared/bigtux-left-1.png",
871 texture_load(&bigtux_left[2] ,DATA_PREFIX "/images/shared/bigtux-left-2.png",
874 texture_load(&bigtux_left_jump ,DATA_PREFIX "/images/shared/bigtux-left-jump.png", USE_ALPHA);
876 texture_load(&bigcape_right[0] ,DATA_PREFIX "/images/shared/bigcape-right-0.png",
879 texture_load(&bigcape_right[1] ,DATA_PREFIX "/images/shared/bigcape-right-1.png",
882 texture_load(&bigcape_left[0] ,DATA_PREFIX "/images/shared/bigcape-left-0.png",
885 texture_load(&bigcape_left[1] ,DATA_PREFIX "/images/shared/bigcape-left-1.png",
888 texture_load(&bigfiretux_right[0] ,DATA_PREFIX "/images/shared/bigfiretux-right-0.png",
891 texture_load(&bigfiretux_right[1] ,DATA_PREFIX "/images/shared/bigfiretux-right-1.png",
894 texture_load(&bigfiretux_right[2] ,DATA_PREFIX "/images/shared/bigfiretux-right-2.png",
897 texture_load(&bigfiretux_right_jump ,DATA_PREFIX "/images/shared/bigfiretux-right-jump.png", USE_ALPHA);
899 texture_load(&bigfiretux_left[0] ,DATA_PREFIX "/images/shared/bigfiretux-left-0.png",
902 texture_load(&bigfiretux_left[1] ,DATA_PREFIX "/images/shared/bigfiretux-left-1.png",
905 texture_load(&bigfiretux_left[2] ,DATA_PREFIX "/images/shared/bigfiretux-left-2.png",
908 texture_load(&bigfiretux_left_jump ,DATA_PREFIX "/images/shared/bigfiretux-left-jump.png", USE_ALPHA);
910 texture_load(&bigcape_right[0] ,DATA_PREFIX "/images/shared/bigcape-right-0.png",
913 texture_load(&bigcape_right[1] ,DATA_PREFIX "/images/shared/bigcape-right-1.png",
916 texture_load(&bigcape_left[0] ,DATA_PREFIX "/images/shared/bigcape-left-0.png",
919 texture_load(&bigcape_left[1] ,DATA_PREFIX "/images/shared/bigcape-left-1.png",
923 texture_load(&ducktux_right ,DATA_PREFIX
924 "/images/shared/ducktux-right.png",
927 texture_load(&ducktux_left ,DATA_PREFIX
928 "/images/shared/ducktux-left.png",
931 texture_load(&skidtux_right ,DATA_PREFIX
932 "/images/shared/skidtux-right.png",
935 texture_load(&skidtux_left ,DATA_PREFIX
936 "/images/shared/skidtux-left.png",
939 texture_load(&duckfiretux_right ,DATA_PREFIX
940 "/images/shared/duckfiretux-right.png",
943 texture_load(&duckfiretux_left ,DATA_PREFIX
944 "/images/shared/duckfiretux-left.png",
947 texture_load(&skidfiretux_right ,DATA_PREFIX
948 "/images/shared/skidfiretux-right.png",
951 texture_load(&skidfiretux_left ,DATA_PREFIX
952 "/images/shared/skidfiretux-left.png",
958 texture_load(&img_box_full ,DATA_PREFIX "/images/shared/box-full.png",
960 texture_load(&img_box_empty ,DATA_PREFIX "/images/shared/box-empty.png",
967 texture_load(&img_water ,DATA_PREFIX "/images/shared/water.png", IGNORE_ALPHA);
969 texture_load(&img_waves[0] ,DATA_PREFIX "/images/shared/waves-0.png",
972 texture_load(&img_waves[1] ,DATA_PREFIX "/images/shared/waves-1.png",
975 texture_load(&img_waves[2] ,DATA_PREFIX "/images/shared/waves-2.png",
981 texture_load(&img_pole ,DATA_PREFIX "/images/shared/pole.png", USE_ALPHA);
982 texture_load(&img_poletop ,DATA_PREFIX "/images/shared/poletop.png",
988 texture_load(&img_flag[0] ,DATA_PREFIX "/images/shared/flag-0.png",
990 texture_load(&img_flag[1] ,DATA_PREFIX "/images/shared/flag-1.png",
996 texture_load(&img_cloud[0][0] ,DATA_PREFIX "/images/shared/cloud-00.png",
999 texture_load(&img_cloud[0][1] ,DATA_PREFIX "/images/shared/cloud-01.png",
1002 texture_load(&img_cloud[0][2] ,DATA_PREFIX "/images/shared/cloud-02.png",
1005 texture_load(&img_cloud[0][3] ,DATA_PREFIX "/images/shared/cloud-03.png",
1009 texture_load(&img_cloud[1][0] ,DATA_PREFIX "/images/shared/cloud-10.png",
1012 texture_load(&img_cloud[1][1] ,DATA_PREFIX "/images/shared/cloud-11.png",
1015 texture_load(&img_cloud[1][2] ,DATA_PREFIX "/images/shared/cloud-12.png",
1018 texture_load(&img_cloud[1][3] ,DATA_PREFIX "/images/shared/cloud-13.png",
1026 texture_load(&img_bsod_left[0] ,DATA_PREFIX
1027 "/images/shared/bsod-left-0.png",
1030 texture_load(&img_bsod_left[1] ,DATA_PREFIX
1031 "/images/shared/bsod-left-1.png",
1034 texture_load(&img_bsod_left[2] ,DATA_PREFIX
1035 "/images/shared/bsod-left-2.png",
1038 texture_load(&img_bsod_left[3] ,DATA_PREFIX
1039 "/images/shared/bsod-left-3.png",
1042 texture_load(&img_bsod_right[0] ,DATA_PREFIX
1043 "/images/shared/bsod-right-0.png",
1046 texture_load(&img_bsod_right[1] ,DATA_PREFIX
1047 "/images/shared/bsod-right-1.png",
1050 texture_load(&img_bsod_right[2] ,DATA_PREFIX
1051 "/images/shared/bsod-right-2.png",
1054 texture_load(&img_bsod_right[3] ,DATA_PREFIX
1055 "/images/shared/bsod-right-3.png",
1058 texture_load(&img_bsod_squished_left ,DATA_PREFIX
1059 "/images/shared/bsod-squished-left.png",
1062 texture_load(&img_bsod_squished_right ,DATA_PREFIX
1063 "/images/shared/bsod-squished-right.png",
1066 texture_load(&img_bsod_falling_left ,DATA_PREFIX
1067 "/images/shared/bsod-falling-left.png",
1070 texture_load(&img_bsod_falling_right ,DATA_PREFIX
1071 "/images/shared/bsod-falling-right.png",
1077 texture_load(&img_laptop_left[0] ,DATA_PREFIX
1078 "/images/shared/laptop-left-0.png",
1081 texture_load(&img_laptop_left[1] ,DATA_PREFIX
1082 "/images/shared/laptop-left-1.png",
1085 texture_load(&img_laptop_left[2] ,DATA_PREFIX
1086 "/images/shared/laptop-left-2.png",
1089 texture_load(&img_laptop_right[0] ,DATA_PREFIX
1090 "/images/shared/laptop-right-0.png",
1093 texture_load(&img_laptop_right[1] ,DATA_PREFIX
1094 "/images/shared/laptop-right-1.png",
1097 texture_load(&img_laptop_right[2] ,DATA_PREFIX
1098 "/images/shared/laptop-right-2.png",
1101 texture_load(&img_laptop_flat_left ,DATA_PREFIX
1102 "/images/shared/laptop-flat-left.png",
1105 texture_load(&img_laptop_flat_right ,DATA_PREFIX
1106 "/images/shared/laptop-flat-right.png",
1109 texture_load(&img_laptop_falling_left ,DATA_PREFIX
1110 "/images/shared/laptop-falling-left.png",
1113 texture_load(&img_laptop_falling_right ,DATA_PREFIX
1114 "/images/shared/laptop-falling-right.png",
1120 texture_load(&img_money_left[0] ,DATA_PREFIX
1121 "/images/shared/bag-left-0.png",
1124 texture_load(&img_money_left[1] ,DATA_PREFIX
1125 "/images/shared/bag-left-1.png",
1128 texture_load(&img_money_right[0] ,DATA_PREFIX
1129 "/images/shared/bag-right-0.png",
1132 texture_load(&img_money_right[1] ,DATA_PREFIX
1133 "/images/shared/bag-right-1.png",
1140 texture_load(&img_mints ,DATA_PREFIX "/images/shared/mints.png", USE_ALPHA);
1141 texture_load(&img_coffee ,DATA_PREFIX "/images/shared/coffee.png", USE_ALPHA);
1146 texture_load(&img_bullet ,DATA_PREFIX "/images/shared/bullet.png", USE_ALPHA);
1148 texture_load(&img_red_glow ,DATA_PREFIX "/images/shared/red-glow.png",
1155 texture_load(&img_distro[0] ,DATA_PREFIX "/images/shared/distro-0.png",
1158 texture_load(&img_distro[1] ,DATA_PREFIX "/images/shared/distro-1.png",
1161 texture_load(&img_distro[2] ,DATA_PREFIX "/images/shared/distro-2.png",
1164 texture_load(&img_distro[3] ,DATA_PREFIX "/images/shared/distro-3.png",
1170 texture_load(&tux_life ,DATA_PREFIX "/images/shared/tux-life.png",
1175 texture_load(&img_golden_herring, DATA_PREFIX "/images/shared/golden-herring.png",
1179 /* Super background: */
1181 texture_load(&img_super_bkgd ,DATA_PREFIX "/images/shared/super-bkgd.png",
1185 /* Sound effects: */
1187 /* if (use_sound) // this will introduce SERIOUS bugs here ! because "load_sound"
1188 // initialize sounds[i] with the correct pointer's value:
1189 // NULL or something else. And it will be dangerous to
1190 // play with not-initialized pointers.
1191 // This is also true with if (use_music)
1192 Send a mail to me: neoneurone@users.sf.net, if you have another opinion. :)
1194 for (i = 0; i < NUM_SOUNDS; i++)
1195 sounds[i] = load_sound(soundfilenames[i]);
1198 herring_song_path = (char *) malloc(sizeof(char) * (strlen(DATA_PREFIX) +
1199 strlen("SALCON.MOD") + 8));
1201 sprintf(herring_song_path, "%s/music/%s", DATA_PREFIX, "SALCON.MOD");
1203 herring_song = load_song(herring_song_path);
1205 free(herring_song_path);
1210 /* Free shared data: */
1212 void unloadshared(void)
1216 for (i = 0; i < 3; i++)
1218 texture_free(&tux_right[i]);
1219 texture_free(&tux_left[i]);
1220 texture_free(&bigtux_right[i]);
1221 texture_free(&bigtux_left[i]);
1224 texture_free(&bigtux_right_jump);
1225 texture_free(&bigtux_left_jump);
1227 for (i = 0; i < 2; i++)
1229 texture_free(&cape_right[i]);
1230 texture_free(&cape_left[i]);
1231 texture_free(&bigcape_right[i]);
1232 texture_free(&bigcape_left[i]);
1235 texture_free(&ducktux_left);
1236 texture_free(&ducktux_right);
1238 texture_free(&skidtux_left);
1239 texture_free(&skidtux_right);
1241 for (i = 0; i < 4; i++)
1243 texture_free(&img_bsod_left[i]);
1244 texture_free(&img_bsod_right[i]);
1247 texture_free(&img_bsod_squished_left);
1248 texture_free(&img_bsod_squished_right);
1250 texture_free(&img_bsod_falling_left);
1251 texture_free(&img_bsod_falling_right);
1253 for (i = 0; i < 3; i++)
1255 texture_free(&img_laptop_left[i]);
1256 texture_free(&img_laptop_right[i]);
1259 texture_free(&img_laptop_flat_left);
1260 texture_free(&img_laptop_flat_right);
1262 texture_free(&img_laptop_falling_left);
1263 texture_free(&img_laptop_falling_right);
1265 for (i = 0; i < 2; i++)
1267 texture_free(&img_money_left[i]);
1268 texture_free(&img_money_right[i]);
1271 texture_free(&img_box_full);
1272 texture_free(&img_box_empty);
1274 texture_free(&img_water);
1275 for (i = 0; i < 3; i++)
1276 texture_free(&img_waves[i]);
1278 texture_free(&img_pole);
1279 texture_free(&img_poletop);
1281 for (i = 0; i < 2; i++)
1282 texture_free(&img_flag[i]);
1284 texture_free(&img_mints);
1285 texture_free(&img_coffee);
1287 for (i = 0; i < 4; i++)
1289 texture_free(&img_distro[i]);
1290 texture_free(&img_cloud[0][i]);
1291 texture_free(&img_cloud[1][i]);
1294 texture_free(&img_golden_herring);
1296 for (i = 0; i < NUM_SOUNDS; i++)
1297 free_chunk(sounds[i]);
1299 /* free the herring song */
1300 free_music( herring_song );
1304 /* Draw a tile on the screen: */
1306 void drawshape(float x, float y, unsigned char c)
1310 if (c == 'X' || c == 'x')
1311 texture_draw(&img_brick[0], x, y, NO_UPDATE);
1312 else if (c == 'Y' || c == 'y')
1313 texture_draw(&img_brick[1], x, y, NO_UPDATE);
1314 else if (c == 'A' || c =='B' || c == '!')
1315 texture_draw(&img_box_full, x, y, NO_UPDATE);
1317 texture_draw(&img_box_empty, x, y, NO_UPDATE);
1318 else if (c >= 'C' && c <= 'F')
1319 texture_draw(&img_cloud[0][c - 'C'], x, y, NO_UPDATE);
1320 else if (c >= 'c' && c <= 'f')
1321 texture_draw(&img_cloud[1][c - 'c'], x, y, NO_UPDATE);
1322 else if (c >= 'G' && c <= 'J')
1323 texture_draw(&img_bkgd_tile[0][c - 'G'], x, y, NO_UPDATE);
1324 else if (c >= 'g' && c <= 'j')
1325 texture_draw(&img_bkgd_tile[1][c - 'g'], x, y, NO_UPDATE);
1327 texture_draw(&img_solid[0], x, y, NO_UPDATE);
1329 texture_draw(&img_solid[1], x, y, NO_UPDATE);
1331 texture_draw(&img_solid[2], x, y, NO_UPDATE);
1333 texture_draw(&img_solid[3], x, y, NO_UPDATE);
1337 z = (frame / 2) % 6;
1340 texture_draw(&img_distro[z], x, y, NO_UPDATE);
1342 texture_draw(&img_distro[2], x, y, NO_UPDATE);
1344 texture_draw(&img_distro[1], x, y, NO_UPDATE);
1348 z = (frame / 3) % 3;
1350 texture_draw(&img_waves[z], x, y, NO_UPDATE);
1353 texture_draw(&img_poletop, x, y, NO_UPDATE);
1356 texture_draw(&img_pole, x, y, NO_UPDATE);
1361 z = (frame / 3) % 2;
1363 texture_draw(&img_flag[z], x + 16, y, NO_UPDATE);
1366 texture_draw(&img_water, x, y, NO_UPDATE);
1370 /* What shape is at some position? */
1372 unsigned char shape(float x, float y)
1381 if (yy >= 0 && yy < 15 && xx >= 0 && xx <= current_level.width)
1383 c = current_level.tiles[yy][xx];
1394 int issolid(float x, float y)
1396 if (isbrick(x, y) ||
1398 (shape(x, y) == '[') ||
1399 (shape(x, y) == '=') ||
1400 (shape(x, y) == ']') ||
1401 (shape(x, y) == 'A') ||
1402 (shape(x, y) == 'B') ||
1403 (shape(x, y) == '!') ||
1404 (shape(x, y) == 'a'))
1413 /* Is it a brick? */
1415 int isbrick(float x, float y)
1417 if (shape(x, y) == 'X' ||
1418 shape(x, y) == 'x' ||
1419 shape(x, y) == 'Y' ||
1431 int isice(float x, float y)
1433 if (shape(x, y) == '#')
1442 /* Is it a full box? */
1444 int isfullbox(float x, float y)
1446 if (shape(x, y) == 'A' ||
1447 shape(x, y) == 'B' ||
1456 /* Break a brick: */
1458 void trybreakbrick(float x, float y)
1462 if (shape(x, y) == 'x' || shape(x, y) == 'y')
1464 /* Get a distro from it: */
1466 add_bouncy_distro(((int)(x + 1) / 32) * 32,
1467 (int)(y / 32) * 32);
1469 if (counting_distros == NO)
1471 counting_distros = YES;
1472 distro_counter = 50;
1475 if (distro_counter <= 0)
1476 level_change(¤t_level,x, y, 'a');
1478 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1479 score = score + SCORE_DISTRO;
1484 /* Get rid of it: */
1486 level_change(¤t_level,x, y,'.');
1490 /* Replace it with broken bits: */
1492 add_broken_brick(((int)(x + 1) / 32) * 32,
1493 (int)(y / 32) * 32);
1496 /* Get some score: */
1498 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
1499 score = score + SCORE_BRICK;
1504 /* Bounce a brick: */
1506 void bumpbrick(float x, float y)
1508 add_bouncy_brick(((int)(x + 1) / 32) * 32,
1509 (int)(y / 32) * 32);
1511 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
1518 void tryemptybox(float x, float y, int col_side)
1520 if (!isfullbox(x, y))
1523 // according to the collision side, set the upgrade direction
1525 if(col_side == LEFT)
1532 case 'A': /* Box with a distro! */
1533 add_bouncy_distro(((int)(x + 1) / 32) * 32, (int)(y / 32) * 32 - 32);
1534 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1535 score = score + SCORE_DISTRO;
1538 case 'B': /* Add an upgrade! */
1539 if (tux.size == SMALL) /* Tux is small, add mints! */
1540 add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_MINTS);
1541 else /* Tux is big, add coffee: */
1542 add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_COFFEE);
1543 play_sound(sounds[SND_UPGRADE], SOUND_CENTER_SPEAKER);
1545 case '!': /* Add a golden herring */
1546 add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_HERRING);
1552 /* Empty the box: */
1553 level_change(¤t_level,x, y, 'a');
1557 /* Try to grab a distro: */
1559 void trygrabdistro(float x, float y, int bounciness)
1561 if (shape(x, y) == '$')
1563 level_change(¤t_level,x, y, '.');
1564 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1566 if (bounciness == BOUNCE)
1568 add_bouncy_distro(((int)(x + 1) / 32) * 32,
1569 (int)(y / 32) * 32);
1572 score = score + SCORE_DISTRO;
1577 /* Try to bump a bad guy from below: */
1579 void trybumpbadguy(float x, float y)
1586 for (i = 0; i < num_bad_guys; i++)
1588 if (bad_guys[i].base.alive &&
1589 bad_guys[i].base.x >= x - 32 && bad_guys[i].base.x <= x + 32 &&
1590 bad_guys[i].base.y >= y - 16 && bad_guys[i].base.y <= y + 16)
1592 if (bad_guys[i].kind == BAD_BSOD ||
1593 bad_guys[i].kind == BAD_LAPTOP)
1595 bad_guys[i].dying = FALLING;
1596 bad_guys[i].base.ym = -8;
1597 play_sound(sounds[SND_FALL], SOUND_CENTER_SPEAKER);
1605 for (i = 0; i < num_upgrades; i++)
1607 if (upgrades[i].base.alive && upgrades[i].base.height == 32 &&
1608 upgrades[i].base.x >= x - 32 && upgrades[i].base.x <= x + 32 &&
1609 upgrades[i].base.y >= y - 16 && upgrades[i].base.y <= y + 16)
1611 upgrades[i].base.xm = -upgrades[i].base.xm;
1612 upgrades[i].base.ym = -8;
1613 play_sound(sounds[SND_BUMP_UPGRADE], SOUND_CENTER_SPEAKER);
1619 void drawstatus(void)
1623 sprintf(str, "%d", score);
1624 text_draw(&white_text, "SCORE", 0, 0, 1, NO_UPDATE);
1625 text_draw(&gold_text, str, 96, 0, 1, NO_UPDATE);
1627 if(st_gl_mode != ST_GL_TEST)
1629 sprintf(str, "%d", hs_score);
1630 text_draw(&white_text, "HIGH", 0, 20, 1, NO_UPDATE);
1631 text_draw(&gold_text, str, 96, 20, 1, NO_UPDATE);
1635 text_draw(&white_text,"Press ESC To Return",0,20,1, NO_UPDATE);
1638 if (timer_get_left(&time_left) > TIME_WARNING || (frame % 10) < 5)
1640 sprintf(str, "%d", timer_get_left(&time_left) / 1000 );
1641 text_draw(&white_text, "TIME", 224, 0, 1, NO_UPDATE);
1642 text_draw(&gold_text, str, 304, 0, 1, NO_UPDATE);
1645 sprintf(str, "%d", distros);
1646 text_draw(&white_text, "DISTROS", screen->h, 0, 1, NO_UPDATE);
1647 text_draw(&gold_text, str, 608, 0, 1, NO_UPDATE);
1649 text_draw(&white_text, "LIVES", screen->h, 20, 1, NO_UPDATE);
1653 sprintf(str, "%2.1f", fps_fps);
1654 text_draw(&white_text, "FPS", screen->h, 40, 1, NO_UPDATE);
1655 text_draw(&gold_text, str, screen->h + 60, 40, 1, NO_UPDATE);
1658 for(i=0; i < tux.lives; ++i)
1660 texture_draw(&tux_life,565+(18*i),20,NO_UPDATE);
1665 void drawendscreen(void)
1669 clearscreen(0, 0, 0);
1671 text_drawf(&blue_text, "GAMEOVER", 0, 200, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
1673 sprintf(str, "SCORE: %d", score);
1674 text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
1676 sprintf(str, "DISTROS: %d", distros);
1677 text_drawf(&gold_text, str, 0, 256, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
1683 void drawresultscreen(void)
1687 clearscreen(0, 0, 0);
1689 text_drawf(&blue_text, "Result:", 0, 200, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
1691 sprintf(str, "SCORE: %d", score);
1692 text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
1694 sprintf(str, "DISTROS: %d", distros);
1695 text_drawf(&gold_text, str, 0, 256, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
1701 void savegame(int slot)
1703 char savefile[1024];
1707 sprintf(savefile,"%s/slot%d.save",st_save_dir,slot);
1709 fi = fopen(savefile, "wb");
1713 fprintf(stderr, "Warning: I could not open the slot file ");
1718 fputs(level_subset, fi);
1720 fwrite(&level,sizeof(int),1,fi);
1721 fwrite(&score,sizeof(int),1,fi);
1722 fwrite(&distros,sizeof(int),1,fi);
1723 fwrite(&scroll_x,sizeof(float),1,fi);
1724 fwrite(&tux,sizeof(player_type),1,fi);
1725 timer_fwrite(&tux.invincible_timer,fi);
1726 timer_fwrite(&tux.skidding_timer,fi);
1727 timer_fwrite(&tux.safe_timer,fi);
1728 timer_fwrite(&tux.frame_timer,fi);
1729 timer_fwrite(&time_left,fi);
1730 ui = st_get_ticks();
1731 fwrite(&ui,sizeof(int),1,fi);
1737 void loadgame(int slot)
1739 char savefile[1024];
1744 sprintf(savefile,"%s/slot%d.save",st_save_dir,slot);
1746 fi = fopen(savefile, "rb");
1750 fprintf(stderr, "Warning: I could not open the slot file ");
1757 fgets(str, 100, fi);
1758 strcpy(level_subset, str);
1759 level_subset[strlen(level_subset)-1] = '\0';
1760 fread(&level,sizeof(int),1,fi);
1763 level_free(¤t_level);
1764 if(level_load(¤t_level,level_subset,level) != 0)
1768 activate_bad_guys();
1770 level_load_gfx(¤t_level);
1772 level_load_song(¤t_level);
1774 update_time = st_get_ticks();
1776 fread(&score,sizeof(int),1,fi);
1777 fread(&distros,sizeof(int),1,fi);
1778 fread(&scroll_x,sizeof(float),1,fi);
1779 fread(&tux,sizeof(player_type),1,fi);
1780 timer_fread(&tux.invincible_timer,fi);
1781 timer_fread(&tux.skidding_timer,fi);
1782 timer_fread(&tux.safe_timer,fi);
1783 timer_fread(&tux.frame_timer,fi);
1784 timer_fread(&time_left,fi);
1785 fread(&ui,sizeof(int),1,fi);
1786 tux.hphysic.start_time += st_get_ticks() - ui;
1787 tux.vphysic.start_time += st_get_ticks() - ui;
1793 void slotinfo(char **pinfo, int slot)
1796 char slotfile[1024];
1800 sprintf(slotfile,"%s/slot%d.save",st_save_dir,slot);
1802 fi = fopen(slotfile, "rb");
1804 sprintf(tmp,"Slot %d - ",slot);
1812 fgets(str, 100, fi);
1813 str[strlen(str)-1] = '\0';
1815 strcat(tmp, " / Level:");
1816 fread(&slot_level,sizeof(int),1,fi);
1817 sprintf(str,"%d",slot_level);
1822 *pinfo = (char*) malloc(sizeof(char) * (strlen(tmp)+1));