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);
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(st_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 level_free(¤t_level);
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 level_free(¤t_level);
353 } /* if (lives < 0) */
356 /* Either way, (re-)load the (next) level... */
360 level_free(¤t_level);
362 if (st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
364 if(level_load(¤t_level, level_subset) != 0)
369 if(level_load(¤t_level,level_subset,level) != 0)
374 activate_bad_guys(¤t_level);
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(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 int gameloop(const char * subset, int levelnb, int mode)
584 int fps_cnt, jump, done;
585 timer_type fps_timer, frame_timer;
586 timer_init(&fps_timer, true);
587 timer_init(&frame_timer, true);
598 strcpy(level_subset,subset);
600 if (st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
602 if (level_load(¤t_level, level_subset))
607 if(level_load(¤t_level, level_subset, level) != 0)
611 level_load_gfx(¤t_level);
613 activate_bad_guys(¤t_level);
614 activate_particle_systems();
615 level_load_song(¤t_level);
619 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);
640 last_update_time = st_get_ticks();
645 clearscreen(0, 0, 0);
649 play_current_music();
652 while (SDL_PollEvent(&event))
660 /* Calculate the movement-factor */
661 frame_ratio = ((double)(update_time-last_update_time))/((double)FRAME_RATE);
662 if(frame_ratio > 1.5) /* Quick hack to correct the unprecise CPU clocks a little bit. */
663 frame_ratio = 1.5 + (frame_ratio - 1.5) * 0.85;
665 if(!timer_check(&frame_timer))
667 timer_start(&frame_timer,25);
668 ++global_frame_counter;
673 tux.input.old_fire = tux.input.fire;
679 if(current_menu == game_menu)
681 switch (game_menu->check())
684 st_pause_ticks_stop();
687 update_load_save_game_menu(save_game_menu, false);
690 update_load_save_game_menu(load_game_menu, true);
693 st_pause_ticks_stop();
698 else if(current_menu == options_menu)
700 process_options_menu();
702 else if(current_menu == save_game_menu )
704 process_save_game_menu();
706 else if(current_menu == load_game_menu )
708 process_load_game_menu();
713 /* Handle actions: */
715 if(!game_pause && !show_menu)
717 /*float z = frame_ratio;
721 if (game_action() == 0)
723 /* == 0: no more lives */
724 /* == -1: continues */
736 if(debug_mode && debug_fps)
739 /*Draw the current scene to the screen */
740 /*If the machine running the game is too slow
741 skip the drawing of the frame (so the calculations are more precise and
742 the FPS aren't affected).*/
743 /*if( ! fps_fps < 50.0 )
746 jump = true;*/ /*FIXME: Implement this tweak right.*/
749 /* Time stops in pause mode */
750 if(game_pause || show_menu )
755 /* Set the time of the last update and the time of the current update */
756 last_update_time = update_time;
757 update_time = st_get_ticks();
759 /* Pause till next frame, if the machine running the game is too fast: */
760 /* FIXME: Works great for in OpenGl mode, where the CPU doesn't have to do that much. But
761 the results in SDL mode aren't perfect (thought the 100 FPS are reached), even on an AMD2500+. */
762 if(last_update_time >= update_time - 12 && !jump) {
764 update_time = st_get_ticks();
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(&smalltux_stand_left, datadir + "/images/shared/smalltux-left-6.png", USE_ALPHA);
826 texture_load(&smalltux_stand_right, datadir + "/images/shared/smalltux-right-6.png", USE_ALPHA);
828 texture_load(&smalltux_jump_left, datadir + "/images/shared/smalltux-jump-left.png", USE_ALPHA);
829 texture_load(&smalltux_jump_right, datadir + "/images/shared/smalltux-jump-right.png", USE_ALPHA);
832 texture_load(&tux_right[0], datadir + "/images/shared/smalltux-right-1.png", USE_ALPHA);
833 texture_load(&tux_right[1], datadir + "/images/shared/smalltux-right-2.png", USE_ALPHA);
834 texture_load(&tux_right[2], datadir + "/images/shared/smalltux-right-3.png", USE_ALPHA);
835 texture_load(&tux_right[3], datadir + "/images/shared/smalltux-right-4.png", USE_ALPHA);
836 texture_load(&tux_right[4], datadir + "/images/shared/smalltux-right-5.png", USE_ALPHA);
837 texture_load(&tux_right[5], datadir + "/images/shared/smalltux-right-6.png", USE_ALPHA);
838 texture_load(&tux_right[6], datadir + "/images/shared/smalltux-right-7.png", USE_ALPHA);
839 texture_load(&tux_right[7], datadir + "/images/shared/smalltux-right-8.png", USE_ALPHA);
842 texture_load(&tux_left[0], datadir + "/images/shared/smalltux-left-1.png", USE_ALPHA);
843 texture_load(&tux_left[1], datadir + "/images/shared/smalltux-left-2.png", USE_ALPHA);
844 texture_load(&tux_left[2], datadir + "/images/shared/smalltux-left-3.png", USE_ALPHA);
845 texture_load(&tux_left[3], datadir + "/images/shared/smalltux-left-4.png", USE_ALPHA);
846 texture_load(&tux_left[4], datadir + "/images/shared/smalltux-left-5.png", USE_ALPHA);
847 texture_load(&tux_left[5], datadir + "/images/shared/smalltux-left-6.png", USE_ALPHA);
848 texture_load(&tux_left[6], datadir + "/images/shared/smalltux-left-7.png", USE_ALPHA);
849 texture_load(&tux_left[7], datadir + "/images/shared/smalltux-left-8.png", USE_ALPHA);
851 texture_load(&firetux_right[0], datadir + "/images/shared/firetux-right-0.png", USE_ALPHA);
852 texture_load(&firetux_right[1], datadir + "/images/shared/firetux-right-1.png", USE_ALPHA);
853 texture_load(&firetux_right[2], datadir + "/images/shared/firetux-right-2.png", USE_ALPHA);
855 texture_load(&firetux_left[0], datadir + "/images/shared/firetux-left-0.png", USE_ALPHA);
856 texture_load(&firetux_left[1], datadir + "/images/shared/firetux-left-1.png", USE_ALPHA);
857 texture_load(&firetux_left[2], datadir + "/images/shared/firetux-left-2.png", USE_ALPHA);
860 texture_load(&cape_right[0], datadir + "/images/shared/cape-right-0.png",
863 texture_load(&cape_right[1], datadir + "/images/shared/cape-right-1.png",
866 texture_load(&cape_left[0], datadir + "/images/shared/cape-left-0.png",
869 texture_load(&cape_left[1], datadir + "/images/shared/cape-left-1.png",
872 texture_load(&bigtux_right[0], datadir + "/images/shared/bigtux-right-0.png",
875 texture_load(&bigtux_right[1], datadir + "/images/shared/bigtux-right-1.png",
878 texture_load(&bigtux_right[2], datadir + "/images/shared/bigtux-right-2.png",
881 texture_load(&bigtux_right_jump, datadir + "/images/shared/bigtux-right-jump.png", USE_ALPHA);
883 texture_load(&bigtux_left[0], datadir + "/images/shared/bigtux-left-0.png",
886 texture_load(&bigtux_left[1], datadir + "/images/shared/bigtux-left-1.png",
889 texture_load(&bigtux_left[2], datadir + "/images/shared/bigtux-left-2.png",
892 texture_load(&bigtux_left_jump, datadir + "/images/shared/bigtux-left-jump.png", USE_ALPHA);
894 texture_load(&bigcape_right[0], datadir + "/images/shared/bigcape-right-0.png",
897 texture_load(&bigcape_right[1], datadir + "/images/shared/bigcape-right-1.png",
900 texture_load(&bigcape_left[0], datadir + "/images/shared/bigcape-left-0.png",
903 texture_load(&bigcape_left[1], datadir + "/images/shared/bigcape-left-1.png",
906 texture_load(&bigfiretux_right[0], datadir + "/images/shared/bigfiretux-right-0.png",
909 texture_load(&bigfiretux_right[1], datadir + "/images/shared/bigfiretux-right-1.png",
912 texture_load(&bigfiretux_right[2], datadir + "/images/shared/bigfiretux-right-2.png",
915 texture_load(&bigfiretux_right_jump, datadir + "/images/shared/bigfiretux-right-jump.png", USE_ALPHA);
917 texture_load(&bigfiretux_left[0], datadir + "/images/shared/bigfiretux-left-0.png",
920 texture_load(&bigfiretux_left[1], datadir + "/images/shared/bigfiretux-left-1.png",
923 texture_load(&bigfiretux_left[2], datadir + "/images/shared/bigfiretux-left-2.png",
926 texture_load(&bigfiretux_left_jump, datadir + "/images/shared/bigfiretux-left-jump.png", USE_ALPHA);
928 texture_load(&bigcape_right[0], datadir + "/images/shared/bigcape-right-0.png",
931 texture_load(&bigcape_right[1], datadir + "/images/shared/bigcape-right-1.png",
934 texture_load(&bigcape_left[0], datadir + "/images/shared/bigcape-left-0.png",
937 texture_load(&bigcape_left[1], datadir + "/images/shared/bigcape-left-1.png",
941 texture_load(&ducktux_right, datadir +
942 "/images/shared/ducktux-right.png",
945 texture_load(&ducktux_left, datadir +
946 "/images/shared/ducktux-left.png",
949 texture_load(&skidtux_right, datadir +
950 "/images/shared/skidtux-right.png",
953 texture_load(&skidtux_left, datadir +
954 "/images/shared/skidtux-left.png",
957 texture_load(&duckfiretux_right, datadir +
958 "/images/shared/duckfiretux-right.png",
961 texture_load(&duckfiretux_left, datadir +
962 "/images/shared/duckfiretux-left.png",
965 texture_load(&skidfiretux_right, datadir +
966 "/images/shared/skidfiretux-right.png",
969 texture_load(&skidfiretux_left, datadir +
970 "/images/shared/skidfiretux-left.png",
976 texture_load(&img_box_full, datadir + "/images/shared/box-full.png",
978 texture_load(&img_box_empty, datadir + "/images/shared/box-empty.png",
985 texture_load(&img_water, datadir + "/images/shared/water.png", IGNORE_ALPHA);
987 texture_load(&img_waves[0], datadir + "/images/shared/waves-0.png",
990 texture_load(&img_waves[1], datadir + "/images/shared/waves-1.png",
993 texture_load(&img_waves[2], datadir + "/images/shared/waves-2.png",
999 texture_load(&img_pole, datadir + "/images/shared/pole.png", USE_ALPHA);
1000 texture_load(&img_poletop, datadir + "/images/shared/poletop.png",
1006 texture_load(&img_flag[0], datadir + "/images/shared/flag-0.png",
1008 texture_load(&img_flag[1], datadir + "/images/shared/flag-1.png",
1014 texture_load(&img_cloud[0][0], datadir + "/images/shared/cloud-00.png",
1017 texture_load(&img_cloud[0][1], datadir + "/images/shared/cloud-01.png",
1020 texture_load(&img_cloud[0][2], datadir + "/images/shared/cloud-02.png",
1023 texture_load(&img_cloud[0][3], datadir + "/images/shared/cloud-03.png",
1027 texture_load(&img_cloud[1][0], datadir + "/images/shared/cloud-10.png",
1030 texture_load(&img_cloud[1][1], datadir + "/images/shared/cloud-11.png",
1033 texture_load(&img_cloud[1][2], datadir + "/images/shared/cloud-12.png",
1036 texture_load(&img_cloud[1][3], datadir + "/images/shared/cloud-13.png",
1045 texture_load(&img_mints, datadir + "/images/shared/mints.png", USE_ALPHA);
1046 texture_load(&img_coffee, datadir + "/images/shared/coffee.png", USE_ALPHA);
1051 texture_load(&img_bullet, datadir + "/images/shared/bullet.png", USE_ALPHA);
1053 texture_load(&img_red_glow, datadir + "/images/shared/red-glow.png",
1060 texture_load(&img_distro[0], datadir + "/images/shared/distro-0.png",
1063 texture_load(&img_distro[1], datadir + "/images/shared/distro-1.png",
1066 texture_load(&img_distro[2], datadir + "/images/shared/distro-2.png",
1069 texture_load(&img_distro[3], datadir + "/images/shared/distro-3.png",
1075 texture_load(&tux_life, datadir + "/images/shared/tux-life.png",
1080 texture_load(&img_golden_herring, datadir + "/images/shared/golden-herring.png",
1084 /* Super background: */
1086 texture_load(&img_super_bkgd, datadir + "/images/shared/super-bkgd.png",
1090 /* Sound effects: */
1092 /* if (use_sound) // this will introduce SERIOUS bugs here ! because "load_sound"
1093 // initialize sounds[i] with the correct pointer's value:
1094 // NULL or something else. And it will be dangerous to
1095 // play with not-initialized pointers.
1096 // This is also true with if (use_music)
1097 Send a mail to me: neoneurone@users.sf.net, if you have another opinion. :)
1099 for (i = 0; i < NUM_SOUNDS; i++)
1100 sounds[i] = load_sound(datadir + soundfilenames[i]);
1103 herring_song = load_song(datadir + "/music/SALCON.MOD");
1107 /* Free shared data: */
1109 void unloadshared(void)
1113 for (i = 0; i < 3; i++)
1115 texture_free(&tux_right[i]);
1116 texture_free(&tux_left[i]);
1117 texture_free(&bigtux_right[i]);
1118 texture_free(&bigtux_left[i]);
1121 texture_free(&bigtux_right_jump);
1122 texture_free(&bigtux_left_jump);
1124 for (i = 0; i < 2; i++)
1126 texture_free(&cape_right[i]);
1127 texture_free(&cape_left[i]);
1128 texture_free(&bigcape_right[i]);
1129 texture_free(&bigcape_left[i]);
1132 texture_free(&ducktux_left);
1133 texture_free(&ducktux_right);
1135 texture_free(&skidtux_left);
1136 texture_free(&skidtux_right);
1140 texture_free(&img_box_full);
1141 texture_free(&img_box_empty);
1143 texture_free(&img_water);
1144 for (i = 0; i < 3; i++)
1145 texture_free(&img_waves[i]);
1147 texture_free(&img_pole);
1148 texture_free(&img_poletop);
1150 for (i = 0; i < 2; i++)
1151 texture_free(&img_flag[i]);
1153 texture_free(&img_mints);
1154 texture_free(&img_coffee);
1156 for (i = 0; i < 4; i++)
1158 texture_free(&img_distro[i]);
1159 texture_free(&img_cloud[0][i]);
1160 texture_free(&img_cloud[1][i]);
1163 texture_free(&img_golden_herring);
1165 for (i = 0; i < NUM_SOUNDS; i++)
1166 free_chunk(sounds[i]);
1168 /* free the herring song */
1169 free_music( herring_song );
1173 /* Draw a tile on the screen: */
1175 void drawshape(float x, float y, unsigned int c, Uint8 alpha)
1179 Tile* ptile = TileManager::instance()->get(c);
1182 if(ptile->images.size() > 1)
1184 texture_draw(&ptile->images[( ((global_frame_counter*25) / ptile->anim_speed) % (ptile->images.size()))],x,y, alpha);
1186 else if (ptile->images.size() == 1)
1188 texture_draw(&ptile->images[0],x,y, alpha);
1192 //printf("Tile not dravable %u\n", c);
1199 /* What shape is at some position? */
1200 unsigned int shape(float x, float y)
1209 if (yy >= 0 && yy < 15 && xx >= 0 && xx <= current_level.width)
1211 c = current_level.ia_tiles[yy][xx];
1219 Tile* gettile(float x, float y)
1221 return TileManager::instance()->get(shape(x, y));
1224 bool issolid(float x, float y)
1226 Tile* tile = TileManager::instance()->get
1230 if(tile->solid == true)
1241 /* Is it a brick? */
1243 bool isbrick(float x, float y)
1245 Tile* tile = TileManager::instance()->get
1249 if(tile->brick == true)
1263 bool isice(float x, float y)
1265 Tile* tile = TileManager::instance()->get
1269 if(tile->ice == true)
1280 /* Is it a full box? */
1282 bool isfullbox(float x, float y)
1284 Tile* tile = TileManager::instance()->get
1288 if(tile->fullbox == true)
1299 bool isdistro(float x, float y)
1301 Tile* tile = TileManager::instance()->get(shape(x,y));
1302 return tile && tile->distro;
1305 /* Break a brick: */
1306 void trybreakbrick(float x, float y, bool small)
1308 Tile* tile = gettile(x, y);
1313 /* Get a distro from it: */
1314 add_bouncy_distro(((int)(x + 1) / 32) * 32,
1315 (int)(y / 32) * 32);
1317 if (!counting_distros)
1319 counting_distros = true;
1320 distro_counter = 50;
1323 if (distro_counter <= 0)
1324 level_change(¤t_level,x, y, TM_IA, tile->next_tile);
1326 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1327 score = score + SCORE_DISTRO;
1332 /* Get rid of it: */
1333 level_change(¤t_level,x, y, TM_IA, tile->next_tile);
1335 /* Replace it with broken bits: */
1336 add_broken_brick(((int)(x + 1) / 32) * 32,
1337 (int)(y / 32) * 32);
1339 /* Get some score: */
1340 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
1341 score = score + SCORE_BRICK;
1347 /* Bounce a brick: */
1349 void bumpbrick(float x, float y)
1351 add_bouncy_brick(((int)(x + 1) / 32) * 32,
1352 (int)(y / 32) * 32);
1354 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
1360 void tryemptybox(float x, float y, int col_side)
1362 Tile* tile = gettile(x,y);
1366 // according to the collision side, set the upgrade direction
1367 if(col_side == LEFT)
1374 case 1: //'A': /* Box with a distro! */
1375 add_bouncy_distro(((int)(x + 1) / 32) * 32, (int)(y / 32) * 32 - 32);
1376 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1377 score = score + SCORE_DISTRO;
1381 case 2: // 'B': /* Add an upgrade! */
1382 if (tux.size == SMALL) /* Tux is small, add mints! */
1383 add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_MINTS);
1384 else /* Tux is big, add coffee: */
1385 add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_COFFEE);
1386 play_sound(sounds[SND_UPGRADE], SOUND_CENTER_SPEAKER);
1389 case 3:// '!': /* Add a golden herring */
1390 add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_HERRING);
1396 /* Empty the box: */
1397 level_change(¤t_level,x, y, TM_IA, tile->next_tile);
1400 /* Try to grab a distro: */
1401 void trygrabdistro(float x, float y, int bounciness)
1403 Tile* tile = gettile(x, y);
1404 if (tile && tile->distro)
1406 level_change(¤t_level,x, y, TM_IA, tile->next_tile);
1407 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1409 if (bounciness == BOUNCE)
1411 add_bouncy_distro(((int)(x + 1) / 32) * 32,
1412 (int)(y / 32) * 32);
1415 score = score + SCORE_DISTRO;
1420 /* Try to bump a bad guy from below: */
1421 void trybumpbadguy(float x, float y)
1424 for (unsigned int i = 0; i < bad_guys.size(); i++)
1426 if (bad_guys[i].base.x >= x - 32 && bad_guys[i].base.x <= x + 32 &&
1427 bad_guys[i].base.y >= y - 16 && bad_guys[i].base.y <= y + 16)
1429 bad_guys[i].collision(&tux, CO_PLAYER, COLLISION_BUMP);
1435 for (unsigned int i = 0; i < upgrades.size(); i++)
1437 if (upgrades[i].base.height == 32 &&
1438 upgrades[i].base.x >= x - 32 && upgrades[i].base.x <= x + 32 &&
1439 upgrades[i].base.y >= y - 16 && upgrades[i].base.y <= y + 16)
1441 upgrades[i].base.xm = -upgrades[i].base.xm;
1442 upgrades[i].base.ym = -8;
1443 play_sound(sounds[SND_BUMP_UPGRADE], SOUND_CENTER_SPEAKER);
1449 void drawstatus(void)
1453 sprintf(str, "%d", score);
1454 text_draw(&white_text, "SCORE", 0, 0, 1);
1455 text_draw(&gold_text, str, 96, 0, 1);
1457 if(st_gl_mode != ST_GL_TEST)
1459 sprintf(str, "%d", hs_score);
1460 text_draw(&white_text, "HIGH", 0, 20, 1);
1461 text_draw(&gold_text, str, 96, 20, 1);
1465 text_draw(&white_text,"Press ESC To Return",0,20,1);
1468 if (timer_get_left(&time_left) > TIME_WARNING || (global_frame_counter % 10) < 5)
1470 sprintf(str, "%d", timer_get_left(&time_left) / 1000 );
1471 text_draw(&white_text, "TIME", 224, 0, 1);
1472 text_draw(&gold_text, str, 304, 0, 1);
1475 sprintf(str, "%d", distros);
1476 text_draw(&white_text, "DISTROS", screen->h, 0, 1);
1477 text_draw(&gold_text, str, 608, 0, 1);
1479 text_draw(&white_text, "LIVES", screen->h, 20, 1);
1483 sprintf(str, "%2.1f", fps_fps);
1484 text_draw(&white_text, "FPS", screen->h, 40, 1);
1485 text_draw(&gold_text, str, screen->h + 60, 40, 1);
1488 for(int i=0; i < tux.lives; ++i)
1490 texture_draw(&tux_life,565+(18*i),20);
1495 void drawendscreen(void)
1499 clearscreen(0, 0, 0);
1501 text_drawf(&blue_text, "GAMEOVER", 0, 200, A_HMIDDLE, A_TOP, 1);
1503 sprintf(str, "SCORE: %d", score);
1504 text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1);
1506 sprintf(str, "DISTROS: %d", distros);
1507 text_drawf(&gold_text, str, 0, 256, A_HMIDDLE, A_TOP, 1);
1512 wait_for_event(event,2000,5000,true);
1515 void drawresultscreen(void)
1519 clearscreen(0, 0, 0);
1521 text_drawf(&blue_text, "Result:", 0, 200, A_HMIDDLE, A_TOP, 1);
1523 sprintf(str, "SCORE: %d", score);
1524 text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1);
1526 sprintf(str, "DISTROS: %d", distros);
1527 text_drawf(&gold_text, str, 0, 256, A_HMIDDLE, A_TOP, 1);
1532 wait_for_event(event,2000,5000,true);
1535 void savegame(int slot)
1537 char savefile[1024];
1541 sprintf(savefile,"%s/slot%d.save",st_save_dir,slot);
1543 fi = fopen(savefile, "wb");
1547 fprintf(stderr, "Warning: I could not open the slot file ");
1551 fputs(level_subset, fi);
1553 fwrite(&level,sizeof(int),1,fi);
1554 fwrite(&score,sizeof(int),1,fi);
1555 fwrite(&distros,sizeof(int),1,fi);
1556 fwrite(&scroll_x,sizeof(float),1,fi);
1557 fwrite(&tux,sizeof(Player),1,fi);
1558 timer_fwrite(&tux.invincible_timer,fi);
1559 timer_fwrite(&tux.skidding_timer,fi);
1560 timer_fwrite(&tux.safe_timer,fi);
1561 timer_fwrite(&tux.frame_timer,fi);
1562 timer_fwrite(&time_left,fi);
1563 ui = st_get_ticks();
1564 fwrite(&ui,sizeof(int),1,fi);
1570 void loadgame(int slot)
1572 char savefile[1024];
1577 sprintf(savefile,"%s/slot%d.save",st_save_dir,slot);
1579 fi = fopen(savefile, "rb");
1583 fprintf(stderr, "Warning: I could not open the slot file ");
1588 fgets(str, 100, fi);
1589 strcpy(level_subset, str);
1590 level_subset[strlen(level_subset)-1] = '\0';
1591 fread(&level,sizeof(int),1,fi);
1594 level_free(¤t_level);
1595 if(level_load(¤t_level,level_subset,level) != 0)
1598 activate_bad_guys(¤t_level);
1599 activate_particle_systems();
1601 level_load_gfx(¤t_level);
1603 level_load_song(¤t_level);
1605 update_time = st_get_ticks();
1607 fread(&score,sizeof(int),1,fi);
1608 fread(&distros,sizeof(int),1,fi);
1609 fread(&scroll_x,sizeof(float),1,fi);
1610 fread(&tux, sizeof(Player), 1, fi);
1611 timer_fread(&tux.invincible_timer,fi);
1612 timer_fread(&tux.skidding_timer,fi);
1613 timer_fread(&tux.safe_timer,fi);
1614 timer_fread(&tux.frame_timer,fi);
1615 timer_fread(&time_left,fi);
1616 fread(&ui,sizeof(int),1,fi);
1622 std::string slotinfo(int slot)
1625 char slotfile[1024];
1629 sprintf(slotfile,"%s/slot%d.save",st_save_dir,slot);
1631 fi = fopen(slotfile, "rb");
1633 sprintf(tmp,"Slot %d - ",slot);
1641 fgets(str, 100, fi);
1642 str[strlen(str)-1] = '\0';
1644 strcat(tmp, " / Level:");
1645 fread(&slot_level,sizeof(int),1,fi);
1646 sprintf(str,"%d",slot_level);