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: */
522 for (y = 0; y < 15; ++y)
524 for (x = 0; x < 21; ++x)
526 drawshape(32*x - fmodf(scroll_x, 32), y * 32,
527 current_level.ia_tiles[(int)y][(int)x + (int)(scroll_x / 32)]);
531 /* (Bouncy bricks): */
533 for (unsigned int i = 0; i < bouncy_bricks.size(); ++i)
534 bouncy_brick_draw(&bouncy_bricks[i]);
536 for (unsigned int i = 0; i < bad_guys.size(); ++i)
541 for (unsigned int i = 0; i < bullets.size(); ++i)
542 bullet_draw(&bullets[i]);
544 for (unsigned int i = 0; i < floating_scores.size(); ++i)
545 floating_score_draw(&floating_scores[i]);
547 for (unsigned int i = 0; i < upgrades.size(); ++i)
548 upgrade_draw(&upgrades[i]);
550 for (unsigned int i = 0; i < bouncy_distros.size(); ++i)
551 bouncy_distro_draw(&bouncy_distros[i]);
553 for (unsigned int i = 0; i < broken_bricks.size(); ++i)
554 broken_brick_draw(&broken_bricks[i]);
556 /* Draw foreground: */
558 for (y = 0; y < 15; ++y)
560 for (x = 0; x < 21; ++x)
562 drawshape(32*x - fmodf(scroll_x, 32), y * 32,
563 current_level.fg_tiles[(int)y][(int)x + (int)(scroll_x / 32)]);
567 /* Draw particle systems (foreground) */
568 for(p = particle_systems.begin(); p != particle_systems.end(); ++p)
570 (*p)->draw(scroll_x, 0, 1);
577 int x = screen->h / 20;
578 for(int i = 0; i < x; ++i)
580 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);
582 fillrect(0,0,screen->w,screen->h,rand() % 50, rand() % 50, rand() % 50, 128);
583 text_drawf(&blue_text, "PAUSE - Press 'P' To Play", 0, 230, A_HMIDDLE, A_TOP, 1);
587 menu_process_current();
589 /* (Update it all!) */
593 /* --- GAME LOOP! --- */
595 int gameloop(const char * subset, int levelnb, int mode)
597 int fps_cnt, jump, done;
598 timer_type fps_timer, frame_timer;
599 timer_init(&fps_timer, true);
600 timer_init(&frame_timer, true);
611 strcpy(level_subset,subset);
613 if (st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
615 if (level_load(¤t_level, level_subset))
620 if(level_load(¤t_level, level_subset, level) != 0)
624 level_load_gfx(¤t_level);
626 activate_particle_systems();
627 level_load_song(¤t_level);
631 if(st_gl_mode != ST_GL_TEST)
636 if(st_gl_mode == ST_GL_PLAY || st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
639 timer_init(&time_left,true);
642 if(st_gl_mode == ST_GL_LOAD_GAME)
645 /* --- MAIN GAME LOOP!!! --- */
650 global_frame_counter = 0;
652 timer_init(&fps_timer,true);
653 timer_init(&frame_timer,true);
658 clearscreen(0, 0, 0);
662 play_current_music();
665 while (SDL_PollEvent(&event))
673 /* Calculate the movement-factor */
674 frame_ratio = ((double)(update_time-last_update_time))/((double)FRAME_RATE);
675 if(frame_ratio > 1.5) /* Quick hack to correct the unprecise CPU clocks a little bit. */
676 frame_ratio = 1.5 + (frame_ratio - 1.5) * 0.85;
678 if(!timer_check(&frame_timer))
680 timer_start(&frame_timer,25);
681 ++global_frame_counter;
686 tux.input.old_fire = tux.input.fire;
692 if(current_menu == game_menu)
694 switch (game_menu->check())
697 st_pause_ticks_stop();
700 update_load_save_game_menu(save_game_menu, false);
703 update_load_save_game_menu(load_game_menu, true);
706 st_pause_ticks_stop();
711 else if(current_menu == options_menu)
713 process_options_menu();
715 else if(current_menu == save_game_menu )
717 process_save_load_game_menu(true);
719 else if(current_menu == load_game_menu )
721 process_save_load_game_menu(false);
726 /* Handle actions: */
728 if(!game_pause && !show_menu)
730 /*float z = frame_ratio;
734 if (game_action() == 0)
736 /* == 0: no more lives */
737 /* == -1: continues */
749 if(debug_mode && debug_fps)
752 /*Draw the current scene to the screen */
753 /*If the machine running the game is too slow
754 skip the drawing of the frame (so the calculations are more precise and
755 the FPS aren't affected).*/
756 /*if( ! fps_fps < 50.0 )
759 jump = true;*/ /*FIXME: Implement this tweak right.*/
762 /* Time stops in pause mode */
763 if(game_pause || show_menu )
768 /* Set the time of the last update and the time of the current update */
769 last_update_time = update_time;
770 update_time = st_get_ticks();
772 /* Pause till next frame, if the machine running the game is too fast: */
773 /* FIXME: Works great for in OpenGl mode, where the CPU doesn't have to do that much. But
774 the results in SDL mode aren't perfect (thought the 100 FPS are reached), even on an AMD2500+. */
775 if(last_update_time >= update_time - 12 && !jump)
777 /*if((update_time - last_update_time) < 10)
778 SDL_Delay((11 - (update_time - last_update_time))/2);*/
784 if (timer_check(&time_left))
786 /* are we low on time ? */
787 if ((timer_get_left(&time_left) < TIME_WARNING)
788 && (get_current_music() != HURRYUP_MUSIC)) /* play the fast music */
790 set_current_music(HURRYUP_MUSIC);
791 play_current_music();
799 /* Calculate frames per second */
803 fps_fps = (1000.0 / (float)timer_get_gone(&fps_timer)) * (float)fps_cnt;
805 if(!timer_check(&fps_timer))
807 timer_start(&fps_timer,1000);
813 while (!done && !quit);
818 level_free(¤t_level);
823 game_started = false;
829 /* Load graphics/sounds shared between all levels: */
831 void loadshared(void)
836 texture_load(&tux_right[0], datadir + "/images/shared/tux-right-0.png", USE_ALPHA);
837 texture_load(&tux_right[1], datadir + "/images/shared/tux-right-1.png", USE_ALPHA);
838 texture_load(&tux_right[2], datadir + "/images/shared/tux-right-2.png", USE_ALPHA);
840 texture_load(&tux_left[0], datadir + "/images/shared/tux-left-0.png", USE_ALPHA);
841 texture_load(&tux_left[1], datadir + "/images/shared/tux-left-1.png", USE_ALPHA);
842 texture_load(&tux_left[2], datadir + "/images/shared/tux-left-2.png", USE_ALPHA);
844 texture_load(&firetux_right[0], datadir + "/images/shared/firetux-right-0.png", USE_ALPHA);
845 texture_load(&firetux_right[1], datadir + "/images/shared/firetux-right-1.png", USE_ALPHA);
846 texture_load(&firetux_right[2], datadir + "/images/shared/firetux-right-2.png", USE_ALPHA);
848 texture_load(&firetux_left[0], datadir + "/images/shared/firetux-left-0.png", USE_ALPHA);
849 texture_load(&firetux_left[1], datadir + "/images/shared/firetux-left-1.png", USE_ALPHA);
850 texture_load(&firetux_left[2], datadir + "/images/shared/firetux-left-2.png", USE_ALPHA);
853 texture_load(&cape_right[0], datadir + "/images/shared/cape-right-0.png",
856 texture_load(&cape_right[1], datadir + "/images/shared/cape-right-1.png",
859 texture_load(&cape_left[0], datadir + "/images/shared/cape-left-0.png",
862 texture_load(&cape_left[1], datadir + "/images/shared/cape-left-1.png",
865 texture_load(&bigtux_right[0], datadir + "/images/shared/bigtux-right-0.png",
868 texture_load(&bigtux_right[1], datadir + "/images/shared/bigtux-right-1.png",
871 texture_load(&bigtux_right[2], datadir + "/images/shared/bigtux-right-2.png",
874 texture_load(&bigtux_right_jump, datadir + "/images/shared/bigtux-right-jump.png", USE_ALPHA);
876 texture_load(&bigtux_left[0], datadir + "/images/shared/bigtux-left-0.png",
879 texture_load(&bigtux_left[1], datadir + "/images/shared/bigtux-left-1.png",
882 texture_load(&bigtux_left[2], datadir + "/images/shared/bigtux-left-2.png",
885 texture_load(&bigtux_left_jump, datadir + "/images/shared/bigtux-left-jump.png", USE_ALPHA);
887 texture_load(&bigcape_right[0], datadir + "/images/shared/bigcape-right-0.png",
890 texture_load(&bigcape_right[1], datadir + "/images/shared/bigcape-right-1.png",
893 texture_load(&bigcape_left[0], datadir + "/images/shared/bigcape-left-0.png",
896 texture_load(&bigcape_left[1], datadir + "/images/shared/bigcape-left-1.png",
899 texture_load(&bigfiretux_right[0], datadir + "/images/shared/bigfiretux-right-0.png",
902 texture_load(&bigfiretux_right[1], datadir + "/images/shared/bigfiretux-right-1.png",
905 texture_load(&bigfiretux_right[2], datadir + "/images/shared/bigfiretux-right-2.png",
908 texture_load(&bigfiretux_right_jump, datadir + "/images/shared/bigfiretux-right-jump.png", USE_ALPHA);
910 texture_load(&bigfiretux_left[0], datadir + "/images/shared/bigfiretux-left-0.png",
913 texture_load(&bigfiretux_left[1], datadir + "/images/shared/bigfiretux-left-1.png",
916 texture_load(&bigfiretux_left[2], datadir + "/images/shared/bigfiretux-left-2.png",
919 texture_load(&bigfiretux_left_jump, datadir + "/images/shared/bigfiretux-left-jump.png", USE_ALPHA);
921 texture_load(&bigcape_right[0], datadir + "/images/shared/bigcape-right-0.png",
924 texture_load(&bigcape_right[1], datadir + "/images/shared/bigcape-right-1.png",
927 texture_load(&bigcape_left[0], datadir + "/images/shared/bigcape-left-0.png",
930 texture_load(&bigcape_left[1], datadir + "/images/shared/bigcape-left-1.png",
934 texture_load(&ducktux_right, datadir +
935 "/images/shared/ducktux-right.png",
938 texture_load(&ducktux_left, datadir +
939 "/images/shared/ducktux-left.png",
942 texture_load(&skidtux_right, datadir +
943 "/images/shared/skidtux-right.png",
946 texture_load(&skidtux_left, datadir +
947 "/images/shared/skidtux-left.png",
950 texture_load(&duckfiretux_right, datadir +
951 "/images/shared/duckfiretux-right.png",
954 texture_load(&duckfiretux_left, datadir +
955 "/images/shared/duckfiretux-left.png",
958 texture_load(&skidfiretux_right, datadir +
959 "/images/shared/skidfiretux-right.png",
962 texture_load(&skidfiretux_left, datadir +
963 "/images/shared/skidfiretux-left.png",
969 texture_load(&img_box_full, datadir + "/images/shared/box-full.png",
971 texture_load(&img_box_empty, datadir + "/images/shared/box-empty.png",
978 texture_load(&img_water, datadir + "/images/shared/water.png", IGNORE_ALPHA);
980 texture_load(&img_waves[0], datadir + "/images/shared/waves-0.png",
983 texture_load(&img_waves[1], datadir + "/images/shared/waves-1.png",
986 texture_load(&img_waves[2], datadir + "/images/shared/waves-2.png",
992 texture_load(&img_pole, datadir + "/images/shared/pole.png", USE_ALPHA);
993 texture_load(&img_poletop, datadir + "/images/shared/poletop.png",
999 texture_load(&img_flag[0], datadir + "/images/shared/flag-0.png",
1001 texture_load(&img_flag[1], datadir + "/images/shared/flag-1.png",
1007 texture_load(&img_cloud[0][0], datadir + "/images/shared/cloud-00.png",
1010 texture_load(&img_cloud[0][1], datadir + "/images/shared/cloud-01.png",
1013 texture_load(&img_cloud[0][2], datadir + "/images/shared/cloud-02.png",
1016 texture_load(&img_cloud[0][3], datadir + "/images/shared/cloud-03.png",
1020 texture_load(&img_cloud[1][0], datadir + "/images/shared/cloud-10.png",
1023 texture_load(&img_cloud[1][1], datadir + "/images/shared/cloud-11.png",
1026 texture_load(&img_cloud[1][2], datadir + "/images/shared/cloud-12.png",
1029 texture_load(&img_cloud[1][3], datadir + "/images/shared/cloud-13.png",
1037 texture_load(&img_bsod_left[0], datadir +
1038 "/images/shared/bsod-left-0.png",
1041 texture_load(&img_bsod_left[1], datadir +
1042 "/images/shared/bsod-left-1.png",
1045 texture_load(&img_bsod_left[2], datadir +
1046 "/images/shared/bsod-left-2.png",
1049 texture_load(&img_bsod_left[3], datadir +
1050 "/images/shared/bsod-left-3.png",
1053 texture_load(&img_bsod_right[0], datadir +
1054 "/images/shared/bsod-right-0.png",
1057 texture_load(&img_bsod_right[1], datadir +
1058 "/images/shared/bsod-right-1.png",
1061 texture_load(&img_bsod_right[2], datadir +
1062 "/images/shared/bsod-right-2.png",
1065 texture_load(&img_bsod_right[3], datadir +
1066 "/images/shared/bsod-right-3.png",
1069 texture_load(&img_bsod_squished_left, datadir +
1070 "/images/shared/bsod-squished-left.png",
1073 texture_load(&img_bsod_squished_right, datadir +
1074 "/images/shared/bsod-squished-right.png",
1077 texture_load(&img_bsod_falling_left, datadir +
1078 "/images/shared/bsod-falling-left.png",
1081 texture_load(&img_bsod_falling_right, datadir +
1082 "/images/shared/bsod-falling-right.png",
1088 texture_load(&img_laptop_left[0], datadir +
1089 "/images/shared/laptop-left-0.png",
1092 texture_load(&img_laptop_left[1], datadir +
1093 "/images/shared/laptop-left-1.png",
1096 texture_load(&img_laptop_left[2], datadir +
1097 "/images/shared/laptop-left-2.png",
1100 texture_load(&img_laptop_right[0], datadir +
1101 "/images/shared/laptop-right-0.png",
1104 texture_load(&img_laptop_right[1], datadir +
1105 "/images/shared/laptop-right-1.png",
1108 texture_load(&img_laptop_right[2], datadir +
1109 "/images/shared/laptop-right-2.png",
1112 texture_load(&img_laptop_flat_left, datadir +
1113 "/images/shared/laptop-flat-left.png",
1116 texture_load(&img_laptop_flat_right, datadir +
1117 "/images/shared/laptop-flat-right.png",
1120 texture_load(&img_laptop_falling_left, datadir +
1121 "/images/shared/laptop-falling-left.png",
1124 texture_load(&img_laptop_falling_right, datadir +
1125 "/images/shared/laptop-falling-right.png",
1131 texture_load(&img_money_left[0], datadir +
1132 "/images/shared/bag-left-0.png",
1135 texture_load(&img_money_left[1], datadir +
1136 "/images/shared/bag-left-1.png",
1139 texture_load(&img_money_right[0], datadir +
1140 "/images/shared/bag-right-0.png",
1143 texture_load(&img_money_right[1], datadir +
1144 "/images/shared/bag-right-1.png",
1148 for(int i=0; i<4; ++i) {
1150 snprintf(num, 4, "%d", i);
1151 texture_load(&img_mrbomb_left[i],
1152 datadir + "/images/shared/mrbomb-left-" + num + ".png", USE_ALPHA);
1153 texture_load(&img_mrbomb_right[i],
1154 datadir + "/images/shared/mrbomb-right-" + num + ".png", USE_ALPHA);
1158 texture_load(&img_stalactite,
1159 datadir + "/images/shared/stalactite.png", USE_ALPHA);
1160 texture_load(&img_stalactite_broken,
1161 datadir + "/images/shared/stalactite-broken.png", USE_ALPHA);
1165 texture_load(&img_mints, datadir + "/images/shared/mints.png", USE_ALPHA);
1166 texture_load(&img_coffee, datadir + "/images/shared/coffee.png", USE_ALPHA);
1171 texture_load(&img_bullet, datadir + "/images/shared/bullet.png", USE_ALPHA);
1173 texture_load(&img_red_glow, datadir + "/images/shared/red-glow.png",
1180 texture_load(&img_distro[0], datadir + "/images/shared/distro-0.png",
1183 texture_load(&img_distro[1], datadir + "/images/shared/distro-1.png",
1186 texture_load(&img_distro[2], datadir + "/images/shared/distro-2.png",
1189 texture_load(&img_distro[3], datadir + "/images/shared/distro-3.png",
1195 texture_load(&tux_life, datadir + "/images/shared/tux-life.png",
1200 texture_load(&img_golden_herring, datadir + "/images/shared/golden-herring.png",
1204 /* Super background: */
1206 texture_load(&img_super_bkgd, datadir + "/images/shared/super-bkgd.png",
1210 /* Sound effects: */
1212 /* if (use_sound) // this will introduce SERIOUS bugs here ! because "load_sound"
1213 // initialize sounds[i] with the correct pointer's value:
1214 // NULL or something else. And it will be dangerous to
1215 // play with not-initialized pointers.
1216 // This is also true with if (use_music)
1217 Send a mail to me: neoneurone@users.sf.net, if you have another opinion. :)
1219 for (i = 0; i < NUM_SOUNDS; i++)
1220 sounds[i] = load_sound(datadir + soundfilenames[i]);
1223 herring_song = load_song(datadir + "/music/SALCON.MOD");
1227 /* Free shared data: */
1229 void unloadshared(void)
1233 for (i = 0; i < 3; i++)
1235 texture_free(&tux_right[i]);
1236 texture_free(&tux_left[i]);
1237 texture_free(&bigtux_right[i]);
1238 texture_free(&bigtux_left[i]);
1241 texture_free(&bigtux_right_jump);
1242 texture_free(&bigtux_left_jump);
1244 for (i = 0; i < 2; i++)
1246 texture_free(&cape_right[i]);
1247 texture_free(&cape_left[i]);
1248 texture_free(&bigcape_right[i]);
1249 texture_free(&bigcape_left[i]);
1252 texture_free(&ducktux_left);
1253 texture_free(&ducktux_right);
1255 texture_free(&skidtux_left);
1256 texture_free(&skidtux_right);
1258 for (i = 0; i < 4; i++)
1260 texture_free(&img_bsod_left[i]);
1261 texture_free(&img_bsod_right[i]);
1264 texture_free(&img_bsod_squished_left);
1265 texture_free(&img_bsod_squished_right);
1267 texture_free(&img_bsod_falling_left);
1268 texture_free(&img_bsod_falling_right);
1270 for (i = 0; i < 3; i++)
1272 texture_free(&img_laptop_left[i]);
1273 texture_free(&img_laptop_right[i]);
1276 texture_free(&img_laptop_flat_left);
1277 texture_free(&img_laptop_flat_right);
1279 texture_free(&img_laptop_falling_left);
1280 texture_free(&img_laptop_falling_right);
1282 for (i = 0; i < 2; i++)
1284 texture_free(&img_money_left[i]);
1285 texture_free(&img_money_right[i]);
1288 for(i = 0; i < 4; i++) {
1289 texture_free(&img_mrbomb_left[i]);
1290 texture_free(&img_mrbomb_right[i]);
1293 texture_free(&img_stalactite);
1294 texture_free(&img_stalactite_broken);
1296 texture_free(&img_box_full);
1297 texture_free(&img_box_empty);
1299 texture_free(&img_water);
1300 for (i = 0; i < 3; i++)
1301 texture_free(&img_waves[i]);
1303 texture_free(&img_pole);
1304 texture_free(&img_poletop);
1306 for (i = 0; i < 2; i++)
1307 texture_free(&img_flag[i]);
1309 texture_free(&img_mints);
1310 texture_free(&img_coffee);
1312 for (i = 0; i < 4; i++)
1314 texture_free(&img_distro[i]);
1315 texture_free(&img_cloud[0][i]);
1316 texture_free(&img_cloud[1][i]);
1319 texture_free(&img_golden_herring);
1321 for (i = 0; i < NUM_SOUNDS; i++)
1322 free_chunk(sounds[i]);
1324 /* free the herring song */
1325 free_music( herring_song );
1329 /* Draw a tile on the screen: */
1331 void drawshape(float x, float y, unsigned int c)
1335 Tile* ptile = TileManager::instance()->get(c);
1338 if(ptile->images.size() > 1)
1340 texture_draw(&ptile->images[( ((global_frame_counter*25) / ptile->anim_speed) % (ptile->images.size()))],x,y);
1342 else if (ptile->images.size() == 1)
1344 texture_draw(&ptile->images[0],x,y);
1348 printf("Tile not dravable %u\n", c);
1354 if (c == 'X' || c == 'x')
1355 texture_draw(&img_brick[0], x, y);
1356 else if (c == 'Y' || c == 'y')
1357 texture_draw(&img_brick[1], x, y);
1358 else if (c == 'A' || c =='B' || c == '!')
1359 texture_draw(&img_box_full, x, y);
1361 texture_draw(&img_box_empty, x, y);
1362 else if (c >= 'C' && c <= 'F')
1363 texture_draw(&img_cloud[0][c - 'C'], x, y);
1364 else if (c >= 'c' && c <= 'f')
1365 texture_draw(&img_cloud[1][c - 'c'], x, y);
1366 else if (c >= 'G' && c <= 'J')
1367 texture_draw(&img_bkgd_tile[0][c - 'G'], x, y);
1368 else if (c >= 'g' && c <= 'j')
1369 texture_draw(&img_bkgd_tile[1][c - 'g'], x, y);
1371 texture_draw(&img_solid[0], x, y);
1373 texture_draw(&img_solid[1], x, y);
1375 texture_draw(&img_solid[2], x, y);
1377 texture_draw(&img_solid[3], x, y);
1380 z = (global_frame_counter / 2) % 6;
1383 texture_draw(&img_distro[z], x, y);
1385 texture_draw(&img_distro[2], x, y);
1387 texture_draw(&img_distro[1], x, y);
1391 z = (global_frame_counter / 3) % 3;
1393 texture_draw(&img_waves[z], x, y);
1396 texture_draw(&img_poletop, x, y);
1399 texture_draw(&img_pole, x, y);
1404 z = (global_frame_counter / 3) % 2;
1406 texture_draw(&img_flag[z], x + 16, y);
1409 texture_draw(&img_water, x, y);*/
1414 /* What shape is at some position? */
1415 unsigned int shape(float x, float y)
1424 if (yy >= 0 && yy < 15 && xx >= 0 && xx <= current_level.width)
1426 c = current_level.ia_tiles[yy][xx];
1434 Tile* gettile(float x, float y)
1436 return TileManager::instance()->get(shape(x, y));
1439 bool issolid(float x, float y)
1441 Tile* tile = TileManager::instance()->get
1445 if(tile->solid == true)
1456 /* Is it a brick? */
1458 bool isbrick(float x, float y)
1460 Tile* tile = TileManager::instance()->get
1464 if(tile->brick == true)
1478 bool isice(float x, float y)
1480 Tile* tile = TileManager::instance()->get
1484 if(tile->ice == true)
1495 /* Is it a full box? */
1497 bool isfullbox(float x, float y)
1499 Tile* tile = TileManager::instance()->get
1503 if(tile->fullbox == true)
1514 bool isdistro(float x, float y)
1516 Tile* tile = TileManager::instance()->get(shape(x,y));
1517 return tile && tile->distro;
1520 /* Break a brick: */
1522 void trybreakbrick(float x, float y)
1524 Tile* tile = gettile(x, y);
1529 /* Get a distro from it: */
1530 add_bouncy_distro(((int)(x + 1) / 32) * 32,
1531 (int)(y / 32) * 32);
1533 if (!counting_distros)
1535 counting_distros = true;
1536 distro_counter = 50;
1539 if (distro_counter <= 0)
1540 level_change(¤t_level,x, y, TM_IA, tile->next_tile2);
1542 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1543 score = score + SCORE_DISTRO;
1548 /* Get rid of it: */
1549 level_change(¤t_level,x, y, TM_IA, tile->next_tile);
1553 /* Replace it with broken bits: */
1555 add_broken_brick(((int)(x + 1) / 32) * 32,
1556 (int)(y / 32) * 32);
1559 /* Get some score: */
1561 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
1562 score = score + SCORE_BRICK;
1567 /* Bounce a brick: */
1569 void bumpbrick(float x, float y)
1571 add_bouncy_brick(((int)(x + 1) / 32) * 32,
1572 (int)(y / 32) * 32);
1574 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
1580 void tryemptybox(float x, float y, int col_side)
1582 Tile* tile = gettile(x,y);
1586 // according to the collision side, set the upgrade direction
1587 if(col_side == LEFT)
1594 case 1: //'A': /* Box with a distro! */
1595 add_bouncy_distro(((int)(x + 1) / 32) * 32, (int)(y / 32) * 32 - 32);
1596 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1597 score = score + SCORE_DISTRO;
1601 case 2: // 'B': /* Add an upgrade! */
1602 if (tux.size == SMALL) /* Tux is small, add mints! */
1603 add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_MINTS);
1604 else /* Tux is big, add coffee: */
1605 add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_COFFEE);
1606 play_sound(sounds[SND_UPGRADE], SOUND_CENTER_SPEAKER);
1609 case 3:// '!': /* Add a golden herring */
1610 add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_HERRING);
1616 /* Empty the box: */
1617 level_change(¤t_level,x, y, TM_IA, tile->next_tile);
1620 /* Try to grab a distro: */
1621 void trygrabdistro(float x, float y, int bounciness)
1623 Tile* tile = gettile(x, y);
1624 if (tile && tile->distro)
1626 level_change(¤t_level,x, y, TM_IA, tile->next_tile);
1627 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1629 if (bounciness == BOUNCE)
1631 add_bouncy_distro(((int)(x + 1) / 32) * 32,
1632 (int)(y / 32) * 32);
1635 score = score + SCORE_DISTRO;
1640 /* Try to bump a bad guy from below: */
1641 void trybumpbadguy(float x, float y)
1644 for (unsigned int i = 0; i < bad_guys.size(); i++)
1646 if (bad_guys[i].base.x >= x - 32 && bad_guys[i].base.x <= x + 32 &&
1647 bad_guys[i].base.y >= y - 16 && bad_guys[i].base.y <= y + 16)
1649 bad_guys[i].collision(&tux, CO_PLAYER, COLLISION_BUMP);
1655 for (unsigned int i = 0; i < upgrades.size(); i++)
1657 if (upgrades[i].base.height == 32 &&
1658 upgrades[i].base.x >= x - 32 && upgrades[i].base.x <= x + 32 &&
1659 upgrades[i].base.y >= y - 16 && upgrades[i].base.y <= y + 16)
1661 upgrades[i].base.xm = -upgrades[i].base.xm;
1662 upgrades[i].base.ym = -8;
1663 play_sound(sounds[SND_BUMP_UPGRADE], SOUND_CENTER_SPEAKER);
1669 void drawstatus(void)
1673 sprintf(str, "%d", score);
1674 text_draw(&white_text, "SCORE", 0, 0, 1);
1675 text_draw(&gold_text, str, 96, 0, 1);
1677 if(st_gl_mode != ST_GL_TEST)
1679 sprintf(str, "%d", hs_score);
1680 text_draw(&white_text, "HIGH", 0, 20, 1);
1681 text_draw(&gold_text, str, 96, 20, 1);
1685 text_draw(&white_text,"Press ESC To Return",0,20,1);
1688 if (timer_get_left(&time_left) > TIME_WARNING || (global_frame_counter % 10) < 5)
1690 sprintf(str, "%d", timer_get_left(&time_left) / 1000 );
1691 text_draw(&white_text, "TIME", 224, 0, 1);
1692 text_draw(&gold_text, str, 304, 0, 1);
1695 sprintf(str, "%d", distros);
1696 text_draw(&white_text, "DISTROS", screen->h, 0, 1);
1697 text_draw(&gold_text, str, 608, 0, 1);
1699 text_draw(&white_text, "LIVES", screen->h, 20, 1);
1703 sprintf(str, "%2.1f", fps_fps);
1704 text_draw(&white_text, "FPS", screen->h, 40, 1);
1705 text_draw(&gold_text, str, screen->h + 60, 40, 1);
1708 for(int i=0; i < tux.lives; ++i)
1710 texture_draw(&tux_life,565+(18*i),20);
1715 void drawendscreen(void)
1719 clearscreen(0, 0, 0);
1721 text_drawf(&blue_text, "GAMEOVER", 0, 200, A_HMIDDLE, A_TOP, 1);
1723 sprintf(str, "SCORE: %d", score);
1724 text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1);
1726 sprintf(str, "DISTROS: %d", distros);
1727 text_drawf(&gold_text, str, 0, 256, A_HMIDDLE, A_TOP, 1);
1733 void drawresultscreen(void)
1737 clearscreen(0, 0, 0);
1739 text_drawf(&blue_text, "Result:", 0, 200, A_HMIDDLE, A_TOP, 1);
1741 sprintf(str, "SCORE: %d", score);
1742 text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1);
1744 sprintf(str, "DISTROS: %d", distros);
1745 text_drawf(&gold_text, str, 0, 256, A_HMIDDLE, A_TOP, 1);
1751 void savegame(int slot)
1753 char savefile[1024];
1757 sprintf(savefile,"%s/slot%d.save",st_save_dir,slot);
1759 fi = fopen(savefile, "wb");
1763 fprintf(stderr, "Warning: I could not open the slot file ");
1767 fputs(level_subset, fi);
1769 fwrite(&level,sizeof(int),1,fi);
1770 fwrite(&score,sizeof(int),1,fi);
1771 fwrite(&distros,sizeof(int),1,fi);
1772 fwrite(&scroll_x,sizeof(float),1,fi);
1773 fwrite(&tux,sizeof(Player),1,fi);
1774 timer_fwrite(&tux.invincible_timer,fi);
1775 timer_fwrite(&tux.skidding_timer,fi);
1776 timer_fwrite(&tux.safe_timer,fi);
1777 timer_fwrite(&tux.frame_timer,fi);
1778 timer_fwrite(&time_left,fi);
1779 ui = st_get_ticks();
1780 fwrite(&ui,sizeof(int),1,fi);
1786 void loadgame(int slot)
1788 char savefile[1024];
1793 sprintf(savefile,"%s/slot%d.save",st_save_dir,slot);
1795 fi = fopen(savefile, "rb");
1799 fprintf(stderr, "Warning: I could not open the slot file ");
1804 fgets(str, 100, fi);
1805 strcpy(level_subset, str);
1806 level_subset[strlen(level_subset)-1] = '\0';
1807 fread(&level,sizeof(int),1,fi);
1810 level_free(¤t_level);
1811 if(level_load(¤t_level,level_subset,level) != 0)
1815 activate_bad_guys();
1816 activate_particle_systems();
1818 level_load_gfx(¤t_level);
1820 level_load_song(¤t_level);
1822 update_time = st_get_ticks();
1824 fread(&score,sizeof(int),1,fi);
1825 fread(&distros,sizeof(int),1,fi);
1826 fread(&scroll_x,sizeof(float),1,fi);
1827 fread(&tux, sizeof(Player), 1, fi);
1828 timer_fread(&tux.invincible_timer,fi);
1829 timer_fread(&tux.skidding_timer,fi);
1830 timer_fread(&tux.safe_timer,fi);
1831 timer_fread(&tux.frame_timer,fi);
1832 timer_fread(&time_left,fi);
1833 fread(&ui,sizeof(int),1,fi);
1834 tux.hphysic.start_time += st_get_ticks() - ui;
1835 tux.vphysic.start_time += st_get_ticks() - ui;
1841 void slotinfo(char **pinfo, int slot)
1844 char slotfile[1024];
1848 sprintf(slotfile,"%s/slot%d.save",st_save_dir,slot);
1850 fi = fopen(slotfile, "rb");
1852 sprintf(tmp,"Slot %d - ",slot);
1860 fgets(str, 100, fi);
1861 str[strlen(str)-1] = '\0';
1863 strcat(tmp, " / Level:");
1864 fread(&slot_level,sizeof(int),1,fi);
1865 sprintf(str,"%d",slot_level);
1870 *pinfo = (char*) malloc(sizeof(char) * (strlen(tmp)+1));