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 */
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);
91 wait_for_event(event,1000,3000,true);
95 void start_timers(void)
97 timer_start(&time_left,current_level.time_left*1000);
98 st_pause_ticks_init();
99 update_time = st_get_ticks();
102 void activate_bad_guys(Level* plevel)
104 for (std::vector<BadGuyData>::iterator i = plevel->badguy_data.begin();
105 i != plevel->badguy_data.end();
108 add_bad_guy(i->x, i->y, i->kind);
112 void activate_particle_systems(void)
114 if(current_level.particle_system == "clouds")
116 particle_systems.push_back(new CloudParticleSystem);
118 else if(current_level.particle_system == "snow")
120 particle_systems.push_back(new SnowParticleSystem);
122 else if(current_level.particle_system != "")
124 st_abort("unknown particle system specified in level", "");
128 /* --- GAME EVENT! --- */
130 void game_event(void)
132 while (SDL_PollEvent(&event))
134 /* Check for menu-events, if the menu is shown */
139 case SDL_QUIT: /* Quit event - quit: */
142 case SDL_KEYDOWN: /* A keypress! */
143 key = event.key.keysym.sym;
145 if(tux.key_event(key,DOWN))
150 case SDLK_ESCAPE: /* Escape: Open/Close the menu: */
153 if(st_gl_mode == ST_GL_TEST)
157 Menu::set_current(game_menu);
159 st_pause_ticks_stop();
163 Menu::set_current(game_menu);
165 st_pause_ticks_start();
173 case SDL_KEYUP: /* A keyrelease! */
174 key = event.key.keysym.sym;
176 if(tux.key_event(key, UP))
187 st_pause_ticks_stop();
192 st_pause_ticks_start();
199 tux.size = !tux.size;
202 tux.base.height = 64;
205 tux.base.height = 32;
222 timer_start(&tux.invincible_timer,TUX_INVINCIBLE_TIME);
242 case SDL_JOYAXISMOTION:
243 switch(event.jaxis.axis)
246 if (event.jaxis.value < -JOYSTICK_DEAD_ZONE)
248 tux.input.left = DOWN;
249 tux.input.right = UP;
251 else if (event.jaxis.value > JOYSTICK_DEAD_ZONE)
254 tux.input.right = DOWN;
258 tux.input.left = DOWN;
259 tux.input.right = DOWN;
263 if (event.jaxis.value > JOYSTICK_DEAD_ZONE)
264 tux.input.down = DOWN;
265 else if (event.jaxis.value < -JOYSTICK_DEAD_ZONE)
275 case SDL_JOYBUTTONDOWN:
276 if (event.jbutton.button == JOY_A)
278 else if (event.jbutton.button == JOY_B)
279 tux.input.fire = DOWN;
281 case SDL_JOYBUTTONUP:
282 if (event.jbutton.button == JOY_A)
284 else if (event.jbutton.button == JOY_B)
297 /* --- GAME ACTION! --- */
299 int game_action(void)
303 /* (tux.is_dead() || next_level) */
304 if (tux.is_dead() || next_level)
306 /* Tux either died, or reached the end of a level! */
313 /* End of a level! */
316 if(st_gl_mode != ST_GL_TEST)
323 current_level.cleanup();
335 /* No more lives!? */
339 if(st_gl_mode != ST_GL_TEST)
342 if(st_gl_mode != ST_GL_TEST)
344 if (score > hs_score)
348 current_level.cleanup();
353 } /* if (lives < 0) */
356 /* Either way, (re-)load the (next) level... */
360 current_level.cleanup();
362 if (st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
364 if(current_level.load(level_subset) != 0)
369 if(current_level.load(level_subset,level) != 0)
374 activate_bad_guys(¤t_level);
375 activate_particle_systems();
377 current_level.load_gfx();
379 current_level.load_song();
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(timer_check(&super_bkgd_timer))
473 texture_draw(&img_super_bkgd, 0, 0);
476 /* Draw the real background */
477 if(current_level.bkgd_image[0] != '\0')
479 int s = (int)scroll_x / 30;
480 texture_draw_part(&img_bkgd,s,0,0,0,img_bkgd.w - s, img_bkgd.h);
481 texture_draw_part(&img_bkgd,0,0,screen->w - s ,0,s,img_bkgd.h);
485 clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue);
489 /* Draw particle systems (background) */
490 std::vector<ParticleSystem*>::iterator p;
491 for(p = particle_systems.begin(); p != particle_systems.end(); ++p)
493 (*p)->draw(scroll_x, 0, 0);
496 /* Draw background: */
498 for (y = 0; y < 15; ++y)
500 for (x = 0; x < 21; ++x)
502 drawshape(32*x - fmodf(scroll_x, 32), y * 32,
503 current_level.bg_tiles[(int)y][(int)x + (int)(scroll_x / 32)]);
507 /* Draw interactive tiles: */
508 for (y = 0; y < 15; ++y)
510 for (x = 0; x < 21; ++x)
512 drawshape(32*x - fmodf(scroll_x, 32), y * 32,
513 current_level.ia_tiles[(int)y][(int)x + (int)(scroll_x / 32)]);
517 /* (Bouncy bricks): */
518 for (unsigned int i = 0; i < bouncy_bricks.size(); ++i)
519 bouncy_brick_draw(&bouncy_bricks[i]);
521 for (unsigned int i = 0; i < bad_guys.size(); ++i)
526 for (unsigned int i = 0; i < bullets.size(); ++i)
527 bullet_draw(&bullets[i]);
529 for (unsigned int i = 0; i < floating_scores.size(); ++i)
530 floating_score_draw(&floating_scores[i]);
532 for (unsigned int i = 0; i < upgrades.size(); ++i)
533 upgrade_draw(&upgrades[i]);
535 for (unsigned int i = 0; i < bouncy_distros.size(); ++i)
536 bouncy_distro_draw(&bouncy_distros[i]);
538 for (unsigned int i = 0; i < broken_bricks.size(); ++i)
539 broken_brick_draw(&broken_bricks[i]);
541 /* Draw foreground: */
542 for (y = 0; y < 15; ++y)
544 for (x = 0; x < 21; ++x)
546 drawshape(32*x - fmodf(scroll_x, 32), y * 32,
547 current_level.fg_tiles[(int)y][(int)x + (int)(scroll_x / 32)]);
551 /* Draw particle systems (foreground) */
552 for(p = particle_systems.begin(); p != particle_systems.end(); ++p)
554 (*p)->draw(scroll_x, 0, 1);
561 int x = screen->h / 20;
562 for(int i = 0; i < x; ++i)
564 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);
566 fillrect(0,0,screen->w,screen->h,rand() % 50, rand() % 50, rand() % 50, 128);
567 text_drawf(&blue_text, "PAUSE - Press 'P' To Play", 0, 230, A_HMIDDLE, A_TOP, 1);
572 menu_process_current();
573 mouse_cursor->draw();
576 /* (Update it all!) */
580 /* --- GAME LOOP! --- */
582 GameSession::GameSession(const char * subset, int levelnb, int mode)
584 timer_init(&fps_timer, true);
585 timer_init(&frame_timer, true);
596 strcpy(level_subset,subset);
598 if (st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
600 if (current_level.load(level_subset))
605 if(current_level.load(level_subset, level) != 0)
609 current_level.load_gfx();
611 activate_bad_guys(¤t_level);
612 activate_particle_systems();
613 current_level.load_song();
617 if(st_gl_mode != ST_GL_TEST)
620 if(st_gl_mode == ST_GL_PLAY || st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
623 timer_init(&time_left,true);
626 if(st_gl_mode == ST_GL_LOAD_GAME)
637 /* --- MAIN GAME LOOP!!! --- */
641 global_frame_counter = 0;
643 timer_init(&fps_timer,true);
644 timer_init(&frame_timer,true);
645 last_update_time = st_get_ticks();
649 clearscreen(0, 0, 0);
653 play_current_music();
655 while (SDL_PollEvent(&event))
663 /* Calculate the movement-factor */
664 frame_ratio = ((double)(update_time-last_update_time))/((double)FRAME_RATE);
665 if(frame_ratio > 1.5) /* Quick hack to correct the unprecise CPU clocks a little bit. */
666 frame_ratio = 1.5 + (frame_ratio - 1.5) * 0.85;
668 if(!timer_check(&frame_timer))
670 timer_start(&frame_timer,25);
671 ++global_frame_counter;
676 tux.input.old_fire = tux.input.fire;
682 if(current_menu == game_menu)
684 switch (game_menu->check())
687 st_pause_ticks_stop();
690 update_load_save_game_menu(save_game_menu, false);
693 update_load_save_game_menu(load_game_menu, true);
696 st_pause_ticks_stop();
701 else if(current_menu == options_menu)
703 process_options_menu();
705 else if(current_menu == save_game_menu )
707 process_save_game_menu();
709 else if(current_menu == load_game_menu )
711 process_load_game_menu();
716 /* Handle actions: */
718 if(!game_pause && !show_menu)
720 /*float z = frame_ratio;
724 if (game_action() == 0)
726 /* == 0: no more lives */
727 /* == -1: continues */
739 if(debug_mode && debug_fps)
742 /*Draw the current scene to the screen */
743 /*If the machine running the game is too slow
744 skip the drawing of the frame (so the calculations are more precise and
745 the FPS aren't affected).*/
746 /*if( ! fps_fps < 50.0 )
749 jump = true;*/ /*FIXME: Implement this tweak right.*/
752 /* Time stops in pause mode */
753 if(game_pause || show_menu )
758 /* Set the time of the last update and the time of the current update */
759 last_update_time = update_time;
760 update_time = st_get_ticks();
762 /* Pause till next frame, if the machine running the game is too fast: */
763 /* FIXME: Works great for in OpenGl mode, where the CPU doesn't have to do that much. But
764 the results in SDL mode aren't perfect (thought the 100 FPS are reached), even on an AMD2500+. */
765 if(last_update_time >= update_time - 12 && !jump) {
767 update_time = st_get_ticks();
769 /*if((update_time - last_update_time) < 10)
770 SDL_Delay((11 - (update_time - last_update_time))/2);*/
776 if (timer_check(&time_left))
778 /* are we low on time ? */
779 if ((timer_get_left(&time_left) < TIME_WARNING)
780 && (get_current_music() != HURRYUP_MUSIC)) /* play the fast music */
782 set_current_music(HURRYUP_MUSIC);
783 play_current_music();
791 /* Calculate frames per second */
795 fps_fps = (1000.0 / (float)timer_get_gone(&fps_timer)) * (float)fps_cnt;
797 if(!timer_check(&fps_timer))
799 timer_start(&fps_timer,1000);
805 while (!done && !quit);
810 current_level.cleanup();
815 game_started = false;
821 /* Load graphics/sounds shared between all levels: */
823 void loadshared(void)
828 texture_load(&smalltux_stand_left, datadir + "/images/shared/smalltux-left-6.png", USE_ALPHA);
829 texture_load(&smalltux_stand_right, datadir + "/images/shared/smalltux-right-6.png", USE_ALPHA);
831 texture_load(&smalltux_jump_left, datadir + "/images/shared/smalltux-jump-left.png", USE_ALPHA);
832 texture_load(&smalltux_jump_right, datadir + "/images/shared/smalltux-jump-right.png", USE_ALPHA);
835 texture_load(&tux_right[0], datadir + "/images/shared/smalltux-right-1.png", USE_ALPHA);
836 texture_load(&tux_right[1], datadir + "/images/shared/smalltux-right-2.png", USE_ALPHA);
837 texture_load(&tux_right[2], datadir + "/images/shared/smalltux-right-3.png", USE_ALPHA);
838 texture_load(&tux_right[3], datadir + "/images/shared/smalltux-right-4.png", USE_ALPHA);
839 texture_load(&tux_right[4], datadir + "/images/shared/smalltux-right-5.png", USE_ALPHA);
840 texture_load(&tux_right[5], datadir + "/images/shared/smalltux-right-6.png", USE_ALPHA);
841 texture_load(&tux_right[6], datadir + "/images/shared/smalltux-right-7.png", USE_ALPHA);
842 texture_load(&tux_right[7], datadir + "/images/shared/smalltux-right-8.png", USE_ALPHA);
845 texture_load(&tux_left[0], datadir + "/images/shared/smalltux-left-1.png", USE_ALPHA);
846 texture_load(&tux_left[1], datadir + "/images/shared/smalltux-left-2.png", USE_ALPHA);
847 texture_load(&tux_left[2], datadir + "/images/shared/smalltux-left-3.png", USE_ALPHA);
848 texture_load(&tux_left[3], datadir + "/images/shared/smalltux-left-4.png", USE_ALPHA);
849 texture_load(&tux_left[4], datadir + "/images/shared/smalltux-left-5.png", USE_ALPHA);
850 texture_load(&tux_left[5], datadir + "/images/shared/smalltux-left-6.png", USE_ALPHA);
851 texture_load(&tux_left[6], datadir + "/images/shared/smalltux-left-7.png", USE_ALPHA);
852 texture_load(&tux_left[7], datadir + "/images/shared/smalltux-left-8.png", USE_ALPHA);
854 texture_load(&firetux_right[0], datadir + "/images/shared/firetux-right-0.png", USE_ALPHA);
855 texture_load(&firetux_right[1], datadir + "/images/shared/firetux-right-1.png", USE_ALPHA);
856 texture_load(&firetux_right[2], datadir + "/images/shared/firetux-right-2.png", USE_ALPHA);
858 texture_load(&firetux_left[0], datadir + "/images/shared/firetux-left-0.png", USE_ALPHA);
859 texture_load(&firetux_left[1], datadir + "/images/shared/firetux-left-1.png", USE_ALPHA);
860 texture_load(&firetux_left[2], datadir + "/images/shared/firetux-left-2.png", USE_ALPHA);
863 texture_load(&cape_right[0], datadir + "/images/shared/cape-right-0.png",
866 texture_load(&cape_right[1], datadir + "/images/shared/cape-right-1.png",
869 texture_load(&cape_left[0], datadir + "/images/shared/cape-left-0.png",
872 texture_load(&cape_left[1], datadir + "/images/shared/cape-left-1.png",
875 texture_load(&bigtux_right[0], datadir + "/images/shared/bigtux-right-0.png",
878 texture_load(&bigtux_right[1], datadir + "/images/shared/bigtux-right-1.png",
881 texture_load(&bigtux_right[2], datadir + "/images/shared/bigtux-right-2.png",
884 texture_load(&bigtux_right_jump, datadir + "/images/shared/bigtux-right-jump.png", USE_ALPHA);
886 texture_load(&bigtux_left[0], datadir + "/images/shared/bigtux-left-0.png",
889 texture_load(&bigtux_left[1], datadir + "/images/shared/bigtux-left-1.png",
892 texture_load(&bigtux_left[2], datadir + "/images/shared/bigtux-left-2.png",
895 texture_load(&bigtux_left_jump, datadir + "/images/shared/bigtux-left-jump.png", USE_ALPHA);
897 texture_load(&bigcape_right[0], datadir + "/images/shared/bigcape-right-0.png",
900 texture_load(&bigcape_right[1], datadir + "/images/shared/bigcape-right-1.png",
903 texture_load(&bigcape_left[0], datadir + "/images/shared/bigcape-left-0.png",
906 texture_load(&bigcape_left[1], datadir + "/images/shared/bigcape-left-1.png",
909 texture_load(&bigfiretux_right[0], datadir + "/images/shared/bigfiretux-right-0.png",
912 texture_load(&bigfiretux_right[1], datadir + "/images/shared/bigfiretux-right-1.png",
915 texture_load(&bigfiretux_right[2], datadir + "/images/shared/bigfiretux-right-2.png",
918 texture_load(&bigfiretux_right_jump, datadir + "/images/shared/bigfiretux-right-jump.png", USE_ALPHA);
920 texture_load(&bigfiretux_left[0], datadir + "/images/shared/bigfiretux-left-0.png",
923 texture_load(&bigfiretux_left[1], datadir + "/images/shared/bigfiretux-left-1.png",
926 texture_load(&bigfiretux_left[2], datadir + "/images/shared/bigfiretux-left-2.png",
929 texture_load(&bigfiretux_left_jump, datadir + "/images/shared/bigfiretux-left-jump.png", USE_ALPHA);
931 texture_load(&bigcape_right[0], datadir + "/images/shared/bigcape-right-0.png",
934 texture_load(&bigcape_right[1], datadir + "/images/shared/bigcape-right-1.png",
937 texture_load(&bigcape_left[0], datadir + "/images/shared/bigcape-left-0.png",
940 texture_load(&bigcape_left[1], datadir + "/images/shared/bigcape-left-1.png",
944 texture_load(&ducktux_right, datadir +
945 "/images/shared/ducktux-right.png",
948 texture_load(&ducktux_left, datadir +
949 "/images/shared/ducktux-left.png",
952 texture_load(&skidtux_right, datadir +
953 "/images/shared/skidtux-right.png",
956 texture_load(&skidtux_left, datadir +
957 "/images/shared/skidtux-left.png",
960 texture_load(&duckfiretux_right, datadir +
961 "/images/shared/duckfiretux-right.png",
964 texture_load(&duckfiretux_left, datadir +
965 "/images/shared/duckfiretux-left.png",
968 texture_load(&skidfiretux_right, datadir +
969 "/images/shared/skidfiretux-right.png",
972 texture_load(&skidfiretux_left, datadir +
973 "/images/shared/skidfiretux-left.png",
979 texture_load(&img_box_full, datadir + "/images/shared/box-full.png",
981 texture_load(&img_box_empty, datadir + "/images/shared/box-empty.png",
988 texture_load(&img_water, datadir + "/images/shared/water.png", IGNORE_ALPHA);
990 texture_load(&img_waves[0], datadir + "/images/shared/waves-0.png",
993 texture_load(&img_waves[1], datadir + "/images/shared/waves-1.png",
996 texture_load(&img_waves[2], datadir + "/images/shared/waves-2.png",
1002 texture_load(&img_pole, datadir + "/images/shared/pole.png", USE_ALPHA);
1003 texture_load(&img_poletop, datadir + "/images/shared/poletop.png",
1009 texture_load(&img_flag[0], datadir + "/images/shared/flag-0.png",
1011 texture_load(&img_flag[1], datadir + "/images/shared/flag-1.png",
1017 texture_load(&img_cloud[0][0], datadir + "/images/shared/cloud-00.png",
1020 texture_load(&img_cloud[0][1], datadir + "/images/shared/cloud-01.png",
1023 texture_load(&img_cloud[0][2], datadir + "/images/shared/cloud-02.png",
1026 texture_load(&img_cloud[0][3], datadir + "/images/shared/cloud-03.png",
1030 texture_load(&img_cloud[1][0], datadir + "/images/shared/cloud-10.png",
1033 texture_load(&img_cloud[1][1], datadir + "/images/shared/cloud-11.png",
1036 texture_load(&img_cloud[1][2], datadir + "/images/shared/cloud-12.png",
1039 texture_load(&img_cloud[1][3], datadir + "/images/shared/cloud-13.png",
1048 texture_load(&img_mints, datadir + "/images/shared/mints.png", USE_ALPHA);
1049 texture_load(&img_coffee, datadir + "/images/shared/coffee.png", USE_ALPHA);
1054 texture_load(&img_bullet, datadir + "/images/shared/bullet.png", USE_ALPHA);
1056 texture_load(&img_red_glow, datadir + "/images/shared/red-glow.png",
1063 texture_load(&img_distro[0], datadir + "/images/shared/distro-0.png",
1066 texture_load(&img_distro[1], datadir + "/images/shared/distro-1.png",
1069 texture_load(&img_distro[2], datadir + "/images/shared/distro-2.png",
1072 texture_load(&img_distro[3], datadir + "/images/shared/distro-3.png",
1078 texture_load(&tux_life, datadir + "/images/shared/tux-life.png",
1083 texture_load(&img_golden_herring, datadir + "/images/shared/golden-herring.png",
1087 /* Super background: */
1089 texture_load(&img_super_bkgd, datadir + "/images/shared/super-bkgd.png",
1093 /* Sound effects: */
1095 /* if (use_sound) // this will introduce SERIOUS bugs here ! because "load_sound"
1096 // initialize sounds[i] with the correct pointer's value:
1097 // NULL or something else. And it will be dangerous to
1098 // play with not-initialized pointers.
1099 // This is also true with if (use_music)
1100 Send a mail to me: neoneurone@users.sf.net, if you have another opinion. :)
1102 for (i = 0; i < NUM_SOUNDS; i++)
1103 sounds[i] = load_sound(datadir + soundfilenames[i]);
1106 herring_song = load_song(datadir + "/music/SALCON.MOD");
1110 /* Free shared data: */
1112 void unloadshared(void)
1116 for (i = 0; i < 3; i++)
1118 texture_free(&tux_right[i]);
1119 texture_free(&tux_left[i]);
1120 texture_free(&bigtux_right[i]);
1121 texture_free(&bigtux_left[i]);
1124 texture_free(&bigtux_right_jump);
1125 texture_free(&bigtux_left_jump);
1127 for (i = 0; i < 2; i++)
1129 texture_free(&cape_right[i]);
1130 texture_free(&cape_left[i]);
1131 texture_free(&bigcape_right[i]);
1132 texture_free(&bigcape_left[i]);
1135 texture_free(&ducktux_left);
1136 texture_free(&ducktux_right);
1138 texture_free(&skidtux_left);
1139 texture_free(&skidtux_right);
1143 texture_free(&img_box_full);
1144 texture_free(&img_box_empty);
1146 texture_free(&img_water);
1147 for (i = 0; i < 3; i++)
1148 texture_free(&img_waves[i]);
1150 texture_free(&img_pole);
1151 texture_free(&img_poletop);
1153 for (i = 0; i < 2; i++)
1154 texture_free(&img_flag[i]);
1156 texture_free(&img_mints);
1157 texture_free(&img_coffee);
1159 for (i = 0; i < 4; i++)
1161 texture_free(&img_distro[i]);
1162 texture_free(&img_cloud[0][i]);
1163 texture_free(&img_cloud[1][i]);
1166 texture_free(&img_golden_herring);
1168 for (i = 0; i < NUM_SOUNDS; i++)
1169 free_chunk(sounds[i]);
1171 /* free the herring song */
1172 free_music( herring_song );
1176 /* Draw a tile on the screen: */
1178 void drawshape(float x, float y, unsigned int c, Uint8 alpha)
1182 Tile* ptile = TileManager::instance()->get(c);
1185 if(ptile->images.size() > 1)
1187 texture_draw(&ptile->images[( ((global_frame_counter*25) / ptile->anim_speed) % (ptile->images.size()))],x,y, alpha);
1189 else if (ptile->images.size() == 1)
1191 texture_draw(&ptile->images[0],x,y, alpha);
1195 //printf("Tile not dravable %u\n", c);
1201 /* Break a brick: */
1202 void trybreakbrick(float x, float y, bool small)
1204 Tile* tile = gettile(x, y);
1209 /* Get a distro from it: */
1210 add_bouncy_distro(((int)(x + 1) / 32) * 32,
1211 (int)(y / 32) * 32);
1213 if (!counting_distros)
1215 counting_distros = true;
1216 distro_counter = 50;
1219 if (distro_counter <= 0)
1220 current_level.change(x, y, TM_IA, tile->next_tile);
1222 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1223 score = score + SCORE_DISTRO;
1228 /* Get rid of it: */
1229 current_level.change(x, y, TM_IA, tile->next_tile);
1231 /* Replace it with broken bits: */
1232 add_broken_brick(((int)(x + 1) / 32) * 32,
1233 (int)(y / 32) * 32);
1235 /* Get some score: */
1236 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
1237 score = score + SCORE_BRICK;
1243 /* Bounce a brick: */
1245 void bumpbrick(float x, float y)
1247 add_bouncy_brick(((int)(x + 1) / 32) * 32,
1248 (int)(y / 32) * 32);
1250 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
1254 void tryemptybox(float x, float y, int col_side)
1256 Tile* tile = gettile(x,y);
1260 // according to the collision side, set the upgrade direction
1261 if(col_side == LEFT)
1268 case 1: //'A': /* Box with a distro! */
1269 add_bouncy_distro(((int)(x + 1) / 32) * 32, (int)(y / 32) * 32 - 32);
1270 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1271 score = score + SCORE_DISTRO;
1275 case 2: // 'B': /* Add an upgrade! */
1276 if (tux.size == SMALL) /* Tux is small, add mints! */
1277 add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_MINTS);
1278 else /* Tux is big, add coffee: */
1279 add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_COFFEE);
1280 play_sound(sounds[SND_UPGRADE], SOUND_CENTER_SPEAKER);
1283 case 3:// '!': /* Add a golden herring */
1284 add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_HERRING);
1290 /* Empty the box: */
1291 current_level.change(x, y, TM_IA, tile->next_tile);
1294 /* Try to grab a distro: */
1295 void trygrabdistro(float x, float y, int bounciness)
1297 Tile* tile = gettile(x, y);
1298 if (tile && tile->distro)
1300 current_level.change(x, y, TM_IA, tile->next_tile);
1301 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1303 if (bounciness == BOUNCE)
1305 add_bouncy_distro(((int)(x + 1) / 32) * 32,
1306 (int)(y / 32) * 32);
1309 score = score + SCORE_DISTRO;
1314 /* Try to bump a bad guy from below: */
1315 void trybumpbadguy(float x, float y)
1318 for (unsigned int i = 0; i < bad_guys.size(); i++)
1320 if (bad_guys[i].base.x >= x - 32 && bad_guys[i].base.x <= x + 32 &&
1321 bad_guys[i].base.y >= y - 16 && bad_guys[i].base.y <= y + 16)
1323 bad_guys[i].collision(&tux, CO_PLAYER, COLLISION_BUMP);
1329 for (unsigned int i = 0; i < upgrades.size(); i++)
1331 if (upgrades[i].base.height == 32 &&
1332 upgrades[i].base.x >= x - 32 && upgrades[i].base.x <= x + 32 &&
1333 upgrades[i].base.y >= y - 16 && upgrades[i].base.y <= y + 16)
1335 upgrades[i].base.xm = -upgrades[i].base.xm;
1336 upgrades[i].base.ym = -8;
1337 play_sound(sounds[SND_BUMP_UPGRADE], SOUND_CENTER_SPEAKER);
1343 void drawstatus(void)
1347 sprintf(str, "%d", score);
1348 text_draw(&white_text, "SCORE", 0, 0, 1);
1349 text_draw(&gold_text, str, 96, 0, 1);
1351 if(st_gl_mode != ST_GL_TEST)
1353 sprintf(str, "%d", hs_score);
1354 text_draw(&white_text, "HIGH", 0, 20, 1);
1355 text_draw(&gold_text, str, 96, 20, 1);
1359 text_draw(&white_text,"Press ESC To Return",0,20,1);
1362 if (timer_get_left(&time_left) > TIME_WARNING || (global_frame_counter % 10) < 5)
1364 sprintf(str, "%d", timer_get_left(&time_left) / 1000 );
1365 text_draw(&white_text, "TIME", 224, 0, 1);
1366 text_draw(&gold_text, str, 304, 0, 1);
1369 sprintf(str, "%d", distros);
1370 text_draw(&white_text, "DISTROS", screen->h, 0, 1);
1371 text_draw(&gold_text, str, 608, 0, 1);
1373 text_draw(&white_text, "LIVES", screen->h, 20, 1);
1377 sprintf(str, "%2.1f", fps_fps);
1378 text_draw(&white_text, "FPS", screen->h, 40, 1);
1379 text_draw(&gold_text, str, screen->h + 60, 40, 1);
1382 for(int i=0; i < tux.lives; ++i)
1384 texture_draw(&tux_life,565+(18*i),20);
1389 void drawendscreen(void)
1393 clearscreen(0, 0, 0);
1395 text_drawf(&blue_text, "GAMEOVER", 0, 200, A_HMIDDLE, A_TOP, 1);
1397 sprintf(str, "SCORE: %d", score);
1398 text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1);
1400 sprintf(str, "DISTROS: %d", distros);
1401 text_drawf(&gold_text, str, 0, 256, A_HMIDDLE, A_TOP, 1);
1406 wait_for_event(event,2000,5000,true);
1409 void drawresultscreen(void)
1413 clearscreen(0, 0, 0);
1415 text_drawf(&blue_text, "Result:", 0, 200, A_HMIDDLE, A_TOP, 1);
1417 sprintf(str, "SCORE: %d", score);
1418 text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1);
1420 sprintf(str, "DISTROS: %d", distros);
1421 text_drawf(&gold_text, str, 0, 256, A_HMIDDLE, A_TOP, 1);
1426 wait_for_event(event,2000,5000,true);
1429 void savegame(int slot)
1431 char savefile[1024];
1435 sprintf(savefile,"%s/slot%d.save",st_save_dir,slot);
1437 fi = fopen(savefile, "wb");
1441 fprintf(stderr, "Warning: I could not open the slot file ");
1445 fputs(level_subset, fi);
1447 fwrite(&level,sizeof(int),1,fi);
1448 fwrite(&score,sizeof(int),1,fi);
1449 fwrite(&distros,sizeof(int),1,fi);
1450 fwrite(&scroll_x,sizeof(float),1,fi);
1451 fwrite(&tux,sizeof(Player),1,fi);
1452 timer_fwrite(&tux.invincible_timer,fi);
1453 timer_fwrite(&tux.skidding_timer,fi);
1454 timer_fwrite(&tux.safe_timer,fi);
1455 timer_fwrite(&tux.frame_timer,fi);
1456 timer_fwrite(&time_left,fi);
1457 ui = st_get_ticks();
1458 fwrite(&ui,sizeof(int),1,fi);
1464 void loadgame(int slot)
1466 char savefile[1024];
1471 sprintf(savefile,"%s/slot%d.save",st_save_dir,slot);
1473 fi = fopen(savefile, "rb");
1477 fprintf(stderr, "Warning: I could not open the slot file ");
1482 fgets(str, 100, fi);
1483 strcpy(level_subset, str);
1484 level_subset[strlen(level_subset)-1] = '\0';
1485 fread(&level,sizeof(int),1,fi);
1488 current_level.cleanup();
1489 if(current_level.load(level_subset,level) != 0)
1492 activate_bad_guys(¤t_level);
1493 activate_particle_systems();
1495 current_level.load_gfx();
1497 current_level.load_song();
1499 update_time = st_get_ticks();
1501 fread(&score,sizeof(int),1,fi);
1502 fread(&distros,sizeof(int),1,fi);
1503 fread(&scroll_x,sizeof(float),1,fi);
1504 fread(&tux, sizeof(Player), 1, fi);
1505 timer_fread(&tux.invincible_timer,fi);
1506 timer_fread(&tux.skidding_timer,fi);
1507 timer_fread(&tux.safe_timer,fi);
1508 timer_fread(&tux.frame_timer,fi);
1509 timer_fread(&time_left,fi);
1510 fread(&ui,sizeof(int),1,fi);
1516 std::string slotinfo(int slot)
1519 char slotfile[1024];
1523 sprintf(slotfile,"%s/slot%d.save",st_save_dir,slot);
1525 fi = fopen(slotfile, "rb");
1527 sprintf(tmp,"Slot %d - ",slot);
1535 fgets(str, 100, fi);
1536 str[strlen(str)-1] = '\0';
1538 strcat(tmp, " / Level:");
1539 fread(&slot_level,sizeof(int),1,fi);
1540 sprintf(str,"%d",slot_level);