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(void)
104 for (std::vector<BadGuyData>::iterator i = current_level.badguy_data.begin();
105 i != current_level.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_dying || next_level) */
304 if (tux.dying || 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)
375 activate_particle_systems();
377 level_load_gfx(¤t_level);
379 level_load_song(¤t_level);
380 if(st_gl_mode != ST_GL_TEST)
384 play_current_music();
389 /* Handle bouncy distros: */
390 for (i = 0; i < bouncy_distros.size(); i++)
392 bouncy_distro_action(&bouncy_distros[i]);
396 /* Handle broken bricks: */
397 for (i = 0; i < broken_bricks.size(); i++)
399 broken_brick_action(&broken_bricks[i]);
403 /* Handle distro counting: */
405 if (counting_distros)
409 if (distro_counter <= 0)
410 counting_distros = -1;
414 /* Handle bouncy bricks: */
416 for (i = 0; i < bouncy_bricks.size(); i++)
418 bouncy_brick_action(&bouncy_bricks[i]);
422 /* Handle floating scores: */
424 for (i = 0; i < floating_scores.size(); i++)
426 floating_score_action(&floating_scores[i]);
430 /* Handle bullets: */
432 for (i = 0; i < bullets.size(); ++i)
434 bullet_action(&bullets[i]);
437 /* Handle upgrades: */
439 for (i = 0; i < upgrades.size(); i++)
441 upgrade_action(&upgrades[i]);
445 /* Handle bad guys: */
447 for (i = 0; i < bad_guys.size(); i++)
449 bad_guys[i].action();
452 /* update particle systems */
453 std::vector<ParticleSystem*>::iterator p;
454 for(p = particle_systems.begin(); p != particle_systems.end(); ++p)
456 (*p)->simulate(frame_ratio);
459 /* Handle all possible collisions. */
465 /* --- GAME DRAW! --- */
472 if (tux.dying && (global_frame_counter % 4) == 0)
473 clearscreen(255, 255, 255);
474 else if(timer_check(&super_bkgd_timer))
475 texture_draw(&img_super_bkgd, 0, 0);
478 /* Draw the real background */
479 if(current_level.bkgd_image[0] != '\0')
481 int s = (int)scroll_x / 30;
482 texture_draw_part(&img_bkgd,s,0,0,0,img_bkgd.w - s, img_bkgd.h);
483 texture_draw_part(&img_bkgd,0,0,screen->w - s ,0,s,img_bkgd.h);
487 clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue);
491 /* Draw particle systems (background) */
492 std::vector<ParticleSystem*>::iterator p;
493 for(p = particle_systems.begin(); p != particle_systems.end(); ++p)
495 (*p)->draw(scroll_x, 0, 0);
498 /* Draw background: */
500 for (y = 0; y < 15; ++y)
502 for (x = 0; x < 21; ++x)
504 drawshape(32*x - fmodf(scroll_x, 32), y * 32,
505 current_level.bg_tiles[(int)y][(int)x + (int)(scroll_x / 32)]);
509 /* Draw interactive tiles: */
510 for (y = 0; y < 15; ++y)
512 for (x = 0; x < 21; ++x)
514 drawshape(32*x - fmodf(scroll_x, 32), y * 32,
515 current_level.ia_tiles[(int)y][(int)x + (int)(scroll_x / 32)]);
519 /* (Bouncy bricks): */
520 for (unsigned int i = 0; i < bouncy_bricks.size(); ++i)
521 bouncy_brick_draw(&bouncy_bricks[i]);
523 for (unsigned int i = 0; i < bad_guys.size(); ++i)
528 for (unsigned int i = 0; i < bullets.size(); ++i)
529 bullet_draw(&bullets[i]);
531 for (unsigned int i = 0; i < floating_scores.size(); ++i)
532 floating_score_draw(&floating_scores[i]);
534 for (unsigned int i = 0; i < upgrades.size(); ++i)
535 upgrade_draw(&upgrades[i]);
537 for (unsigned int i = 0; i < bouncy_distros.size(); ++i)
538 bouncy_distro_draw(&bouncy_distros[i]);
540 for (unsigned int i = 0; i < broken_bricks.size(); ++i)
541 broken_brick_draw(&broken_bricks[i]);
543 /* Draw foreground: */
544 for (y = 0; y < 15; ++y)
546 for (x = 0; x < 21; ++x)
548 drawshape(32*x - fmodf(scroll_x, 32), y * 32,
549 current_level.fg_tiles[(int)y][(int)x + (int)(scroll_x / 32)]);
553 /* Draw particle systems (foreground) */
554 for(p = particle_systems.begin(); p != particle_systems.end(); ++p)
556 (*p)->draw(scroll_x, 0, 1);
563 int x = screen->h / 20;
564 for(int i = 0; i < x; ++i)
566 fillrect(i % 2 ? (pause_menu_frame * i)%screen->w : -((pause_menu_frame * i)%screen->w) ,(i*20+pause_menu_frame)%screen->h,screen->w,10,20,20,20, rand() % 20 + 1);
568 fillrect(0,0,screen->w,screen->h,rand() % 50, rand() % 50, rand() % 50, 128);
569 text_drawf(&blue_text, "PAUSE - Press 'P' To Play", 0, 230, A_HMIDDLE, A_TOP, 1);
574 menu_process_current();
575 mouse_cursor->draw();
578 /* (Update it all!) */
582 /* --- GAME LOOP! --- */
584 int gameloop(const char * subset, int levelnb, int mode)
586 int fps_cnt, jump, done;
587 timer_type fps_timer, frame_timer;
588 timer_init(&fps_timer, true);
589 timer_init(&frame_timer, true);
600 strcpy(level_subset,subset);
602 if (st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
604 if (level_load(¤t_level, level_subset))
609 if(level_load(¤t_level, level_subset, level) != 0)
613 level_load_gfx(¤t_level);
615 activate_particle_systems();
616 level_load_song(¤t_level);
620 if(st_gl_mode != ST_GL_TEST)
625 if(st_gl_mode == ST_GL_PLAY || st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
628 timer_init(&time_left,true);
631 if(st_gl_mode == ST_GL_LOAD_GAME)
634 /* --- MAIN GAME LOOP!!! --- */
639 global_frame_counter = 0;
641 timer_init(&fps_timer,true);
642 timer_init(&frame_timer,true);
647 clearscreen(0, 0, 0);
651 play_current_music();
654 while (SDL_PollEvent(&event))
662 /* Calculate the movement-factor */
663 frame_ratio = ((double)(update_time-last_update_time))/((double)FRAME_RATE);
664 if(frame_ratio > 1.5) /* Quick hack to correct the unprecise CPU clocks a little bit. */
665 frame_ratio = 1.5 + (frame_ratio - 1.5) * 0.85;
667 if(!timer_check(&frame_timer))
669 timer_start(&frame_timer,25);
670 ++global_frame_counter;
675 tux.input.old_fire = tux.input.fire;
681 if(current_menu == game_menu)
683 switch (game_menu->check())
686 st_pause_ticks_stop();
689 update_load_save_game_menu(save_game_menu, false);
692 update_load_save_game_menu(load_game_menu, true);
695 st_pause_ticks_stop();
700 else if(current_menu == options_menu)
702 process_options_menu();
704 else if(current_menu == save_game_menu )
706 process_save_load_game_menu(true);
708 else if(current_menu == load_game_menu )
710 process_save_load_game_menu(false);
715 /* Handle actions: */
717 if(!game_pause && !show_menu)
719 /*float z = frame_ratio;
723 if (game_action() == 0)
725 /* == 0: no more lives */
726 /* == -1: continues */
738 if(debug_mode && debug_fps)
741 /*Draw the current scene to the screen */
742 /*If the machine running the game is too slow
743 skip the drawing of the frame (so the calculations are more precise and
744 the FPS aren't affected).*/
745 /*if( ! fps_fps < 50.0 )
748 jump = true;*/ /*FIXME: Implement this tweak right.*/
751 /* Time stops in pause mode */
752 if(game_pause || show_menu )
757 /* Set the time of the last update and the time of the current update */
758 last_update_time = update_time;
759 update_time = st_get_ticks();
761 /* Pause till next frame, if the machine running the game is too fast: */
762 /* FIXME: Works great for in OpenGl mode, where the CPU doesn't have to do that much. But
763 the results in SDL mode aren't perfect (thought the 100 FPS are reached), even on an AMD2500+. */
764 if(last_update_time >= update_time - 12 && !jump) {
766 update_time = st_get_ticks();
768 /*if((update_time - last_update_time) < 10)
769 SDL_Delay((11 - (update_time - last_update_time))/2);*/
775 if (timer_check(&time_left))
777 /* are we low on time ? */
778 if ((timer_get_left(&time_left) < TIME_WARNING)
779 && (get_current_music() != HURRYUP_MUSIC)) /* play the fast music */
781 set_current_music(HURRYUP_MUSIC);
782 play_current_music();
790 /* Calculate frames per second */
794 fps_fps = (1000.0 / (float)timer_get_gone(&fps_timer)) * (float)fps_cnt;
796 if(!timer_check(&fps_timer))
798 timer_start(&fps_timer,1000);
804 while (!done && !quit);
809 level_free(¤t_level);
814 game_started = false;
820 /* Load graphics/sounds shared between all levels: */
822 void loadshared(void)
827 texture_load(&tux_right[0], datadir + "/images/shared/tux-right-0.png", USE_ALPHA);
828 texture_load(&tux_right[1], datadir + "/images/shared/tux-right-1.png", USE_ALPHA);
829 texture_load(&tux_right[2], datadir + "/images/shared/tux-right-2.png", USE_ALPHA);
831 texture_load(&tux_left[0], datadir + "/images/shared/tux-left-0.png", USE_ALPHA);
832 texture_load(&tux_left[1], datadir + "/images/shared/tux-left-1.png", USE_ALPHA);
833 texture_load(&tux_left[2], datadir + "/images/shared/tux-left-2.png", USE_ALPHA);
835 texture_load(&firetux_right[0], datadir + "/images/shared/firetux-right-0.png", USE_ALPHA);
836 texture_load(&firetux_right[1], datadir + "/images/shared/firetux-right-1.png", USE_ALPHA);
837 texture_load(&firetux_right[2], datadir + "/images/shared/firetux-right-2.png", USE_ALPHA);
839 texture_load(&firetux_left[0], datadir + "/images/shared/firetux-left-0.png", USE_ALPHA);
840 texture_load(&firetux_left[1], datadir + "/images/shared/firetux-left-1.png", USE_ALPHA);
841 texture_load(&firetux_left[2], datadir + "/images/shared/firetux-left-2.png", USE_ALPHA);
844 texture_load(&cape_right[0], datadir + "/images/shared/cape-right-0.png",
847 texture_load(&cape_right[1], datadir + "/images/shared/cape-right-1.png",
850 texture_load(&cape_left[0], datadir + "/images/shared/cape-left-0.png",
853 texture_load(&cape_left[1], datadir + "/images/shared/cape-left-1.png",
856 texture_load(&bigtux_right[0], datadir + "/images/shared/bigtux-right-0.png",
859 texture_load(&bigtux_right[1], datadir + "/images/shared/bigtux-right-1.png",
862 texture_load(&bigtux_right[2], datadir + "/images/shared/bigtux-right-2.png",
865 texture_load(&bigtux_right_jump, datadir + "/images/shared/bigtux-right-jump.png", USE_ALPHA);
867 texture_load(&bigtux_left[0], datadir + "/images/shared/bigtux-left-0.png",
870 texture_load(&bigtux_left[1], datadir + "/images/shared/bigtux-left-1.png",
873 texture_load(&bigtux_left[2], datadir + "/images/shared/bigtux-left-2.png",
876 texture_load(&bigtux_left_jump, datadir + "/images/shared/bigtux-left-jump.png", USE_ALPHA);
878 texture_load(&bigcape_right[0], datadir + "/images/shared/bigcape-right-0.png",
881 texture_load(&bigcape_right[1], datadir + "/images/shared/bigcape-right-1.png",
884 texture_load(&bigcape_left[0], datadir + "/images/shared/bigcape-left-0.png",
887 texture_load(&bigcape_left[1], datadir + "/images/shared/bigcape-left-1.png",
890 texture_load(&bigfiretux_right[0], datadir + "/images/shared/bigfiretux-right-0.png",
893 texture_load(&bigfiretux_right[1], datadir + "/images/shared/bigfiretux-right-1.png",
896 texture_load(&bigfiretux_right[2], datadir + "/images/shared/bigfiretux-right-2.png",
899 texture_load(&bigfiretux_right_jump, datadir + "/images/shared/bigfiretux-right-jump.png", USE_ALPHA);
901 texture_load(&bigfiretux_left[0], datadir + "/images/shared/bigfiretux-left-0.png",
904 texture_load(&bigfiretux_left[1], datadir + "/images/shared/bigfiretux-left-1.png",
907 texture_load(&bigfiretux_left[2], datadir + "/images/shared/bigfiretux-left-2.png",
910 texture_load(&bigfiretux_left_jump, datadir + "/images/shared/bigfiretux-left-jump.png", USE_ALPHA);
912 texture_load(&bigcape_right[0], datadir + "/images/shared/bigcape-right-0.png",
915 texture_load(&bigcape_right[1], datadir + "/images/shared/bigcape-right-1.png",
918 texture_load(&bigcape_left[0], datadir + "/images/shared/bigcape-left-0.png",
921 texture_load(&bigcape_left[1], datadir + "/images/shared/bigcape-left-1.png",
925 texture_load(&ducktux_right, datadir +
926 "/images/shared/ducktux-right.png",
929 texture_load(&ducktux_left, datadir +
930 "/images/shared/ducktux-left.png",
933 texture_load(&skidtux_right, datadir +
934 "/images/shared/skidtux-right.png",
937 texture_load(&skidtux_left, datadir +
938 "/images/shared/skidtux-left.png",
941 texture_load(&duckfiretux_right, datadir +
942 "/images/shared/duckfiretux-right.png",
945 texture_load(&duckfiretux_left, datadir +
946 "/images/shared/duckfiretux-left.png",
949 texture_load(&skidfiretux_right, datadir +
950 "/images/shared/skidfiretux-right.png",
953 texture_load(&skidfiretux_left, datadir +
954 "/images/shared/skidfiretux-left.png",
960 texture_load(&img_box_full, datadir + "/images/shared/box-full.png",
962 texture_load(&img_box_empty, datadir + "/images/shared/box-empty.png",
969 texture_load(&img_water, datadir + "/images/shared/water.png", IGNORE_ALPHA);
971 texture_load(&img_waves[0], datadir + "/images/shared/waves-0.png",
974 texture_load(&img_waves[1], datadir + "/images/shared/waves-1.png",
977 texture_load(&img_waves[2], datadir + "/images/shared/waves-2.png",
983 texture_load(&img_pole, datadir + "/images/shared/pole.png", USE_ALPHA);
984 texture_load(&img_poletop, datadir + "/images/shared/poletop.png",
990 texture_load(&img_flag[0], datadir + "/images/shared/flag-0.png",
992 texture_load(&img_flag[1], datadir + "/images/shared/flag-1.png",
998 texture_load(&img_cloud[0][0], datadir + "/images/shared/cloud-00.png",
1001 texture_load(&img_cloud[0][1], datadir + "/images/shared/cloud-01.png",
1004 texture_load(&img_cloud[0][2], datadir + "/images/shared/cloud-02.png",
1007 texture_load(&img_cloud[0][3], datadir + "/images/shared/cloud-03.png",
1011 texture_load(&img_cloud[1][0], datadir + "/images/shared/cloud-10.png",
1014 texture_load(&img_cloud[1][1], datadir + "/images/shared/cloud-11.png",
1017 texture_load(&img_cloud[1][2], datadir + "/images/shared/cloud-12.png",
1020 texture_load(&img_cloud[1][3], datadir + "/images/shared/cloud-13.png",
1029 texture_load(&img_mints, datadir + "/images/shared/mints.png", USE_ALPHA);
1030 texture_load(&img_coffee, datadir + "/images/shared/coffee.png", USE_ALPHA);
1035 texture_load(&img_bullet, datadir + "/images/shared/bullet.png", USE_ALPHA);
1037 texture_load(&img_red_glow, datadir + "/images/shared/red-glow.png",
1044 texture_load(&img_distro[0], datadir + "/images/shared/distro-0.png",
1047 texture_load(&img_distro[1], datadir + "/images/shared/distro-1.png",
1050 texture_load(&img_distro[2], datadir + "/images/shared/distro-2.png",
1053 texture_load(&img_distro[3], datadir + "/images/shared/distro-3.png",
1059 texture_load(&tux_life, datadir + "/images/shared/tux-life.png",
1064 texture_load(&img_golden_herring, datadir + "/images/shared/golden-herring.png",
1068 /* Super background: */
1070 texture_load(&img_super_bkgd, datadir + "/images/shared/super-bkgd.png",
1074 /* Sound effects: */
1076 /* if (use_sound) // this will introduce SERIOUS bugs here ! because "load_sound"
1077 // initialize sounds[i] with the correct pointer's value:
1078 // NULL or something else. And it will be dangerous to
1079 // play with not-initialized pointers.
1080 // This is also true with if (use_music)
1081 Send a mail to me: neoneurone@users.sf.net, if you have another opinion. :)
1083 for (i = 0; i < NUM_SOUNDS; i++)
1084 sounds[i] = load_sound(datadir + soundfilenames[i]);
1087 herring_song = load_song(datadir + "/music/SALCON.MOD");
1091 /* Free shared data: */
1093 void unloadshared(void)
1097 for (i = 0; i < 3; i++)
1099 texture_free(&tux_right[i]);
1100 texture_free(&tux_left[i]);
1101 texture_free(&bigtux_right[i]);
1102 texture_free(&bigtux_left[i]);
1105 texture_free(&bigtux_right_jump);
1106 texture_free(&bigtux_left_jump);
1108 for (i = 0; i < 2; i++)
1110 texture_free(&cape_right[i]);
1111 texture_free(&cape_left[i]);
1112 texture_free(&bigcape_right[i]);
1113 texture_free(&bigcape_left[i]);
1116 texture_free(&ducktux_left);
1117 texture_free(&ducktux_right);
1119 texture_free(&skidtux_left);
1120 texture_free(&skidtux_right);
1124 texture_free(&img_box_full);
1125 texture_free(&img_box_empty);
1127 texture_free(&img_water);
1128 for (i = 0; i < 3; i++)
1129 texture_free(&img_waves[i]);
1131 texture_free(&img_pole);
1132 texture_free(&img_poletop);
1134 for (i = 0; i < 2; i++)
1135 texture_free(&img_flag[i]);
1137 texture_free(&img_mints);
1138 texture_free(&img_coffee);
1140 for (i = 0; i < 4; i++)
1142 texture_free(&img_distro[i]);
1143 texture_free(&img_cloud[0][i]);
1144 texture_free(&img_cloud[1][i]);
1147 texture_free(&img_golden_herring);
1149 for (i = 0; i < NUM_SOUNDS; i++)
1150 free_chunk(sounds[i]);
1152 /* free the herring song */
1153 free_music( herring_song );
1157 /* Draw a tile on the screen: */
1159 void drawshape(float x, float y, unsigned int c)
1163 Tile* ptile = TileManager::instance()->get(c);
1166 if(ptile->images.size() > 1)
1168 texture_draw(&ptile->images[( ((global_frame_counter*25) / ptile->anim_speed) % (ptile->images.size()))],x,y);
1170 else if (ptile->images.size() == 1)
1172 texture_draw(&ptile->images[0],x,y);
1176 //printf("Tile not dravable %u\n", c);
1182 if (c == 'X' || c == 'x')
1183 texture_draw(&img_brick[0], x, y);
1184 else if (c == 'Y' || c == 'y')
1185 texture_draw(&img_brick[1], x, y);
1186 else if (c == 'A' || c =='B' || c == '!')
1187 texture_draw(&img_box_full, x, y);
1189 texture_draw(&img_box_empty, x, y);
1190 else if (c >= 'C' && c <= 'F')
1191 texture_draw(&img_cloud[0][c - 'C'], x, y);
1192 else if (c >= 'c' && c <= 'f')
1193 texture_draw(&img_cloud[1][c - 'c'], x, y);
1194 else if (c >= 'G' && c <= 'J')
1195 texture_draw(&img_bkgd_tile[0][c - 'G'], x, y);
1196 else if (c >= 'g' && c <= 'j')
1197 texture_draw(&img_bkgd_tile[1][c - 'g'], x, y);
1199 texture_draw(&img_solid[0], x, y);
1201 texture_draw(&img_solid[1], x, y);
1203 texture_draw(&img_solid[2], x, y);
1205 texture_draw(&img_solid[3], x, y);
1208 z = (global_frame_counter / 2) % 6;
1211 texture_draw(&img_distro[z], x, y);
1213 texture_draw(&img_distro[2], x, y);
1215 texture_draw(&img_distro[1], x, y);
1219 z = (global_frame_counter / 3) % 3;
1221 texture_draw(&img_waves[z], x, y);
1224 texture_draw(&img_poletop, x, y);
1227 texture_draw(&img_pole, x, y);
1232 z = (global_frame_counter / 3) % 2;
1234 texture_draw(&img_flag[z], x + 16, y);
1237 texture_draw(&img_water, x, y);*/
1242 /* What shape is at some position? */
1243 unsigned int shape(float x, float y)
1252 if (yy >= 0 && yy < 15 && xx >= 0 && xx <= current_level.width)
1254 c = current_level.ia_tiles[yy][xx];
1262 Tile* gettile(float x, float y)
1264 return TileManager::instance()->get(shape(x, y));
1267 bool issolid(float x, float y)
1269 Tile* tile = TileManager::instance()->get
1273 if(tile->solid == true)
1284 /* Is it a brick? */
1286 bool isbrick(float x, float y)
1288 Tile* tile = TileManager::instance()->get
1292 if(tile->brick == true)
1306 bool isice(float x, float y)
1308 Tile* tile = TileManager::instance()->get
1312 if(tile->ice == true)
1323 /* Is it a full box? */
1325 bool isfullbox(float x, float y)
1327 Tile* tile = TileManager::instance()->get
1331 if(tile->fullbox == true)
1342 bool isdistro(float x, float y)
1344 Tile* tile = TileManager::instance()->get(shape(x,y));
1345 return tile && tile->distro;
1348 /* Break a brick: */
1349 void trybreakbrick(float x, float y, bool small)
1351 Tile* tile = gettile(x, y);
1356 /* Get a distro from it: */
1357 add_bouncy_distro(((int)(x + 1) / 32) * 32,
1358 (int)(y / 32) * 32);
1360 if (!counting_distros)
1362 counting_distros = true;
1363 distro_counter = 50;
1366 if (distro_counter <= 0)
1367 level_change(¤t_level,x, y, TM_IA, tile->next_tile);
1369 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1370 score = score + SCORE_DISTRO;
1375 /* Get rid of it: */
1376 level_change(¤t_level,x, y, TM_IA, tile->next_tile);
1378 /* Replace it with broken bits: */
1379 add_broken_brick(((int)(x + 1) / 32) * 32,
1380 (int)(y / 32) * 32);
1382 /* Get some score: */
1383 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
1384 score = score + SCORE_BRICK;
1390 /* Bounce a brick: */
1392 void bumpbrick(float x, float y)
1394 add_bouncy_brick(((int)(x + 1) / 32) * 32,
1395 (int)(y / 32) * 32);
1397 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
1403 void tryemptybox(float x, float y, int col_side)
1405 Tile* tile = gettile(x,y);
1409 // according to the collision side, set the upgrade direction
1410 if(col_side == LEFT)
1417 case 1: //'A': /* Box with a distro! */
1418 add_bouncy_distro(((int)(x + 1) / 32) * 32, (int)(y / 32) * 32 - 32);
1419 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1420 score = score + SCORE_DISTRO;
1424 case 2: // 'B': /* Add an upgrade! */
1425 if (tux.size == SMALL) /* Tux is small, add mints! */
1426 add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_MINTS);
1427 else /* Tux is big, add coffee: */
1428 add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_COFFEE);
1429 play_sound(sounds[SND_UPGRADE], SOUND_CENTER_SPEAKER);
1432 case 3:// '!': /* Add a golden herring */
1433 add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_HERRING);
1439 /* Empty the box: */
1440 level_change(¤t_level,x, y, TM_IA, tile->next_tile);
1443 /* Try to grab a distro: */
1444 void trygrabdistro(float x, float y, int bounciness)
1446 Tile* tile = gettile(x, y);
1447 if (tile && tile->distro)
1449 level_change(¤t_level,x, y, TM_IA, tile->next_tile);
1450 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1452 if (bounciness == BOUNCE)
1454 add_bouncy_distro(((int)(x + 1) / 32) * 32,
1455 (int)(y / 32) * 32);
1458 score = score + SCORE_DISTRO;
1463 /* Try to bump a bad guy from below: */
1464 void trybumpbadguy(float x, float y)
1467 for (unsigned int i = 0; i < bad_guys.size(); i++)
1469 if (bad_guys[i].base.x >= x - 32 && bad_guys[i].base.x <= x + 32 &&
1470 bad_guys[i].base.y >= y - 16 && bad_guys[i].base.y <= y + 16)
1472 bad_guys[i].collision(&tux, CO_PLAYER, COLLISION_BUMP);
1478 for (unsigned int i = 0; i < upgrades.size(); i++)
1480 if (upgrades[i].base.height == 32 &&
1481 upgrades[i].base.x >= x - 32 && upgrades[i].base.x <= x + 32 &&
1482 upgrades[i].base.y >= y - 16 && upgrades[i].base.y <= y + 16)
1484 upgrades[i].base.xm = -upgrades[i].base.xm;
1485 upgrades[i].base.ym = -8;
1486 play_sound(sounds[SND_BUMP_UPGRADE], SOUND_CENTER_SPEAKER);
1492 void drawstatus(void)
1496 sprintf(str, "%d", score);
1497 text_draw(&white_text, "SCORE", 0, 0, 1);
1498 text_draw(&gold_text, str, 96, 0, 1);
1500 if(st_gl_mode != ST_GL_TEST)
1502 sprintf(str, "%d", hs_score);
1503 text_draw(&white_text, "HIGH", 0, 20, 1);
1504 text_draw(&gold_text, str, 96, 20, 1);
1508 text_draw(&white_text,"Press ESC To Return",0,20,1);
1511 if (timer_get_left(&time_left) > TIME_WARNING || (global_frame_counter % 10) < 5)
1513 sprintf(str, "%d", timer_get_left(&time_left) / 1000 );
1514 text_draw(&white_text, "TIME", 224, 0, 1);
1515 text_draw(&gold_text, str, 304, 0, 1);
1518 sprintf(str, "%d", distros);
1519 text_draw(&white_text, "DISTROS", screen->h, 0, 1);
1520 text_draw(&gold_text, str, 608, 0, 1);
1522 text_draw(&white_text, "LIVES", screen->h, 20, 1);
1526 sprintf(str, "%2.1f", fps_fps);
1527 text_draw(&white_text, "FPS", screen->h, 40, 1);
1528 text_draw(&gold_text, str, screen->h + 60, 40, 1);
1531 for(int i=0; i < tux.lives; ++i)
1533 texture_draw(&tux_life,565+(18*i),20);
1538 void drawendscreen(void)
1542 clearscreen(0, 0, 0);
1544 text_drawf(&blue_text, "GAMEOVER", 0, 200, A_HMIDDLE, A_TOP, 1);
1546 sprintf(str, "SCORE: %d", score);
1547 text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1);
1549 sprintf(str, "DISTROS: %d", distros);
1550 text_drawf(&gold_text, str, 0, 256, A_HMIDDLE, A_TOP, 1);
1555 wait_for_event(event,2000,5000,true);
1558 void drawresultscreen(void)
1562 clearscreen(0, 0, 0);
1564 text_drawf(&blue_text, "Result:", 0, 200, A_HMIDDLE, A_TOP, 1);
1566 sprintf(str, "SCORE: %d", score);
1567 text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1);
1569 sprintf(str, "DISTROS: %d", distros);
1570 text_drawf(&gold_text, str, 0, 256, A_HMIDDLE, A_TOP, 1);
1575 wait_for_event(event,2000,5000,true);
1578 void savegame(int slot)
1580 char savefile[1024];
1584 sprintf(savefile,"%s/slot%d.save",st_save_dir,slot);
1586 fi = fopen(savefile, "wb");
1590 fprintf(stderr, "Warning: I could not open the slot file ");
1594 fputs(level_subset, fi);
1596 fwrite(&level,sizeof(int),1,fi);
1597 fwrite(&score,sizeof(int),1,fi);
1598 fwrite(&distros,sizeof(int),1,fi);
1599 fwrite(&scroll_x,sizeof(float),1,fi);
1600 fwrite(&tux,sizeof(Player),1,fi);
1601 timer_fwrite(&tux.invincible_timer,fi);
1602 timer_fwrite(&tux.skidding_timer,fi);
1603 timer_fwrite(&tux.safe_timer,fi);
1604 timer_fwrite(&tux.frame_timer,fi);
1605 timer_fwrite(&time_left,fi);
1606 ui = st_get_ticks();
1607 fwrite(&ui,sizeof(int),1,fi);
1613 void loadgame(int slot)
1615 char savefile[1024];
1620 sprintf(savefile,"%s/slot%d.save",st_save_dir,slot);
1622 fi = fopen(savefile, "rb");
1626 fprintf(stderr, "Warning: I could not open the slot file ");
1631 fgets(str, 100, fi);
1632 strcpy(level_subset, str);
1633 level_subset[strlen(level_subset)-1] = '\0';
1634 fread(&level,sizeof(int),1,fi);
1637 level_free(¤t_level);
1638 if(level_load(¤t_level,level_subset,level) != 0)
1641 activate_bad_guys();
1642 activate_particle_systems();
1644 level_load_gfx(¤t_level);
1646 level_load_song(¤t_level);
1648 update_time = st_get_ticks();
1650 fread(&score,sizeof(int),1,fi);
1651 fread(&distros,sizeof(int),1,fi);
1652 fread(&scroll_x,sizeof(float),1,fi);
1653 fread(&tux, sizeof(Player), 1, fi);
1654 timer_fread(&tux.invincible_timer,fi);
1655 timer_fread(&tux.skidding_timer,fi);
1656 timer_fread(&tux.safe_timer,fi);
1657 timer_fread(&tux.frame_timer,fi);
1658 timer_fread(&time_left,fi);
1659 fread(&ui,sizeof(int),1,fi);
1660 tux.hphysic.start_time += st_get_ticks() - ui;
1661 tux.vphysic.start_time += st_get_ticks() - ui;
1667 void slotinfo(char **pinfo, int slot)
1670 char slotfile[1024];
1674 sprintf(slotfile,"%s/slot%d.save",st_save_dir,slot);
1676 fi = fopen(slotfile, "rb");
1678 sprintf(tmp,"Slot %d - ",slot);
1686 fgets(str, 100, fi);
1687 str[strlen(str)-1] = '\0';
1689 strcat(tmp, " / Level:");
1690 fread(&slot_level,sizeof(int),1,fi);
1691 sprintf(str,"%d",slot_level);
1696 *pinfo = (char*) malloc(sizeof(char) * (strlen(tmp)+1));