6 by Bill Kendrick & Tobias Glaesser
7 bill@newbreedsoftware.com
8 http://www.newbreedsoftware.com/supertux/
10 April 11, 2000 - February 1st, 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);
360 if(level_load(¤t_level,level_subset,level) != 0)
366 level_load_gfx(¤t_level);
368 level_load_song(¤t_level);
369 if(st_gl_mode != ST_GL_TEST)
373 play_current_music();
378 /* Handle bouncy distros: */
380 for (i = 0; i < num_bouncy_distros; i++)
382 bouncy_distro_action(&bouncy_distros[i]);
386 /* Handle broken bricks: */
388 for (i = 0; i < num_broken_bricks; i++)
390 broken_brick_action(&broken_bricks[i]);
394 /* Handle distro counting: */
396 if (counting_distros == YES)
400 if (distro_counter <= 0)
401 counting_distros = -1;
405 /* Handle bouncy bricks: */
407 for (i = 0; i < num_bouncy_bricks; i++)
409 bouncy_brick_action(&bouncy_bricks[i]);
413 /* Handle floating scores: */
415 for (i = 0; i < num_floating_scores; i++)
417 floating_score_action(&floating_scores[i]);
421 /* Handle bullets: */
423 for (i = 0; i < num_bullets; ++i)
425 bullet_action(&bullets[i]);
428 /* Handle upgrades: */
430 for (i = 0; i < num_upgrades; i++)
432 upgrade_action(&upgrades[i]);
436 /* Handle bad guys: */
438 for (i = 0; i < num_bad_guys; i++)
440 badguy_action(&bad_guys[i]);
443 /* Handle all possible collisions. */
449 /* --- GAME DRAW! --- */
457 if (tux.dying && (frame % 4) == 0)
458 clearscreen(255, 255, 255);
459 else if(timer_check(&super_bkgd_timer))
460 texture_draw(&img_super_bkgd, 0, 0, NO_UPDATE);
463 /* Draw the real background */
464 if(current_level.bkgd_image[0] != '\0')
466 s = (int)scroll_x / 30;
467 texture_draw_part(&img_bkgd,s,0,0,0,img_bkgd.w - s, img_bkgd.h, NO_UPDATE);
468 texture_draw_part(&img_bkgd,0,0,screen->w - s ,0,s,img_bkgd.h, NO_UPDATE);
472 clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue);
476 /* Draw background: */
478 for (y = 0; y < 15; ++y)
480 for (x = 0; x < 21; ++x)
482 drawshape(x * 32 - ((int)scroll_x % 32), y * 32,
483 current_level.tiles[(int)y][(int)x + (int)(scroll_x / 32)]);
488 /* (Bouncy bricks): */
490 for (i = 0; i < num_bouncy_bricks; ++i)
492 bouncy_brick_draw(&bouncy_bricks[i]);
498 for (i = 0; i < num_bad_guys; ++i)
500 badguy_draw(&bad_guys[i]);
509 for (i = 0; i < num_bullets; ++i)
511 bullet_draw(&bullets[i]);
514 /* (Floating scores): */
516 for (i = 0; i < num_floating_scores; ++i)
518 floating_score_draw(&floating_scores[i]);
524 for (i = 0; i < num_upgrades; ++i)
526 upgrade_draw(&upgrades[i]);
530 /* (Bouncy distros): */
532 for (i = 0; i < num_bouncy_distros; ++i)
534 bouncy_distro_draw(&bouncy_distros[i]);
538 /* (Broken bricks): */
540 for (i = 0; i < num_broken_bricks; ++i)
542 broken_brick_draw(&broken_bricks[i]);
551 for(i = 0; i < x; ++i)
553 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);
555 fillrect(0,0,screen->w,screen->h,rand() % 50, rand() % 50, rand() % 50, 128);
556 text_drawf(&blue_text, "PAUSE - Press 'P' To Play", 0, 230, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
560 menu_process_current();
562 /* (Update it all!) */
569 /* --- GAME LOOP! --- */
571 int gameloop(char * subset, int levelnb, int mode)
573 int fps_cnt, jump, done;
574 timer_type fps_timer, frame_timer;
575 timer_init(&fps_timer, YES);
576 timer_init(&frame_timer, YES);
582 strcpy(level_subset,subset);
588 if(level_load(¤t_level,level_subset,level) != 0)
590 level_load_gfx(¤t_level);
592 level_load_song(¤t_level);
596 if(st_gl_mode != ST_GL_TEST)
601 if(st_gl_mode == ST_GL_PLAY)
605 timer_init(&time_left,YES);
608 if(st_gl_mode == ST_GL_LOAD_GAME)
612 /* --- MAIN GAME LOOP!!! --- */
619 timer_init(&fps_timer,YES);
620 timer_init(&frame_timer,YES);
625 clearscreen(0, 0, 0);
629 play_current_music();
632 while (SDL_PollEvent(&event))
640 /* Calculate the movement-factor */
641 frame_ratio = ((double)(update_time-last_update_time))/((double)FRAME_RATE);
643 if(!timer_check(&frame_timer))
645 timer_start(&frame_timer,25);
651 tux.input.old_fire = tux.input.fire;
657 if(current_menu == &game_menu)
659 switch (menu_check(&game_menu))
662 st_pause_ticks_stop();
665 update_load_save_game_menu(&save_game_menu, NO);
668 update_load_save_game_menu(&load_game_menu, YES);
671 st_pause_ticks_stop();
676 else if(current_menu == &options_menu)
678 process_options_menu();
680 else if(current_menu == &save_game_menu )
682 process_save_load_game_menu(YES);
684 else if(current_menu == &load_game_menu )
686 process_save_load_game_menu(NO);
691 /* Handle actions: */
693 if(!game_pause && !show_menu)
695 /*float z = frame_ratio;
699 if (game_action() == 0)
701 /* == 0: no more lives */
702 /* == -1: continues */
714 if(debug_mode && debug_fps == YES)
717 /*Draw the current scene to the screen */
718 /*If the machine running the game is too slow
719 skip the drawing of the frame (so the calculations are more precise and
720 the FPS aren't affected).*/
721 /*if( ! fps_fps < 50.0 )
724 jump = YES;*/ /*FIXME: Implement this tweak right.*/
727 /* Time stops in pause mode */
728 if(game_pause || show_menu )
733 /* Set the time the last update and the time of the current update */
734 last_update_time = update_time;
735 update_time = st_get_ticks();
738 /* Pause till next frame, if the machine running the game is too fast: */
739 /* FIXME: Works great for in OpenGl mode, where the CPU doesn't have to do that much. But
740 the results in SDL mode aren't perfect (thought the 100 FPS are reached), even on an AMD2500+. */
741 if(last_update_time >= update_time - 12 && jump != YES )
743 /*if((update_time - last_update_time) < 10)
744 SDL_Delay((11 - (update_time - last_update_time))/2);*/
750 if (timer_check(&time_left))
752 /* are we low on time ? */
753 if ((timer_get_left(&time_left) < TIME_WARNING)
754 && (get_current_music() != HURRYUP_MUSIC)) /* play the fast music */
756 set_current_music(HURRYUP_MUSIC);
757 play_current_music();
762 player_kill(&tux,KILL);
765 /* Calculate frames per second */
769 fps_fps = (1000.0 / (float)timer_get_gone(&fps_timer)) * (float)fps_cnt;
771 if(!timer_check(&fps_timer))
773 timer_start(&fps_timer,1000);
779 while (!done && !quit);
784 level_free(¤t_level);
795 /* Load graphics/sounds shared between all levels: */
797 void loadshared(void)
800 char * herring_song_path; /* for loading herring song*/
804 texture_load(&tux_right[0],DATA_PREFIX "/images/shared/tux-right-0.png", USE_ALPHA);
805 texture_load(&tux_right[1],DATA_PREFIX "/images/shared/tux-right-1.png", USE_ALPHA);
806 texture_load(&tux_right[2],DATA_PREFIX "/images/shared/tux-right-2.png", USE_ALPHA);
808 texture_load(&tux_left[0],DATA_PREFIX "/images/shared/tux-left-0.png", USE_ALPHA);
809 texture_load(&tux_left[1],DATA_PREFIX "/images/shared/tux-left-1.png", USE_ALPHA);
810 texture_load(&tux_left[2],DATA_PREFIX "/images/shared/tux-left-2.png", USE_ALPHA);
812 texture_load(&firetux_right[0],DATA_PREFIX "/images/shared/firetux-right-0.png", USE_ALPHA);
813 texture_load(&firetux_right[1],DATA_PREFIX "/images/shared/firetux-right-1.png", USE_ALPHA);
814 texture_load(&firetux_right[2],DATA_PREFIX "/images/shared/firetux-right-2.png", USE_ALPHA);
816 texture_load(&firetux_left[0],DATA_PREFIX "/images/shared/firetux-left-0.png", USE_ALPHA);
817 texture_load(&firetux_left[1],DATA_PREFIX "/images/shared/firetux-left-1.png", USE_ALPHA);
818 texture_load(&firetux_left[2],DATA_PREFIX "/images/shared/firetux-left-2.png", USE_ALPHA);
821 texture_load(&cape_right[0] ,DATA_PREFIX "/images/shared/cape-right-0.png",
824 texture_load(&cape_right[1] ,DATA_PREFIX "/images/shared/cape-right-1.png",
827 texture_load(&cape_left[0] ,DATA_PREFIX "/images/shared/cape-left-0.png",
830 texture_load(&cape_left[1] ,DATA_PREFIX "/images/shared/cape-left-1.png",
833 texture_load(&bigtux_right[0] ,DATA_PREFIX "/images/shared/bigtux-right-0.png",
836 texture_load(&bigtux_right[1] ,DATA_PREFIX "/images/shared/bigtux-right-1.png",
839 texture_load(&bigtux_right[2] ,DATA_PREFIX "/images/shared/bigtux-right-2.png",
842 texture_load(&bigtux_right_jump ,DATA_PREFIX "/images/shared/bigtux-right-jump.png", USE_ALPHA);
844 texture_load(&bigtux_left[0] ,DATA_PREFIX "/images/shared/bigtux-left-0.png",
847 texture_load(&bigtux_left[1] ,DATA_PREFIX "/images/shared/bigtux-left-1.png",
850 texture_load(&bigtux_left[2] ,DATA_PREFIX "/images/shared/bigtux-left-2.png",
853 texture_load(&bigtux_left_jump ,DATA_PREFIX "/images/shared/bigtux-left-jump.png", USE_ALPHA);
855 texture_load(&bigcape_right[0] ,DATA_PREFIX "/images/shared/bigcape-right-0.png",
858 texture_load(&bigcape_right[1] ,DATA_PREFIX "/images/shared/bigcape-right-1.png",
861 texture_load(&bigcape_left[0] ,DATA_PREFIX "/images/shared/bigcape-left-0.png",
864 texture_load(&bigcape_left[1] ,DATA_PREFIX "/images/shared/bigcape-left-1.png",
867 texture_load(&bigfiretux_right[0] ,DATA_PREFIX "/images/shared/bigfiretux-right-0.png",
870 texture_load(&bigfiretux_right[1] ,DATA_PREFIX "/images/shared/bigfiretux-right-1.png",
873 texture_load(&bigfiretux_right[2] ,DATA_PREFIX "/images/shared/bigfiretux-right-2.png",
876 texture_load(&bigfiretux_right_jump ,DATA_PREFIX "/images/shared/bigfiretux-right-jump.png", USE_ALPHA);
878 texture_load(&bigfiretux_left[0] ,DATA_PREFIX "/images/shared/bigfiretux-left-0.png",
881 texture_load(&bigfiretux_left[1] ,DATA_PREFIX "/images/shared/bigfiretux-left-1.png",
884 texture_load(&bigfiretux_left[2] ,DATA_PREFIX "/images/shared/bigfiretux-left-2.png",
887 texture_load(&bigfiretux_left_jump ,DATA_PREFIX "/images/shared/bigfiretux-left-jump.png", USE_ALPHA);
889 texture_load(&bigcape_right[0] ,DATA_PREFIX "/images/shared/bigcape-right-0.png",
892 texture_load(&bigcape_right[1] ,DATA_PREFIX "/images/shared/bigcape-right-1.png",
895 texture_load(&bigcape_left[0] ,DATA_PREFIX "/images/shared/bigcape-left-0.png",
898 texture_load(&bigcape_left[1] ,DATA_PREFIX "/images/shared/bigcape-left-1.png",
902 texture_load(&ducktux_right ,DATA_PREFIX
903 "/images/shared/ducktux-right.png",
906 texture_load(&ducktux_left ,DATA_PREFIX
907 "/images/shared/ducktux-left.png",
910 texture_load(&skidtux_right ,DATA_PREFIX
911 "/images/shared/skidtux-right.png",
914 texture_load(&skidtux_left ,DATA_PREFIX
915 "/images/shared/skidtux-left.png",
918 texture_load(&duckfiretux_right ,DATA_PREFIX
919 "/images/shared/duckfiretux-right.png",
922 texture_load(&duckfiretux_left ,DATA_PREFIX
923 "/images/shared/duckfiretux-left.png",
926 texture_load(&skidfiretux_right ,DATA_PREFIX
927 "/images/shared/skidfiretux-right.png",
930 texture_load(&skidfiretux_left ,DATA_PREFIX
931 "/images/shared/skidfiretux-left.png",
937 texture_load(&img_box_full ,DATA_PREFIX "/images/shared/box-full.png",
939 texture_load(&img_box_empty ,DATA_PREFIX "/images/shared/box-empty.png",
946 texture_load(&img_water ,DATA_PREFIX "/images/shared/water.png", IGNORE_ALPHA);
948 texture_load(&img_waves[0] ,DATA_PREFIX "/images/shared/waves-0.png",
951 texture_load(&img_waves[1] ,DATA_PREFIX "/images/shared/waves-1.png",
954 texture_load(&img_waves[2] ,DATA_PREFIX "/images/shared/waves-2.png",
960 texture_load(&img_pole ,DATA_PREFIX "/images/shared/pole.png", USE_ALPHA);
961 texture_load(&img_poletop ,DATA_PREFIX "/images/shared/poletop.png",
967 texture_load(&img_flag[0] ,DATA_PREFIX "/images/shared/flag-0.png",
969 texture_load(&img_flag[1] ,DATA_PREFIX "/images/shared/flag-1.png",
975 texture_load(&img_cloud[0][0] ,DATA_PREFIX "/images/shared/cloud-00.png",
978 texture_load(&img_cloud[0][1] ,DATA_PREFIX "/images/shared/cloud-01.png",
981 texture_load(&img_cloud[0][2] ,DATA_PREFIX "/images/shared/cloud-02.png",
984 texture_load(&img_cloud[0][3] ,DATA_PREFIX "/images/shared/cloud-03.png",
988 texture_load(&img_cloud[1][0] ,DATA_PREFIX "/images/shared/cloud-10.png",
991 texture_load(&img_cloud[1][1] ,DATA_PREFIX "/images/shared/cloud-11.png",
994 texture_load(&img_cloud[1][2] ,DATA_PREFIX "/images/shared/cloud-12.png",
997 texture_load(&img_cloud[1][3] ,DATA_PREFIX "/images/shared/cloud-13.png",
1005 texture_load(&img_bsod_left[0] ,DATA_PREFIX
1006 "/images/shared/bsod-left-0.png",
1009 texture_load(&img_bsod_left[1] ,DATA_PREFIX
1010 "/images/shared/bsod-left-1.png",
1013 texture_load(&img_bsod_left[2] ,DATA_PREFIX
1014 "/images/shared/bsod-left-2.png",
1017 texture_load(&img_bsod_left[3] ,DATA_PREFIX
1018 "/images/shared/bsod-left-3.png",
1021 texture_load(&img_bsod_right[0] ,DATA_PREFIX
1022 "/images/shared/bsod-right-0.png",
1025 texture_load(&img_bsod_right[1] ,DATA_PREFIX
1026 "/images/shared/bsod-right-1.png",
1029 texture_load(&img_bsod_right[2] ,DATA_PREFIX
1030 "/images/shared/bsod-right-2.png",
1033 texture_load(&img_bsod_right[3] ,DATA_PREFIX
1034 "/images/shared/bsod-right-3.png",
1037 texture_load(&img_bsod_squished_left ,DATA_PREFIX
1038 "/images/shared/bsod-squished-left.png",
1041 texture_load(&img_bsod_squished_right ,DATA_PREFIX
1042 "/images/shared/bsod-squished-right.png",
1045 texture_load(&img_bsod_falling_left ,DATA_PREFIX
1046 "/images/shared/bsod-falling-left.png",
1049 texture_load(&img_bsod_falling_right ,DATA_PREFIX
1050 "/images/shared/bsod-falling-right.png",
1056 texture_load(&img_laptop_left[0] ,DATA_PREFIX
1057 "/images/shared/laptop-left-0.png",
1060 texture_load(&img_laptop_left[1] ,DATA_PREFIX
1061 "/images/shared/laptop-left-1.png",
1064 texture_load(&img_laptop_left[2] ,DATA_PREFIX
1065 "/images/shared/laptop-left-2.png",
1068 texture_load(&img_laptop_right[0] ,DATA_PREFIX
1069 "/images/shared/laptop-right-0.png",
1072 texture_load(&img_laptop_right[1] ,DATA_PREFIX
1073 "/images/shared/laptop-right-1.png",
1076 texture_load(&img_laptop_right[2] ,DATA_PREFIX
1077 "/images/shared/laptop-right-2.png",
1080 texture_load(&img_laptop_flat_left ,DATA_PREFIX
1081 "/images/shared/laptop-flat-left.png",
1084 texture_load(&img_laptop_flat_right ,DATA_PREFIX
1085 "/images/shared/laptop-flat-right.png",
1088 texture_load(&img_laptop_falling_left ,DATA_PREFIX
1089 "/images/shared/laptop-falling-left.png",
1092 texture_load(&img_laptop_falling_right ,DATA_PREFIX
1093 "/images/shared/laptop-falling-right.png",
1099 texture_load(&img_money_left[0] ,DATA_PREFIX
1100 "/images/shared/bag-left-0.png",
1103 texture_load(&img_money_left[1] ,DATA_PREFIX
1104 "/images/shared/bag-left-1.png",
1107 texture_load(&img_money_right[0] ,DATA_PREFIX
1108 "/images/shared/bag-right-0.png",
1111 texture_load(&img_money_right[1] ,DATA_PREFIX
1112 "/images/shared/bag-right-1.png",
1119 texture_load(&img_mints ,DATA_PREFIX "/images/shared/mints.png", USE_ALPHA);
1120 texture_load(&img_coffee ,DATA_PREFIX "/images/shared/coffee.png", USE_ALPHA);
1125 texture_load(&img_bullet ,DATA_PREFIX "/images/shared/bullet.png", USE_ALPHA);
1127 texture_load(&img_red_glow ,DATA_PREFIX "/images/shared/red-glow.png",
1134 texture_load(&img_distro[0] ,DATA_PREFIX "/images/shared/distro-0.png",
1137 texture_load(&img_distro[1] ,DATA_PREFIX "/images/shared/distro-1.png",
1140 texture_load(&img_distro[2] ,DATA_PREFIX "/images/shared/distro-2.png",
1143 texture_load(&img_distro[3] ,DATA_PREFIX "/images/shared/distro-3.png",
1149 texture_load(&tux_life ,DATA_PREFIX "/images/shared/tux-life.png",
1154 texture_load(&img_golden_herring, DATA_PREFIX "/images/shared/golden-herring.png",
1158 /* Super background: */
1160 texture_load(&img_super_bkgd ,DATA_PREFIX "/images/shared/super-bkgd.png",
1164 /* Sound effects: */
1166 /* if (use_sound) // this will introduce SERIOUS bugs here ! because "load_sound"
1167 // initialize sounds[i] with the correct pointer's value:
1168 // NULL or something else. And it will be dangerous to
1169 // play with not-initialized pointers.
1170 // This is also true with if (use_music)
1171 Send a mail to me: neoneurone@users.sf.net, if you have another opinion. :)
1173 for (i = 0; i < NUM_SOUNDS; i++)
1174 sounds[i] = load_sound(soundfilenames[i]);
1177 herring_song_path = (char *) malloc(sizeof(char) * (strlen(DATA_PREFIX) +
1178 strlen("SALCON.MOD") + 8));
1180 sprintf(herring_song_path, "%s/music/%s", DATA_PREFIX, "SALCON.MOD");
1182 herring_song = load_song(herring_song_path);
1184 free(herring_song_path);
1189 /* Free shared data: */
1191 void unloadshared(void)
1195 for (i = 0; i < 3; i++)
1197 texture_free(&tux_right[i]);
1198 texture_free(&tux_left[i]);
1199 texture_free(&bigtux_right[i]);
1200 texture_free(&bigtux_left[i]);
1203 texture_free(&bigtux_right_jump);
1204 texture_free(&bigtux_left_jump);
1206 for (i = 0; i < 2; i++)
1208 texture_free(&cape_right[i]);
1209 texture_free(&cape_left[i]);
1210 texture_free(&bigcape_right[i]);
1211 texture_free(&bigcape_left[i]);
1214 texture_free(&ducktux_left);
1215 texture_free(&ducktux_right);
1217 texture_free(&skidtux_left);
1218 texture_free(&skidtux_right);
1220 for (i = 0; i < 4; i++)
1222 texture_free(&img_bsod_left[i]);
1223 texture_free(&img_bsod_right[i]);
1226 texture_free(&img_bsod_squished_left);
1227 texture_free(&img_bsod_squished_right);
1229 texture_free(&img_bsod_falling_left);
1230 texture_free(&img_bsod_falling_right);
1232 for (i = 0; i < 3; i++)
1234 texture_free(&img_laptop_left[i]);
1235 texture_free(&img_laptop_right[i]);
1238 texture_free(&img_laptop_flat_left);
1239 texture_free(&img_laptop_flat_right);
1241 texture_free(&img_laptop_falling_left);
1242 texture_free(&img_laptop_falling_right);
1244 for (i = 0; i < 2; i++)
1246 texture_free(&img_money_left[i]);
1247 texture_free(&img_money_right[i]);
1250 texture_free(&img_box_full);
1251 texture_free(&img_box_empty);
1253 texture_free(&img_water);
1254 for (i = 0; i < 3; i++)
1255 texture_free(&img_waves[i]);
1257 texture_free(&img_pole);
1258 texture_free(&img_poletop);
1260 for (i = 0; i < 2; i++)
1261 texture_free(&img_flag[i]);
1263 texture_free(&img_mints);
1264 texture_free(&img_coffee);
1266 for (i = 0; i < 4; i++)
1268 texture_free(&img_distro[i]);
1269 texture_free(&img_cloud[0][i]);
1270 texture_free(&img_cloud[1][i]);
1273 texture_free(&img_golden_herring);
1275 for (i = 0; i < NUM_SOUNDS; i++)
1276 free_chunk(sounds[i]);
1278 /* free the herring song */
1279 free_music( herring_song );
1283 /* Draw a tile on the screen: */
1285 void drawshape(float x, float y, unsigned char c)
1289 if (c == 'X' || c == 'x')
1290 texture_draw(&img_brick[0], x, y, NO_UPDATE);
1291 else if (c == 'Y' || c == 'y')
1292 texture_draw(&img_brick[1], x, y, NO_UPDATE);
1293 else if (c == 'A' || c =='B' || c == '!')
1294 texture_draw(&img_box_full, x, y, NO_UPDATE);
1296 texture_draw(&img_box_empty, x, y, NO_UPDATE);
1297 else if (c >= 'C' && c <= 'F')
1298 texture_draw(&img_cloud[0][c - 'C'], x, y, NO_UPDATE);
1299 else if (c >= 'c' && c <= 'f')
1300 texture_draw(&img_cloud[1][c - 'c'], x, y, NO_UPDATE);
1301 else if (c >= 'G' && c <= 'J')
1302 texture_draw(&img_bkgd_tile[0][c - 'G'], x, y, NO_UPDATE);
1303 else if (c >= 'g' && c <= 'j')
1304 texture_draw(&img_bkgd_tile[1][c - 'g'], x, y, NO_UPDATE);
1306 texture_draw(&img_solid[0], x, y, NO_UPDATE);
1308 texture_draw(&img_solid[1], x, y, NO_UPDATE);
1310 texture_draw(&img_solid[2], x, y, NO_UPDATE);
1312 texture_draw(&img_solid[3], x, y, NO_UPDATE);
1316 z = (frame / 2) % 6;
1319 texture_draw(&img_distro[z], x, y, NO_UPDATE);
1321 texture_draw(&img_distro[2], x, y, NO_UPDATE);
1323 texture_draw(&img_distro[1], x, y, NO_UPDATE);
1327 z = (frame / 3) % 3;
1329 texture_draw(&img_waves[z], x, y, NO_UPDATE);
1332 texture_draw(&img_poletop, x, y, NO_UPDATE);
1335 texture_draw(&img_pole, x, y, NO_UPDATE);
1340 z = (frame / 3) % 2;
1342 texture_draw(&img_flag[z], x + 16, y, NO_UPDATE);
1345 texture_draw(&img_water, x, y, NO_UPDATE);
1349 /* What shape is at some position? */
1351 unsigned char shape(float x, float y)
1360 if (yy >= 0 && yy < 15 && xx >= 0 && xx <= current_level.width)
1362 c = current_level.tiles[yy][xx];
1373 int issolid(float x, float y)
1375 if (isbrick(x, y) ||
1377 (shape(x, y) == '[') ||
1378 (shape(x, y) == '=') ||
1379 (shape(x, y) == ']') ||
1380 (shape(x, y) == 'A') ||
1381 (shape(x, y) == 'B') ||
1382 (shape(x, y) == '!') ||
1383 (shape(x, y) == 'a'))
1392 int issolid(float x, float y)
1394 if (isbrick(x, y) ||
1395 isbrick(x + 31, y) ||
1398 (shape(x, y) == '[' ||
1399 shape(x + 31, y) == '[') ||
1400 (shape(x, y) == '=' ||
1401 shape(x + 31, y) == '=') ||
1402 (shape(x, y) == ']' ||
1403 shape(x + 31, y) == ']') ||
1404 (shape(x, y) == 'A' ||
1405 shape(x + 31, y) == 'A') ||
1406 (shape(x, y) == 'B' ||
1407 shape(x + 31, y) == 'B') ||
1408 (shape(x, y) == '!' ||
1409 shape(x + 31, y) == '!') ||
1410 (shape(x, y) == 'a' ||
1411 shape(x + 31, y) == 'a'))
1420 /* Is it a brick? */
1422 int isbrick(float x, float y)
1424 if (shape(x, y) == 'X' ||
1425 shape(x, y) == 'x' ||
1426 shape(x, y) == 'Y' ||
1438 int isice(float x, float y)
1440 if (shape(x, y) == '#')
1449 /* Is it a full box? */
1451 int isfullbox(float x, float y)
1453 if (shape(x, y) == 'A' ||
1454 shape(x, y) == 'B' ||
1463 /* Break a brick: */
1465 void trybreakbrick(float x, float y)
1469 if (shape(x, y) == 'x' || shape(x, y) == 'y')
1471 /* Get a distro from it: */
1473 add_bouncy_distro(((int)(x + 1) / 32) * 32,
1474 (int)(y / 32) * 32);
1476 if (counting_distros == NO)
1478 counting_distros = YES;
1479 distro_counter = 50;
1482 if (distro_counter <= 0)
1483 level_change(¤t_level,x, y, 'a');
1485 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1486 score = score + SCORE_DISTRO;
1491 /* Get rid of it: */
1493 level_change(¤t_level,x, y,'.');
1497 /* Replace it with broken bits: */
1499 add_broken_brick(((int)(x + 1) / 32) * 32,
1500 (int)(y / 32) * 32);
1503 /* Get some score: */
1505 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
1506 score = score + SCORE_BRICK;
1511 /* Bounce a brick: */
1513 void bumpbrick(float x, float y)
1515 add_bouncy_brick(((int)(x + 1) / 32) * 32,
1516 (int)(y / 32) * 32);
1518 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
1525 void tryemptybox(float x, float y, int col_side)
1527 if (!isfullbox(x, y))
1530 // according to the collision side, set the upgrade direction
1532 if(col_side == LEFT)
1539 case 'A': /* Box with a distro! */
1540 add_bouncy_distro(((int)(x + 1) / 32) * 32, (int)(y / 32) * 32 - 32);
1541 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1542 score = score + SCORE_DISTRO;
1545 case 'B': /* Add an upgrade! */
1546 if (tux.size == SMALL) /* Tux is small, add mints! */
1547 add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_MINTS);
1548 else /* Tux is big, add coffee: */
1549 add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_COFFEE);
1550 play_sound(sounds[SND_UPGRADE], SOUND_CENTER_SPEAKER);
1552 case '!': /* Add a golden herring */
1553 add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_HERRING);
1559 /* Empty the box: */
1560 level_change(¤t_level,x, y, 'a');
1564 /* Try to grab a distro: */
1566 void trygrabdistro(float x, float y, int bounciness)
1568 if (shape(x, y) == '$')
1570 level_change(¤t_level,x, y, '.');
1571 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1573 if (bounciness == BOUNCE)
1575 add_bouncy_distro(((int)(x + 1) / 32) * 32,
1576 (int)(y / 32) * 32);
1579 score = score + SCORE_DISTRO;
1584 /* Try to bump a bad guy from below: */
1586 void trybumpbadguy(float x, float y)
1593 for (i = 0; i < num_bad_guys; i++)
1595 if (bad_guys[i].base.alive &&
1596 bad_guys[i].base.x >= x - 32 && bad_guys[i].base.x <= x + 32 &&
1597 bad_guys[i].base.y >= y - 16 && bad_guys[i].base.y <= y + 16)
1599 if (bad_guys[i].kind == BAD_BSOD ||
1600 bad_guys[i].kind == BAD_LAPTOP)
1602 bad_guys[i].dying = FALLING;
1603 bad_guys[i].base.ym = -8;
1604 play_sound(sounds[SND_FALL], SOUND_CENTER_SPEAKER);
1612 for (i = 0; i < num_upgrades; i++)
1614 if (upgrades[i].base.alive && upgrades[i].base.height == 32 &&
1615 upgrades[i].base.x >= x - 32 && upgrades[i].base.x <= x + 32 &&
1616 upgrades[i].base.y >= y - 16 && upgrades[i].base.y <= y + 16)
1618 upgrades[i].base.xm = -upgrades[i].base.xm;
1619 upgrades[i].base.ym = -8;
1620 play_sound(sounds[SND_BUMP_UPGRADE], SOUND_CENTER_SPEAKER);
1626 void drawstatus(void)
1630 sprintf(str, "%d", score);
1631 text_draw(&white_text, "SCORE", 0, 0, 1, NO_UPDATE);
1632 text_draw(&gold_text, str, 96, 0, 1, NO_UPDATE);
1634 if(st_gl_mode != ST_GL_TEST)
1636 sprintf(str, "%d", hs_score);
1637 text_draw(&white_text, "HIGH", 0, 20, 1, NO_UPDATE);
1638 text_draw(&gold_text, str, 96, 20, 1, NO_UPDATE);
1642 text_draw(&white_text,"Press ESC To Return",0,20,1, NO_UPDATE);
1645 if (timer_get_left(&time_left) > TIME_WARNING || (frame % 10) < 5)
1647 sprintf(str, "%d", timer_get_left(&time_left) / 1000 );
1648 text_draw(&white_text, "TIME", 224, 0, 1, NO_UPDATE);
1649 text_draw(&gold_text, str, 304, 0, 1, NO_UPDATE);
1652 sprintf(str, "%d", distros);
1653 text_draw(&white_text, "DISTROS", screen->h, 0, 1, NO_UPDATE);
1654 text_draw(&gold_text, str, 608, 0, 1, NO_UPDATE);
1656 text_draw(&white_text, "LIVES", screen->h, 20, 1, NO_UPDATE);
1660 sprintf(str, "%2.1f", fps_fps);
1661 text_draw(&white_text, "FPS", screen->h, 40, 1, NO_UPDATE);
1662 text_draw(&gold_text, str, screen->h + 60, 40, 1, NO_UPDATE);
1665 for(i=0; i < tux.lives; ++i)
1667 texture_draw(&tux_life,565+(18*i),20,NO_UPDATE);
1672 void drawendscreen(void)
1676 clearscreen(0, 0, 0);
1678 text_drawf(&blue_text, "GAMEOVER", 0, 200, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
1680 sprintf(str, "SCORE: %d", score);
1681 text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
1683 sprintf(str, "DISTROS: %d", distros);
1684 text_drawf(&gold_text, str, 0, 256, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
1690 void drawresultscreen(void)
1694 clearscreen(0, 0, 0);
1696 text_drawf(&blue_text, "Result:", 0, 200, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
1698 sprintf(str, "SCORE: %d", score);
1699 text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
1701 sprintf(str, "DISTROS: %d", distros);
1702 text_drawf(&gold_text, str, 0, 256, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
1708 void savegame(int slot)
1710 char savefile[1024];
1714 sprintf(savefile,"%s/slot%d.save",st_save_dir,slot);
1716 fi = fopen(savefile, "wb");
1720 fprintf(stderr, "Warning: I could not open the slot file ");
1725 fputs(level_subset, fi);
1727 fwrite(&level,sizeof(int),1,fi);
1728 fwrite(&score,sizeof(int),1,fi);
1729 fwrite(&distros,sizeof(int),1,fi);
1730 fwrite(&scroll_x,sizeof(float),1,fi);
1731 fwrite(&tux,sizeof(player_type),1,fi);
1732 timer_fwrite(&tux.invincible_timer,fi);
1733 timer_fwrite(&tux.skidding_timer,fi);
1734 timer_fwrite(&tux.safe_timer,fi);
1735 timer_fwrite(&tux.frame_timer,fi);
1736 timer_fwrite(&time_left,fi);
1737 ui = st_get_ticks();
1738 fwrite(&ui,sizeof(int),1,fi);
1744 void loadgame(int slot)
1746 char savefile[1024];
1751 sprintf(savefile,"%s/slot%d.save",st_save_dir,slot);
1753 fi = fopen(savefile, "rb");
1757 fprintf(stderr, "Warning: I could not open the slot file ");
1764 fgets(str, 100, fi);
1765 strcpy(level_subset, str);
1766 level_subset[strlen(level_subset)-1] = '\0';
1767 fread(&level,sizeof(int),1,fi);
1770 level_free(¤t_level);
1771 if(level_load(¤t_level,level_subset,level) != 0)
1775 activate_bad_guys();
1777 level_load_gfx(¤t_level);
1779 level_load_song(¤t_level);
1781 update_time = st_get_ticks();
1783 fread(&score,sizeof(int),1,fi);
1784 fread(&distros,sizeof(int),1,fi);
1785 fread(&scroll_x,sizeof(float),1,fi);
1786 fread(&tux,sizeof(player_type),1,fi);
1787 timer_fread(&tux.invincible_timer,fi);
1788 timer_fread(&tux.skidding_timer,fi);
1789 timer_fread(&tux.safe_timer,fi);
1790 timer_fread(&tux.frame_timer,fi);
1791 timer_fread(&time_left,fi);
1792 fread(&ui,sizeof(int),1,fi);
1793 tux.hphysic.start_time += st_get_ticks() - ui;
1794 tux.vphysic.start_time += st_get_ticks() - ui;
1800 void slotinfo(char **pinfo, int slot)
1803 char slotfile[1024];
1807 sprintf(slotfile,"%s/slot%d.save",st_save_dir,slot);
1809 fi = fopen(slotfile, "rb");
1811 sprintf(tmp,"Slot %d - ",slot);
1819 fgets(str, 100, fi);
1820 str[strlen(str)-1] = '\0';
1822 strcat(tmp, " / Level:");
1823 fread(&slot_level,sizeof(int),1,fi);
1824 sprintf(str,"%d",slot_level);
1829 *pinfo = (char*) malloc(sizeof(char) * (strlen(tmp)+1));