7 bill@newbreedsoftware.com
8 http://www.newbreedsoftware.com/supertux/
10 April 11, 2000 - December 9, 2003
19 #include <SDL_image.h>
22 #include <SDL_mixer.h>
27 #include <sys/types.h>
60 char * soundfilenames[NUM_SOUNDS] = {
61 DATA_PREFIX "/sounds/jump.wav",
62 DATA_PREFIX "/sounds/bigjump.wav",
63 DATA_PREFIX "/sounds/skid.wav",
64 DATA_PREFIX "/sounds/distro.wav",
65 DATA_PREFIX "/sounds/herring.wav",
66 DATA_PREFIX "/sounds/brick.wav",
67 DATA_PREFIX "/sounds/hurt.wav",
68 DATA_PREFIX "/sounds/squish.wav",
69 DATA_PREFIX "/sounds/fall.wav",
70 DATA_PREFIX "/sounds/ricochet.wav",
71 DATA_PREFIX "/sounds/bump-upgrade.wav",
72 DATA_PREFIX "/sounds/upgrade.wav",
73 DATA_PREFIX "/sounds/excellent.wav",
74 DATA_PREFIX "/sounds/coffee.wav",
75 DATA_PREFIX "/sounds/shoot.wav"
79 /* Local variables: */
81 int score, distros, level, lives, scroll_x, next_level,
82 tux_dir, tux_size, tux_duck, tux_x, tux_xm, tux_y, tux_ym,
83 tux_dying, tux_safe, jumping, jump_counter, frame, score_multiplier,
84 tux_frame_main, tux_frame, tux_got_coffee, tux_skidding,
85 super_bkgd_time, time_left, tux_invincible_time, endpos,
86 counting_distros, distro_counter;
87 int bkgd_red, bkgd_green, bkgd_blue, level_width;
88 int left, right, up, down, fire, old_fire;
89 SDL_Surface * img_brick[2], * img_solid[4], * img_distro[4],
90 * img_waves[3], * img_water, * img_pole, * img_poletop, * img_flag[2];
91 SDL_Surface * img_bkgd[2][4];
92 SDL_Surface * img_golden_herring;
93 SDL_Surface * img_bsod_left[4], * img_bsod_right[4],
94 * img_laptop_left[3], * img_laptop_right[3],
95 * img_money_left[2], * img_money_right[2];
96 SDL_Surface * img_bsod_squished_left, * img_bsod_squished_right,
97 * img_bsod_falling_left, * img_bsod_falling_right,
98 * img_laptop_flat_left, * img_laptop_flat_right,
99 * img_laptop_falling_left, * img_laptop_falling_right;
100 SDL_Surface * img_box_full, * img_box_empty, * img_mints, * img_coffee,
101 * img_super_bkgd, * img_bullet, * img_red_glow;
102 SDL_Surface * img_cloud[2][4];
103 SDL_Surface * tux_right[3], * tux_left[3],
104 * bigtux_right[3], * bigtux_left[3],
105 * bigtux_right_jump, * bigtux_left_jump,
106 * cape_right[2], * cape_left[2],
107 * bigcape_right[2], * bigcape_left[2],
108 * ducktux_right, * ducktux_left,
109 * skidtux_right, * skidtux_left;
111 Mix_Chunk * sounds[NUM_SOUNDS];
114 unsigned char * tiles[15];
115 bouncy_distro_type bouncy_distros[NUM_BOUNCY_DISTROS];
116 broken_brick_type broken_bricks[NUM_BROKEN_BRICKS];
117 bouncy_brick_type bouncy_bricks[NUM_BOUNCY_BRICKS];
118 bad_guy_type bad_guys[NUM_BAD_GUYS];
119 floating_score_type floating_scores[NUM_FLOATING_SCORES];
120 upgrade_type upgrades[NUM_UPGRADES];
121 bullet_type bullets[NUM_BULLETS];
126 /* Local function prototypes: */
129 void loadlevel(void);
130 void loadlevelgfx(void);
131 void loadlevelsong(void);
132 void unloadlevelgfx(void);
133 void unloadlevelsong(void);
134 void loadshared(void);
135 void unloadshared(void);
136 void drawshape(int x, int y, unsigned char c);
137 unsigned char shape(int x, int y, int sx);
138 int issolid(int x, int y, int sx);
139 int isbrick(int x, int y, int sx);
140 int isice(int x, int y, int sx);
141 int isfullbox(int x, int y, int sx);
142 void change(int x, int y, int sx, unsigned char c);
143 void trybreakbrick(int x, int y, int sx);
144 void bumpbrick(int x, int y, int sx);
145 void tryemptybox(int x, int y, int sx);
146 void trygrabdistro(int x, int y, int sx, int bounciness);
147 void add_bouncy_distro(int x, int y);
148 void add_broken_brick(int x, int y);
149 void add_broken_brick_piece(int x, int y, int xm, int ym);
150 void add_bouncy_brick(int x, int y);
151 void add_bad_guy(int x, int y, int kind);
152 void add_score(int x, int y, int s);
153 void trybumpbadguy(int x, int y, int sx);
154 void add_upgrade(int x, int y, int kind);
155 void killtux(int mode);
156 void add_bullet(int x, int y, int dir, int xm);
159 /* --- GAME LOOP! --- */
163 int done, quit, x, y, i, j;
167 Uint32 last_time, now_time;
173 clearscreen(0, 0, 0);
186 /* --- MAIN GAME LOOP!!! --- */
196 last_time = SDL_GetTicks();
204 while (SDL_PollEvent(&event))
206 if (event.type == SDL_QUIT)
208 /* Quit event - quit: */
212 else if (event.type == SDL_KEYDOWN)
216 key = event.key.keysym.sym;
218 if (key == SDLK_ESCAPE)
220 /* Escape: Quit the game and return to main menu: */
224 else if (key == SDLK_RIGHT)
228 else if (key == SDLK_LEFT)
232 else if (key == SDLK_UP)
236 else if (key == SDLK_DOWN)
240 else if (key == SDLK_LCTRL)
245 else if (event.type == SDL_KEYUP)
249 key = event.key.keysym.sym;
251 if (key == SDLK_RIGHT)
255 else if (key == SDLK_LEFT)
259 else if (key == SDLK_UP)
263 else if (key == SDLK_DOWN)
267 else if (key == SDLK_LCTRL)
271 else if (key == SDLK_TAB)
273 tux_size = !tux_size;
277 else if (event.type == SDL_JOYAXISMOTION)
279 if (event.jaxis.axis == JOY_X)
281 if (event.jaxis.value < -256)
286 if (event.jaxis.value > 256)
291 else if (event.jaxis.axis == JOY_Y)
293 if (event.jaxis.value > 256)
299 else if (event.type == SDL_JOYBUTTONDOWN)
301 if (event.jbutton.button == JOY_A)
303 else if (event.jbutton.button == JOY_B)
306 else if (event.type == SDL_JOYBUTTONUP)
308 if (event.jbutton.button == JOY_A)
310 else if (event.jbutton.button == JOY_B)
317 /* --- HANDLE TUX! --- */
319 /* Handle key and joystick state: */
321 if (!tux_dying && !next_level)
323 if (right == DOWN && left == UP)
327 if (tux_xm < -SKID_XM && !tux_skidding &&
330 tux_skidding = SKID_TIME;
332 playsound(sounds[SND_SKID]);
338 if (tux_xm < 0 && !isice(tux_x, tux_y + 32, scroll_x) &&
346 if (tux_dir == RIGHT)
348 /* Facing the direction we're jumping? Go full-speed: */
352 tux_xm = tux_xm + WALK_SPEED;
354 if (tux_xm > MAX_WALK_XM)
355 tux_xm = MAX_WALK_XM;
357 else if (fire == DOWN)
359 tux_xm = tux_xm + RUN_SPEED;
361 if (tux_xm > MAX_RUN_XM)
367 /* Not facing the direction we're jumping?
370 tux_xm = tux_xm + WALK_SPEED / 2;
372 if (tux_xm > MAX_WALK_XM / 2)
373 tux_xm = MAX_WALK_XM / 2;
377 else if (left == DOWN && right == UP)
381 if (tux_xm > SKID_XM && !tux_skidding &&
384 tux_skidding = SKID_TIME;
386 playsound(sounds[SND_SKID]);
392 if (tux_xm > 0 && !isice(tux_x, tux_y + 32, scroll_x) &&
402 /* Facing the direction we're jumping? Go full-speed: */
406 tux_xm = tux_xm - WALK_SPEED;
408 if (tux_xm < -MAX_WALK_XM)
409 tux_xm = -MAX_WALK_XM;
411 else if (fire == DOWN)
413 tux_xm = tux_xm - RUN_SPEED;
415 if (tux_xm < -MAX_RUN_XM)
416 tux_xm = -MAX_RUN_XM;
421 /* Not facing the direction we're jumping?
424 tux_xm = tux_xm - WALK_SPEED / 2;
426 if (tux_xm < -MAX_WALK_XM / 2)
427 tux_xm = -MAX_WALK_XM / 2;
435 if (tux_x >= endpos && endpos != 0)
437 /* FIXME: No need to kill Tux to end the level! ;^) */
447 if (jump_counter == 0)
451 if (!issolid(tux_x, tux_y + 32, scroll_x) ||
454 /* If they're not on the ground, or are currently moving
455 vertically, don't jump! */
457 jump_counter = MAX_JUMP_COUNT;
461 /* Make sure we're not standing back up into a solid! */
463 if (tux_size == SMALL || tux_duck == NO ||
464 !issolid(tux_x, tux_y, scroll_x))
469 if (tux_size == SMALL)
470 playsound(sounds[SND_JUMP]);
472 playsound(sounds[SND_BIGJUMP]);
479 /* Keep jumping for a while: */
481 if (jump_counter < MAX_JUMP_COUNT)
483 tux_ym = tux_ym - JUMP_SPEED;
493 if (fire == DOWN && old_fire == UP && tux_got_coffee)
495 add_bullet(tux_x + scroll_x, tux_y, tux_dir, tux_xm);
508 if (tux_size == BIG && tux_duck == YES)
510 /* Make sure we're not standing back up into a solid! */
512 if (!issolid(tux_x, tux_y - 32, scroll_x))
518 } /* !tux_dying && !next_level */
521 /* Tux either died, or reached the end of a level! */
523 tux_ym = tux_ym + GRAVITY;
530 if (Mix_PlayingMusic())
537 /* End of a level! */
550 /* No more lives!? */
556 /* Display end-of-level stuff */
557 /* (FIXME: This should go in its own event loop function!) */
559 clearscreen(0, 0, 0);
561 drawcenteredtext("GAMEOVER", 200, letters_red, NO_UPDATE);
563 sprintf(str, "SCORE: %d", score);
564 drawcenteredtext(str, 224, letters_gold, NO_UPDATE);
566 sprintf(str, "DISTROS: %d", distros);
567 drawcenteredtext(str, 256, letters_blue, NO_UPDATE);
573 /* FIXME: Should return to title screen, not restart game... */
583 /* Either way, (re-)load the (next) level... */
594 tux_x = tux_x + tux_xm;
595 tux_y = tux_y + tux_ym;
598 /* Keep tux in bounds: */
602 else if (tux_x > 320 && scroll_x < ((level_width * 32) - 640))
604 /* Scroll the screen in past center: */
606 scroll_x = scroll_x + (tux_x - 320);
609 if (scroll_x > ((level_width * 32) - 640))
610 scroll_x = ((level_width * 32) - 640);
612 else if (tux_x > 608)
614 /* ... unless there's no more to scroll! */
624 if (issolid(tux_x, tux_y + 31, scroll_x) &&
625 !issolid(tux_x - tux_xm, tux_y + 31, scroll_x))
627 while (issolid(tux_x, tux_y + 31, scroll_x))
638 if (issolid(tux_x, tux_y, scroll_x) &&
639 !issolid(tux_x - tux_xm, tux_y, scroll_x))
641 while (issolid(tux_x, tux_y, scroll_x))
652 if (issolid(tux_x, tux_y + 31, scroll_x))
654 /* Set down properly: */
656 while (issolid(tux_x, tux_y + 31, scroll_x))
665 /* Reset score multiplier (for mutli-hits): */
668 score_multiplier = 1;
678 /* Bump into things: */
680 if (issolid(tux_x, tux_y, scroll_x) ||
681 (tux_size == BIG && !tux_duck &&
682 (issolid(tux_x, tux_y - 32, scroll_x))))
684 if (!issolid(tux_x - tux_xm, tux_y, scroll_x) &&
685 (tux_size == SMALL || tux_duck ||
686 !issolid(tux_x - tux_xm, tux_y - 32, scroll_x)))
688 tux_x = tux_x - tux_xm;
691 else if (!issolid(tux_x, tux_y - tux_ym, scroll_x) &&
692 (tux_size == SMALL || tux_duck ||
693 !issolid(tux_x, tux_y - 32 - tux_ym, scroll_x)))
701 /* Break bricks and empty boxes: */
705 if (isbrick(tux_x, tux_y - 32, scroll_x) ||
706 isfullbox(tux_x, tux_y - 32, scroll_x))
708 trygrabdistro(tux_x, tux_y - 64, scroll_x,
710 trybumpbadguy(tux_x, tux_y - 96, scroll_x);
712 if (isfullbox(tux_x, tux_y - 32,
715 bumpbrick(tux_x, tux_y - 32,
719 trybreakbrick(tux_x, tux_y - 32, scroll_x);
720 tryemptybox(tux_x, tux_y - 32, scroll_x);
723 if (isbrick(tux_x + 31, tux_y - 32, scroll_x) ||
724 isfullbox(tux_x + 31, tux_y - 32, scroll_x))
726 trygrabdistro(tux_x + 31,
730 trybumpbadguy(tux_x + 31,
734 if (isfullbox(tux_x + 31, tux_y - 32,
737 bumpbrick(tux_x + 31, tux_y - 32,
741 trybreakbrick(tux_x + 31,
744 tryemptybox(tux_x + 31,
751 if (isbrick(tux_x, tux_y, scroll_x) ||
752 isfullbox(tux_x, tux_y, scroll_x))
754 trygrabdistro(tux_x, tux_y - 32, scroll_x,
756 trybumpbadguy(tux_x, tux_y - 64, scroll_x);
757 if (isfullbox(tux_x, tux_y, scroll_x))
758 bumpbrick(tux_x, tux_y, scroll_x);
759 trybreakbrick(tux_x, tux_y, scroll_x);
760 tryemptybox(tux_x, tux_y, scroll_x);
763 if (isbrick(tux_x + 31, tux_y, scroll_x) ||
764 isfullbox(tux_x + 31, tux_y, scroll_x))
766 trygrabdistro(tux_x + 31,
770 trybumpbadguy(tux_x + 31,
773 if (isfullbox(tux_x + 31, tux_y, scroll_x))
774 bumpbrick(tux_x + 31, tux_y, scroll_x);
775 trybreakbrick(tux_x + 31, tux_y, scroll_x);
776 tryemptybox(tux_x + 31, tux_y, scroll_x);
782 /* It's a brick and we're small, make the brick
783 bounce, and grab any distros above it: */
785 if (isbrick(tux_x, tux_y, scroll_x) ||
786 isfullbox(tux_x, tux_y, scroll_x))
788 trygrabdistro(tux_x, tux_y - 32, scroll_x,
790 trybumpbadguy(tux_x, tux_y - 64, scroll_x);
791 bumpbrick(tux_x, tux_y, scroll_x);
792 tryemptybox(tux_x, tux_y, scroll_x);
795 if (isbrick(tux_x + 31, tux_y, scroll_x) ||
796 isfullbox(tux_x + 31, tux_y, scroll_x))
798 trygrabdistro(tux_x + 31, tux_y - 32, scroll_x,
800 trybumpbadguy(tux_x + 31, tux_y - 64, scroll_x);
801 bumpbrick(tux_x + 31, tux_y, scroll_x);
802 tryemptybox(tux_x + 31, tux_y, scroll_x);
806 /* Get a distro from a brick? */
808 if (shape(tux_x, tux_y, scroll_x) == 'x' ||
809 shape(tux_x, tux_y, scroll_x) == 'y')
811 add_bouncy_distro(((tux_x + scroll_x + 1)
815 if (counting_distros == NO)
817 counting_distros = YES;
818 distro_counter = 100;
821 if (distro_counter <= 0)
822 change(tux_x, tux_y, scroll_x, 'a');
825 playsound(sounds[SND_DISTRO]);
827 score = score + SCORE_DISTRO;
830 else if (shape(tux_x + 31, tux_y, scroll_x) == 'x' ||
831 shape(tux_x + 31, tux_y, scroll_x) == 'y')
833 add_bouncy_distro(((tux_x + scroll_x + 1 + 31)
837 if (counting_distros == NO)
839 counting_distros = YES;
840 distro_counter = 100;
843 if (distro_counter <= 0)
844 change(tux_x + 31, tux_y, scroll_x, 'a');
847 playsound(sounds[SND_DISTRO]);
849 score = score + SCORE_DISTRO;
857 tux_y = (tux_y / 32) * 32 + 30;
863 tux_y = (tux_y / 32) * 32 - 32;
868 jump_counter = MAX_JUMP_COUNT;
878 trygrabdistro(tux_x, tux_y, scroll_x, NO_BOUNCE);
879 trygrabdistro(tux_x + 31, tux_y, scroll_x, NO_BOUNCE);
881 if (tux_size == BIG && !tux_duck)
883 trygrabdistro(tux_x, tux_y - 32, scroll_x, NO_BOUNCE);
884 trygrabdistro(tux_x + 31, tux_y - 32, scroll_x, NO_BOUNCE);
889 /* Enough distros for a One-up? */
891 if (distros >= DISTROS_LIFEUP)
893 /* FIXME: Play a special sound or flash or both! */
895 distros = distros - DISTROS_LIFEUP;
900 /* Keep in-bounds, vertically: */
904 else if (tux_y > 480)
910 /* Slow down horizontally: */
914 if (right == UP && left == UP)
916 if (isice(tux_x, tux_y + 32, scroll_x) ||
917 !issolid(tux_x, tux_y + 32, scroll_x))
919 /* Slowly on ice or in air: */
928 /* Quickly, otherwise: */
935 /* Drop vertically: */
937 if (!issolid(tux_x, tux_y + 32, scroll_x))
939 tux_ym = tux_ym + GRAVITY;
951 /* ---- DONE HANDLING TUX! --- */
954 /* Handle bouncy distros: */
956 for (i = 0; i < NUM_BOUNCY_DISTROS; i++)
958 if (bouncy_distros[i].alive)
960 bouncy_distros[i].y = bouncy_distros[i].y + bouncy_distros[i].ym;
962 bouncy_distros[i].ym++;
964 if (bouncy_distros[i].ym >= 0)
965 bouncy_distros[i].alive = NO;
970 /* Handle broken bricks: */
972 for (i = 0; i < NUM_BROKEN_BRICKS; i++)
974 if (broken_bricks[i].alive)
976 broken_bricks[i].x = broken_bricks[i].x + broken_bricks[i].xm;
977 broken_bricks[i].y = broken_bricks[i].y + broken_bricks[i].ym;
979 broken_bricks[i].ym++;
981 if (broken_bricks[i].ym >= 0)
982 broken_bricks[i].alive = NO;
987 /* Handle distro counting: */
989 if (counting_distros == YES)
993 if (distro_counter <= 0)
994 counting_distros = -1;
998 /* Handle bouncy bricks: */
1000 for (i = 0; i < NUM_BOUNCY_BRICKS; i++)
1002 if (bouncy_bricks[i].alive)
1004 bouncy_bricks[i].offset = (bouncy_bricks[i].offset +
1005 bouncy_bricks[i].offset_m);
1009 if (bouncy_bricks[i].offset < -BOUNCY_BRICK_MAX_OFFSET)
1010 bouncy_bricks[i].offset_m = BOUNCY_BRICK_SPEED;
1013 /* Stop bouncing? */
1015 if (bouncy_bricks[i].offset == 0)
1016 bouncy_bricks[i].alive = NO;
1021 /* Handle floating scores: */
1023 for (i = 0; i < NUM_FLOATING_SCORES; i++)
1025 if (floating_scores[i].alive)
1027 floating_scores[i].y = floating_scores[i].y - 2;
1028 floating_scores[i].timer--;
1030 if (floating_scores[i].timer <= 0)
1031 floating_scores[i].alive = NO;
1036 /* Handle bullets: */
1038 for (i = 0; i < NUM_BULLETS; i++)
1040 if (bullets[i].alive)
1042 bullets[i].x = bullets[i].x + bullets[i].xm;
1043 bullets[i].y = bullets[i].y + bullets[i].ym;
1045 if (issolid(bullets[i].x, bullets[i].y, 0))
1047 if (issolid(bullets[i].x, bullets[i].y - bullets[i].ym, 0))
1048 bullets[i].alive = NO;
1051 if (bullets[i].ym >= 0)
1053 bullets[i].y = (bullets[i].y / 32) * 32 - 8;
1055 bullets[i].ym = -bullets[i].ym;
1059 bullets[i].ym = bullets[i].ym + GRAVITY;
1061 if (bullets[i].x < scroll_x ||
1062 bullets[i].x > scroll_x + 640)
1064 bullets[i].alive = NO;
1069 if (bullets[i].alive)
1071 for (j = 0; j < NUM_BAD_GUYS; j++)
1073 if (bad_guys[j].alive && !bad_guys[j].dying)
1075 if (bullets[i].x >= bad_guys[j].x - 4 &&
1076 bullets[i].x <= bad_guys[j].x + 32 + 4 &&
1077 bullets[i].y >= bad_guys[j].y - 4 &&
1078 bullets[i].y <= bad_guys[j].y + 32 + 4)
1080 /* Kill the bad guy! */
1082 bullets[i].alive = 0;
1083 bad_guys[j].dying = FALLING;
1084 bad_guys[j].ym = -8;
1087 /* Gain some points: */
1089 if (bad_guys[j].kind == BAD_BSOD)
1091 add_score(bad_guys[j].x - scroll_x, bad_guys[j].y,
1092 50 * score_multiplier);
1094 else if (bad_guys[j].kind == BAD_LAPTOP)
1096 add_score(bad_guys[j].x - scroll_x, bad_guys[j].y,
1097 25 * score_multiplier);
1101 /* Play death sound: */
1103 playsound(sounds[SND_FALL]);
1112 /* Handle background timer: */
1114 if (super_bkgd_time)
1118 /* Handle invincibility timer: */
1120 if (tux_invincible_time)
1121 tux_invincible_time--;
1124 /* Handle upgrades: */
1126 for (i = 0; i < NUM_UPGRADES; i++)
1128 if (upgrades[i].alive)
1130 if (upgrades[i].height < 32)
1134 upgrades[i].height++;
1140 if (upgrades[i].kind == UPGRADE_MINTS ||
1141 upgrades[i].kind == UPGRADE_HERRING)
1143 upgrades[i].x = upgrades[i].x + upgrades[i].xm;
1144 upgrades[i].y = upgrades[i].y + upgrades[i].ym;
1146 if (issolid(upgrades[i].x, upgrades[i].y + 31, 0) ||
1147 issolid(upgrades[i].x + 31, upgrades[i].y + 31, 0))
1149 if (upgrades[i].ym > 0)
1151 if (upgrades[i].kind == UPGRADE_MINTS)
1155 else if (upgrades[i].kind == UPGRADE_HERRING)
1157 upgrades[i].ym = -24;
1160 upgrades[i].y = (upgrades[i].y / 32) * 32;
1164 upgrades[i].ym = upgrades[i].ym + GRAVITY;
1166 if (issolid(upgrades[i].x, upgrades[i].y, 0))
1168 upgrades[i].xm = -upgrades[i].xm;
1173 /* Off the screen? Kill it! */
1175 if (upgrades[i].x < scroll_x)
1176 upgrades[i].alive = NO;
1179 /* Did the player grab it? */
1181 if (tux_x + scroll_x >= upgrades[i].x - 32 &&
1182 tux_x + scroll_x <= upgrades[i].x + 32 &&
1183 tux_y >= upgrades[i].y - 32 &&
1184 tux_y <= upgrades[i].y + 32)
1186 /* Remove the upgrade: */
1188 upgrades[i].alive = NO;
1191 /* Affect the player: */
1193 if (upgrades[i].kind == UPGRADE_MINTS)
1196 playsound(sounds[SND_EXCELLENT]);
1199 super_bkgd_time = 8;
1201 else if (upgrades[i].kind == UPGRADE_COFFEE)
1204 playsound(sounds[SND_COFFEE]);
1206 tux_got_coffee = YES;
1207 super_bkgd_time = 4;
1209 else if (upgrades[i].kind == UPGRADE_HERRING)
1212 playsound(sounds[SND_HERRING]);
1214 tux_invincible_time = 200;
1215 super_bkgd_time = 4;
1223 /* Handle bad guys: */
1225 for (i = 0; i < NUM_BAD_GUYS; i++)
1227 if (bad_guys[i].alive)
1229 if (bad_guys[i].seen)
1231 if (bad_guys[i].kind == BAD_BSOD)
1233 /* --- BLUE SCREEN OF DEATH MONSTER: --- */
1235 /* Move left/right: */
1237 if (bad_guys[i].dying == NO ||
1238 bad_guys[i].dying == FALLING)
1240 if (bad_guys[i].dir == RIGHT)
1241 bad_guys[i].x = bad_guys[i].x + 4;
1242 else if (bad_guys[i].dir == LEFT)
1243 bad_guys[i].x = bad_guys[i].x - 4;
1247 /* Move vertically: */
1249 bad_guys[i].y = bad_guys[i].y + bad_guys[i].ym;
1252 /* Bump into things horizontally: */
1254 if (!bad_guys[i].dying)
1256 if (issolid(bad_guys[i].x, bad_guys[i].y, 0))
1257 bad_guys[i].dir = !bad_guys[i].dir;
1261 /* Bump into other bad guys: */
1263 for (j = 0; j < NUM_BAD_GUYS; j++)
1265 if (j != i && bad_guys[j].alive &&
1266 !bad_guys[j].dying && !bad_guys[i].dying &&
1267 bad_guys[i].x >= bad_guys[j].x - 32 &&
1268 bad_guys[i].x <= bad_guys[j].x + 32 &&
1269 bad_guys[i].y >= bad_guys[j].y - 32 &&
1270 bad_guys[i].y <= bad_guys[j].y + 32)
1272 bad_guys[i].dir = !bad_guys[i].dir;
1277 /* Fall if we get off the ground: */
1279 if (bad_guys[i].dying != FALLING)
1281 if (!issolid(bad_guys[i].x, bad_guys[i].y + 32, 0) &&
1282 bad_guys[i].ym < MAX_YM)
1284 bad_guys[i].ym = bad_guys[i].ym + GRAVITY;
1290 if (bad_guys[i].ym > 0)
1292 bad_guys[i].y = (bad_guys[i].y / 32) * 32;
1298 bad_guys[i].ym = bad_guys[i].ym + GRAVITY;
1300 if (bad_guys[i].y > 480)
1301 bad_guys[i].alive = NO;
1303 else if (bad_guys[i].kind == BAD_LAPTOP)
1305 /* --- LAPTOP MONSTER: --- */
1307 /* Move left/right: */
1309 if (bad_guys[i].mode != FLAT && bad_guys[i].mode != KICK)
1311 if (bad_guys[i].dying == NO ||
1312 bad_guys[i].dying == FALLING)
1314 if (bad_guys[i].dir == RIGHT)
1315 bad_guys[i].x = bad_guys[i].x + 4;
1316 else if (bad_guys[i].dir == LEFT)
1317 bad_guys[i].x = bad_guys[i].x - 4;
1320 else if (bad_guys[i].mode == KICK)
1322 if (bad_guys[i].dir == RIGHT)
1323 bad_guys[i].x = bad_guys[i].x + 16;
1324 else if (bad_guys[i].dir == LEFT)
1325 bad_guys[i].x = bad_guys[i].x - 16;
1329 /* Move vertically: */
1331 bad_guys[i].y = bad_guys[i].y + bad_guys[i].ym;
1334 /* Bump into things horizontally: */
1336 if (!bad_guys[i].dying)
1338 if (issolid(bad_guys[i].x, bad_guys[i].y, 0))
1340 bad_guys[i].dir = !bad_guys[i].dir;
1343 if (bad_guys[i].mode == KICK)
1344 playsound(sounds[SND_RICOCHET]);
1350 /* Bump into other bad guys: */
1352 for (j = 0; j < NUM_BAD_GUYS; j++)
1354 if (j != i && bad_guys[j].alive &&
1355 !bad_guys[j].dying && !bad_guys[i].dying &&
1356 bad_guys[i].x >= bad_guys[j].x - 32 &&
1357 bad_guys[i].x <= bad_guys[j].x + 32 &&
1358 bad_guys[i].y >= bad_guys[j].y - 32 &&
1359 bad_guys[i].y <= bad_guys[j].y + 32)
1361 if (bad_guys[i].mode != KICK)
1362 bad_guys[i].dir = !bad_guys[i].dir;
1365 /* We're in kick mode, kill the other guy: */
1367 bad_guys[j].dying = FALLING;
1368 bad_guys[j].ym = -8;
1370 playsound(sounds[SND_FALL]);
1373 add_score(bad_guys[i].x - scroll_x,
1374 bad_guys[i].y, 100);
1380 /* Fall if we get off the ground: */
1382 if (bad_guys[i].dying != FALLING)
1384 if (!issolid(bad_guys[i].x, bad_guys[i].y + 32, 0) &&
1385 bad_guys[i].ym < MAX_YM)
1387 bad_guys[i].ym = bad_guys[i].ym + GRAVITY;
1393 if (bad_guys[i].ym > 0)
1395 bad_guys[i].y = (bad_guys[i].y / 32) * 32;
1401 bad_guys[i].ym = bad_guys[i].ym + GRAVITY;
1403 if (bad_guys[i].y > 480)
1404 bad_guys[i].alive = NO;
1406 else if (bad_guys[i].kind == BAD_MONEY)
1408 /* --- MONEY BAGS: --- */
1411 /* Move vertically: */
1413 bad_guys[i].y = bad_guys[i].y + bad_guys[i].ym;
1416 /* Fall if we get off the ground: */
1418 if (bad_guys[i].dying != FALLING)
1420 if (!issolid(bad_guys[i].x, bad_guys[i].y + 32, 0))
1422 if (bad_guys[i].ym < MAX_YM)
1424 bad_guys[i].ym = bad_guys[i].ym + GRAVITY;
1431 if (bad_guys[i].ym > 0)
1433 bad_guys[i].y = (bad_guys[i].y / 32) * 32;
1434 bad_guys[i].ym = -MAX_YM;
1439 bad_guys[i].ym = bad_guys[i].ym + GRAVITY;
1441 if (bad_guys[i].y > 480)
1442 bad_guys[i].alive = NO;
1444 else if (bad_guys[i].kind == -1)
1449 /* Kill it if the player jumped on it: */
1451 if (!bad_guys[i].dying && !tux_dying && !tux_safe &&
1452 tux_x + scroll_x >= bad_guys[i].x - 32 &&
1453 tux_x + scroll_x <= bad_guys[i].x + 32 &&
1454 tux_y >= bad_guys[i].y - 32 &&
1455 tux_y <= bad_guys[i].y - 8
1459 if (bad_guys[i].kind == BAD_BSOD)
1461 bad_guys[i].dying = SQUISHED;
1462 bad_guys[i].timer = 16;
1463 tux_ym = -KILL_BOUNCE_YM;
1465 add_score(bad_guys[i].x - scroll_x, bad_guys[i].y,
1466 50 * score_multiplier);
1469 playsound(sounds[SND_SQUISH]);
1472 else if (bad_guys[i].kind == BAD_LAPTOP)
1474 if (bad_guys[i].mode != FLAT)
1478 bad_guys[i].mode = FLAT;
1480 bad_guys[i].timer = 64;
1488 bad_guys[i].mode = KICK;
1490 if (tux_x + scroll_x <= bad_guys[i].x)
1491 bad_guys[i].dir = RIGHT;
1493 bad_guys[i].dir = LEFT;
1495 bad_guys[i].timer = 8;
1498 tux_ym = -KILL_BOUNCE_YM;
1500 add_score(bad_guys[i].x - scroll_x,
1502 25 * score_multiplier);
1505 /* playsound(sounds[SND_SQUISH]); */
1508 else if (bad_guys[i].kind == -1)
1516 /* Hurt the player if he just touched it: */
1518 if (!bad_guys[i].dying && !tux_dying &&
1520 tux_x + scroll_x >= bad_guys[i].x - 32 &&
1521 tux_x + scroll_x <= bad_guys[i].x + 32 &&
1522 tux_y >= bad_guys[i].y - 32 &&
1523 tux_y <= bad_guys[i].y + 32)
1525 if (bad_guys[i].mode == FLAT)
1529 bad_guys[i].mode = KICK;
1531 if (tux_x < bad_guys[i].x)
1533 bad_guys[i].dir = RIGHT;
1534 bad_guys[i].x = bad_guys[i].x + 16;
1538 bad_guys[i].dir = LEFT;
1539 bad_guys[i].x = bad_guys[i].x - 16;
1542 bad_guys[i].timer = 8;
1544 else if (bad_guys[i].mode == KICK)
1546 if (tux_y < bad_guys[i].y - 16 &&
1547 bad_guys[i].timer == 0)
1549 /* Step on (stop being kicked) */
1551 bad_guys[i].mode = FLAT;
1552 bad_guys[i].timer = 64;
1556 /* Hurt if you get hit by kicked laptop: */
1558 if (bad_guys[i].timer == 0)
1560 if (tux_invincible_time == 0)
1566 bad_guys[i].dying = FALLING;
1567 bad_guys[i].ym = -8;
1569 playsound(sounds[SND_FALL]);
1577 if (tux_invincible_time == 0)
1583 bad_guys[i].dying = FALLING;
1584 bad_guys[i].ym = -8;
1586 playsound(sounds[SND_FALL]);
1593 /* Handle mode timer: */
1595 if (bad_guys[i].mode == FLAT)
1597 bad_guys[i].timer--;
1599 if (bad_guys[i].timer <= 0)
1600 bad_guys[i].mode = NORMAL;
1602 else if (bad_guys[i].mode == KICK)
1604 if (bad_guys[i].timer > 0)
1605 bad_guys[i].timer--;
1609 /* Handle dying timer: */
1611 if (bad_guys[i].dying == SQUISHED)
1613 bad_guys[i].timer--;
1616 /* Remove it if time's up: */
1618 if (bad_guys[i].timer <= 0)
1619 bad_guys[i].alive = NO;
1623 /* Remove if it's far off the screen: */
1625 if (bad_guys[i].x < scroll_x - OFFSCREEN_DISTANCE)
1626 bad_guys[i].alive = NO;
1630 /* Once it's on screen, it's activated! */
1632 if (bad_guys[i].x <= scroll_x + 640 + OFFSCREEN_DISTANCE)
1633 bad_guys[i].seen = YES;
1639 /* Handle skidding: */
1641 if (tux_skidding > 0)
1649 if (tux_dying && (frame % 4) == 0)
1650 clearscreen(255, 255, 255);
1653 if (super_bkgd_time == 0)
1654 clearscreen(bkgd_red, bkgd_green, bkgd_blue);
1656 drawimage(img_super_bkgd, 0, 0, NO_UPDATE);
1660 /* Draw background: */
1662 for (y = 0; y < 15; y++)
1664 for (x = 0; x < 21; x++)
1666 drawshape(x * 32 - (scroll_x % 32), y * 32,
1667 tiles[y][x + (scroll_x / 32)]);
1672 /* (Bouncy bricks): */
1674 for (i = 0; i < NUM_BOUNCY_BRICKS; i++)
1676 if (bouncy_bricks[i].alive)
1678 if (bouncy_bricks[i].x >= scroll_x - 32 &&
1679 bouncy_bricks[i].x <= scroll_x + 640)
1681 dest.x = bouncy_bricks[i].x - scroll_x;
1682 dest.y = bouncy_bricks[i].y;
1686 SDL_FillRect(screen, &dest, SDL_MapRGB(screen->format,
1691 drawshape(bouncy_bricks[i].x - scroll_x,
1692 bouncy_bricks[i].y + bouncy_bricks[i].offset,
1693 bouncy_bricks[i].shape);
1701 for (i = 0; i < NUM_BAD_GUYS; i++)
1703 if (bad_guys[i].alive &&
1704 bad_guys[i].x > scroll_x - 32 &&
1705 bad_guys[i].x < scroll_x + 640)
1707 if (bad_guys[i].kind == BAD_BSOD)
1709 /* --- BLUE SCREEN OF DEATH MONSTER: --- */
1711 if (bad_guys[i].dying == NO)
1715 if (bad_guys[i].dir == LEFT)
1717 drawimage(img_bsod_left[(frame / 5) % 4],
1718 bad_guys[i].x - scroll_x,
1724 drawimage(img_bsod_right[(frame / 5) % 4],
1725 bad_guys[i].x - scroll_x,
1730 else if (bad_guys[i].dying == FALLING)
1734 if (bad_guys[i].dir == LEFT)
1736 drawimage(img_bsod_falling_left,
1737 bad_guys[i].x - scroll_x,
1743 drawimage(img_bsod_falling_right,
1744 bad_guys[i].x - scroll_x,
1749 else if (bad_guys[i].dying == SQUISHED)
1751 /* Dying - Squished: */
1753 if (bad_guys[i].dir == LEFT)
1755 drawimage(img_bsod_squished_left,
1756 bad_guys[i].x - scroll_x,
1762 drawimage(img_bsod_squished_right,
1763 bad_guys[i].x - scroll_x,
1769 else if (bad_guys[i].kind == BAD_LAPTOP)
1771 /* --- LAPTOP MONSTER: --- */
1773 if (bad_guys[i].dying == NO)
1777 if (bad_guys[i].mode == NORMAL)
1781 if (bad_guys[i].dir == LEFT)
1783 drawimage(img_laptop_left[(frame / 5) % 3],
1784 bad_guys[i].x - scroll_x,
1790 drawimage(img_laptop_right[(frame / 5) % 3],
1791 bad_guys[i].x - scroll_x,
1800 if (bad_guys[i].dir == LEFT)
1802 drawimage(img_laptop_flat_left,
1803 bad_guys[i].x - scroll_x,
1809 drawimage(img_laptop_flat_right,
1810 bad_guys[i].x - scroll_x,
1816 else if (bad_guys[i].dying == FALLING)
1820 if (bad_guys[i].dir == LEFT)
1822 drawimage(img_laptop_falling_left,
1823 bad_guys[i].x - scroll_x,
1829 drawimage(img_laptop_falling_right,
1830 bad_guys[i].x - scroll_x,
1836 else if (bad_guys[i].kind == BAD_MONEY)
1838 if (bad_guys[i].ym > -16)
1840 if (bad_guys[i].dir == LEFT)
1842 drawimage(img_money_left[0],
1843 bad_guys[i].x - scroll_x,
1849 drawimage(img_money_right[0],
1850 bad_guys[i].x - scroll_x,
1857 if (bad_guys[i].dir == LEFT)
1859 drawimage(img_money_left[1],
1860 bad_guys[i].x - scroll_x,
1866 drawimage(img_money_right[1],
1867 bad_guys[i].x - scroll_x,
1873 else if (bad_guys[i].kind == -1)
1882 if (right == UP && left == UP)
1889 if ((fire == DOWN && (frame % 2) == 0) ||
1891 tux_frame_main = (tux_frame_main + 1) % 4;
1893 tux_frame = tux_frame_main;
1900 if (tux_got_coffee && (frame % 2) == 1)
1904 drawimage(img_red_glow, tux_x - 8, tux_y - 32, NO_UPDATE);
1908 if (tux_safe == 0 || (frame % 2) == 0)
1910 if (tux_size == SMALL)
1912 if (tux_invincible_time)
1916 if (tux_dir == RIGHT)
1918 drawimage(cape_right[frame % 2],
1924 drawimage(cape_left[frame % 2],
1931 if (tux_dir == RIGHT)
1933 drawimage(tux_right[tux_frame], tux_x, tux_y, NO_UPDATE);
1937 drawimage(tux_left[tux_frame], tux_x, tux_y, NO_UPDATE);
1942 if (tux_invincible_time)
1946 if (tux_dir == RIGHT)
1948 drawimage(bigcape_right[frame % 2],
1949 tux_x - 8 - 16, tux_y - 32,
1954 drawimage(bigcape_left[frame % 2],
1955 tux_x - 8, tux_y - 32,
1964 if (!jumping || tux_ym > 0)
1966 if (tux_dir == RIGHT)
1968 drawimage(bigtux_right[tux_frame],
1969 tux_x - 8, tux_y - 32,
1974 drawimage(bigtux_left[tux_frame],
1975 tux_x - 8, tux_y - 32,
1981 if (tux_dir == RIGHT)
1983 drawimage(bigtux_right_jump,
1984 tux_x - 8, tux_y - 32,
1989 drawimage(bigtux_left_jump,
1990 tux_x - 8, tux_y - 32,
1997 if (tux_dir == RIGHT)
1999 drawimage(skidtux_right,
2000 tux_x - 8, tux_y - 32,
2005 drawimage(skidtux_left,
2006 tux_x - 8, tux_y - 32,
2013 if (tux_dir == RIGHT)
2015 drawimage(ducktux_right, tux_x - 8, tux_y - 16,
2020 drawimage(ducktux_left, tux_x - 8, tux_y - 16,
2030 for (i = 0; i < NUM_BULLETS; i++)
2032 if (bullets[i].alive &&
2033 bullets[i].x >= scroll_x - 4 &&
2034 bullets[i].x <= scroll_x + 640)
2036 drawimage(img_bullet, bullets[i].x - scroll_x, bullets[i].y,
2042 /* (Floating scores): */
2044 for (i = 0; i < NUM_FLOATING_SCORES; i++)
2046 if (floating_scores[i].alive)
2048 sprintf(str, "%d", floating_scores[i].value);
2050 floating_scores[i].x + 16 - strlen(str) * 8,
2051 floating_scores[i].y,
2052 letters_gold, NO_UPDATE);
2059 for (i = 0; i < NUM_UPGRADES; i++)
2061 if (upgrades[i].alive)
2063 if (upgrades[i].height < 32)
2067 dest.x = upgrades[i].x - scroll_x;
2068 dest.y = upgrades[i].y + 32 - upgrades[i].height;
2070 dest.h = upgrades[i].height;
2075 src.h = upgrades[i].height;
2077 if (upgrades[i].kind == UPGRADE_MINTS)
2078 SDL_BlitSurface(img_mints, &src, screen, &dest);
2079 else if (upgrades[i].kind == UPGRADE_COFFEE)
2080 SDL_BlitSurface(img_coffee, &src, screen, &dest);
2081 else if (upgrades[i].kind == UPGRADE_HERRING)
2082 SDL_BlitSurface(img_golden_herring, &src, screen, &dest);
2086 if (upgrades[i].kind == UPGRADE_MINTS)
2088 drawimage(img_mints,
2089 upgrades[i].x - scroll_x, upgrades[i].y,
2092 else if (upgrades[i].kind == UPGRADE_COFFEE)
2094 drawimage(img_coffee,
2095 upgrades[i].x - scroll_x, upgrades[i].y,
2098 else if (upgrades[i].kind == UPGRADE_HERRING)
2100 drawimage(img_golden_herring,
2101 upgrades[i].x - scroll_x, upgrades[i].y,
2109 /* (Bouncy distros): */
2111 for (i = 0; i < NUM_BOUNCY_DISTROS; i++)
2113 if (bouncy_distros[i].alive)
2115 drawimage(img_distro[0],
2116 bouncy_distros[i].x - scroll_x,
2117 bouncy_distros[i].y,
2123 /* (Broken bricks): */
2125 for (i = 0; i < NUM_BROKEN_BRICKS; i++)
2127 if (broken_bricks[i].alive)
2129 src.x = rand() % 16;
2130 src.y = rand() % 16;
2134 dest.x = broken_bricks[i].x - scroll_x;
2135 dest.y = broken_bricks[i].y;
2139 SDL_BlitSurface(img_brick[0], &src, screen, &dest);
2146 sprintf(str, "%d", score);
2147 drawtext("SCORE", 0, 0, letters_blue, NO_UPDATE);
2148 drawtext(str, 96, 0, letters_gold, NO_UPDATE);
2150 if (time_left >= 50 || (frame % 10) < 5)
2152 sprintf(str, "%d", time_left);
2153 drawtext("TIME", 224, 0, letters_blue, NO_UPDATE);
2154 drawtext(str, 304, 0, letters_gold, NO_UPDATE);
2157 sprintf(str, "%d", distros);
2158 drawtext("DISTROS", 480, 0, letters_blue, NO_UPDATE);
2159 drawtext(str, 608, 0, letters_gold, NO_UPDATE);
2162 /* (Update it all!) */
2167 /* Keep playing music: */
2172 if (!Mix_PlayingMusic())
2174 Mix_PlayMusic(song, 1);
2180 /* Pause til next frame: */
2182 now_time = SDL_GetTicks();
2183 if (now_time < last_time + FPS)
2184 SDL_Delay(last_time + FPS - now_time);
2189 if ((frame % 10) == 0 && time_left > 0)
2197 while (!done && !quit);
2202 if (Mix_PlayingMusic())
2215 /* Initialize the game stuff: */
2226 /* Load data for this level: */
2228 void loadlevel(void)
2239 for (i = 0; i < NUM_BOUNCY_DISTROS; i++)
2240 bouncy_distros[i].alive = NO;
2242 for (i = 0; i < NUM_BROKEN_BRICKS; i++)
2243 broken_bricks[i].alive = NO;
2245 for (i = 0; i < NUM_BOUNCY_BRICKS; i++)
2246 bouncy_bricks[i].alive = NO;
2248 for (i = 0; i < NUM_BAD_GUYS; i++)
2249 bad_guys[i].alive = NO;
2251 for (i = 0; i < NUM_FLOATING_SCORES; i++)
2252 floating_scores[i].alive = NO;
2254 for (i = 0; i < NUM_UPGRADES; i++)
2255 upgrades[i].alive = NO;
2257 for (i = 0; i < NUM_BULLETS; i++)
2258 bullets[i].alive = NO;
2261 /* Load data file: */
2263 filename = (char *) malloc(sizeof(char) * (strlen(DATA_PREFIX) + 20));
2264 sprintf(filename, "%s/levels/level%d.dat", DATA_PREFIX, level);
2265 fi = fopen(filename, "r");
2274 /* Load header info: */
2278 strcpy(levelname, str);
2280 /* (Time to beat level) */
2282 time_left = atoi(str);
2284 /* (Song file for this level) */
2286 strcpy(song_title, str);
2288 /* (Level background color) */
2290 bkgd_red = atoi(str);
2292 bkgd_green= atoi(str);
2294 bkgd_blue = atoi(str);
2298 level_width = atoi(str);
2301 /* Allocate some space for the line-reading! */
2303 line = (char *) malloc(sizeof(char) * (level_width + 5));
2306 fprintf(stderr, "Couldn't allocate space to load level data!");
2311 /* Load the level lines: */
2313 for (y = 0; y < 15; y++)
2315 fgets(line, level_width + 5, fi);
2316 line[strlen(line) - 1] = '\0';
2317 tiles[y] = strdup(line);
2323 /* Activate bad guys: */
2325 for (y = 0; y < 15; y++)
2327 for (x = 0; x < level_width; x++)
2329 if (tiles[y][x] >= '0' && tiles[y][x] <= '9')
2331 add_bad_guy(x * 32, y * 32, tiles[y][x] - '0');
2346 tux_got_coffee = NO;
2347 tux_invincible_time = 0;
2351 tux_safe = TUX_SAFE_TIME;
2367 score_multiplier = 1;
2368 super_bkgd_time = 0;
2372 counting_distros = NO;
2378 clearscreen(0, 0, 0);
2380 sprintf(str, "LEVEL %d", level + 1);
2381 drawcenteredtext(str, 200, letters_red, NO_UPDATE);
2383 sprintf(str, "%s", levelname);
2384 drawcenteredtext(str, 224, letters_gold, NO_UPDATE);
2386 sprintf(str, "TUX x %d", lives);
2387 drawcenteredtext(str, 256, letters_blue, NO_UPDATE);
2395 /* Load graphics: */
2397 void loadlevelgfx(void)
2399 img_brick[0] = load_image(DATA_PREFIX "/images/level1/brick0.png",
2401 img_brick[1] = load_image(DATA_PREFIX "/images/level1/brick1.png",
2404 img_solid[0] = load_image(DATA_PREFIX "/images/level1/solid0.png",
2406 img_solid[1] = load_image(DATA_PREFIX "/images/level1/solid1.png",
2408 img_solid[2] = load_image(DATA_PREFIX "/images/level1/solid2.png",
2410 img_solid[3] = load_image(DATA_PREFIX "/images/level1/solid3.png",
2413 img_bkgd[0][0] = load_image(DATA_PREFIX "/images/level1/bkgd-00.png",
2415 img_bkgd[0][1] = load_image(DATA_PREFIX "/images/level1/bkgd-01.png",
2417 img_bkgd[0][2] = load_image(DATA_PREFIX "/images/level1/bkgd-02.png",
2419 img_bkgd[0][3] = load_image(DATA_PREFIX "/images/level1/bkgd-03.png",
2422 img_bkgd[1][0] = load_image(DATA_PREFIX "/images/level1/bkgd-10.png",
2424 img_bkgd[1][1] = load_image(DATA_PREFIX "/images/level1/bkgd-11.png",
2426 img_bkgd[1][2] = load_image(DATA_PREFIX "/images/level1/bkgd-12.png",
2428 img_bkgd[1][3] = load_image(DATA_PREFIX "/images/level1/bkgd-13.png",
2435 void loadlevelsong(void)
2440 song_path = (char *) malloc(sizeof(char) * (strlen(DATA_PREFIX) +
2441 strlen(song_title) + 8));
2443 sprintf(song_path, "%s/music/%s", DATA_PREFIX, song_title);
2445 song = load_song(DATA_PREFIX "/music/ji_turn.it");
2452 /* Free graphics data for this level: */
2454 void unloadlevelgfx(void)
2458 for (i = 0; i < 2; i++)
2460 SDL_FreeSurface(img_brick[i]);
2462 for (i = 0; i < 4; i++)
2464 SDL_FreeSurface(img_solid[i]);
2465 SDL_FreeSurface(img_bkgd[0][i]);
2466 SDL_FreeSurface(img_bkgd[1][i]);
2471 /* Free music data for this level: */
2473 void unloadlevelsong(void)
2478 Mix_FreeMusic(song);
2484 /* Load graphics shared between all levels: */
2486 void loadshared(void)
2495 tux_right[0] = load_image(DATA_PREFIX "/images/shared/tux-right-0.png",
2498 tux_right[1] = load_image(DATA_PREFIX "/images/shared/tux-right-1.png",
2501 tux_right[2] = load_image(DATA_PREFIX "/images/shared/tux-right-2.png",
2504 tux_left[0] = load_image(DATA_PREFIX "/images/shared/tux-left-0.png",
2507 tux_left[1] = load_image(DATA_PREFIX "/images/shared/tux-left-1.png",
2510 tux_left[2] = load_image(DATA_PREFIX "/images/shared/tux-left-2.png",
2513 cape_right[0] = load_image(DATA_PREFIX "/images/shared/cape-right-0.png",
2516 cape_right[1] = load_image(DATA_PREFIX "/images/shared/cape-right-1.png",
2519 cape_left[0] = load_image(DATA_PREFIX "/images/shared/cape-left-0.png",
2522 cape_left[1] = load_image(DATA_PREFIX "/images/shared/cape-left-1.png",
2525 bigtux_right[0] = load_image(DATA_PREFIX "/images/shared/bigtux-right-0.png",
2528 bigtux_right[1] = load_image(DATA_PREFIX "/images/shared/bigtux-right-1.png",
2531 bigtux_right[2] = load_image(DATA_PREFIX "/images/shared/bigtux-right-2.png",
2535 load_image(DATA_PREFIX "/images/shared/bigtux-right-jump.png", USE_ALPHA);
2537 bigtux_left[0] = load_image(DATA_PREFIX "/images/shared/bigtux-left-0.png",
2540 bigtux_left[1] = load_image(DATA_PREFIX "/images/shared/bigtux-left-1.png",
2543 bigtux_left[2] = load_image(DATA_PREFIX "/images/shared/bigtux-left-2.png",
2547 load_image(DATA_PREFIX "/images/shared/bigtux-left-jump.png", USE_ALPHA);
2550 load_image(DATA_PREFIX "/images/shared/bigcape-right-0.png",
2554 load_image(DATA_PREFIX "/images/shared/bigcape-right-1.png",
2558 load_image(DATA_PREFIX "/images/shared/bigcape-left-0.png",
2562 load_image(DATA_PREFIX "/images/shared/bigcape-left-1.png",
2565 ducktux_right = load_image(DATA_PREFIX
2566 "/images/shared/ducktux-right.png",
2569 ducktux_left = load_image(DATA_PREFIX
2570 "/images/shared/ducktux-left.png",
2573 skidtux_right = load_image(DATA_PREFIX
2574 "/images/shared/skidtux-right.png",
2577 skidtux_left = load_image(DATA_PREFIX
2578 "/images/shared/skidtux-left.png",
2584 img_box_full = load_image(DATA_PREFIX "/images/shared/box-full.png",
2586 img_box_empty = load_image(DATA_PREFIX "/images/shared/box-empty.png",
2593 img_water = load_image(DATA_PREFIX "/images/shared/water.png", IGNORE_ALPHA);
2595 img_waves[0] = load_image(DATA_PREFIX "/images/shared/waves-0.png",
2598 img_waves[1] = load_image(DATA_PREFIX "/images/shared/waves-1.png",
2601 img_waves[2] = load_image(DATA_PREFIX "/images/shared/waves-2.png",
2607 img_pole = load_image(DATA_PREFIX "/images/shared/pole.png", USE_ALPHA);
2608 img_poletop = load_image(DATA_PREFIX "/images/shared/poletop.png",
2614 img_flag[0] = load_image(DATA_PREFIX "/images/shared/flag-0.png",
2616 img_flag[1] = load_image(DATA_PREFIX "/images/shared/flag-1.png",
2622 img_cloud[0][0] = load_image(DATA_PREFIX "/images/shared/cloud-00.png",
2625 img_cloud[0][1] = load_image(DATA_PREFIX "/images/shared/cloud-01.png",
2628 img_cloud[0][2] = load_image(DATA_PREFIX "/images/shared/cloud-02.png",
2631 img_cloud[0][3] = load_image(DATA_PREFIX "/images/shared/cloud-03.png",
2635 img_cloud[1][0] = load_image(DATA_PREFIX "/images/shared/cloud-10.png",
2638 img_cloud[1][1] = load_image(DATA_PREFIX "/images/shared/cloud-11.png",
2641 img_cloud[1][2] = load_image(DATA_PREFIX "/images/shared/cloud-12.png",
2644 img_cloud[1][3] = load_image(DATA_PREFIX "/images/shared/cloud-13.png",
2652 img_bsod_left[0] = load_image(DATA_PREFIX
2653 "/images/shared/bsod-left-0.png",
2656 img_bsod_left[1] = load_image(DATA_PREFIX
2657 "/images/shared/bsod-left-1.png",
2660 img_bsod_left[2] = load_image(DATA_PREFIX
2661 "/images/shared/bsod-left-2.png",
2664 img_bsod_left[3] = load_image(DATA_PREFIX
2665 "/images/shared/bsod-left-3.png",
2668 img_bsod_right[0] = load_image(DATA_PREFIX
2669 "/images/shared/bsod-right-0.png",
2672 img_bsod_right[1] = load_image(DATA_PREFIX
2673 "/images/shared/bsod-right-1.png",
2676 img_bsod_right[2] = load_image(DATA_PREFIX
2677 "/images/shared/bsod-right-2.png",
2680 img_bsod_right[3] = load_image(DATA_PREFIX
2681 "/images/shared/bsod-right-3.png",
2684 img_bsod_squished_left = load_image(DATA_PREFIX
2685 "/images/shared/bsod-squished-left.png",
2688 img_bsod_squished_right = load_image(DATA_PREFIX
2689 "/images/shared/bsod-squished-right.png",
2692 img_bsod_falling_left = load_image(DATA_PREFIX
2693 "/images/shared/bsod-falling-left.png",
2696 img_bsod_falling_right = load_image(DATA_PREFIX
2697 "/images/shared/bsod-falling-right.png",
2703 img_laptop_left[0] = load_image(DATA_PREFIX
2704 "/images/shared/laptop-left-0.png",
2707 img_laptop_left[1] = load_image(DATA_PREFIX
2708 "/images/shared/laptop-left-1.png",
2711 img_laptop_left[2] = load_image(DATA_PREFIX
2712 "/images/shared/laptop-left-2.png",
2715 img_laptop_right[0] = load_image(DATA_PREFIX
2716 "/images/shared/laptop-right-0.png",
2719 img_laptop_right[1] = load_image(DATA_PREFIX
2720 "/images/shared/laptop-right-1.png",
2723 img_laptop_right[2] = load_image(DATA_PREFIX
2724 "/images/shared/laptop-right-2.png",
2727 img_laptop_flat_left = load_image(DATA_PREFIX
2728 "/images/shared/laptop-flat-left.png",
2731 img_laptop_flat_right = load_image(DATA_PREFIX
2732 "/images/shared/laptop-flat-right.png",
2735 img_laptop_falling_left =
2736 load_image(DATA_PREFIX
2737 "/images/shared/laptop-falling-left.png",
2740 img_laptop_falling_right =
2741 load_image(DATA_PREFIX
2742 "/images/shared/laptop-falling-right.png",
2748 img_money_left[0] = load_image(DATA_PREFIX
2749 "/images/shared/bag-left-0.png",
2752 img_money_left[1] = load_image(DATA_PREFIX
2753 "/images/shared/bag-left-1.png",
2756 img_money_right[0] = load_image(DATA_PREFIX
2757 "/images/shared/bag-right-0.png",
2760 img_money_right[1] = load_image(DATA_PREFIX
2761 "/images/shared/bag-right-1.png",
2768 img_mints = load_image(DATA_PREFIX "/images/shared/mints.png", USE_ALPHA);
2769 img_coffee = load_image(DATA_PREFIX "/images/shared/coffee.png", USE_ALPHA);
2774 img_bullet = load_image(DATA_PREFIX "/images/shared/bullet.png", USE_ALPHA);
2776 img_red_glow = load_image(DATA_PREFIX "/images/shared/red-glow.png",
2782 img_distro[0] = load_image(DATA_PREFIX "/images/shared/distro-0.png",
2785 img_distro[1] = load_image(DATA_PREFIX "/images/shared/distro-1.png",
2788 img_distro[2] = load_image(DATA_PREFIX "/images/shared/distro-2.png",
2791 img_distro[3] = load_image(DATA_PREFIX "/images/shared/distro-3.png",
2797 img_golden_herring =
2798 load_image(DATA_PREFIX "/images/shared/golden-herring.png",
2802 /* Super background: */
2804 img_super_bkgd = load_image(DATA_PREFIX "/images/shared/super-bkgd.png",
2808 /* Sound effects: */
2813 for (i = 0; i < NUM_SOUNDS; i++)
2814 sounds[i] = load_sound(soundfilenames[i]);
2820 /* Free shared data: */
2822 void unloadshared(void)
2826 for (i = 0; i < 3; i++)
2828 SDL_FreeSurface(tux_right[i]);
2829 SDL_FreeSurface(tux_left[i]);
2830 SDL_FreeSurface(bigtux_right[i]);
2831 SDL_FreeSurface(bigtux_left[i]);
2834 SDL_FreeSurface(bigtux_right_jump);
2835 SDL_FreeSurface(bigtux_left_jump);
2837 for (i = 0; i < 2; i++)
2839 SDL_FreeSurface(cape_right[i]);
2840 SDL_FreeSurface(cape_left[i]);
2841 SDL_FreeSurface(bigcape_right[i]);
2842 SDL_FreeSurface(bigcape_left[i]);
2845 SDL_FreeSurface(ducktux_left);
2846 SDL_FreeSurface(ducktux_right);
2848 SDL_FreeSurface(skidtux_left);
2849 SDL_FreeSurface(skidtux_right);
2851 for (i = 0; i < 4; i++)
2853 SDL_FreeSurface(img_bsod_left[i]);
2854 SDL_FreeSurface(img_bsod_right[i]);
2857 SDL_FreeSurface(img_bsod_squished_left);
2858 SDL_FreeSurface(img_bsod_squished_right);
2860 SDL_FreeSurface(img_bsod_falling_left);
2861 SDL_FreeSurface(img_bsod_falling_right);
2863 for (i = 0; i < 3; i++)
2865 SDL_FreeSurface(img_laptop_left[i]);
2866 SDL_FreeSurface(img_laptop_right[i]);
2869 SDL_FreeSurface(img_laptop_flat_left);
2870 SDL_FreeSurface(img_laptop_flat_right);
2872 SDL_FreeSurface(img_laptop_falling_left);
2873 SDL_FreeSurface(img_laptop_falling_right);
2875 for (i = 0; i < 2; i++)
2877 SDL_FreeSurface(img_money_left[i]);
2878 SDL_FreeSurface(img_money_right[i]);
2881 SDL_FreeSurface(img_box_full);
2882 SDL_FreeSurface(img_box_empty);
2884 SDL_FreeSurface(img_water);
2885 for (i = 0; i < 3; i++)
2886 SDL_FreeSurface(img_waves[i]);
2888 SDL_FreeSurface(img_pole);
2889 SDL_FreeSurface(img_poletop);
2891 for (i = 0; i < 2; i++)
2892 SDL_FreeSurface(img_flag[i]);
2894 SDL_FreeSurface(img_mints);
2895 SDL_FreeSurface(img_coffee);
2897 for (i = 0; i < 4; i++)
2899 SDL_FreeSurface(img_distro[i]);
2900 SDL_FreeSurface(img_cloud[0][i]);
2901 SDL_FreeSurface(img_cloud[1][i]);
2904 SDL_FreeSurface(img_golden_herring);
2909 for (i = 0; i < NUM_SOUNDS; i++)
2910 Mix_FreeChunk(sounds[i]);
2916 /* Draw a tile on the screen: */
2918 void drawshape(int x, int y, unsigned char c)
2922 if (c == 'X' || c == 'x')
2923 drawimage(img_brick[0], x, y, NO_UPDATE);
2924 else if (c == 'Y' || c == 'y')
2925 drawimage(img_brick[1], x, y, NO_UPDATE);
2926 else if (c == 'A' || c =='B' || c == '!')
2927 drawimage(img_box_full, x, y, NO_UPDATE);
2929 drawimage(img_box_empty, x, y, NO_UPDATE);
2930 else if (c >= 'C' && c <= 'F')
2931 drawimage(img_cloud[0][c - 'C'], x, y, NO_UPDATE);
2932 else if (c >= 'c' && c <= 'f')
2933 drawimage(img_cloud[1][c - 'c'], x, y, NO_UPDATE);
2934 else if (c >= 'G' && c <= 'J')
2935 drawimage(img_bkgd[0][c - 'G'], x, y, NO_UPDATE);
2936 else if (c >= 'g' && c <= 'j')
2937 drawimage(img_bkgd[1][c - 'g'], x, y, NO_UPDATE);
2939 drawimage(img_solid[0], x, y, NO_UPDATE);
2941 drawimage(img_solid[1], x, y, NO_UPDATE);
2943 drawimage(img_solid[2], x, y, NO_UPDATE);
2945 drawimage(img_solid[3], x, y, NO_UPDATE);
2948 z = (frame / 2) % 6;
2951 drawimage(img_distro[z], x, y, NO_UPDATE);
2953 drawimage(img_distro[2], x, y, NO_UPDATE);
2955 drawimage(img_distro[1], x, y, NO_UPDATE);
2959 z = (frame / 3) % 3;
2961 drawimage(img_waves[z], x, y, NO_UPDATE);
2964 drawimage(img_poletop, x, y, NO_UPDATE);
2967 drawimage(img_pole, x, y, NO_UPDATE);
2969 /* Mark this as the end position of the level! */
2975 z = (frame / 3) % 2;
2977 drawimage(img_flag[z], x + 16, y, NO_UPDATE);
2980 drawimage(img_water, x, y, NO_UPDATE);
2984 /* What shape is at some position? */
2986 unsigned char shape(int x, int y, int sx)
2992 xx = ((x + sx) / 32);
2994 if (yy >= 0 && yy <= 15 && xx >= 0 && xx <= level_width)
3005 int issolid(int x, int y, int sx)
3011 if (isbrick(x, y, sx) ||
3012 isbrick(x + 31, y, sx) ||
3014 isice(x + 31, y, sx) ||
3015 (shape(x, y, sx) == '[' ||
3016 shape(x + 31, y, sx) == '[') ||
3017 (shape(x, y, sx) == '=' ||
3018 shape(x + 31, y, sx) == '=') ||
3019 (shape(x, y, sx) == ']' ||
3020 shape(x + 31, y, sx) == ']') ||
3021 (shape(x, y, sx) == 'A' ||
3022 shape(x + 31, y, sx) == 'A') ||
3023 (shape(x, y, sx) == 'B' ||
3024 shape(x + 31, y, sx) == 'B') ||
3025 (shape(x, y, sx) == '!' ||
3026 shape(x + 31, y, sx) == '!') ||
3027 (shape(x, y, sx) == 'a' ||
3028 shape(x + 31, y, sx) == 'a'))
3037 /* Is it a brick? */
3039 int isbrick(int x, int y, int sx)
3045 if (shape(x, y, sx) == 'X' ||
3046 shape(x, y, sx) == 'x' ||
3047 shape(x, y, sx) == 'Y' ||
3048 shape(x, y, sx) == 'y')
3059 int isice(int x, int y, int sx)
3065 if (shape(x, y, sx) == '#')
3074 /* Is it a full box? */
3076 int isfullbox(int x, int y, int sx)
3082 if (shape(x, y, sx) == 'A' ||
3083 shape(x, y, sx) == 'B' ||
3084 shape(x, y, sx) == '!')
3093 /* Edit a piece of the map! */
3095 void change(int x, int y, int sx, unsigned char c)
3100 xx = ((x + sx) / 32);
3102 if (yy >= 0 && yy <= 15 && xx >= 0 && xx <= level_width)
3107 /* Break a brick: */
3109 void trybreakbrick(int x, int y, int sx)
3111 if (isbrick(x, y, sx))
3113 if (shape(x, y, sx) == 'x' || shape(x, y, sx) == 'y')
3115 /* Get a distro from it: */
3117 add_bouncy_distro(((x + sx + 1) / 32) * 32,
3120 if (counting_distros == NO)
3122 counting_distros = YES;
3123 distro_counter = 50;
3126 if (distro_counter <= 0)
3127 change(x, y, sx, 'a');
3130 playsound(sounds[SND_DISTRO]);
3132 score = score + SCORE_DISTRO;
3137 /* Get rid of it: */
3139 change(x, y, sx, '.');
3143 /* Replace it with broken bits: */
3145 add_broken_brick(((x + sx + 1) / 32) * 32,
3149 /* Get some score: */
3152 playsound(sounds[SND_BRICK]);
3154 score = score + SCORE_BRICK;
3159 /* Bounce a brick: */
3161 void bumpbrick(int x, int y, int sx)
3163 add_bouncy_brick(((x + sx + 1) / 32) * 32,
3167 playsound(sounds[SND_BRICK]);
3174 void tryemptybox(int x, int y, int sx)
3176 if (isfullbox(x, y, sx))
3178 if (shape(x, y, sx) == 'A')
3180 /* Box with a distro! */
3182 add_bouncy_distro(((x + sx + 1) / 32) * 32,
3183 (y / 32) * 32 - 32);
3186 playsound(sounds[SND_DISTRO]);
3188 score = score + SCORE_DISTRO;
3191 else if (shape(x, y, sx) == 'B')
3193 /* Add an upgrade! */
3195 if (tux_size == SMALL)
3197 /* Tux is small, add mints! */
3199 add_upgrade(((x + sx + 1) / 32) * 32,
3205 /* Tux is big, add coffee: */
3207 add_upgrade(((x + sx + 1) / 32) * 32,
3213 playsound(sounds[SND_UPGRADE]);
3216 else if (shape(x, y, sx) == '!')
3218 /* Add a golden herring */
3220 add_upgrade(((x + sx + 1) / 32) * 32,
3225 /* Empty the box: */
3227 change(x, y, sx, 'a');
3232 /* Try to grab a distro: */
3234 void trygrabdistro(int x, int y, int sx, int bounciness)
3236 if (shape(x, y, sx) == '$')
3238 change(x, y, sx, '.');
3240 playsound(sounds[SND_DISTRO]);
3243 if (bounciness == BOUNCE)
3245 add_bouncy_distro(((x + sx + 1) / 32) * 32,
3249 score = score + SCORE_DISTRO;
3255 /* Add a bouncy distro: */
3257 void add_bouncy_distro(int x, int y)
3263 for (i = 0; i < NUM_BOUNCY_DISTROS && found == -1; i++)
3265 if (!bouncy_distros[i].alive)
3271 bouncy_distros[found].alive = YES;
3272 bouncy_distros[found].x = x;
3273 bouncy_distros[found].y = y;
3274 bouncy_distros[found].ym = -6;
3279 /* Add broken brick pieces: */
3281 void add_broken_brick(int x, int y)
3283 add_broken_brick_piece(x, y, -4, -16);
3284 add_broken_brick_piece(x, y + 16, -6, -12);
3286 add_broken_brick_piece(x + 16, y, 4, -16);
3287 add_broken_brick_piece(x + 16, y + 16, 6, -12);
3291 /* Add a broken brick piece: */
3293 void add_broken_brick_piece(int x, int y, int xm, int ym)
3299 for (i = 0; i < NUM_BROKEN_BRICKS && found == -1; i++)
3301 if (!broken_bricks[i].alive)
3307 broken_bricks[found].alive = YES;
3308 broken_bricks[found].x = x;
3309 broken_bricks[found].y = y;
3310 broken_bricks[found].xm = xm;
3311 broken_bricks[found].ym = ym;
3316 /* Add a bouncy brick piece: */
3318 void add_bouncy_brick(int x, int y)
3324 for (i = 0; i < NUM_BOUNCY_BRICKS && found == -1; i++)
3326 if (!bouncy_bricks[i].alive)
3332 bouncy_bricks[found].alive = YES;
3333 bouncy_bricks[found].x = x;
3334 bouncy_bricks[found].y = y;
3335 bouncy_bricks[found].offset = 0;
3336 bouncy_bricks[found].offset_m = -BOUNCY_BRICK_SPEED;
3337 bouncy_bricks[found].shape = shape(x, y, 0);
3342 /* Add a bad guy: */
3344 void add_bad_guy(int x, int y, int kind)
3350 for (i = 0; i < NUM_BAD_GUYS && found == -1; i++)
3352 if (!bad_guys[i].alive)
3358 bad_guys[found].alive = YES;
3359 bad_guys[found].mode = NORMAL;
3360 bad_guys[found].dying = NO;
3361 bad_guys[found].timer = 0;
3362 bad_guys[found].kind = kind;
3363 bad_guys[found].x = x;
3364 bad_guys[found].y = y;
3365 bad_guys[found].xm = 0;
3366 bad_guys[found].ym = 0;
3367 bad_guys[found].dir = LEFT;
3368 bad_guys[found].seen = NO;
3375 void add_score(int x, int y, int s)
3380 /* Add the score: */
3385 /* Add a floating score thing to the game: */
3389 for (i = 0; i < NUM_FLOATING_SCORES && found == -1; i++)
3391 if (!floating_scores[i].alive)
3398 floating_scores[found].alive = YES;
3399 floating_scores[found].x = x;
3400 floating_scores[found].y = y - 16;
3401 floating_scores[found].timer = 8;
3402 floating_scores[found].value = s;
3407 /* Try to bump a bad guy from below: */
3409 void trybumpbadguy(int x, int y, int sx)
3416 for (i = 0; i < NUM_BAD_GUYS; i++)
3418 if (bad_guys[i].alive &&
3419 bad_guys[i].x >= x + sx - 32 && bad_guys[i].x <= x + sx + 32 &&
3420 bad_guys[i].y >= y - 16 && bad_guys[i].y <= y + 16)
3422 if (bad_guys[i].kind == BAD_BSOD ||
3423 bad_guys[i].kind == BAD_LAPTOP)
3425 bad_guys[i].dying = FALLING;
3426 bad_guys[i].ym = -8;
3428 playsound(sounds[SND_FALL]);
3437 for (i = 0; i < NUM_UPGRADES; i++)
3439 if (upgrades[i].alive && upgrades[i].height == 32 &&
3440 upgrades[i].x >= x + sx - 32 && upgrades[i].x <= x + sx + 32 &&
3441 upgrades[i].y >= y - 16 && upgrades[i].y <= y + 16)
3443 upgrades[i].xm = -upgrades[i].xm;
3444 upgrades[i].ym = -8;
3446 playsound(sounds[SND_BUMP_UPGRADE]);
3453 /* Add an upgrade: */
3455 void add_upgrade(int x, int y, int kind)
3461 for (i = 0; i < NUM_UPGRADES && found == -1; i++)
3463 if (!upgrades[i].alive)
3469 upgrades[found].alive = YES;
3470 upgrades[found].kind = kind;
3471 upgrades[found].x = x;
3472 upgrades[found].y = y;
3473 upgrades[found].xm = 4;
3474 upgrades[found].ym = -4;
3475 upgrades[found].height = 0;
3482 void killtux(int mode)
3487 playsound(sounds[SND_HURT]);
3490 if (tux_dir == RIGHT)
3492 else if (tux_dir == LEFT)
3495 if (mode == SHRINK && tux_size == BIG)
3498 tux_got_coffee = NO;
3502 tux_safe = TUX_SAFE_TIME;
3513 void add_bullet(int x, int y, int dir, int xm)
3519 for (i = 0; i < NUM_BULLETS && found == -1; i++)
3521 if (!bullets[i].alive)
3527 bullets[found].alive = YES;
3531 bullets[found].x = x + 32;
3532 bullets[found].xm = BULLET_XM + xm;
3536 bullets[found].x = x;
3537 bullets[found].xm = -BULLET_XM + xm;
3540 bullets[found].y = y;
3541 bullets[found].ym = BULLET_STARTING_YM;
3544 playsound(sounds[SND_SHOOT]);