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 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 (current_level.load(level_subset))
607 if(current_level.load(level_subset, level) != 0)
611 current_level.load_gfx();
613 activate_bad_guys(¤t_level);
614 activate_particle_systems();
615 current_level.load_song();
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 current_level.cleanup();
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);
1198 /* Break a brick: */
1199 void trybreakbrick(float x, float y, bool small)
1201 Tile* tile = gettile(x, y);
1206 /* Get a distro from it: */
1207 add_bouncy_distro(((int)(x + 1) / 32) * 32,
1208 (int)(y / 32) * 32);
1210 if (!counting_distros)
1212 counting_distros = true;
1213 distro_counter = 50;
1216 if (distro_counter <= 0)
1217 current_level.change(x, y, TM_IA, tile->next_tile);
1219 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1220 score = score + SCORE_DISTRO;
1225 /* Get rid of it: */
1226 current_level.change(x, y, TM_IA, tile->next_tile);
1228 /* Replace it with broken bits: */
1229 add_broken_brick(((int)(x + 1) / 32) * 32,
1230 (int)(y / 32) * 32);
1232 /* Get some score: */
1233 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
1234 score = score + SCORE_BRICK;
1240 /* Bounce a brick: */
1242 void bumpbrick(float x, float y)
1244 add_bouncy_brick(((int)(x + 1) / 32) * 32,
1245 (int)(y / 32) * 32);
1247 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
1251 void tryemptybox(float x, float y, int col_side)
1253 Tile* tile = gettile(x,y);
1257 // according to the collision side, set the upgrade direction
1258 if(col_side == LEFT)
1265 case 1: //'A': /* Box with a distro! */
1266 add_bouncy_distro(((int)(x + 1) / 32) * 32, (int)(y / 32) * 32 - 32);
1267 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1268 score = score + SCORE_DISTRO;
1272 case 2: // 'B': /* Add an upgrade! */
1273 if (tux.size == SMALL) /* Tux is small, add mints! */
1274 add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_MINTS);
1275 else /* Tux is big, add coffee: */
1276 add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_COFFEE);
1277 play_sound(sounds[SND_UPGRADE], SOUND_CENTER_SPEAKER);
1280 case 3:// '!': /* Add a golden herring */
1281 add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_HERRING);
1287 /* Empty the box: */
1288 current_level.change(x, y, TM_IA, tile->next_tile);
1291 /* Try to grab a distro: */
1292 void trygrabdistro(float x, float y, int bounciness)
1294 Tile* tile = gettile(x, y);
1295 if (tile && tile->distro)
1297 current_level.change(x, y, TM_IA, tile->next_tile);
1298 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1300 if (bounciness == BOUNCE)
1302 add_bouncy_distro(((int)(x + 1) / 32) * 32,
1303 (int)(y / 32) * 32);
1306 score = score + SCORE_DISTRO;
1311 /* Try to bump a bad guy from below: */
1312 void trybumpbadguy(float x, float y)
1315 for (unsigned int i = 0; i < bad_guys.size(); i++)
1317 if (bad_guys[i].base.x >= x - 32 && bad_guys[i].base.x <= x + 32 &&
1318 bad_guys[i].base.y >= y - 16 && bad_guys[i].base.y <= y + 16)
1320 bad_guys[i].collision(&tux, CO_PLAYER, COLLISION_BUMP);
1326 for (unsigned int i = 0; i < upgrades.size(); i++)
1328 if (upgrades[i].base.height == 32 &&
1329 upgrades[i].base.x >= x - 32 && upgrades[i].base.x <= x + 32 &&
1330 upgrades[i].base.y >= y - 16 && upgrades[i].base.y <= y + 16)
1332 upgrades[i].base.xm = -upgrades[i].base.xm;
1333 upgrades[i].base.ym = -8;
1334 play_sound(sounds[SND_BUMP_UPGRADE], SOUND_CENTER_SPEAKER);
1340 void drawstatus(void)
1344 sprintf(str, "%d", score);
1345 text_draw(&white_text, "SCORE", 0, 0, 1);
1346 text_draw(&gold_text, str, 96, 0, 1);
1348 if(st_gl_mode != ST_GL_TEST)
1350 sprintf(str, "%d", hs_score);
1351 text_draw(&white_text, "HIGH", 0, 20, 1);
1352 text_draw(&gold_text, str, 96, 20, 1);
1356 text_draw(&white_text,"Press ESC To Return",0,20,1);
1359 if (timer_get_left(&time_left) > TIME_WARNING || (global_frame_counter % 10) < 5)
1361 sprintf(str, "%d", timer_get_left(&time_left) / 1000 );
1362 text_draw(&white_text, "TIME", 224, 0, 1);
1363 text_draw(&gold_text, str, 304, 0, 1);
1366 sprintf(str, "%d", distros);
1367 text_draw(&white_text, "DISTROS", screen->h, 0, 1);
1368 text_draw(&gold_text, str, 608, 0, 1);
1370 text_draw(&white_text, "LIVES", screen->h, 20, 1);
1374 sprintf(str, "%2.1f", fps_fps);
1375 text_draw(&white_text, "FPS", screen->h, 40, 1);
1376 text_draw(&gold_text, str, screen->h + 60, 40, 1);
1379 for(int i=0; i < tux.lives; ++i)
1381 texture_draw(&tux_life,565+(18*i),20);
1386 void drawendscreen(void)
1390 clearscreen(0, 0, 0);
1392 text_drawf(&blue_text, "GAMEOVER", 0, 200, A_HMIDDLE, A_TOP, 1);
1394 sprintf(str, "SCORE: %d", score);
1395 text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1);
1397 sprintf(str, "DISTROS: %d", distros);
1398 text_drawf(&gold_text, str, 0, 256, A_HMIDDLE, A_TOP, 1);
1403 wait_for_event(event,2000,5000,true);
1406 void drawresultscreen(void)
1410 clearscreen(0, 0, 0);
1412 text_drawf(&blue_text, "Result:", 0, 200, A_HMIDDLE, A_TOP, 1);
1414 sprintf(str, "SCORE: %d", score);
1415 text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1);
1417 sprintf(str, "DISTROS: %d", distros);
1418 text_drawf(&gold_text, str, 0, 256, A_HMIDDLE, A_TOP, 1);
1423 wait_for_event(event,2000,5000,true);
1426 void savegame(int slot)
1428 char savefile[1024];
1432 sprintf(savefile,"%s/slot%d.save",st_save_dir,slot);
1434 fi = fopen(savefile, "wb");
1438 fprintf(stderr, "Warning: I could not open the slot file ");
1442 fputs(level_subset, fi);
1444 fwrite(&level,sizeof(int),1,fi);
1445 fwrite(&score,sizeof(int),1,fi);
1446 fwrite(&distros,sizeof(int),1,fi);
1447 fwrite(&scroll_x,sizeof(float),1,fi);
1448 fwrite(&tux,sizeof(Player),1,fi);
1449 timer_fwrite(&tux.invincible_timer,fi);
1450 timer_fwrite(&tux.skidding_timer,fi);
1451 timer_fwrite(&tux.safe_timer,fi);
1452 timer_fwrite(&tux.frame_timer,fi);
1453 timer_fwrite(&time_left,fi);
1454 ui = st_get_ticks();
1455 fwrite(&ui,sizeof(int),1,fi);
1461 void loadgame(int slot)
1463 char savefile[1024];
1468 sprintf(savefile,"%s/slot%d.save",st_save_dir,slot);
1470 fi = fopen(savefile, "rb");
1474 fprintf(stderr, "Warning: I could not open the slot file ");
1479 fgets(str, 100, fi);
1480 strcpy(level_subset, str);
1481 level_subset[strlen(level_subset)-1] = '\0';
1482 fread(&level,sizeof(int),1,fi);
1485 current_level.cleanup();
1486 if(current_level.load(level_subset,level) != 0)
1489 activate_bad_guys(¤t_level);
1490 activate_particle_systems();
1492 current_level.load_gfx();
1494 current_level.load_song();
1496 update_time = st_get_ticks();
1498 fread(&score,sizeof(int),1,fi);
1499 fread(&distros,sizeof(int),1,fi);
1500 fread(&scroll_x,sizeof(float),1,fi);
1501 fread(&tux, sizeof(Player), 1, fi);
1502 timer_fread(&tux.invincible_timer,fi);
1503 timer_fread(&tux.skidding_timer,fi);
1504 timer_fread(&tux.safe_timer,fi);
1505 timer_fread(&tux.frame_timer,fi);
1506 timer_fread(&time_left,fi);
1507 fread(&ui,sizeof(int),1,fi);
1513 std::string slotinfo(int slot)
1516 char slotfile[1024];
1520 sprintf(slotfile,"%s/slot%d.save",st_save_dir,slot);
1522 fi = fopen(slotfile, "rb");
1524 sprintf(tmp,"Slot %d - ",slot);
1532 fgets(str, 100, fi);
1533 str[strlen(str)-1] = '\0';
1535 strcat(tmp, " / Level:");
1536 fread(&slot_level,sizeof(int),1,fi);
1537 sprintf(str,"%d",slot_level);