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)
105 /* Activate bad guys: */
107 for (y = 0; y < 15; y++)
109 for (x = 0; x < current_level.width; x++)
111 if (current_level.dn_tiles[y][x] >= '0' && current_level.dn_tiles[y][x] <= '9')
113 add_bad_guy(x * 32, y * 32, static_cast<BadGuyKind>(current_level.dn_tiles[y][x] - '0'));
114 current_level.dn_tiles[y][x] = 0;
120 void activate_particle_systems(void)
122 printf("PSys: %s\n", current_level.particle_system.c_str());
123 if(current_level.particle_system == "clouds")
125 particle_systems.push_back(new CloudParticleSystem);
127 else if(current_level.particle_system == "snow")
129 particle_systems.push_back(new SnowParticleSystem);
131 else if(current_level.particle_system != "")
133 st_abort("unknown particle system specified in level", "");
137 /* --- GAME EVENT! --- */
139 void game_event(void)
141 while (SDL_PollEvent(&event))
145 case SDL_QUIT: /* Quit event - quit: */
148 case SDL_KEYDOWN: /* A keypress! */
149 key = event.key.keysym.sym;
151 /* Check for menu-events, if the menu is shown */
153 menu_event(&event.key.keysym);
155 if(tux.key_event(key,DOWN))
160 case SDLK_ESCAPE: /* Escape: Open/Close the menu: */
163 if(st_gl_mode == ST_GL_TEST)
167 Menu::set_current(game_menu);
169 st_pause_ticks_stop();
173 Menu::set_current(game_menu);
175 st_pause_ticks_start();
183 case SDL_KEYUP: /* A keyrelease! */
184 key = event.key.keysym.sym;
186 if(tux.key_event(key, UP))
197 st_pause_ticks_stop();
202 st_pause_ticks_start();
209 tux.size = !tux.size;
212 tux.base.height = 64;
215 tux.base.height = 32;
232 timer_start(&tux.invincible_timer,TUX_INVINCIBLE_TIME);
252 case SDL_JOYAXISMOTION:
253 switch(event.jaxis.axis)
256 if (event.jaxis.value < -JOYSTICK_DEAD_ZONE)
258 tux.input.left = DOWN;
259 tux.input.right = UP;
261 else if (event.jaxis.value > JOYSTICK_DEAD_ZONE)
264 tux.input.right = DOWN;
268 tux.input.left = DOWN;
269 tux.input.right = DOWN;
273 if (event.jaxis.value > JOYSTICK_DEAD_ZONE)
274 tux.input.down = DOWN;
275 else if (event.jaxis.value < -JOYSTICK_DEAD_ZONE)
280 /* Handle joystick for the menu */
283 if(tux.input.down == DOWN)
284 menuaction = MENU_ACTION_DOWN;
286 menuaction = MENU_ACTION_UP;
293 case SDL_JOYBUTTONDOWN:
294 if (event.jbutton.button == JOY_A)
296 else if (event.jbutton.button == JOY_B)
297 tux.input.fire = DOWN;
299 case SDL_JOYBUTTONUP:
300 if (event.jbutton.button == JOY_A)
302 else if (event.jbutton.button == JOY_B)
306 menuaction = MENU_ACTION_HIT;
317 /* --- GAME ACTION! --- */
319 int game_action(void)
323 /* (tux_dying || next_level) */
324 if (tux.dying || next_level)
326 /* Tux either died, or reached the end of a level! */
333 /* End of a level! */
336 if(st_gl_mode != ST_GL_TEST)
343 level_free(¤t_level);
355 /* No more lives!? */
359 if(st_gl_mode != ST_GL_TEST)
362 if(st_gl_mode != ST_GL_TEST)
364 if (score > hs_score)
368 level_free(¤t_level);
373 } /* if (lives < 0) */
376 /* Either way, (re-)load the (next) level... */
380 level_free(¤t_level);
382 if (st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
384 if(level_load(¤t_level, level_subset) != 0)
389 if(level_load(¤t_level,level_subset,level) != 0)
396 activate_particle_systems();
398 level_load_gfx(¤t_level);
400 level_load_song(¤t_level);
401 if(st_gl_mode != ST_GL_TEST)
405 play_current_music();
410 /* Handle bouncy distros: */
411 for (i = 0; i < bouncy_distros.size(); i++)
413 bouncy_distro_action(&bouncy_distros[i]);
417 /* Handle broken bricks: */
418 for (i = 0; i < broken_bricks.size(); i++)
420 broken_brick_action(&broken_bricks[i]);
424 /* Handle distro counting: */
426 if (counting_distros)
430 if (distro_counter <= 0)
431 counting_distros = -1;
435 /* Handle bouncy bricks: */
437 for (i = 0; i < bouncy_bricks.size(); i++)
439 bouncy_brick_action(&bouncy_bricks[i]);
443 /* Handle floating scores: */
445 for (i = 0; i < floating_scores.size(); i++)
447 floating_score_action(&floating_scores[i]);
451 /* Handle bullets: */
453 for (i = 0; i < bullets.size(); ++i)
455 bullet_action(&bullets[i]);
458 /* Handle upgrades: */
460 for (i = 0; i < upgrades.size(); i++)
462 upgrade_action(&upgrades[i]);
466 /* Handle bad guys: */
468 for (i = 0; i < bad_guys.size(); i++)
470 bad_guys[i].action();
473 /* update particle systems */
474 std::vector<ParticleSystem*>::iterator p;
475 for(p = particle_systems.begin(); p != particle_systems.end(); ++p)
477 (*p)->simulate(frame_ratio);
480 /* Handle all possible collisions. */
486 /* --- GAME DRAW! --- */
493 if (tux.dying && (global_frame_counter % 4) == 0)
494 clearscreen(255, 255, 255);
495 else if(timer_check(&super_bkgd_timer))
496 texture_draw(&img_super_bkgd, 0, 0);
499 /* Draw the real background */
500 if(current_level.bkgd_image[0] != '\0')
502 int s = (int)scroll_x / 30;
503 texture_draw_part(&img_bkgd,s,0,0,0,img_bkgd.w - s, img_bkgd.h);
504 texture_draw_part(&img_bkgd,0,0,screen->w - s ,0,s,img_bkgd.h);
508 clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue);
512 /* Draw particle systems (background) */
513 std::vector<ParticleSystem*>::iterator p;
514 for(p = particle_systems.begin(); p != particle_systems.end(); ++p)
516 (*p)->draw(scroll_x, 0, 0);
519 /* Draw background: */
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.bg_tiles[(int)y][(int)x + (int)(scroll_x / 32)]);
530 /* Draw interactive tiles: */
532 for (y = 0; y < 15; ++y)
534 for (x = 0; x < 21; ++x)
536 drawshape(32*x - fmodf(scroll_x, 32), y * 32,
537 current_level.ia_tiles[(int)y][(int)x + (int)(scroll_x / 32)]);
541 /* (Bouncy bricks): */
543 for (unsigned int i = 0; i < bouncy_bricks.size(); ++i)
544 bouncy_brick_draw(&bouncy_bricks[i]);
546 for (unsigned int i = 0; i < bad_guys.size(); ++i)
551 for (unsigned int i = 0; i < bullets.size(); ++i)
552 bullet_draw(&bullets[i]);
554 for (unsigned int i = 0; i < floating_scores.size(); ++i)
555 floating_score_draw(&floating_scores[i]);
557 for (unsigned int i = 0; i < upgrades.size(); ++i)
558 upgrade_draw(&upgrades[i]);
560 for (unsigned int i = 0; i < bouncy_distros.size(); ++i)
561 bouncy_distro_draw(&bouncy_distros[i]);
563 for (unsigned int i = 0; i < broken_bricks.size(); ++i)
564 broken_brick_draw(&broken_bricks[i]);
566 /* Draw foreground: */
568 for (y = 0; y < 15; ++y)
570 for (x = 0; x < 21; ++x)
572 drawshape(32*x - fmodf(scroll_x, 32), y * 32,
573 current_level.fg_tiles[(int)y][(int)x + (int)(scroll_x / 32)]);
577 /* Draw particle systems (foreground) */
578 for(p = particle_systems.begin(); p != particle_systems.end(); ++p)
580 (*p)->draw(scroll_x, 0, 1);
587 int x = screen->h / 20;
588 for(int i = 0; i < x; ++i)
590 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);
592 fillrect(0,0,screen->w,screen->h,rand() % 50, rand() % 50, rand() % 50, 128);
593 text_drawf(&blue_text, "PAUSE - Press 'P' To Play", 0, 230, A_HMIDDLE, A_TOP, 1);
597 menu_process_current();
599 /* (Update it all!) */
603 /* --- GAME LOOP! --- */
605 int gameloop(const char * subset, int levelnb, int mode)
607 int fps_cnt, jump, done;
608 timer_type fps_timer, frame_timer;
609 timer_init(&fps_timer, true);
610 timer_init(&frame_timer, true);
621 strcpy(level_subset,subset);
623 if (st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
625 if (level_load(¤t_level, level_subset))
630 if(level_load(¤t_level, level_subset, level) != 0)
634 level_load_gfx(¤t_level);
636 activate_particle_systems();
637 level_load_song(¤t_level);
641 if(st_gl_mode != ST_GL_TEST)
646 if(st_gl_mode == ST_GL_PLAY || st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
649 timer_init(&time_left,true);
652 if(st_gl_mode == ST_GL_LOAD_GAME)
655 /* --- MAIN GAME LOOP!!! --- */
660 global_frame_counter = 0;
662 timer_init(&fps_timer,true);
663 timer_init(&frame_timer,true);
668 clearscreen(0, 0, 0);
672 play_current_music();
675 while (SDL_PollEvent(&event))
683 /* Calculate the movement-factor */
684 frame_ratio = ((double)(update_time-last_update_time))/((double)FRAME_RATE);
685 if(frame_ratio > 1.5) /* Quick hack to correct the unprecise CPU clocks a little bit. */
686 frame_ratio = 1.5 + (frame_ratio - 1.5) * 0.85;
688 if(!timer_check(&frame_timer))
690 timer_start(&frame_timer,25);
691 ++global_frame_counter;
696 tux.input.old_fire = tux.input.fire;
702 if(current_menu == game_menu)
704 switch (game_menu->check())
707 st_pause_ticks_stop();
710 update_load_save_game_menu(save_game_menu, false);
713 update_load_save_game_menu(load_game_menu, true);
716 st_pause_ticks_stop();
721 else if(current_menu == options_menu)
723 process_options_menu();
725 else if(current_menu == save_game_menu )
727 process_save_load_game_menu(true);
729 else if(current_menu == load_game_menu )
731 process_save_load_game_menu(false);
736 /* Handle actions: */
738 if(!game_pause && !show_menu)
740 /*float z = frame_ratio;
744 if (game_action() == 0)
746 /* == 0: no more lives */
747 /* == -1: continues */
759 if(debug_mode && debug_fps)
762 /*Draw the current scene to the screen */
763 /*If the machine running the game is too slow
764 skip the drawing of the frame (so the calculations are more precise and
765 the FPS aren't affected).*/
766 /*if( ! fps_fps < 50.0 )
769 jump = true;*/ /*FIXME: Implement this tweak right.*/
772 /* Time stops in pause mode */
773 if(game_pause || show_menu )
778 /* Set the time of the last update and the time of the current update */
779 last_update_time = update_time;
780 update_time = st_get_ticks();
782 /* Pause till next frame, if the machine running the game is too fast: */
783 /* FIXME: Works great for in OpenGl mode, where the CPU doesn't have to do that much. But
784 the results in SDL mode aren't perfect (thought the 100 FPS are reached), even on an AMD2500+. */
785 if(last_update_time >= update_time - 12 && !jump)
787 /*if((update_time - last_update_time) < 10)
788 SDL_Delay((11 - (update_time - last_update_time))/2);*/
794 if (timer_check(&time_left))
796 /* are we low on time ? */
797 if ((timer_get_left(&time_left) < TIME_WARNING)
798 && (get_current_music() != HURRYUP_MUSIC)) /* play the fast music */
800 set_current_music(HURRYUP_MUSIC);
801 play_current_music();
809 /* Calculate frames per second */
813 fps_fps = (1000.0 / (float)timer_get_gone(&fps_timer)) * (float)fps_cnt;
815 if(!timer_check(&fps_timer))
817 timer_start(&fps_timer,1000);
823 while (!done && !quit);
828 level_free(¤t_level);
833 game_started = false;
839 /* Load graphics/sounds shared between all levels: */
841 void loadshared(void)
846 texture_load(&tux_right[0], datadir + "/images/shared/tux-right-0.png", USE_ALPHA);
847 texture_load(&tux_right[1], datadir + "/images/shared/tux-right-1.png", USE_ALPHA);
848 texture_load(&tux_right[2], datadir + "/images/shared/tux-right-2.png", USE_ALPHA);
850 texture_load(&tux_left[0], datadir + "/images/shared/tux-left-0.png", USE_ALPHA);
851 texture_load(&tux_left[1], datadir + "/images/shared/tux-left-1.png", USE_ALPHA);
852 texture_load(&tux_left[2], datadir + "/images/shared/tux-left-2.png", USE_ALPHA);
854 texture_load(&firetux_right[0], datadir + "/images/shared/firetux-right-0.png", USE_ALPHA);
855 texture_load(&firetux_right[1], datadir + "/images/shared/firetux-right-1.png", USE_ALPHA);
856 texture_load(&firetux_right[2], datadir + "/images/shared/firetux-right-2.png", USE_ALPHA);
858 texture_load(&firetux_left[0], datadir + "/images/shared/firetux-left-0.png", USE_ALPHA);
859 texture_load(&firetux_left[1], datadir + "/images/shared/firetux-left-1.png", USE_ALPHA);
860 texture_load(&firetux_left[2], datadir + "/images/shared/firetux-left-2.png", USE_ALPHA);
863 texture_load(&cape_right[0], datadir + "/images/shared/cape-right-0.png",
866 texture_load(&cape_right[1], datadir + "/images/shared/cape-right-1.png",
869 texture_load(&cape_left[0], datadir + "/images/shared/cape-left-0.png",
872 texture_load(&cape_left[1], datadir + "/images/shared/cape-left-1.png",
875 texture_load(&bigtux_right[0], datadir + "/images/shared/bigtux-right-0.png",
878 texture_load(&bigtux_right[1], datadir + "/images/shared/bigtux-right-1.png",
881 texture_load(&bigtux_right[2], datadir + "/images/shared/bigtux-right-2.png",
884 texture_load(&bigtux_right_jump, datadir + "/images/shared/bigtux-right-jump.png", USE_ALPHA);
886 texture_load(&bigtux_left[0], datadir + "/images/shared/bigtux-left-0.png",
889 texture_load(&bigtux_left[1], datadir + "/images/shared/bigtux-left-1.png",
892 texture_load(&bigtux_left[2], datadir + "/images/shared/bigtux-left-2.png",
895 texture_load(&bigtux_left_jump, datadir + "/images/shared/bigtux-left-jump.png", USE_ALPHA);
897 texture_load(&bigcape_right[0], datadir + "/images/shared/bigcape-right-0.png",
900 texture_load(&bigcape_right[1], datadir + "/images/shared/bigcape-right-1.png",
903 texture_load(&bigcape_left[0], datadir + "/images/shared/bigcape-left-0.png",
906 texture_load(&bigcape_left[1], datadir + "/images/shared/bigcape-left-1.png",
909 texture_load(&bigfiretux_right[0], datadir + "/images/shared/bigfiretux-right-0.png",
912 texture_load(&bigfiretux_right[1], datadir + "/images/shared/bigfiretux-right-1.png",
915 texture_load(&bigfiretux_right[2], datadir + "/images/shared/bigfiretux-right-2.png",
918 texture_load(&bigfiretux_right_jump, datadir + "/images/shared/bigfiretux-right-jump.png", USE_ALPHA);
920 texture_load(&bigfiretux_left[0], datadir + "/images/shared/bigfiretux-left-0.png",
923 texture_load(&bigfiretux_left[1], datadir + "/images/shared/bigfiretux-left-1.png",
926 texture_load(&bigfiretux_left[2], datadir + "/images/shared/bigfiretux-left-2.png",
929 texture_load(&bigfiretux_left_jump, datadir + "/images/shared/bigfiretux-left-jump.png", USE_ALPHA);
931 texture_load(&bigcape_right[0], datadir + "/images/shared/bigcape-right-0.png",
934 texture_load(&bigcape_right[1], datadir + "/images/shared/bigcape-right-1.png",
937 texture_load(&bigcape_left[0], datadir + "/images/shared/bigcape-left-0.png",
940 texture_load(&bigcape_left[1], datadir + "/images/shared/bigcape-left-1.png",
944 texture_load(&ducktux_right, datadir +
945 "/images/shared/ducktux-right.png",
948 texture_load(&ducktux_left, datadir +
949 "/images/shared/ducktux-left.png",
952 texture_load(&skidtux_right, datadir +
953 "/images/shared/skidtux-right.png",
956 texture_load(&skidtux_left, datadir +
957 "/images/shared/skidtux-left.png",
960 texture_load(&duckfiretux_right, datadir +
961 "/images/shared/duckfiretux-right.png",
964 texture_load(&duckfiretux_left, datadir +
965 "/images/shared/duckfiretux-left.png",
968 texture_load(&skidfiretux_right, datadir +
969 "/images/shared/skidfiretux-right.png",
972 texture_load(&skidfiretux_left, datadir +
973 "/images/shared/skidfiretux-left.png",
979 texture_load(&img_box_full, datadir + "/images/shared/box-full.png",
981 texture_load(&img_box_empty, datadir + "/images/shared/box-empty.png",
988 texture_load(&img_water, datadir + "/images/shared/water.png", IGNORE_ALPHA);
990 texture_load(&img_waves[0], datadir + "/images/shared/waves-0.png",
993 texture_load(&img_waves[1], datadir + "/images/shared/waves-1.png",
996 texture_load(&img_waves[2], datadir + "/images/shared/waves-2.png",
1002 texture_load(&img_pole, datadir + "/images/shared/pole.png", USE_ALPHA);
1003 texture_load(&img_poletop, datadir + "/images/shared/poletop.png",
1009 texture_load(&img_flag[0], datadir + "/images/shared/flag-0.png",
1011 texture_load(&img_flag[1], datadir + "/images/shared/flag-1.png",
1017 texture_load(&img_cloud[0][0], datadir + "/images/shared/cloud-00.png",
1020 texture_load(&img_cloud[0][1], datadir + "/images/shared/cloud-01.png",
1023 texture_load(&img_cloud[0][2], datadir + "/images/shared/cloud-02.png",
1026 texture_load(&img_cloud[0][3], datadir + "/images/shared/cloud-03.png",
1030 texture_load(&img_cloud[1][0], datadir + "/images/shared/cloud-10.png",
1033 texture_load(&img_cloud[1][1], datadir + "/images/shared/cloud-11.png",
1036 texture_load(&img_cloud[1][2], datadir + "/images/shared/cloud-12.png",
1039 texture_load(&img_cloud[1][3], datadir + "/images/shared/cloud-13.png",
1047 texture_load(&img_bsod_left[0], datadir +
1048 "/images/shared/bsod-left-0.png",
1051 texture_load(&img_bsod_left[1], datadir +
1052 "/images/shared/bsod-left-1.png",
1055 texture_load(&img_bsod_left[2], datadir +
1056 "/images/shared/bsod-left-2.png",
1059 texture_load(&img_bsod_left[3], datadir +
1060 "/images/shared/bsod-left-3.png",
1063 texture_load(&img_bsod_right[0], datadir +
1064 "/images/shared/bsod-right-0.png",
1067 texture_load(&img_bsod_right[1], datadir +
1068 "/images/shared/bsod-right-1.png",
1071 texture_load(&img_bsod_right[2], datadir +
1072 "/images/shared/bsod-right-2.png",
1075 texture_load(&img_bsod_right[3], datadir +
1076 "/images/shared/bsod-right-3.png",
1079 texture_load(&img_bsod_squished_left, datadir +
1080 "/images/shared/bsod-squished-left.png",
1083 texture_load(&img_bsod_squished_right, datadir +
1084 "/images/shared/bsod-squished-right.png",
1087 texture_load(&img_bsod_falling_left, datadir +
1088 "/images/shared/bsod-falling-left.png",
1091 texture_load(&img_bsod_falling_right, datadir +
1092 "/images/shared/bsod-falling-right.png",
1098 texture_load(&img_laptop_left[0], datadir +
1099 "/images/shared/laptop-left-0.png",
1102 texture_load(&img_laptop_left[1], datadir +
1103 "/images/shared/laptop-left-1.png",
1106 texture_load(&img_laptop_left[2], datadir +
1107 "/images/shared/laptop-left-2.png",
1110 texture_load(&img_laptop_right[0], datadir +
1111 "/images/shared/laptop-right-0.png",
1114 texture_load(&img_laptop_right[1], datadir +
1115 "/images/shared/laptop-right-1.png",
1118 texture_load(&img_laptop_right[2], datadir +
1119 "/images/shared/laptop-right-2.png",
1122 texture_load(&img_laptop_flat_left, datadir +
1123 "/images/shared/laptop-flat-left.png",
1126 texture_load(&img_laptop_flat_right, datadir +
1127 "/images/shared/laptop-flat-right.png",
1130 texture_load(&img_laptop_falling_left, datadir +
1131 "/images/shared/laptop-falling-left.png",
1134 texture_load(&img_laptop_falling_right, datadir +
1135 "/images/shared/laptop-falling-right.png",
1141 texture_load(&img_money_left[0], datadir +
1142 "/images/shared/bag-left-0.png",
1145 texture_load(&img_money_left[1], datadir +
1146 "/images/shared/bag-left-1.png",
1149 texture_load(&img_money_right[0], datadir +
1150 "/images/shared/bag-right-0.png",
1153 texture_load(&img_money_right[1], datadir +
1154 "/images/shared/bag-right-1.png",
1161 texture_load(&img_mints, datadir + "/images/shared/mints.png", USE_ALPHA);
1162 texture_load(&img_coffee, datadir + "/images/shared/coffee.png", USE_ALPHA);
1167 texture_load(&img_bullet, datadir + "/images/shared/bullet.png", USE_ALPHA);
1169 texture_load(&img_red_glow, datadir + "/images/shared/red-glow.png",
1176 texture_load(&img_distro[0], datadir + "/images/shared/distro-0.png",
1179 texture_load(&img_distro[1], datadir + "/images/shared/distro-1.png",
1182 texture_load(&img_distro[2], datadir + "/images/shared/distro-2.png",
1185 texture_load(&img_distro[3], datadir + "/images/shared/distro-3.png",
1191 texture_load(&tux_life, datadir + "/images/shared/tux-life.png",
1196 texture_load(&img_golden_herring, datadir + "/images/shared/golden-herring.png",
1200 /* Super background: */
1202 texture_load(&img_super_bkgd, datadir + "/images/shared/super-bkgd.png",
1206 /* Sound effects: */
1208 /* if (use_sound) // this will introduce SERIOUS bugs here ! because "load_sound"
1209 // initialize sounds[i] with the correct pointer's value:
1210 // NULL or something else. And it will be dangerous to
1211 // play with not-initialized pointers.
1212 // This is also true with if (use_music)
1213 Send a mail to me: neoneurone@users.sf.net, if you have another opinion. :)
1215 for (i = 0; i < NUM_SOUNDS; i++)
1216 sounds[i] = load_sound(datadir + soundfilenames[i]);
1219 herring_song = load_song(datadir + "/music/SALCON.MOD");
1223 /* Free shared data: */
1225 void unloadshared(void)
1229 for (i = 0; i < 3; i++)
1231 texture_free(&tux_right[i]);
1232 texture_free(&tux_left[i]);
1233 texture_free(&bigtux_right[i]);
1234 texture_free(&bigtux_left[i]);
1237 texture_free(&bigtux_right_jump);
1238 texture_free(&bigtux_left_jump);
1240 for (i = 0; i < 2; i++)
1242 texture_free(&cape_right[i]);
1243 texture_free(&cape_left[i]);
1244 texture_free(&bigcape_right[i]);
1245 texture_free(&bigcape_left[i]);
1248 texture_free(&ducktux_left);
1249 texture_free(&ducktux_right);
1251 texture_free(&skidtux_left);
1252 texture_free(&skidtux_right);
1254 for (i = 0; i < 4; i++)
1256 texture_free(&img_bsod_left[i]);
1257 texture_free(&img_bsod_right[i]);
1260 texture_free(&img_bsod_squished_left);
1261 texture_free(&img_bsod_squished_right);
1263 texture_free(&img_bsod_falling_left);
1264 texture_free(&img_bsod_falling_right);
1266 for (i = 0; i < 3; i++)
1268 texture_free(&img_laptop_left[i]);
1269 texture_free(&img_laptop_right[i]);
1272 texture_free(&img_laptop_flat_left);
1273 texture_free(&img_laptop_flat_right);
1275 texture_free(&img_laptop_falling_left);
1276 texture_free(&img_laptop_falling_right);
1278 for (i = 0; i < 2; i++)
1280 texture_free(&img_money_left[i]);
1281 texture_free(&img_money_right[i]);
1284 texture_free(&img_box_full);
1285 texture_free(&img_box_empty);
1287 texture_free(&img_water);
1288 for (i = 0; i < 3; i++)
1289 texture_free(&img_waves[i]);
1291 texture_free(&img_pole);
1292 texture_free(&img_poletop);
1294 for (i = 0; i < 2; i++)
1295 texture_free(&img_flag[i]);
1297 texture_free(&img_mints);
1298 texture_free(&img_coffee);
1300 for (i = 0; i < 4; i++)
1302 texture_free(&img_distro[i]);
1303 texture_free(&img_cloud[0][i]);
1304 texture_free(&img_cloud[1][i]);
1307 texture_free(&img_golden_herring);
1309 for (i = 0; i < NUM_SOUNDS; i++)
1310 free_chunk(sounds[i]);
1312 /* free the herring song */
1313 free_music( herring_song );
1317 /* Draw a tile on the screen: */
1319 void drawshape(float x, float y, unsigned int c)
1323 Tile* ptile = TileManager::instance()->get(c);
1326 if(ptile->images.size() > 1)
1328 texture_draw(&ptile->images[( ((global_frame_counter*25) / ptile->anim_speed) % (ptile->images.size()))],x,y);
1332 texture_draw(&ptile->images[0],x,y);
1338 if (c == 'X' || c == 'x')
1339 texture_draw(&img_brick[0], x, y);
1340 else if (c == 'Y' || c == 'y')
1341 texture_draw(&img_brick[1], x, y);
1342 else if (c == 'A' || c =='B' || c == '!')
1343 texture_draw(&img_box_full, x, y);
1345 texture_draw(&img_box_empty, x, y);
1346 else if (c >= 'C' && c <= 'F')
1347 texture_draw(&img_cloud[0][c - 'C'], x, y);
1348 else if (c >= 'c' && c <= 'f')
1349 texture_draw(&img_cloud[1][c - 'c'], x, y);
1350 else if (c >= 'G' && c <= 'J')
1351 texture_draw(&img_bkgd_tile[0][c - 'G'], x, y);
1352 else if (c >= 'g' && c <= 'j')
1353 texture_draw(&img_bkgd_tile[1][c - 'g'], x, y);
1355 texture_draw(&img_solid[0], x, y);
1357 texture_draw(&img_solid[1], x, y);
1359 texture_draw(&img_solid[2], x, y);
1361 texture_draw(&img_solid[3], x, y);
1364 z = (global_frame_counter / 2) % 6;
1367 texture_draw(&img_distro[z], x, y);
1369 texture_draw(&img_distro[2], x, y);
1371 texture_draw(&img_distro[1], x, y);
1375 z = (global_frame_counter / 3) % 3;
1377 texture_draw(&img_waves[z], x, y);
1380 texture_draw(&img_poletop, x, y);
1383 texture_draw(&img_pole, x, y);
1388 z = (global_frame_counter / 3) % 2;
1390 texture_draw(&img_flag[z], x + 16, y);
1393 texture_draw(&img_water, x, y);*/
1398 /* What shape is at some position? */
1399 unsigned int shape(float x, float y)
1408 if (yy >= 0 && yy < 15 && xx >= 0 && xx <= current_level.width)
1410 c = current_level.ia_tiles[yy][xx];
1418 Tile* gettile(float x, float y)
1420 return TileManager::instance()->get(shape(x, y));
1426 bool issolid(float x, float y)
1428 Tile* tile = TileManager::instance()->get
1432 if(tile->solid == true)
1443 /* Is it a brick? */
1445 bool isbrick(float x, float y)
1447 Tile* tile = TileManager::instance()->get
1451 if(tile->brick == true)
1465 bool isice(float x, float y)
1467 Tile* tile = TileManager::instance()->get
1471 if(tile->ice == true)
1482 /* Is it a full box? */
1484 bool isfullbox(float x, float y)
1486 Tile* tile = TileManager::instance()->get
1490 if(tile->fullbox == true)
1501 bool isdistro(float x, float y)
1503 Tile* tile = TileManager::instance()->get(shape(x,y));
1504 return tile && tile->distro;
1507 /* Break a brick: */
1509 void trybreakbrick(float x, float y)
1513 if (shape(x, y) == 'x' || shape(x, y) == 'y')
1515 /* Get a distro from it: */
1517 add_bouncy_distro(((int)(x + 1) / 32) * 32,
1518 (int)(y / 32) * 32);
1520 if (!counting_distros)
1522 counting_distros = true;
1523 distro_counter = 50;
1526 if (distro_counter <= 0)
1527 level_change(¤t_level,x, y, TM_IA, 'a');
1529 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1530 score = score + SCORE_DISTRO;
1535 /* Get rid of it: */
1537 level_change(¤t_level,x, y, TM_IA, '.');
1541 /* Replace it with broken bits: */
1543 add_broken_brick(((int)(x + 1) / 32) * 32,
1544 (int)(y / 32) * 32);
1547 /* Get some score: */
1549 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
1550 score = score + SCORE_BRICK;
1555 /* Bounce a brick: */
1557 void bumpbrick(float x, float y)
1559 add_bouncy_brick(((int)(x + 1) / 32) * 32,
1560 (int)(y / 32) * 32);
1562 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
1569 void tryemptybox(float x, float y, int col_side)
1571 if (!isfullbox(x, y))
1574 // according to the collision side, set the upgrade direction
1576 if(col_side == LEFT)
1581 // FIXME: Content of boxes must be handled otherwise
1582 switch(gettile(x,y)->data)
1584 case 1: //'A': /* Box with a distro! */
1585 add_bouncy_distro(((int)(x + 1) / 32) * 32, (int)(y / 32) * 32 - 32);
1586 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1587 score = score + SCORE_DISTRO;
1590 case 2: // 'B': /* Add an upgrade! */
1591 if (tux.size == SMALL) /* Tux is small, add mints! */
1592 add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_MINTS);
1593 else /* Tux is big, add coffee: */
1594 add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_COFFEE);
1595 play_sound(sounds[SND_UPGRADE], SOUND_CENTER_SPEAKER);
1597 case 3:// '!': /* Add a golden herring */
1598 add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_HERRING);
1604 /* Empty the box: */
1605 level_change(¤t_level,x, y, TM_IA, 'a');
1609 /* Try to grab a distro: */
1611 void trygrabdistro(float x, float y, int bounciness)
1613 Tile* tile = gettile(x, y);
1614 if (tile && tile->distro)
1616 level_change(¤t_level,x, y, TM_IA, '.');
1617 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1619 if (bounciness == BOUNCE)
1621 add_bouncy_distro(((int)(x + 1) / 32) * 32,
1622 (int)(y / 32) * 32);
1625 score = score + SCORE_DISTRO;
1630 /* Try to bump a bad guy from below: */
1632 void trybumpbadguy(float x, float y)
1637 for (i = 0; i < bad_guys.size(); i++)
1639 if (bad_guys[i].base.x >= x - 32 && bad_guys[i].base.x <= x + 32 &&
1640 bad_guys[i].base.y >= y - 16 && bad_guys[i].base.y <= y + 16)
1642 if (bad_guys[i].kind == BAD_BSOD ||
1643 bad_guys[i].kind == BAD_LAPTOP)
1645 bad_guys[i].dying = DYING_FALLING;
1646 bad_guys[i].base.ym = -8;
1647 play_sound(sounds[SND_FALL], SOUND_CENTER_SPEAKER);
1654 for (i = 0; i < upgrades.size(); i++)
1656 if (upgrades[i].base.height == 32 &&
1657 upgrades[i].base.x >= x - 32 && upgrades[i].base.x <= x + 32 &&
1658 upgrades[i].base.y >= y - 16 && upgrades[i].base.y <= y + 16)
1660 upgrades[i].base.xm = -upgrades[i].base.xm;
1661 upgrades[i].base.ym = -8;
1662 play_sound(sounds[SND_BUMP_UPGRADE], SOUND_CENTER_SPEAKER);
1668 void drawstatus(void)
1672 sprintf(str, "%d", score);
1673 text_draw(&white_text, "SCORE", 0, 0, 1);
1674 text_draw(&gold_text, str, 96, 0, 1);
1676 if(st_gl_mode != ST_GL_TEST)
1678 sprintf(str, "%d", hs_score);
1679 text_draw(&white_text, "HIGH", 0, 20, 1);
1680 text_draw(&gold_text, str, 96, 20, 1);
1684 text_draw(&white_text,"Press ESC To Return",0,20,1);
1687 if (timer_get_left(&time_left) > TIME_WARNING || (global_frame_counter % 10) < 5)
1689 sprintf(str, "%d", timer_get_left(&time_left) / 1000 );
1690 text_draw(&white_text, "TIME", 224, 0, 1);
1691 text_draw(&gold_text, str, 304, 0, 1);
1694 sprintf(str, "%d", distros);
1695 text_draw(&white_text, "DISTROS", screen->h, 0, 1);
1696 text_draw(&gold_text, str, 608, 0, 1);
1698 text_draw(&white_text, "LIVES", screen->h, 20, 1);
1702 sprintf(str, "%2.1f", fps_fps);
1703 text_draw(&white_text, "FPS", screen->h, 40, 1);
1704 text_draw(&gold_text, str, screen->h + 60, 40, 1);
1707 for(int i=0; i < tux.lives; ++i)
1709 texture_draw(&tux_life,565+(18*i),20);
1714 void drawendscreen(void)
1718 clearscreen(0, 0, 0);
1720 text_drawf(&blue_text, "GAMEOVER", 0, 200, A_HMIDDLE, A_TOP, 1);
1722 sprintf(str, "SCORE: %d", score);
1723 text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1);
1725 sprintf(str, "DISTROS: %d", distros);
1726 text_drawf(&gold_text, str, 0, 256, A_HMIDDLE, A_TOP, 1);
1732 void drawresultscreen(void)
1736 clearscreen(0, 0, 0);
1738 text_drawf(&blue_text, "Result:", 0, 200, A_HMIDDLE, A_TOP, 1);
1740 sprintf(str, "SCORE: %d", score);
1741 text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1);
1743 sprintf(str, "DISTROS: %d", distros);
1744 text_drawf(&gold_text, str, 0, 256, A_HMIDDLE, A_TOP, 1);
1750 void savegame(int slot)
1752 char savefile[1024];
1756 sprintf(savefile,"%s/slot%d.save",st_save_dir,slot);
1758 fi = fopen(savefile, "wb");
1762 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));