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 // Activate badguys the new style
104 for (std::vector<BadGuyData>::iterator i = current_level.badguy_data.begin();
105 i != current_level.badguy_data.end();
108 add_bad_guy(i->x, i->y, i->kind);
111 // FIXME: should be removed;
112 // Activate bad guys the old style
113 for (int y = 0; y < 15; y++)
115 for (int x = 0; x < current_level.width; x++)
117 if (current_level.ia_tiles[y][x] >= 1000 && current_level.ia_tiles[y][x] <= 1010)
119 add_bad_guy(x * 32, y * 32,
120 static_cast<BadGuyKind>(current_level.ia_tiles[y][x] - 1000));
121 current_level.ia_tiles[y][x] = 0;
127 void activate_particle_systems(void)
129 printf("PSys: %s\n", current_level.particle_system.c_str());
130 if(current_level.particle_system == "clouds")
132 particle_systems.push_back(new CloudParticleSystem);
134 else if(current_level.particle_system == "snow")
136 particle_systems.push_back(new SnowParticleSystem);
138 else if(current_level.particle_system != "")
140 st_abort("unknown particle system specified in level", "");
144 /* --- GAME EVENT! --- */
146 void game_event(void)
148 while (SDL_PollEvent(&event))
152 case SDL_QUIT: /* Quit event - quit: */
155 case SDL_KEYDOWN: /* A keypress! */
156 key = event.key.keysym.sym;
158 /* Check for menu-events, if the menu is shown */
160 menu_event(&event.key.keysym);
162 if(tux.key_event(key,DOWN))
167 case SDLK_ESCAPE: /* Escape: Open/Close the menu: */
170 if(st_gl_mode == ST_GL_TEST)
174 Menu::set_current(game_menu);
176 st_pause_ticks_stop();
180 Menu::set_current(game_menu);
182 st_pause_ticks_start();
190 case SDL_KEYUP: /* A keyrelease! */
191 key = event.key.keysym.sym;
193 if(tux.key_event(key, UP))
204 st_pause_ticks_stop();
209 st_pause_ticks_start();
216 tux.size = !tux.size;
219 tux.base.height = 64;
222 tux.base.height = 32;
239 timer_start(&tux.invincible_timer,TUX_INVINCIBLE_TIME);
259 case SDL_JOYAXISMOTION:
260 switch(event.jaxis.axis)
263 if (event.jaxis.value < -JOYSTICK_DEAD_ZONE)
265 tux.input.left = DOWN;
266 tux.input.right = UP;
268 else if (event.jaxis.value > JOYSTICK_DEAD_ZONE)
271 tux.input.right = DOWN;
275 tux.input.left = DOWN;
276 tux.input.right = DOWN;
280 if (event.jaxis.value > JOYSTICK_DEAD_ZONE)
281 tux.input.down = DOWN;
282 else if (event.jaxis.value < -JOYSTICK_DEAD_ZONE)
287 /* Handle joystick for the menu */
290 if(tux.input.down == DOWN)
291 menuaction = MENU_ACTION_DOWN;
293 menuaction = MENU_ACTION_UP;
300 case SDL_JOYBUTTONDOWN:
301 if (event.jbutton.button == JOY_A)
303 else if (event.jbutton.button == JOY_B)
304 tux.input.fire = DOWN;
306 case SDL_JOYBUTTONUP:
307 if (event.jbutton.button == JOY_A)
309 else if (event.jbutton.button == JOY_B)
313 menuaction = MENU_ACTION_HIT;
324 /* --- GAME ACTION! --- */
326 int game_action(void)
330 /* (tux_dying || next_level) */
331 if (tux.dying || next_level)
333 /* Tux either died, or reached the end of a level! */
340 /* End of a level! */
343 if(st_gl_mode != ST_GL_TEST)
350 level_free(¤t_level);
362 /* No more lives!? */
366 if(st_gl_mode != ST_GL_TEST)
369 if(st_gl_mode != ST_GL_TEST)
371 if (score > hs_score)
375 level_free(¤t_level);
380 } /* if (lives < 0) */
383 /* Either way, (re-)load the (next) level... */
387 level_free(¤t_level);
389 if (st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
391 if(level_load(¤t_level, level_subset) != 0)
396 if(level_load(¤t_level,level_subset,level) != 0)
403 activate_particle_systems();
405 level_load_gfx(¤t_level);
407 level_load_song(¤t_level);
408 if(st_gl_mode != ST_GL_TEST)
412 play_current_music();
417 /* Handle bouncy distros: */
418 for (i = 0; i < bouncy_distros.size(); i++)
420 bouncy_distro_action(&bouncy_distros[i]);
424 /* Handle broken bricks: */
425 for (i = 0; i < broken_bricks.size(); i++)
427 broken_brick_action(&broken_bricks[i]);
431 /* Handle distro counting: */
433 if (counting_distros)
437 if (distro_counter <= 0)
438 counting_distros = -1;
442 /* Handle bouncy bricks: */
444 for (i = 0; i < bouncy_bricks.size(); i++)
446 bouncy_brick_action(&bouncy_bricks[i]);
450 /* Handle floating scores: */
452 for (i = 0; i < floating_scores.size(); i++)
454 floating_score_action(&floating_scores[i]);
458 /* Handle bullets: */
460 for (i = 0; i < bullets.size(); ++i)
462 bullet_action(&bullets[i]);
465 /* Handle upgrades: */
467 for (i = 0; i < upgrades.size(); i++)
469 upgrade_action(&upgrades[i]);
473 /* Handle bad guys: */
475 for (i = 0; i < bad_guys.size(); i++)
477 bad_guys[i].action();
480 /* update particle systems */
481 std::vector<ParticleSystem*>::iterator p;
482 for(p = particle_systems.begin(); p != particle_systems.end(); ++p)
484 (*p)->simulate(frame_ratio);
487 /* Handle all possible collisions. */
493 /* --- GAME DRAW! --- */
500 if (tux.dying && (global_frame_counter % 4) == 0)
501 clearscreen(255, 255, 255);
502 else if(timer_check(&super_bkgd_timer))
503 texture_draw(&img_super_bkgd, 0, 0);
506 /* Draw the real background */
507 if(current_level.bkgd_image[0] != '\0')
509 int s = (int)scroll_x / 30;
510 texture_draw_part(&img_bkgd,s,0,0,0,img_bkgd.w - s, img_bkgd.h);
511 texture_draw_part(&img_bkgd,0,0,screen->w - s ,0,s,img_bkgd.h);
515 clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue);
519 /* Draw particle systems (background) */
520 std::vector<ParticleSystem*>::iterator p;
521 for(p = particle_systems.begin(); p != particle_systems.end(); ++p)
523 (*p)->draw(scroll_x, 0, 0);
526 /* Draw background: */
528 for (y = 0; y < 15; ++y)
530 for (x = 0; x < 21; ++x)
532 drawshape(32*x - fmodf(scroll_x, 32), y * 32,
533 current_level.bg_tiles[(int)y][(int)x + (int)(scroll_x / 32)]);
537 /* Draw interactive tiles: */
539 for (y = 0; y < 15; ++y)
541 for (x = 0; x < 21; ++x)
543 drawshape(32*x - fmodf(scroll_x, 32), y * 32,
544 current_level.ia_tiles[(int)y][(int)x + (int)(scroll_x / 32)]);
548 /* (Bouncy bricks): */
550 for (unsigned int i = 0; i < bouncy_bricks.size(); ++i)
551 bouncy_brick_draw(&bouncy_bricks[i]);
553 for (unsigned int i = 0; i < bad_guys.size(); ++i)
558 for (unsigned int i = 0; i < bullets.size(); ++i)
559 bullet_draw(&bullets[i]);
561 for (unsigned int i = 0; i < floating_scores.size(); ++i)
562 floating_score_draw(&floating_scores[i]);
564 for (unsigned int i = 0; i < upgrades.size(); ++i)
565 upgrade_draw(&upgrades[i]);
567 for (unsigned int i = 0; i < bouncy_distros.size(); ++i)
568 bouncy_distro_draw(&bouncy_distros[i]);
570 for (unsigned int i = 0; i < broken_bricks.size(); ++i)
571 broken_brick_draw(&broken_bricks[i]);
573 /* Draw foreground: */
575 for (y = 0; y < 15; ++y)
577 for (x = 0; x < 21; ++x)
579 drawshape(32*x - fmodf(scroll_x, 32), y * 32,
580 current_level.fg_tiles[(int)y][(int)x + (int)(scroll_x / 32)]);
584 /* Draw particle systems (foreground) */
585 for(p = particle_systems.begin(); p != particle_systems.end(); ++p)
587 (*p)->draw(scroll_x, 0, 1);
594 int x = screen->h / 20;
595 for(int i = 0; i < x; ++i)
597 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);
599 fillrect(0,0,screen->w,screen->h,rand() % 50, rand() % 50, rand() % 50, 128);
600 text_drawf(&blue_text, "PAUSE - Press 'P' To Play", 0, 230, A_HMIDDLE, A_TOP, 1);
604 menu_process_current();
606 /* (Update it all!) */
610 /* --- GAME LOOP! --- */
612 int gameloop(const char * subset, int levelnb, int mode)
614 int fps_cnt, jump, done;
615 timer_type fps_timer, frame_timer;
616 timer_init(&fps_timer, true);
617 timer_init(&frame_timer, true);
628 strcpy(level_subset,subset);
630 if (st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
632 if (level_load(¤t_level, level_subset))
637 if(level_load(¤t_level, level_subset, level) != 0)
641 level_load_gfx(¤t_level);
643 activate_particle_systems();
644 level_load_song(¤t_level);
648 if(st_gl_mode != ST_GL_TEST)
653 if(st_gl_mode == ST_GL_PLAY || st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
656 timer_init(&time_left,true);
659 if(st_gl_mode == ST_GL_LOAD_GAME)
662 /* --- MAIN GAME LOOP!!! --- */
667 global_frame_counter = 0;
669 timer_init(&fps_timer,true);
670 timer_init(&frame_timer,true);
675 clearscreen(0, 0, 0);
679 play_current_music();
682 while (SDL_PollEvent(&event))
690 /* Calculate the movement-factor */
691 frame_ratio = ((double)(update_time-last_update_time))/((double)FRAME_RATE);
692 if(frame_ratio > 1.5) /* Quick hack to correct the unprecise CPU clocks a little bit. */
693 frame_ratio = 1.5 + (frame_ratio - 1.5) * 0.85;
695 if(!timer_check(&frame_timer))
697 timer_start(&frame_timer,25);
698 ++global_frame_counter;
703 tux.input.old_fire = tux.input.fire;
709 if(current_menu == game_menu)
711 switch (game_menu->check())
714 st_pause_ticks_stop();
717 update_load_save_game_menu(save_game_menu, false);
720 update_load_save_game_menu(load_game_menu, true);
723 st_pause_ticks_stop();
728 else if(current_menu == options_menu)
730 process_options_menu();
732 else if(current_menu == save_game_menu )
734 process_save_load_game_menu(true);
736 else if(current_menu == load_game_menu )
738 process_save_load_game_menu(false);
743 /* Handle actions: */
745 if(!game_pause && !show_menu)
747 /*float z = frame_ratio;
751 if (game_action() == 0)
753 /* == 0: no more lives */
754 /* == -1: continues */
766 if(debug_mode && debug_fps)
769 /*Draw the current scene to the screen */
770 /*If the machine running the game is too slow
771 skip the drawing of the frame (so the calculations are more precise and
772 the FPS aren't affected).*/
773 /*if( ! fps_fps < 50.0 )
776 jump = true;*/ /*FIXME: Implement this tweak right.*/
779 /* Time stops in pause mode */
780 if(game_pause || show_menu )
785 /* Set the time of the last update and the time of the current update */
786 last_update_time = update_time;
787 update_time = st_get_ticks();
789 /* Pause till next frame, if the machine running the game is too fast: */
790 /* FIXME: Works great for in OpenGl mode, where the CPU doesn't have to do that much. But
791 the results in SDL mode aren't perfect (thought the 100 FPS are reached), even on an AMD2500+. */
792 if(last_update_time >= update_time - 12 && !jump)
794 /*if((update_time - last_update_time) < 10)
795 SDL_Delay((11 - (update_time - last_update_time))/2);*/
801 if (timer_check(&time_left))
803 /* are we low on time ? */
804 if ((timer_get_left(&time_left) < TIME_WARNING)
805 && (get_current_music() != HURRYUP_MUSIC)) /* play the fast music */
807 set_current_music(HURRYUP_MUSIC);
808 play_current_music();
816 /* Calculate frames per second */
820 fps_fps = (1000.0 / (float)timer_get_gone(&fps_timer)) * (float)fps_cnt;
822 if(!timer_check(&fps_timer))
824 timer_start(&fps_timer,1000);
830 while (!done && !quit);
835 level_free(¤t_level);
840 game_started = false;
846 /* Load graphics/sounds shared between all levels: */
848 void loadshared(void)
853 texture_load(&tux_right[0], datadir + "/images/shared/tux-right-0.png", USE_ALPHA);
854 texture_load(&tux_right[1], datadir + "/images/shared/tux-right-1.png", USE_ALPHA);
855 texture_load(&tux_right[2], datadir + "/images/shared/tux-right-2.png", USE_ALPHA);
857 texture_load(&tux_left[0], datadir + "/images/shared/tux-left-0.png", USE_ALPHA);
858 texture_load(&tux_left[1], datadir + "/images/shared/tux-left-1.png", USE_ALPHA);
859 texture_load(&tux_left[2], datadir + "/images/shared/tux-left-2.png", USE_ALPHA);
861 texture_load(&firetux_right[0], datadir + "/images/shared/firetux-right-0.png", USE_ALPHA);
862 texture_load(&firetux_right[1], datadir + "/images/shared/firetux-right-1.png", USE_ALPHA);
863 texture_load(&firetux_right[2], datadir + "/images/shared/firetux-right-2.png", USE_ALPHA);
865 texture_load(&firetux_left[0], datadir + "/images/shared/firetux-left-0.png", USE_ALPHA);
866 texture_load(&firetux_left[1], datadir + "/images/shared/firetux-left-1.png", USE_ALPHA);
867 texture_load(&firetux_left[2], datadir + "/images/shared/firetux-left-2.png", USE_ALPHA);
870 texture_load(&cape_right[0], datadir + "/images/shared/cape-right-0.png",
873 texture_load(&cape_right[1], datadir + "/images/shared/cape-right-1.png",
876 texture_load(&cape_left[0], datadir + "/images/shared/cape-left-0.png",
879 texture_load(&cape_left[1], datadir + "/images/shared/cape-left-1.png",
882 texture_load(&bigtux_right[0], datadir + "/images/shared/bigtux-right-0.png",
885 texture_load(&bigtux_right[1], datadir + "/images/shared/bigtux-right-1.png",
888 texture_load(&bigtux_right[2], datadir + "/images/shared/bigtux-right-2.png",
891 texture_load(&bigtux_right_jump, datadir + "/images/shared/bigtux-right-jump.png", USE_ALPHA);
893 texture_load(&bigtux_left[0], datadir + "/images/shared/bigtux-left-0.png",
896 texture_load(&bigtux_left[1], datadir + "/images/shared/bigtux-left-1.png",
899 texture_load(&bigtux_left[2], datadir + "/images/shared/bigtux-left-2.png",
902 texture_load(&bigtux_left_jump, datadir + "/images/shared/bigtux-left-jump.png", USE_ALPHA);
904 texture_load(&bigcape_right[0], datadir + "/images/shared/bigcape-right-0.png",
907 texture_load(&bigcape_right[1], datadir + "/images/shared/bigcape-right-1.png",
910 texture_load(&bigcape_left[0], datadir + "/images/shared/bigcape-left-0.png",
913 texture_load(&bigcape_left[1], datadir + "/images/shared/bigcape-left-1.png",
916 texture_load(&bigfiretux_right[0], datadir + "/images/shared/bigfiretux-right-0.png",
919 texture_load(&bigfiretux_right[1], datadir + "/images/shared/bigfiretux-right-1.png",
922 texture_load(&bigfiretux_right[2], datadir + "/images/shared/bigfiretux-right-2.png",
925 texture_load(&bigfiretux_right_jump, datadir + "/images/shared/bigfiretux-right-jump.png", USE_ALPHA);
927 texture_load(&bigfiretux_left[0], datadir + "/images/shared/bigfiretux-left-0.png",
930 texture_load(&bigfiretux_left[1], datadir + "/images/shared/bigfiretux-left-1.png",
933 texture_load(&bigfiretux_left[2], datadir + "/images/shared/bigfiretux-left-2.png",
936 texture_load(&bigfiretux_left_jump, datadir + "/images/shared/bigfiretux-left-jump.png", USE_ALPHA);
938 texture_load(&bigcape_right[0], datadir + "/images/shared/bigcape-right-0.png",
941 texture_load(&bigcape_right[1], datadir + "/images/shared/bigcape-right-1.png",
944 texture_load(&bigcape_left[0], datadir + "/images/shared/bigcape-left-0.png",
947 texture_load(&bigcape_left[1], datadir + "/images/shared/bigcape-left-1.png",
951 texture_load(&ducktux_right, datadir +
952 "/images/shared/ducktux-right.png",
955 texture_load(&ducktux_left, datadir +
956 "/images/shared/ducktux-left.png",
959 texture_load(&skidtux_right, datadir +
960 "/images/shared/skidtux-right.png",
963 texture_load(&skidtux_left, datadir +
964 "/images/shared/skidtux-left.png",
967 texture_load(&duckfiretux_right, datadir +
968 "/images/shared/duckfiretux-right.png",
971 texture_load(&duckfiretux_left, datadir +
972 "/images/shared/duckfiretux-left.png",
975 texture_load(&skidfiretux_right, datadir +
976 "/images/shared/skidfiretux-right.png",
979 texture_load(&skidfiretux_left, datadir +
980 "/images/shared/skidfiretux-left.png",
986 texture_load(&img_box_full, datadir + "/images/shared/box-full.png",
988 texture_load(&img_box_empty, datadir + "/images/shared/box-empty.png",
995 texture_load(&img_water, datadir + "/images/shared/water.png", IGNORE_ALPHA);
997 texture_load(&img_waves[0], datadir + "/images/shared/waves-0.png",
1000 texture_load(&img_waves[1], datadir + "/images/shared/waves-1.png",
1003 texture_load(&img_waves[2], datadir + "/images/shared/waves-2.png",
1009 texture_load(&img_pole, datadir + "/images/shared/pole.png", USE_ALPHA);
1010 texture_load(&img_poletop, datadir + "/images/shared/poletop.png",
1016 texture_load(&img_flag[0], datadir + "/images/shared/flag-0.png",
1018 texture_load(&img_flag[1], datadir + "/images/shared/flag-1.png",
1024 texture_load(&img_cloud[0][0], datadir + "/images/shared/cloud-00.png",
1027 texture_load(&img_cloud[0][1], datadir + "/images/shared/cloud-01.png",
1030 texture_load(&img_cloud[0][2], datadir + "/images/shared/cloud-02.png",
1033 texture_load(&img_cloud[0][3], datadir + "/images/shared/cloud-03.png",
1037 texture_load(&img_cloud[1][0], datadir + "/images/shared/cloud-10.png",
1040 texture_load(&img_cloud[1][1], datadir + "/images/shared/cloud-11.png",
1043 texture_load(&img_cloud[1][2], datadir + "/images/shared/cloud-12.png",
1046 texture_load(&img_cloud[1][3], datadir + "/images/shared/cloud-13.png",
1054 texture_load(&img_bsod_left[0], datadir +
1055 "/images/shared/bsod-left-0.png",
1058 texture_load(&img_bsod_left[1], datadir +
1059 "/images/shared/bsod-left-1.png",
1062 texture_load(&img_bsod_left[2], datadir +
1063 "/images/shared/bsod-left-2.png",
1066 texture_load(&img_bsod_left[3], datadir +
1067 "/images/shared/bsod-left-3.png",
1070 texture_load(&img_bsod_right[0], datadir +
1071 "/images/shared/bsod-right-0.png",
1074 texture_load(&img_bsod_right[1], datadir +
1075 "/images/shared/bsod-right-1.png",
1078 texture_load(&img_bsod_right[2], datadir +
1079 "/images/shared/bsod-right-2.png",
1082 texture_load(&img_bsod_right[3], datadir +
1083 "/images/shared/bsod-right-3.png",
1086 texture_load(&img_bsod_squished_left, datadir +
1087 "/images/shared/bsod-squished-left.png",
1090 texture_load(&img_bsod_squished_right, datadir +
1091 "/images/shared/bsod-squished-right.png",
1094 texture_load(&img_bsod_falling_left, datadir +
1095 "/images/shared/bsod-falling-left.png",
1098 texture_load(&img_bsod_falling_right, datadir +
1099 "/images/shared/bsod-falling-right.png",
1105 texture_load(&img_laptop_left[0], datadir +
1106 "/images/shared/laptop-left-0.png",
1109 texture_load(&img_laptop_left[1], datadir +
1110 "/images/shared/laptop-left-1.png",
1113 texture_load(&img_laptop_left[2], datadir +
1114 "/images/shared/laptop-left-2.png",
1117 texture_load(&img_laptop_right[0], datadir +
1118 "/images/shared/laptop-right-0.png",
1121 texture_load(&img_laptop_right[1], datadir +
1122 "/images/shared/laptop-right-1.png",
1125 texture_load(&img_laptop_right[2], datadir +
1126 "/images/shared/laptop-right-2.png",
1129 texture_load(&img_laptop_flat_left, datadir +
1130 "/images/shared/laptop-flat-left.png",
1133 texture_load(&img_laptop_flat_right, datadir +
1134 "/images/shared/laptop-flat-right.png",
1137 texture_load(&img_laptop_falling_left, datadir +
1138 "/images/shared/laptop-falling-left.png",
1141 texture_load(&img_laptop_falling_right, datadir +
1142 "/images/shared/laptop-falling-right.png",
1148 texture_load(&img_money_left[0], datadir +
1149 "/images/shared/bag-left-0.png",
1152 texture_load(&img_money_left[1], datadir +
1153 "/images/shared/bag-left-1.png",
1156 texture_load(&img_money_right[0], datadir +
1157 "/images/shared/bag-right-0.png",
1160 texture_load(&img_money_right[1], datadir +
1161 "/images/shared/bag-right-1.png",
1168 texture_load(&img_mints, datadir + "/images/shared/mints.png", USE_ALPHA);
1169 texture_load(&img_coffee, datadir + "/images/shared/coffee.png", USE_ALPHA);
1174 texture_load(&img_bullet, datadir + "/images/shared/bullet.png", USE_ALPHA);
1176 texture_load(&img_red_glow, datadir + "/images/shared/red-glow.png",
1183 texture_load(&img_distro[0], datadir + "/images/shared/distro-0.png",
1186 texture_load(&img_distro[1], datadir + "/images/shared/distro-1.png",
1189 texture_load(&img_distro[2], datadir + "/images/shared/distro-2.png",
1192 texture_load(&img_distro[3], datadir + "/images/shared/distro-3.png",
1198 texture_load(&tux_life, datadir + "/images/shared/tux-life.png",
1203 texture_load(&img_golden_herring, datadir + "/images/shared/golden-herring.png",
1207 /* Super background: */
1209 texture_load(&img_super_bkgd, datadir + "/images/shared/super-bkgd.png",
1213 /* Sound effects: */
1215 /* if (use_sound) // this will introduce SERIOUS bugs here ! because "load_sound"
1216 // initialize sounds[i] with the correct pointer's value:
1217 // NULL or something else. And it will be dangerous to
1218 // play with not-initialized pointers.
1219 // This is also true with if (use_music)
1220 Send a mail to me: neoneurone@users.sf.net, if you have another opinion. :)
1222 for (i = 0; i < NUM_SOUNDS; i++)
1223 sounds[i] = load_sound(datadir + soundfilenames[i]);
1226 herring_song = load_song(datadir + "/music/SALCON.MOD");
1230 /* Free shared data: */
1232 void unloadshared(void)
1236 for (i = 0; i < 3; i++)
1238 texture_free(&tux_right[i]);
1239 texture_free(&tux_left[i]);
1240 texture_free(&bigtux_right[i]);
1241 texture_free(&bigtux_left[i]);
1244 texture_free(&bigtux_right_jump);
1245 texture_free(&bigtux_left_jump);
1247 for (i = 0; i < 2; i++)
1249 texture_free(&cape_right[i]);
1250 texture_free(&cape_left[i]);
1251 texture_free(&bigcape_right[i]);
1252 texture_free(&bigcape_left[i]);
1255 texture_free(&ducktux_left);
1256 texture_free(&ducktux_right);
1258 texture_free(&skidtux_left);
1259 texture_free(&skidtux_right);
1261 for (i = 0; i < 4; i++)
1263 texture_free(&img_bsod_left[i]);
1264 texture_free(&img_bsod_right[i]);
1267 texture_free(&img_bsod_squished_left);
1268 texture_free(&img_bsod_squished_right);
1270 texture_free(&img_bsod_falling_left);
1271 texture_free(&img_bsod_falling_right);
1273 for (i = 0; i < 3; i++)
1275 texture_free(&img_laptop_left[i]);
1276 texture_free(&img_laptop_right[i]);
1279 texture_free(&img_laptop_flat_left);
1280 texture_free(&img_laptop_flat_right);
1282 texture_free(&img_laptop_falling_left);
1283 texture_free(&img_laptop_falling_right);
1285 for (i = 0; i < 2; i++)
1287 texture_free(&img_money_left[i]);
1288 texture_free(&img_money_right[i]);
1291 texture_free(&img_box_full);
1292 texture_free(&img_box_empty);
1294 texture_free(&img_water);
1295 for (i = 0; i < 3; i++)
1296 texture_free(&img_waves[i]);
1298 texture_free(&img_pole);
1299 texture_free(&img_poletop);
1301 for (i = 0; i < 2; i++)
1302 texture_free(&img_flag[i]);
1304 texture_free(&img_mints);
1305 texture_free(&img_coffee);
1307 for (i = 0; i < 4; i++)
1309 texture_free(&img_distro[i]);
1310 texture_free(&img_cloud[0][i]);
1311 texture_free(&img_cloud[1][i]);
1314 texture_free(&img_golden_herring);
1316 for (i = 0; i < NUM_SOUNDS; i++)
1317 free_chunk(sounds[i]);
1319 /* free the herring song */
1320 free_music( herring_song );
1324 /* Draw a tile on the screen: */
1326 void drawshape(float x, float y, unsigned int c)
1330 Tile* ptile = TileManager::instance()->get(c);
1333 if(ptile->images.size() > 1)
1335 texture_draw(&ptile->images[( ((global_frame_counter*25) / ptile->anim_speed) % (ptile->images.size()))],x,y);
1337 else if (ptile->images.size() == 1)
1339 texture_draw(&ptile->images[0],x,y);
1343 printf("Tile not dravable %u\n", c);
1349 if (c == 'X' || c == 'x')
1350 texture_draw(&img_brick[0], x, y);
1351 else if (c == 'Y' || c == 'y')
1352 texture_draw(&img_brick[1], x, y);
1353 else if (c == 'A' || c =='B' || c == '!')
1354 texture_draw(&img_box_full, x, y);
1356 texture_draw(&img_box_empty, x, y);
1357 else if (c >= 'C' && c <= 'F')
1358 texture_draw(&img_cloud[0][c - 'C'], x, y);
1359 else if (c >= 'c' && c <= 'f')
1360 texture_draw(&img_cloud[1][c - 'c'], x, y);
1361 else if (c >= 'G' && c <= 'J')
1362 texture_draw(&img_bkgd_tile[0][c - 'G'], x, y);
1363 else if (c >= 'g' && c <= 'j')
1364 texture_draw(&img_bkgd_tile[1][c - 'g'], x, y);
1366 texture_draw(&img_solid[0], x, y);
1368 texture_draw(&img_solid[1], x, y);
1370 texture_draw(&img_solid[2], x, y);
1372 texture_draw(&img_solid[3], x, y);
1375 z = (global_frame_counter / 2) % 6;
1378 texture_draw(&img_distro[z], x, y);
1380 texture_draw(&img_distro[2], x, y);
1382 texture_draw(&img_distro[1], x, y);
1386 z = (global_frame_counter / 3) % 3;
1388 texture_draw(&img_waves[z], x, y);
1391 texture_draw(&img_poletop, x, y);
1394 texture_draw(&img_pole, x, y);
1399 z = (global_frame_counter / 3) % 2;
1401 texture_draw(&img_flag[z], x + 16, y);
1404 texture_draw(&img_water, x, y);*/
1409 /* What shape is at some position? */
1410 unsigned int shape(float x, float y)
1419 if (yy >= 0 && yy < 15 && xx >= 0 && xx <= current_level.width)
1421 c = current_level.ia_tiles[yy][xx];
1429 Tile* gettile(float x, float y)
1431 return TileManager::instance()->get(shape(x, y));
1437 bool issolid(float x, float y)
1439 Tile* tile = TileManager::instance()->get
1443 if(tile->solid == true)
1454 /* Is it a brick? */
1456 bool isbrick(float x, float y)
1458 Tile* tile = TileManager::instance()->get
1462 if(tile->brick == true)
1476 bool isice(float x, float y)
1478 Tile* tile = TileManager::instance()->get
1482 if(tile->ice == true)
1493 /* Is it a full box? */
1495 bool isfullbox(float x, float y)
1497 Tile* tile = TileManager::instance()->get
1501 if(tile->fullbox == true)
1512 bool isdistro(float x, float y)
1514 Tile* tile = TileManager::instance()->get(shape(x,y));
1515 return tile && tile->distro;
1518 /* Break a brick: */
1520 void trybreakbrick(float x, float y)
1522 Tile* tile = gettile(x, y);
1527 /* Get a distro from it: */
1528 add_bouncy_distro(((int)(x + 1) / 32) * 32,
1529 (int)(y / 32) * 32);
1531 if (!counting_distros)
1533 counting_distros = true;
1534 distro_counter = 50;
1537 if (distro_counter <= 0)
1538 level_change(¤t_level,x, y, TM_IA, tile->next_tile2);
1540 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1541 score = score + SCORE_DISTRO;
1546 /* Get rid of it: */
1547 level_change(¤t_level,x, y, TM_IA, tile->next_tile);
1551 /* Replace it with broken bits: */
1553 add_broken_brick(((int)(x + 1) / 32) * 32,
1554 (int)(y / 32) * 32);
1557 /* Get some score: */
1559 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
1560 score = score + SCORE_BRICK;
1565 /* Bounce a brick: */
1567 void bumpbrick(float x, float y)
1569 add_bouncy_brick(((int)(x + 1) / 32) * 32,
1570 (int)(y / 32) * 32);
1572 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
1579 void tryemptybox(float x, float y, int col_side)
1581 Tile* tile = gettile(x,y);
1585 // according to the collision side, set the upgrade direction
1587 if(col_side == LEFT)
1592 // FIXME: Content of boxes must be handled otherwise
1595 case 1: //'A': /* Box with a distro! */
1596 add_bouncy_distro(((int)(x + 1) / 32) * 32, (int)(y / 32) * 32 - 32);
1597 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1598 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);
1608 case 3:// '!': /* Add a golden herring */
1609 add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_HERRING);
1615 /* Empty the box: */
1616 level_change(¤t_level,x, y, TM_IA, tile->next_tile);
1620 /* Try to grab a distro: */
1622 void trygrabdistro(float x, float y, int bounciness)
1624 Tile* tile = gettile(x, y);
1625 if (tile && tile->distro)
1627 level_change(¤t_level,x, y, TM_IA, tile->next_tile);
1628 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1630 if (bounciness == BOUNCE)
1632 add_bouncy_distro(((int)(x + 1) / 32) * 32,
1633 (int)(y / 32) * 32);
1636 score = score + SCORE_DISTRO;
1641 /* Try to bump a bad guy from below: */
1643 void trybumpbadguy(float x, float y)
1648 for (i = 0; i < bad_guys.size(); i++)
1650 if (bad_guys[i].base.x >= x - 32 && bad_guys[i].base.x <= x + 32 &&
1651 bad_guys[i].base.y >= y - 16 && bad_guys[i].base.y <= y + 16)
1653 if (bad_guys[i].kind == BAD_BSOD ||
1654 bad_guys[i].kind == BAD_LAPTOP)
1656 bad_guys[i].dying = DYING_FALLING;
1657 bad_guys[i].base.ym = -8;
1658 play_sound(sounds[SND_FALL], SOUND_CENTER_SPEAKER);
1665 for (i = 0; i < upgrades.size(); i++)
1667 if (upgrades[i].base.height == 32 &&
1668 upgrades[i].base.x >= x - 32 && upgrades[i].base.x <= x + 32 &&
1669 upgrades[i].base.y >= y - 16 && upgrades[i].base.y <= y + 16)
1671 upgrades[i].base.xm = -upgrades[i].base.xm;
1672 upgrades[i].base.ym = -8;
1673 play_sound(sounds[SND_BUMP_UPGRADE], SOUND_CENTER_SPEAKER);
1679 void drawstatus(void)
1683 sprintf(str, "%d", score);
1684 text_draw(&white_text, "SCORE", 0, 0, 1);
1685 text_draw(&gold_text, str, 96, 0, 1);
1687 if(st_gl_mode != ST_GL_TEST)
1689 sprintf(str, "%d", hs_score);
1690 text_draw(&white_text, "HIGH", 0, 20, 1);
1691 text_draw(&gold_text, str, 96, 20, 1);
1695 text_draw(&white_text,"Press ESC To Return",0,20,1);
1698 if (timer_get_left(&time_left) > TIME_WARNING || (global_frame_counter % 10) < 5)
1700 sprintf(str, "%d", timer_get_left(&time_left) / 1000 );
1701 text_draw(&white_text, "TIME", 224, 0, 1);
1702 text_draw(&gold_text, str, 304, 0, 1);
1705 sprintf(str, "%d", distros);
1706 text_draw(&white_text, "DISTROS", screen->h, 0, 1);
1707 text_draw(&gold_text, str, 608, 0, 1);
1709 text_draw(&white_text, "LIVES", screen->h, 20, 1);
1713 sprintf(str, "%2.1f", fps_fps);
1714 text_draw(&white_text, "FPS", screen->h, 40, 1);
1715 text_draw(&gold_text, str, screen->h + 60, 40, 1);
1718 for(int i=0; i < tux.lives; ++i)
1720 texture_draw(&tux_life,565+(18*i),20);
1725 void drawendscreen(void)
1729 clearscreen(0, 0, 0);
1731 text_drawf(&blue_text, "GAMEOVER", 0, 200, A_HMIDDLE, A_TOP, 1);
1733 sprintf(str, "SCORE: %d", score);
1734 text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1);
1736 sprintf(str, "DISTROS: %d", distros);
1737 text_drawf(&gold_text, str, 0, 256, A_HMIDDLE, A_TOP, 1);
1743 void drawresultscreen(void)
1747 clearscreen(0, 0, 0);
1749 text_drawf(&blue_text, "Result:", 0, 200, A_HMIDDLE, A_TOP, 1);
1751 sprintf(str, "SCORE: %d", score);
1752 text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1);
1754 sprintf(str, "DISTROS: %d", distros);
1755 text_drawf(&gold_text, str, 0, 256, A_HMIDDLE, A_TOP, 1);
1761 void savegame(int slot)
1763 char savefile[1024];
1767 sprintf(savefile,"%s/slot%d.save",st_save_dir,slot);
1769 fi = fopen(savefile, "wb");
1773 fprintf(stderr, "Warning: I could not open the slot file ");
1778 fputs(level_subset, fi);
1780 fwrite(&level,sizeof(int),1,fi);
1781 fwrite(&score,sizeof(int),1,fi);
1782 fwrite(&distros,sizeof(int),1,fi);
1783 fwrite(&scroll_x,sizeof(float),1,fi);
1784 fwrite(&tux,sizeof(Player),1,fi);
1785 timer_fwrite(&tux.invincible_timer,fi);
1786 timer_fwrite(&tux.skidding_timer,fi);
1787 timer_fwrite(&tux.safe_timer,fi);
1788 timer_fwrite(&tux.frame_timer,fi);
1789 timer_fwrite(&time_left,fi);
1790 ui = st_get_ticks();
1791 fwrite(&ui,sizeof(int),1,fi);
1797 void loadgame(int slot)
1799 char savefile[1024];
1804 sprintf(savefile,"%s/slot%d.save",st_save_dir,slot);
1806 fi = fopen(savefile, "rb");
1810 fprintf(stderr, "Warning: I could not open the slot file ");
1815 fgets(str, 100, fi);
1816 strcpy(level_subset, str);
1817 level_subset[strlen(level_subset)-1] = '\0';
1818 fread(&level,sizeof(int),1,fi);
1821 level_free(¤t_level);
1822 if(level_load(¤t_level,level_subset,level) != 0)
1826 activate_bad_guys();
1827 activate_particle_systems();
1829 level_load_gfx(¤t_level);
1831 level_load_song(¤t_level);
1833 update_time = st_get_ticks();
1835 fread(&score,sizeof(int),1,fi);
1836 fread(&distros,sizeof(int),1,fi);
1837 fread(&scroll_x,sizeof(float),1,fi);
1838 fread(&tux, sizeof(Player), 1, fi);
1839 timer_fread(&tux.invincible_timer,fi);
1840 timer_fread(&tux.skidding_timer,fi);
1841 timer_fread(&tux.safe_timer,fi);
1842 timer_fread(&tux.frame_timer,fi);
1843 timer_fread(&time_left,fi);
1844 fread(&ui,sizeof(int),1,fi);
1845 tux.hphysic.start_time += st_get_ticks() - ui;
1846 tux.vphysic.start_time += st_get_ticks() - ui;
1852 void slotinfo(char **pinfo, int slot)
1855 char slotfile[1024];
1859 sprintf(slotfile,"%s/slot%d.save",st_save_dir,slot);
1861 fi = fopen(slotfile, "rb");
1863 sprintf(tmp,"Slot %d - ",slot);
1871 fgets(str, 100, fi);
1872 str[strlen(str)-1] = '\0';
1874 strcat(tmp, " / Level:");
1875 fread(&slot_level,sizeof(int),1,fi);
1876 sprintf(str,"%d",slot_level);
1881 *pinfo = (char*) malloc(sizeof(char) * (strlen(tmp)+1));