7 bill@newbreedsoftware.com
8 http://www.newbreedsoftware.com/supertux/
10 April 11, 2000 - July 15, 2002
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"
81 char * levelnames[] = {
94 /* Local variables: */
96 int score, distros, level, lives, scroll_x,
97 tux_dir, tux_size, tux_duck, tux_x, tux_xm, tux_y, tux_ym,
98 tux_dying, tux_safe, jumping, jump_counter, frame, score_multiplier,
99 tux_frame_main, tux_frame, tux_got_coffee, tux_skidding,
100 super_bkgd_time, time_left, tux_invincible_time,
101 counting_distros, distro_counter;
102 int bkgd_red, bkgd_green, bkgd_blue;
103 int left, right, up, down, fire, old_fire;
104 SDL_Surface * img_brick[2], * img_solid[4], * img_distro[4],
105 * img_waves[3], * img_water, * img_pole, * img_poletop, * img_flag[2];
106 SDL_Surface * img_bkgd[2][4];
107 SDL_Surface * img_golden_herring;
108 SDL_Surface * img_bsod_left[4], * img_bsod_right[4],
109 * img_laptop_left[3], * img_laptop_right[3],
110 * img_money_left[2], * img_money_right[2];
111 SDL_Surface * img_bsod_squished_left, * img_bsod_squished_right,
112 * img_bsod_falling_left, * img_bsod_falling_right,
113 * img_laptop_flat_left, * img_laptop_flat_right,
114 * img_laptop_falling_left, * img_laptop_falling_right;
115 SDL_Surface * img_box_full, * img_box_empty, * img_mints, * img_coffee,
116 * img_super_bkgd, * img_bullet, * img_red_glow;
117 SDL_Surface * img_cloud[2][4];
118 SDL_Surface * tux_right[3], * tux_left[3],
119 * bigtux_right[3], * bigtux_left[3],
120 * bigtux_right_jump, * bigtux_left_jump,
121 * cape_right[2], * cape_left[2],
122 * bigcape_right[2], * bigcape_left[2],
123 * ducktux_right, * ducktux_left,
124 * skidtux_right, * skidtux_left;
126 Mix_Chunk * sounds[NUM_SOUNDS];
129 unsigned char tiles[15][LEVEL_WIDTH + 5];
130 bouncy_distro_type bouncy_distros[NUM_BOUNCY_DISTROS];
131 broken_brick_type broken_bricks[NUM_BROKEN_BRICKS];
132 bouncy_brick_type bouncy_bricks[NUM_BOUNCY_BRICKS];
133 bad_guy_type bad_guys[NUM_BAD_GUYS];
134 floating_score_type floating_scores[NUM_FLOATING_SCORES];
135 upgrade_type upgrades[NUM_UPGRADES];
136 bullet_type bullets[NUM_BULLETS];
139 /* Local function prototypes: */
142 void loadlevel(void);
143 void loadlevelgfx(void);
144 void loadlevelsong(void);
145 void unloadlevelgfx(void);
146 void unloadlevelsong(void);
147 void loadshared(void);
148 void unloadshared(void);
149 void drawshape(int x, int y, unsigned char c);
150 unsigned char shape(int x, int y, int sx);
151 int issolid(int x, int y, int sx);
152 int isbrick(int x, int y, int sx);
153 int isice(int x, int y, int sx);
154 int isfullbox(int x, int y, int sx);
155 void change(int x, int y, int sx, unsigned char c);
156 void trybreakbrick(int x, int y, int sx);
157 void bumpbrick(int x, int y, int sx);
158 void tryemptybox(int x, int y, int sx);
159 void trygrabdistro(int x, int y, int sx, int bounciness);
160 void add_bouncy_distro(int x, int y);
161 void add_broken_brick(int x, int y);
162 void add_broken_brick_piece(int x, int y, int xm, int ym);
163 void add_bouncy_brick(int x, int y);
164 void add_bad_guy(int x, int y, int kind);
165 void add_score(int x, int y, int s);
166 void trybumpbadguy(int x, int y, int sx);
167 void add_upgrade(int x, int y, int kind);
168 void killtux(int mode);
169 void add_bullet(int x, int y, int dir, int xm);
172 /* --- GAME LOOP! --- */
176 int done, quit, x, y, i, j;
180 Uint32 last_time, now_time;
186 clearscreen(0, 0, 0);
199 /* --- MAIN GAME LOOP!!! --- */
209 last_time = SDL_GetTicks();
217 while (SDL_PollEvent(&event))
219 if (event.type == SDL_QUIT)
221 /* Quit event - quit: */
225 else if (event.type == SDL_KEYDOWN)
229 key = event.key.keysym.sym;
231 if (key == SDLK_ESCAPE)
233 /* Escape: Quit the game and return to main menu: */
237 else if (key == SDLK_RIGHT)
241 else if (key == SDLK_LEFT)
245 else if (key == SDLK_UP)
249 else if (key == SDLK_DOWN)
253 else if (key == SDLK_LCTRL)
258 else if (event.type == SDL_KEYUP)
262 key = event.key.keysym.sym;
264 if (key == SDLK_RIGHT)
268 else if (key == SDLK_LEFT)
272 else if (key == SDLK_UP)
276 else if (key == SDLK_DOWN)
280 else if (key == SDLK_LCTRL)
284 else if (key == SDLK_TAB)
286 tux_size = !tux_size;
290 else if (event.type == SDL_JOYAXISMOTION)
292 if (event.jaxis.axis == JOY_X)
294 if (event.jaxis.value < -256)
299 if (event.jaxis.value > 256)
304 else if (event.jaxis.axis == JOY_Y)
306 if (event.jaxis.value > 256)
312 else if (event.type == SDL_JOYBUTTONDOWN)
314 if (event.jbutton.button == JOY_A)
316 else if (event.jbutton.button == JOY_B)
319 else if (event.type == SDL_JOYBUTTONUP)
321 if (event.jbutton.button == JOY_A)
323 else if (event.jbutton.button == JOY_B)
330 /* --- HANDLE TUX! --- */
332 /* Handle key and joystick state: */
336 if (right == DOWN && left == UP)
340 if (tux_xm < -SKID_XM && !tux_skidding &&
343 tux_skidding = SKID_TIME;
345 playsound(sounds[SND_SKID]);
351 if (tux_xm < 0 && !isice(tux_x, tux_y + 32, scroll_x) &&
359 if (tux_dir == RIGHT)
361 /* Facing the direction we're jumping? Go full-speed: */
365 tux_xm = tux_xm + WALK_SPEED;
367 if (tux_xm > MAX_WALK_XM)
368 tux_xm = MAX_WALK_XM;
370 else if (fire == DOWN)
372 tux_xm = tux_xm + RUN_SPEED;
374 if (tux_xm > MAX_RUN_XM)
380 /* Not facing the direction we're jumping?
383 tux_xm = tux_xm + WALK_SPEED / 2;
385 if (tux_xm > MAX_WALK_XM / 2)
386 tux_xm = MAX_WALK_XM / 2;
390 else if (left == DOWN && right == UP)
394 if (tux_xm > SKID_XM && !tux_skidding &&
397 tux_skidding = SKID_TIME;
399 playsound(sounds[SND_SKID]);
405 if (tux_xm > 0 && !isice(tux_x, tux_y + 32, scroll_x) &&
415 /* Facing the direction we're jumping? Go full-speed: */
419 tux_xm = tux_xm - WALK_SPEED;
421 if (tux_xm < -MAX_WALK_XM)
422 tux_xm = -MAX_WALK_XM;
424 else if (fire == DOWN)
426 tux_xm = tux_xm - RUN_SPEED;
428 if (tux_xm < -MAX_RUN_XM)
429 tux_xm = -MAX_RUN_XM;
434 /* Not facing the direction we're jumping?
437 tux_xm = tux_xm - WALK_SPEED / 2;
439 if (tux_xm < -MAX_WALK_XM / 2)
440 tux_xm = -MAX_WALK_XM / 2;
450 if (jump_counter == 0)
454 if (!issolid(tux_x, tux_y + 32, scroll_x) ||
457 /* If they're not on the ground, or are currently moving
458 vertically, don't jump! */
460 jump_counter = MAX_JUMP_COUNT;
464 /* Make sure we're not standing back up into a solid! */
466 if (tux_size == SMALL || tux_duck == NO ||
467 !issolid(tux_x, tux_y, scroll_x))
472 if (tux_size == SMALL)
473 playsound(sounds[SND_JUMP]);
475 playsound(sounds[SND_BIGJUMP]);
482 /* Keep jumping for a while: */
484 if (jump_counter < MAX_JUMP_COUNT)
486 tux_ym = tux_ym - JUMP_SPEED;
496 if (fire == DOWN && old_fire == UP && tux_got_coffee)
498 add_bullet(tux_x + scroll_x, tux_y, tux_dir, tux_xm);
511 if (tux_size == BIG && tux_duck == YES)
513 /* Make sure we're not standing back up into a solid! */
515 if (!issolid(tux_x, tux_y - 32, scroll_x))
524 tux_ym = tux_ym + GRAVITY;
531 if (Mix_PlayingMusic())
544 tux_x = tux_x + tux_xm;
545 tux_y = tux_y + tux_ym;
548 /* Keep tux in bounds: */
552 else if (tux_x > 320 && scroll_x < ((LEVEL_WIDTH * 32) - 640))
554 /* Scroll the screen in past center: */
556 scroll_x = scroll_x + (tux_x - 320);
559 if (scroll_x > ((LEVEL_WIDTH * 32) - 640))
560 scroll_x = ((LEVEL_WIDTH * 32) - 640);
562 else if (tux_x > 608)
564 /* ... unless there's no more to scroll! */
574 if (issolid(tux_x, tux_y + 31, scroll_x) &&
575 !issolid(tux_x - tux_xm, tux_y + 31, scroll_x))
577 while (issolid(tux_x, tux_y + 31, scroll_x))
588 if (issolid(tux_x, tux_y, scroll_x) &&
589 !issolid(tux_x - tux_xm, tux_y, scroll_x))
591 while (issolid(tux_x, tux_y, scroll_x))
602 if (issolid(tux_x, tux_y + 31, scroll_x))
604 /* Set down properly: */
606 while (issolid(tux_x, tux_y + 31, scroll_x))
615 /* Reset score multiplier (for mutli-hits): */
618 score_multiplier = 1;
628 /* Bump into things: */
630 if (issolid(tux_x, tux_y, scroll_x) ||
631 (tux_size == BIG && !tux_duck &&
632 (issolid(tux_x, tux_y - 32, scroll_x))))
634 if (!issolid(tux_x - tux_xm, tux_y, scroll_x) &&
635 (tux_size == SMALL || tux_duck ||
636 !issolid(tux_x - tux_xm, tux_y - 32, scroll_x)))
638 tux_x = tux_x - tux_xm;
641 else if (!issolid(tux_x, tux_y - tux_ym, scroll_x) &&
642 (tux_size == SMALL || tux_duck ||
643 !issolid(tux_x, tux_y - 32 - tux_ym, scroll_x)))
651 /* Break bricks and empty boxes: */
655 if (isbrick(tux_x, tux_y - 32, scroll_x) ||
656 isfullbox(tux_x, tux_y - 32, scroll_x))
658 trygrabdistro(tux_x, tux_y - 64, scroll_x,
660 trybumpbadguy(tux_x, tux_y - 96, scroll_x);
662 if (isfullbox(tux_x, tux_y - 32,
665 bumpbrick(tux_x, tux_y - 32,
669 trybreakbrick(tux_x, tux_y - 32, scroll_x);
670 tryemptybox(tux_x, tux_y - 32, scroll_x);
673 if (isbrick(tux_x + 31, tux_y - 32, scroll_x) ||
674 isfullbox(tux_x + 31, tux_y - 32, scroll_x))
676 trygrabdistro(tux_x + 31,
680 trybumpbadguy(tux_x + 31,
684 if (isfullbox(tux_x + 31, tux_y - 32,
687 bumpbrick(tux_x + 31, tux_y - 32,
691 trybreakbrick(tux_x + 31,
694 tryemptybox(tux_x + 31,
701 if (isbrick(tux_x, tux_y, scroll_x) ||
702 isfullbox(tux_x, tux_y, scroll_x))
704 trygrabdistro(tux_x, tux_y - 32, scroll_x,
706 trybumpbadguy(tux_x, tux_y - 64, scroll_x);
707 if (isfullbox(tux_x, tux_y, scroll_x))
708 bumpbrick(tux_x, tux_y, scroll_x);
709 trybreakbrick(tux_x, tux_y, scroll_x);
710 tryemptybox(tux_x, tux_y, scroll_x);
713 if (isbrick(tux_x + 31, tux_y, scroll_x) ||
714 isfullbox(tux_x + 31, tux_y, scroll_x))
716 trygrabdistro(tux_x + 31,
720 trybumpbadguy(tux_x + 31,
723 if (isfullbox(tux_x + 31, tux_y, scroll_x))
724 bumpbrick(tux_x + 31, tux_y, scroll_x);
725 trybreakbrick(tux_x + 31, tux_y, scroll_x);
726 tryemptybox(tux_x + 31, tux_y, scroll_x);
732 /* It's a brick and we're small, make the brick
733 bounce, and grab any distros above it: */
735 if (isbrick(tux_x, tux_y, scroll_x) ||
736 isfullbox(tux_x, tux_y, scroll_x))
738 trygrabdistro(tux_x, tux_y - 32, scroll_x,
740 trybumpbadguy(tux_x, tux_y - 64, scroll_x);
741 bumpbrick(tux_x, tux_y, scroll_x);
742 tryemptybox(tux_x, tux_y, scroll_x);
745 if (isbrick(tux_x + 31, tux_y, scroll_x) ||
746 isfullbox(tux_x + 31, tux_y, scroll_x))
748 trygrabdistro(tux_x + 31, tux_y - 32, scroll_x,
750 trybumpbadguy(tux_x + 31, tux_y - 64, scroll_x);
751 bumpbrick(tux_x + 31, tux_y, scroll_x);
752 tryemptybox(tux_x + 31, tux_y, scroll_x);
756 /* Get a distro from a brick? */
758 if (shape(tux_x, tux_y, scroll_x) == 'x' ||
759 shape(tux_x, tux_y, scroll_x) == 'y')
761 add_bouncy_distro(((tux_x + scroll_x + 1)
765 if (counting_distros == NO)
767 counting_distros = YES;
768 distro_counter = 100;
771 if (distro_counter <= 0)
772 change(tux_x, tux_y, scroll_x, 'a');
775 playsound(sounds[SND_DISTRO]);
777 score = score + SCORE_DISTRO;
780 else if (shape(tux_x + 31, tux_y, scroll_x) == 'x' ||
781 shape(tux_x + 31, tux_y, scroll_x) == 'y')
783 add_bouncy_distro(((tux_x + scroll_x + 1 + 31)
787 if (counting_distros == NO)
789 counting_distros = YES;
790 distro_counter = 100;
793 if (distro_counter <= 0)
794 change(tux_x + 31, tux_y, scroll_x, 'a');
797 playsound(sounds[SND_DISTRO]);
799 score = score + SCORE_DISTRO;
807 tux_y = (tux_y / 32) * 32 + 30;
813 tux_y = (tux_y / 32) * 32 - 32;
818 jump_counter = MAX_JUMP_COUNT;
828 trygrabdistro(tux_x, tux_y, scroll_x, NO_BOUNCE);
829 trygrabdistro(tux_x + 31, tux_y, scroll_x, NO_BOUNCE);
831 if (tux_size == BIG && !tux_duck)
833 trygrabdistro(tux_x, tux_y - 32, scroll_x, NO_BOUNCE);
834 trygrabdistro(tux_x + 31, tux_y - 32, scroll_x, NO_BOUNCE);
839 /* Keep in-bounds, vertically: */
843 else if (tux_y > 480)
849 /* Slow down horizontally: */
853 if (right == UP && left == UP)
855 if (isice(tux_x, tux_y + 32, scroll_x) ||
856 !issolid(tux_x, tux_y + 32, scroll_x))
858 /* Slowly on ice or in air: */
867 /* Quickly, otherwise: */
874 /* Drop vertically: */
876 if (!issolid(tux_x, tux_y + 32, scroll_x))
878 tux_ym = tux_ym + GRAVITY;
890 /* ---- DONE HANDLING TUX! --- */
893 /* Handle bouncy distros: */
895 for (i = 0; i < NUM_BOUNCY_DISTROS; i++)
897 if (bouncy_distros[i].alive)
899 bouncy_distros[i].y = bouncy_distros[i].y + bouncy_distros[i].ym;
901 bouncy_distros[i].ym++;
903 if (bouncy_distros[i].ym >= 0)
904 bouncy_distros[i].alive = NO;
909 /* Handle broken bricks: */
911 for (i = 0; i < NUM_BROKEN_BRICKS; i++)
913 if (broken_bricks[i].alive)
915 broken_bricks[i].x = broken_bricks[i].x + broken_bricks[i].xm;
916 broken_bricks[i].y = broken_bricks[i].y + broken_bricks[i].ym;
918 broken_bricks[i].ym++;
920 if (broken_bricks[i].ym >= 0)
921 broken_bricks[i].alive = NO;
926 /* Handle distro counting: */
928 if (counting_distros == YES)
932 if (distro_counter <= 0)
933 counting_distros = -1;
937 /* Handle bouncy bricks: */
939 for (i = 0; i < NUM_BOUNCY_BRICKS; i++)
941 if (bouncy_bricks[i].alive)
943 bouncy_bricks[i].offset = (bouncy_bricks[i].offset +
944 bouncy_bricks[i].offset_m);
948 if (bouncy_bricks[i].offset < -BOUNCY_BRICK_MAX_OFFSET)
949 bouncy_bricks[i].offset_m = BOUNCY_BRICK_SPEED;
954 if (bouncy_bricks[i].offset == 0)
955 bouncy_bricks[i].alive = NO;
960 /* Handle floating scores: */
962 for (i = 0; i < NUM_FLOATING_SCORES; i++)
964 if (floating_scores[i].alive)
966 floating_scores[i].y = floating_scores[i].y - 2;
967 floating_scores[i].timer--;
969 if (floating_scores[i].timer <= 0)
970 floating_scores[i].alive = NO;
975 /* Handle bullets: */
977 for (i = 0; i < NUM_BULLETS; i++)
979 if (bullets[i].alive)
981 bullets[i].x = bullets[i].x + bullets[i].xm;
982 bullets[i].y = bullets[i].y + bullets[i].ym;
984 if (issolid(bullets[i].x, bullets[i].y, 0))
986 if (issolid(bullets[i].x, bullets[i].y - bullets[i].ym, 0))
987 bullets[i].alive = NO;
990 if (bullets[i].ym >= 0)
992 bullets[i].y = (bullets[i].y / 32) * 32 - 8;
994 bullets[i].ym = -bullets[i].ym;
998 bullets[i].ym = bullets[i].ym + GRAVITY;
1000 if (bullets[i].x < scroll_x ||
1001 bullets[i].x > scroll_x + 640)
1003 bullets[i].alive = NO;
1008 if (bullets[i].alive)
1010 for (j = 0; j < NUM_BAD_GUYS; j++)
1012 if (bad_guys[j].alive && !bad_guys[j].dying)
1014 if (bullets[i].x >= bad_guys[j].x - 4 &&
1015 bullets[i].x <= bad_guys[j].x + 32 + 4 &&
1016 bullets[i].y >= bad_guys[j].y - 4 &&
1017 bullets[i].y <= bad_guys[j].y + 32 + 4)
1019 bullets[i].alive = 0;
1020 bad_guys[j].dying = FALLING;
1021 bad_guys[j].ym = -8;
1023 playsound(sounds[SND_FALL]);
1032 /* Handle background timer: */
1034 if (super_bkgd_time)
1038 /* Handle invincibility timer: */
1040 if (tux_invincible_time)
1041 tux_invincible_time--;
1044 /* Handle upgrades: */
1046 for (i = 0; i < NUM_UPGRADES; i++)
1048 if (upgrades[i].alive)
1050 if (upgrades[i].height < 32)
1054 upgrades[i].height++;
1060 if (upgrades[i].kind == UPGRADE_MINTS ||
1061 upgrades[i].kind == UPGRADE_HERRING)
1063 upgrades[i].x = upgrades[i].x + upgrades[i].xm;
1064 upgrades[i].y = upgrades[i].y + upgrades[i].ym;
1066 if (issolid(upgrades[i].x, upgrades[i].y + 31, 0) ||
1067 issolid(upgrades[i].x + 31, upgrades[i].y + 31, 0))
1069 if (upgrades[i].ym > 0)
1071 if (upgrades[i].kind == UPGRADE_MINTS)
1075 else if (upgrades[i].kind == UPGRADE_HERRING)
1077 upgrades[i].ym = -24;
1080 upgrades[i].y = (upgrades[i].y / 32) * 32;
1084 upgrades[i].ym = upgrades[i].ym + GRAVITY;
1086 if (issolid(upgrades[i].x, upgrades[i].y, 0))
1088 upgrades[i].xm = -upgrades[i].xm;
1093 /* Off the screen? Kill it! */
1095 if (upgrades[i].x < scroll_x)
1096 upgrades[i].alive = NO;
1099 /* Did the player grab it? */
1101 if (tux_x + scroll_x >= upgrades[i].x - 32 &&
1102 tux_x + scroll_x <= upgrades[i].x + 32 &&
1103 tux_y >= upgrades[i].y - 32 &&
1104 tux_y <= upgrades[i].y + 32)
1106 /* Remove the upgrade: */
1108 upgrades[i].alive = NO;
1111 /* Affect the player: */
1113 if (upgrades[i].kind == UPGRADE_MINTS)
1116 playsound(sounds[SND_EXCELLENT]);
1119 super_bkgd_time = 8;
1121 else if (upgrades[i].kind == UPGRADE_COFFEE)
1124 playsound(sounds[SND_COFFEE]);
1126 tux_got_coffee = YES;
1127 super_bkgd_time = 4;
1129 else if (upgrades[i].kind == UPGRADE_HERRING)
1132 playsound(sounds[SND_HERRING]);
1134 tux_invincible_time = 200;
1135 super_bkgd_time = 4;
1143 /* Handle bad guys: */
1145 for (i = 0; i < NUM_BAD_GUYS; i++)
1147 if (bad_guys[i].alive)
1149 if (bad_guys[i].seen)
1151 if (bad_guys[i].kind == BAD_BSOD)
1153 /* --- BLUE SCREEN OF DEATH MONSTER: --- */
1155 /* Move left/right: */
1157 if (bad_guys[i].dying == NO ||
1158 bad_guys[i].dying == FALLING)
1160 if (bad_guys[i].dir == RIGHT)
1161 bad_guys[i].x = bad_guys[i].x + 4;
1162 else if (bad_guys[i].dir == LEFT)
1163 bad_guys[i].x = bad_guys[i].x - 4;
1167 /* Move vertically: */
1169 bad_guys[i].y = bad_guys[i].y + bad_guys[i].ym;
1172 /* Bump into things horizontally: */
1174 if (!bad_guys[i].dying)
1176 if (issolid(bad_guys[i].x, bad_guys[i].y, 0))
1177 bad_guys[i].dir = !bad_guys[i].dir;
1181 /* Bump into other bad guys: */
1183 for (j = 0; j < NUM_BAD_GUYS; j++)
1185 if (j != i && bad_guys[j].alive &&
1186 !bad_guys[j].dying && !bad_guys[i].dying &&
1187 bad_guys[i].x >= bad_guys[j].x - 32 &&
1188 bad_guys[i].x <= bad_guys[j].x + 32 &&
1189 bad_guys[i].y >= bad_guys[j].y - 32 &&
1190 bad_guys[i].y <= bad_guys[j].y + 32)
1192 bad_guys[i].dir = !bad_guys[i].dir;
1197 /* Fall if we get off the ground: */
1199 if (bad_guys[i].dying != FALLING)
1201 if (!issolid(bad_guys[i].x, bad_guys[i].y + 32, 0) &&
1202 bad_guys[i].ym < MAX_YM)
1204 bad_guys[i].ym = bad_guys[i].ym + GRAVITY;
1210 if (bad_guys[i].ym > 0)
1212 bad_guys[i].y = (bad_guys[i].y / 32) * 32;
1218 bad_guys[i].ym = bad_guys[i].ym + GRAVITY;
1220 if (bad_guys[i].y > 480)
1221 bad_guys[i].alive = NO;
1223 else if (bad_guys[i].kind == BAD_LAPTOP)
1225 /* --- LAPTOP MONSTER: --- */
1227 /* Move left/right: */
1229 if (bad_guys[i].mode != FLAT && bad_guys[i].mode != KICK)
1231 if (bad_guys[i].dying == NO ||
1232 bad_guys[i].dying == FALLING)
1234 if (bad_guys[i].dir == RIGHT)
1235 bad_guys[i].x = bad_guys[i].x + 4;
1236 else if (bad_guys[i].dir == LEFT)
1237 bad_guys[i].x = bad_guys[i].x - 4;
1240 else if (bad_guys[i].mode == KICK)
1242 if (bad_guys[i].dir == RIGHT)
1243 bad_guys[i].x = bad_guys[i].x + 16;
1244 else if (bad_guys[i].dir == LEFT)
1245 bad_guys[i].x = bad_guys[i].x - 16;
1249 /* Move vertically: */
1251 bad_guys[i].y = bad_guys[i].y + bad_guys[i].ym;
1254 /* Bump into things horizontally: */
1256 if (!bad_guys[i].dying)
1258 if (issolid(bad_guys[i].x, bad_guys[i].y, 0))
1260 bad_guys[i].dir = !bad_guys[i].dir;
1263 if (bad_guys[i].mode == KICK)
1264 playsound(sounds[SND_RICOCHET]);
1270 /* Bump into other bad guys: */
1272 for (j = 0; j < NUM_BAD_GUYS; j++)
1274 if (j != i && bad_guys[j].alive &&
1275 !bad_guys[j].dying && !bad_guys[i].dying &&
1276 bad_guys[i].x >= bad_guys[j].x - 32 &&
1277 bad_guys[i].x <= bad_guys[j].x + 32 &&
1278 bad_guys[i].y >= bad_guys[j].y - 32 &&
1279 bad_guys[i].y <= bad_guys[j].y + 32)
1281 if (bad_guys[i].mode != KICK)
1282 bad_guys[i].dir = !bad_guys[i].dir;
1285 /* We're in kick mode, kill the other guy: */
1287 bad_guys[j].dying = FALLING;
1288 bad_guys[j].ym = -8;
1290 playsound(sounds[SND_FALL]);
1293 add_score(bad_guys[i].x - scroll_x,
1294 bad_guys[i].y, 100);
1300 /* Fall if we get off the ground: */
1302 if (bad_guys[i].dying != FALLING)
1304 if (!issolid(bad_guys[i].x, bad_guys[i].y + 32, 0) &&
1305 bad_guys[i].ym < MAX_YM)
1307 bad_guys[i].ym = bad_guys[i].ym + GRAVITY;
1313 if (bad_guys[i].ym > 0)
1315 bad_guys[i].y = (bad_guys[i].y / 32) * 32;
1321 bad_guys[i].ym = bad_guys[i].ym + GRAVITY;
1323 if (bad_guys[i].y > 480)
1324 bad_guys[i].alive = NO;
1326 else if (bad_guys[i].kind == BAD_MONEY)
1328 /* --- MONEY BAGS: --- */
1331 /* Move vertically: */
1333 bad_guys[i].y = bad_guys[i].y + bad_guys[i].ym;
1336 /* Fall if we get off the ground: */
1338 if (bad_guys[i].dying != FALLING)
1340 if (!issolid(bad_guys[i].x, bad_guys[i].y + 32, 0))
1342 if (bad_guys[i].ym < MAX_YM)
1344 bad_guys[i].ym = bad_guys[i].ym + GRAVITY;
1351 if (bad_guys[i].ym > 0)
1353 bad_guys[i].y = (bad_guys[i].y / 32) * 32;
1354 bad_guys[i].ym = -MAX_YM;
1359 bad_guys[i].ym = bad_guys[i].ym + GRAVITY;
1361 if (bad_guys[i].y > 480)
1362 bad_guys[i].alive = NO;
1364 else if (bad_guys[i].kind == -1)
1369 /* Kill it if the player jumped on it: */
1371 if (!bad_guys[i].dying && !tux_dying && !tux_safe &&
1372 tux_x + scroll_x >= bad_guys[i].x - 32 &&
1373 tux_x + scroll_x <= bad_guys[i].x + 32 &&
1374 tux_y >= bad_guys[i].y - 32 &&
1375 tux_y <= bad_guys[i].y - 8
1379 if (bad_guys[i].kind == BAD_BSOD)
1381 bad_guys[i].dying = SQUISHED;
1382 bad_guys[i].timer = 16;
1383 tux_ym = -KILL_BOUNCE_YM;
1385 add_score(bad_guys[i].x - scroll_x, bad_guys[i].y,
1386 50 * score_multiplier);
1389 playsound(sounds[SND_SQUISH]);
1392 else if (bad_guys[i].kind == BAD_LAPTOP)
1394 if (bad_guys[i].mode != FLAT)
1398 bad_guys[i].mode = FLAT;
1400 bad_guys[i].timer = 64;
1408 bad_guys[i].mode = KICK;
1410 if (tux_x + scroll_x <= bad_guys[i].x)
1411 bad_guys[i].dir = RIGHT;
1413 bad_guys[i].dir = LEFT;
1415 bad_guys[i].timer = 8;
1418 tux_ym = -KILL_BOUNCE_YM;
1420 add_score(bad_guys[i].x - scroll_x,
1422 25 * score_multiplier);
1425 /* playsound(sounds[SND_SQUISH]); */
1428 else if (bad_guys[i].kind == -1)
1436 /* Hurt the player if he just touched it: */
1438 if (!bad_guys[i].dying && !tux_dying &&
1440 tux_x + scroll_x >= bad_guys[i].x - 32 &&
1441 tux_x + scroll_x <= bad_guys[i].x + 32 &&
1442 tux_y >= bad_guys[i].y - 32 &&
1443 tux_y <= bad_guys[i].y + 32)
1445 if (bad_guys[i].mode == FLAT)
1449 bad_guys[i].mode = KICK;
1451 if (tux_x < bad_guys[i].x)
1453 bad_guys[i].dir = RIGHT;
1454 bad_guys[i].x = bad_guys[i].x + 16;
1458 bad_guys[i].dir = LEFT;
1459 bad_guys[i].x = bad_guys[i].x - 16;
1462 bad_guys[i].timer = 8;
1464 else if (bad_guys[i].mode == KICK)
1466 if (tux_y < bad_guys[i].y - 16 &&
1467 bad_guys[i].timer == 0)
1469 /* Step on (stop being kicked) */
1471 bad_guys[i].mode = FLAT;
1472 bad_guys[i].timer = 64;
1476 /* Hurt if you get hit by kicked laptop: */
1478 if (bad_guys[i].timer == 0)
1480 if (tux_invincible_time == 0)
1486 bad_guys[i].dying = FALLING;
1487 bad_guys[i].ym = -8;
1489 playsound(sounds[SND_FALL]);
1497 if (tux_invincible_time == 0)
1503 bad_guys[i].dying = FALLING;
1504 bad_guys[i].ym = -8;
1506 playsound(sounds[SND_FALL]);
1513 /* Handle mode timer: */
1515 if (bad_guys[i].mode == FLAT)
1517 bad_guys[i].timer--;
1519 if (bad_guys[i].timer <= 0)
1520 bad_guys[i].mode = NORMAL;
1522 else if (bad_guys[i].mode == KICK)
1524 if (bad_guys[i].timer > 0)
1525 bad_guys[i].timer--;
1529 /* Handle dying timer: */
1531 if (bad_guys[i].dying == SQUISHED)
1533 bad_guys[i].timer--;
1536 /* Remove it if time's up: */
1538 if (bad_guys[i].timer <= 0)
1539 bad_guys[i].alive = NO;
1543 /* Remove if it's far off the screen: */
1545 if (bad_guys[i].x < scroll_x - OFFSCREEN_DISTANCE)
1546 bad_guys[i].alive = NO;
1550 /* Once it's on screen, it's activated! */
1552 if (bad_guys[i].x <= scroll_x + 640 + OFFSCREEN_DISTANCE)
1553 bad_guys[i].seen = YES;
1559 /* Handle skidding: */
1561 if (tux_skidding > 0)
1569 if (tux_dying && (frame % 4) == 0)
1570 clearscreen(255, 255, 255);
1573 if (super_bkgd_time == 0)
1574 clearscreen(bkgd_red, bkgd_green, bkgd_blue);
1576 drawimage(img_super_bkgd, 0, 0, NO_UPDATE);
1580 /* Draw background: */
1582 for (y = 0; y < 15; y++)
1584 for (x = 0; x < 21; x++)
1586 drawshape(x * 32 - (scroll_x % 32), y * 32,
1587 tiles[y][x + (scroll_x / 32)]);
1592 /* (Bouncy bricks): */
1594 for (i = 0; i < NUM_BOUNCY_BRICKS; i++)
1596 if (bouncy_bricks[i].alive)
1598 if (bouncy_bricks[i].x >= scroll_x - 32 &&
1599 bouncy_bricks[i].x <= scroll_x + 640)
1601 dest.x = bouncy_bricks[i].x - scroll_x;
1602 dest.y = bouncy_bricks[i].y;
1606 SDL_FillRect(screen, &dest, SDL_MapRGB(screen->format,
1611 drawshape(bouncy_bricks[i].x - scroll_x,
1612 bouncy_bricks[i].y + bouncy_bricks[i].offset,
1613 bouncy_bricks[i].shape);
1621 for (i = 0; i < NUM_BAD_GUYS; i++)
1623 if (bad_guys[i].alive &&
1624 bad_guys[i].x > scroll_x - 32 &&
1625 bad_guys[i].x < scroll_x + 640)
1627 if (bad_guys[i].kind == BAD_BSOD)
1629 /* --- BLUE SCREEN OF DEATH MONSTER: --- */
1631 if (bad_guys[i].dying == NO)
1635 if (bad_guys[i].dir == LEFT)
1637 drawimage(img_bsod_left[(frame / 5) % 4],
1638 bad_guys[i].x - scroll_x,
1644 drawimage(img_bsod_right[(frame / 5) % 4],
1645 bad_guys[i].x - scroll_x,
1650 else if (bad_guys[i].dying == FALLING)
1654 if (bad_guys[i].dir == LEFT)
1656 drawimage(img_bsod_falling_left,
1657 bad_guys[i].x - scroll_x,
1663 drawimage(img_bsod_falling_right,
1664 bad_guys[i].x - scroll_x,
1669 else if (bad_guys[i].dying == SQUISHED)
1671 /* Dying - Squished: */
1673 if (bad_guys[i].dir == LEFT)
1675 drawimage(img_bsod_squished_left,
1676 bad_guys[i].x - scroll_x,
1682 drawimage(img_bsod_squished_right,
1683 bad_guys[i].x - scroll_x,
1689 else if (bad_guys[i].kind == BAD_LAPTOP)
1691 /* --- LAPTOP MONSTER: --- */
1693 if (bad_guys[i].dying == NO)
1697 if (bad_guys[i].mode == NORMAL)
1701 if (bad_guys[i].dir == LEFT)
1703 drawimage(img_laptop_left[(frame / 5) % 3],
1704 bad_guys[i].x - scroll_x,
1710 drawimage(img_laptop_right[(frame / 5) % 3],
1711 bad_guys[i].x - scroll_x,
1720 if (bad_guys[i].dir == LEFT)
1722 drawimage(img_laptop_flat_left,
1723 bad_guys[i].x - scroll_x,
1729 drawimage(img_laptop_flat_right,
1730 bad_guys[i].x - scroll_x,
1736 else if (bad_guys[i].dying == FALLING)
1740 if (bad_guys[i].dir == LEFT)
1742 drawimage(img_laptop_falling_left,
1743 bad_guys[i].x - scroll_x,
1749 drawimage(img_laptop_falling_right,
1750 bad_guys[i].x - scroll_x,
1756 else if (bad_guys[i].kind == BAD_MONEY)
1758 if (bad_guys[i].ym > -16)
1760 if (bad_guys[i].dir == LEFT)
1762 drawimage(img_money_left[0],
1763 bad_guys[i].x - scroll_x,
1769 drawimage(img_money_right[0],
1770 bad_guys[i].x - scroll_x,
1777 if (bad_guys[i].dir == LEFT)
1779 drawimage(img_money_left[1],
1780 bad_guys[i].x - scroll_x,
1786 drawimage(img_money_right[1],
1787 bad_guys[i].x - scroll_x,
1793 else if (bad_guys[i].kind == -1)
1802 if (right == UP && left == UP)
1809 if ((fire == DOWN && (frame % 2) == 0) ||
1811 tux_frame_main = (tux_frame_main + 1) % 4;
1813 tux_frame = tux_frame_main;
1820 if (tux_got_coffee && (frame % 2) == 1)
1824 drawimage(img_red_glow, tux_x - 8, tux_y - 32, NO_UPDATE);
1828 if (tux_safe == 0 || (frame % 2) == 0)
1830 if (tux_size == SMALL)
1832 if (tux_invincible_time)
1836 if (tux_dir == RIGHT)
1838 drawimage(cape_right[frame % 2],
1844 drawimage(cape_left[frame % 2],
1851 if (tux_dir == RIGHT)
1853 drawimage(tux_right[tux_frame], tux_x, tux_y, NO_UPDATE);
1857 drawimage(tux_left[tux_frame], tux_x, tux_y, NO_UPDATE);
1862 if (tux_invincible_time)
1866 if (tux_dir == RIGHT)
1868 drawimage(bigcape_right[frame % 2],
1869 tux_x - 8 - 16, tux_y - 32,
1874 drawimage(bigcape_left[frame % 2],
1875 tux_x - 8, tux_y - 32,
1884 if (!jumping || tux_ym > 0)
1886 if (tux_dir == RIGHT)
1888 drawimage(bigtux_right[tux_frame],
1889 tux_x - 8, tux_y - 32,
1894 drawimage(bigtux_left[tux_frame],
1895 tux_x - 8, tux_y - 32,
1901 if (tux_dir == RIGHT)
1903 drawimage(bigtux_right_jump,
1904 tux_x - 8, tux_y - 32,
1909 drawimage(bigtux_left_jump,
1910 tux_x - 8, tux_y - 32,
1917 if (tux_dir == RIGHT)
1919 drawimage(skidtux_right,
1920 tux_x - 8, tux_y - 32,
1925 drawimage(skidtux_left,
1926 tux_x - 8, tux_y - 32,
1933 if (tux_dir == RIGHT)
1935 drawimage(ducktux_right, tux_x - 8, tux_y - 16,
1940 drawimage(ducktux_left, tux_x - 8, tux_y - 16,
1950 for (i = 0; i < NUM_BULLETS; i++)
1952 if (bullets[i].alive &&
1953 bullets[i].x >= scroll_x - 4 &&
1954 bullets[i].x <= scroll_x + 640)
1956 drawimage(img_bullet, bullets[i].x - scroll_x, bullets[i].y,
1962 /* (Floating scores): */
1964 for (i = 0; i < NUM_FLOATING_SCORES; i++)
1966 if (floating_scores[i].alive)
1968 sprintf(str, "%d", floating_scores[i].value);
1970 floating_scores[i].x + 16 - strlen(str) * 8,
1971 floating_scores[i].y,
1972 letters_gold, NO_UPDATE);
1979 for (i = 0; i < NUM_UPGRADES; i++)
1981 if (upgrades[i].alive)
1983 if (upgrades[i].height < 32)
1987 dest.x = upgrades[i].x - scroll_x;
1988 dest.y = upgrades[i].y + 32 - upgrades[i].height;
1990 dest.h = upgrades[i].height;
1995 src.h = upgrades[i].height;
1997 if (upgrades[i].kind == UPGRADE_MINTS)
1998 SDL_BlitSurface(img_mints, &src, screen, &dest);
1999 else if (upgrades[i].kind == UPGRADE_COFFEE)
2000 SDL_BlitSurface(img_coffee, &src, screen, &dest);
2001 else if (upgrades[i].kind == UPGRADE_HERRING)
2002 SDL_BlitSurface(img_golden_herring, &src, screen, &dest);
2006 if (upgrades[i].kind == UPGRADE_MINTS)
2008 drawimage(img_mints,
2009 upgrades[i].x - scroll_x, upgrades[i].y,
2012 else if (upgrades[i].kind == UPGRADE_COFFEE)
2014 drawimage(img_coffee,
2015 upgrades[i].x - scroll_x, upgrades[i].y,
2018 else if (upgrades[i].kind == UPGRADE_HERRING)
2020 drawimage(img_golden_herring,
2021 upgrades[i].x - scroll_x, upgrades[i].y,
2029 /* (Bouncy distros): */
2031 for (i = 0; i < NUM_BOUNCY_DISTROS; i++)
2033 if (bouncy_distros[i].alive)
2035 drawimage(img_distro[0],
2036 bouncy_distros[i].x - scroll_x,
2037 bouncy_distros[i].y,
2043 /* (Broken bricks): */
2045 for (i = 0; i < NUM_BROKEN_BRICKS; i++)
2047 if (broken_bricks[i].alive)
2049 src.x = rand() % 16;
2050 src.y = rand() % 16;
2054 dest.x = broken_bricks[i].x - scroll_x;
2055 dest.y = broken_bricks[i].y;
2059 SDL_BlitSurface(img_brick[0], &src, screen, &dest);
2066 sprintf(str, "%d", score);
2067 drawtext("SCORE", 0, 0, letters_blue, NO_UPDATE);
2068 drawtext(str, 96, 0, letters_gold, NO_UPDATE);
2070 if (time_left >= 50 || (frame % 10) < 5)
2072 sprintf(str, "%d", time_left);
2073 drawtext("TIME", 224, 0, letters_blue, NO_UPDATE);
2074 drawtext(str, 304, 0, letters_gold, NO_UPDATE);
2077 sprintf(str, "%d", distros);
2078 drawtext("DISTROS", 480, 0, letters_blue, NO_UPDATE);
2079 drawtext(str, 608, 0, letters_gold, NO_UPDATE);
2082 /* (Update it all!) */
2087 /* Keep playing music: */
2092 if (!Mix_PlayingMusic())
2094 Mix_PlayMusic(song, 1);
2100 /* Pause til next frame: */
2102 now_time = SDL_GetTicks();
2103 if (now_time < last_time + FPS)
2104 SDL_Delay(last_time + FPS - now_time);
2109 if ((frame % 10) == 0 && time_left > 0)
2117 while (!done && !quit);
2122 if (Mix_PlayingMusic())
2135 /* Initialize the game stuff: */
2146 /* Load data for this level: */
2148 void loadlevel(void)
2154 char line[LEVEL_WIDTH + 5];
2159 for (i = 0; i < NUM_BOUNCY_DISTROS; i++)
2160 bouncy_distros[i].alive = NO;
2162 for (i = 0; i < NUM_BROKEN_BRICKS; i++)
2163 broken_bricks[i].alive = NO;
2165 for (i = 0; i < NUM_BOUNCY_BRICKS; i++)
2166 bouncy_bricks[i].alive = NO;
2168 for (i = 0; i < NUM_BAD_GUYS; i++)
2169 bad_guys[i].alive = NO;
2171 for (i = 0; i < NUM_FLOATING_SCORES; i++)
2172 floating_scores[i].alive = NO;
2174 for (i = 0; i < NUM_UPGRADES; i++)
2175 upgrades[i].alive = NO;
2177 for (i = 0; i < NUM_BULLETS; i++)
2178 bullets[i].alive = NO;
2181 /* Load data file: */
2183 filename = strdup(DATA_PREFIX "/levels/level1.dat");
2184 fi = fopen(filename, "r");
2192 fgets(line, 10, fi);
2193 bkgd_red = atoi(line);
2194 fgets(line, 10, fi);
2195 bkgd_green= atoi(line);
2196 fgets(line, 10, fi);
2197 bkgd_blue = atoi(line);
2199 for (y = 0; y < 15; y++)
2201 fgets(line, LEVEL_WIDTH + 5, fi);
2202 line[strlen(line) - 1] = '\0';
2203 strcpy(tiles[y], line);
2209 /* Activate bad guys: */
2211 for (y = 0; y < 15; y++)
2213 for (x = 0; x < LEVEL_WIDTH; x++)
2215 if (tiles[y][x] >= '0' && tiles[y][x] <= '9')
2217 add_bad_guy(x * 32, y * 32, tiles[y][x] - '0');
2232 tux_got_coffee = NO;
2233 tux_invincible_time = 0;
2237 tux_safe = TUX_SAFE_TIME;
2253 score_multiplier = 1;
2254 super_bkgd_time = 0;
2258 counting_distros = NO;
2264 clearscreen(0, 0, 0);
2266 sprintf(str, "LEVEL %d", level + 1);
2267 drawcenteredtext(str, 200, letters_red, NO_UPDATE);
2269 sprintf(str, "%s", levelnames[level]);
2270 drawcenteredtext(str, 224, letters_gold, NO_UPDATE);
2272 sprintf(str, "TUX x %d", lives);
2273 drawcenteredtext(str, 256, letters_blue, NO_UPDATE);
2281 /* Load graphics: */
2283 void loadlevelgfx(void)
2285 img_brick[0] = load_image(DATA_PREFIX "/images/level1/brick0.png",
2287 img_brick[1] = load_image(DATA_PREFIX "/images/level1/brick1.png",
2290 img_solid[0] = load_image(DATA_PREFIX "/images/level1/solid0.png",
2292 img_solid[1] = load_image(DATA_PREFIX "/images/level1/solid1.png",
2294 img_solid[2] = load_image(DATA_PREFIX "/images/level1/solid2.png",
2296 img_solid[3] = load_image(DATA_PREFIX "/images/level1/solid3.png",
2299 img_bkgd[0][0] = load_image(DATA_PREFIX "/images/level1/bkgd-00.png",
2301 img_bkgd[0][1] = load_image(DATA_PREFIX "/images/level1/bkgd-01.png",
2303 img_bkgd[0][2] = load_image(DATA_PREFIX "/images/level1/bkgd-02.png",
2305 img_bkgd[0][3] = load_image(DATA_PREFIX "/images/level1/bkgd-03.png",
2308 img_bkgd[1][0] = load_image(DATA_PREFIX "/images/level1/bkgd-10.png",
2310 img_bkgd[1][1] = load_image(DATA_PREFIX "/images/level1/bkgd-11.png",
2312 img_bkgd[1][2] = load_image(DATA_PREFIX "/images/level1/bkgd-12.png",
2314 img_bkgd[1][3] = load_image(DATA_PREFIX "/images/level1/bkgd-13.png",
2321 void loadlevelsong(void)
2324 song = load_song(DATA_PREFIX "/music/ji_turn.it");
2329 /* Free graphics data for this level: */
2331 void unloadlevelgfx(void)
2335 for (i = 0; i < 2; i++)
2337 SDL_FreeSurface(img_brick[i]);
2339 for (i = 0; i < 4; i++)
2341 SDL_FreeSurface(img_solid[i]);
2342 SDL_FreeSurface(img_bkgd[0][i]);
2343 SDL_FreeSurface(img_bkgd[1][i]);
2348 /* Free music data for this level: */
2350 void unloadlevelsong(void)
2355 Mix_FreeMusic(song);
2361 /* Load graphics shared between all levels: */
2363 void loadshared(void)
2372 tux_right[0] = load_image(DATA_PREFIX "/images/shared/tux-right-0.png",
2375 tux_right[1] = load_image(DATA_PREFIX "/images/shared/tux-right-1.png",
2378 tux_right[2] = load_image(DATA_PREFIX "/images/shared/tux-right-2.png",
2381 tux_left[0] = load_image(DATA_PREFIX "/images/shared/tux-left-0.png",
2384 tux_left[1] = load_image(DATA_PREFIX "/images/shared/tux-left-1.png",
2387 tux_left[2] = load_image(DATA_PREFIX "/images/shared/tux-left-2.png",
2390 cape_right[0] = load_image(DATA_PREFIX "/images/shared/cape-right-0.png",
2393 cape_right[1] = load_image(DATA_PREFIX "/images/shared/cape-right-1.png",
2396 cape_left[0] = load_image(DATA_PREFIX "/images/shared/cape-left-0.png",
2399 cape_left[1] = load_image(DATA_PREFIX "/images/shared/cape-left-1.png",
2402 bigtux_right[0] = load_image(DATA_PREFIX "/images/shared/bigtux-right-0.png",
2405 bigtux_right[1] = load_image(DATA_PREFIX "/images/shared/bigtux-right-1.png",
2408 bigtux_right[2] = load_image(DATA_PREFIX "/images/shared/bigtux-right-2.png",
2412 load_image(DATA_PREFIX "/images/shared/bigtux-right-jump.png", USE_ALPHA);
2414 bigtux_left[0] = load_image(DATA_PREFIX "/images/shared/bigtux-left-0.png",
2417 bigtux_left[1] = load_image(DATA_PREFIX "/images/shared/bigtux-left-1.png",
2420 bigtux_left[2] = load_image(DATA_PREFIX "/images/shared/bigtux-left-2.png",
2424 load_image(DATA_PREFIX "/images/shared/bigtux-left-jump.png", USE_ALPHA);
2427 load_image(DATA_PREFIX "/images/shared/bigcape-right-0.png",
2431 load_image(DATA_PREFIX "/images/shared/bigcape-right-1.png",
2435 load_image(DATA_PREFIX "/images/shared/bigcape-left-0.png",
2439 load_image(DATA_PREFIX "/images/shared/bigcape-left-1.png",
2442 ducktux_right = load_image(DATA_PREFIX
2443 "/images/shared/ducktux-right.png",
2446 ducktux_left = load_image(DATA_PREFIX
2447 "/images/shared/ducktux-left.png",
2450 skidtux_right = load_image(DATA_PREFIX
2451 "/images/shared/skidtux-right.png",
2454 skidtux_left = load_image(DATA_PREFIX
2455 "/images/shared/skidtux-left.png",
2461 img_box_full = load_image(DATA_PREFIX "/images/shared/box-full.png",
2463 img_box_empty = load_image(DATA_PREFIX "/images/shared/box-empty.png",
2470 img_water = load_image(DATA_PREFIX "/images/shared/water.png", IGNORE_ALPHA);
2472 img_waves[0] = load_image(DATA_PREFIX "/images/shared/waves-0.png",
2475 img_waves[1] = load_image(DATA_PREFIX "/images/shared/waves-1.png",
2478 img_waves[2] = load_image(DATA_PREFIX "/images/shared/waves-2.png",
2484 img_pole = load_image(DATA_PREFIX "/images/shared/pole.png", USE_ALPHA);
2485 img_poletop = load_image(DATA_PREFIX "/images/shared/poletop.png",
2491 img_flag[0] = load_image(DATA_PREFIX "/images/shared/flag-0.png",
2493 img_flag[1] = load_image(DATA_PREFIX "/images/shared/flag-1.png",
2499 img_cloud[0][0] = load_image(DATA_PREFIX "/images/shared/cloud-00.png",
2502 img_cloud[0][1] = load_image(DATA_PREFIX "/images/shared/cloud-01.png",
2505 img_cloud[0][2] = load_image(DATA_PREFIX "/images/shared/cloud-02.png",
2508 img_cloud[0][3] = load_image(DATA_PREFIX "/images/shared/cloud-03.png",
2512 img_cloud[1][0] = load_image(DATA_PREFIX "/images/shared/cloud-10.png",
2515 img_cloud[1][1] = load_image(DATA_PREFIX "/images/shared/cloud-11.png",
2518 img_cloud[1][2] = load_image(DATA_PREFIX "/images/shared/cloud-12.png",
2521 img_cloud[1][3] = load_image(DATA_PREFIX "/images/shared/cloud-13.png",
2529 img_bsod_left[0] = load_image(DATA_PREFIX
2530 "/images/shared/bsod-left-0.png",
2533 img_bsod_left[1] = load_image(DATA_PREFIX
2534 "/images/shared/bsod-left-1.png",
2537 img_bsod_left[2] = load_image(DATA_PREFIX
2538 "/images/shared/bsod-left-2.png",
2541 img_bsod_left[3] = load_image(DATA_PREFIX
2542 "/images/shared/bsod-left-3.png",
2545 img_bsod_right[0] = load_image(DATA_PREFIX
2546 "/images/shared/bsod-right-0.png",
2549 img_bsod_right[1] = load_image(DATA_PREFIX
2550 "/images/shared/bsod-right-1.png",
2553 img_bsod_right[2] = load_image(DATA_PREFIX
2554 "/images/shared/bsod-right-2.png",
2557 img_bsod_right[3] = load_image(DATA_PREFIX
2558 "/images/shared/bsod-right-3.png",
2561 img_bsod_squished_left = load_image(DATA_PREFIX
2562 "/images/shared/bsod-squished-left.png",
2565 img_bsod_squished_right = load_image(DATA_PREFIX
2566 "/images/shared/bsod-squished-right.png",
2569 img_bsod_falling_left = load_image(DATA_PREFIX
2570 "/images/shared/bsod-falling-left.png",
2573 img_bsod_falling_right = load_image(DATA_PREFIX
2574 "/images/shared/bsod-falling-right.png",
2580 img_laptop_left[0] = load_image(DATA_PREFIX
2581 "/images/shared/laptop-left-0.png",
2584 img_laptop_left[1] = load_image(DATA_PREFIX
2585 "/images/shared/laptop-left-1.png",
2588 img_laptop_left[2] = load_image(DATA_PREFIX
2589 "/images/shared/laptop-left-2.png",
2592 img_laptop_right[0] = load_image(DATA_PREFIX
2593 "/images/shared/laptop-right-0.png",
2596 img_laptop_right[1] = load_image(DATA_PREFIX
2597 "/images/shared/laptop-right-1.png",
2600 img_laptop_right[2] = load_image(DATA_PREFIX
2601 "/images/shared/laptop-right-2.png",
2604 img_laptop_flat_left = load_image(DATA_PREFIX
2605 "/images/shared/laptop-flat-left.png",
2608 img_laptop_flat_right = load_image(DATA_PREFIX
2609 "/images/shared/laptop-flat-right.png",
2612 img_laptop_falling_left =
2613 load_image(DATA_PREFIX
2614 "/images/shared/laptop-falling-left.png",
2617 img_laptop_falling_right =
2618 load_image(DATA_PREFIX
2619 "/images/shared/laptop-falling-right.png",
2625 img_money_left[0] = load_image(DATA_PREFIX
2626 "/images/shared/bag-left-0.png",
2629 img_money_left[1] = load_image(DATA_PREFIX
2630 "/images/shared/bag-left-1.png",
2633 img_money_right[0] = load_image(DATA_PREFIX
2634 "/images/shared/bag-right-0.png",
2637 img_money_right[1] = load_image(DATA_PREFIX
2638 "/images/shared/bag-right-1.png",
2645 img_mints = load_image(DATA_PREFIX "/images/shared/mints.png", USE_ALPHA);
2646 img_coffee = load_image(DATA_PREFIX "/images/shared/coffee.png", USE_ALPHA);
2651 img_bullet = load_image(DATA_PREFIX "/images/shared/bullet.png", USE_ALPHA);
2653 img_red_glow = load_image(DATA_PREFIX "/images/shared/red-glow.png",
2659 img_distro[0] = load_image(DATA_PREFIX "/images/shared/distro-0.png",
2662 img_distro[1] = load_image(DATA_PREFIX "/images/shared/distro-1.png",
2665 img_distro[2] = load_image(DATA_PREFIX "/images/shared/distro-2.png",
2668 img_distro[3] = load_image(DATA_PREFIX "/images/shared/distro-3.png",
2674 img_golden_herring =
2675 load_image(DATA_PREFIX "/images/shared/golden-herring.png",
2679 /* Super background: */
2681 img_super_bkgd = load_image(DATA_PREFIX "/images/shared/super-bkgd.png",
2685 /* Sound effects: */
2690 for (i = 0; i < NUM_SOUNDS; i++)
2691 sounds[i] = load_sound(soundfilenames[i]);
2697 /* Free shared data: */
2699 void unloadshared(void)
2703 for (i = 0; i < 3; i++)
2705 SDL_FreeSurface(tux_right[i]);
2706 SDL_FreeSurface(tux_left[i]);
2707 SDL_FreeSurface(bigtux_right[i]);
2708 SDL_FreeSurface(bigtux_left[i]);
2711 SDL_FreeSurface(bigtux_right_jump);
2712 SDL_FreeSurface(bigtux_left_jump);
2714 for (i = 0; i < 2; i++)
2716 SDL_FreeSurface(cape_right[i]);
2717 SDL_FreeSurface(cape_left[i]);
2718 SDL_FreeSurface(bigcape_right[i]);
2719 SDL_FreeSurface(bigcape_left[i]);
2722 SDL_FreeSurface(ducktux_left);
2723 SDL_FreeSurface(ducktux_right);
2725 SDL_FreeSurface(skidtux_left);
2726 SDL_FreeSurface(skidtux_right);
2728 for (i = 0; i < 4; i++)
2730 SDL_FreeSurface(img_bsod_left[i]);
2731 SDL_FreeSurface(img_bsod_right[i]);
2734 SDL_FreeSurface(img_bsod_squished_left);
2735 SDL_FreeSurface(img_bsod_squished_right);
2737 SDL_FreeSurface(img_bsod_falling_left);
2738 SDL_FreeSurface(img_bsod_falling_right);
2740 for (i = 0; i < 3; i++)
2742 SDL_FreeSurface(img_laptop_left[i]);
2743 SDL_FreeSurface(img_laptop_right[i]);
2746 SDL_FreeSurface(img_laptop_flat_left);
2747 SDL_FreeSurface(img_laptop_flat_right);
2749 SDL_FreeSurface(img_laptop_falling_left);
2750 SDL_FreeSurface(img_laptop_falling_right);
2752 for (i = 0; i < 2; i++)
2754 SDL_FreeSurface(img_money_left[i]);
2755 SDL_FreeSurface(img_money_right[i]);
2758 SDL_FreeSurface(img_box_full);
2759 SDL_FreeSurface(img_box_empty);
2761 SDL_FreeSurface(img_water);
2762 for (i = 0; i < 3; i++)
2763 SDL_FreeSurface(img_waves[i]);
2765 SDL_FreeSurface(img_pole);
2766 SDL_FreeSurface(img_poletop);
2768 for (i = 0; i < 2; i++)
2769 SDL_FreeSurface(img_flag[i]);
2771 SDL_FreeSurface(img_mints);
2772 SDL_FreeSurface(img_coffee);
2774 for (i = 0; i < 4; i++)
2776 SDL_FreeSurface(img_distro[i]);
2777 SDL_FreeSurface(img_cloud[0][i]);
2778 SDL_FreeSurface(img_cloud[1][i]);
2781 SDL_FreeSurface(img_golden_herring);
2786 for (i = 0; i < NUM_SOUNDS; i++)
2787 Mix_FreeChunk(sounds[i]);
2793 /* Draw a tile on the screen: */
2795 void drawshape(int x, int y, unsigned char c)
2799 if (c == 'X' || c == 'x')
2800 drawimage(img_brick[0], x, y, NO_UPDATE);
2801 else if (c == 'Y' || c == 'y')
2802 drawimage(img_brick[1], x, y, NO_UPDATE);
2803 else if (c == 'A' || c =='B' || c == '!')
2804 drawimage(img_box_full, x, y, NO_UPDATE);
2806 drawimage(img_box_empty, x, y, NO_UPDATE);
2807 else if (c >= 'C' && c <= 'F')
2808 drawimage(img_cloud[0][c - 'C'], x, y, NO_UPDATE);
2809 else if (c >= 'c' && c <= 'f')
2810 drawimage(img_cloud[1][c - 'c'], x, y, NO_UPDATE);
2811 else if (c >= 'G' && c <= 'J')
2812 drawimage(img_bkgd[0][c - 'G'], x, y, NO_UPDATE);
2813 else if (c >= 'g' && c <= 'j')
2814 drawimage(img_bkgd[1][c - 'g'], x, y, NO_UPDATE);
2816 drawimage(img_solid[0], x, y, NO_UPDATE);
2818 drawimage(img_solid[1], x, y, NO_UPDATE);
2820 drawimage(img_solid[2], x, y, NO_UPDATE);
2822 drawimage(img_solid[3], x, y, NO_UPDATE);
2825 z = (frame / 2) % 6;
2828 drawimage(img_distro[z], x, y, NO_UPDATE);
2830 drawimage(img_distro[2], x, y, NO_UPDATE);
2832 drawimage(img_distro[1], x, y, NO_UPDATE);
2836 z = (frame / 3) % 3;
2838 drawimage(img_waves[z], x, y, NO_UPDATE);
2841 drawimage(img_poletop, x, y, NO_UPDATE);
2843 drawimage(img_pole, x, y, NO_UPDATE);
2846 z = (frame / 3) % 2;
2848 drawimage(img_flag[z], x + 16, y, NO_UPDATE);
2851 drawimage(img_water, x, y, NO_UPDATE);
2855 /* What shape is at some position? */
2857 unsigned char shape(int x, int y, int sx)
2863 xx = ((x + sx) / 32);
2865 if (yy >= 0 && yy <= 15 && xx >= 0 && xx <= LEVEL_WIDTH)
2876 int issolid(int x, int y, int sx)
2882 if (isbrick(x, y, sx) ||
2883 isbrick(x + 31, y, sx) ||
2885 isice(x + 31, y, sx) ||
2886 (shape(x, y, sx) == '[' ||
2887 shape(x + 31, y, sx) == '[') ||
2888 (shape(x, y, sx) == '=' ||
2889 shape(x + 31, y, sx) == '=') ||
2890 (shape(x, y, sx) == ']' ||
2891 shape(x + 31, y, sx) == ']') ||
2892 (shape(x, y, sx) == 'A' ||
2893 shape(x + 31, y, sx) == 'A') ||
2894 (shape(x, y, sx) == 'B' ||
2895 shape(x + 31, y, sx) == 'B') ||
2896 (shape(x, y, sx) == '!' ||
2897 shape(x + 31, y, sx) == '!') ||
2898 (shape(x, y, sx) == 'a' ||
2899 shape(x + 31, y, sx) == 'a'))
2908 /* Is it a brick? */
2910 int isbrick(int x, int y, int sx)
2916 if (shape(x, y, sx) == 'X' ||
2917 shape(x, y, sx) == 'x' ||
2918 shape(x, y, sx) == 'Y' ||
2919 shape(x, y, sx) == 'y')
2930 int isice(int x, int y, int sx)
2936 if (shape(x, y, sx) == '#')
2945 /* Is it a full box? */
2947 int isfullbox(int x, int y, int sx)
2953 if (shape(x, y, sx) == 'A' ||
2954 shape(x, y, sx) == 'B' ||
2955 shape(x, y, sx) == '!')
2964 /* Edit a piece of the map! */
2966 void change(int x, int y, int sx, unsigned char c)
2971 xx = ((x + sx) / 32);
2973 if (yy >= 0 && yy <= 15 && xx >= 0 && xx <= LEVEL_WIDTH)
2978 /* Break a brick: */
2980 void trybreakbrick(int x, int y, int sx)
2982 if (isbrick(x, y, sx))
2984 if (shape(x, y, sx) == 'x' || shape(x, y, sx) == 'y')
2986 /* Get a distro from it: */
2988 add_bouncy_distro(((x + sx + 1) / 32) * 32,
2991 if (counting_distros == NO)
2993 counting_distros = YES;
2994 distro_counter = 50;
2997 if (distro_counter <= 0)
2998 change(x, y, sx, 'a');
3001 playsound(sounds[SND_DISTRO]);
3003 score = score + SCORE_DISTRO;
3008 /* Get rid of it: */
3010 change(x, y, sx, '.');
3014 /* Replace it with broken bits: */
3016 add_broken_brick(((x + sx + 1) / 32) * 32,
3020 /* Get some score: */
3023 playsound(sounds[SND_BRICK]);
3025 score = score + SCORE_BRICK;
3030 /* Bounce a brick: */
3032 void bumpbrick(int x, int y, int sx)
3034 add_bouncy_brick(((x + sx + 1) / 32) * 32,
3038 playsound(sounds[SND_BRICK]);
3045 void tryemptybox(int x, int y, int sx)
3047 if (isfullbox(x, y, sx))
3049 if (shape(x, y, sx) == 'A')
3051 /* Box with a distro! */
3053 add_bouncy_distro(((x + sx + 1) / 32) * 32,
3054 (y / 32) * 32 - 32);
3057 playsound(sounds[SND_DISTRO]);
3059 score = score + SCORE_DISTRO;
3062 else if (shape(x, y, sx) == 'B')
3064 /* Add an upgrade! */
3066 if (tux_size == SMALL)
3068 /* Tux is small, add mints! */
3070 add_upgrade(((x + sx + 1) / 32) * 32,
3076 /* Tux is big, add coffee: */
3078 add_upgrade(((x + sx + 1) / 32) * 32,
3084 playsound(sounds[SND_UPGRADE]);
3087 else if (shape(x, y, sx) == '!')
3089 /* Add a golden herring */
3091 add_upgrade(((x + sx + 1) / 32) * 32,
3096 /* Empty the box: */
3098 change(x, y, sx, 'a');
3103 /* Try to grab a distro: */
3105 void trygrabdistro(int x, int y, int sx, int bounciness)
3107 if (shape(x, y, sx) == '$')
3109 change(x, y, sx, '.');
3111 playsound(sounds[SND_DISTRO]);
3114 if (bounciness == BOUNCE)
3116 add_bouncy_distro(((x + sx + 1) / 32) * 32,
3120 score = score + SCORE_DISTRO;
3126 /* Add a bouncy distro: */
3128 void add_bouncy_distro(int x, int y)
3134 for (i = 0; i < NUM_BOUNCY_DISTROS && found == -1; i++)
3136 if (!bouncy_distros[i].alive)
3142 bouncy_distros[found].alive = YES;
3143 bouncy_distros[found].x = x;
3144 bouncy_distros[found].y = y;
3145 bouncy_distros[found].ym = -6;
3150 /* Add broken brick pieces: */
3152 void add_broken_brick(int x, int y)
3154 add_broken_brick_piece(x, y, -4, -16);
3155 add_broken_brick_piece(x, y + 16, -6, -12);
3157 add_broken_brick_piece(x + 16, y, 4, -16);
3158 add_broken_brick_piece(x + 16, y + 16, 6, -12);
3162 /* Add a broken brick piece: */
3164 void add_broken_brick_piece(int x, int y, int xm, int ym)
3170 for (i = 0; i < NUM_BROKEN_BRICKS && found == -1; i++)
3172 if (!broken_bricks[i].alive)
3178 broken_bricks[found].alive = YES;
3179 broken_bricks[found].x = x;
3180 broken_bricks[found].y = y;
3181 broken_bricks[found].xm = xm;
3182 broken_bricks[found].ym = ym;
3187 /* Add a bouncy brick piece: */
3189 void add_bouncy_brick(int x, int y)
3195 for (i = 0; i < NUM_BOUNCY_BRICKS && found == -1; i++)
3197 if (!bouncy_bricks[i].alive)
3203 bouncy_bricks[found].alive = YES;
3204 bouncy_bricks[found].x = x;
3205 bouncy_bricks[found].y = y;
3206 bouncy_bricks[found].offset = 0;
3207 bouncy_bricks[found].offset_m = -BOUNCY_BRICK_SPEED;
3208 bouncy_bricks[found].shape = shape(x, y, 0);
3213 /* Add a bad guy: */
3215 void add_bad_guy(int x, int y, int kind)
3221 for (i = 0; i < NUM_BAD_GUYS && found == -1; i++)
3223 if (!bad_guys[i].alive)
3229 bad_guys[found].alive = YES;
3230 bad_guys[found].mode = NORMAL;
3231 bad_guys[found].dying = NO;
3232 bad_guys[found].timer = 0;
3233 bad_guys[found].kind = kind;
3234 bad_guys[found].x = x;
3235 bad_guys[found].y = y;
3236 bad_guys[found].xm = 0;
3237 bad_guys[found].ym = 0;
3238 bad_guys[found].dir = LEFT;
3239 bad_guys[found].seen = NO;
3246 void add_score(int x, int y, int s)
3251 /* Add the score: */
3256 /* Add a floating score thing to the game: */
3260 for (i = 0; i < NUM_FLOATING_SCORES && found == -1; i++)
3262 if (!floating_scores[i].alive)
3269 floating_scores[found].alive = YES;
3270 floating_scores[found].x = x;
3271 floating_scores[found].y = y - 16;
3272 floating_scores[found].timer = 8;
3273 floating_scores[found].value = s;
3278 /* Try to bump a bad guy from below: */
3280 void trybumpbadguy(int x, int y, int sx)
3287 for (i = 0; i < NUM_BAD_GUYS; i++)
3289 if (bad_guys[i].alive &&
3290 bad_guys[i].x >= x + sx - 32 && bad_guys[i].x <= x + sx + 32 &&
3291 bad_guys[i].y >= y - 16 && bad_guys[i].y <= y + 16)
3293 if (bad_guys[i].kind == BAD_BSOD ||
3294 bad_guys[i].kind == BAD_LAPTOP)
3296 bad_guys[i].dying = FALLING;
3297 bad_guys[i].ym = -8;
3299 playsound(sounds[SND_FALL]);
3308 for (i = 0; i < NUM_UPGRADES; i++)
3310 if (upgrades[i].alive && upgrades[i].height == 32 &&
3311 upgrades[i].x >= x + sx - 32 && upgrades[i].x <= x + sx + 32 &&
3312 upgrades[i].y >= y - 16 && upgrades[i].y <= y + 16)
3314 upgrades[i].xm = -upgrades[i].xm;
3315 upgrades[i].ym = -8;
3317 playsound(sounds[SND_BUMP_UPGRADE]);
3324 /* Add an upgrade: */
3326 void add_upgrade(int x, int y, int kind)
3332 for (i = 0; i < NUM_UPGRADES && found == -1; i++)
3334 if (!upgrades[i].alive)
3340 upgrades[found].alive = YES;
3341 upgrades[found].kind = kind;
3342 upgrades[found].x = x;
3343 upgrades[found].y = y;
3344 upgrades[found].xm = 4;
3345 upgrades[found].ym = -4;
3346 upgrades[found].height = 0;
3353 void killtux(int mode)
3358 playsound(sounds[SND_HURT]);
3361 if (tux_dir == RIGHT)
3363 else if (tux_dir == LEFT)
3366 if (mode == SHRINK && tux_size == BIG)
3369 tux_got_coffee = NO;
3373 tux_safe = TUX_SAFE_TIME;
3384 void add_bullet(int x, int y, int dir, int xm)
3390 for (i = 0; i < NUM_BULLETS && found == -1; i++)
3392 if (!bullets[i].alive)
3398 bullets[found].alive = YES;
3402 bullets[found].x = x + 32;
3403 bullets[found].xm = BULLET_XM + xm;
3407 bullets[found].x = x;
3408 bullets[found].xm = -BULLET_XM + xm;
3411 bullets[found].y = y;
3412 bullets[found].ym = BULLET_STARTING_YM;
3415 playsound(sounds[SND_SHOOT]);