6 by Bill Kendrick & Tobias Glaesser
7 bill@newbreedsoftware.com
8 http://www.newbreedsoftware.com/supertux/
10 April 11, 2000 - March 15, 2004
24 #include <sys/types.h>
33 #include "high_scores.h"
41 #include "collision.h"
43 #include "particlesystem.h"
45 /* extern variables */
47 st_level current_level;
48 int game_started = false;
50 /* Local variables: */
52 static texture_type img_waves[3], img_water, img_pole, img_poletop, img_flag[2];
53 static texture_type img_cloud[2][4];
54 static SDL_Event event;
56 static char level_subset[100];
58 static int st_gl_mode;
59 static unsigned int last_update_time;
60 static unsigned int update_time;
61 static int pause_menu_frame;
64 /* Local function prototypes: */
66 void levelintro(void);
67 void loadshared(void);
68 void unloadshared(void);
69 void drawstatus(void);
70 void drawendscreen(void);
71 void drawresultscreen(void);
79 sprintf(str, "LEVEL %d", level);
80 text_drawf(&blue_text, str, 0, 200, A_HMIDDLE, A_TOP, 1);
82 sprintf(str, "%s", current_level.name.c_str());
83 text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1);
85 sprintf(str, "TUX x %d", tux.lives);
86 text_drawf(&white_text, str, 0, 256, A_HMIDDLE, A_TOP, 1);
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)
103 for (std::vector<BadGuyData>::iterator i = current_level.badguy_data.begin();
104 i != current_level.badguy_data.end();
107 add_bad_guy(i->x, i->y, i->kind);
111 void activate_particle_systems(void)
113 if(current_level.particle_system == "clouds")
115 particle_systems.push_back(new CloudParticleSystem);
117 else if(current_level.particle_system == "snow")
119 particle_systems.push_back(new SnowParticleSystem);
121 else if(current_level.particle_system != "")
123 st_abort("unknown particle system specified in level", "");
127 /* --- GAME EVENT! --- */
129 void game_event(void)
131 while (SDL_PollEvent(&event))
133 /* Check for menu-events, if the menu is shown */
138 case SDL_QUIT: /* Quit event - quit: */
141 case SDL_KEYDOWN: /* A keypress! */
142 key = event.key.keysym.sym;
144 if(tux.key_event(key,DOWN))
149 case SDLK_ESCAPE: /* Escape: Open/Close the menu: */
152 if(st_gl_mode == ST_GL_TEST)
156 Menu::set_current(game_menu);
158 st_pause_ticks_stop();
162 Menu::set_current(game_menu);
164 st_pause_ticks_start();
172 case SDL_KEYUP: /* A keyrelease! */
173 key = event.key.keysym.sym;
175 if(tux.key_event(key, UP))
186 st_pause_ticks_stop();
191 st_pause_ticks_start();
198 tux.size = !tux.size;
201 tux.base.height = 64;
204 tux.base.height = 32;
221 timer_start(&tux.invincible_timer,TUX_INVINCIBLE_TIME);
241 case SDL_JOYAXISMOTION:
242 switch(event.jaxis.axis)
245 if (event.jaxis.value < -JOYSTICK_DEAD_ZONE)
247 tux.input.left = DOWN;
248 tux.input.right = UP;
250 else if (event.jaxis.value > JOYSTICK_DEAD_ZONE)
253 tux.input.right = DOWN;
257 tux.input.left = DOWN;
258 tux.input.right = DOWN;
262 if (event.jaxis.value > JOYSTICK_DEAD_ZONE)
263 tux.input.down = DOWN;
264 else if (event.jaxis.value < -JOYSTICK_DEAD_ZONE)
274 case SDL_JOYBUTTONDOWN:
275 if (event.jbutton.button == JOY_A)
277 else if (event.jbutton.button == JOY_B)
278 tux.input.fire = DOWN;
280 case SDL_JOYBUTTONUP:
281 if (event.jbutton.button == JOY_A)
283 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);
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... */
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)
375 activate_particle_systems();
377 level_load_gfx(¤t_level);
379 level_load_song(¤t_level);
380 if(st_gl_mode != ST_GL_TEST)
384 play_current_music();
389 /* Handle bouncy distros: */
390 for (i = 0; i < bouncy_distros.size(); i++)
392 bouncy_distro_action(&bouncy_distros[i]);
396 /* Handle broken bricks: */
397 for (i = 0; i < broken_bricks.size(); i++)
399 broken_brick_action(&broken_bricks[i]);
403 /* Handle distro counting: */
405 if (counting_distros)
409 if (distro_counter <= 0)
410 counting_distros = -1;
414 /* Handle bouncy bricks: */
416 for (i = 0; i < bouncy_bricks.size(); i++)
418 bouncy_brick_action(&bouncy_bricks[i]);
422 /* Handle floating scores: */
424 for (i = 0; i < floating_scores.size(); i++)
426 floating_score_action(&floating_scores[i]);
430 /* Handle bullets: */
432 for (i = 0; i < bullets.size(); ++i)
434 bullet_action(&bullets[i]);
437 /* Handle upgrades: */
439 for (i = 0; i < upgrades.size(); i++)
441 upgrade_action(&upgrades[i]);
445 /* Handle bad guys: */
447 for (i = 0; i < bad_guys.size(); i++)
449 bad_guys[i].action();
452 /* update particle systems */
453 std::vector<ParticleSystem*>::iterator p;
454 for(p = particle_systems.begin(); p != particle_systems.end(); ++p)
456 (*p)->simulate(frame_ratio);
459 /* Handle all possible collisions. */
465 /* --- GAME DRAW! --- */
472 if (tux.dying && (global_frame_counter % 4) == 0)
473 clearscreen(255, 255, 255);
474 else if(timer_check(&super_bkgd_timer))
475 texture_draw(&img_super_bkgd, 0, 0);
478 /* Draw the real background */
479 if(current_level.bkgd_image[0] != '\0')
481 int s = (int)scroll_x / 30;
482 texture_draw_part(&img_bkgd,s,0,0,0,img_bkgd.w - s, img_bkgd.h);
483 texture_draw_part(&img_bkgd,0,0,screen->w - s ,0,s,img_bkgd.h);
487 clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue);
491 /* Draw particle systems (background) */
492 std::vector<ParticleSystem*>::iterator p;
493 for(p = particle_systems.begin(); p != particle_systems.end(); ++p)
495 (*p)->draw(scroll_x, 0, 0);
498 /* Draw background: */
500 for (y = 0; y < 15; ++y)
502 for (x = 0; x < 21; ++x)
504 drawshape(32*x - fmodf(scroll_x, 32), y * 32,
505 current_level.bg_tiles[(int)y][(int)x + (int)(scroll_x / 32)]);
509 /* Draw interactive tiles: */
510 for (y = 0; y < 15; ++y)
512 for (x = 0; x < 21; ++x)
514 drawshape(32*x - fmodf(scroll_x, 32), y * 32,
515 current_level.ia_tiles[(int)y][(int)x + (int)(scroll_x / 32)]);
519 /* (Bouncy bricks): */
520 for (unsigned int i = 0; i < bouncy_bricks.size(); ++i)
521 bouncy_brick_draw(&bouncy_bricks[i]);
523 for (unsigned int i = 0; i < bad_guys.size(); ++i)
528 for (unsigned int i = 0; i < bullets.size(); ++i)
529 bullet_draw(&bullets[i]);
531 for (unsigned int i = 0; i < floating_scores.size(); ++i)
532 floating_score_draw(&floating_scores[i]);
534 for (unsigned int i = 0; i < upgrades.size(); ++i)
535 upgrade_draw(&upgrades[i]);
537 for (unsigned int i = 0; i < bouncy_distros.size(); ++i)
538 bouncy_distro_draw(&bouncy_distros[i]);
540 for (unsigned int i = 0; i < broken_bricks.size(); ++i)
541 broken_brick_draw(&broken_bricks[i]);
543 /* Draw foreground: */
544 for (y = 0; y < 15; ++y)
546 for (x = 0; x < 21; ++x)
548 drawshape(32*x - fmodf(scroll_x, 32), y * 32,
549 current_level.fg_tiles[(int)y][(int)x + (int)(scroll_x / 32)]);
553 /* Draw particle systems (foreground) */
554 for(p = particle_systems.begin(); p != particle_systems.end(); ++p)
556 (*p)->draw(scroll_x, 0, 1);
563 int x = screen->h / 20;
564 for(int i = 0; i < x; ++i)
566 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);
568 fillrect(0,0,screen->w,screen->h,rand() % 50, rand() % 50, rand() % 50, 128);
569 text_drawf(&blue_text, "PAUSE - Press 'P' To Play", 0, 230, A_HMIDDLE, A_TOP, 1);
574 menu_process_current();
575 mouse_cursor->draw();
578 /* (Update it all!) */
582 /* --- GAME LOOP! --- */
584 int gameloop(const char * subset, int levelnb, int mode)
586 int fps_cnt, jump, done;
587 timer_type fps_timer, frame_timer;
588 timer_init(&fps_timer, true);
589 timer_init(&frame_timer, true);
600 strcpy(level_subset,subset);
602 if (st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
604 if (level_load(¤t_level, level_subset))
609 if(level_load(¤t_level, level_subset, level) != 0)
613 level_load_gfx(¤t_level);
615 activate_particle_systems();
616 level_load_song(¤t_level);
620 if(st_gl_mode != ST_GL_TEST)
625 if(st_gl_mode == ST_GL_PLAY || st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
628 timer_init(&time_left,true);
631 if(st_gl_mode == ST_GL_LOAD_GAME)
634 /* --- MAIN GAME LOOP!!! --- */
639 global_frame_counter = 0;
641 timer_init(&fps_timer,true);
642 timer_init(&frame_timer,true);
647 clearscreen(0, 0, 0);
651 play_current_music();
654 while (SDL_PollEvent(&event))
662 /* Calculate the movement-factor */
663 frame_ratio = ((double)(update_time-last_update_time))/((double)FRAME_RATE);
664 if(frame_ratio > 1.5) /* Quick hack to correct the unprecise CPU clocks a little bit. */
665 frame_ratio = 1.5 + (frame_ratio - 1.5) * 0.85;
667 if(!timer_check(&frame_timer))
669 timer_start(&frame_timer,25);
670 ++global_frame_counter;
675 tux.input.old_fire = tux.input.fire;
681 if(current_menu == game_menu)
683 switch (game_menu->check())
686 st_pause_ticks_stop();
689 update_load_save_game_menu(save_game_menu, false);
692 update_load_save_game_menu(load_game_menu, true);
695 st_pause_ticks_stop();
700 else if(current_menu == options_menu)
702 process_options_menu();
704 else if(current_menu == save_game_menu )
706 process_save_load_game_menu(true);
708 else if(current_menu == load_game_menu )
710 process_save_load_game_menu(false);
715 /* Handle actions: */
717 if(!game_pause && !show_menu)
719 /*float z = frame_ratio;
723 if (game_action() == 0)
725 /* == 0: no more lives */
726 /* == -1: continues */
738 if(debug_mode && debug_fps)
741 /*Draw the current scene to the screen */
742 /*If the machine running the game is too slow
743 skip the drawing of the frame (so the calculations are more precise and
744 the FPS aren't affected).*/
745 /*if( ! fps_fps < 50.0 )
748 jump = true;*/ /*FIXME: Implement this tweak right.*/
751 /* Time stops in pause mode */
752 if(game_pause || show_menu )
757 /* Set the time of the last update and the time of the current update */
758 last_update_time = update_time;
759 update_time = st_get_ticks();
761 /* Pause till next frame, if the machine running the game is too fast: */
762 /* FIXME: Works great for in OpenGl mode, where the CPU doesn't have to do that much. But
763 the results in SDL mode aren't perfect (thought the 100 FPS are reached), even on an AMD2500+. */
764 if(last_update_time >= update_time - 12 && !jump)
766 /*if((update_time - last_update_time) < 10)
767 SDL_Delay((11 - (update_time - last_update_time))/2);*/
773 if (timer_check(&time_left))
775 /* are we low on time ? */
776 if ((timer_get_left(&time_left) < TIME_WARNING)
777 && (get_current_music() != HURRYUP_MUSIC)) /* play the fast music */
779 set_current_music(HURRYUP_MUSIC);
780 play_current_music();
788 /* Calculate frames per second */
792 fps_fps = (1000.0 / (float)timer_get_gone(&fps_timer)) * (float)fps_cnt;
794 if(!timer_check(&fps_timer))
796 timer_start(&fps_timer,1000);
802 while (!done && !quit);
807 level_free(¤t_level);
812 game_started = false;
818 /* Load graphics/sounds shared between all levels: */
820 void loadshared(void)
825 texture_load(&tux_right[0], datadir + "/images/shared/tux-right-0.png", USE_ALPHA);
826 texture_load(&tux_right[1], datadir + "/images/shared/tux-right-1.png", USE_ALPHA);
827 texture_load(&tux_right[2], datadir + "/images/shared/tux-right-2.png", USE_ALPHA);
829 texture_load(&tux_left[0], datadir + "/images/shared/tux-left-0.png", USE_ALPHA);
830 texture_load(&tux_left[1], datadir + "/images/shared/tux-left-1.png", USE_ALPHA);
831 texture_load(&tux_left[2], datadir + "/images/shared/tux-left-2.png", USE_ALPHA);
833 texture_load(&firetux_right[0], datadir + "/images/shared/firetux-right-0.png", USE_ALPHA);
834 texture_load(&firetux_right[1], datadir + "/images/shared/firetux-right-1.png", USE_ALPHA);
835 texture_load(&firetux_right[2], datadir + "/images/shared/firetux-right-2.png", USE_ALPHA);
837 texture_load(&firetux_left[0], datadir + "/images/shared/firetux-left-0.png", USE_ALPHA);
838 texture_load(&firetux_left[1], datadir + "/images/shared/firetux-left-1.png", USE_ALPHA);
839 texture_load(&firetux_left[2], datadir + "/images/shared/firetux-left-2.png", USE_ALPHA);
842 texture_load(&cape_right[0], datadir + "/images/shared/cape-right-0.png",
845 texture_load(&cape_right[1], datadir + "/images/shared/cape-right-1.png",
848 texture_load(&cape_left[0], datadir + "/images/shared/cape-left-0.png",
851 texture_load(&cape_left[1], datadir + "/images/shared/cape-left-1.png",
854 texture_load(&bigtux_right[0], datadir + "/images/shared/bigtux-right-0.png",
857 texture_load(&bigtux_right[1], datadir + "/images/shared/bigtux-right-1.png",
860 texture_load(&bigtux_right[2], datadir + "/images/shared/bigtux-right-2.png",
863 texture_load(&bigtux_right_jump, datadir + "/images/shared/bigtux-right-jump.png", USE_ALPHA);
865 texture_load(&bigtux_left[0], datadir + "/images/shared/bigtux-left-0.png",
868 texture_load(&bigtux_left[1], datadir + "/images/shared/bigtux-left-1.png",
871 texture_load(&bigtux_left[2], datadir + "/images/shared/bigtux-left-2.png",
874 texture_load(&bigtux_left_jump, datadir + "/images/shared/bigtux-left-jump.png", USE_ALPHA);
876 texture_load(&bigcape_right[0], datadir + "/images/shared/bigcape-right-0.png",
879 texture_load(&bigcape_right[1], datadir + "/images/shared/bigcape-right-1.png",
882 texture_load(&bigcape_left[0], datadir + "/images/shared/bigcape-left-0.png",
885 texture_load(&bigcape_left[1], datadir + "/images/shared/bigcape-left-1.png",
888 texture_load(&bigfiretux_right[0], datadir + "/images/shared/bigfiretux-right-0.png",
891 texture_load(&bigfiretux_right[1], datadir + "/images/shared/bigfiretux-right-1.png",
894 texture_load(&bigfiretux_right[2], datadir + "/images/shared/bigfiretux-right-2.png",
897 texture_load(&bigfiretux_right_jump, datadir + "/images/shared/bigfiretux-right-jump.png", USE_ALPHA);
899 texture_load(&bigfiretux_left[0], datadir + "/images/shared/bigfiretux-left-0.png",
902 texture_load(&bigfiretux_left[1], datadir + "/images/shared/bigfiretux-left-1.png",
905 texture_load(&bigfiretux_left[2], datadir + "/images/shared/bigfiretux-left-2.png",
908 texture_load(&bigfiretux_left_jump, datadir + "/images/shared/bigfiretux-left-jump.png", USE_ALPHA);
910 texture_load(&bigcape_right[0], datadir + "/images/shared/bigcape-right-0.png",
913 texture_load(&bigcape_right[1], datadir + "/images/shared/bigcape-right-1.png",
916 texture_load(&bigcape_left[0], datadir + "/images/shared/bigcape-left-0.png",
919 texture_load(&bigcape_left[1], datadir + "/images/shared/bigcape-left-1.png",
923 texture_load(&ducktux_right, datadir +
924 "/images/shared/ducktux-right.png",
927 texture_load(&ducktux_left, datadir +
928 "/images/shared/ducktux-left.png",
931 texture_load(&skidtux_right, datadir +
932 "/images/shared/skidtux-right.png",
935 texture_load(&skidtux_left, datadir +
936 "/images/shared/skidtux-left.png",
939 texture_load(&duckfiretux_right, datadir +
940 "/images/shared/duckfiretux-right.png",
943 texture_load(&duckfiretux_left, datadir +
944 "/images/shared/duckfiretux-left.png",
947 texture_load(&skidfiretux_right, datadir +
948 "/images/shared/skidfiretux-right.png",
951 texture_load(&skidfiretux_left, datadir +
952 "/images/shared/skidfiretux-left.png",
958 texture_load(&img_box_full, datadir + "/images/shared/box-full.png",
960 texture_load(&img_box_empty, datadir + "/images/shared/box-empty.png",
967 texture_load(&img_water, datadir + "/images/shared/water.png", IGNORE_ALPHA);
969 texture_load(&img_waves[0], datadir + "/images/shared/waves-0.png",
972 texture_load(&img_waves[1], datadir + "/images/shared/waves-1.png",
975 texture_load(&img_waves[2], datadir + "/images/shared/waves-2.png",
981 texture_load(&img_pole, datadir + "/images/shared/pole.png", USE_ALPHA);
982 texture_load(&img_poletop, datadir + "/images/shared/poletop.png",
988 texture_load(&img_flag[0], datadir + "/images/shared/flag-0.png",
990 texture_load(&img_flag[1], datadir + "/images/shared/flag-1.png",
996 texture_load(&img_cloud[0][0], datadir + "/images/shared/cloud-00.png",
999 texture_load(&img_cloud[0][1], datadir + "/images/shared/cloud-01.png",
1002 texture_load(&img_cloud[0][2], datadir + "/images/shared/cloud-02.png",
1005 texture_load(&img_cloud[0][3], datadir + "/images/shared/cloud-03.png",
1009 texture_load(&img_cloud[1][0], datadir + "/images/shared/cloud-10.png",
1012 texture_load(&img_cloud[1][1], datadir + "/images/shared/cloud-11.png",
1015 texture_load(&img_cloud[1][2], datadir + "/images/shared/cloud-12.png",
1018 texture_load(&img_cloud[1][3], datadir + "/images/shared/cloud-13.png",
1026 texture_load(&img_bsod_left[0], datadir +
1027 "/images/shared/bsod-left-0.png",
1030 texture_load(&img_bsod_left[1], datadir +
1031 "/images/shared/bsod-left-1.png",
1034 texture_load(&img_bsod_left[2], datadir +
1035 "/images/shared/bsod-left-2.png",
1038 texture_load(&img_bsod_left[3], datadir +
1039 "/images/shared/bsod-left-3.png",
1042 texture_load(&img_bsod_right[0], datadir +
1043 "/images/shared/bsod-right-0.png",
1046 texture_load(&img_bsod_right[1], datadir +
1047 "/images/shared/bsod-right-1.png",
1050 texture_load(&img_bsod_right[2], datadir +
1051 "/images/shared/bsod-right-2.png",
1054 texture_load(&img_bsod_right[3], datadir +
1055 "/images/shared/bsod-right-3.png",
1058 texture_load(&img_bsod_squished_left, datadir +
1059 "/images/shared/bsod-squished-left.png",
1062 texture_load(&img_bsod_squished_right, datadir +
1063 "/images/shared/bsod-squished-right.png",
1066 texture_load(&img_bsod_falling_left, datadir +
1067 "/images/shared/bsod-falling-left.png",
1070 texture_load(&img_bsod_falling_right, datadir +
1071 "/images/shared/bsod-falling-right.png",
1077 texture_load(&img_laptop_left[0], datadir +
1078 "/images/shared/laptop-left-0.png",
1081 texture_load(&img_laptop_left[1], datadir +
1082 "/images/shared/laptop-left-1.png",
1085 texture_load(&img_laptop_left[2], datadir +
1086 "/images/shared/laptop-left-2.png",
1089 texture_load(&img_laptop_right[0], datadir +
1090 "/images/shared/laptop-right-0.png",
1093 texture_load(&img_laptop_right[1], datadir +
1094 "/images/shared/laptop-right-1.png",
1097 texture_load(&img_laptop_right[2], datadir +
1098 "/images/shared/laptop-right-2.png",
1101 texture_load(&img_laptop_flat_left, datadir +
1102 "/images/shared/laptop-flat-left.png",
1105 texture_load(&img_laptop_flat_right, datadir +
1106 "/images/shared/laptop-flat-right.png",
1109 texture_load(&img_laptop_falling_left, datadir +
1110 "/images/shared/laptop-falling-left.png",
1113 texture_load(&img_laptop_falling_right, datadir +
1114 "/images/shared/laptop-falling-right.png",
1120 texture_load(&img_money_left[0], datadir +
1121 "/images/shared/bag-left-0.png",
1124 texture_load(&img_money_left[1], datadir +
1125 "/images/shared/bag-left-1.png",
1128 texture_load(&img_money_right[0], datadir +
1129 "/images/shared/bag-right-0.png",
1132 texture_load(&img_money_right[1], datadir +
1133 "/images/shared/bag-right-1.png",
1137 for(int i=0; i<4; ++i) {
1139 snprintf(num, 4, "%d", i);
1140 texture_load(&img_mrbomb_left[i],
1141 datadir + "/images/shared/mrbomb-left-" + num + ".png", USE_ALPHA);
1142 texture_load(&img_mrbomb_right[i],
1143 datadir + "/images/shared/mrbomb-right-" + num + ".png", USE_ALPHA);
1147 texture_load(&img_stalactite,
1148 datadir + "/images/shared/stalactite.png", USE_ALPHA);
1149 texture_load(&img_stalactite_broken,
1150 datadir + "/images/shared/stalactite-broken.png", USE_ALPHA);
1154 texture_load(&img_mints, datadir + "/images/shared/mints.png", USE_ALPHA);
1155 texture_load(&img_coffee, datadir + "/images/shared/coffee.png", USE_ALPHA);
1160 texture_load(&img_bullet, datadir + "/images/shared/bullet.png", USE_ALPHA);
1162 texture_load(&img_red_glow, datadir + "/images/shared/red-glow.png",
1169 texture_load(&img_distro[0], datadir + "/images/shared/distro-0.png",
1172 texture_load(&img_distro[1], datadir + "/images/shared/distro-1.png",
1175 texture_load(&img_distro[2], datadir + "/images/shared/distro-2.png",
1178 texture_load(&img_distro[3], datadir + "/images/shared/distro-3.png",
1184 texture_load(&tux_life, datadir + "/images/shared/tux-life.png",
1189 texture_load(&img_golden_herring, datadir + "/images/shared/golden-herring.png",
1193 /* Super background: */
1195 texture_load(&img_super_bkgd, datadir + "/images/shared/super-bkgd.png",
1199 /* Sound effects: */
1201 /* if (use_sound) // this will introduce SERIOUS bugs here ! because "load_sound"
1202 // initialize sounds[i] with the correct pointer's value:
1203 // NULL or something else. And it will be dangerous to
1204 // play with not-initialized pointers.
1205 // This is also true with if (use_music)
1206 Send a mail to me: neoneurone@users.sf.net, if you have another opinion. :)
1208 for (i = 0; i < NUM_SOUNDS; i++)
1209 sounds[i] = load_sound(datadir + soundfilenames[i]);
1212 herring_song = load_song(datadir + "/music/SALCON.MOD");
1216 /* Free shared data: */
1218 void unloadshared(void)
1222 for (i = 0; i < 3; i++)
1224 texture_free(&tux_right[i]);
1225 texture_free(&tux_left[i]);
1226 texture_free(&bigtux_right[i]);
1227 texture_free(&bigtux_left[i]);
1230 texture_free(&bigtux_right_jump);
1231 texture_free(&bigtux_left_jump);
1233 for (i = 0; i < 2; i++)
1235 texture_free(&cape_right[i]);
1236 texture_free(&cape_left[i]);
1237 texture_free(&bigcape_right[i]);
1238 texture_free(&bigcape_left[i]);
1241 texture_free(&ducktux_left);
1242 texture_free(&ducktux_right);
1244 texture_free(&skidtux_left);
1245 texture_free(&skidtux_right);
1247 for (i = 0; i < 4; i++)
1249 texture_free(&img_bsod_left[i]);
1250 texture_free(&img_bsod_right[i]);
1253 texture_free(&img_bsod_squished_left);
1254 texture_free(&img_bsod_squished_right);
1256 texture_free(&img_bsod_falling_left);
1257 texture_free(&img_bsod_falling_right);
1259 for (i = 0; i < 3; i++)
1261 texture_free(&img_laptop_left[i]);
1262 texture_free(&img_laptop_right[i]);
1265 texture_free(&img_laptop_flat_left);
1266 texture_free(&img_laptop_flat_right);
1268 texture_free(&img_laptop_falling_left);
1269 texture_free(&img_laptop_falling_right);
1271 for (i = 0; i < 2; i++)
1273 texture_free(&img_money_left[i]);
1274 texture_free(&img_money_right[i]);
1277 for(i = 0; i < 4; i++) {
1278 texture_free(&img_mrbomb_left[i]);
1279 texture_free(&img_mrbomb_right[i]);
1282 texture_free(&img_stalactite);
1283 texture_free(&img_stalactite_broken);
1285 texture_free(&img_box_full);
1286 texture_free(&img_box_empty);
1288 texture_free(&img_water);
1289 for (i = 0; i < 3; i++)
1290 texture_free(&img_waves[i]);
1292 texture_free(&img_pole);
1293 texture_free(&img_poletop);
1295 for (i = 0; i < 2; i++)
1296 texture_free(&img_flag[i]);
1298 texture_free(&img_mints);
1299 texture_free(&img_coffee);
1301 for (i = 0; i < 4; i++)
1303 texture_free(&img_distro[i]);
1304 texture_free(&img_cloud[0][i]);
1305 texture_free(&img_cloud[1][i]);
1308 texture_free(&img_golden_herring);
1310 for (i = 0; i < NUM_SOUNDS; i++)
1311 free_chunk(sounds[i]);
1313 /* free the herring song */
1314 free_music( herring_song );
1318 /* Draw a tile on the screen: */
1320 void drawshape(float x, float y, unsigned int c)
1324 Tile* ptile = TileManager::instance()->get(c);
1327 if(ptile->images.size() > 1)
1329 texture_draw(&ptile->images[( ((global_frame_counter*25) / ptile->anim_speed) % (ptile->images.size()))],x,y);
1331 else if (ptile->images.size() == 1)
1333 texture_draw(&ptile->images[0],x,y);
1337 printf("Tile not dravable %u\n", c);
1343 if (c == 'X' || c == 'x')
1344 texture_draw(&img_brick[0], x, y);
1345 else if (c == 'Y' || c == 'y')
1346 texture_draw(&img_brick[1], x, y);
1347 else if (c == 'A' || c =='B' || c == '!')
1348 texture_draw(&img_box_full, x, y);
1350 texture_draw(&img_box_empty, x, y);
1351 else if (c >= 'C' && c <= 'F')
1352 texture_draw(&img_cloud[0][c - 'C'], x, y);
1353 else if (c >= 'c' && c <= 'f')
1354 texture_draw(&img_cloud[1][c - 'c'], x, y);
1355 else if (c >= 'G' && c <= 'J')
1356 texture_draw(&img_bkgd_tile[0][c - 'G'], x, y);
1357 else if (c >= 'g' && c <= 'j')
1358 texture_draw(&img_bkgd_tile[1][c - 'g'], x, y);
1360 texture_draw(&img_solid[0], x, y);
1362 texture_draw(&img_solid[1], x, y);
1364 texture_draw(&img_solid[2], x, y);
1366 texture_draw(&img_solid[3], x, y);
1369 z = (global_frame_counter / 2) % 6;
1372 texture_draw(&img_distro[z], x, y);
1374 texture_draw(&img_distro[2], x, y);
1376 texture_draw(&img_distro[1], x, y);
1380 z = (global_frame_counter / 3) % 3;
1382 texture_draw(&img_waves[z], x, y);
1385 texture_draw(&img_poletop, x, y);
1388 texture_draw(&img_pole, x, y);
1393 z = (global_frame_counter / 3) % 2;
1395 texture_draw(&img_flag[z], x + 16, y);
1398 texture_draw(&img_water, x, y);*/
1403 /* What shape is at some position? */
1404 unsigned int shape(float x, float y)
1413 if (yy >= 0 && yy < 15 && xx >= 0 && xx <= current_level.width)
1415 c = current_level.ia_tiles[yy][xx];
1423 Tile* gettile(float x, float y)
1425 return TileManager::instance()->get(shape(x, y));
1428 bool issolid(float x, float y)
1430 Tile* tile = TileManager::instance()->get
1434 if(tile->solid == true)
1445 /* Is it a brick? */
1447 bool isbrick(float x, float y)
1449 Tile* tile = TileManager::instance()->get
1453 if(tile->brick == true)
1467 bool isice(float x, float y)
1469 Tile* tile = TileManager::instance()->get
1473 if(tile->ice == true)
1484 /* Is it a full box? */
1486 bool isfullbox(float x, float y)
1488 Tile* tile = TileManager::instance()->get
1492 if(tile->fullbox == true)
1503 bool isdistro(float x, float y)
1505 Tile* tile = TileManager::instance()->get(shape(x,y));
1506 return tile && tile->distro;
1509 /* Break a brick: */
1511 void trybreakbrick(float x, float y)
1513 Tile* tile = gettile(x, y);
1518 /* Get a distro from it: */
1519 add_bouncy_distro(((int)(x + 1) / 32) * 32,
1520 (int)(y / 32) * 32);
1522 if (!counting_distros)
1524 counting_distros = true;
1525 distro_counter = 50;
1528 if (distro_counter <= 0)
1529 level_change(¤t_level,x, y, TM_IA, tile->next_tile2);
1531 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1532 score = score + SCORE_DISTRO;
1537 /* Get rid of it: */
1538 level_change(¤t_level,x, y, TM_IA, tile->next_tile);
1542 /* Replace it with broken bits: */
1544 add_broken_brick(((int)(x + 1) / 32) * 32,
1545 (int)(y / 32) * 32);
1548 /* Get some score: */
1550 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
1551 score = score + SCORE_BRICK;
1556 /* Bounce a brick: */
1558 void bumpbrick(float x, float y)
1560 add_bouncy_brick(((int)(x + 1) / 32) * 32,
1561 (int)(y / 32) * 32);
1563 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
1569 void tryemptybox(float x, float y, int col_side)
1571 Tile* tile = gettile(x,y);
1575 // according to the collision side, set the upgrade direction
1576 if(col_side == LEFT)
1583 case 1: //'A': /* Box with a distro! */
1584 add_bouncy_distro(((int)(x + 1) / 32) * 32, (int)(y / 32) * 32 - 32);
1585 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1586 score = score + SCORE_DISTRO;
1590 case 2: // 'B': /* Add an upgrade! */
1591 if (tux.size == SMALL) /* Tux is small, add mints! */
1592 add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_MINTS);
1593 else /* Tux is big, add coffee: */
1594 add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_COFFEE);
1595 play_sound(sounds[SND_UPGRADE], SOUND_CENTER_SPEAKER);
1598 case 3:// '!': /* Add a golden herring */
1599 add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_HERRING);
1605 /* Empty the box: */
1606 level_change(¤t_level,x, y, TM_IA, tile->next_tile);
1609 /* Try to grab a distro: */
1610 void trygrabdistro(float x, float y, int bounciness)
1612 Tile* tile = gettile(x, y);
1613 if (tile && tile->distro)
1615 level_change(¤t_level,x, y, TM_IA, tile->next_tile);
1616 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1618 if (bounciness == BOUNCE)
1620 add_bouncy_distro(((int)(x + 1) / 32) * 32,
1621 (int)(y / 32) * 32);
1624 score = score + SCORE_DISTRO;
1629 /* Try to bump a bad guy from below: */
1630 void trybumpbadguy(float x, float y)
1633 for (unsigned int i = 0; i < bad_guys.size(); i++)
1635 if (bad_guys[i].base.x >= x - 32 && bad_guys[i].base.x <= x + 32 &&
1636 bad_guys[i].base.y >= y - 16 && bad_guys[i].base.y <= y + 16)
1638 bad_guys[i].collision(&tux, CO_PLAYER, COLLISION_BUMP);
1644 for (unsigned int i = 0; i < upgrades.size(); i++)
1646 if (upgrades[i].base.height == 32 &&
1647 upgrades[i].base.x >= x - 32 && upgrades[i].base.x <= x + 32 &&
1648 upgrades[i].base.y >= y - 16 && upgrades[i].base.y <= y + 16)
1650 upgrades[i].base.xm = -upgrades[i].base.xm;
1651 upgrades[i].base.ym = -8;
1652 play_sound(sounds[SND_BUMP_UPGRADE], SOUND_CENTER_SPEAKER);
1658 void drawstatus(void)
1662 sprintf(str, "%d", score);
1663 text_draw(&white_text, "SCORE", 0, 0, 1);
1664 text_draw(&gold_text, str, 96, 0, 1);
1666 if(st_gl_mode != ST_GL_TEST)
1668 sprintf(str, "%d", hs_score);
1669 text_draw(&white_text, "HIGH", 0, 20, 1);
1670 text_draw(&gold_text, str, 96, 20, 1);
1674 text_draw(&white_text,"Press ESC To Return",0,20,1);
1677 if (timer_get_left(&time_left) > TIME_WARNING || (global_frame_counter % 10) < 5)
1679 sprintf(str, "%d", timer_get_left(&time_left) / 1000 );
1680 text_draw(&white_text, "TIME", 224, 0, 1);
1681 text_draw(&gold_text, str, 304, 0, 1);
1684 sprintf(str, "%d", distros);
1685 text_draw(&white_text, "DISTROS", screen->h, 0, 1);
1686 text_draw(&gold_text, str, 608, 0, 1);
1688 text_draw(&white_text, "LIVES", screen->h, 20, 1);
1692 sprintf(str, "%2.1f", fps_fps);
1693 text_draw(&white_text, "FPS", screen->h, 40, 1);
1694 text_draw(&gold_text, str, screen->h + 60, 40, 1);
1697 for(int i=0; i < tux.lives; ++i)
1699 texture_draw(&tux_life,565+(18*i),20);
1704 void drawendscreen(void)
1708 clearscreen(0, 0, 0);
1710 text_drawf(&blue_text, "GAMEOVER", 0, 200, A_HMIDDLE, A_TOP, 1);
1712 sprintf(str, "SCORE: %d", score);
1713 text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1);
1715 sprintf(str, "DISTROS: %d", distros);
1716 text_drawf(&gold_text, str, 0, 256, A_HMIDDLE, A_TOP, 1);
1722 void drawresultscreen(void)
1726 clearscreen(0, 0, 0);
1728 text_drawf(&blue_text, "Result:", 0, 200, A_HMIDDLE, A_TOP, 1);
1730 sprintf(str, "SCORE: %d", score);
1731 text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1);
1733 sprintf(str, "DISTROS: %d", distros);
1734 text_drawf(&gold_text, str, 0, 256, A_HMIDDLE, A_TOP, 1);
1740 void savegame(int slot)
1742 char savefile[1024];
1746 sprintf(savefile,"%s/slot%d.save",st_save_dir,slot);
1748 fi = fopen(savefile, "wb");
1752 fprintf(stderr, "Warning: I could not open the slot file ");
1756 fputs(level_subset, fi);
1758 fwrite(&level,sizeof(int),1,fi);
1759 fwrite(&score,sizeof(int),1,fi);
1760 fwrite(&distros,sizeof(int),1,fi);
1761 fwrite(&scroll_x,sizeof(float),1,fi);
1762 fwrite(&tux,sizeof(Player),1,fi);
1763 timer_fwrite(&tux.invincible_timer,fi);
1764 timer_fwrite(&tux.skidding_timer,fi);
1765 timer_fwrite(&tux.safe_timer,fi);
1766 timer_fwrite(&tux.frame_timer,fi);
1767 timer_fwrite(&time_left,fi);
1768 ui = st_get_ticks();
1769 fwrite(&ui,sizeof(int),1,fi);
1775 void loadgame(int slot)
1777 char savefile[1024];
1782 sprintf(savefile,"%s/slot%d.save",st_save_dir,slot);
1784 fi = fopen(savefile, "rb");
1788 fprintf(stderr, "Warning: I could not open the slot file ");
1793 fgets(str, 100, fi);
1794 strcpy(level_subset, str);
1795 level_subset[strlen(level_subset)-1] = '\0';
1796 fread(&level,sizeof(int),1,fi);
1799 level_free(¤t_level);
1800 if(level_load(¤t_level,level_subset,level) != 0)
1804 activate_bad_guys();
1805 activate_particle_systems();
1807 level_load_gfx(¤t_level);
1809 level_load_song(¤t_level);
1811 update_time = st_get_ticks();
1813 fread(&score,sizeof(int),1,fi);
1814 fread(&distros,sizeof(int),1,fi);
1815 fread(&scroll_x,sizeof(float),1,fi);
1816 fread(&tux, sizeof(Player), 1, fi);
1817 timer_fread(&tux.invincible_timer,fi);
1818 timer_fread(&tux.skidding_timer,fi);
1819 timer_fread(&tux.safe_timer,fi);
1820 timer_fread(&tux.frame_timer,fi);
1821 timer_fread(&time_left,fi);
1822 fread(&ui,sizeof(int),1,fi);
1823 tux.hphysic.start_time += st_get_ticks() - ui;
1824 tux.vphysic.start_time += st_get_ticks() - ui;
1830 void slotinfo(char **pinfo, int slot)
1833 char slotfile[1024];
1837 sprintf(slotfile,"%s/slot%d.save",st_save_dir,slot);
1839 fi = fopen(slotfile, "rb");
1841 sprintf(tmp,"Slot %d - ",slot);
1849 fgets(str, 100, fi);
1850 str[strlen(str)-1] = '\0';
1852 strcat(tmp, " / Level:");
1853 fread(&slot_level,sizeof(int),1,fi);
1854 sprintf(str,"%d",slot_level);
1859 *pinfo = (char*) malloc(sizeof(char) * (strlen(tmp)+1));