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);
573 menu_process_current();
575 /* (Update it all!) */
579 /* --- GAME LOOP! --- */
581 int gameloop(const char * subset, int levelnb, int mode)
583 int fps_cnt, jump, done;
584 timer_type fps_timer, frame_timer;
585 timer_init(&fps_timer, true);
586 timer_init(&frame_timer, true);
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 activate_particle_systems();
613 level_load_song(¤t_level);
617 if(st_gl_mode != ST_GL_TEST)
622 if(st_gl_mode == ST_GL_PLAY || st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
625 timer_init(&time_left,true);
628 if(st_gl_mode == ST_GL_LOAD_GAME)
631 /* --- MAIN GAME LOOP!!! --- */
636 global_frame_counter = 0;
638 timer_init(&fps_timer,true);
639 timer_init(&frame_timer,true);
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);
667 ++global_frame_counter;
672 tux.input.old_fire = tux.input.fire;
678 if(current_menu == game_menu)
680 switch (game_menu->check())
683 st_pause_ticks_stop();
686 update_load_save_game_menu(save_game_menu, false);
689 update_load_save_game_menu(load_game_menu, true);
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(true);
705 else if(current_menu == load_game_menu )
707 process_save_load_game_menu(false);
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)
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 = true;*/ /*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();
758 /* Pause till next frame, if the machine running the game is too fast: */
759 /* FIXME: Works great for in OpenGl mode, where the CPU doesn't have to do that much. But
760 the results in SDL mode aren't perfect (thought the 100 FPS are reached), even on an AMD2500+. */
761 if(last_update_time >= update_time - 12 && !jump)
763 /*if((update_time - last_update_time) < 10)
764 SDL_Delay((11 - (update_time - last_update_time))/2);*/
770 if (timer_check(&time_left))
772 /* are we low on time ? */
773 if ((timer_get_left(&time_left) < TIME_WARNING)
774 && (get_current_music() != HURRYUP_MUSIC)) /* play the fast music */
776 set_current_music(HURRYUP_MUSIC);
777 play_current_music();
785 /* Calculate frames per second */
789 fps_fps = (1000.0 / (float)timer_get_gone(&fps_timer)) * (float)fps_cnt;
791 if(!timer_check(&fps_timer))
793 timer_start(&fps_timer,1000);
799 while (!done && !quit);
804 level_free(¤t_level);
809 game_started = false;
815 /* Load graphics/sounds shared between all levels: */
817 void loadshared(void)
822 texture_load(&tux_right[0], datadir + "/images/shared/tux-right-0.png", USE_ALPHA);
823 texture_load(&tux_right[1], datadir + "/images/shared/tux-right-1.png", USE_ALPHA);
824 texture_load(&tux_right[2], datadir + "/images/shared/tux-right-2.png", USE_ALPHA);
826 texture_load(&tux_left[0], datadir + "/images/shared/tux-left-0.png", USE_ALPHA);
827 texture_load(&tux_left[1], datadir + "/images/shared/tux-left-1.png", USE_ALPHA);
828 texture_load(&tux_left[2], datadir + "/images/shared/tux-left-2.png", USE_ALPHA);
830 texture_load(&firetux_right[0], datadir + "/images/shared/firetux-right-0.png", USE_ALPHA);
831 texture_load(&firetux_right[1], datadir + "/images/shared/firetux-right-1.png", USE_ALPHA);
832 texture_load(&firetux_right[2], datadir + "/images/shared/firetux-right-2.png", USE_ALPHA);
834 texture_load(&firetux_left[0], datadir + "/images/shared/firetux-left-0.png", USE_ALPHA);
835 texture_load(&firetux_left[1], datadir + "/images/shared/firetux-left-1.png", USE_ALPHA);
836 texture_load(&firetux_left[2], datadir + "/images/shared/firetux-left-2.png", USE_ALPHA);
839 texture_load(&cape_right[0], datadir + "/images/shared/cape-right-0.png",
842 texture_load(&cape_right[1], datadir + "/images/shared/cape-right-1.png",
845 texture_load(&cape_left[0], datadir + "/images/shared/cape-left-0.png",
848 texture_load(&cape_left[1], datadir + "/images/shared/cape-left-1.png",
851 texture_load(&bigtux_right[0], datadir + "/images/shared/bigtux-right-0.png",
854 texture_load(&bigtux_right[1], datadir + "/images/shared/bigtux-right-1.png",
857 texture_load(&bigtux_right[2], datadir + "/images/shared/bigtux-right-2.png",
860 texture_load(&bigtux_right_jump, datadir + "/images/shared/bigtux-right-jump.png", USE_ALPHA);
862 texture_load(&bigtux_left[0], datadir + "/images/shared/bigtux-left-0.png",
865 texture_load(&bigtux_left[1], datadir + "/images/shared/bigtux-left-1.png",
868 texture_load(&bigtux_left[2], datadir + "/images/shared/bigtux-left-2.png",
871 texture_load(&bigtux_left_jump, datadir + "/images/shared/bigtux-left-jump.png", USE_ALPHA);
873 texture_load(&bigcape_right[0], datadir + "/images/shared/bigcape-right-0.png",
876 texture_load(&bigcape_right[1], datadir + "/images/shared/bigcape-right-1.png",
879 texture_load(&bigcape_left[0], datadir + "/images/shared/bigcape-left-0.png",
882 texture_load(&bigcape_left[1], datadir + "/images/shared/bigcape-left-1.png",
885 texture_load(&bigfiretux_right[0], datadir + "/images/shared/bigfiretux-right-0.png",
888 texture_load(&bigfiretux_right[1], datadir + "/images/shared/bigfiretux-right-1.png",
891 texture_load(&bigfiretux_right[2], datadir + "/images/shared/bigfiretux-right-2.png",
894 texture_load(&bigfiretux_right_jump, datadir + "/images/shared/bigfiretux-right-jump.png", USE_ALPHA);
896 texture_load(&bigfiretux_left[0], datadir + "/images/shared/bigfiretux-left-0.png",
899 texture_load(&bigfiretux_left[1], datadir + "/images/shared/bigfiretux-left-1.png",
902 texture_load(&bigfiretux_left[2], datadir + "/images/shared/bigfiretux-left-2.png",
905 texture_load(&bigfiretux_left_jump, datadir + "/images/shared/bigfiretux-left-jump.png", USE_ALPHA);
907 texture_load(&bigcape_right[0], datadir + "/images/shared/bigcape-right-0.png",
910 texture_load(&bigcape_right[1], datadir + "/images/shared/bigcape-right-1.png",
913 texture_load(&bigcape_left[0], datadir + "/images/shared/bigcape-left-0.png",
916 texture_load(&bigcape_left[1], datadir + "/images/shared/bigcape-left-1.png",
920 texture_load(&ducktux_right, datadir +
921 "/images/shared/ducktux-right.png",
924 texture_load(&ducktux_left, datadir +
925 "/images/shared/ducktux-left.png",
928 texture_load(&skidtux_right, datadir +
929 "/images/shared/skidtux-right.png",
932 texture_load(&skidtux_left, datadir +
933 "/images/shared/skidtux-left.png",
936 texture_load(&duckfiretux_right, datadir +
937 "/images/shared/duckfiretux-right.png",
940 texture_load(&duckfiretux_left, datadir +
941 "/images/shared/duckfiretux-left.png",
944 texture_load(&skidfiretux_right, datadir +
945 "/images/shared/skidfiretux-right.png",
948 texture_load(&skidfiretux_left, datadir +
949 "/images/shared/skidfiretux-left.png",
955 texture_load(&img_box_full, datadir + "/images/shared/box-full.png",
957 texture_load(&img_box_empty, datadir + "/images/shared/box-empty.png",
964 texture_load(&img_water, datadir + "/images/shared/water.png", IGNORE_ALPHA);
966 texture_load(&img_waves[0], datadir + "/images/shared/waves-0.png",
969 texture_load(&img_waves[1], datadir + "/images/shared/waves-1.png",
972 texture_load(&img_waves[2], datadir + "/images/shared/waves-2.png",
978 texture_load(&img_pole, datadir + "/images/shared/pole.png", USE_ALPHA);
979 texture_load(&img_poletop, datadir + "/images/shared/poletop.png",
985 texture_load(&img_flag[0], datadir + "/images/shared/flag-0.png",
987 texture_load(&img_flag[1], datadir + "/images/shared/flag-1.png",
993 texture_load(&img_cloud[0][0], datadir + "/images/shared/cloud-00.png",
996 texture_load(&img_cloud[0][1], datadir + "/images/shared/cloud-01.png",
999 texture_load(&img_cloud[0][2], datadir + "/images/shared/cloud-02.png",
1002 texture_load(&img_cloud[0][3], datadir + "/images/shared/cloud-03.png",
1006 texture_load(&img_cloud[1][0], datadir + "/images/shared/cloud-10.png",
1009 texture_load(&img_cloud[1][1], datadir + "/images/shared/cloud-11.png",
1012 texture_load(&img_cloud[1][2], datadir + "/images/shared/cloud-12.png",
1015 texture_load(&img_cloud[1][3], datadir + "/images/shared/cloud-13.png",
1023 texture_load(&img_bsod_left[0], datadir +
1024 "/images/shared/bsod-left-0.png",
1027 texture_load(&img_bsod_left[1], datadir +
1028 "/images/shared/bsod-left-1.png",
1031 texture_load(&img_bsod_left[2], datadir +
1032 "/images/shared/bsod-left-2.png",
1035 texture_load(&img_bsod_left[3], datadir +
1036 "/images/shared/bsod-left-3.png",
1039 texture_load(&img_bsod_right[0], datadir +
1040 "/images/shared/bsod-right-0.png",
1043 texture_load(&img_bsod_right[1], datadir +
1044 "/images/shared/bsod-right-1.png",
1047 texture_load(&img_bsod_right[2], datadir +
1048 "/images/shared/bsod-right-2.png",
1051 texture_load(&img_bsod_right[3], datadir +
1052 "/images/shared/bsod-right-3.png",
1055 texture_load(&img_bsod_squished_left, datadir +
1056 "/images/shared/bsod-squished-left.png",
1059 texture_load(&img_bsod_squished_right, datadir +
1060 "/images/shared/bsod-squished-right.png",
1063 texture_load(&img_bsod_falling_left, datadir +
1064 "/images/shared/bsod-falling-left.png",
1067 texture_load(&img_bsod_falling_right, datadir +
1068 "/images/shared/bsod-falling-right.png",
1074 texture_load(&img_laptop_left[0], datadir +
1075 "/images/shared/laptop-left-0.png",
1078 texture_load(&img_laptop_left[1], datadir +
1079 "/images/shared/laptop-left-1.png",
1082 texture_load(&img_laptop_left[2], datadir +
1083 "/images/shared/laptop-left-2.png",
1086 texture_load(&img_laptop_right[0], datadir +
1087 "/images/shared/laptop-right-0.png",
1090 texture_load(&img_laptop_right[1], datadir +
1091 "/images/shared/laptop-right-1.png",
1094 texture_load(&img_laptop_right[2], datadir +
1095 "/images/shared/laptop-right-2.png",
1098 texture_load(&img_laptop_flat_left, datadir +
1099 "/images/shared/laptop-flat-left.png",
1102 texture_load(&img_laptop_flat_right, datadir +
1103 "/images/shared/laptop-flat-right.png",
1106 texture_load(&img_laptop_falling_left, datadir +
1107 "/images/shared/laptop-falling-left.png",
1110 texture_load(&img_laptop_falling_right, datadir +
1111 "/images/shared/laptop-falling-right.png",
1117 texture_load(&img_money_left[0], datadir +
1118 "/images/shared/bag-left-0.png",
1121 texture_load(&img_money_left[1], datadir +
1122 "/images/shared/bag-left-1.png",
1125 texture_load(&img_money_right[0], datadir +
1126 "/images/shared/bag-right-0.png",
1129 texture_load(&img_money_right[1], datadir +
1130 "/images/shared/bag-right-1.png",
1134 for(int i=0; i<4; ++i) {
1136 snprintf(num, 4, "%d", i);
1137 texture_load(&img_mrbomb_left[i],
1138 datadir + "/images/shared/mrbomb-left-" + num + ".png", USE_ALPHA);
1139 texture_load(&img_mrbomb_right[i],
1140 datadir + "/images/shared/mrbomb-right-" + num + ".png", USE_ALPHA);
1144 texture_load(&img_stalactite,
1145 datadir + "/images/shared/stalactite.png", USE_ALPHA);
1146 texture_load(&img_stalactite_broken,
1147 datadir + "/images/shared/stalactite-broken.png", USE_ALPHA);
1151 texture_load(&img_mints, datadir + "/images/shared/mints.png", USE_ALPHA);
1152 texture_load(&img_coffee, datadir + "/images/shared/coffee.png", USE_ALPHA);
1157 texture_load(&img_bullet, datadir + "/images/shared/bullet.png", USE_ALPHA);
1159 texture_load(&img_red_glow, datadir + "/images/shared/red-glow.png",
1166 texture_load(&img_distro[0], datadir + "/images/shared/distro-0.png",
1169 texture_load(&img_distro[1], datadir + "/images/shared/distro-1.png",
1172 texture_load(&img_distro[2], datadir + "/images/shared/distro-2.png",
1175 texture_load(&img_distro[3], datadir + "/images/shared/distro-3.png",
1181 texture_load(&tux_life, datadir + "/images/shared/tux-life.png",
1186 texture_load(&img_golden_herring, datadir + "/images/shared/golden-herring.png",
1190 /* Super background: */
1192 texture_load(&img_super_bkgd, datadir + "/images/shared/super-bkgd.png",
1196 /* Sound effects: */
1198 /* if (use_sound) // this will introduce SERIOUS bugs here ! because "load_sound"
1199 // initialize sounds[i] with the correct pointer's value:
1200 // NULL or something else. And it will be dangerous to
1201 // play with not-initialized pointers.
1202 // This is also true with if (use_music)
1203 Send a mail to me: neoneurone@users.sf.net, if you have another opinion. :)
1205 for (i = 0; i < NUM_SOUNDS; i++)
1206 sounds[i] = load_sound(datadir + soundfilenames[i]);
1209 herring_song = load_song(datadir + "/music/SALCON.MOD");
1213 /* Free shared data: */
1215 void unloadshared(void)
1219 for (i = 0; i < 3; i++)
1221 texture_free(&tux_right[i]);
1222 texture_free(&tux_left[i]);
1223 texture_free(&bigtux_right[i]);
1224 texture_free(&bigtux_left[i]);
1227 texture_free(&bigtux_right_jump);
1228 texture_free(&bigtux_left_jump);
1230 for (i = 0; i < 2; i++)
1232 texture_free(&cape_right[i]);
1233 texture_free(&cape_left[i]);
1234 texture_free(&bigcape_right[i]);
1235 texture_free(&bigcape_left[i]);
1238 texture_free(&ducktux_left);
1239 texture_free(&ducktux_right);
1241 texture_free(&skidtux_left);
1242 texture_free(&skidtux_right);
1244 for (i = 0; i < 4; i++)
1246 texture_free(&img_bsod_left[i]);
1247 texture_free(&img_bsod_right[i]);
1250 texture_free(&img_bsod_squished_left);
1251 texture_free(&img_bsod_squished_right);
1253 texture_free(&img_bsod_falling_left);
1254 texture_free(&img_bsod_falling_right);
1256 for (i = 0; i < 3; i++)
1258 texture_free(&img_laptop_left[i]);
1259 texture_free(&img_laptop_right[i]);
1262 texture_free(&img_laptop_flat_left);
1263 texture_free(&img_laptop_flat_right);
1265 texture_free(&img_laptop_falling_left);
1266 texture_free(&img_laptop_falling_right);
1268 for (i = 0; i < 2; i++)
1270 texture_free(&img_money_left[i]);
1271 texture_free(&img_money_right[i]);
1274 for(i = 0; i < 4; i++) {
1275 texture_free(&img_mrbomb_left[i]);
1276 texture_free(&img_mrbomb_right[i]);
1279 texture_free(&img_stalactite);
1280 texture_free(&img_stalactite_broken);
1282 texture_free(&img_box_full);
1283 texture_free(&img_box_empty);
1285 texture_free(&img_water);
1286 for (i = 0; i < 3; i++)
1287 texture_free(&img_waves[i]);
1289 texture_free(&img_pole);
1290 texture_free(&img_poletop);
1292 for (i = 0; i < 2; i++)
1293 texture_free(&img_flag[i]);
1295 texture_free(&img_mints);
1296 texture_free(&img_coffee);
1298 for (i = 0; i < 4; i++)
1300 texture_free(&img_distro[i]);
1301 texture_free(&img_cloud[0][i]);
1302 texture_free(&img_cloud[1][i]);
1305 texture_free(&img_golden_herring);
1307 for (i = 0; i < NUM_SOUNDS; i++)
1308 free_chunk(sounds[i]);
1310 /* free the herring song */
1311 free_music( herring_song );
1315 /* Draw a tile on the screen: */
1317 void drawshape(float x, float y, unsigned int c)
1321 Tile* ptile = TileManager::instance()->get(c);
1324 if(ptile->images.size() > 1)
1326 texture_draw(&ptile->images[( ((global_frame_counter*25) / ptile->anim_speed) % (ptile->images.size()))],x,y);
1328 else if (ptile->images.size() == 1)
1330 texture_draw(&ptile->images[0],x,y);
1334 printf("Tile not dravable %u\n", c);
1340 if (c == 'X' || c == 'x')
1341 texture_draw(&img_brick[0], x, y);
1342 else if (c == 'Y' || c == 'y')
1343 texture_draw(&img_brick[1], x, y);
1344 else if (c == 'A' || c =='B' || c == '!')
1345 texture_draw(&img_box_full, x, y);
1347 texture_draw(&img_box_empty, x, y);
1348 else if (c >= 'C' && c <= 'F')
1349 texture_draw(&img_cloud[0][c - 'C'], x, y);
1350 else if (c >= 'c' && c <= 'f')
1351 texture_draw(&img_cloud[1][c - 'c'], x, y);
1352 else if (c >= 'G' && c <= 'J')
1353 texture_draw(&img_bkgd_tile[0][c - 'G'], x, y);
1354 else if (c >= 'g' && c <= 'j')
1355 texture_draw(&img_bkgd_tile[1][c - 'g'], x, y);
1357 texture_draw(&img_solid[0], x, y);
1359 texture_draw(&img_solid[1], x, y);
1361 texture_draw(&img_solid[2], x, y);
1363 texture_draw(&img_solid[3], x, y);
1366 z = (global_frame_counter / 2) % 6;
1369 texture_draw(&img_distro[z], x, y);
1371 texture_draw(&img_distro[2], x, y);
1373 texture_draw(&img_distro[1], x, y);
1377 z = (global_frame_counter / 3) % 3;
1379 texture_draw(&img_waves[z], x, y);
1382 texture_draw(&img_poletop, x, y);
1385 texture_draw(&img_pole, x, y);
1390 z = (global_frame_counter / 3) % 2;
1392 texture_draw(&img_flag[z], x + 16, y);
1395 texture_draw(&img_water, x, y);*/
1400 /* What shape is at some position? */
1401 unsigned int shape(float x, float y)
1410 if (yy >= 0 && yy < 15 && xx >= 0 && xx <= current_level.width)
1412 c = current_level.ia_tiles[yy][xx];
1420 Tile* gettile(float x, float y)
1422 return TileManager::instance()->get(shape(x, y));
1425 bool issolid(float x, float y)
1427 Tile* tile = TileManager::instance()->get
1431 if(tile->solid == true)
1442 /* Is it a brick? */
1444 bool isbrick(float x, float y)
1446 Tile* tile = TileManager::instance()->get
1450 if(tile->brick == true)
1464 bool isice(float x, float y)
1466 Tile* tile = TileManager::instance()->get
1470 if(tile->ice == true)
1481 /* Is it a full box? */
1483 bool isfullbox(float x, float y)
1485 Tile* tile = TileManager::instance()->get
1489 if(tile->fullbox == true)
1500 bool isdistro(float x, float y)
1502 Tile* tile = TileManager::instance()->get(shape(x,y));
1503 return tile && tile->distro;
1506 /* Break a brick: */
1508 void trybreakbrick(float x, float y)
1510 Tile* tile = gettile(x, y);
1515 /* Get a distro from it: */
1516 add_bouncy_distro(((int)(x + 1) / 32) * 32,
1517 (int)(y / 32) * 32);
1519 if (!counting_distros)
1521 counting_distros = true;
1522 distro_counter = 50;
1525 if (distro_counter <= 0)
1526 level_change(¤t_level,x, y, TM_IA, tile->next_tile2);
1528 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1529 score = score + SCORE_DISTRO;
1534 /* Get rid of it: */
1535 level_change(¤t_level,x, y, TM_IA, tile->next_tile);
1539 /* Replace it with broken bits: */
1541 add_broken_brick(((int)(x + 1) / 32) * 32,
1542 (int)(y / 32) * 32);
1545 /* Get some score: */
1547 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
1548 score = score + SCORE_BRICK;
1553 /* Bounce a brick: */
1555 void bumpbrick(float x, float y)
1557 add_bouncy_brick(((int)(x + 1) / 32) * 32,
1558 (int)(y / 32) * 32);
1560 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
1566 void tryemptybox(float x, float y, int col_side)
1568 Tile* tile = gettile(x,y);
1572 // according to the collision side, set the upgrade direction
1573 if(col_side == LEFT)
1580 case 1: //'A': /* Box with a distro! */
1581 add_bouncy_distro(((int)(x + 1) / 32) * 32, (int)(y / 32) * 32 - 32);
1582 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1583 score = score + SCORE_DISTRO;
1587 case 2: // 'B': /* Add an upgrade! */
1588 if (tux.size == SMALL) /* Tux is small, add mints! */
1589 add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_MINTS);
1590 else /* Tux is big, add coffee: */
1591 add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_COFFEE);
1592 play_sound(sounds[SND_UPGRADE], SOUND_CENTER_SPEAKER);
1595 case 3:// '!': /* Add a golden herring */
1596 add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_HERRING);
1602 /* Empty the box: */
1603 level_change(¤t_level,x, y, TM_IA, tile->next_tile);
1606 /* Try to grab a distro: */
1607 void trygrabdistro(float x, float y, int bounciness)
1609 Tile* tile = gettile(x, y);
1610 if (tile && tile->distro)
1612 level_change(¤t_level,x, y, TM_IA, tile->next_tile);
1613 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1615 if (bounciness == BOUNCE)
1617 add_bouncy_distro(((int)(x + 1) / 32) * 32,
1618 (int)(y / 32) * 32);
1621 score = score + SCORE_DISTRO;
1626 /* Try to bump a bad guy from below: */
1627 void trybumpbadguy(float x, float y)
1630 for (unsigned int i = 0; i < bad_guys.size(); i++)
1632 if (bad_guys[i].base.x >= x - 32 && bad_guys[i].base.x <= x + 32 &&
1633 bad_guys[i].base.y >= y - 16 && bad_guys[i].base.y <= y + 16)
1635 bad_guys[i].collision(&tux, CO_PLAYER, COLLISION_BUMP);
1641 for (unsigned int i = 0; i < upgrades.size(); i++)
1643 if (upgrades[i].base.height == 32 &&
1644 upgrades[i].base.x >= x - 32 && upgrades[i].base.x <= x + 32 &&
1645 upgrades[i].base.y >= y - 16 && upgrades[i].base.y <= y + 16)
1647 upgrades[i].base.xm = -upgrades[i].base.xm;
1648 upgrades[i].base.ym = -8;
1649 play_sound(sounds[SND_BUMP_UPGRADE], SOUND_CENTER_SPEAKER);
1655 void drawstatus(void)
1659 sprintf(str, "%d", score);
1660 text_draw(&white_text, "SCORE", 0, 0, 1);
1661 text_draw(&gold_text, str, 96, 0, 1);
1663 if(st_gl_mode != ST_GL_TEST)
1665 sprintf(str, "%d", hs_score);
1666 text_draw(&white_text, "HIGH", 0, 20, 1);
1667 text_draw(&gold_text, str, 96, 20, 1);
1671 text_draw(&white_text,"Press ESC To Return",0,20,1);
1674 if (timer_get_left(&time_left) > TIME_WARNING || (global_frame_counter % 10) < 5)
1676 sprintf(str, "%d", timer_get_left(&time_left) / 1000 );
1677 text_draw(&white_text, "TIME", 224, 0, 1);
1678 text_draw(&gold_text, str, 304, 0, 1);
1681 sprintf(str, "%d", distros);
1682 text_draw(&white_text, "DISTROS", screen->h, 0, 1);
1683 text_draw(&gold_text, str, 608, 0, 1);
1685 text_draw(&white_text, "LIVES", screen->h, 20, 1);
1689 sprintf(str, "%2.1f", fps_fps);
1690 text_draw(&white_text, "FPS", screen->h, 40, 1);
1691 text_draw(&gold_text, str, screen->h + 60, 40, 1);
1694 for(int i=0; i < tux.lives; ++i)
1696 texture_draw(&tux_life,565+(18*i),20);
1701 void drawendscreen(void)
1705 clearscreen(0, 0, 0);
1707 text_drawf(&blue_text, "GAMEOVER", 0, 200, A_HMIDDLE, A_TOP, 1);
1709 sprintf(str, "SCORE: %d", score);
1710 text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1);
1712 sprintf(str, "DISTROS: %d", distros);
1713 text_drawf(&gold_text, str, 0, 256, A_HMIDDLE, A_TOP, 1);
1719 void drawresultscreen(void)
1723 clearscreen(0, 0, 0);
1725 text_drawf(&blue_text, "Result:", 0, 200, A_HMIDDLE, A_TOP, 1);
1727 sprintf(str, "SCORE: %d", score);
1728 text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1);
1730 sprintf(str, "DISTROS: %d", distros);
1731 text_drawf(&gold_text, str, 0, 256, A_HMIDDLE, A_TOP, 1);
1737 void savegame(int slot)
1739 char savefile[1024];
1743 sprintf(savefile,"%s/slot%d.save",st_save_dir,slot);
1745 fi = fopen(savefile, "wb");
1749 fprintf(stderr, "Warning: I could not open the slot file ");
1753 fputs(level_subset, fi);
1755 fwrite(&level,sizeof(int),1,fi);
1756 fwrite(&score,sizeof(int),1,fi);
1757 fwrite(&distros,sizeof(int),1,fi);
1758 fwrite(&scroll_x,sizeof(float),1,fi);
1759 fwrite(&tux,sizeof(Player),1,fi);
1760 timer_fwrite(&tux.invincible_timer,fi);
1761 timer_fwrite(&tux.skidding_timer,fi);
1762 timer_fwrite(&tux.safe_timer,fi);
1763 timer_fwrite(&tux.frame_timer,fi);
1764 timer_fwrite(&time_left,fi);
1765 ui = st_get_ticks();
1766 fwrite(&ui,sizeof(int),1,fi);
1772 void loadgame(int slot)
1774 char savefile[1024];
1779 sprintf(savefile,"%s/slot%d.save",st_save_dir,slot);
1781 fi = fopen(savefile, "rb");
1785 fprintf(stderr, "Warning: I could not open the slot file ");
1790 fgets(str, 100, fi);
1791 strcpy(level_subset, str);
1792 level_subset[strlen(level_subset)-1] = '\0';
1793 fread(&level,sizeof(int),1,fi);
1796 level_free(¤t_level);
1797 if(level_load(¤t_level,level_subset,level) != 0)
1801 activate_bad_guys();
1802 activate_particle_systems();
1804 level_load_gfx(¤t_level);
1806 level_load_song(¤t_level);
1808 update_time = st_get_ticks();
1810 fread(&score,sizeof(int),1,fi);
1811 fread(&distros,sizeof(int),1,fi);
1812 fread(&scroll_x,sizeof(float),1,fi);
1813 fread(&tux, sizeof(Player), 1, fi);
1814 timer_fread(&tux.invincible_timer,fi);
1815 timer_fread(&tux.skidding_timer,fi);
1816 timer_fread(&tux.safe_timer,fi);
1817 timer_fread(&tux.frame_timer,fi);
1818 timer_fread(&time_left,fi);
1819 fread(&ui,sizeof(int),1,fi);
1820 tux.hphysic.start_time += st_get_ticks() - ui;
1821 tux.vphysic.start_time += st_get_ticks() - ui;
1827 void slotinfo(char **pinfo, int slot)
1830 char slotfile[1024];
1834 sprintf(slotfile,"%s/slot%d.save",st_save_dir,slot);
1836 fi = fopen(slotfile, "rb");
1838 sprintf(tmp,"Slot %d - ",slot);
1846 fgets(str, 100, fi);
1847 str[strlen(str)-1] = '\0';
1849 strcat(tmp, " / Level:");
1850 fread(&slot_level,sizeof(int),1,fi);
1851 sprintf(str,"%d",slot_level);
1856 *pinfo = (char*) malloc(sizeof(char) * (strlen(tmp)+1));