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);
94 void start_timers(void)
96 timer_start(&time_left,current_level.time_left*1000);
97 st_pause_ticks_init();
98 update_time = st_get_ticks();
101 void activate_bad_guys(void)
103 for (std::vector<BadGuyData>::iterator i = current_level.badguy_data.begin();
104 i != current_level.badguy_data.end();
107 add_bad_guy(i->x, i->y, i->kind);
111 void activate_particle_systems(void)
113 if(current_level.particle_system == "clouds")
115 particle_systems.push_back(new CloudParticleSystem);
117 else if(current_level.particle_system == "snow")
119 particle_systems.push_back(new SnowParticleSystem);
121 else if(current_level.particle_system != "")
123 st_abort("unknown particle system specified in level", "");
127 /* --- GAME EVENT! --- */
129 void game_event(void)
131 while (SDL_PollEvent(&event))
135 case SDL_QUIT: /* Quit event - quit: */
138 case SDL_KEYDOWN: /* A keypress! */
139 key = event.key.keysym.sym;
141 /* Check for menu-events, if the menu is shown */
143 menu_event(&event.key.keysym);
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)
270 /* Handle joystick for the menu */
273 if(tux.input.down == DOWN)
274 menuaction = MENU_ACTION_DOWN;
276 menuaction = MENU_ACTION_UP;
283 case SDL_JOYBUTTONDOWN:
284 if (event.jbutton.button == JOY_A)
286 else if (event.jbutton.button == JOY_B)
287 tux.input.fire = DOWN;
289 case SDL_JOYBUTTONUP:
290 if (event.jbutton.button == JOY_A)
292 else if (event.jbutton.button == JOY_B)
296 menuaction = MENU_ACTION_HIT;
307 /* --- GAME ACTION! --- */
309 int game_action(void)
313 /* (tux_dying || next_level) */
314 if (tux.dying || next_level)
316 /* Tux either died, or reached the end of a level! */
323 /* End of a level! */
326 if(st_gl_mode != ST_GL_TEST)
333 level_free(¤t_level);
345 /* No more lives!? */
349 if(st_gl_mode != ST_GL_TEST)
352 if(st_gl_mode != ST_GL_TEST)
354 if (score > hs_score)
358 level_free(¤t_level);
363 } /* if (lives < 0) */
366 /* Either way, (re-)load the (next) level... */
370 level_free(¤t_level);
372 if (st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
374 if(level_load(¤t_level, level_subset) != 0)
379 if(level_load(¤t_level,level_subset,level) != 0)
386 activate_particle_systems();
388 level_load_gfx(¤t_level);
390 level_load_song(¤t_level);
391 if(st_gl_mode != ST_GL_TEST)
395 play_current_music();
400 /* Handle bouncy distros: */
401 for (i = 0; i < bouncy_distros.size(); i++)
403 bouncy_distro_action(&bouncy_distros[i]);
407 /* Handle broken bricks: */
408 for (i = 0; i < broken_bricks.size(); i++)
410 broken_brick_action(&broken_bricks[i]);
414 /* Handle distro counting: */
416 if (counting_distros)
420 if (distro_counter <= 0)
421 counting_distros = -1;
425 /* Handle bouncy bricks: */
427 for (i = 0; i < bouncy_bricks.size(); i++)
429 bouncy_brick_action(&bouncy_bricks[i]);
433 /* Handle floating scores: */
435 for (i = 0; i < floating_scores.size(); i++)
437 floating_score_action(&floating_scores[i]);
441 /* Handle bullets: */
443 for (i = 0; i < bullets.size(); ++i)
445 bullet_action(&bullets[i]);
448 /* Handle upgrades: */
450 for (i = 0; i < upgrades.size(); i++)
452 upgrade_action(&upgrades[i]);
456 /* Handle bad guys: */
458 for (i = 0; i < bad_guys.size(); i++)
460 bad_guys[i].action();
463 /* update particle systems */
464 std::vector<ParticleSystem*>::iterator p;
465 for(p = particle_systems.begin(); p != particle_systems.end(); ++p)
467 (*p)->simulate(frame_ratio);
470 /* Handle all possible collisions. */
476 /* --- GAME DRAW! --- */
483 if (tux.dying && (global_frame_counter % 4) == 0)
484 clearscreen(255, 255, 255);
485 else if(timer_check(&super_bkgd_timer))
486 texture_draw(&img_super_bkgd, 0, 0);
489 /* Draw the real background */
490 if(current_level.bkgd_image[0] != '\0')
492 int s = (int)scroll_x / 30;
493 texture_draw_part(&img_bkgd,s,0,0,0,img_bkgd.w - s, img_bkgd.h);
494 texture_draw_part(&img_bkgd,0,0,screen->w - s ,0,s,img_bkgd.h);
498 clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue);
502 /* Draw particle systems (background) */
503 std::vector<ParticleSystem*>::iterator p;
504 for(p = particle_systems.begin(); p != particle_systems.end(); ++p)
506 (*p)->draw(scroll_x, 0, 0);
509 /* Draw background: */
511 for (y = 0; y < 15; ++y)
513 for (x = 0; x < 21; ++x)
515 drawshape(32*x - fmodf(scroll_x, 32), y * 32,
516 current_level.bg_tiles[(int)y][(int)x + (int)(scroll_x / 32)]);
520 /* Draw interactive tiles: */
521 for (y = 0; y < 15; ++y)
523 for (x = 0; x < 21; ++x)
525 drawshape(32*x - fmodf(scroll_x, 32), y * 32,
526 current_level.ia_tiles[(int)y][(int)x + (int)(scroll_x / 32)]);
530 /* (Bouncy bricks): */
531 for (unsigned int i = 0; i < bouncy_bricks.size(); ++i)
532 bouncy_brick_draw(&bouncy_bricks[i]);
534 for (unsigned int i = 0; i < bad_guys.size(); ++i)
539 for (unsigned int i = 0; i < bullets.size(); ++i)
540 bullet_draw(&bullets[i]);
542 for (unsigned int i = 0; i < floating_scores.size(); ++i)
543 floating_score_draw(&floating_scores[i]);
545 for (unsigned int i = 0; i < upgrades.size(); ++i)
546 upgrade_draw(&upgrades[i]);
548 for (unsigned int i = 0; i < bouncy_distros.size(); ++i)
549 bouncy_distro_draw(&bouncy_distros[i]);
551 for (unsigned int i = 0; i < broken_bricks.size(); ++i)
552 broken_brick_draw(&broken_bricks[i]);
554 /* Draw foreground: */
555 for (y = 0; y < 15; ++y)
557 for (x = 0; x < 21; ++x)
559 drawshape(32*x - fmodf(scroll_x, 32), y * 32,
560 current_level.fg_tiles[(int)y][(int)x + (int)(scroll_x / 32)]);
564 /* Draw particle systems (foreground) */
565 for(p = particle_systems.begin(); p != particle_systems.end(); ++p)
567 (*p)->draw(scroll_x, 0, 1);
574 int x = screen->h / 20;
575 for(int i = 0; i < x; ++i)
577 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);
579 fillrect(0,0,screen->w,screen->h,rand() % 50, rand() % 50, rand() % 50, 128);
580 text_drawf(&blue_text, "PAUSE - Press 'P' To Play", 0, 230, A_HMIDDLE, A_TOP, 1);
584 menu_process_current();
586 /* (Update it all!) */
590 /* --- GAME LOOP! --- */
592 int gameloop(const char * subset, int levelnb, int mode)
594 int fps_cnt, jump, done;
595 timer_type fps_timer, frame_timer;
596 timer_init(&fps_timer, true);
597 timer_init(&frame_timer, true);
608 strcpy(level_subset,subset);
610 if (st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
612 if (level_load(¤t_level, level_subset))
617 if(level_load(¤t_level, level_subset, level) != 0)
621 level_load_gfx(¤t_level);
623 activate_particle_systems();
624 level_load_song(¤t_level);
628 if(st_gl_mode != ST_GL_TEST)
633 if(st_gl_mode == ST_GL_PLAY || st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
636 timer_init(&time_left,true);
639 if(st_gl_mode == ST_GL_LOAD_GAME)
642 /* --- MAIN GAME LOOP!!! --- */
647 global_frame_counter = 0;
649 timer_init(&fps_timer,true);
650 timer_init(&frame_timer,true);
655 clearscreen(0, 0, 0);
659 play_current_music();
662 while (SDL_PollEvent(&event))
670 /* Calculate the movement-factor */
671 frame_ratio = ((double)(update_time-last_update_time))/((double)FRAME_RATE);
672 if(frame_ratio > 1.5) /* Quick hack to correct the unprecise CPU clocks a little bit. */
673 frame_ratio = 1.5 + (frame_ratio - 1.5) * 0.85;
675 if(!timer_check(&frame_timer))
677 timer_start(&frame_timer,25);
678 ++global_frame_counter;
683 tux.input.old_fire = tux.input.fire;
689 if(current_menu == game_menu)
691 switch (game_menu->check())
694 st_pause_ticks_stop();
697 update_load_save_game_menu(save_game_menu, false);
700 update_load_save_game_menu(load_game_menu, true);
703 st_pause_ticks_stop();
708 else if(current_menu == options_menu)
710 process_options_menu();
712 else if(current_menu == save_game_menu )
714 process_save_load_game_menu(true);
716 else if(current_menu == load_game_menu )
718 process_save_load_game_menu(false);
723 /* Handle actions: */
725 if(!game_pause && !show_menu)
727 /*float z = frame_ratio;
731 if (game_action() == 0)
733 /* == 0: no more lives */
734 /* == -1: continues */
746 if(debug_mode && debug_fps)
749 /*Draw the current scene to the screen */
750 /*If the machine running the game is too slow
751 skip the drawing of the frame (so the calculations are more precise and
752 the FPS aren't affected).*/
753 /*if( ! fps_fps < 50.0 )
756 jump = true;*/ /*FIXME: Implement this tweak right.*/
759 /* Time stops in pause mode */
760 if(game_pause || show_menu )
765 /* Set the time of the last update and the time of the current update */
766 last_update_time = update_time;
767 update_time = st_get_ticks();
769 /* Pause till next frame, if the machine running the game is too fast: */
770 /* FIXME: Works great for in OpenGl mode, where the CPU doesn't have to do that much. But
771 the results in SDL mode aren't perfect (thought the 100 FPS are reached), even on an AMD2500+. */
772 if(last_update_time >= update_time - 12 && !jump)
774 /*if((update_time - last_update_time) < 10)
775 SDL_Delay((11 - (update_time - last_update_time))/2);*/
781 if (timer_check(&time_left))
783 /* are we low on time ? */
784 if ((timer_get_left(&time_left) < TIME_WARNING)
785 && (get_current_music() != HURRYUP_MUSIC)) /* play the fast music */
787 set_current_music(HURRYUP_MUSIC);
788 play_current_music();
796 /* Calculate frames per second */
800 fps_fps = (1000.0 / (float)timer_get_gone(&fps_timer)) * (float)fps_cnt;
802 if(!timer_check(&fps_timer))
804 timer_start(&fps_timer,1000);
810 while (!done && !quit);
815 level_free(¤t_level);
820 game_started = false;
826 /* Load graphics/sounds shared between all levels: */
828 void loadshared(void)
833 texture_load(&tux_right[0], datadir + "/images/shared/tux-right-0.png", USE_ALPHA);
834 texture_load(&tux_right[1], datadir + "/images/shared/tux-right-1.png", USE_ALPHA);
835 texture_load(&tux_right[2], datadir + "/images/shared/tux-right-2.png", USE_ALPHA);
837 texture_load(&tux_left[0], datadir + "/images/shared/tux-left-0.png", USE_ALPHA);
838 texture_load(&tux_left[1], datadir + "/images/shared/tux-left-1.png", USE_ALPHA);
839 texture_load(&tux_left[2], datadir + "/images/shared/tux-left-2.png", USE_ALPHA);
841 texture_load(&firetux_right[0], datadir + "/images/shared/firetux-right-0.png", USE_ALPHA);
842 texture_load(&firetux_right[1], datadir + "/images/shared/firetux-right-1.png", USE_ALPHA);
843 texture_load(&firetux_right[2], datadir + "/images/shared/firetux-right-2.png", USE_ALPHA);
845 texture_load(&firetux_left[0], datadir + "/images/shared/firetux-left-0.png", USE_ALPHA);
846 texture_load(&firetux_left[1], datadir + "/images/shared/firetux-left-1.png", USE_ALPHA);
847 texture_load(&firetux_left[2], datadir + "/images/shared/firetux-left-2.png", USE_ALPHA);
850 texture_load(&cape_right[0], datadir + "/images/shared/cape-right-0.png",
853 texture_load(&cape_right[1], datadir + "/images/shared/cape-right-1.png",
856 texture_load(&cape_left[0], datadir + "/images/shared/cape-left-0.png",
859 texture_load(&cape_left[1], datadir + "/images/shared/cape-left-1.png",
862 texture_load(&bigtux_right[0], datadir + "/images/shared/bigtux-right-0.png",
865 texture_load(&bigtux_right[1], datadir + "/images/shared/bigtux-right-1.png",
868 texture_load(&bigtux_right[2], datadir + "/images/shared/bigtux-right-2.png",
871 texture_load(&bigtux_right_jump, datadir + "/images/shared/bigtux-right-jump.png", USE_ALPHA);
873 texture_load(&bigtux_left[0], datadir + "/images/shared/bigtux-left-0.png",
876 texture_load(&bigtux_left[1], datadir + "/images/shared/bigtux-left-1.png",
879 texture_load(&bigtux_left[2], datadir + "/images/shared/bigtux-left-2.png",
882 texture_load(&bigtux_left_jump, datadir + "/images/shared/bigtux-left-jump.png", USE_ALPHA);
884 texture_load(&bigcape_right[0], datadir + "/images/shared/bigcape-right-0.png",
887 texture_load(&bigcape_right[1], datadir + "/images/shared/bigcape-right-1.png",
890 texture_load(&bigcape_left[0], datadir + "/images/shared/bigcape-left-0.png",
893 texture_load(&bigcape_left[1], datadir + "/images/shared/bigcape-left-1.png",
896 texture_load(&bigfiretux_right[0], datadir + "/images/shared/bigfiretux-right-0.png",
899 texture_load(&bigfiretux_right[1], datadir + "/images/shared/bigfiretux-right-1.png",
902 texture_load(&bigfiretux_right[2], datadir + "/images/shared/bigfiretux-right-2.png",
905 texture_load(&bigfiretux_right_jump, datadir + "/images/shared/bigfiretux-right-jump.png", USE_ALPHA);
907 texture_load(&bigfiretux_left[0], datadir + "/images/shared/bigfiretux-left-0.png",
910 texture_load(&bigfiretux_left[1], datadir + "/images/shared/bigfiretux-left-1.png",
913 texture_load(&bigfiretux_left[2], datadir + "/images/shared/bigfiretux-left-2.png",
916 texture_load(&bigfiretux_left_jump, datadir + "/images/shared/bigfiretux-left-jump.png", USE_ALPHA);
918 texture_load(&bigcape_right[0], datadir + "/images/shared/bigcape-right-0.png",
921 texture_load(&bigcape_right[1], datadir + "/images/shared/bigcape-right-1.png",
924 texture_load(&bigcape_left[0], datadir + "/images/shared/bigcape-left-0.png",
927 texture_load(&bigcape_left[1], datadir + "/images/shared/bigcape-left-1.png",
931 texture_load(&ducktux_right, datadir +
932 "/images/shared/ducktux-right.png",
935 texture_load(&ducktux_left, datadir +
936 "/images/shared/ducktux-left.png",
939 texture_load(&skidtux_right, datadir +
940 "/images/shared/skidtux-right.png",
943 texture_load(&skidtux_left, datadir +
944 "/images/shared/skidtux-left.png",
947 texture_load(&duckfiretux_right, datadir +
948 "/images/shared/duckfiretux-right.png",
951 texture_load(&duckfiretux_left, datadir +
952 "/images/shared/duckfiretux-left.png",
955 texture_load(&skidfiretux_right, datadir +
956 "/images/shared/skidfiretux-right.png",
959 texture_load(&skidfiretux_left, datadir +
960 "/images/shared/skidfiretux-left.png",
966 texture_load(&img_box_full, datadir + "/images/shared/box-full.png",
968 texture_load(&img_box_empty, datadir + "/images/shared/box-empty.png",
975 texture_load(&img_water, datadir + "/images/shared/water.png", IGNORE_ALPHA);
977 texture_load(&img_waves[0], datadir + "/images/shared/waves-0.png",
980 texture_load(&img_waves[1], datadir + "/images/shared/waves-1.png",
983 texture_load(&img_waves[2], datadir + "/images/shared/waves-2.png",
989 texture_load(&img_pole, datadir + "/images/shared/pole.png", USE_ALPHA);
990 texture_load(&img_poletop, datadir + "/images/shared/poletop.png",
996 texture_load(&img_flag[0], datadir + "/images/shared/flag-0.png",
998 texture_load(&img_flag[1], datadir + "/images/shared/flag-1.png",
1004 texture_load(&img_cloud[0][0], datadir + "/images/shared/cloud-00.png",
1007 texture_load(&img_cloud[0][1], datadir + "/images/shared/cloud-01.png",
1010 texture_load(&img_cloud[0][2], datadir + "/images/shared/cloud-02.png",
1013 texture_load(&img_cloud[0][3], datadir + "/images/shared/cloud-03.png",
1017 texture_load(&img_cloud[1][0], datadir + "/images/shared/cloud-10.png",
1020 texture_load(&img_cloud[1][1], datadir + "/images/shared/cloud-11.png",
1023 texture_load(&img_cloud[1][2], datadir + "/images/shared/cloud-12.png",
1026 texture_load(&img_cloud[1][3], datadir + "/images/shared/cloud-13.png",
1034 texture_load(&img_bsod_left[0], datadir +
1035 "/images/shared/bsod-left-0.png",
1038 texture_load(&img_bsod_left[1], datadir +
1039 "/images/shared/bsod-left-1.png",
1042 texture_load(&img_bsod_left[2], datadir +
1043 "/images/shared/bsod-left-2.png",
1046 texture_load(&img_bsod_left[3], datadir +
1047 "/images/shared/bsod-left-3.png",
1050 texture_load(&img_bsod_right[0], datadir +
1051 "/images/shared/bsod-right-0.png",
1054 texture_load(&img_bsod_right[1], datadir +
1055 "/images/shared/bsod-right-1.png",
1058 texture_load(&img_bsod_right[2], datadir +
1059 "/images/shared/bsod-right-2.png",
1062 texture_load(&img_bsod_right[3], datadir +
1063 "/images/shared/bsod-right-3.png",
1066 texture_load(&img_bsod_squished_left, datadir +
1067 "/images/shared/bsod-squished-left.png",
1070 texture_load(&img_bsod_squished_right, datadir +
1071 "/images/shared/bsod-squished-right.png",
1074 texture_load(&img_bsod_falling_left, datadir +
1075 "/images/shared/bsod-falling-left.png",
1078 texture_load(&img_bsod_falling_right, datadir +
1079 "/images/shared/bsod-falling-right.png",
1085 texture_load(&img_laptop_left[0], datadir +
1086 "/images/shared/laptop-left-0.png",
1089 texture_load(&img_laptop_left[1], datadir +
1090 "/images/shared/laptop-left-1.png",
1093 texture_load(&img_laptop_left[2], datadir +
1094 "/images/shared/laptop-left-2.png",
1097 texture_load(&img_laptop_right[0], datadir +
1098 "/images/shared/laptop-right-0.png",
1101 texture_load(&img_laptop_right[1], datadir +
1102 "/images/shared/laptop-right-1.png",
1105 texture_load(&img_laptop_right[2], datadir +
1106 "/images/shared/laptop-right-2.png",
1109 texture_load(&img_laptop_flat_left, datadir +
1110 "/images/shared/laptop-flat-left.png",
1113 texture_load(&img_laptop_flat_right, datadir +
1114 "/images/shared/laptop-flat-right.png",
1117 texture_load(&img_laptop_falling_left, datadir +
1118 "/images/shared/laptop-falling-left.png",
1121 texture_load(&img_laptop_falling_right, datadir +
1122 "/images/shared/laptop-falling-right.png",
1128 texture_load(&img_money_left[0], datadir +
1129 "/images/shared/bag-left-0.png",
1132 texture_load(&img_money_left[1], datadir +
1133 "/images/shared/bag-left-1.png",
1136 texture_load(&img_money_right[0], datadir +
1137 "/images/shared/bag-right-0.png",
1140 texture_load(&img_money_right[1], datadir +
1141 "/images/shared/bag-right-1.png",
1145 for(int i=0; i<4; ++i) {
1147 snprintf(num, 4, "%d", i);
1148 texture_load(&img_mrbomb_left[i],
1149 datadir + "/images/shared/mrbomb-left-" + num + ".png", USE_ALPHA);
1150 texture_load(&img_mrbomb_right[i],
1151 datadir + "/images/shared/mrbomb-right-" + num + ".png", USE_ALPHA);
1155 texture_load(&img_stalactite,
1156 datadir + "/images/shared/stalactite.png", USE_ALPHA);
1157 texture_load(&img_stalactite_broken,
1158 datadir + "/images/shared/stalactite-broken.png", USE_ALPHA);
1162 texture_load(&img_mints, datadir + "/images/shared/mints.png", USE_ALPHA);
1163 texture_load(&img_coffee, datadir + "/images/shared/coffee.png", USE_ALPHA);
1168 texture_load(&img_bullet, datadir + "/images/shared/bullet.png", USE_ALPHA);
1170 texture_load(&img_red_glow, datadir + "/images/shared/red-glow.png",
1177 texture_load(&img_distro[0], datadir + "/images/shared/distro-0.png",
1180 texture_load(&img_distro[1], datadir + "/images/shared/distro-1.png",
1183 texture_load(&img_distro[2], datadir + "/images/shared/distro-2.png",
1186 texture_load(&img_distro[3], datadir + "/images/shared/distro-3.png",
1192 texture_load(&tux_life, datadir + "/images/shared/tux-life.png",
1197 texture_load(&img_golden_herring, datadir + "/images/shared/golden-herring.png",
1201 /* Super background: */
1203 texture_load(&img_super_bkgd, datadir + "/images/shared/super-bkgd.png",
1207 /* Sound effects: */
1209 /* if (use_sound) // this will introduce SERIOUS bugs here ! because "load_sound"
1210 // initialize sounds[i] with the correct pointer's value:
1211 // NULL or something else. And it will be dangerous to
1212 // play with not-initialized pointers.
1213 // This is also true with if (use_music)
1214 Send a mail to me: neoneurone@users.sf.net, if you have another opinion. :)
1216 for (i = 0; i < NUM_SOUNDS; i++)
1217 sounds[i] = load_sound(datadir + soundfilenames[i]);
1220 herring_song = load_song(datadir + "/music/SALCON.MOD");
1224 /* Free shared data: */
1226 void unloadshared(void)
1230 for (i = 0; i < 3; i++)
1232 texture_free(&tux_right[i]);
1233 texture_free(&tux_left[i]);
1234 texture_free(&bigtux_right[i]);
1235 texture_free(&bigtux_left[i]);
1238 texture_free(&bigtux_right_jump);
1239 texture_free(&bigtux_left_jump);
1241 for (i = 0; i < 2; i++)
1243 texture_free(&cape_right[i]);
1244 texture_free(&cape_left[i]);
1245 texture_free(&bigcape_right[i]);
1246 texture_free(&bigcape_left[i]);
1249 texture_free(&ducktux_left);
1250 texture_free(&ducktux_right);
1252 texture_free(&skidtux_left);
1253 texture_free(&skidtux_right);
1255 for (i = 0; i < 4; i++)
1257 texture_free(&img_bsod_left[i]);
1258 texture_free(&img_bsod_right[i]);
1261 texture_free(&img_bsod_squished_left);
1262 texture_free(&img_bsod_squished_right);
1264 texture_free(&img_bsod_falling_left);
1265 texture_free(&img_bsod_falling_right);
1267 for (i = 0; i < 3; i++)
1269 texture_free(&img_laptop_left[i]);
1270 texture_free(&img_laptop_right[i]);
1273 texture_free(&img_laptop_flat_left);
1274 texture_free(&img_laptop_flat_right);
1276 texture_free(&img_laptop_falling_left);
1277 texture_free(&img_laptop_falling_right);
1279 for (i = 0; i < 2; i++)
1281 texture_free(&img_money_left[i]);
1282 texture_free(&img_money_right[i]);
1285 for(i = 0; i < 4; i++) {
1286 texture_free(&img_mrbomb_left[i]);
1287 texture_free(&img_mrbomb_right[i]);
1290 texture_free(&img_stalactite);
1291 texture_free(&img_stalactite_broken);
1293 texture_free(&img_box_full);
1294 texture_free(&img_box_empty);
1296 texture_free(&img_water);
1297 for (i = 0; i < 3; i++)
1298 texture_free(&img_waves[i]);
1300 texture_free(&img_pole);
1301 texture_free(&img_poletop);
1303 for (i = 0; i < 2; i++)
1304 texture_free(&img_flag[i]);
1306 texture_free(&img_mints);
1307 texture_free(&img_coffee);
1309 for (i = 0; i < 4; i++)
1311 texture_free(&img_distro[i]);
1312 texture_free(&img_cloud[0][i]);
1313 texture_free(&img_cloud[1][i]);
1316 texture_free(&img_golden_herring);
1318 for (i = 0; i < NUM_SOUNDS; i++)
1319 free_chunk(sounds[i]);
1321 /* free the herring song */
1322 free_music( herring_song );
1326 /* Draw a tile on the screen: */
1328 void drawshape(float x, float y, unsigned int c)
1332 Tile* ptile = TileManager::instance()->get(c);
1335 if(ptile->images.size() > 1)
1337 texture_draw(&ptile->images[( ((global_frame_counter*25) / ptile->anim_speed) % (ptile->images.size()))],x,y);
1339 else if (ptile->images.size() == 1)
1341 texture_draw(&ptile->images[0],x,y);
1345 printf("Tile not dravable %u\n", c);
1351 if (c == 'X' || c == 'x')
1352 texture_draw(&img_brick[0], x, y);
1353 else if (c == 'Y' || c == 'y')
1354 texture_draw(&img_brick[1], x, y);
1355 else if (c == 'A' || c =='B' || c == '!')
1356 texture_draw(&img_box_full, x, y);
1358 texture_draw(&img_box_empty, x, y);
1359 else if (c >= 'C' && c <= 'F')
1360 texture_draw(&img_cloud[0][c - 'C'], x, y);
1361 else if (c >= 'c' && c <= 'f')
1362 texture_draw(&img_cloud[1][c - 'c'], x, y);
1363 else if (c >= 'G' && c <= 'J')
1364 texture_draw(&img_bkgd_tile[0][c - 'G'], x, y);
1365 else if (c >= 'g' && c <= 'j')
1366 texture_draw(&img_bkgd_tile[1][c - 'g'], x, y);
1368 texture_draw(&img_solid[0], x, y);
1370 texture_draw(&img_solid[1], x, y);
1372 texture_draw(&img_solid[2], x, y);
1374 texture_draw(&img_solid[3], x, y);
1377 z = (global_frame_counter / 2) % 6;
1380 texture_draw(&img_distro[z], x, y);
1382 texture_draw(&img_distro[2], x, y);
1384 texture_draw(&img_distro[1], x, y);
1388 z = (global_frame_counter / 3) % 3;
1390 texture_draw(&img_waves[z], x, y);
1393 texture_draw(&img_poletop, x, y);
1396 texture_draw(&img_pole, x, y);
1401 z = (global_frame_counter / 3) % 2;
1403 texture_draw(&img_flag[z], x + 16, y);
1406 texture_draw(&img_water, x, y);*/
1411 /* What shape is at some position? */
1412 unsigned int shape(float x, float y)
1421 if (yy >= 0 && yy < 15 && xx >= 0 && xx <= current_level.width)
1423 c = current_level.ia_tiles[yy][xx];
1431 Tile* gettile(float x, float y)
1433 return TileManager::instance()->get(shape(x, y));
1436 bool issolid(float x, float y)
1438 Tile* tile = TileManager::instance()->get
1442 if(tile->solid == true)
1453 /* Is it a brick? */
1455 bool isbrick(float x, float y)
1457 Tile* tile = TileManager::instance()->get
1461 if(tile->brick == true)
1475 bool isice(float x, float y)
1477 Tile* tile = TileManager::instance()->get
1481 if(tile->ice == true)
1492 /* Is it a full box? */
1494 bool isfullbox(float x, float y)
1496 Tile* tile = TileManager::instance()->get
1500 if(tile->fullbox == true)
1511 bool isdistro(float x, float y)
1513 Tile* tile = TileManager::instance()->get(shape(x,y));
1514 return tile && tile->distro;
1517 /* Break a brick: */
1519 void trybreakbrick(float x, float y)
1521 Tile* tile = gettile(x, y);
1526 /* Get a distro from it: */
1527 add_bouncy_distro(((int)(x + 1) / 32) * 32,
1528 (int)(y / 32) * 32);
1530 if (!counting_distros)
1532 counting_distros = true;
1533 distro_counter = 50;
1536 if (distro_counter <= 0)
1537 level_change(¤t_level,x, y, TM_IA, tile->next_tile2);
1539 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1540 score = score + SCORE_DISTRO;
1545 /* Get rid of it: */
1546 level_change(¤t_level,x, y, TM_IA, tile->next_tile);
1550 /* Replace it with broken bits: */
1552 add_broken_brick(((int)(x + 1) / 32) * 32,
1553 (int)(y / 32) * 32);
1556 /* Get some score: */
1558 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
1559 score = score + SCORE_BRICK;
1564 /* Bounce a brick: */
1566 void bumpbrick(float x, float y)
1568 add_bouncy_brick(((int)(x + 1) / 32) * 32,
1569 (int)(y / 32) * 32);
1571 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
1577 void tryemptybox(float x, float y, int col_side)
1579 Tile* tile = gettile(x,y);
1583 // according to the collision side, set the upgrade direction
1584 if(col_side == LEFT)
1591 case 1: //'A': /* Box with a distro! */
1592 add_bouncy_distro(((int)(x + 1) / 32) * 32, (int)(y / 32) * 32 - 32);
1593 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1594 score = score + SCORE_DISTRO;
1598 case 2: // 'B': /* Add an upgrade! */
1599 if (tux.size == SMALL) /* Tux is small, add mints! */
1600 add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_MINTS);
1601 else /* Tux is big, add coffee: */
1602 add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_COFFEE);
1603 play_sound(sounds[SND_UPGRADE], SOUND_CENTER_SPEAKER);
1606 case 3:// '!': /* Add a golden herring */
1607 add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_HERRING);
1613 /* Empty the box: */
1614 level_change(¤t_level,x, y, TM_IA, tile->next_tile);
1617 /* Try to grab a distro: */
1618 void trygrabdistro(float x, float y, int bounciness)
1620 Tile* tile = gettile(x, y);
1621 if (tile && tile->distro)
1623 level_change(¤t_level,x, y, TM_IA, tile->next_tile);
1624 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1626 if (bounciness == BOUNCE)
1628 add_bouncy_distro(((int)(x + 1) / 32) * 32,
1629 (int)(y / 32) * 32);
1632 score = score + SCORE_DISTRO;
1637 /* Try to bump a bad guy from below: */
1638 void trybumpbadguy(float x, float y)
1641 for (unsigned int i = 0; i < bad_guys.size(); i++)
1643 if (bad_guys[i].base.x >= x - 32 && bad_guys[i].base.x <= x + 32 &&
1644 bad_guys[i].base.y >= y - 16 && bad_guys[i].base.y <= y + 16)
1646 bad_guys[i].collision(&tux, CO_PLAYER, COLLISION_BUMP);
1652 for (unsigned int i = 0; i < upgrades.size(); i++)
1654 if (upgrades[i].base.height == 32 &&
1655 upgrades[i].base.x >= x - 32 && upgrades[i].base.x <= x + 32 &&
1656 upgrades[i].base.y >= y - 16 && upgrades[i].base.y <= y + 16)
1658 upgrades[i].base.xm = -upgrades[i].base.xm;
1659 upgrades[i].base.ym = -8;
1660 play_sound(sounds[SND_BUMP_UPGRADE], SOUND_CENTER_SPEAKER);
1666 void drawstatus(void)
1670 sprintf(str, "%d", score);
1671 text_draw(&white_text, "SCORE", 0, 0, 1);
1672 text_draw(&gold_text, str, 96, 0, 1);
1674 if(st_gl_mode != ST_GL_TEST)
1676 sprintf(str, "%d", hs_score);
1677 text_draw(&white_text, "HIGH", 0, 20, 1);
1678 text_draw(&gold_text, str, 96, 20, 1);
1682 text_draw(&white_text,"Press ESC To Return",0,20,1);
1685 if (timer_get_left(&time_left) > TIME_WARNING || (global_frame_counter % 10) < 5)
1687 sprintf(str, "%d", timer_get_left(&time_left) / 1000 );
1688 text_draw(&white_text, "TIME", 224, 0, 1);
1689 text_draw(&gold_text, str, 304, 0, 1);
1692 sprintf(str, "%d", distros);
1693 text_draw(&white_text, "DISTROS", screen->h, 0, 1);
1694 text_draw(&gold_text, str, 608, 0, 1);
1696 text_draw(&white_text, "LIVES", screen->h, 20, 1);
1700 sprintf(str, "%2.1f", fps_fps);
1701 text_draw(&white_text, "FPS", screen->h, 40, 1);
1702 text_draw(&gold_text, str, screen->h + 60, 40, 1);
1705 for(int i=0; i < tux.lives; ++i)
1707 texture_draw(&tux_life,565+(18*i),20);
1712 void drawendscreen(void)
1716 clearscreen(0, 0, 0);
1718 text_drawf(&blue_text, "GAMEOVER", 0, 200, A_HMIDDLE, A_TOP, 1);
1720 sprintf(str, "SCORE: %d", score);
1721 text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1);
1723 sprintf(str, "DISTROS: %d", distros);
1724 text_drawf(&gold_text, str, 0, 256, A_HMIDDLE, A_TOP, 1);
1730 void drawresultscreen(void)
1734 clearscreen(0, 0, 0);
1736 text_drawf(&blue_text, "Result:", 0, 200, A_HMIDDLE, A_TOP, 1);
1738 sprintf(str, "SCORE: %d", score);
1739 text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1);
1741 sprintf(str, "DISTROS: %d", distros);
1742 text_drawf(&gold_text, str, 0, 256, A_HMIDDLE, A_TOP, 1);
1748 void savegame(int slot)
1750 char savefile[1024];
1754 sprintf(savefile,"%s/slot%d.save",st_save_dir,slot);
1756 fi = fopen(savefile, "wb");
1760 fprintf(stderr, "Warning: I could not open the slot file ");
1764 fputs(level_subset, fi);
1766 fwrite(&level,sizeof(int),1,fi);
1767 fwrite(&score,sizeof(int),1,fi);
1768 fwrite(&distros,sizeof(int),1,fi);
1769 fwrite(&scroll_x,sizeof(float),1,fi);
1770 fwrite(&tux,sizeof(Player),1,fi);
1771 timer_fwrite(&tux.invincible_timer,fi);
1772 timer_fwrite(&tux.skidding_timer,fi);
1773 timer_fwrite(&tux.safe_timer,fi);
1774 timer_fwrite(&tux.frame_timer,fi);
1775 timer_fwrite(&time_left,fi);
1776 ui = st_get_ticks();
1777 fwrite(&ui,sizeof(int),1,fi);
1783 void loadgame(int slot)
1785 char savefile[1024];
1790 sprintf(savefile,"%s/slot%d.save",st_save_dir,slot);
1792 fi = fopen(savefile, "rb");
1796 fprintf(stderr, "Warning: I could not open the slot file ");
1801 fgets(str, 100, fi);
1802 strcpy(level_subset, str);
1803 level_subset[strlen(level_subset)-1] = '\0';
1804 fread(&level,sizeof(int),1,fi);
1807 level_free(¤t_level);
1808 if(level_load(¤t_level,level_subset,level) != 0)
1812 activate_bad_guys();
1813 activate_particle_systems();
1815 level_load_gfx(¤t_level);
1817 level_load_song(¤t_level);
1819 update_time = st_get_ticks();
1821 fread(&score,sizeof(int),1,fi);
1822 fread(&distros,sizeof(int),1,fi);
1823 fread(&scroll_x,sizeof(float),1,fi);
1824 fread(&tux, sizeof(Player), 1, fi);
1825 timer_fread(&tux.invincible_timer,fi);
1826 timer_fread(&tux.skidding_timer,fi);
1827 timer_fread(&tux.safe_timer,fi);
1828 timer_fread(&tux.frame_timer,fi);
1829 timer_fread(&time_left,fi);
1830 fread(&ui,sizeof(int),1,fi);
1831 tux.hphysic.start_time += st_get_ticks() - ui;
1832 tux.vphysic.start_time += st_get_ticks() - ui;
1838 void slotinfo(char **pinfo, int slot)
1841 char slotfile[1024];
1845 sprintf(slotfile,"%s/slot%d.save",st_save_dir,slot);
1847 fi = fopen(slotfile, "rb");
1849 sprintf(tmp,"Slot %d - ",slot);
1857 fgets(str, 100, fi);
1858 str[strlen(str)-1] = '\0';
1860 strcat(tmp, " / Level:");
1861 fread(&slot_level,sizeof(int),1,fi);
1862 sprintf(str,"%d",slot_level);
1867 *pinfo = (char*) malloc(sizeof(char) * (strlen(tmp)+1));