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_load_game_menu(true);
706 else if(current_menu == load_game_menu )
708 process_save_load_game_menu(false);
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(&tux_right[0], datadir + "/images/shared/tux-right-0.png", USE_ALPHA);
826 texture_load(&tux_right[1], datadir + "/images/shared/tux-right-1.png", USE_ALPHA);
827 texture_load(&tux_right[2], datadir + "/images/shared/tux-right-2.png", USE_ALPHA);
829 texture_load(&tux_left[0], datadir + "/images/shared/tux-left-0.png", USE_ALPHA);
830 texture_load(&tux_left[1], datadir + "/images/shared/tux-left-1.png", USE_ALPHA);
831 texture_load(&tux_left[2], datadir + "/images/shared/tux-left-2.png", USE_ALPHA);
833 texture_load(&firetux_right[0], datadir + "/images/shared/firetux-right-0.png", USE_ALPHA);
834 texture_load(&firetux_right[1], datadir + "/images/shared/firetux-right-1.png", USE_ALPHA);
835 texture_load(&firetux_right[2], datadir + "/images/shared/firetux-right-2.png", USE_ALPHA);
837 texture_load(&firetux_left[0], datadir + "/images/shared/firetux-left-0.png", USE_ALPHA);
838 texture_load(&firetux_left[1], datadir + "/images/shared/firetux-left-1.png", USE_ALPHA);
839 texture_load(&firetux_left[2], datadir + "/images/shared/firetux-left-2.png", USE_ALPHA);
842 texture_load(&cape_right[0], datadir + "/images/shared/cape-right-0.png",
845 texture_load(&cape_right[1], datadir + "/images/shared/cape-right-1.png",
848 texture_load(&cape_left[0], datadir + "/images/shared/cape-left-0.png",
851 texture_load(&cape_left[1], datadir + "/images/shared/cape-left-1.png",
854 texture_load(&bigtux_right[0], datadir + "/images/shared/bigtux-right-0.png",
857 texture_load(&bigtux_right[1], datadir + "/images/shared/bigtux-right-1.png",
860 texture_load(&bigtux_right[2], datadir + "/images/shared/bigtux-right-2.png",
863 texture_load(&bigtux_right_jump, datadir + "/images/shared/bigtux-right-jump.png", USE_ALPHA);
865 texture_load(&bigtux_left[0], datadir + "/images/shared/bigtux-left-0.png",
868 texture_load(&bigtux_left[1], datadir + "/images/shared/bigtux-left-1.png",
871 texture_load(&bigtux_left[2], datadir + "/images/shared/bigtux-left-2.png",
874 texture_load(&bigtux_left_jump, datadir + "/images/shared/bigtux-left-jump.png", USE_ALPHA);
876 texture_load(&bigcape_right[0], datadir + "/images/shared/bigcape-right-0.png",
879 texture_load(&bigcape_right[1], datadir + "/images/shared/bigcape-right-1.png",
882 texture_load(&bigcape_left[0], datadir + "/images/shared/bigcape-left-0.png",
885 texture_load(&bigcape_left[1], datadir + "/images/shared/bigcape-left-1.png",
888 texture_load(&bigfiretux_right[0], datadir + "/images/shared/bigfiretux-right-0.png",
891 texture_load(&bigfiretux_right[1], datadir + "/images/shared/bigfiretux-right-1.png",
894 texture_load(&bigfiretux_right[2], datadir + "/images/shared/bigfiretux-right-2.png",
897 texture_load(&bigfiretux_right_jump, datadir + "/images/shared/bigfiretux-right-jump.png", USE_ALPHA);
899 texture_load(&bigfiretux_left[0], datadir + "/images/shared/bigfiretux-left-0.png",
902 texture_load(&bigfiretux_left[1], datadir + "/images/shared/bigfiretux-left-1.png",
905 texture_load(&bigfiretux_left[2], datadir + "/images/shared/bigfiretux-left-2.png",
908 texture_load(&bigfiretux_left_jump, datadir + "/images/shared/bigfiretux-left-jump.png", USE_ALPHA);
910 texture_load(&bigcape_right[0], datadir + "/images/shared/bigcape-right-0.png",
913 texture_load(&bigcape_right[1], datadir + "/images/shared/bigcape-right-1.png",
916 texture_load(&bigcape_left[0], datadir + "/images/shared/bigcape-left-0.png",
919 texture_load(&bigcape_left[1], datadir + "/images/shared/bigcape-left-1.png",
923 texture_load(&ducktux_right, datadir +
924 "/images/shared/ducktux-right.png",
927 texture_load(&ducktux_left, datadir +
928 "/images/shared/ducktux-left.png",
931 texture_load(&skidtux_right, datadir +
932 "/images/shared/skidtux-right.png",
935 texture_load(&skidtux_left, datadir +
936 "/images/shared/skidtux-left.png",
939 texture_load(&duckfiretux_right, datadir +
940 "/images/shared/duckfiretux-right.png",
943 texture_load(&duckfiretux_left, datadir +
944 "/images/shared/duckfiretux-left.png",
947 texture_load(&skidfiretux_right, datadir +
948 "/images/shared/skidfiretux-right.png",
951 texture_load(&skidfiretux_left, datadir +
952 "/images/shared/skidfiretux-left.png",
958 texture_load(&img_box_full, datadir + "/images/shared/box-full.png",
960 texture_load(&img_box_empty, datadir + "/images/shared/box-empty.png",
967 texture_load(&img_water, datadir + "/images/shared/water.png", IGNORE_ALPHA);
969 texture_load(&img_waves[0], datadir + "/images/shared/waves-0.png",
972 texture_load(&img_waves[1], datadir + "/images/shared/waves-1.png",
975 texture_load(&img_waves[2], datadir + "/images/shared/waves-2.png",
981 texture_load(&img_pole, datadir + "/images/shared/pole.png", USE_ALPHA);
982 texture_load(&img_poletop, datadir + "/images/shared/poletop.png",
988 texture_load(&img_flag[0], datadir + "/images/shared/flag-0.png",
990 texture_load(&img_flag[1], datadir + "/images/shared/flag-1.png",
996 texture_load(&img_cloud[0][0], datadir + "/images/shared/cloud-00.png",
999 texture_load(&img_cloud[0][1], datadir + "/images/shared/cloud-01.png",
1002 texture_load(&img_cloud[0][2], datadir + "/images/shared/cloud-02.png",
1005 texture_load(&img_cloud[0][3], datadir + "/images/shared/cloud-03.png",
1009 texture_load(&img_cloud[1][0], datadir + "/images/shared/cloud-10.png",
1012 texture_load(&img_cloud[1][1], datadir + "/images/shared/cloud-11.png",
1015 texture_load(&img_cloud[1][2], datadir + "/images/shared/cloud-12.png",
1018 texture_load(&img_cloud[1][3], datadir + "/images/shared/cloud-13.png",
1027 texture_load(&img_mints, datadir + "/images/shared/mints.png", USE_ALPHA);
1028 texture_load(&img_coffee, datadir + "/images/shared/coffee.png", USE_ALPHA);
1033 texture_load(&img_bullet, datadir + "/images/shared/bullet.png", USE_ALPHA);
1035 texture_load(&img_red_glow, datadir + "/images/shared/red-glow.png",
1042 texture_load(&img_distro[0], datadir + "/images/shared/distro-0.png",
1045 texture_load(&img_distro[1], datadir + "/images/shared/distro-1.png",
1048 texture_load(&img_distro[2], datadir + "/images/shared/distro-2.png",
1051 texture_load(&img_distro[3], datadir + "/images/shared/distro-3.png",
1057 texture_load(&tux_life, datadir + "/images/shared/tux-life.png",
1062 texture_load(&img_golden_herring, datadir + "/images/shared/golden-herring.png",
1066 /* Super background: */
1068 texture_load(&img_super_bkgd, datadir + "/images/shared/super-bkgd.png",
1072 /* Sound effects: */
1074 /* if (use_sound) // this will introduce SERIOUS bugs here ! because "load_sound"
1075 // initialize sounds[i] with the correct pointer's value:
1076 // NULL or something else. And it will be dangerous to
1077 // play with not-initialized pointers.
1078 // This is also true with if (use_music)
1079 Send a mail to me: neoneurone@users.sf.net, if you have another opinion. :)
1081 for (i = 0; i < NUM_SOUNDS; i++)
1082 sounds[i] = load_sound(datadir + soundfilenames[i]);
1085 herring_song = load_song(datadir + "/music/SALCON.MOD");
1089 /* Free shared data: */
1091 void unloadshared(void)
1095 for (i = 0; i < 3; i++)
1097 texture_free(&tux_right[i]);
1098 texture_free(&tux_left[i]);
1099 texture_free(&bigtux_right[i]);
1100 texture_free(&bigtux_left[i]);
1103 texture_free(&bigtux_right_jump);
1104 texture_free(&bigtux_left_jump);
1106 for (i = 0; i < 2; i++)
1108 texture_free(&cape_right[i]);
1109 texture_free(&cape_left[i]);
1110 texture_free(&bigcape_right[i]);
1111 texture_free(&bigcape_left[i]);
1114 texture_free(&ducktux_left);
1115 texture_free(&ducktux_right);
1117 texture_free(&skidtux_left);
1118 texture_free(&skidtux_right);
1122 texture_free(&img_box_full);
1123 texture_free(&img_box_empty);
1125 texture_free(&img_water);
1126 for (i = 0; i < 3; i++)
1127 texture_free(&img_waves[i]);
1129 texture_free(&img_pole);
1130 texture_free(&img_poletop);
1132 for (i = 0; i < 2; i++)
1133 texture_free(&img_flag[i]);
1135 texture_free(&img_mints);
1136 texture_free(&img_coffee);
1138 for (i = 0; i < 4; i++)
1140 texture_free(&img_distro[i]);
1141 texture_free(&img_cloud[0][i]);
1142 texture_free(&img_cloud[1][i]);
1145 texture_free(&img_golden_herring);
1147 for (i = 0; i < NUM_SOUNDS; i++)
1148 free_chunk(sounds[i]);
1150 /* free the herring song */
1151 free_music( herring_song );
1155 /* Draw a tile on the screen: */
1157 void drawshape(float x, float y, unsigned int c, Uint8 alpha)
1161 Tile* ptile = TileManager::instance()->get(c);
1164 if(ptile->images.size() > 1)
1166 texture_draw(&ptile->images[( ((global_frame_counter*25) / ptile->anim_speed) % (ptile->images.size()))],x,y, alpha);
1168 else if (ptile->images.size() == 1)
1170 texture_draw(&ptile->images[0],x,y, alpha);
1174 //printf("Tile not dravable %u\n", c);
1181 /* What shape is at some position? */
1182 unsigned int shape(float x, float y)
1191 if (yy >= 0 && yy < 15 && xx >= 0 && xx <= current_level.width)
1193 c = current_level.ia_tiles[yy][xx];
1201 Tile* gettile(float x, float y)
1203 return TileManager::instance()->get(shape(x, y));
1206 bool issolid(float x, float y)
1208 Tile* tile = TileManager::instance()->get
1212 if(tile->solid == true)
1223 /* Is it a brick? */
1225 bool isbrick(float x, float y)
1227 Tile* tile = TileManager::instance()->get
1231 if(tile->brick == true)
1245 bool isice(float x, float y)
1247 Tile* tile = TileManager::instance()->get
1251 if(tile->ice == true)
1262 /* Is it a full box? */
1264 bool isfullbox(float x, float y)
1266 Tile* tile = TileManager::instance()->get
1270 if(tile->fullbox == true)
1281 bool isdistro(float x, float y)
1283 Tile* tile = TileManager::instance()->get(shape(x,y));
1284 return tile && tile->distro;
1287 /* Break a brick: */
1288 void trybreakbrick(float x, float y, bool small)
1290 Tile* tile = gettile(x, y);
1295 /* Get a distro from it: */
1296 add_bouncy_distro(((int)(x + 1) / 32) * 32,
1297 (int)(y / 32) * 32);
1299 if (!counting_distros)
1301 counting_distros = true;
1302 distro_counter = 50;
1305 if (distro_counter <= 0)
1306 level_change(¤t_level,x, y, TM_IA, tile->next_tile);
1308 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1309 score = score + SCORE_DISTRO;
1314 /* Get rid of it: */
1315 level_change(¤t_level,x, y, TM_IA, tile->next_tile);
1317 /* Replace it with broken bits: */
1318 add_broken_brick(((int)(x + 1) / 32) * 32,
1319 (int)(y / 32) * 32);
1321 /* Get some score: */
1322 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
1323 score = score + SCORE_BRICK;
1329 /* Bounce a brick: */
1331 void bumpbrick(float x, float y)
1333 add_bouncy_brick(((int)(x + 1) / 32) * 32,
1334 (int)(y / 32) * 32);
1336 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
1342 void tryemptybox(float x, float y, int col_side)
1344 Tile* tile = gettile(x,y);
1348 // according to the collision side, set the upgrade direction
1349 if(col_side == LEFT)
1356 case 1: //'A': /* Box with a distro! */
1357 add_bouncy_distro(((int)(x + 1) / 32) * 32, (int)(y / 32) * 32 - 32);
1358 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1359 score = score + SCORE_DISTRO;
1363 case 2: // 'B': /* Add an upgrade! */
1364 if (tux.size == SMALL) /* Tux is small, add mints! */
1365 add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_MINTS);
1366 else /* Tux is big, add coffee: */
1367 add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_COFFEE);
1368 play_sound(sounds[SND_UPGRADE], SOUND_CENTER_SPEAKER);
1371 case 3:// '!': /* Add a golden herring */
1372 add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_HERRING);
1378 /* Empty the box: */
1379 level_change(¤t_level,x, y, TM_IA, tile->next_tile);
1382 /* Try to grab a distro: */
1383 void trygrabdistro(float x, float y, int bounciness)
1385 Tile* tile = gettile(x, y);
1386 if (tile && tile->distro)
1388 level_change(¤t_level,x, y, TM_IA, tile->next_tile);
1389 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1391 if (bounciness == BOUNCE)
1393 add_bouncy_distro(((int)(x + 1) / 32) * 32,
1394 (int)(y / 32) * 32);
1397 score = score + SCORE_DISTRO;
1402 /* Try to bump a bad guy from below: */
1403 void trybumpbadguy(float x, float y)
1406 for (unsigned int i = 0; i < bad_guys.size(); i++)
1408 if (bad_guys[i].base.x >= x - 32 && bad_guys[i].base.x <= x + 32 &&
1409 bad_guys[i].base.y >= y - 16 && bad_guys[i].base.y <= y + 16)
1411 bad_guys[i].collision(&tux, CO_PLAYER, COLLISION_BUMP);
1417 for (unsigned int i = 0; i < upgrades.size(); i++)
1419 if (upgrades[i].base.height == 32 &&
1420 upgrades[i].base.x >= x - 32 && upgrades[i].base.x <= x + 32 &&
1421 upgrades[i].base.y >= y - 16 && upgrades[i].base.y <= y + 16)
1423 upgrades[i].base.xm = -upgrades[i].base.xm;
1424 upgrades[i].base.ym = -8;
1425 play_sound(sounds[SND_BUMP_UPGRADE], SOUND_CENTER_SPEAKER);
1431 void drawstatus(void)
1435 sprintf(str, "%d", score);
1436 text_draw(&white_text, "SCORE", 0, 0, 1);
1437 text_draw(&gold_text, str, 96, 0, 1);
1439 if(st_gl_mode != ST_GL_TEST)
1441 sprintf(str, "%d", hs_score);
1442 text_draw(&white_text, "HIGH", 0, 20, 1);
1443 text_draw(&gold_text, str, 96, 20, 1);
1447 text_draw(&white_text,"Press ESC To Return",0,20,1);
1450 if (timer_get_left(&time_left) > TIME_WARNING || (global_frame_counter % 10) < 5)
1452 sprintf(str, "%d", timer_get_left(&time_left) / 1000 );
1453 text_draw(&white_text, "TIME", 224, 0, 1);
1454 text_draw(&gold_text, str, 304, 0, 1);
1457 sprintf(str, "%d", distros);
1458 text_draw(&white_text, "DISTROS", screen->h, 0, 1);
1459 text_draw(&gold_text, str, 608, 0, 1);
1461 text_draw(&white_text, "LIVES", screen->h, 20, 1);
1465 sprintf(str, "%2.1f", fps_fps);
1466 text_draw(&white_text, "FPS", screen->h, 40, 1);
1467 text_draw(&gold_text, str, screen->h + 60, 40, 1);
1470 for(int i=0; i < tux.lives; ++i)
1472 texture_draw(&tux_life,565+(18*i),20);
1477 void drawendscreen(void)
1481 clearscreen(0, 0, 0);
1483 text_drawf(&blue_text, "GAMEOVER", 0, 200, A_HMIDDLE, A_TOP, 1);
1485 sprintf(str, "SCORE: %d", score);
1486 text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1);
1488 sprintf(str, "DISTROS: %d", distros);
1489 text_drawf(&gold_text, str, 0, 256, A_HMIDDLE, A_TOP, 1);
1494 wait_for_event(event,2000,5000,true);
1497 void drawresultscreen(void)
1501 clearscreen(0, 0, 0);
1503 text_drawf(&blue_text, "Result:", 0, 200, A_HMIDDLE, A_TOP, 1);
1505 sprintf(str, "SCORE: %d", score);
1506 text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1);
1508 sprintf(str, "DISTROS: %d", distros);
1509 text_drawf(&gold_text, str, 0, 256, A_HMIDDLE, A_TOP, 1);
1514 wait_for_event(event,2000,5000,true);
1517 void savegame(int slot)
1519 char savefile[1024];
1523 sprintf(savefile,"%s/slot%d.save",st_save_dir,slot);
1525 fi = fopen(savefile, "wb");
1529 fprintf(stderr, "Warning: I could not open the slot file ");
1533 fputs(level_subset, fi);
1535 fwrite(&level,sizeof(int),1,fi);
1536 fwrite(&score,sizeof(int),1,fi);
1537 fwrite(&distros,sizeof(int),1,fi);
1538 fwrite(&scroll_x,sizeof(float),1,fi);
1539 fwrite(&tux,sizeof(Player),1,fi);
1540 timer_fwrite(&tux.invincible_timer,fi);
1541 timer_fwrite(&tux.skidding_timer,fi);
1542 timer_fwrite(&tux.safe_timer,fi);
1543 timer_fwrite(&tux.frame_timer,fi);
1544 timer_fwrite(&time_left,fi);
1545 ui = st_get_ticks();
1546 fwrite(&ui,sizeof(int),1,fi);
1552 void loadgame(int slot)
1554 char savefile[1024];
1559 sprintf(savefile,"%s/slot%d.save",st_save_dir,slot);
1561 fi = fopen(savefile, "rb");
1565 fprintf(stderr, "Warning: I could not open the slot file ");
1570 fgets(str, 100, fi);
1571 strcpy(level_subset, str);
1572 level_subset[strlen(level_subset)-1] = '\0';
1573 fread(&level,sizeof(int),1,fi);
1576 level_free(¤t_level);
1577 if(level_load(¤t_level,level_subset,level) != 0)
1580 activate_bad_guys(¤t_level);
1581 activate_particle_systems();
1583 level_load_gfx(¤t_level);
1585 level_load_song(¤t_level);
1587 update_time = st_get_ticks();
1589 fread(&score,sizeof(int),1,fi);
1590 fread(&distros,sizeof(int),1,fi);
1591 fread(&scroll_x,sizeof(float),1,fi);
1592 fread(&tux, sizeof(Player), 1, fi);
1593 timer_fread(&tux.invincible_timer,fi);
1594 timer_fread(&tux.skidding_timer,fi);
1595 timer_fread(&tux.safe_timer,fi);
1596 timer_fread(&tux.frame_timer,fi);
1597 timer_fread(&time_left,fi);
1598 fread(&ui,sizeof(int),1,fi);
1604 void slotinfo(char **pinfo, int slot)
1607 char slotfile[1024];
1611 sprintf(slotfile,"%s/slot%d.save",st_save_dir,slot);
1613 fi = fopen(slotfile, "rb");
1615 sprintf(tmp,"Slot %d - ",slot);
1623 fgets(str, 100, fi);
1624 str[strlen(str)-1] = '\0';
1626 strcat(tmp, " / Level:");
1627 fread(&slot_level,sizeof(int),1,fi);
1628 sprintf(str,"%d",slot_level);
1633 *pinfo = (char*) malloc(sizeof(char) * (strlen(tmp)+1));