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 printf("PSys: %s\n", current_level.particle_system.c_str());
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))
136 case SDL_QUIT: /* Quit event - quit: */
139 case SDL_KEYDOWN: /* A keypress! */
140 key = event.key.keysym.sym;
142 /* Check for menu-events, if the menu is shown */
144 menu_event(&event.key.keysym);
146 if(tux.key_event(key,DOWN))
151 case SDLK_ESCAPE: /* Escape: Open/Close the menu: */
154 if(st_gl_mode == ST_GL_TEST)
158 Menu::set_current(game_menu);
160 st_pause_ticks_stop();
164 Menu::set_current(game_menu);
166 st_pause_ticks_start();
174 case SDL_KEYUP: /* A keyrelease! */
175 key = event.key.keysym.sym;
177 if(tux.key_event(key, UP))
188 st_pause_ticks_stop();
193 st_pause_ticks_start();
200 tux.size = !tux.size;
203 tux.base.height = 64;
206 tux.base.height = 32;
223 timer_start(&tux.invincible_timer,TUX_INVINCIBLE_TIME);
243 case SDL_JOYAXISMOTION:
244 switch(event.jaxis.axis)
247 if (event.jaxis.value < -JOYSTICK_DEAD_ZONE)
249 tux.input.left = DOWN;
250 tux.input.right = UP;
252 else if (event.jaxis.value > JOYSTICK_DEAD_ZONE)
255 tux.input.right = DOWN;
259 tux.input.left = DOWN;
260 tux.input.right = DOWN;
264 if (event.jaxis.value > JOYSTICK_DEAD_ZONE)
265 tux.input.down = DOWN;
266 else if (event.jaxis.value < -JOYSTICK_DEAD_ZONE)
271 /* Handle joystick for the menu */
274 if(tux.input.down == DOWN)
275 menuaction = MENU_ACTION_DOWN;
277 menuaction = MENU_ACTION_UP;
284 case SDL_JOYBUTTONDOWN:
285 if (event.jbutton.button == JOY_A)
287 else if (event.jbutton.button == JOY_B)
288 tux.input.fire = DOWN;
290 case SDL_JOYBUTTONUP:
291 if (event.jbutton.button == JOY_A)
293 else if (event.jbutton.button == JOY_B)
297 menuaction = MENU_ACTION_HIT;
308 /* --- GAME ACTION! --- */
310 int game_action(void)
314 /* (tux_dying || next_level) */
315 if (tux.dying || next_level)
317 /* Tux either died, or reached the end of a level! */
324 /* End of a level! */
327 if(st_gl_mode != ST_GL_TEST)
334 level_free(¤t_level);
346 /* No more lives!? */
350 if(st_gl_mode != ST_GL_TEST)
353 if(st_gl_mode != ST_GL_TEST)
355 if (score > hs_score)
359 level_free(¤t_level);
364 } /* if (lives < 0) */
367 /* Either way, (re-)load the (next) level... */
371 level_free(¤t_level);
373 if (st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
375 if(level_load(¤t_level, level_subset) != 0)
380 if(level_load(¤t_level,level_subset,level) != 0)
387 activate_particle_systems();
389 level_load_gfx(¤t_level);
391 level_load_song(¤t_level);
392 if(st_gl_mode != ST_GL_TEST)
396 play_current_music();
401 /* Handle bouncy distros: */
402 for (i = 0; i < bouncy_distros.size(); i++)
404 bouncy_distro_action(&bouncy_distros[i]);
408 /* Handle broken bricks: */
409 for (i = 0; i < broken_bricks.size(); i++)
411 broken_brick_action(&broken_bricks[i]);
415 /* Handle distro counting: */
417 if (counting_distros)
421 if (distro_counter <= 0)
422 counting_distros = -1;
426 /* Handle bouncy bricks: */
428 for (i = 0; i < bouncy_bricks.size(); i++)
430 bouncy_brick_action(&bouncy_bricks[i]);
434 /* Handle floating scores: */
436 for (i = 0; i < floating_scores.size(); i++)
438 floating_score_action(&floating_scores[i]);
442 /* Handle bullets: */
444 for (i = 0; i < bullets.size(); ++i)
446 bullet_action(&bullets[i]);
449 /* Handle upgrades: */
451 for (i = 0; i < upgrades.size(); i++)
453 upgrade_action(&upgrades[i]);
457 /* Handle bad guys: */
459 for (i = 0; i < bad_guys.size(); i++)
461 bad_guys[i].action();
464 /* update particle systems */
465 std::vector<ParticleSystem*>::iterator p;
466 for(p = particle_systems.begin(); p != particle_systems.end(); ++p)
468 (*p)->simulate(frame_ratio);
471 /* Handle all possible collisions. */
477 /* --- GAME DRAW! --- */
484 if (tux.dying && (global_frame_counter % 4) == 0)
485 clearscreen(255, 255, 255);
486 else if(timer_check(&super_bkgd_timer))
487 texture_draw(&img_super_bkgd, 0, 0);
490 /* Draw the real background */
491 if(current_level.bkgd_image[0] != '\0')
493 int s = (int)scroll_x / 30;
494 texture_draw_part(&img_bkgd,s,0,0,0,img_bkgd.w - s, img_bkgd.h);
495 texture_draw_part(&img_bkgd,0,0,screen->w - s ,0,s,img_bkgd.h);
499 clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue);
503 /* Draw particle systems (background) */
504 std::vector<ParticleSystem*>::iterator p;
505 for(p = particle_systems.begin(); p != particle_systems.end(); ++p)
507 (*p)->draw(scroll_x, 0, 0);
510 /* Draw background: */
512 for (y = 0; y < 15; ++y)
514 for (x = 0; x < 21; ++x)
516 drawshape(32*x - fmodf(scroll_x, 32), y * 32,
517 current_level.bg_tiles[(int)y][(int)x + (int)(scroll_x / 32)]);
521 /* Draw interactive tiles: */
523 for (y = 0; y < 15; ++y)
525 for (x = 0; x < 21; ++x)
527 drawshape(32*x - fmodf(scroll_x, 32), y * 32,
528 current_level.ia_tiles[(int)y][(int)x + (int)(scroll_x / 32)]);
532 /* (Bouncy bricks): */
534 for (unsigned int i = 0; i < bouncy_bricks.size(); ++i)
535 bouncy_brick_draw(&bouncy_bricks[i]);
537 for (unsigned int i = 0; i < bad_guys.size(); ++i)
542 for (unsigned int i = 0; i < bullets.size(); ++i)
543 bullet_draw(&bullets[i]);
545 for (unsigned int i = 0; i < floating_scores.size(); ++i)
546 floating_score_draw(&floating_scores[i]);
548 for (unsigned int i = 0; i < upgrades.size(); ++i)
549 upgrade_draw(&upgrades[i]);
551 for (unsigned int i = 0; i < bouncy_distros.size(); ++i)
552 bouncy_distro_draw(&bouncy_distros[i]);
554 for (unsigned int i = 0; i < broken_bricks.size(); ++i)
555 broken_brick_draw(&broken_bricks[i]);
557 /* Draw foreground: */
559 for (y = 0; y < 15; ++y)
561 for (x = 0; x < 21; ++x)
563 drawshape(32*x - fmodf(scroll_x, 32), y * 32,
564 current_level.fg_tiles[(int)y][(int)x + (int)(scroll_x / 32)]);
568 /* Draw particle systems (foreground) */
569 for(p = particle_systems.begin(); p != particle_systems.end(); ++p)
571 (*p)->draw(scroll_x, 0, 1);
578 int x = screen->h / 20;
579 for(int i = 0; i < x; ++i)
581 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);
583 fillrect(0,0,screen->w,screen->h,rand() % 50, rand() % 50, rand() % 50, 128);
584 text_drawf(&blue_text, "PAUSE - Press 'P' To Play", 0, 230, A_HMIDDLE, A_TOP, 1);
588 menu_process_current();
590 /* (Update it all!) */
594 /* --- GAME LOOP! --- */
596 int gameloop(const char * subset, int levelnb, int mode)
598 int fps_cnt, jump, done;
599 timer_type fps_timer, frame_timer;
600 timer_init(&fps_timer, true);
601 timer_init(&frame_timer, true);
612 strcpy(level_subset,subset);
614 if (st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
616 if (level_load(¤t_level, level_subset))
621 if(level_load(¤t_level, level_subset, level) != 0)
625 level_load_gfx(¤t_level);
627 activate_particle_systems();
628 level_load_song(¤t_level);
632 if(st_gl_mode != ST_GL_TEST)
637 if(st_gl_mode == ST_GL_PLAY || st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
640 timer_init(&time_left,true);
643 if(st_gl_mode == ST_GL_LOAD_GAME)
646 /* --- MAIN GAME LOOP!!! --- */
651 global_frame_counter = 0;
653 timer_init(&fps_timer,true);
654 timer_init(&frame_timer,true);
659 clearscreen(0, 0, 0);
663 play_current_music();
666 while (SDL_PollEvent(&event))
674 /* Calculate the movement-factor */
675 frame_ratio = ((double)(update_time-last_update_time))/((double)FRAME_RATE);
676 if(frame_ratio > 1.5) /* Quick hack to correct the unprecise CPU clocks a little bit. */
677 frame_ratio = 1.5 + (frame_ratio - 1.5) * 0.85;
679 if(!timer_check(&frame_timer))
681 timer_start(&frame_timer,25);
682 ++global_frame_counter;
687 tux.input.old_fire = tux.input.fire;
693 if(current_menu == game_menu)
695 switch (game_menu->check())
698 st_pause_ticks_stop();
701 update_load_save_game_menu(save_game_menu, false);
704 update_load_save_game_menu(load_game_menu, true);
707 st_pause_ticks_stop();
712 else if(current_menu == options_menu)
714 process_options_menu();
716 else if(current_menu == save_game_menu )
718 process_save_load_game_menu(true);
720 else if(current_menu == load_game_menu )
722 process_save_load_game_menu(false);
727 /* Handle actions: */
729 if(!game_pause && !show_menu)
731 /*float z = frame_ratio;
735 if (game_action() == 0)
737 /* == 0: no more lives */
738 /* == -1: continues */
750 if(debug_mode && debug_fps)
753 /*Draw the current scene to the screen */
754 /*If the machine running the game is too slow
755 skip the drawing of the frame (so the calculations are more precise and
756 the FPS aren't affected).*/
757 /*if( ! fps_fps < 50.0 )
760 jump = true;*/ /*FIXME: Implement this tweak right.*/
763 /* Time stops in pause mode */
764 if(game_pause || show_menu )
769 /* Set the time of the last update and the time of the current update */
770 last_update_time = update_time;
771 update_time = st_get_ticks();
773 /* Pause till next frame, if the machine running the game is too fast: */
774 /* FIXME: Works great for in OpenGl mode, where the CPU doesn't have to do that much. But
775 the results in SDL mode aren't perfect (thought the 100 FPS are reached), even on an AMD2500+. */
776 if(last_update_time >= update_time - 12 && !jump)
778 /*if((update_time - last_update_time) < 10)
779 SDL_Delay((11 - (update_time - last_update_time))/2);*/
785 if (timer_check(&time_left))
787 /* are we low on time ? */
788 if ((timer_get_left(&time_left) < TIME_WARNING)
789 && (get_current_music() != HURRYUP_MUSIC)) /* play the fast music */
791 set_current_music(HURRYUP_MUSIC);
792 play_current_music();
800 /* Calculate frames per second */
804 fps_fps = (1000.0 / (float)timer_get_gone(&fps_timer)) * (float)fps_cnt;
806 if(!timer_check(&fps_timer))
808 timer_start(&fps_timer,1000);
814 while (!done && !quit);
819 level_free(¤t_level);
824 game_started = false;
830 /* Load graphics/sounds shared between all levels: */
832 void loadshared(void)
837 texture_load(&tux_right[0], datadir + "/images/shared/tux-right-0.png", USE_ALPHA);
838 texture_load(&tux_right[1], datadir + "/images/shared/tux-right-1.png", USE_ALPHA);
839 texture_load(&tux_right[2], datadir + "/images/shared/tux-right-2.png", USE_ALPHA);
841 texture_load(&tux_left[0], datadir + "/images/shared/tux-left-0.png", USE_ALPHA);
842 texture_load(&tux_left[1], datadir + "/images/shared/tux-left-1.png", USE_ALPHA);
843 texture_load(&tux_left[2], datadir + "/images/shared/tux-left-2.png", USE_ALPHA);
845 texture_load(&firetux_right[0], datadir + "/images/shared/firetux-right-0.png", USE_ALPHA);
846 texture_load(&firetux_right[1], datadir + "/images/shared/firetux-right-1.png", USE_ALPHA);
847 texture_load(&firetux_right[2], datadir + "/images/shared/firetux-right-2.png", USE_ALPHA);
849 texture_load(&firetux_left[0], datadir + "/images/shared/firetux-left-0.png", USE_ALPHA);
850 texture_load(&firetux_left[1], datadir + "/images/shared/firetux-left-1.png", USE_ALPHA);
851 texture_load(&firetux_left[2], datadir + "/images/shared/firetux-left-2.png", USE_ALPHA);
854 texture_load(&cape_right[0], datadir + "/images/shared/cape-right-0.png",
857 texture_load(&cape_right[1], datadir + "/images/shared/cape-right-1.png",
860 texture_load(&cape_left[0], datadir + "/images/shared/cape-left-0.png",
863 texture_load(&cape_left[1], datadir + "/images/shared/cape-left-1.png",
866 texture_load(&bigtux_right[0], datadir + "/images/shared/bigtux-right-0.png",
869 texture_load(&bigtux_right[1], datadir + "/images/shared/bigtux-right-1.png",
872 texture_load(&bigtux_right[2], datadir + "/images/shared/bigtux-right-2.png",
875 texture_load(&bigtux_right_jump, datadir + "/images/shared/bigtux-right-jump.png", USE_ALPHA);
877 texture_load(&bigtux_left[0], datadir + "/images/shared/bigtux-left-0.png",
880 texture_load(&bigtux_left[1], datadir + "/images/shared/bigtux-left-1.png",
883 texture_load(&bigtux_left[2], datadir + "/images/shared/bigtux-left-2.png",
886 texture_load(&bigtux_left_jump, datadir + "/images/shared/bigtux-left-jump.png", USE_ALPHA);
888 texture_load(&bigcape_right[0], datadir + "/images/shared/bigcape-right-0.png",
891 texture_load(&bigcape_right[1], datadir + "/images/shared/bigcape-right-1.png",
894 texture_load(&bigcape_left[0], datadir + "/images/shared/bigcape-left-0.png",
897 texture_load(&bigcape_left[1], datadir + "/images/shared/bigcape-left-1.png",
900 texture_load(&bigfiretux_right[0], datadir + "/images/shared/bigfiretux-right-0.png",
903 texture_load(&bigfiretux_right[1], datadir + "/images/shared/bigfiretux-right-1.png",
906 texture_load(&bigfiretux_right[2], datadir + "/images/shared/bigfiretux-right-2.png",
909 texture_load(&bigfiretux_right_jump, datadir + "/images/shared/bigfiretux-right-jump.png", USE_ALPHA);
911 texture_load(&bigfiretux_left[0], datadir + "/images/shared/bigfiretux-left-0.png",
914 texture_load(&bigfiretux_left[1], datadir + "/images/shared/bigfiretux-left-1.png",
917 texture_load(&bigfiretux_left[2], datadir + "/images/shared/bigfiretux-left-2.png",
920 texture_load(&bigfiretux_left_jump, datadir + "/images/shared/bigfiretux-left-jump.png", USE_ALPHA);
922 texture_load(&bigcape_right[0], datadir + "/images/shared/bigcape-right-0.png",
925 texture_load(&bigcape_right[1], datadir + "/images/shared/bigcape-right-1.png",
928 texture_load(&bigcape_left[0], datadir + "/images/shared/bigcape-left-0.png",
931 texture_load(&bigcape_left[1], datadir + "/images/shared/bigcape-left-1.png",
935 texture_load(&ducktux_right, datadir +
936 "/images/shared/ducktux-right.png",
939 texture_load(&ducktux_left, datadir +
940 "/images/shared/ducktux-left.png",
943 texture_load(&skidtux_right, datadir +
944 "/images/shared/skidtux-right.png",
947 texture_load(&skidtux_left, datadir +
948 "/images/shared/skidtux-left.png",
951 texture_load(&duckfiretux_right, datadir +
952 "/images/shared/duckfiretux-right.png",
955 texture_load(&duckfiretux_left, datadir +
956 "/images/shared/duckfiretux-left.png",
959 texture_load(&skidfiretux_right, datadir +
960 "/images/shared/skidfiretux-right.png",
963 texture_load(&skidfiretux_left, datadir +
964 "/images/shared/skidfiretux-left.png",
970 texture_load(&img_box_full, datadir + "/images/shared/box-full.png",
972 texture_load(&img_box_empty, datadir + "/images/shared/box-empty.png",
979 texture_load(&img_water, datadir + "/images/shared/water.png", IGNORE_ALPHA);
981 texture_load(&img_waves[0], datadir + "/images/shared/waves-0.png",
984 texture_load(&img_waves[1], datadir + "/images/shared/waves-1.png",
987 texture_load(&img_waves[2], datadir + "/images/shared/waves-2.png",
993 texture_load(&img_pole, datadir + "/images/shared/pole.png", USE_ALPHA);
994 texture_load(&img_poletop, datadir + "/images/shared/poletop.png",
1000 texture_load(&img_flag[0], datadir + "/images/shared/flag-0.png",
1002 texture_load(&img_flag[1], datadir + "/images/shared/flag-1.png",
1008 texture_load(&img_cloud[0][0], datadir + "/images/shared/cloud-00.png",
1011 texture_load(&img_cloud[0][1], datadir + "/images/shared/cloud-01.png",
1014 texture_load(&img_cloud[0][2], datadir + "/images/shared/cloud-02.png",
1017 texture_load(&img_cloud[0][3], datadir + "/images/shared/cloud-03.png",
1021 texture_load(&img_cloud[1][0], datadir + "/images/shared/cloud-10.png",
1024 texture_load(&img_cloud[1][1], datadir + "/images/shared/cloud-11.png",
1027 texture_load(&img_cloud[1][2], datadir + "/images/shared/cloud-12.png",
1030 texture_load(&img_cloud[1][3], datadir + "/images/shared/cloud-13.png",
1038 texture_load(&img_bsod_left[0], datadir +
1039 "/images/shared/bsod-left-0.png",
1042 texture_load(&img_bsod_left[1], datadir +
1043 "/images/shared/bsod-left-1.png",
1046 texture_load(&img_bsod_left[2], datadir +
1047 "/images/shared/bsod-left-2.png",
1050 texture_load(&img_bsod_left[3], datadir +
1051 "/images/shared/bsod-left-3.png",
1054 texture_load(&img_bsod_right[0], datadir +
1055 "/images/shared/bsod-right-0.png",
1058 texture_load(&img_bsod_right[1], datadir +
1059 "/images/shared/bsod-right-1.png",
1062 texture_load(&img_bsod_right[2], datadir +
1063 "/images/shared/bsod-right-2.png",
1066 texture_load(&img_bsod_right[3], datadir +
1067 "/images/shared/bsod-right-3.png",
1070 texture_load(&img_bsod_squished_left, datadir +
1071 "/images/shared/bsod-squished-left.png",
1074 texture_load(&img_bsod_squished_right, datadir +
1075 "/images/shared/bsod-squished-right.png",
1078 texture_load(&img_bsod_falling_left, datadir +
1079 "/images/shared/bsod-falling-left.png",
1082 texture_load(&img_bsod_falling_right, datadir +
1083 "/images/shared/bsod-falling-right.png",
1089 texture_load(&img_laptop_left[0], datadir +
1090 "/images/shared/laptop-left-0.png",
1093 texture_load(&img_laptop_left[1], datadir +
1094 "/images/shared/laptop-left-1.png",
1097 texture_load(&img_laptop_left[2], datadir +
1098 "/images/shared/laptop-left-2.png",
1101 texture_load(&img_laptop_right[0], datadir +
1102 "/images/shared/laptop-right-0.png",
1105 texture_load(&img_laptop_right[1], datadir +
1106 "/images/shared/laptop-right-1.png",
1109 texture_load(&img_laptop_right[2], datadir +
1110 "/images/shared/laptop-right-2.png",
1113 texture_load(&img_laptop_flat_left, datadir +
1114 "/images/shared/laptop-flat-left.png",
1117 texture_load(&img_laptop_flat_right, datadir +
1118 "/images/shared/laptop-flat-right.png",
1121 texture_load(&img_laptop_falling_left, datadir +
1122 "/images/shared/laptop-falling-left.png",
1125 texture_load(&img_laptop_falling_right, datadir +
1126 "/images/shared/laptop-falling-right.png",
1132 texture_load(&img_money_left[0], datadir +
1133 "/images/shared/bag-left-0.png",
1136 texture_load(&img_money_left[1], datadir +
1137 "/images/shared/bag-left-1.png",
1140 texture_load(&img_money_right[0], datadir +
1141 "/images/shared/bag-right-0.png",
1144 texture_load(&img_money_right[1], datadir +
1145 "/images/shared/bag-right-1.png",
1152 texture_load(&img_mints, datadir + "/images/shared/mints.png", USE_ALPHA);
1153 texture_load(&img_coffee, datadir + "/images/shared/coffee.png", USE_ALPHA);
1158 texture_load(&img_bullet, datadir + "/images/shared/bullet.png", USE_ALPHA);
1160 texture_load(&img_red_glow, datadir + "/images/shared/red-glow.png",
1167 texture_load(&img_distro[0], datadir + "/images/shared/distro-0.png",
1170 texture_load(&img_distro[1], datadir + "/images/shared/distro-1.png",
1173 texture_load(&img_distro[2], datadir + "/images/shared/distro-2.png",
1176 texture_load(&img_distro[3], datadir + "/images/shared/distro-3.png",
1182 texture_load(&tux_life, datadir + "/images/shared/tux-life.png",
1187 texture_load(&img_golden_herring, datadir + "/images/shared/golden-herring.png",
1191 /* Super background: */
1193 texture_load(&img_super_bkgd, datadir + "/images/shared/super-bkgd.png",
1197 /* Sound effects: */
1199 /* if (use_sound) // this will introduce SERIOUS bugs here ! because "load_sound"
1200 // initialize sounds[i] with the correct pointer's value:
1201 // NULL or something else. And it will be dangerous to
1202 // play with not-initialized pointers.
1203 // This is also true with if (use_music)
1204 Send a mail to me: neoneurone@users.sf.net, if you have another opinion. :)
1206 for (i = 0; i < NUM_SOUNDS; i++)
1207 sounds[i] = load_sound(datadir + soundfilenames[i]);
1210 herring_song = load_song(datadir + "/music/SALCON.MOD");
1214 /* Free shared data: */
1216 void unloadshared(void)
1220 for (i = 0; i < 3; i++)
1222 texture_free(&tux_right[i]);
1223 texture_free(&tux_left[i]);
1224 texture_free(&bigtux_right[i]);
1225 texture_free(&bigtux_left[i]);
1228 texture_free(&bigtux_right_jump);
1229 texture_free(&bigtux_left_jump);
1231 for (i = 0; i < 2; i++)
1233 texture_free(&cape_right[i]);
1234 texture_free(&cape_left[i]);
1235 texture_free(&bigcape_right[i]);
1236 texture_free(&bigcape_left[i]);
1239 texture_free(&ducktux_left);
1240 texture_free(&ducktux_right);
1242 texture_free(&skidtux_left);
1243 texture_free(&skidtux_right);
1245 for (i = 0; i < 4; i++)
1247 texture_free(&img_bsod_left[i]);
1248 texture_free(&img_bsod_right[i]);
1251 texture_free(&img_bsod_squished_left);
1252 texture_free(&img_bsod_squished_right);
1254 texture_free(&img_bsod_falling_left);
1255 texture_free(&img_bsod_falling_right);
1257 for (i = 0; i < 3; i++)
1259 texture_free(&img_laptop_left[i]);
1260 texture_free(&img_laptop_right[i]);
1263 texture_free(&img_laptop_flat_left);
1264 texture_free(&img_laptop_flat_right);
1266 texture_free(&img_laptop_falling_left);
1267 texture_free(&img_laptop_falling_right);
1269 for (i = 0; i < 2; i++)
1271 texture_free(&img_money_left[i]);
1272 texture_free(&img_money_right[i]);
1275 texture_free(&img_box_full);
1276 texture_free(&img_box_empty);
1278 texture_free(&img_water);
1279 for (i = 0; i < 3; i++)
1280 texture_free(&img_waves[i]);
1282 texture_free(&img_pole);
1283 texture_free(&img_poletop);
1285 for (i = 0; i < 2; i++)
1286 texture_free(&img_flag[i]);
1288 texture_free(&img_mints);
1289 texture_free(&img_coffee);
1291 for (i = 0; i < 4; i++)
1293 texture_free(&img_distro[i]);
1294 texture_free(&img_cloud[0][i]);
1295 texture_free(&img_cloud[1][i]);
1298 texture_free(&img_golden_herring);
1300 for (i = 0; i < NUM_SOUNDS; i++)
1301 free_chunk(sounds[i]);
1303 /* free the herring song */
1304 free_music( herring_song );
1308 /* Draw a tile on the screen: */
1310 void drawshape(float x, float y, unsigned int c)
1314 Tile* ptile = TileManager::instance()->get(c);
1317 if(ptile->images.size() > 1)
1319 texture_draw(&ptile->images[( ((global_frame_counter*25) / ptile->anim_speed) % (ptile->images.size()))],x,y);
1321 else if (ptile->images.size() == 1)
1323 texture_draw(&ptile->images[0],x,y);
1327 printf("Tile not dravable %u\n", c);
1333 if (c == 'X' || c == 'x')
1334 texture_draw(&img_brick[0], x, y);
1335 else if (c == 'Y' || c == 'y')
1336 texture_draw(&img_brick[1], x, y);
1337 else if (c == 'A' || c =='B' || c == '!')
1338 texture_draw(&img_box_full, x, y);
1340 texture_draw(&img_box_empty, x, y);
1341 else if (c >= 'C' && c <= 'F')
1342 texture_draw(&img_cloud[0][c - 'C'], x, y);
1343 else if (c >= 'c' && c <= 'f')
1344 texture_draw(&img_cloud[1][c - 'c'], x, y);
1345 else if (c >= 'G' && c <= 'J')
1346 texture_draw(&img_bkgd_tile[0][c - 'G'], x, y);
1347 else if (c >= 'g' && c <= 'j')
1348 texture_draw(&img_bkgd_tile[1][c - 'g'], x, y);
1350 texture_draw(&img_solid[0], x, y);
1352 texture_draw(&img_solid[1], x, y);
1354 texture_draw(&img_solid[2], x, y);
1356 texture_draw(&img_solid[3], x, y);
1359 z = (global_frame_counter / 2) % 6;
1362 texture_draw(&img_distro[z], x, y);
1364 texture_draw(&img_distro[2], x, y);
1366 texture_draw(&img_distro[1], x, y);
1370 z = (global_frame_counter / 3) % 3;
1372 texture_draw(&img_waves[z], x, y);
1375 texture_draw(&img_poletop, x, y);
1378 texture_draw(&img_pole, x, y);
1383 z = (global_frame_counter / 3) % 2;
1385 texture_draw(&img_flag[z], x + 16, y);
1388 texture_draw(&img_water, x, y);*/
1393 /* What shape is at some position? */
1394 unsigned int shape(float x, float y)
1403 if (yy >= 0 && yy < 15 && xx >= 0 && xx <= current_level.width)
1405 c = current_level.ia_tiles[yy][xx];
1413 Tile* gettile(float x, float y)
1415 return TileManager::instance()->get(shape(x, y));
1421 bool issolid(float x, float y)
1423 Tile* tile = TileManager::instance()->get
1427 if(tile->solid == true)
1438 /* Is it a brick? */
1440 bool isbrick(float x, float y)
1442 Tile* tile = TileManager::instance()->get
1446 if(tile->brick == true)
1460 bool isice(float x, float y)
1462 Tile* tile = TileManager::instance()->get
1466 if(tile->ice == true)
1477 /* Is it a full box? */
1479 bool isfullbox(float x, float y)
1481 Tile* tile = TileManager::instance()->get
1485 if(tile->fullbox == true)
1496 bool isdistro(float x, float y)
1498 Tile* tile = TileManager::instance()->get(shape(x,y));
1499 return tile && tile->distro;
1502 /* Break a brick: */
1504 void trybreakbrick(float x, float y)
1506 Tile* tile = gettile(x, y);
1511 /* Get a distro from it: */
1512 add_bouncy_distro(((int)(x + 1) / 32) * 32,
1513 (int)(y / 32) * 32);
1515 if (!counting_distros)
1517 counting_distros = true;
1518 distro_counter = 50;
1521 if (distro_counter <= 0)
1522 level_change(¤t_level,x, y, TM_IA, tile->next_tile2);
1524 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1525 score = score + SCORE_DISTRO;
1530 /* Get rid of it: */
1531 level_change(¤t_level,x, y, TM_IA, tile->next_tile);
1535 /* Replace it with broken bits: */
1537 add_broken_brick(((int)(x + 1) / 32) * 32,
1538 (int)(y / 32) * 32);
1541 /* Get some score: */
1543 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
1544 score = score + SCORE_BRICK;
1549 /* Bounce a brick: */
1551 void bumpbrick(float x, float y)
1553 add_bouncy_brick(((int)(x + 1) / 32) * 32,
1554 (int)(y / 32) * 32);
1556 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
1563 void tryemptybox(float x, float y, int col_side)
1565 Tile* tile = gettile(x,y);
1569 // according to the collision side, set the upgrade direction
1571 if(col_side == LEFT)
1576 // FIXME: Content of boxes must be handled otherwise
1579 case 1: //'A': /* Box with a distro! */
1580 add_bouncy_distro(((int)(x + 1) / 32) * 32, (int)(y / 32) * 32 - 32);
1581 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1582 score = score + SCORE_DISTRO;
1585 case 2: // 'B': /* Add an upgrade! */
1586 if (tux.size == SMALL) /* Tux is small, add mints! */
1587 add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_MINTS);
1588 else /* Tux is big, add coffee: */
1589 add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_COFFEE);
1590 play_sound(sounds[SND_UPGRADE], SOUND_CENTER_SPEAKER);
1592 case 3:// '!': /* Add a golden herring */
1593 add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_HERRING);
1599 /* Empty the box: */
1600 level_change(¤t_level,x, y, TM_IA, tile->next_tile);
1604 /* Try to grab a distro: */
1606 void trygrabdistro(float x, float y, int bounciness)
1608 Tile* tile = gettile(x, y);
1609 if (tile && tile->distro)
1611 level_change(¤t_level,x, y, TM_IA, tile->next_tile);
1612 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1614 if (bounciness == BOUNCE)
1616 add_bouncy_distro(((int)(x + 1) / 32) * 32,
1617 (int)(y / 32) * 32);
1620 score = score + SCORE_DISTRO;
1625 /* Try to bump a bad guy from below: */
1627 void trybumpbadguy(float x, float y)
1632 for (i = 0; i < bad_guys.size(); i++)
1634 if (bad_guys[i].base.x >= x - 32 && bad_guys[i].base.x <= x + 32 &&
1635 bad_guys[i].base.y >= y - 16 && bad_guys[i].base.y <= y + 16)
1637 if (bad_guys[i].kind == BAD_BSOD ||
1638 bad_guys[i].kind == BAD_LAPTOP)
1640 bad_guys[i].dying = DYING_FALLING;
1641 bad_guys[i].base.ym = -8;
1642 play_sound(sounds[SND_FALL], SOUND_CENTER_SPEAKER);
1649 for (i = 0; i < upgrades.size(); i++)
1651 if (upgrades[i].base.height == 32 &&
1652 upgrades[i].base.x >= x - 32 && upgrades[i].base.x <= x + 32 &&
1653 upgrades[i].base.y >= y - 16 && upgrades[i].base.y <= y + 16)
1655 upgrades[i].base.xm = -upgrades[i].base.xm;
1656 upgrades[i].base.ym = -8;
1657 play_sound(sounds[SND_BUMP_UPGRADE], SOUND_CENTER_SPEAKER);
1663 void drawstatus(void)
1667 sprintf(str, "%d", score);
1668 text_draw(&white_text, "SCORE", 0, 0, 1);
1669 text_draw(&gold_text, str, 96, 0, 1);
1671 if(st_gl_mode != ST_GL_TEST)
1673 sprintf(str, "%d", hs_score);
1674 text_draw(&white_text, "HIGH", 0, 20, 1);
1675 text_draw(&gold_text, str, 96, 20, 1);
1679 text_draw(&white_text,"Press ESC To Return",0,20,1);
1682 if (timer_get_left(&time_left) > TIME_WARNING || (global_frame_counter % 10) < 5)
1684 sprintf(str, "%d", timer_get_left(&time_left) / 1000 );
1685 text_draw(&white_text, "TIME", 224, 0, 1);
1686 text_draw(&gold_text, str, 304, 0, 1);
1689 sprintf(str, "%d", distros);
1690 text_draw(&white_text, "DISTROS", screen->h, 0, 1);
1691 text_draw(&gold_text, str, 608, 0, 1);
1693 text_draw(&white_text, "LIVES", screen->h, 20, 1);
1697 sprintf(str, "%2.1f", fps_fps);
1698 text_draw(&white_text, "FPS", screen->h, 40, 1);
1699 text_draw(&gold_text, str, screen->h + 60, 40, 1);
1702 for(int i=0; i < tux.lives; ++i)
1704 texture_draw(&tux_life,565+(18*i),20);
1709 void drawendscreen(void)
1713 clearscreen(0, 0, 0);
1715 text_drawf(&blue_text, "GAMEOVER", 0, 200, A_HMIDDLE, A_TOP, 1);
1717 sprintf(str, "SCORE: %d", score);
1718 text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1);
1720 sprintf(str, "DISTROS: %d", distros);
1721 text_drawf(&gold_text, str, 0, 256, A_HMIDDLE, A_TOP, 1);
1727 void drawresultscreen(void)
1731 clearscreen(0, 0, 0);
1733 text_drawf(&blue_text, "Result:", 0, 200, A_HMIDDLE, A_TOP, 1);
1735 sprintf(str, "SCORE: %d", score);
1736 text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1);
1738 sprintf(str, "DISTROS: %d", distros);
1739 text_drawf(&gold_text, str, 0, 256, A_HMIDDLE, A_TOP, 1);
1745 void savegame(int slot)
1747 char savefile[1024];
1751 sprintf(savefile,"%s/slot%d.save",st_save_dir,slot);
1753 fi = fopen(savefile, "wb");
1757 fprintf(stderr, "Warning: I could not open the slot file ");
1762 fputs(level_subset, fi);
1764 fwrite(&level,sizeof(int),1,fi);
1765 fwrite(&score,sizeof(int),1,fi);
1766 fwrite(&distros,sizeof(int),1,fi);
1767 fwrite(&scroll_x,sizeof(float),1,fi);
1768 fwrite(&tux,sizeof(Player),1,fi);
1769 timer_fwrite(&tux.invincible_timer,fi);
1770 timer_fwrite(&tux.skidding_timer,fi);
1771 timer_fwrite(&tux.safe_timer,fi);
1772 timer_fwrite(&tux.frame_timer,fi);
1773 timer_fwrite(&time_left,fi);
1774 ui = st_get_ticks();
1775 fwrite(&ui,sizeof(int),1,fi);
1781 void loadgame(int slot)
1783 char savefile[1024];
1788 sprintf(savefile,"%s/slot%d.save",st_save_dir,slot);
1790 fi = fopen(savefile, "rb");
1794 fprintf(stderr, "Warning: I could not open the slot file ");
1799 fgets(str, 100, fi);
1800 strcpy(level_subset, str);
1801 level_subset[strlen(level_subset)-1] = '\0';
1802 fread(&level,sizeof(int),1,fi);
1805 level_free(¤t_level);
1806 if(level_load(¤t_level,level_subset,level) != 0)
1810 activate_bad_guys();
1811 activate_particle_systems();
1813 level_load_gfx(¤t_level);
1815 level_load_song(¤t_level);
1817 update_time = st_get_ticks();
1819 fread(&score,sizeof(int),1,fi);
1820 fread(&distros,sizeof(int),1,fi);
1821 fread(&scroll_x,sizeof(float),1,fi);
1822 fread(&tux, sizeof(Player), 1, fi);
1823 timer_fread(&tux.invincible_timer,fi);
1824 timer_fread(&tux.skidding_timer,fi);
1825 timer_fread(&tux.safe_timer,fi);
1826 timer_fread(&tux.frame_timer,fi);
1827 timer_fread(&time_left,fi);
1828 fread(&ui,sizeof(int),1,fi);
1829 tux.hphysic.start_time += st_get_ticks() - ui;
1830 tux.vphysic.start_time += st_get_ticks() - ui;
1836 void slotinfo(char **pinfo, int slot)
1839 char slotfile[1024];
1843 sprintf(slotfile,"%s/slot%d.save",st_save_dir,slot);
1845 fi = fopen(slotfile, "rb");
1847 sprintf(tmp,"Slot %d - ",slot);
1855 fgets(str, 100, fi);
1856 str[strlen(str)-1] = '\0';
1858 strcat(tmp, " / Level:");
1859 fread(&slot_level,sizeof(int),1,fi);
1860 sprintf(str,"%d",slot_level);
1865 *pinfo = (char*) malloc(sizeof(char) * (strlen(tmp)+1));