--- /dev/null
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+\f
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+\f
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+\f
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+\f
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
--- /dev/null
+/*
+ gameloop.c
+
+ Super Tux - Game Loop!
+
+ by Bill Kendrick
+ bill@newbreedsoftware.com
+ http://www.newbreedsoftware.com/supertux/
+
+ April 11, 2000 - July 15, 2002
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <SDL.h>
+#include <SDL_image.h>
+
+#ifndef NOSOUND
+#include <SDL_mixer.h>
+#endif
+
+#ifdef LINUX
+#include <pwd.h>
+#include <sys/types.h>
+#include <ctype.h>
+#endif
+
+#include "defines.h"
+#include "globals.h"
+#include "gameloop.h"
+#include "screen.h"
+#include "sound.h"
+#include "setup.h"
+
+
+/* Sound files: */
+
+enum {
+ SND_JUMP,
+ SND_BIGJUMP,
+ SND_SKID,
+ SND_DISTRO,
+ SND_HERRING,
+ SND_BRICK,
+ SND_HURT,
+ SND_SQUISH,
+ SND_FALL,
+ SND_RICOCHET,
+ SND_BUMP_UPGRADE,
+ SND_UPGRADE,
+ SND_EXCELLENT,
+ SND_COFFEE,
+ SND_SHOOT,
+ NUM_SOUNDS
+};
+
+char * soundfilenames[NUM_SOUNDS] = {
+ DATA_PREFIX "/sounds/jump.wav",
+ DATA_PREFIX "/sounds/bigjump.wav",
+ DATA_PREFIX "/sounds/skid.wav",
+ DATA_PREFIX "/sounds/distro.wav",
+ DATA_PREFIX "/sounds/herring.wav",
+ DATA_PREFIX "/sounds/brick.wav",
+ DATA_PREFIX "/sounds/hurt.wav",
+ DATA_PREFIX "/sounds/squish.wav",
+ DATA_PREFIX "/sounds/fall.wav",
+ DATA_PREFIX "/sounds/ricochet.wav",
+ DATA_PREFIX "/sounds/bump-upgrade.wav",
+ DATA_PREFIX "/sounds/upgrade.wav",
+ DATA_PREFIX "/sounds/excellent.wav",
+ DATA_PREFIX "/sounds/coffee.wav",
+ DATA_PREFIX "/sounds/shoot.wav"
+};
+
+
+/* Level names: */
+
+char * levelnames[] = {
+ "Antarctica",
+ "Australia",
+ "India",
+ "Egypt",
+ "Greece",
+ "Spain",
+ "Brazil",
+ "America",
+ "Redmond"
+};
+
+
+/* Local variables: */
+
+int score, distros, level, lives, scroll_x,
+ tux_dir, tux_size, tux_duck, tux_x, tux_xm, tux_y, tux_ym,
+ tux_dying, tux_safe, jumping, jump_counter, frame, score_multiplier,
+ tux_frame_main, tux_frame, tux_got_coffee, tux_skidding,
+ super_bkgd_time, time_left, tux_invincible_time,
+ counting_distros, distro_counter;
+int bkgd_red, bkgd_green, bkgd_blue;
+int left, right, up, down, fire, old_fire;
+SDL_Surface * img_brick[2], * img_solid[4], * img_distro[4],
+ * img_waves[3], * img_water, * img_pole, * img_poletop, * img_flag[2];
+SDL_Surface * img_bkgd[2][4];
+SDL_Surface * img_golden_herring;
+SDL_Surface * img_bsod_left[4], * img_bsod_right[4],
+ * img_laptop_left[3], * img_laptop_right[3],
+ * img_money_left[2], * img_money_right[2];
+SDL_Surface * img_bsod_squished_left, * img_bsod_squished_right,
+ * img_bsod_falling_left, * img_bsod_falling_right,
+ * img_laptop_flat_left, * img_laptop_flat_right,
+ * img_laptop_falling_left, * img_laptop_falling_right;
+SDL_Surface * img_box_full, * img_box_empty, * img_mints, * img_coffee,
+ * img_super_bkgd, * img_bullet, * img_red_glow;
+SDL_Surface * img_cloud[2][4];
+SDL_Surface * tux_right[3], * tux_left[3],
+ * bigtux_right[3], * bigtux_left[3],
+ * bigtux_right_jump, * bigtux_left_jump,
+ * cape_right[2], * cape_left[2],
+ * bigcape_right[2], * bigcape_left[2],
+ * ducktux_right, * ducktux_left,
+ * skidtux_right, * skidtux_left;
+#ifndef NOSOUND
+Mix_Chunk * sounds[NUM_SOUNDS];
+Mix_Music * song;
+#endif
+unsigned char tiles[15][LEVEL_WIDTH + 5];
+bouncy_distro_type bouncy_distros[NUM_BOUNCY_DISTROS];
+broken_brick_type broken_bricks[NUM_BROKEN_BRICKS];
+bouncy_brick_type bouncy_bricks[NUM_BOUNCY_BRICKS];
+bad_guy_type bad_guys[NUM_BAD_GUYS];
+floating_score_type floating_scores[NUM_FLOATING_SCORES];
+upgrade_type upgrades[NUM_UPGRADES];
+bullet_type bullets[NUM_BULLETS];
+
+
+/* Local function prototypes: */
+
+void initgame(void);
+void loadlevel(void);
+void loadlevelgfx(void);
+void loadlevelsong(void);
+void unloadlevelgfx(void);
+void unloadlevelsong(void);
+void loadshared(void);
+void unloadshared(void);
+void drawshape(int x, int y, unsigned char c);
+unsigned char shape(int x, int y, int sx);
+int issolid(int x, int y, int sx);
+int isbrick(int x, int y, int sx);
+int isice(int x, int y, int sx);
+int isfullbox(int x, int y, int sx);
+void change(int x, int y, int sx, unsigned char c);
+void trybreakbrick(int x, int y, int sx);
+void bumpbrick(int x, int y, int sx);
+void tryemptybox(int x, int y, int sx);
+void trygrabdistro(int x, int y, int sx, int bounciness);
+void add_bouncy_distro(int x, int y);
+void add_broken_brick(int x, int y);
+void add_broken_brick_piece(int x, int y, int xm, int ym);
+void add_bouncy_brick(int x, int y);
+void add_bad_guy(int x, int y, int kind);
+void add_score(int x, int y, int s);
+void trybumpbadguy(int x, int y, int sx);
+void add_upgrade(int x, int y, int kind);
+void killtux(int mode);
+void add_bullet(int x, int y, int dir, int xm);
+
+
+/* --- GAME LOOP! --- */
+
+int gameloop(void)
+{
+ int done, quit, x, y, i, j;
+ SDL_Event event;
+ SDL_Rect src, dest;
+ SDLKey key;
+ Uint32 last_time, now_time;
+ char str[10];
+
+
+ /* Clear screen: */
+
+ clearscreen(0, 0, 0);
+ updatescreen();
+
+
+ /* Init the game: */
+
+ initgame();
+ loadshared();
+ loadlevel();
+ loadlevelgfx();
+ loadlevelsong();
+
+
+ /* --- MAIN GAME LOOP!!! --- */
+
+ done = 0;
+ quit = 0;
+ frame = 0;
+ tux_frame_main = 0;
+ tux_frame = 0;
+
+ do
+ {
+ last_time = SDL_GetTicks();
+ frame++;
+
+
+ /* Handle events: */
+
+ old_fire = fire;
+
+ while (SDL_PollEvent(&event))
+ {
+ if (event.type == SDL_QUIT)
+ {
+ /* Quit event - quit: */
+
+ quit = 1;
+ }
+ else if (event.type == SDL_KEYDOWN)
+ {
+ /* A keypress! */
+
+ key = event.key.keysym.sym;
+
+ if (key == SDLK_ESCAPE)
+ {
+ /* Escape: Quit the game and return to main menu: */
+
+ done = 1;
+ }
+ else if (key == SDLK_RIGHT)
+ {
+ right = DOWN;
+ }
+ else if (key == SDLK_LEFT)
+ {
+ left = DOWN;
+ }
+ else if (key == SDLK_UP)
+ {
+ up = DOWN;
+ }
+ else if (key == SDLK_DOWN)
+ {
+ down = DOWN;
+ }
+ else if (key == SDLK_LCTRL)
+ {
+ fire = DOWN;
+ }
+ }
+ else if (event.type == SDL_KEYUP)
+ {
+ /* A keyrelease! */
+
+ key = event.key.keysym.sym;
+
+ if (key == SDLK_RIGHT)
+ {
+ right = UP;
+ }
+ else if (key == SDLK_LEFT)
+ {
+ left = UP;
+ }
+ else if (key == SDLK_UP)
+ {
+ up = UP;
+ }
+ else if (key == SDLK_DOWN)
+ {
+ down = UP;
+ }
+ else if (key == SDLK_LCTRL)
+ {
+ fire = UP;
+ }
+ else if (key == SDLK_TAB)
+ {
+ tux_size = !tux_size;
+ }
+ }
+#ifdef JOY_YES
+ else if (event.type == SDL_JOYAXISMOTION)
+ {
+ if (event.jaxis.axis == JOY_X)
+ {
+ if (event.jaxis.value < -256)
+ left = DOWN;
+ else
+ left = UP;
+
+ if (event.jaxis.value > 256)
+ right = DOWN;
+ else
+ right = UP;
+ }
+ else if (event.jaxis.axis == JOY_Y)
+ {
+ if (event.jaxis.value > 256)
+ down = DOWN;
+ else
+ down = UP;
+ }
+ }
+ else if (event.type == SDL_JOYBUTTONDOWN)
+ {
+ if (event.jbutton.button == JOY_A)
+ up = DOWN;
+ else if (event.jbutton.button == JOY_B)
+ fire = DOWN;
+ }
+ else if (event.type == SDL_JOYBUTTONUP)
+ {
+ if (event.jbutton.button == JOY_A)
+ up = UP;
+ else if (event.jbutton.button == JOY_B)
+ fire = UP;
+ }
+#endif
+ }
+
+
+ /* --- HANDLE TUX! --- */
+
+ /* Handle key and joystick state: */
+
+ if (!tux_dying)
+ {
+ if (right == DOWN && left == UP)
+ {
+ if (jumping == NO)
+ {
+ if (tux_xm < -SKID_XM && !tux_skidding &&
+ tux_dir == LEFT)
+ {
+ tux_skidding = SKID_TIME;
+#ifndef NOSOUND
+ playsound(sounds[SND_SKID]);
+#endif
+ }
+ tux_dir = RIGHT;
+ }
+
+ if (tux_xm < 0 && !isice(tux_x, tux_y + 32, scroll_x) &&
+ !tux_skidding)
+ {
+ tux_xm = 0;
+ }
+
+ if (!tux_duck)
+ {
+ if (tux_dir == RIGHT)
+ {
+ /* Facing the direction we're jumping? Go full-speed: */
+
+ if (fire == UP)
+ {
+ tux_xm = tux_xm + WALK_SPEED;
+
+ if (tux_xm > MAX_WALK_XM)
+ tux_xm = MAX_WALK_XM;
+ }
+ else if (fire == DOWN)
+ {
+ tux_xm = tux_xm + RUN_SPEED;
+
+ if (tux_xm > MAX_RUN_XM)
+ tux_xm = MAX_RUN_XM;
+ }
+ }
+ else
+ {
+ /* Not facing the direction we're jumping?
+ Go half-speed: */
+
+ tux_xm = tux_xm + WALK_SPEED / 2;
+
+ if (tux_xm > MAX_WALK_XM / 2)
+ tux_xm = MAX_WALK_XM / 2;
+ }
+ }
+ }
+ else if (left == DOWN && right == UP)
+ {
+ if (jumping == NO)
+ {
+ if (tux_xm > SKID_XM && !tux_skidding &&
+ tux_dir == RIGHT)
+ {
+ tux_skidding = SKID_TIME;
+#ifndef NOSOUND
+ playsound(sounds[SND_SKID]);
+#endif
+ }
+ tux_dir = LEFT;
+ }
+
+ if (tux_xm > 0 && !isice(tux_x, tux_y + 32, scroll_x) &&
+ !tux_skidding)
+ {
+ tux_xm = 0;
+ }
+
+ if (!tux_duck)
+ {
+ if (tux_dir == LEFT)
+ {
+ /* Facing the direction we're jumping? Go full-speed: */
+
+ if (fire == UP)
+ {
+ tux_xm = tux_xm - WALK_SPEED;
+
+ if (tux_xm < -MAX_WALK_XM)
+ tux_xm = -MAX_WALK_XM;
+ }
+ else if (fire == DOWN)
+ {
+ tux_xm = tux_xm - RUN_SPEED;
+
+ if (tux_xm < -MAX_RUN_XM)
+ tux_xm = -MAX_RUN_XM;
+ }
+ }
+ else
+ {
+ /* Not facing the direction we're jumping?
+ Go half-speed: */
+
+ tux_xm = tux_xm - WALK_SPEED / 2;
+
+ if (tux_xm < -MAX_WALK_XM / 2)
+ tux_xm = -MAX_WALK_XM / 2;
+ }
+ }
+ }
+
+
+ /* Jump/jumping? */
+
+ if (up == DOWN)
+ {
+ if (jump_counter == 0)
+ {
+ /* Taking off? */
+
+ if (!issolid(tux_x, tux_y + 32, scroll_x) ||
+ tux_ym != 0)
+ {
+ /* If they're not on the ground, or are currently moving
+ vertically, don't jump! */
+
+ jump_counter = MAX_JUMP_COUNT;
+ }
+ else
+ {
+ /* Make sure we're not standing back up into a solid! */
+
+ if (tux_size == SMALL || tux_duck == NO ||
+ !issolid(tux_x, tux_y, scroll_x))
+ {
+ jumping = YES;
+
+#ifndef NOSOUND
+ if (tux_size == SMALL)
+ playsound(sounds[SND_JUMP]);
+ else
+ playsound(sounds[SND_BIGJUMP]);
+#endif
+ }
+ }
+ }
+
+
+ /* Keep jumping for a while: */
+
+ if (jump_counter < MAX_JUMP_COUNT)
+ {
+ tux_ym = tux_ym - JUMP_SPEED;
+ jump_counter++;
+ }
+ }
+ else
+ jump_counter = 0;
+
+
+ /* Shoot! */
+
+ if (fire == DOWN && old_fire == UP && tux_got_coffee)
+ {
+ add_bullet(tux_x + scroll_x, tux_y, tux_dir, tux_xm);
+ }
+
+
+ /* Duck! */
+
+ if (down == DOWN)
+ {
+ if (tux_size == BIG)
+ tux_duck = YES;
+ }
+ else
+ {
+ if (tux_size == BIG && tux_duck == YES)
+ {
+ /* Make sure we're not standing back up into a solid! */
+
+ if (!issolid(tux_x, tux_y - 32, scroll_x))
+ tux_duck = NO;
+ }
+ else
+ tux_duck = NO;
+ }
+ } /* !tux_dying */
+ else
+ {
+ tux_ym = tux_ym + GRAVITY;
+
+ if (tux_y >= 480)
+ {
+#ifndef NOSOUND
+ if (use_sound)
+ {
+ if (Mix_PlayingMusic())
+ Mix_HaltMusic();
+ }
+#endif
+
+ lives--;
+ loadlevel();
+ }
+ }
+
+
+ /* Move tux: */
+
+ tux_x = tux_x + tux_xm;
+ tux_y = tux_y + tux_ym;
+
+
+ /* Keep tux in bounds: */
+
+ if (tux_x < 0)
+ tux_x = 0;
+ else if (tux_x > 320 && scroll_x < ((LEVEL_WIDTH * 32) - 640))
+ {
+ /* Scroll the screen in past center: */
+
+ scroll_x = scroll_x + (tux_x - 320);
+ tux_x = 320;
+
+ if (scroll_x > ((LEVEL_WIDTH * 32) - 640))
+ scroll_x = ((LEVEL_WIDTH * 32) - 640);
+ }
+ else if (tux_x > 608)
+ {
+ /* ... unless there's no more to scroll! */
+
+ tux_x = 608;
+ }
+
+
+ /* Land: */
+
+ if (!tux_dying)
+ {
+ if (issolid(tux_x, tux_y + 31, scroll_x) &&
+ !issolid(tux_x - tux_xm, tux_y + 31, scroll_x))
+ {
+ while (issolid(tux_x, tux_y + 31, scroll_x))
+ {
+ if (tux_xm < 0)
+ tux_x++;
+ else if (tux_xm > 0)
+ tux_x--;
+ }
+
+ tux_xm = 0;
+ }
+
+ if (issolid(tux_x, tux_y, scroll_x) &&
+ !issolid(tux_x - tux_xm, tux_y, scroll_x))
+ {
+ while (issolid(tux_x, tux_y, scroll_x))
+ {
+ if (tux_xm < 0)
+ tux_x++;
+ else if (tux_xm > 0)
+ tux_x--;
+ }
+
+ tux_xm = 0;
+ }
+
+ if (issolid(tux_x, tux_y + 31, scroll_x))
+ {
+ /* Set down properly: */
+
+ while (issolid(tux_x, tux_y + 31, scroll_x))
+ {
+ if (tux_ym < 0)
+ tux_y++;
+ else if (tux_ym > 0)
+ tux_y--;
+ }
+
+
+ /* Reset score multiplier (for mutli-hits): */
+
+ if (tux_ym > 0)
+ score_multiplier = 1;
+
+
+ /* Stop jumping! */
+
+ tux_ym = 0;
+ jumping = NO;
+ }
+
+
+ /* Bump into things: */
+
+ if (issolid(tux_x, tux_y, scroll_x) ||
+ (tux_size == BIG && !tux_duck &&
+ (issolid(tux_x, tux_y - 32, scroll_x))))
+ {
+ if (!issolid(tux_x - tux_xm, tux_y, scroll_x) &&
+ (tux_size == SMALL || tux_duck ||
+ !issolid(tux_x - tux_xm, tux_y - 32, scroll_x)))
+ {
+ tux_x = tux_x - tux_xm;
+ tux_xm = 0;
+ }
+ else if (!issolid(tux_x, tux_y - tux_ym, scroll_x) &&
+ (tux_size == SMALL || tux_duck ||
+ !issolid(tux_x, tux_y - 32 - tux_ym, scroll_x)))
+ {
+ if (tux_ym <= 0)
+ {
+ /* Jumping up? */
+
+ if (tux_size == BIG)
+ {
+ /* Break bricks and empty boxes: */
+
+ if (!tux_duck)
+ {
+ if (isbrick(tux_x, tux_y - 32, scroll_x) ||
+ isfullbox(tux_x, tux_y - 32, scroll_x))
+ {
+ trygrabdistro(tux_x, tux_y - 64, scroll_x,
+ BOUNCE);
+ trybumpbadguy(tux_x, tux_y - 96, scroll_x);
+
+ if (isfullbox(tux_x, tux_y - 32,
+ scroll_x))
+ {
+ bumpbrick(tux_x, tux_y - 32,
+ scroll_x);
+ }
+
+ trybreakbrick(tux_x, tux_y - 32, scroll_x);
+ tryemptybox(tux_x, tux_y - 32, scroll_x);
+ }
+
+ if (isbrick(tux_x + 31, tux_y - 32, scroll_x) ||
+ isfullbox(tux_x + 31, tux_y - 32, scroll_x))
+ {
+ trygrabdistro(tux_x + 31,
+ tux_y - 64,
+ scroll_x,
+ BOUNCE);
+ trybumpbadguy(tux_x + 31,
+ tux_y - 96,
+ scroll_x);
+
+ if (isfullbox(tux_x + 31, tux_y - 32,
+ scroll_x))
+ {
+ bumpbrick(tux_x + 31, tux_y - 32,
+ scroll_x);
+ }
+
+ trybreakbrick(tux_x + 31,
+ tux_y - 32,
+ scroll_x);
+ tryemptybox(tux_x + 31,
+ tux_y - 32,
+ scroll_x);
+ }
+ }
+ else /* ducking */
+ {
+ if (isbrick(tux_x, tux_y, scroll_x) ||
+ isfullbox(tux_x, tux_y, scroll_x))
+ {
+ trygrabdistro(tux_x, tux_y - 32, scroll_x,
+ BOUNCE);
+ trybumpbadguy(tux_x, tux_y - 64, scroll_x);
+ if (isfullbox(tux_x, tux_y, scroll_x))
+ bumpbrick(tux_x, tux_y, scroll_x);
+ trybreakbrick(tux_x, tux_y, scroll_x);
+ tryemptybox(tux_x, tux_y, scroll_x);
+ }
+
+ if (isbrick(tux_x + 31, tux_y, scroll_x) ||
+ isfullbox(tux_x + 31, tux_y, scroll_x))
+ {
+ trygrabdistro(tux_x + 31,
+ tux_y - 32,
+ scroll_x,
+ BOUNCE);
+ trybumpbadguy(tux_x + 31,
+ tux_y - 64,
+ scroll_x);
+ if (isfullbox(tux_x + 31, tux_y, scroll_x))
+ bumpbrick(tux_x + 31, tux_y, scroll_x);
+ trybreakbrick(tux_x + 31, tux_y, scroll_x);
+ tryemptybox(tux_x + 31, tux_y, scroll_x);
+ }
+ }
+ }
+ else
+ {
+ /* It's a brick and we're small, make the brick
+ bounce, and grab any distros above it: */
+
+ if (isbrick(tux_x, tux_y, scroll_x) ||
+ isfullbox(tux_x, tux_y, scroll_x))
+ {
+ trygrabdistro(tux_x, tux_y - 32, scroll_x,
+ BOUNCE);
+ trybumpbadguy(tux_x, tux_y - 64, scroll_x);
+ bumpbrick(tux_x, tux_y, scroll_x);
+ tryemptybox(tux_x, tux_y, scroll_x);
+ }
+
+ if (isbrick(tux_x + 31, tux_y, scroll_x) ||
+ isfullbox(tux_x + 31, tux_y, scroll_x))
+ {
+ trygrabdistro(tux_x + 31, tux_y - 32, scroll_x,
+ BOUNCE);
+ trybumpbadguy(tux_x + 31, tux_y - 64, scroll_x);
+ bumpbrick(tux_x + 31, tux_y, scroll_x);
+ tryemptybox(tux_x + 31, tux_y, scroll_x);
+ }
+
+
+ /* Get a distro from a brick? */
+
+ if (shape(tux_x, tux_y, scroll_x) == 'x' ||
+ shape(tux_x, tux_y, scroll_x) == 'y')
+ {
+ add_bouncy_distro(((tux_x + scroll_x + 1)
+ / 32) * 32,
+ (tux_y / 32) * 32);
+
+ if (counting_distros == NO)
+ {
+ counting_distros = YES;
+ distro_counter = 100;
+ }
+
+ if (distro_counter <= 0)
+ change(tux_x, tux_y, scroll_x, 'a');
+
+#ifndef NOSOUND
+ playsound(sounds[SND_DISTRO]);
+#endif
+ score = score + SCORE_DISTRO;
+ distros++;
+ }
+ else if (shape(tux_x + 31, tux_y, scroll_x) == 'x' ||
+ shape(tux_x + 31, tux_y, scroll_x) == 'y')
+ {
+ add_bouncy_distro(((tux_x + scroll_x + 1 + 31)
+ / 32) * 32,
+ (tux_y / 32) * 32);
+
+ if (counting_distros == NO)
+ {
+ counting_distros = YES;
+ distro_counter = 100;
+ }
+
+ if (distro_counter <= 0)
+ change(tux_x + 31, tux_y, scroll_x, 'a');
+
+#ifndef NOSOUND
+ playsound(sounds[SND_DISTRO]);
+#endif
+ score = score + SCORE_DISTRO;
+ distros++;
+ }
+ }
+
+
+ /* Bump head: */
+
+ tux_y = (tux_y / 32) * 32 + 30;
+ }
+ else
+ {
+ /* Land on feet: */
+
+ tux_y = (tux_y / 32) * 32 - 32;
+ }
+
+ tux_ym = 0;
+ jumping = NO;
+ jump_counter = MAX_JUMP_COUNT;
+ }
+ }
+ }
+
+
+ /* Grab distros: */
+
+ if (!tux_dying)
+ {
+ trygrabdistro(tux_x, tux_y, scroll_x, NO_BOUNCE);
+ trygrabdistro(tux_x + 31, tux_y, scroll_x, NO_BOUNCE);
+
+ if (tux_size == BIG && !tux_duck)
+ {
+ trygrabdistro(tux_x, tux_y - 32, scroll_x, NO_BOUNCE);
+ trygrabdistro(tux_x + 31, tux_y - 32, scroll_x, NO_BOUNCE);
+ }
+ }
+
+
+ /* Keep in-bounds, vertically: */
+
+ if (tux_y < 0)
+ tux_y = 0;
+ else if (tux_y > 480)
+ {
+ killtux(KILL);
+ }
+
+
+ /* Slow down horizontally: */
+
+ if (!tux_dying)
+ {
+ if (right == UP && left == UP)
+ {
+ if (isice(tux_x, tux_y + 32, scroll_x) ||
+ !issolid(tux_x, tux_y + 32, scroll_x))
+ {
+ /* Slowly on ice or in air: */
+
+ if (tux_xm > 0)
+ tux_xm--;
+ else if (tux_xm < 0)
+ tux_xm++;
+ }
+ else
+ {
+ /* Quickly, otherwise: */
+
+ tux_xm = tux_xm / 2;
+ }
+ }
+
+
+ /* Drop vertically: */
+
+ if (!issolid(tux_x, tux_y + 32, scroll_x))
+ {
+ tux_ym = tux_ym + GRAVITY;
+
+ if (tux_ym > MAX_YM)
+ tux_ym = MAX_YM;
+ }
+ }
+
+
+ if (tux_safe > 0)
+ tux_safe--;
+
+
+ /* ---- DONE HANDLING TUX! --- */
+
+
+ /* Handle bouncy distros: */
+
+ for (i = 0; i < NUM_BOUNCY_DISTROS; i++)
+ {
+ if (bouncy_distros[i].alive)
+ {
+ bouncy_distros[i].y = bouncy_distros[i].y + bouncy_distros[i].ym;
+
+ bouncy_distros[i].ym++;
+
+ if (bouncy_distros[i].ym >= 0)
+ bouncy_distros[i].alive = NO;
+ }
+ }
+
+
+ /* Handle broken bricks: */
+
+ for (i = 0; i < NUM_BROKEN_BRICKS; i++)
+ {
+ if (broken_bricks[i].alive)
+ {
+ broken_bricks[i].x = broken_bricks[i].x + broken_bricks[i].xm;
+ broken_bricks[i].y = broken_bricks[i].y + broken_bricks[i].ym;
+
+ broken_bricks[i].ym++;
+
+ if (broken_bricks[i].ym >= 0)
+ broken_bricks[i].alive = NO;
+ }
+ }
+
+
+ /* Handle distro counting: */
+
+ if (counting_distros == YES)
+ {
+ distro_counter--;
+
+ if (distro_counter <= 0)
+ counting_distros = -1;
+ }
+
+
+ /* Handle bouncy bricks: */
+
+ for (i = 0; i < NUM_BOUNCY_BRICKS; i++)
+ {
+ if (bouncy_bricks[i].alive)
+ {
+ bouncy_bricks[i].offset = (bouncy_bricks[i].offset +
+ bouncy_bricks[i].offset_m);
+
+ /* Go back down? */
+
+ if (bouncy_bricks[i].offset < -BOUNCY_BRICK_MAX_OFFSET)
+ bouncy_bricks[i].offset_m = BOUNCY_BRICK_SPEED;
+
+
+ /* Stop bouncing? */
+
+ if (bouncy_bricks[i].offset == 0)
+ bouncy_bricks[i].alive = NO;
+ }
+ }
+
+
+ /* Handle floating scores: */
+
+ for (i = 0; i < NUM_FLOATING_SCORES; i++)
+ {
+ if (floating_scores[i].alive)
+ {
+ floating_scores[i].y = floating_scores[i].y - 2;
+ floating_scores[i].timer--;
+
+ if (floating_scores[i].timer <= 0)
+ floating_scores[i].alive = NO;
+ }
+ }
+
+
+ /* Handle bullets: */
+
+ for (i = 0; i < NUM_BULLETS; i++)
+ {
+ if (bullets[i].alive)
+ {
+ bullets[i].x = bullets[i].x + bullets[i].xm;
+ bullets[i].y = bullets[i].y + bullets[i].ym;
+
+ if (issolid(bullets[i].x, bullets[i].y, 0))
+ {
+ if (issolid(bullets[i].x, bullets[i].y - bullets[i].ym, 0))
+ bullets[i].alive = NO;
+ else
+ {
+ if (bullets[i].ym >= 0)
+ {
+ bullets[i].y = (bullets[i].y / 32) * 32 - 8;
+ }
+ bullets[i].ym = -bullets[i].ym;
+ }
+ }
+
+ bullets[i].ym = bullets[i].ym + GRAVITY;
+
+ if (bullets[i].x < scroll_x ||
+ bullets[i].x > scroll_x + 640)
+ {
+ bullets[i].alive = NO;
+ }
+ }
+
+
+ if (bullets[i].alive)
+ {
+ for (j = 0; j < NUM_BAD_GUYS; j++)
+ {
+ if (bad_guys[j].alive && !bad_guys[j].dying)
+ {
+ if (bullets[i].x >= bad_guys[j].x - 4 &&
+ bullets[i].x <= bad_guys[j].x + 32 + 4 &&
+ bullets[i].y >= bad_guys[j].y - 4 &&
+ bullets[i].y <= bad_guys[j].y + 32 + 4)
+ {
+ bullets[i].alive = 0;
+ bad_guys[j].dying = FALLING;
+ bad_guys[j].ym = -8;
+#ifndef NOSOUND
+ playsound(sounds[SND_FALL]);
+#endif
+ }
+ }
+ }
+ }
+ }
+
+
+ /* Handle background timer: */
+
+ if (super_bkgd_time)
+ super_bkgd_time--;
+
+
+ /* Handle invincibility timer: */
+
+ if (tux_invincible_time)
+ tux_invincible_time--;
+
+
+ /* Handle upgrades: */
+
+ for (i = 0; i < NUM_UPGRADES; i++)
+ {
+ if (upgrades[i].alive)
+ {
+ if (upgrades[i].height < 32)
+ {
+ /* Rise up! */
+
+ upgrades[i].height++;
+ }
+ else
+ {
+ /* Move around? */
+
+ if (upgrades[i].kind == UPGRADE_MINTS ||
+ upgrades[i].kind == UPGRADE_HERRING)
+ {
+ upgrades[i].x = upgrades[i].x + upgrades[i].xm;
+ upgrades[i].y = upgrades[i].y + upgrades[i].ym;
+
+ if (issolid(upgrades[i].x, upgrades[i].y + 31, 0) ||
+ issolid(upgrades[i].x + 31, upgrades[i].y + 31, 0))
+ {
+ if (upgrades[i].ym > 0)
+ {
+ if (upgrades[i].kind == UPGRADE_MINTS)
+ {
+ upgrades[i].ym = 0;
+ }
+ else if (upgrades[i].kind == UPGRADE_HERRING)
+ {
+ upgrades[i].ym = -24;
+ }
+
+ upgrades[i].y = (upgrades[i].y / 32) * 32;
+ }
+ }
+ else
+ upgrades[i].ym = upgrades[i].ym + GRAVITY;
+
+ if (issolid(upgrades[i].x, upgrades[i].y, 0))
+ {
+ upgrades[i].xm = -upgrades[i].xm;
+ }
+ }
+
+
+ /* Off the screen? Kill it! */
+
+ if (upgrades[i].x < scroll_x)
+ upgrades[i].alive = NO;
+
+
+ /* Did the player grab it? */
+
+ if (tux_x + scroll_x >= upgrades[i].x - 32 &&
+ tux_x + scroll_x <= upgrades[i].x + 32 &&
+ tux_y >= upgrades[i].y - 32 &&
+ tux_y <= upgrades[i].y + 32)
+ {
+ /* Remove the upgrade: */
+
+ upgrades[i].alive = NO;
+
+
+ /* Affect the player: */
+
+ if (upgrades[i].kind == UPGRADE_MINTS)
+ {
+#ifndef NOSOUND
+ playsound(sounds[SND_EXCELLENT]);
+#endif
+ tux_size = BIG;
+ super_bkgd_time = 8;
+ }
+ else if (upgrades[i].kind == UPGRADE_COFFEE)
+ {
+#ifndef NOSOUND
+ playsound(sounds[SND_COFFEE]);
+#endif
+ tux_got_coffee = YES;
+ super_bkgd_time = 4;
+ }
+ else if (upgrades[i].kind == UPGRADE_HERRING)
+ {
+#ifndef NOSOUND
+ playsound(sounds[SND_HERRING]);
+#endif
+ tux_invincible_time = 200;
+ super_bkgd_time = 4;
+ }
+ }
+ }
+ }
+ }
+
+
+ /* Handle bad guys: */
+
+ for (i = 0; i < NUM_BAD_GUYS; i++)
+ {
+ if (bad_guys[i].alive)
+ {
+ if (bad_guys[i].seen)
+ {
+ if (bad_guys[i].kind == BAD_BSOD)
+ {
+ /* --- BLUE SCREEN OF DEATH MONSTER: --- */
+
+ /* Move left/right: */
+
+ if (bad_guys[i].dying == NO ||
+ bad_guys[i].dying == FALLING)
+ {
+ if (bad_guys[i].dir == RIGHT)
+ bad_guys[i].x = bad_guys[i].x + 4;
+ else if (bad_guys[i].dir == LEFT)
+ bad_guys[i].x = bad_guys[i].x - 4;
+ }
+
+
+ /* Move vertically: */
+
+ bad_guys[i].y = bad_guys[i].y + bad_guys[i].ym;
+
+
+ /* Bump into things horizontally: */
+
+ if (!bad_guys[i].dying)
+ {
+ if (issolid(bad_guys[i].x, bad_guys[i].y, 0))
+ bad_guys[i].dir = !bad_guys[i].dir;
+ }
+
+
+ /* Bump into other bad guys: */
+
+ for (j = 0; j < NUM_BAD_GUYS; j++)
+ {
+ if (j != i && bad_guys[j].alive &&
+ !bad_guys[j].dying && !bad_guys[i].dying &&
+ bad_guys[i].x >= bad_guys[j].x - 32 &&
+ bad_guys[i].x <= bad_guys[j].x + 32 &&
+ bad_guys[i].y >= bad_guys[j].y - 32 &&
+ bad_guys[i].y <= bad_guys[j].y + 32)
+ {
+ bad_guys[i].dir = !bad_guys[i].dir;
+ }
+ }
+
+
+ /* Fall if we get off the ground: */
+
+ if (bad_guys[i].dying != FALLING)
+ {
+ if (!issolid(bad_guys[i].x, bad_guys[i].y + 32, 0) &&
+ bad_guys[i].ym < MAX_YM)
+ {
+ bad_guys[i].ym = bad_guys[i].ym + GRAVITY;
+ }
+ else
+ {
+ /* Land: */
+
+ if (bad_guys[i].ym > 0)
+ {
+ bad_guys[i].y = (bad_guys[i].y / 32) * 32;
+ bad_guys[i].ym = 0;
+ }
+ }
+ }
+ else
+ bad_guys[i].ym = bad_guys[i].ym + GRAVITY;
+
+ if (bad_guys[i].y > 480)
+ bad_guys[i].alive = NO;
+ }
+ else if (bad_guys[i].kind == BAD_LAPTOP)
+ {
+ /* --- LAPTOP MONSTER: --- */
+
+ /* Move left/right: */
+
+ if (bad_guys[i].mode != FLAT && bad_guys[i].mode != KICK)
+ {
+ if (bad_guys[i].dying == NO ||
+ bad_guys[i].dying == FALLING)
+ {
+ if (bad_guys[i].dir == RIGHT)
+ bad_guys[i].x = bad_guys[i].x + 4;
+ else if (bad_guys[i].dir == LEFT)
+ bad_guys[i].x = bad_guys[i].x - 4;
+ }
+ }
+ else if (bad_guys[i].mode == KICK)
+ {
+ if (bad_guys[i].dir == RIGHT)
+ bad_guys[i].x = bad_guys[i].x + 16;
+ else if (bad_guys[i].dir == LEFT)
+ bad_guys[i].x = bad_guys[i].x - 16;
+ }
+
+
+ /* Move vertically: */
+
+ bad_guys[i].y = bad_guys[i].y + bad_guys[i].ym;
+
+
+ /* Bump into things horizontally: */
+
+ if (!bad_guys[i].dying)
+ {
+ if (issolid(bad_guys[i].x, bad_guys[i].y, 0))
+ {
+ bad_guys[i].dir = !bad_guys[i].dir;
+
+#ifndef NOSOUND
+ if (bad_guys[i].mode == KICK)
+ playsound(sounds[SND_RICOCHET]);
+#endif
+ }
+ }
+
+
+ /* Bump into other bad guys: */
+
+ for (j = 0; j < NUM_BAD_GUYS; j++)
+ {
+ if (j != i && bad_guys[j].alive &&
+ !bad_guys[j].dying && !bad_guys[i].dying &&
+ bad_guys[i].x >= bad_guys[j].x - 32 &&
+ bad_guys[i].x <= bad_guys[j].x + 32 &&
+ bad_guys[i].y >= bad_guys[j].y - 32 &&
+ bad_guys[i].y <= bad_guys[j].y + 32)
+ {
+ if (bad_guys[i].mode != KICK)
+ bad_guys[i].dir = !bad_guys[i].dir;
+ else
+ {
+ /* We're in kick mode, kill the other guy: */
+
+ bad_guys[j].dying = FALLING;
+ bad_guys[j].ym = -8;
+#ifndef NOSOUND
+ playsound(sounds[SND_FALL]);
+#endif
+
+ add_score(bad_guys[i].x - scroll_x,
+ bad_guys[i].y, 100);
+ }
+ }
+ }
+
+
+ /* Fall if we get off the ground: */
+
+ if (bad_guys[i].dying != FALLING)
+ {
+ if (!issolid(bad_guys[i].x, bad_guys[i].y + 32, 0) &&
+ bad_guys[i].ym < MAX_YM)
+ {
+ bad_guys[i].ym = bad_guys[i].ym + GRAVITY;
+ }
+ else
+ {
+ /* Land: */
+
+ if (bad_guys[i].ym > 0)
+ {
+ bad_guys[i].y = (bad_guys[i].y / 32) * 32;
+ bad_guys[i].ym = 0;
+ }
+ }
+ }
+ else
+ bad_guys[i].ym = bad_guys[i].ym + GRAVITY;
+
+ if (bad_guys[i].y > 480)
+ bad_guys[i].alive = NO;
+ }
+ else if (bad_guys[i].kind == BAD_MONEY)
+ {
+ /* --- MONEY BAGS: --- */
+
+
+ /* Move vertically: */
+
+ bad_guys[i].y = bad_guys[i].y + bad_guys[i].ym;
+
+
+ /* Fall if we get off the ground: */
+
+ if (bad_guys[i].dying != FALLING)
+ {
+ if (!issolid(bad_guys[i].x, bad_guys[i].y + 32, 0))
+ {
+ if (bad_guys[i].ym < MAX_YM)
+ {
+ bad_guys[i].ym = bad_guys[i].ym + GRAVITY;
+ }
+ }
+ else
+ {
+ /* Land: */
+
+ if (bad_guys[i].ym > 0)
+ {
+ bad_guys[i].y = (bad_guys[i].y / 32) * 32;
+ bad_guys[i].ym = -MAX_YM;
+ }
+ }
+ }
+ else
+ bad_guys[i].ym = bad_guys[i].ym + GRAVITY;
+
+ if (bad_guys[i].y > 480)
+ bad_guys[i].alive = NO;
+ }
+ else if (bad_guys[i].kind == -1)
+ {
+ }
+
+
+ /* Kill it if the player jumped on it: */
+
+ if (!bad_guys[i].dying && !tux_dying && !tux_safe &&
+ tux_x + scroll_x >= bad_guys[i].x - 32 &&
+ tux_x + scroll_x <= bad_guys[i].x + 32 &&
+ tux_y >= bad_guys[i].y - 32 &&
+ tux_y <= bad_guys[i].y - 8
+ /* &&
+ tux_ym >= 0 */)
+ {
+ if (bad_guys[i].kind == BAD_BSOD)
+ {
+ bad_guys[i].dying = SQUISHED;
+ bad_guys[i].timer = 16;
+ tux_ym = -KILL_BOUNCE_YM;
+
+ add_score(bad_guys[i].x - scroll_x, bad_guys[i].y,
+ 50 * score_multiplier);
+
+#ifndef NOSOUND
+ playsound(sounds[SND_SQUISH]);
+#endif
+ }
+ else if (bad_guys[i].kind == BAD_LAPTOP)
+ {
+ if (bad_guys[i].mode != FLAT)
+ {
+ /* Flatten! */
+
+ bad_guys[i].mode = FLAT;
+
+ bad_guys[i].timer = 64;
+
+ tux_y = tux_y - 32;
+ }
+ else
+ {
+ /* Kick! */
+
+ bad_guys[i].mode = KICK;
+
+ if (tux_x + scroll_x <= bad_guys[i].x)
+ bad_guys[i].dir = RIGHT;
+ else
+ bad_guys[i].dir = LEFT;
+
+ bad_guys[i].timer = 8;
+ }
+
+ tux_ym = -KILL_BOUNCE_YM;
+
+ add_score(bad_guys[i].x - scroll_x,
+ bad_guys[i].y,
+ 25 * score_multiplier);
+
+#ifndef NOSOUND
+ /* playsound(sounds[SND_SQUISH]); */
+#endif
+ }
+ else if (bad_guys[i].kind == -1)
+ {
+ }
+
+ score_multiplier++;
+ }
+
+
+ /* Hurt the player if he just touched it: */
+
+ if (!bad_guys[i].dying && !tux_dying &&
+ !tux_safe &&
+ tux_x + scroll_x >= bad_guys[i].x - 32 &&
+ tux_x + scroll_x <= bad_guys[i].x + 32 &&
+ tux_y >= bad_guys[i].y - 32 &&
+ tux_y <= bad_guys[i].y + 32)
+ {
+ if (bad_guys[i].mode == FLAT)
+ {
+ /* Kick: */
+
+ bad_guys[i].mode = KICK;
+
+ if (tux_x < bad_guys[i].x)
+ {
+ bad_guys[i].dir = RIGHT;
+ bad_guys[i].x = bad_guys[i].x + 16;
+ }
+ else
+ {
+ bad_guys[i].dir = LEFT;
+ bad_guys[i].x = bad_guys[i].x - 16;
+ }
+
+ bad_guys[i].timer = 8;
+ }
+ else if (bad_guys[i].mode == KICK)
+ {
+ if (tux_y < bad_guys[i].y - 16 &&
+ bad_guys[i].timer == 0)
+ {
+ /* Step on (stop being kicked) */
+
+ bad_guys[i].mode = FLAT;
+ bad_guys[i].timer = 64;
+ }
+ else
+ {
+ /* Hurt if you get hit by kicked laptop: */
+
+ if (bad_guys[i].timer == 0)
+ {
+ if (tux_invincible_time == 0)
+ {
+ killtux(SHRINK);
+ }
+ else
+ {
+ bad_guys[i].dying = FALLING;
+ bad_guys[i].ym = -8;
+#ifndef NOSOUND
+ playsound(sounds[SND_FALL]);
+#endif
+ }
+ }
+ }
+ }
+ else
+ {
+ if (tux_invincible_time == 0)
+ {
+ killtux(SHRINK);
+ }
+ else
+ {
+ bad_guys[i].dying = FALLING;
+ bad_guys[i].ym = -8;
+#ifndef NOSOUND
+ playsound(sounds[SND_FALL]);
+#endif
+ }
+ }
+ }
+
+
+ /* Handle mode timer: */
+
+ if (bad_guys[i].mode == FLAT)
+ {
+ bad_guys[i].timer--;
+
+ if (bad_guys[i].timer <= 0)
+ bad_guys[i].mode = NORMAL;
+ }
+ else if (bad_guys[i].mode == KICK)
+ {
+ if (bad_guys[i].timer > 0)
+ bad_guys[i].timer--;
+ }
+
+
+ /* Handle dying timer: */
+
+ if (bad_guys[i].dying == SQUISHED)
+ {
+ bad_guys[i].timer--;
+
+
+ /* Remove it if time's up: */
+
+ if (bad_guys[i].timer <= 0)
+ bad_guys[i].alive = NO;
+ }
+
+
+ /* Remove if it's far off the screen: */
+
+ if (bad_guys[i].x < scroll_x - OFFSCREEN_DISTANCE)
+ bad_guys[i].alive = NO;
+ }
+ else /* !seen */
+ {
+ /* Once it's on screen, it's activated! */
+
+ if (bad_guys[i].x <= scroll_x + 640 + OFFSCREEN_DISTANCE)
+ bad_guys[i].seen = YES;
+ }
+ }
+ }
+
+
+ /* Handle skidding: */
+
+ if (tux_skidding > 0)
+ {
+ tux_skidding--;
+ }
+
+
+ /* Draw screen: */
+
+ if (tux_dying && (frame % 4) == 0)
+ clearscreen(255, 255, 255);
+ else
+ {
+ if (super_bkgd_time == 0)
+ clearscreen(bkgd_red, bkgd_green, bkgd_blue);
+ else
+ drawimage(img_super_bkgd, 0, 0, NO_UPDATE);
+ }
+
+
+ /* Draw background: */
+
+ for (y = 0; y < 15; y++)
+ {
+ for (x = 0; x < 21; x++)
+ {
+ drawshape(x * 32 - (scroll_x % 32), y * 32,
+ tiles[y][x + (scroll_x / 32)]);
+ }
+ }
+
+
+ /* (Bouncy bricks): */
+
+ for (i = 0; i < NUM_BOUNCY_BRICKS; i++)
+ {
+ if (bouncy_bricks[i].alive)
+ {
+ if (bouncy_bricks[i].x >= scroll_x - 32 &&
+ bouncy_bricks[i].x <= scroll_x + 640)
+ {
+ dest.x = bouncy_bricks[i].x - scroll_x;
+ dest.y = bouncy_bricks[i].y;
+ dest.w = 32;
+ dest.h = 32;
+
+ SDL_FillRect(screen, &dest, SDL_MapRGB(screen->format,
+ bkgd_red,
+ bkgd_green,
+ bkgd_blue));
+
+ drawshape(bouncy_bricks[i].x - scroll_x,
+ bouncy_bricks[i].y + bouncy_bricks[i].offset,
+ bouncy_bricks[i].shape);
+ }
+ }
+ }
+
+
+ /* (Bad guys): */
+
+ for (i = 0; i < NUM_BAD_GUYS; i++)
+ {
+ if (bad_guys[i].alive &&
+ bad_guys[i].x > scroll_x - 32 &&
+ bad_guys[i].x < scroll_x + 640)
+ {
+ if (bad_guys[i].kind == BAD_BSOD)
+ {
+ /* --- BLUE SCREEN OF DEATH MONSTER: --- */
+
+ if (bad_guys[i].dying == NO)
+ {
+ /* Alive: */
+
+ if (bad_guys[i].dir == LEFT)
+ {
+ drawimage(img_bsod_left[(frame / 5) % 4],
+ bad_guys[i].x - scroll_x,
+ bad_guys[i].y,
+ NO_UPDATE);
+ }
+ else
+ {
+ drawimage(img_bsod_right[(frame / 5) % 4],
+ bad_guys[i].x - scroll_x,
+ bad_guys[i].y,
+ NO_UPDATE);
+ }
+ }
+ else if (bad_guys[i].dying == FALLING)
+ {
+ /* Falling: */
+
+ if (bad_guys[i].dir == LEFT)
+ {
+ drawimage(img_bsod_falling_left,
+ bad_guys[i].x - scroll_x,
+ bad_guys[i].y,
+ NO_UPDATE);
+ }
+ else
+ {
+ drawimage(img_bsod_falling_right,
+ bad_guys[i].x - scroll_x,
+ bad_guys[i].y,
+ NO_UPDATE);
+ }
+ }
+ else if (bad_guys[i].dying == SQUISHED)
+ {
+ /* Dying - Squished: */
+
+ if (bad_guys[i].dir == LEFT)
+ {
+ drawimage(img_bsod_squished_left,
+ bad_guys[i].x - scroll_x,
+ bad_guys[i].y + 24,
+ NO_UPDATE);
+ }
+ else
+ {
+ drawimage(img_bsod_squished_right,
+ bad_guys[i].x - scroll_x,
+ bad_guys[i].y + 24,
+ NO_UPDATE);
+ }
+ }
+ }
+ else if (bad_guys[i].kind == BAD_LAPTOP)
+ {
+ /* --- LAPTOP MONSTER: --- */
+
+ if (bad_guys[i].dying == NO)
+ {
+ /* Alive: */
+
+ if (bad_guys[i].mode == NORMAL)
+ {
+ /* Not flat: */
+
+ if (bad_guys[i].dir == LEFT)
+ {
+ drawimage(img_laptop_left[(frame / 5) % 3],
+ bad_guys[i].x - scroll_x,
+ bad_guys[i].y,
+ NO_UPDATE);
+ }
+ else
+ {
+ drawimage(img_laptop_right[(frame / 5) % 3],
+ bad_guys[i].x - scroll_x,
+ bad_guys[i].y,
+ NO_UPDATE);
+ }
+ }
+ else
+ {
+ /* Flat: */
+
+ if (bad_guys[i].dir == LEFT)
+ {
+ drawimage(img_laptop_flat_left,
+ bad_guys[i].x - scroll_x,
+ bad_guys[i].y,
+ NO_UPDATE);
+ }
+ else
+ {
+ drawimage(img_laptop_flat_right,
+ bad_guys[i].x - scroll_x,
+ bad_guys[i].y,
+ NO_UPDATE);
+ }
+ }
+ }
+ else if (bad_guys[i].dying == FALLING)
+ {
+ /* Falling: */
+
+ if (bad_guys[i].dir == LEFT)
+ {
+ drawimage(img_laptop_falling_left,
+ bad_guys[i].x - scroll_x,
+ bad_guys[i].y,
+ NO_UPDATE);
+ }
+ else
+ {
+ drawimage(img_laptop_falling_right,
+ bad_guys[i].x - scroll_x,
+ bad_guys[i].y,
+ NO_UPDATE);
+ }
+ }
+ }
+ else if (bad_guys[i].kind == BAD_MONEY)
+ {
+ if (bad_guys[i].ym > -16)
+ {
+ if (bad_guys[i].dir == LEFT)
+ {
+ drawimage(img_money_left[0],
+ bad_guys[i].x - scroll_x,
+ bad_guys[i].y,
+ NO_UPDATE);
+ }
+ else
+ {
+ drawimage(img_money_right[0],
+ bad_guys[i].x - scroll_x,
+ bad_guys[i].y,
+ NO_UPDATE);
+ }
+ }
+ else
+ {
+ if (bad_guys[i].dir == LEFT)
+ {
+ drawimage(img_money_left[1],
+ bad_guys[i].x - scroll_x,
+ bad_guys[i].y,
+ NO_UPDATE);
+ }
+ else
+ {
+ drawimage(img_money_right[1],
+ bad_guys[i].x - scroll_x,
+ bad_guys[i].y,
+ NO_UPDATE);
+ }
+ }
+ }
+ else if (bad_guys[i].kind == -1)
+ {
+ }
+ }
+ }
+
+
+ /* (Tux): */
+
+ if (right == UP && left == UP)
+ {
+ tux_frame_main = 1;
+ tux_frame = 1;
+ }
+ else
+ {
+ if ((fire == DOWN && (frame % 2) == 0) ||
+ (frame % 4) == 0)
+ tux_frame_main = (tux_frame_main + 1) % 4;
+
+ tux_frame = tux_frame_main;
+
+ if (tux_frame == 3)
+ tux_frame = 1;
+ }
+
+
+ if (tux_got_coffee && (frame % 2) == 1)
+ {
+ /* Coffee glow: */
+
+ drawimage(img_red_glow, tux_x - 8, tux_y - 32, NO_UPDATE);
+ }
+
+
+ if (tux_safe == 0 || (frame % 2) == 0)
+ {
+ if (tux_size == SMALL)
+ {
+ if (tux_invincible_time)
+ {
+ /* Draw cape: */
+
+ if (tux_dir == RIGHT)
+ {
+ drawimage(cape_right[frame % 2],
+ tux_x, tux_y,
+ NO_UPDATE);
+ }
+ else
+ {
+ drawimage(cape_left[frame % 2],
+ tux_x, tux_y,
+ NO_UPDATE);
+ }
+ }
+
+
+ if (tux_dir == RIGHT)
+ {
+ drawimage(tux_right[tux_frame], tux_x, tux_y, NO_UPDATE);
+ }
+ else
+ {
+ drawimage(tux_left[tux_frame], tux_x, tux_y, NO_UPDATE);
+ }
+ }
+ else
+ {
+ if (tux_invincible_time)
+ {
+ /* Draw cape: */
+
+ if (tux_dir == RIGHT)
+ {
+ drawimage(bigcape_right[frame % 2],
+ tux_x - 8 - 16, tux_y - 32,
+ NO_UPDATE);
+ }
+ else
+ {
+ drawimage(bigcape_left[frame % 2],
+ tux_x - 8, tux_y - 32,
+ NO_UPDATE);
+ }
+ }
+
+ if (!tux_duck)
+ {
+ if (!tux_skidding)
+ {
+ if (!jumping || tux_ym > 0)
+ {
+ if (tux_dir == RIGHT)
+ {
+ drawimage(bigtux_right[tux_frame],
+ tux_x - 8, tux_y - 32,
+ NO_UPDATE);
+ }
+ else
+ {
+ drawimage(bigtux_left[tux_frame],
+ tux_x - 8, tux_y - 32,
+ NO_UPDATE);
+ }
+ }
+ else
+ {
+ if (tux_dir == RIGHT)
+ {
+ drawimage(bigtux_right_jump,
+ tux_x - 8, tux_y - 32,
+ NO_UPDATE);
+ }
+ else
+ {
+ drawimage(bigtux_left_jump,
+ tux_x - 8, tux_y - 32,
+ NO_UPDATE);
+ }
+ }
+ }
+ else
+ {
+ if (tux_dir == RIGHT)
+ {
+ drawimage(skidtux_right,
+ tux_x - 8, tux_y - 32,
+ NO_UPDATE);
+ }
+ else
+ {
+ drawimage(skidtux_left,
+ tux_x - 8, tux_y - 32,
+ NO_UPDATE);
+ }
+ }
+ }
+ else
+ {
+ if (tux_dir == RIGHT)
+ {
+ drawimage(ducktux_right, tux_x - 8, tux_y - 16,
+ NO_UPDATE);
+ }
+ else
+ {
+ drawimage(ducktux_left, tux_x - 8, tux_y - 16,
+ NO_UPDATE);
+ }
+ }
+ }
+ }
+
+
+ /* (Bullets): */
+
+ for (i = 0; i < NUM_BULLETS; i++)
+ {
+ if (bullets[i].alive &&
+ bullets[i].x >= scroll_x - 4 &&
+ bullets[i].x <= scroll_x + 640)
+ {
+ drawimage(img_bullet, bullets[i].x - scroll_x, bullets[i].y,
+ NO_UPDATE);
+ }
+ }
+
+
+ /* (Floating scores): */
+
+ for (i = 0; i < NUM_FLOATING_SCORES; i++)
+ {
+ if (floating_scores[i].alive)
+ {
+ sprintf(str, "%d", floating_scores[i].value);
+ drawtext(str,
+ floating_scores[i].x + 16 - strlen(str) * 8,
+ floating_scores[i].y,
+ letters_gold, NO_UPDATE);
+ }
+ }
+
+
+ /* (Upgrades): */
+
+ for (i = 0; i < NUM_UPGRADES; i++)
+ {
+ if (upgrades[i].alive)
+ {
+ if (upgrades[i].height < 32)
+ {
+ /* Rising up... */
+
+ dest.x = upgrades[i].x - scroll_x;
+ dest.y = upgrades[i].y + 32 - upgrades[i].height;
+ dest.w = 32;
+ dest.h = upgrades[i].height;
+
+ src.x = 0;
+ src.y = 0;
+ src.w = 32;
+ src.h = upgrades[i].height;
+
+ if (upgrades[i].kind == UPGRADE_MINTS)
+ SDL_BlitSurface(img_mints, &src, screen, &dest);
+ else if (upgrades[i].kind == UPGRADE_COFFEE)
+ SDL_BlitSurface(img_coffee, &src, screen, &dest);
+ else if (upgrades[i].kind == UPGRADE_HERRING)
+ SDL_BlitSurface(img_golden_herring, &src, screen, &dest);
+ }
+ else
+ {
+ if (upgrades[i].kind == UPGRADE_MINTS)
+ {
+ drawimage(img_mints,
+ upgrades[i].x - scroll_x, upgrades[i].y,
+ NO_UPDATE);
+ }
+ else if (upgrades[i].kind == UPGRADE_COFFEE)
+ {
+ drawimage(img_coffee,
+ upgrades[i].x - scroll_x, upgrades[i].y,
+ NO_UPDATE);
+ }
+ else if (upgrades[i].kind == UPGRADE_HERRING)
+ {
+ drawimage(img_golden_herring,
+ upgrades[i].x - scroll_x, upgrades[i].y,
+ NO_UPDATE);
+ }
+ }
+ }
+ }
+
+
+ /* (Bouncy distros): */
+
+ for (i = 0; i < NUM_BOUNCY_DISTROS; i++)
+ {
+ if (bouncy_distros[i].alive)
+ {
+ drawimage(img_distro[0],
+ bouncy_distros[i].x - scroll_x,
+ bouncy_distros[i].y,
+ NO_UPDATE);
+ }
+ }
+
+
+ /* (Broken bricks): */
+
+ for (i = 0; i < NUM_BROKEN_BRICKS; i++)
+ {
+ if (broken_bricks[i].alive)
+ {
+ src.x = rand() % 16;
+ src.y = rand() % 16;
+ src.w = 16;
+ src.h = 16;
+
+ dest.x = broken_bricks[i].x - scroll_x;
+ dest.y = broken_bricks[i].y;
+ dest.w = 16;
+ dest.h = 16;
+
+ SDL_BlitSurface(img_brick[0], &src, screen, &dest);
+ }
+ }
+
+
+ /* (Status): */
+
+ sprintf(str, "%d", score);
+ drawtext("SCORE", 0, 0, letters_blue, NO_UPDATE);
+ drawtext(str, 96, 0, letters_gold, NO_UPDATE);
+
+ if (time_left >= 50 || (frame % 10) < 5)
+ {
+ sprintf(str, "%d", time_left);
+ drawtext("TIME", 224, 0, letters_blue, NO_UPDATE);
+ drawtext(str, 304, 0, letters_gold, NO_UPDATE);
+ }
+
+ sprintf(str, "%d", distros);
+ drawtext("DISTROS", 480, 0, letters_blue, NO_UPDATE);
+ drawtext(str, 608, 0, letters_gold, NO_UPDATE);
+
+
+ /* (Update it all!) */
+
+ updatescreen();
+
+
+ /* Keep playing music: */
+
+#ifndef NOSOUND
+ if (use_sound)
+ {
+ if (!Mix_PlayingMusic())
+ {
+ Mix_PlayMusic(song, 1);
+ }
+ }
+#endif
+
+
+ /* Pause til next frame: */
+
+ now_time = SDL_GetTicks();
+ if (now_time < last_time + FPS)
+ SDL_Delay(last_time + FPS - now_time);
+
+
+ /* Handle time: */
+
+ if ((frame % 10) == 0 && time_left > 0)
+ {
+ time_left--;
+
+ if (time_left <= 0)
+ killtux(KILL);
+ }
+ }
+ while (!done && !quit);
+
+#ifndef NOSOUND
+ if (use_sound)
+ {
+ if (Mix_PlayingMusic())
+ Mix_HaltMusic();
+ }
+#endif
+
+ unloadlevelgfx();
+ unloadlevelsong();
+ unloadshared();
+
+ return(quit);
+}
+
+
+/* Initialize the game stuff: */
+
+void initgame(void)
+{
+ level = 0;
+ score = 0;
+ distros = 0;
+ lives = 3;
+}
+
+
+/* Load data for this level: */
+
+void loadlevel(void)
+{
+ int i, x, y;
+ FILE * fi;
+ char * filename;
+ char str[80];
+ char line[LEVEL_WIDTH + 5];
+
+
+ /* Reset arrays: */
+
+ for (i = 0; i < NUM_BOUNCY_DISTROS; i++)
+ bouncy_distros[i].alive = NO;
+
+ for (i = 0; i < NUM_BROKEN_BRICKS; i++)
+ broken_bricks[i].alive = NO;
+
+ for (i = 0; i < NUM_BOUNCY_BRICKS; i++)
+ bouncy_bricks[i].alive = NO;
+
+ for (i = 0; i < NUM_BAD_GUYS; i++)
+ bad_guys[i].alive = NO;
+
+ for (i = 0; i < NUM_FLOATING_SCORES; i++)
+ floating_scores[i].alive = NO;
+
+ for (i = 0; i < NUM_UPGRADES; i++)
+ upgrades[i].alive = NO;
+
+ for (i = 0; i < NUM_BULLETS; i++)
+ bullets[i].alive = NO;
+
+
+ /* Load data file: */
+
+ filename = strdup(DATA_PREFIX "/levels/level1.dat");
+ fi = fopen(filename, "r");
+ if (fi == NULL)
+ {
+ perror(filename);
+ st_shutdown();
+ }
+ free(filename);
+
+ fgets(line, 10, fi);
+ bkgd_red = atoi(line);
+ fgets(line, 10, fi);
+ bkgd_green= atoi(line);
+ fgets(line, 10, fi);
+ bkgd_blue = atoi(line);
+
+ for (y = 0; y < 15; y++)
+ {
+ fgets(line, LEVEL_WIDTH + 5, fi);
+ line[strlen(line) - 1] = '\0';
+ strcpy(tiles[y], line);
+ }
+
+ fclose(fi);
+
+
+ /* Activate bad guys: */
+
+ for (y = 0; y < 15; y++)
+ {
+ for (x = 0; x < LEVEL_WIDTH; x++)
+ {
+ if (tiles[y][x] >= '0' && tiles[y][x] <= '9')
+ {
+ add_bad_guy(x * 32, y * 32, tiles[y][x] - '0');
+ tiles[y][x] = '.';
+ }
+ }
+ }
+
+
+ /* Set defaults: */
+
+ tux_x = 0;
+ tux_xm = 0;
+ tux_y = 240;
+ tux_ym = 0;
+ tux_dir = RIGHT;
+ tux_size = SMALL;
+ tux_got_coffee = NO;
+ tux_invincible_time = 0;
+ tux_duck = NO;
+
+ tux_dying = NO;
+ tux_safe = TUX_SAFE_TIME;
+
+ jumping = NO;
+ jump_counter = 0;
+
+ tux_skidding = 0;
+
+ scroll_x = 0;
+
+ right = UP;
+ left = UP;
+ up = UP;
+ down = UP;
+ fire = UP;
+ old_fire = UP;
+
+ score_multiplier = 1;
+ super_bkgd_time = 0;
+
+ time_left = 255;
+
+ counting_distros = NO;
+ distro_counter = 0;
+
+
+ /* Level Intro: */
+
+ clearscreen(0, 0, 0);
+
+ sprintf(str, "LEVEL %d", level + 1);
+ drawcenteredtext(str, 200, letters_red, NO_UPDATE);
+
+ sprintf(str, "%s", levelnames[level]);
+ drawcenteredtext(str, 224, letters_gold, NO_UPDATE);
+
+ sprintf(str, "TUX x %d", lives);
+ drawcenteredtext(str, 256, letters_blue, NO_UPDATE);
+
+ SDL_Flip(screen);
+
+ SDL_Delay(1000);
+}
+
+
+/* Load graphics: */
+
+void loadlevelgfx(void)
+{
+ img_brick[0] = load_image(DATA_PREFIX "/images/level1/brick0.png",
+ IGNORE_ALPHA);
+ img_brick[1] = load_image(DATA_PREFIX "/images/level1/brick1.png",
+ IGNORE_ALPHA);
+
+ img_solid[0] = load_image(DATA_PREFIX "/images/level1/solid0.png",
+ USE_ALPHA);
+ img_solid[1] = load_image(DATA_PREFIX "/images/level1/solid1.png",
+ USE_ALPHA);
+ img_solid[2] = load_image(DATA_PREFIX "/images/level1/solid2.png",
+ USE_ALPHA);
+ img_solid[3] = load_image(DATA_PREFIX "/images/level1/solid3.png",
+ USE_ALPHA);
+
+ img_bkgd[0][0] = load_image(DATA_PREFIX "/images/level1/bkgd-00.png",
+ USE_ALPHA);
+ img_bkgd[0][1] = load_image(DATA_PREFIX "/images/level1/bkgd-01.png",
+ USE_ALPHA);
+ img_bkgd[0][2] = load_image(DATA_PREFIX "/images/level1/bkgd-02.png",
+ USE_ALPHA);
+ img_bkgd[0][3] = load_image(DATA_PREFIX "/images/level1/bkgd-03.png",
+ USE_ALPHA);
+
+ img_bkgd[1][0] = load_image(DATA_PREFIX "/images/level1/bkgd-10.png",
+ USE_ALPHA);
+ img_bkgd[1][1] = load_image(DATA_PREFIX "/images/level1/bkgd-11.png",
+ USE_ALPHA);
+ img_bkgd[1][2] = load_image(DATA_PREFIX "/images/level1/bkgd-12.png",
+ USE_ALPHA);
+ img_bkgd[1][3] = load_image(DATA_PREFIX "/images/level1/bkgd-13.png",
+ USE_ALPHA);
+}
+
+
+/* Load music: */
+
+void loadlevelsong(void)
+{
+#ifndef NOSOUND
+ song = load_song(DATA_PREFIX "/music/ji_turn.it");
+#endif
+}
+
+
+/* Free graphics data for this level: */
+
+void unloadlevelgfx(void)
+{
+ int i;
+
+ for (i = 0; i < 2; i++)
+ {
+ SDL_FreeSurface(img_brick[i]);
+ }
+ for (i = 0; i < 4; i++)
+ {
+ SDL_FreeSurface(img_solid[i]);
+ SDL_FreeSurface(img_bkgd[0][i]);
+ SDL_FreeSurface(img_bkgd[1][i]);
+ }
+}
+
+
+/* Free music data for this level: */
+
+void unloadlevelsong(void)
+{
+#ifndef NOSOUND
+ if (use_sound)
+ {
+ Mix_FreeMusic(song);
+ }
+#endif
+}
+
+
+/* Load graphics shared between all levels: */
+
+void loadshared(void)
+{
+#ifndef NOSOUND
+ int i;
+#endif
+
+
+ /* Tuxes: */
+
+ tux_right[0] = load_image(DATA_PREFIX "/images/shared/tux-right-0.png",
+ USE_ALPHA);
+
+ tux_right[1] = load_image(DATA_PREFIX "/images/shared/tux-right-1.png",
+ USE_ALPHA);
+
+ tux_right[2] = load_image(DATA_PREFIX "/images/shared/tux-right-2.png",
+ USE_ALPHA);
+
+ tux_left[0] = load_image(DATA_PREFIX "/images/shared/tux-left-0.png",
+ USE_ALPHA);
+
+ tux_left[1] = load_image(DATA_PREFIX "/images/shared/tux-left-1.png",
+ USE_ALPHA);
+
+ tux_left[2] = load_image(DATA_PREFIX "/images/shared/tux-left-2.png",
+ USE_ALPHA);
+
+ cape_right[0] = load_image(DATA_PREFIX "/images/shared/cape-right-0.png",
+ USE_ALPHA);
+
+ cape_right[1] = load_image(DATA_PREFIX "/images/shared/cape-right-1.png",
+ USE_ALPHA);
+
+ cape_left[0] = load_image(DATA_PREFIX "/images/shared/cape-left-0.png",
+ USE_ALPHA);
+
+ cape_left[1] = load_image(DATA_PREFIX "/images/shared/cape-left-1.png",
+ USE_ALPHA);
+
+ bigtux_right[0] = load_image(DATA_PREFIX "/images/shared/bigtux-right-0.png",
+ USE_ALPHA);
+
+ bigtux_right[1] = load_image(DATA_PREFIX "/images/shared/bigtux-right-1.png",
+ USE_ALPHA);
+
+ bigtux_right[2] = load_image(DATA_PREFIX "/images/shared/bigtux-right-2.png",
+ USE_ALPHA);
+
+ bigtux_right_jump =
+ load_image(DATA_PREFIX "/images/shared/bigtux-right-jump.png", USE_ALPHA);
+
+ bigtux_left[0] = load_image(DATA_PREFIX "/images/shared/bigtux-left-0.png",
+ USE_ALPHA);
+
+ bigtux_left[1] = load_image(DATA_PREFIX "/images/shared/bigtux-left-1.png",
+ USE_ALPHA);
+
+ bigtux_left[2] = load_image(DATA_PREFIX "/images/shared/bigtux-left-2.png",
+ USE_ALPHA);
+
+ bigtux_left_jump =
+ load_image(DATA_PREFIX "/images/shared/bigtux-left-jump.png", USE_ALPHA);
+
+ bigcape_right[0] =
+ load_image(DATA_PREFIX "/images/shared/bigcape-right-0.png",
+ USE_ALPHA);
+
+ bigcape_right[1] =
+ load_image(DATA_PREFIX "/images/shared/bigcape-right-1.png",
+ USE_ALPHA);
+
+ bigcape_left[0] =
+ load_image(DATA_PREFIX "/images/shared/bigcape-left-0.png",
+ USE_ALPHA);
+
+ bigcape_left[1] =
+ load_image(DATA_PREFIX "/images/shared/bigcape-left-1.png",
+ USE_ALPHA);
+
+ ducktux_right = load_image(DATA_PREFIX
+ "/images/shared/ducktux-right.png",
+ USE_ALPHA);
+
+ ducktux_left = load_image(DATA_PREFIX
+ "/images/shared/ducktux-left.png",
+ USE_ALPHA);
+
+ skidtux_right = load_image(DATA_PREFIX
+ "/images/shared/skidtux-right.png",
+ USE_ALPHA);
+
+ skidtux_left = load_image(DATA_PREFIX
+ "/images/shared/skidtux-left.png",
+ USE_ALPHA);
+
+
+ /* Boxes: */
+
+ img_box_full = load_image(DATA_PREFIX "/images/shared/box-full.png",
+ IGNORE_ALPHA);
+ img_box_empty = load_image(DATA_PREFIX "/images/shared/box-empty.png",
+ IGNORE_ALPHA);
+
+
+ /* Water: */
+
+
+ img_water = load_image(DATA_PREFIX "/images/shared/water.png", IGNORE_ALPHA);
+
+ img_waves[0] = load_image(DATA_PREFIX "/images/shared/waves-0.png",
+ USE_ALPHA);
+
+ img_waves[1] = load_image(DATA_PREFIX "/images/shared/waves-1.png",
+ USE_ALPHA);
+
+ img_waves[2] = load_image(DATA_PREFIX "/images/shared/waves-2.png",
+ USE_ALPHA);
+
+
+ /* Pole: */
+
+ img_pole = load_image(DATA_PREFIX "/images/shared/pole.png", USE_ALPHA);
+ img_poletop = load_image(DATA_PREFIX "/images/shared/poletop.png",
+ USE_ALPHA);
+
+
+ /* Flag: */
+
+ img_flag[0] = load_image(DATA_PREFIX "/images/shared/flag-0.png",
+ USE_ALPHA);
+ img_flag[1] = load_image(DATA_PREFIX "/images/shared/flag-1.png",
+ USE_ALPHA);
+
+
+ /* Cloud: */
+
+ img_cloud[0][0] = load_image(DATA_PREFIX "/images/shared/cloud-00.png",
+ USE_ALPHA);
+
+ img_cloud[0][1] = load_image(DATA_PREFIX "/images/shared/cloud-01.png",
+ USE_ALPHA);
+
+ img_cloud[0][2] = load_image(DATA_PREFIX "/images/shared/cloud-02.png",
+ USE_ALPHA);
+
+ img_cloud[0][3] = load_image(DATA_PREFIX "/images/shared/cloud-03.png",
+ USE_ALPHA);
+
+
+ img_cloud[1][0] = load_image(DATA_PREFIX "/images/shared/cloud-10.png",
+ USE_ALPHA);
+
+ img_cloud[1][1] = load_image(DATA_PREFIX "/images/shared/cloud-11.png",
+ USE_ALPHA);
+
+ img_cloud[1][2] = load_image(DATA_PREFIX "/images/shared/cloud-12.png",
+ USE_ALPHA);
+
+ img_cloud[1][3] = load_image(DATA_PREFIX "/images/shared/cloud-13.png",
+ USE_ALPHA);
+
+
+ /* Bad guys: */
+
+ /* (BSOD) */
+
+ img_bsod_left[0] = load_image(DATA_PREFIX
+ "/images/shared/bsod-left-0.png",
+ USE_ALPHA);
+
+ img_bsod_left[1] = load_image(DATA_PREFIX
+ "/images/shared/bsod-left-1.png",
+ USE_ALPHA);
+
+ img_bsod_left[2] = load_image(DATA_PREFIX
+ "/images/shared/bsod-left-2.png",
+ USE_ALPHA);
+
+ img_bsod_left[3] = load_image(DATA_PREFIX
+ "/images/shared/bsod-left-3.png",
+ USE_ALPHA);
+
+ img_bsod_right[0] = load_image(DATA_PREFIX
+ "/images/shared/bsod-right-0.png",
+ USE_ALPHA);
+
+ img_bsod_right[1] = load_image(DATA_PREFIX
+ "/images/shared/bsod-right-1.png",
+ USE_ALPHA);
+
+ img_bsod_right[2] = load_image(DATA_PREFIX
+ "/images/shared/bsod-right-2.png",
+ USE_ALPHA);
+
+ img_bsod_right[3] = load_image(DATA_PREFIX
+ "/images/shared/bsod-right-3.png",
+ USE_ALPHA);
+
+ img_bsod_squished_left = load_image(DATA_PREFIX
+ "/images/shared/bsod-squished-left.png",
+ USE_ALPHA);
+
+ img_bsod_squished_right = load_image(DATA_PREFIX
+ "/images/shared/bsod-squished-right.png",
+ USE_ALPHA);
+
+ img_bsod_falling_left = load_image(DATA_PREFIX
+ "/images/shared/bsod-falling-left.png",
+ USE_ALPHA);
+
+ img_bsod_falling_right = load_image(DATA_PREFIX
+ "/images/shared/bsod-falling-right.png",
+ USE_ALPHA);
+
+
+ /* (Laptop) */
+
+ img_laptop_left[0] = load_image(DATA_PREFIX
+ "/images/shared/laptop-left-0.png",
+ USE_ALPHA);
+
+ img_laptop_left[1] = load_image(DATA_PREFIX
+ "/images/shared/laptop-left-1.png",
+ USE_ALPHA);
+
+ img_laptop_left[2] = load_image(DATA_PREFIX
+ "/images/shared/laptop-left-2.png",
+ USE_ALPHA);
+
+ img_laptop_right[0] = load_image(DATA_PREFIX
+ "/images/shared/laptop-right-0.png",
+ USE_ALPHA);
+
+ img_laptop_right[1] = load_image(DATA_PREFIX
+ "/images/shared/laptop-right-1.png",
+ USE_ALPHA);
+
+ img_laptop_right[2] = load_image(DATA_PREFIX
+ "/images/shared/laptop-right-2.png",
+ USE_ALPHA);
+
+ img_laptop_flat_left = load_image(DATA_PREFIX
+ "/images/shared/laptop-flat-left.png",
+ USE_ALPHA);
+
+ img_laptop_flat_right = load_image(DATA_PREFIX
+ "/images/shared/laptop-flat-right.png",
+ USE_ALPHA);
+
+ img_laptop_falling_left =
+ load_image(DATA_PREFIX
+ "/images/shared/laptop-falling-left.png",
+ USE_ALPHA);
+
+ img_laptop_falling_right =
+ load_image(DATA_PREFIX
+ "/images/shared/laptop-falling-right.png",
+ USE_ALPHA);
+
+
+ /* (Money) */
+
+ img_money_left[0] = load_image(DATA_PREFIX
+ "/images/shared/bag-left-0.png",
+ USE_ALPHA);
+
+ img_money_left[1] = load_image(DATA_PREFIX
+ "/images/shared/bag-left-1.png",
+ USE_ALPHA);
+
+ img_money_right[0] = load_image(DATA_PREFIX
+ "/images/shared/bag-right-0.png",
+ USE_ALPHA);
+
+ img_money_right[1] = load_image(DATA_PREFIX
+ "/images/shared/bag-right-1.png",
+ USE_ALPHA);
+
+
+
+ /* Upgrades: */
+
+ img_mints = load_image(DATA_PREFIX "/images/shared/mints.png", USE_ALPHA);
+ img_coffee = load_image(DATA_PREFIX "/images/shared/coffee.png", USE_ALPHA);
+
+
+ /* Weapons: */
+
+ img_bullet = load_image(DATA_PREFIX "/images/shared/bullet.png", USE_ALPHA);
+
+ img_red_glow = load_image(DATA_PREFIX "/images/shared/red-glow.png",
+ USE_ALPHA);
+
+
+ /* Distros: */
+
+ img_distro[0] = load_image(DATA_PREFIX "/images/shared/distro-0.png",
+ USE_ALPHA);
+
+ img_distro[1] = load_image(DATA_PREFIX "/images/shared/distro-1.png",
+ USE_ALPHA);
+
+ img_distro[2] = load_image(DATA_PREFIX "/images/shared/distro-2.png",
+ USE_ALPHA);
+
+ img_distro[3] = load_image(DATA_PREFIX "/images/shared/distro-3.png",
+ USE_ALPHA);
+
+
+ /* Herring: */
+
+ img_golden_herring =
+ load_image(DATA_PREFIX "/images/shared/golden-herring.png",
+ USE_ALPHA);
+
+
+ /* Super background: */
+
+ img_super_bkgd = load_image(DATA_PREFIX "/images/shared/super-bkgd.png",
+ IGNORE_ALPHA);
+
+
+ /* Sound effects: */
+
+#ifndef NOSOUND
+ if (use_sound)
+ {
+ for (i = 0; i < NUM_SOUNDS; i++)
+ sounds[i] = load_sound(soundfilenames[i]);
+ }
+#endif
+}
+
+
+/* Free shared data: */
+
+void unloadshared(void)
+{
+ int i;
+
+ for (i = 0; i < 3; i++)
+ {
+ SDL_FreeSurface(tux_right[i]);
+ SDL_FreeSurface(tux_left[i]);
+ SDL_FreeSurface(bigtux_right[i]);
+ SDL_FreeSurface(bigtux_left[i]);
+ }
+
+ SDL_FreeSurface(bigtux_right_jump);
+ SDL_FreeSurface(bigtux_left_jump);
+
+ for (i = 0; i < 2; i++)
+ {
+ SDL_FreeSurface(cape_right[i]);
+ SDL_FreeSurface(cape_left[i]);
+ SDL_FreeSurface(bigcape_right[i]);
+ SDL_FreeSurface(bigcape_left[i]);
+ }
+
+ SDL_FreeSurface(ducktux_left);
+ SDL_FreeSurface(ducktux_right);
+
+ SDL_FreeSurface(skidtux_left);
+ SDL_FreeSurface(skidtux_right);
+
+ for (i = 0; i < 4; i++)
+ {
+ SDL_FreeSurface(img_bsod_left[i]);
+ SDL_FreeSurface(img_bsod_right[i]);
+ }
+
+ SDL_FreeSurface(img_bsod_squished_left);
+ SDL_FreeSurface(img_bsod_squished_right);
+
+ SDL_FreeSurface(img_bsod_falling_left);
+ SDL_FreeSurface(img_bsod_falling_right);
+
+ for (i = 0; i < 3; i++)
+ {
+ SDL_FreeSurface(img_laptop_left[i]);
+ SDL_FreeSurface(img_laptop_right[i]);
+ }
+
+ SDL_FreeSurface(img_laptop_flat_left);
+ SDL_FreeSurface(img_laptop_flat_right);
+
+ SDL_FreeSurface(img_laptop_falling_left);
+ SDL_FreeSurface(img_laptop_falling_right);
+
+ for (i = 0; i < 2; i++)
+ {
+ SDL_FreeSurface(img_money_left[i]);
+ SDL_FreeSurface(img_money_right[i]);
+ }
+
+ SDL_FreeSurface(img_box_full);
+ SDL_FreeSurface(img_box_empty);
+
+ SDL_FreeSurface(img_water);
+ for (i = 0; i < 3; i++)
+ SDL_FreeSurface(img_waves[i]);
+
+ SDL_FreeSurface(img_pole);
+ SDL_FreeSurface(img_poletop);
+
+ for (i = 0; i < 2; i++)
+ SDL_FreeSurface(img_flag[i]);
+
+ SDL_FreeSurface(img_mints);
+ SDL_FreeSurface(img_coffee);
+
+ for (i = 0; i < 4; i++)
+ {
+ SDL_FreeSurface(img_distro[i]);
+ SDL_FreeSurface(img_cloud[0][i]);
+ SDL_FreeSurface(img_cloud[1][i]);
+ }
+
+ SDL_FreeSurface(img_golden_herring);
+
+#ifndef NOSOUND
+ if (use_sound)
+ {
+ for (i = 0; i < NUM_SOUNDS; i++)
+ Mix_FreeChunk(sounds[i]);
+ }
+#endif
+}
+
+
+/* Draw a tile on the screen: */
+
+void drawshape(int x, int y, unsigned char c)
+{
+ int z;
+
+ if (c == 'X' || c == 'x')
+ drawimage(img_brick[0], x, y, NO_UPDATE);
+ else if (c == 'Y' || c == 'y')
+ drawimage(img_brick[1], x, y, NO_UPDATE);
+ else if (c == 'A' || c =='B' || c == '!')
+ drawimage(img_box_full, x, y, NO_UPDATE);
+ else if (c == 'a')
+ drawimage(img_box_empty, x, y, NO_UPDATE);
+ else if (c >= 'C' && c <= 'F')
+ drawimage(img_cloud[0][c - 'C'], x, y, NO_UPDATE);
+ else if (c >= 'c' && c <= 'f')
+ drawimage(img_cloud[1][c - 'c'], x, y, NO_UPDATE);
+ else if (c >= 'G' && c <= 'J')
+ drawimage(img_bkgd[0][c - 'G'], x, y, NO_UPDATE);
+ else if (c >= 'g' && c <= 'j')
+ drawimage(img_bkgd[1][c - 'g'], x, y, NO_UPDATE);
+ else if (c == '#')
+ drawimage(img_solid[0], x, y, NO_UPDATE);
+ else if (c == '[')
+ drawimage(img_solid[1], x, y, NO_UPDATE);
+ else if (c == '=')
+ drawimage(img_solid[2], x, y, NO_UPDATE);
+ else if (c == ']')
+ drawimage(img_solid[3], x, y, NO_UPDATE);
+ else if (c == '$')
+ {
+ z = (frame / 2) % 6;
+
+ if (z < 4)
+ drawimage(img_distro[z], x, y, NO_UPDATE);
+ else if (z == 4)
+ drawimage(img_distro[2], x, y, NO_UPDATE);
+ else if (z == 5)
+ drawimage(img_distro[1], x, y, NO_UPDATE);
+ }
+ else if (c == '^')
+ {
+ z = (frame / 3) % 3;
+
+ drawimage(img_waves[z], x, y, NO_UPDATE);
+ }
+ else if (c == '*')
+ drawimage(img_poletop, x, y, NO_UPDATE);
+ else if (c == '|')
+ drawimage(img_pole, x, y, NO_UPDATE);
+ else if (c == '\\')
+ {
+ z = (frame / 3) % 2;
+
+ drawimage(img_flag[z], x + 16, y, NO_UPDATE);
+ }
+ else if (c == '&')
+ drawimage(img_water, x, y, NO_UPDATE);
+}
+
+
+/* What shape is at some position? */
+
+unsigned char shape(int x, int y, int sx)
+{
+ int xx, yy;
+ unsigned char c;
+
+ yy = (y / 32);
+ xx = ((x + sx) / 32);
+
+ if (yy >= 0 && yy <= 15 && xx >= 0 && xx <= LEVEL_WIDTH)
+ c = tiles[yy][xx];
+ else
+ c = '.';
+
+ return(c);
+}
+
+
+/* Is is ground? */
+
+int issolid(int x, int y, int sx)
+{
+ int v;
+
+ v = 0;
+
+ if (isbrick(x, y, sx) ||
+ isbrick(x + 31, y, sx) ||
+ isice(x, y, sx) ||
+ isice(x + 31, y, sx) ||
+ (shape(x, y, sx) == '[' ||
+ shape(x + 31, y, sx) == '[') ||
+ (shape(x, y, sx) == '=' ||
+ shape(x + 31, y, sx) == '=') ||
+ (shape(x, y, sx) == ']' ||
+ shape(x + 31, y, sx) == ']') ||
+ (shape(x, y, sx) == 'A' ||
+ shape(x + 31, y, sx) == 'A') ||
+ (shape(x, y, sx) == 'B' ||
+ shape(x + 31, y, sx) == 'B') ||
+ (shape(x, y, sx) == '!' ||
+ shape(x + 31, y, sx) == '!') ||
+ (shape(x, y, sx) == 'a' ||
+ shape(x + 31, y, sx) == 'a'))
+ {
+ v = 1;
+ }
+
+ return(v);
+}
+
+
+/* Is it a brick? */
+
+int isbrick(int x, int y, int sx)
+{
+ int v;
+
+ v = 0;
+
+ if (shape(x, y, sx) == 'X' ||
+ shape(x, y, sx) == 'x' ||
+ shape(x, y, sx) == 'Y' ||
+ shape(x, y, sx) == 'y')
+ {
+ v = 1;
+ }
+
+ return(v);
+}
+
+
+/* Is it ice? */
+
+int isice(int x, int y, int sx)
+{
+ int v;
+
+ v = 0;
+
+ if (shape(x, y, sx) == '#')
+ {
+ v = 1;
+ }
+
+ return(v);
+}
+
+
+/* Is it a full box? */
+
+int isfullbox(int x, int y, int sx)
+{
+ int v;
+
+ v = 0;
+
+ if (shape(x, y, sx) == 'A' ||
+ shape(x, y, sx) == 'B' ||
+ shape(x, y, sx) == '!')
+ {
+ v = 1;
+ }
+
+ return(v);
+}
+
+
+/* Edit a piece of the map! */
+
+void change(int x, int y, int sx, unsigned char c)
+{
+ int xx, yy;
+
+ yy = (y / 32);
+ xx = ((x + sx) / 32);
+
+ if (yy >= 0 && yy <= 15 && xx >= 0 && xx <= LEVEL_WIDTH)
+ tiles[yy][xx] = c;
+}
+
+
+/* Break a brick: */
+
+void trybreakbrick(int x, int y, int sx)
+{
+ if (isbrick(x, y, sx))
+ {
+ if (shape(x, y, sx) == 'x' || shape(x, y, sx) == 'y')
+ {
+ /* Get a distro from it: */
+
+ add_bouncy_distro(((x + sx + 1) / 32) * 32,
+ (y / 32) * 32);
+
+ if (counting_distros == NO)
+ {
+ counting_distros = YES;
+ distro_counter = 50;
+ }
+
+ if (distro_counter <= 0)
+ change(x, y, sx, 'a');
+
+#ifndef NOSOUND
+ playsound(sounds[SND_DISTRO]);
+#endif
+ score = score + SCORE_DISTRO;
+ distros++;
+ }
+ else
+ {
+ /* Get rid of it: */
+
+ change(x, y, sx, '.');
+ }
+
+
+ /* Replace it with broken bits: */
+
+ add_broken_brick(((x + sx + 1) / 32) * 32,
+ (y / 32) * 32);
+
+
+ /* Get some score: */
+
+#ifndef NOSOUND
+ playsound(sounds[SND_BRICK]);
+#endif
+ score = score + SCORE_BRICK;
+ }
+}
+
+
+/* Bounce a brick: */
+
+void bumpbrick(int x, int y, int sx)
+{
+ add_bouncy_brick(((x + sx + 1) / 32) * 32,
+ (y / 32) * 32);
+
+#ifndef NOSOUND
+ playsound(sounds[SND_BRICK]);
+#endif
+}
+
+
+/* Empty a box: */
+
+void tryemptybox(int x, int y, int sx)
+{
+ if (isfullbox(x, y, sx))
+ {
+ if (shape(x, y, sx) == 'A')
+ {
+ /* Box with a distro! */
+
+ add_bouncy_distro(((x + sx + 1) / 32) * 32,
+ (y / 32) * 32 - 32);
+
+#ifndef NOSOUND
+ playsound(sounds[SND_DISTRO]);
+#endif
+ score = score + SCORE_DISTRO;
+ distros++;
+ }
+ else if (shape(x, y, sx) == 'B')
+ {
+ /* Add an upgrade! */
+
+ if (tux_size == SMALL)
+ {
+ /* Tux is small, add mints! */
+
+ add_upgrade(((x + sx + 1) / 32) * 32,
+ (y / 32) * 32 - 32,
+ UPGRADE_MINTS);
+ }
+ else
+ {
+ /* Tux is big, add coffee: */
+
+ add_upgrade(((x + sx + 1) / 32) * 32,
+ (y / 32) * 32 - 32,
+ UPGRADE_COFFEE);
+ }
+
+#ifndef NOSOUND
+ playsound(sounds[SND_UPGRADE]);
+#endif
+ }
+ else if (shape(x, y, sx) == '!')
+ {
+ /* Add a golden herring */
+
+ add_upgrade(((x + sx + 1) / 32) * 32,
+ (y / 32) * 32 - 32,
+ UPGRADE_HERRING);
+ }
+
+ /* Empty the box: */
+
+ change(x, y, sx, 'a');
+ }
+}
+
+
+/* Try to grab a distro: */
+
+void trygrabdistro(int x, int y, int sx, int bounciness)
+{
+ if (shape(x, y, sx) == '$')
+ {
+ change(x, y, sx, '.');
+#ifndef NOSOUND
+ playsound(sounds[SND_DISTRO]);
+#endif
+
+ if (bounciness == BOUNCE)
+ {
+ add_bouncy_distro(((x + sx + 1) / 32) * 32,
+ (y / 32) * 32);
+ }
+
+ score = score + SCORE_DISTRO;
+ distros++;
+ }
+}
+
+
+/* Add a bouncy distro: */
+
+void add_bouncy_distro(int x, int y)
+{
+ int i, found;
+
+ found = -1;
+
+ for (i = 0; i < NUM_BOUNCY_DISTROS && found == -1; i++)
+ {
+ if (!bouncy_distros[i].alive)
+ found = i;
+ }
+
+ if (found != -1)
+ {
+ bouncy_distros[found].alive = YES;
+ bouncy_distros[found].x = x;
+ bouncy_distros[found].y = y;
+ bouncy_distros[found].ym = -6;
+ }
+}
+
+
+/* Add broken brick pieces: */
+
+void add_broken_brick(int x, int y)
+{
+ add_broken_brick_piece(x, y, -4, -16);
+ add_broken_brick_piece(x, y + 16, -6, -12);
+
+ add_broken_brick_piece(x + 16, y, 4, -16);
+ add_broken_brick_piece(x + 16, y + 16, 6, -12);
+}
+
+
+/* Add a broken brick piece: */
+
+void add_broken_brick_piece(int x, int y, int xm, int ym)
+{
+ int i, found;
+
+ found = -1;
+
+ for (i = 0; i < NUM_BROKEN_BRICKS && found == -1; i++)
+ {
+ if (!broken_bricks[i].alive)
+ found = i;
+ }
+
+ if (found != -1)
+ {
+ broken_bricks[found].alive = YES;
+ broken_bricks[found].x = x;
+ broken_bricks[found].y = y;
+ broken_bricks[found].xm = xm;
+ broken_bricks[found].ym = ym;
+ }
+}
+
+
+/* Add a bouncy brick piece: */
+
+void add_bouncy_brick(int x, int y)
+{
+ int i, found;
+
+ found = -1;
+
+ for (i = 0; i < NUM_BOUNCY_BRICKS && found == -1; i++)
+ {
+ if (!bouncy_bricks[i].alive)
+ found = i;
+ }
+
+ if (found != -1)
+ {
+ bouncy_bricks[found].alive = YES;
+ bouncy_bricks[found].x = x;
+ bouncy_bricks[found].y = y;
+ bouncy_bricks[found].offset = 0;
+ bouncy_bricks[found].offset_m = -BOUNCY_BRICK_SPEED;
+ bouncy_bricks[found].shape = shape(x, y, 0);
+ }
+}
+
+
+/* Add a bad guy: */
+
+void add_bad_guy(int x, int y, int kind)
+{
+ int i, found;
+
+ found = -1;
+
+ for (i = 0; i < NUM_BAD_GUYS && found == -1; i++)
+ {
+ if (!bad_guys[i].alive)
+ found = i;
+ }
+
+ if (found != -1)
+ {
+ bad_guys[found].alive = YES;
+ bad_guys[found].mode = NORMAL;
+ bad_guys[found].dying = NO;
+ bad_guys[found].timer = 0;
+ bad_guys[found].kind = kind;
+ bad_guys[found].x = x;
+ bad_guys[found].y = y;
+ bad_guys[found].xm = 0;
+ bad_guys[found].ym = 0;
+ bad_guys[found].dir = LEFT;
+ bad_guys[found].seen = NO;
+ }
+}
+
+
+/* Add score: */
+
+void add_score(int x, int y, int s)
+{
+ int i, found;
+
+
+ /* Add the score: */
+
+ score = score + s;
+
+
+ /* Add a floating score thing to the game: */
+
+ found = -1;
+
+ for (i = 0; i < NUM_FLOATING_SCORES && found == -1; i++)
+ {
+ if (!floating_scores[i].alive)
+ found = i;
+ }
+
+
+ if (found != -1)
+ {
+ floating_scores[found].alive = YES;
+ floating_scores[found].x = x;
+ floating_scores[found].y = y - 16;
+ floating_scores[found].timer = 8;
+ floating_scores[found].value = s;
+ }
+}
+
+
+/* Try to bump a bad guy from below: */
+
+void trybumpbadguy(int x, int y, int sx)
+{
+ int i;
+
+
+ /* Bad guys: */
+
+ for (i = 0; i < NUM_BAD_GUYS; i++)
+ {
+ if (bad_guys[i].alive &&
+ bad_guys[i].x >= x + sx - 32 && bad_guys[i].x <= x + sx + 32 &&
+ bad_guys[i].y >= y - 16 && bad_guys[i].y <= y + 16)
+ {
+ if (bad_guys[i].kind == BAD_BSOD ||
+ bad_guys[i].kind == BAD_LAPTOP)
+ {
+ bad_guys[i].dying = FALLING;
+ bad_guys[i].ym = -8;
+#ifndef NOSOUND
+ playsound(sounds[SND_FALL]);
+#endif
+ }
+ }
+ }
+
+
+ /* Upgrades: */
+
+ for (i = 0; i < NUM_UPGRADES; i++)
+ {
+ if (upgrades[i].alive && upgrades[i].height == 32 &&
+ upgrades[i].x >= x + sx - 32 && upgrades[i].x <= x + sx + 32 &&
+ upgrades[i].y >= y - 16 && upgrades[i].y <= y + 16)
+ {
+ upgrades[i].xm = -upgrades[i].xm;
+ upgrades[i].ym = -8;
+#ifndef NOSOUND
+ playsound(sounds[SND_BUMP_UPGRADE]);
+#endif
+ }
+ }
+}
+
+
+/* Add an upgrade: */
+
+void add_upgrade(int x, int y, int kind)
+{
+ int i, found;
+
+ found = -1;
+
+ for (i = 0; i < NUM_UPGRADES && found == -1; i++)
+ {
+ if (!upgrades[i].alive)
+ found = i;
+ }
+
+ if (found != -1)
+ {
+ upgrades[found].alive = YES;
+ upgrades[found].kind = kind;
+ upgrades[found].x = x;
+ upgrades[found].y = y;
+ upgrades[found].xm = 4;
+ upgrades[found].ym = -4;
+ upgrades[found].height = 0;
+ }
+}
+
+
+/* Kill tux! */
+
+void killtux(int mode)
+{
+ tux_ym = -16;
+
+#ifndef NOSOUND
+ playsound(sounds[SND_HURT]);
+#endif
+
+ if (tux_dir == RIGHT)
+ tux_xm = -8;
+ else if (tux_dir == LEFT)
+ tux_xm = 8;
+
+ if (mode == SHRINK && tux_size == BIG)
+ {
+ if (tux_got_coffee)
+ tux_got_coffee = NO;
+
+ tux_size = SMALL;
+
+ tux_safe = TUX_SAFE_TIME;
+ }
+ else
+ {
+ tux_dying = 1;
+ }
+}
+
+
+/* Add a bullet: */
+
+void add_bullet(int x, int y, int dir, int xm)
+{
+ int i, found;
+
+ found = -1;
+
+ for (i = 0; i < NUM_BULLETS && found == -1; i++)
+ {
+ if (!bullets[i].alive)
+ found = i;
+ }
+
+ if (found != -1)
+ {
+ bullets[found].alive = YES;
+
+ if (dir == RIGHT)
+ {
+ bullets[found].x = x + 32;
+ bullets[found].xm = BULLET_XM + xm;
+ }
+ else
+ {
+ bullets[found].x = x;
+ bullets[found].xm = -BULLET_XM + xm;
+ }
+
+ bullets[found].y = y;
+ bullets[found].ym = BULLET_STARTING_YM;
+
+#ifndef NOSOUND
+ playsound(sounds[SND_SHOOT]);
+#endif
+ }
+}