Logo Search packages:      
Sourcecode: madbomber version File versions  Download package

madbomber.c

/*
  madbomber.c
  
  by Bill Kendrick
  bill@newbreedsoftware.com
  http://www.newbreedsoftware.com/
  
  October 25, 1999 - April 20, 2002
*/


#ifndef EMBEDDED
#define VERSION "0.2.4"
#else
#define VERSION "0.2.4-embedded"
#define SDL_MIXER_BUG
#endif


/* #includes: */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <SDL.h>
#include <SDL_image.h>
#include <math.h>

/* #ifdef WIN32 */
/* #include <windows.h> */
/* #endif */

#ifndef NOSOUND
#include <SDL_mixer.h>
#endif


/* Image enumerations: */

enum {
  IMG_LOADING,
  IMG_BAR,
  IMG_TITLE_TITLE,
  IMG_TITLE_ONE_PLAYER,
  IMG_TITLE_ONE_PLAYER_OFF,
  IMG_TITLE_TWO_PLAYERS,
  IMG_TITLE_TWO_PLAYERS_OFF,
#ifndef EMBEDDED
  IMG_TITLE_TWO_PLAYER_VS,
  IMG_TITLE_TWO_PLAYER_VS_OFF,
#else
  IMG_TITLE_CONTINUE,
  IMG_TITLE_CONTINUE_OFF,
#endif
  IMG_TITLE_OPTIONS,
  IMG_TITLE_OPTIONS_OFF,
  IMG_TITLE_HIGHSCORE,
  IMG_TITLE_HIGHSCORE_OFF,
  IMG_TITLE_EXIT,
  IMG_TITLE_EXIT_OFF,
  IMG_OPTIONS_OPTIONS,
  IMG_OPTIONS_DETAIL,
  IMG_OPTIONS_NORMAL,
  IMG_OPTIONS_NORMAL_OFF,
  IMG_OPTIONS_ZEN,
  IMG_OPTIONS_ZEN_OFF,
  IMG_OPTIONS_PLAYER_ONE,
  IMG_OPTIONS_PLAYER_TWO,
  IMG_OPTIONS_DIFFICULTY,
  IMG_OPTIONS_HARD,
  IMG_OPTIONS_HARD_OFF,
  IMG_OPTIONS_EFFECTS,
#ifndef EMBEDDED
  IMG_OPTIONS_MUSIC,
  IMG_OPTIONS_VOLUME,
#endif
  IMG_OPTIONS_0PERCENT,
  IMG_OPTIONS_0PERCENT_OFF,
  IMG_OPTIONS_25PERCENT,
  IMG_OPTIONS_25PERCENT_OFF,
  IMG_OPTIONS_50PERCENT,
  IMG_OPTIONS_50PERCENT_OFF,
  IMG_OPTIONS_75PERCENT,
  IMG_OPTIONS_75PERCENT_OFF,
  IMG_OPTIONS_100PERCENT,
  IMG_OPTIONS_100PERCENT_OFF,
  IMG_OPTIONS_OK,
  IMG_OPTIONS_OK_OFF,
  IMG_BACKGROUND,
  IMG_BUCKET1,
  IMG_BUCKET2,
  IMG_BUCKET3,
  IMG_BUCKET1RED,
  IMG_BUCKET2RED,
  IMG_BUCKET3RED,
  IMG_SMALL_BUCKET1,
  IMG_SMALL_BUCKET2,
  IMG_SMALL_BUCKET3,
  IMG_SMALL_BUCKET1RED,
  IMG_SMALL_BUCKET2RED,
  IMG_SMALL_BUCKET3RED,
  IMG_BOMB0,
  IMG_BOMB1,
  IMG_BOMB2,
  IMG_BOMB3,
  IMG_EXPLOSION1,
  IMG_EXPLOSION2,
  IMG_BOMBER_SAD,
  IMG_BOMBER_HAPPY,
  IMG_BOMBER_AMAZED,
  IMG_DROP_UP,
  IMG_DROP_RIGHT_UP,
  IMG_DROP_RIGHT,
  IMG_DROP_RIGHT_DOWN,
  IMG_DROP_DOWN,
  IMG_DROP_LEFT_DOWN,
  IMG_DROP_LEFT,
  IMG_DROP_LEFT_UP,
  IMG_0,
  IMG_1,
  IMG_2,
  IMG_3,
  IMG_4,
  IMG_5,
  IMG_6,
  IMG_7,
  IMG_8,
  IMG_9,
  IMG_0RED,
  IMG_1RED,
  IMG_2RED,
  IMG_3RED,
  IMG_4RED,
  IMG_5RED,
  IMG_6RED,
  IMG_7RED,
  IMG_8RED,
  IMG_9RED,
  IMG_HIGHSCORE,
  IMG_PAUSED,
  IMG_GAME_OVER,
  IMG_PRESS_FIRE,
  IMG_PRESS_ESCAPE,
  IMG_SPRAY_CYAN,
  IMG_SPRAY_BLACK,
  IMG_SPRAY_BLUE,
  IMG_HIGHSCORE_HIGHSCORE,
  IMG_HIGHSCORE_LETTERS,
  NUM_IMAGES
};


/* Image filenames: */

const char * image_names[NUM_IMAGES] = {
  DATA_PREFIX "images/loading.png",
  DATA_PREFIX "images/bar.png",
  DATA_PREFIX "images/title/title.png",
  DATA_PREFIX "images/title/one-player.png",
  DATA_PREFIX "images/title/one-player-off.png",
  DATA_PREFIX "images/title/two-players.png",
  DATA_PREFIX "images/title/two-players-off.png",
#ifndef EMBEDDED
  DATA_PREFIX "images/title/two-player-vs.png",
  DATA_PREFIX "images/title/two-player-vs-off.png",
#else
  DATA_PREFIX "images/title/continue.png",
  DATA_PREFIX "images/title/continue-off.png",
#endif
  DATA_PREFIX "images/title/options.png",
  DATA_PREFIX "images/title/options-off.png",
  DATA_PREFIX "images/title/highscore.png",
  DATA_PREFIX "images/title/highscore-off.png",
  DATA_PREFIX "images/title/exit.png",
  DATA_PREFIX "images/title/exit-off.png",
  DATA_PREFIX "images/options/options.png",
  DATA_PREFIX "images/options/detail.png",
  DATA_PREFIX "images/options/normal.png",
  DATA_PREFIX "images/options/normal-off.png",
  DATA_PREFIX "images/options/zen.png",
  DATA_PREFIX "images/options/zen-off.png",
  DATA_PREFIX "images/options/player-one.png",
  DATA_PREFIX "images/options/player-two.png",
  DATA_PREFIX "images/options/difficulty.png",
  DATA_PREFIX "images/options/hard.png",
  DATA_PREFIX "images/options/hard-off.png",
  DATA_PREFIX "images/options/effects.png",
#ifndef EMBEDDED
  DATA_PREFIX "images/options/music.png",
  DATA_PREFIX "images/options/volume.png",
#endif
  DATA_PREFIX "images/options/0percent.png",
  DATA_PREFIX "images/options/0percent-off.png",
  DATA_PREFIX "images/options/25percent.png",
  DATA_PREFIX "images/options/25percent-off.png",
  DATA_PREFIX "images/options/50percent.png",
  DATA_PREFIX "images/options/50percent-off.png",
  DATA_PREFIX "images/options/75percent.png",
  DATA_PREFIX "images/options/75percent-off.png",
  DATA_PREFIX "images/options/100percent.png",
  DATA_PREFIX "images/options/100percent-off.png",
  DATA_PREFIX "images/options/ok.png",
  DATA_PREFIX "images/options/ok-off.png",
  DATA_PREFIX "images/game/background.png",
  DATA_PREFIX "images/game/bucket/bucket1.png",
  DATA_PREFIX "images/game/bucket/bucket2.png",
  DATA_PREFIX "images/game/bucket/bucket3.png",
  DATA_PREFIX "images/game/bucket/bucket1red.png",
  DATA_PREFIX "images/game/bucket/bucket2red.png",
  DATA_PREFIX "images/game/bucket/bucket3red.png",
  DATA_PREFIX "images/game/bucket/small-bucket1.png",
  DATA_PREFIX "images/game/bucket/small-bucket2.png",
  DATA_PREFIX "images/game/bucket/small-bucket2.png",
  DATA_PREFIX "images/game/bucket/small-bucket1red.png",
  DATA_PREFIX "images/game/bucket/small-bucket2red.png",
  DATA_PREFIX "images/game/bucket/small-bucket2red.png",
  DATA_PREFIX "images/game/bomb/bomb0.png",
  DATA_PREFIX "images/game/bomb/bomb1.png",
  DATA_PREFIX "images/game/bomb/bomb2.png",
  DATA_PREFIX "images/game/bomb/bomb3.png",
  DATA_PREFIX "images/game/bomb/explosion1.png",
  DATA_PREFIX "images/game/bomb/explosion2.png",
  DATA_PREFIX "images/game/bomber/bomber-sad.png",
  DATA_PREFIX "images/game/bomber/bomber-happy.png",
  DATA_PREFIX "images/game/bomber/bomber-amazed.png",
  DATA_PREFIX "images/game/drop/drop-up.png",
  DATA_PREFIX "images/game/drop/drop-right-up.png",
  DATA_PREFIX "images/game/drop/drop-right.png",
  DATA_PREFIX "images/game/drop/drop-right-down.png",
  DATA_PREFIX "images/game/drop/drop-down.png",
  DATA_PREFIX "images/game/drop/drop-left-down.png",
  DATA_PREFIX "images/game/drop/drop-left.png",
  DATA_PREFIX "images/game/drop/drop-left-up.png",
  DATA_PREFIX "images/game/numbers/0.png",
  DATA_PREFIX "images/game/numbers/1.png",
  DATA_PREFIX "images/game/numbers/2.png",
  DATA_PREFIX "images/game/numbers/3.png",
  DATA_PREFIX "images/game/numbers/4.png",
  DATA_PREFIX "images/game/numbers/5.png",
  DATA_PREFIX "images/game/numbers/6.png",
  DATA_PREFIX "images/game/numbers/7.png",
  DATA_PREFIX "images/game/numbers/8.png",
  DATA_PREFIX "images/game/numbers/9.png",
  DATA_PREFIX "images/game/numbers/0red.png",
  DATA_PREFIX "images/game/numbers/1red.png",
  DATA_PREFIX "images/game/numbers/2red.png",
  DATA_PREFIX "images/game/numbers/3red.png",
  DATA_PREFIX "images/game/numbers/4red.png",
  DATA_PREFIX "images/game/numbers/5red.png",
  DATA_PREFIX "images/game/numbers/6red.png",
  DATA_PREFIX "images/game/numbers/7red.png",
  DATA_PREFIX "images/game/numbers/8red.png",
  DATA_PREFIX "images/game/numbers/9red.png",
  DATA_PREFIX "images/game/highscore.png",
  DATA_PREFIX "images/game/paused.png",
  DATA_PREFIX "images/game/game-over.png",
  DATA_PREFIX "images/game/press-fire.png",
  DATA_PREFIX "images/game/press-escape.png",
  DATA_PREFIX "images/spray-cyan.png",
  DATA_PREFIX "images/spray-black.png",
  DATA_PREFIX "images/spray-blue.png",
  DATA_PREFIX "images/highscore/highscore.png",
  DATA_PREFIX "images/highscore/letters.png"
};


/* Sound enumerations: */

enum {
  SND_SELECT,
  SND_CONFIRM,
  SND_FUSE,
  SND_EXPLOSION,
  SND_BIGEXPLOSION,
  SND_SPLASH1,
  SND_SPLASH2,
  SND_SPLASH3,
  SND_SPLASH4,
  SND_SPLASH5,
  SND_SPLASH6,
  SND_SPLASH7,
  SND_SPLASH8,
  SND_ONEUP,
  SND_LEVEL8,
  SND_HIGHSCORE,
  SND_SPRAY,
  SND_CAN_SHAKE,
  NUM_SOUNDS
};


/* Sound filenames: */

const char * sound_names[NUM_SOUNDS] = {
  DATA_PREFIX "sounds/select.wav",
  DATA_PREFIX "sounds/confirm.wav",
  DATA_PREFIX "sounds/fuse.wav",
  DATA_PREFIX "sounds/explosion.wav",
  DATA_PREFIX "sounds/bigexplosion.wav",
  DATA_PREFIX "sounds/splash1.wav",
  DATA_PREFIX "sounds/splash2.wav",
  DATA_PREFIX "sounds/splash3.wav",
  DATA_PREFIX "sounds/splash4.wav",
  DATA_PREFIX "sounds/splash5.wav",
  DATA_PREFIX "sounds/splash6.wav",
  DATA_PREFIX "sounds/splash7.wav",
  DATA_PREFIX "sounds/splash8.wav",
  DATA_PREFIX "sounds/oneup.wav",
  DATA_PREFIX "sounds/level8.wav",
  DATA_PREFIX "sounds/highscore.wav",
  DATA_PREFIX "sounds/spray.wav",
  DATA_PREFIX "sounds/can-shake.wav"
};


/* Music filenames: */

#ifndef EMBEDDED

#define MUS_TITLE DATA_PREFIX "music/bizjung.it"
#define MUS_HIGHSCORE DATA_PREFIX "music/waterfal.mod"

#define NUM_GAME_MUSICS 3

const char * game_music_names[NUM_GAME_MUSICS] = {
  DATA_PREFIX "music/fdn-arab.s3m",
  DATA_PREFIX "music/gluppobe.mod",
  DATA_PREFIX "music/astraltr.mod"
};

#else

#define MUS_TITLE DATA_PREFIX "music/winterwi.mod"

#define NUM_GAME_MUSICS 1

const char * game_music_names[NUM_GAME_MUSICS] = {
  DATA_PREFIX "music/fdn-arab.s3m"
};

#endif


/* Title Options: */

enum {
  TITLE_OPTION_ONE_PLAYER,
  TITLE_OPTION_TWO_PLAYERS,
#ifndef EMBEDDED
  TITLE_OPTION_TWO_PLAYER_VS,
#else
  TITLE_OPTION_CONTINUE,
#endif
  TITLE_OPTION_OPTIONS,
  TITLE_OPTION_HIGHSCORE,
  TITLE_OPTION_EXIT,
  NUM_TITLE_OPTIONS
};


/* Title option images: */

const int title_option_images[NUM_TITLE_OPTIONS] = {
  IMG_TITLE_ONE_PLAYER,
  IMG_TITLE_TWO_PLAYERS,
#ifndef EMBEDDED
  IMG_TITLE_TWO_PLAYER_VS,
#else
  IMG_TITLE_CONTINUE,
#endif
  IMG_TITLE_OPTIONS,
  IMG_TITLE_HIGHSCORE,
  IMG_TITLE_EXIT
};


/* Option screen option enumerations: */

enum {
  OPTIONS_OPTION_DETAIL,
  OPTIONS_OPTION_PLAYER_ONE,
  OPTIONS_OPTION_PLAYER_TWO,
  OPTIONS_OPTION_EFFECTS,
  OPTIONS_OPTION_MUSIC,
  OPTIONS_OPTION_OK,
  NUM_OPTIONS_OPTIONS
};


#ifdef EMBEDDED
#define NOSOUND_CONTROLS
#else
#ifdef NOSOUND
#define NOSOUND_CONTROLS
#endif
#endif


#ifndef EMBEDDED

/* Flying number layouts: */

int flying_number_layouts[8][7] = {
  {  0,
   0,  1,
     0,
   0,  1,
     0},

  {  1,
   0,  1,
     1,
   1,  0,
     1},

  {  1,
   0,  1,
     1,
   0,  1,
     1},

  {  0,
   1,  1,
     1,
   0,  1,
     0},

  {  1,
   1,  0,
     1,
   0,  1,
     1},

  {  1,
   1,  0,
     1,
   1,  1,
     1},

  {  1,
   0,  1,
     0,
   0,  1,
     0},

  {  1,
   1,  1,
     1,
   1,  1,
     1}
};

#endif


/* Graffiti letters: */

int graffiti[36][5][2][2] = {
  {
    /* 0 */
    { { 2, 0 }, { 0, 4 } },
    { { 0, 4 }, { 2, 8 } },
    { { 2, 8 }, { 4, 4 } },
    { { 4, 4 }, { 2, 0 } },
    { { 4, 0 }, { 0, 8 } }
  },
  {
    /* 1 */
    { { 0, 1 }, { 2, 0 } },
    { { 2, 0 }, { 2, 8 } },
    { { -1, -1 }, { -1, -1 } },
    { { -1, -1 }, { -1, -1 } },
    { { -1, -1 }, { -1, -1 } }
  },
  {
    /* 2 */
    { { 1, 1 }, { 2, 0 } },
    { { 2, 0 }, { 3, 0 } },
    { { 3, 0 }, { 4, 3 } },
    { { 4, 3 }, { 0, 8 } },
    { { 0, 8 }, { 4, 8 } }
  },
  {
    /* 3 */
    { { 0, 0 }, { 4, 2 } },
    { { 4, 2 }, { 1, 4 } },
    { { 1, 4 }, { 4, 6 } },
    { { 4, 6 }, { 0, 8 } },
    { { -1, -1 }, { -1, -1 } }
  },
  {
    /* 4 */
    { { 1, 0 }, { 0, 4 } },
    { { 0, 4 }, { 4, 4 } },
    { { 4, 0 }, { 2, 8 } },
    { { -1, -1 }, { -1, -1 } },
    { { -1, -1 }, { -1, -1 } }
  },
  {
    /* 5 */
    { { 4, 0 }, { 0, 0 } },
    { { 0, 0 }, { 0, 5 } },
    { { 0, 5 }, { 3, 4 } },
    { { 3, 4 }, { 4, 6 } },
    { { 4, 6 }, { 0, 8 } }
  },
  {
    /* 6 */
    { { 4, 0 }, { 0, 6 } },
    { { 0, 6 }, { 2, 8 } },
    { { 2, 8 }, { 4, 6 } },
    { { 4, 6 }, { 2, 4 } },
    { { -1, -1 }, { -1, -1 } }
  },
  {
    /* 7 */
    { { 0, 1 }, { 4, 0 } },
    { { 4, 0 }, { 1, 8 } },
    { { 1, 4 }, { 4, 3 } },
    { { -1, -1 }, { -1, -1 } },
    { { -1, -1 }, { -1, -1 } }
  },
  {
    /* 8 */
    { { 0, 1 }, { 4, 0 } },
    { { 4, 0 }, { 0, 5 } },
    { { 0, 5 }, { 2, 8 } },
    { { 2, 8 }, { 4, 5 } },
    { { 4, 5 }, { 0, 1 } }
  },
  {
    /* 9 */
    { { 4, 0 }, { 1, 1 } },
    { { 1, 1 }, { 0, 4 } },
    { { 0, 4 }, { 2, 3 } },
    { { 2, 3 }, { 4, 0 } },
    { { 4, 0 }, { 3, 8 } }
  },
  {
    /* A */
    { { 0, 8 }, { 2, 0 } },
    { { 2, 0 }, { 4, 8 } },
    { { 0, 7 }, { 4, 4 } },
    { { -1, -1 }, { -1, -1 } },
    { { -1, -1 }, { -1, -1 } }
  },
  {
    /* B */
    { { 0, 8 }, { 0, 0 } },
    { { 0, 0 }, { 4, 2 } },
    { { 4, 2 }, { 0, 4 } },
    { { 0, 4 }, { 4, 6 } },
    { { 4, 6 }, { 0, 8 } }
  },
  {
    /* C */
    { { 4, 0 }, { 0, 4 } },
    { { 0, 4 }, { 4, 8 } },
    { { -1, -1 }, { -1, -1 } },
    { { -1, -1 }, { -1, -1 } },
    { { -1, -1 }, { -1, -1 } }
  },
  {
    /* D */
    { { 0, 0 }, { 0, 8 } },
    { { 0, 8 }, { 4, 4 } },
    { { 4, 4 }, { 0, 0 } },
    { { -1, -1 }, { -1, -1 } },
    { { -1, -1 }, { -1, -1 } }
  },
  {
    /* E */
    { { 4, 0 }, { 0, 2 } },
    { { 0, 2 }, { 3, 4 } },
    { { 3, 4 }, { 0, 6 } },
    { { 0, 6 }, { 4, 8 } },
    { { -1, -1 }, { -1, -1 } }
  },
  {
    /* F */
    { { 4, 0 }, { 0, 1 } },
    { { 0, 1 }, { 1, 8 } },
    { { 0, 4 }, { 4, 3 } },
    { { -1, -1 }, { -1, -1 } },
    { { -1, -1 }, { -1, -1 } }
  },
  {
    /* G */
    { { 4, 0 }, { 0, 4 } },
    { { 0, 4 }, { 4, 8 } },
    { { 4, 8 }, { 4, 4 } },
    { { -1, -1 }, { -1, -1 } },
    { { -1, -1 }, { -1, -1 } }
  },
  {
    /* H */
    { { 1, 0 }, { 0, 8 } },
    { { 4, 0 }, { 4, 8 } },
    { { 0, 4 }, { 5, 3 } },
    { { -1, -1 }, { -1, -1 } },
    { { -1, -1 }, { -1, -1 } }
  },
  {
    /* I */
    { { 3, 0 }, { 2, 8 } },
    { { -1, -1 }, { -1, -1 } },
    { { -1, -1 }, { -1, -1 } },
    { { -1, -1 }, { -1, -1 } },
    { { -1, -1 }, { -1, -1 } }
  },
  {
    /* J */
    { { 4, 0 }, { 4, 6 } },
    { { 4, 6 }, { 2, 8 } },
    { { 2, 8 }, { 0, 5 } },
    { { -1, -1 }, { -1, -1 } },
    { { -1, -1 }, { -1, -1 } }
  },
  {
    /* K */
    { { 0, 0 }, { 0, 8 } },
    { { 3, 0 }, { 0, 4 } },
    { { 0, 4 }, { 4, 8 } },
    { { -1, -1 }, { -1, -1 } },
    { { -1, -1 }, { -1, -1 } }
  },
  {
    /* L */
    { { 0, 0 }, { 0, 8 } },
    { { 0, 8 }, { 4, 7 } },
    { { -1, -1 }, { -1, -1 } },
    { { -1, -1 }, { -1, -1 } },
    { { -1, -1 }, { -1, -1 } }
  },
  {
    /* M */
    { { 0, 8 }, { 1, 0 } },
    { { 1, 0 }, { 2, 4 } },
    { { 2, 4 }, { 4, 0 } },
    { { 4, 0 }, { 4, 8 } },
    { { -1, -1 }, { -1, -1 } }
  },
  {
    /* N */
    { { 0, 8 }, { 0, 0 } },
    { { 0, 0 }, { 4, 8 } },
    { { 4, 8 }, { 4, 1 } },
    { { -1, -1 }, { -1, -1 } },
    { { -1, -1 }, { -1, -1 } }
  },
  {
    /* O */
    { { 2, 0 }, { 0, 4 } },
    { { 0, 4 }, { 2, 8 } },
    { { 2, 8 }, { 4, 4 } },
    { { 4, 4 }, { 2, 0 } },
    { { -1, -1 }, { -1, -1 } }
  },
  {
    /* P */
    { { 0, 8 }, { 0, 0 } },
    { { 0, 0 }, { 4, 2 } },
    { { 4, 2 }, { 0, 4 } },
    { { -1, -1 }, { -1, -1 } },
    { { -1, -1 }, { -1, -1 } }
  },
  {
    /* Q */
    { { 2, 0 }, { 0, 4 } },
    { { 0, 4 }, { 2, 8 } },
    { { 2, 8 }, { 4, 4 } },
    { { 4, 4 }, { 2, 0 } },
    { { 2, 4 }, { 4, 8 } }
  },
  {
    /* R */
    { { 0, 8 }, { 0, 0 } },
    { { 0, 0 }, { 4, 2 } },
    { { 4, 2 }, { 0, 4 } },
    { { 0, 4 }, { 4, 8 } },
    { { -1, -1 }, { -1, -1 } }
  },
  {
    /* S */
    { { 4, 0 }, { 0, 3 } },
    { { 0, 2 }, { 4, 5 } },
    { { 4, 5 }, { 0, 8 } },
    { { -1, -1 }, { -1, -1 } },
    { { -1, -1 }, { -1, -1 } }
  },
  {
    /* T */
    { { 0, 0 }, { 4, 0 } },
    { { 2, 0 }, { 1, 8 } },
    { { -1, -1 }, { -1, -1 } },
    { { -1, -1 }, { -1, -1 } },
    { { -1, -1 }, { -1, -1 } }
  },
  {
    /* U */
    { { 0, 0 }, { 0, 8 } },
    { { 0, 8 }, { 4, 7 } },
    { { 4, 7 }, { 4, 0 } },
    { { -1, -1 }, { -1, -1 } },
    { { -1, -1 }, { -1, -1 } }
  },
  {
    /* V */
    { { 0, 0 }, { 2, 8 } },
    { { 2, 8 }, { 4, 0 } },
    { { -1, -1 }, { -1, -1 } },
    { { -1, -1 }, { -1, -1 } },
    { { -1, -1 }, { -1, -1 } }
  },
  {
    /* W */
    { { 0, 0 }, { 1, 8 } },
    { { 1, 8 }, { 2, 5 } },
    { { 2, 5 }, { 3, 8 } },
    { { 3, 8 }, { 4, 0 } },
    { { -1, -1 }, { -1, -1 } }
  },
  {
    /* X */
    { { 0, 0 }, { 4, 8 } },
    { { 4, 0 }, { 0, 8 } },
    { { -1, -1 }, { -1, -1 } },
    { { -1, -1 }, { -1, -1 } },
    { { -1, -1 }, { -1, -1 } }
  },
  {
    /* Y */
    { { 0, 0 }, { 2, 4 } },
    { { 4, 0 }, { 0, 8 } },
    { { -1, -1 }, { -1, -1 } },
    { { -1, -1 }, { -1, -1 } },
    { { -1, -1 }, { -1, -1 } }
  },
  {
    /* Z */
    { { 0, 0 }, { 4, 0 } },
    { { 4, 0 }, { 0, 8 } },
    { { 0, 8 }, { 4, 8 } },
    { { -1, -1 }, { -1, -1 } },
    { { -1, -1 }, { -1, -1 } }
  }
};


/* Bomb per level: */

int bombs_per_level[8] = {
  10,
  20,
  30,
  40,
  50,
  75,
  100,
  150
};


/* Bombs: */

#define MAX_BOMBS 128

typedef struct bomb_type {
  int alive, x, y;
} bomb_type;


/* Drops: */

#define MAX_DROPS 256

typedef struct drop_type {
  int alive, timer, x, y, xm, ym;
} drop_type;


/* Spray drips: */

#define MAX_SPRAYDRIPS 16

typedef struct spraydrip_type {
  int alive, timer, img, x, y;
} spraydrip_type;


/* Globals: */

int use_sound, use_fullscreen, zen, effects_volume, music_volume,
  num_rects, highscore, bomber_x, player, frame, vs_mode, spray_count,
  quick_spray;

#ifdef EMBEDDED
int can_continue;
#endif

int level[2], past_level_8[2], half_level[2],
  old_x[2], one_up_score[2], have_highscore[2];
int bomber_go, bomber_happy, bombs_left, no_active_bombs,
  bomber_xm, bomber_xm_time,
  left_down, right_down, bomber_left_down, bomber_right_down,
  bomber_left_left_down, bomber_right_right_down,
  img, explode_the_bombs, game_over, drop_bomb, num_players;

int x[2], width[2], num_buckets[2], score[2];

char highscorer[13];
SDL_Surface * screen, * zen_background;
SDL_Surface * images[NUM_IMAGES];
SDL_Rect option_box;
SDL_Rect rects[(MAX_BOMBS + MAX_DROPS + 4) * 2 + 128];
bomb_type bombs[MAX_BOMBS];
drop_type drops[MAX_DROPS];
spraydrip_type spraydrips[MAX_SPRAYDRIPS];

#ifndef NOSOUND
Mix_Chunk * sounds[NUM_SOUNDS];
Mix_Music * title_music;
#ifndef EMBEDDED
Mix_Music * highscore_music;
#endif
Mix_Music * game_musics[NUM_GAME_MUSICS];
#endif


/* Local function prototypes: */

int game(int mode);
int title(void);
void setup(void);
void mb_shutdown(void);
int widest(int w1, int w2);
void addrect(SDL_Rect rect);
void addbomb(int x);
void addsplash(int x, int y);
void adddrop(int x, int y, int xm);
void playsound(int snd, int chan);
void drawscore(int score, int player);
int pausescreen(void);
void explodebombs(void);
void erase(SDL_Rect dest);
FILE * open_option_file(char * mode);
#ifdef EMBEDDED
FILE * open_state_file(char * mode);
#endif
int optionscreen(void);
void show_option_img(int horiz, int y, int img);
void show_option_meter(int horiz, int value, int selected);
#ifndef EMBEDDED
void draw_flying_numbers(int number, int scale, int r, int g, int b);
void erase_flying_numbers(int scale);
#endif
int highscorescreen(void);
int spraytext(char * str, int y, int img, int scale);
void sprayline(int x1, int y1, int x2, int y2, int img);
void spraydot(int x, int y, int img);
void handle_spraydrips(void);
void add_spraydrip(int x, int y, int img);
int sign_highscore(int player);
void seticon(void);
void my_blit(SDL_Surface * src_img, SDL_Rect * src_rect,
           SDL_Surface * dest_img, SDL_Rect * dest_rect);
void my_updaterect(SDL_Surface * surf, int x, int y, int w, int h);
void my_fillrect(SDL_Surface * surf, SDL_Rect * dest, Uint32 color);


/* --- MAIN --- */

#ifdef WIN32
main(int argc, char * argv[])
#else
int main(int argc, char * argv[])
#endif
{
  FILE * fi;
  int mode, quit, i;
  char temp[512];
  
  
  /* (Use sound, by default): */
  
  use_sound = 1;
  use_fullscreen = 0;
  
  
  /* Check for arguments: */
  
  if (argc == 2)
    {
      if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
      {
        /* Display help stuff: */
        
        printf("\n"
             "-------------------------------------"
             "------------------------------\n"
             "Mad Bomber version " VERSION "\n"
             "Copyright (C) 1999-2002 by Bill Kendrick, "
             "bill@newbreedsoftware.com\n"
             "-------------------------------------"
             "------------------------------\n"
             "\n"
             "This program is free software; you can redistribute it\n"
             "and/or modify it under the terms of the GNU General Public\n"
             "License as published by the Free Software Foundation;\n"
             "either version 2 of the License, or (at your option) any\n"
             "later version.\n"
             "\n"
             "This program is distributed in the hope that it will be\n"
             "useful and entertaning, but WITHOUT ANY WARRANTY; without\n"
             "even the implied warranty of MERCHANTABILITY or FITNESS\n"
             "FOR A PARTICULAR PURPOSE.  See the GNU General Public\n"
             "License for more details.\n"
             "\n"
             "You should have received a copy of the GNU General Public\n"
             "License along with this program; if not, write to the Free\n"
             "Software Foundation, Inc., 59 Temple Place, Suite 330,\n"
             "Boston, MA  02111-1307  USA\n"
             "\n");
        
        printf("Usage: %s [OPTION]\n\n", argv[0]);
        
        printf("Game options\n"
#ifndef NOSOUND
             "  --disable-sound    Disable sound\n"
#endif
#ifndef EMBEDDED
             "  --fullscreen       (Try to) run in fullscreen\n"
#endif
             "\n"
             "Help options\n"
             "  -?, --help         Show this help message\n"
             "  --usage            Display brief usage message\n"
             "\n"
             "Title screen controls\n"
             "  Up/Down            Choose option\n"
#ifndef EMBEDDED
             "  Space/Return       Activate option\n"
             "  Mouse-click        Activate option under mouse pointer\n"
             "  Escape             Quit program\n"
#else
             "  Selector           Activate option\n"
             "  Stylus-tap         Activate option under stylus\n"
             "  Cancel             Quit program\n"
#endif
             "\n"
             "Option screen controls\n"
             "  Up/Down Arrows     Choose option\n"
#ifndef EMBEDDED
             "  Space/Return       Activate option\n"
             "  Mouse-click        Activate option under mouse pointer\n"
             "  Escape             Return to title screen\n"
#else
             "  Selector           Activate option\n"
             "  Stylus-tap         Activate option under stylus\n"
             "  Cancel             Return to title screen\n"
#endif
             "\n"
             "Game controls\n"
             "  Left/Right Arrows  Move buckets\n"
#ifndef EMBEDDED
             "  Mouse-motion       Move buckets\n"
             "  Space/Return       Fire\n"
             "  Mouse-click        Fire\n"
             "  1/2/3/4            (in Vs. mode) Move Mad Bomber\n"
             "                     (1 = left, fast\n"
             "                      2 = left, slow\n"
             "                      3 = right, slow\n"
             "                      4 = right, fast)\n"
             "  Tab/P              Pause\n"
#else
             "  Stylus-drag        Move buckets\n"
             "  Ok/Selector        Fire\n"
#endif
             "  Escape             Quit game (return to title screen)\n"
             "\n");
        
        exit(0);
      }
      else if (strcmp(argv[1], "--usage") == 0)
      {
        /* Display usage: */
        
        printf("Usage: %s [-?] [--help] [--usage] [--disable-sound] "
             "[--fullscreen]\n",
             argv[0]);
        
        exit(0);
      }
      else if (strcmp(argv[1], "--disable-sound") == 0)
      {
        /* Turn off sound: */
        
        use_sound = 0;
      }
      else if (strcmp(argv[1], "--fullscreen") == 0)
      {
        /* Turn on fullscreen mode: */
        
        use_fullscreen = 1;
      }
      else
      {
        /* Display usage (as an error!): */
        
        fprintf(stderr,
              "Usage: %s [-?] [--help] [--usage] [--disable-sound] "
              "[--fullscreen]\n",
              argv[0]);
        
        exit(1);
      }
    }
  else if (argc > 2)
    { 
      /* Display usage (as an error!): */
      
      fprintf(stderr, "Usage: %s [-?] [--help] [--usage] [--disable-sound] "
            "[--fullscreen]\n",
            argv[0]);
      
      exit(1);
   }
  
  
  /* Set defaults: */
  
  highscore = 500;
  strcpy(highscorer, "LARRY KAPLAN");
  zen = 0;
  width[0] = 2;
  width[1] = 2;
  effects_volume = 7;
  music_volume = 5;
  
  
  /* Load options: */
  
  fi = open_option_file("r");
  
  if (fi != NULL)
    {
      do
      {
        fgets(temp, sizeof(temp), fi);
        
        if (!feof(fi))
          {
            temp[strlen(temp) - 1] = '\0';
            
            
            /* Parse each line: */
            
            if (strstr(temp, "highscore=") == temp)
            {
              highscore = atoi(temp + 10);
              
              if (highscore == 0)
                highscore = 500;
            }
            else if (strstr(temp, "highscorer=") == temp)
            {
              if (strlen(temp) > 11 + sizeof(highscorer))
                temp[11 + sizeof(highscorer)] = '\0';
              
              strcpy(highscorer, temp + 11);
            }
            else if (strstr(temp, "details=") == temp)
            {
              if (strcmp(temp + 8, "zen") == 0)
                zen = 1;
            }
            else if (strstr(temp, "diff1=") == temp)
            {
              if (strcmp(temp + 6, "hard") == 0)
                width[0] = 1;
            }
            else if (strstr(temp, "diff2=") == temp)
            {
              if (strcmp(temp + 6, "hard") == 0)
                width[1] = 1;
            }
            else if (strstr(temp, "effects=") == temp)
            {
              effects_volume = atoi(temp + 8);
              
              if (effects_volume < 0)
                effects_volume = 0;
              else if (effects_volume > 8)
                effects_volume = 8;
            }
            else if (strstr(temp, "music=") == temp)
            {
              music_volume = atoi(temp + 6);
              
              if (music_volume < 0)
                music_volume = 0;
              else if (music_volume > 8)
                music_volume = 8;
            }
          }
      }
      while (!feof(fi));
      
      fclose(fi);
    }



#ifdef EMBEDDED
  /* Load state file: */

  can_continue = 0;

  
  /* Load state: */
  
  fi = open_state_file("r");
  
  if (fi != NULL)
    {
      can_continue = fgetc(fi);

      if (can_continue)
      {
        num_players = fgetc(fi);
        player = fgetc(fi);

        fread(&bomber_x, sizeof(int), 1, fi);

        fread(level, sizeof(int), 2, fi);
        fread(past_level_8, sizeof(int), 2, fi);
        fread(half_level, sizeof(int), 2, fi);
        fread(old_x, sizeof(int), 2, fi);
        fread(one_up_score, sizeof(int), 2, fi);
        fread(have_highscore, sizeof(int), 2, fi);
        fread(&bomber_go, sizeof(int), 1, fi);
        fread(&bomber_happy, sizeof(int), 1, fi);
        fread(&bombs_left, sizeof(int), 1, fi);
        fread(&no_active_bombs, sizeof(int), 1, fi);
        fread(&bomber_xm, sizeof(int), 1, fi);
        fread(&bomber_xm_time, sizeof(int), 1, fi);
        fread(&img, sizeof(int), 1, fi);
        fread(&explode_the_bombs, sizeof(int), 1, fi);
        fread(&drop_bomb, sizeof(int), 1, fi);

        fread(x, sizeof(int), 2, fi);
        fread(width, sizeof(int), 2, fi);
        fread(num_buckets, sizeof(int), 2, fi);
        fread(score, sizeof(int), 2, fi);

        fread(bombs, sizeof(bomb_type), MAX_BOMBS, fi);
        fread(bombs, sizeof(bomb_type), MAX_DROPS, fi);
      }
      
      fclose(fi);
    }

#endif

  
  
  /* Setup: */
  
  setup();
  quit = 0;
  
  
  /* Set volumes: */
  
#ifndef NOSOUND
  if (use_sound)
    {
      Mix_Volume(-1, effects_volume * 16);
      Mix_VolumeMusic(music_volume * 16);
    }
#endif
  
  
  /* MAIN INTERFACE LOOP! */
  
  do
    {
      /* Display title screen: */
      
      mode = title();
      
      
      /* Decide what to based on title screen command: */
      
      if (mode == TITLE_OPTION_ONE_PLAYER ||
        mode == TITLE_OPTION_TWO_PLAYERS ||
#ifndef EMBEDDED
        mode == TITLE_OPTION_TWO_PLAYER_VS)
#else
        (mode == TITLE_OPTION_CONTINUE && can_continue))
#endif
      {
        /* Stop music: */
        
#ifndef NOSOUND
        if (use_sound == 1)
          Mix_HaltMusic();
#endif
        
        quit = game(mode);
      }
      else if (mode == TITLE_OPTION_OPTIONS)
      {
        quit = optionscreen();
      }
      else if (mode == TITLE_OPTION_EXIT)
      {
        quit = 1;
      }
      else if (mode == TITLE_OPTION_HIGHSCORE)
      {
        quit = highscorescreen();
      }
    }
  while (quit == 0);
  
  
  /* Save options: */
  
  fi = open_option_file("w");
  if (fi != NULL)
    {
      /* Comment at the top (I wish _everyone_ did this!) */
      
      fprintf(fi, "# Mad Bomber options file\n\n");
      
      
      /* High score: */
      
      fprintf(fi, "# Highscore:\n\n");
      fprintf(fi, "highscore=%d\n\n", highscore);
      fprintf(fi, "highscorer=%s\n\n\n", highscorer);
      

      /* Background details: */
      
      fprintf(fi,
            "# Set \"details\" to \"zen\" for plain background,\n"
            "# or \"normal\" for photorealistic background.\n\n"
            "# (Default: normal)\n\n");
      
      if (zen == 1)
      fprintf(fi, "details=zen\n\n\n");
      else
      fprintf(fi, "details=normal\n\n\n");
      
      
      /* Difficulty levels: */
      
      fprintf(fi,
            "# Set \"diff#\" to \"hard\" for thin buckets, or\n"
            "# \"normal\" for wide buckets.\n"
            "# Where \"#\" is \"1\" or \"2\", for player one or two.\n\n"
            "# (Default: normal)\n\n");
      
      for (i = 0; i < 2; i++)
      {
        fprintf(fi, "diff%d=", i + 1);
        
        if (width[i] == 1)
          fprintf(fi, "hard\n");
        else
          fprintf(fi, "normal\n");
      }
      
      fprintf(fi, "\n");
      
      
      /* Volume levels: */
      
      fprintf(fi,
            "# Set \"effects\" and \"music\" to a value between 0 and 8.\n"
            "# Where \"0\" is silent and \"8\" is maximum volume (loud).\n"
            "# Where \"effects\" sets sound effects volume, and\n"
            "# where \"music\" sets music volume.\n\n"
            "# (Default: 7 and 5, respectively)\n\n");      
      
      fprintf(fi, "effects=%d\n", effects_volume);
      fprintf(fi, "music=%d\n\n", music_volume);
      
      
      /* The end! */
      
      fprintf(fi, "# (File automatically created.)\n");
      
      fclose(fi);
    }

  
#ifdef EMBEDDED
  /* Save state file: */

  fi = open_state_file("w");
  
  if (fi != NULL)
    {
      fputc(can_continue, fi);

      if (can_continue)
      {
        fputc(num_players, fi);
        fputc(player, fi);

        fwrite(&bomber_x, sizeof(int), 1, fi);

        fwrite(level, sizeof(int), 2, fi);
        fwrite(past_level_8, sizeof(int), 2, fi);
        fwrite(half_level, sizeof(int), 2, fi);
        fwrite(old_x, sizeof(int), 2, fi);
        fwrite(one_up_score, sizeof(int), 2, fi);
        fwrite(have_highscore, sizeof(int), 2, fi);
        fwrite(&bomber_go, sizeof(int), 1, fi);
        fwrite(&bomber_happy, sizeof(int), 1, fi);
        fwrite(&bombs_left, sizeof(int), 1, fi);
        fwrite(&no_active_bombs, sizeof(int), 1, fi);
        fwrite(&bomber_xm, sizeof(int), 1, fi);
        fwrite(&bomber_xm_time, sizeof(int), 1, fi);
        fwrite(&img, sizeof(int), 1, fi);
        fwrite(&explode_the_bombs, sizeof(int), 1, fi);
        fwrite(&drop_bomb, sizeof(int), 1, fi);

        fwrite(x, sizeof(int), 2, fi);
        fwrite(width, sizeof(int), 2, fi);
        fwrite(num_buckets, sizeof(int), 2, fi);
        fwrite(score, sizeof(int), 2, fi);

        fwrite(bombs, sizeof(bomb_type), MAX_BOMBS, fi);
        fwrite(bombs, sizeof(bomb_type), MAX_DROPS, fi);
      }
      
      fclose(fi);
    }

#endif
  
  /* Shut down and quit: */
  
  mb_shutdown();
  
  return(0);
}


/* Game loop: */

int game(int mode)
{
  SDL_Event event;
  SDLKey key;
  int done, quit, i, fire, old_bomber_x;
#ifndef EMBEDDED
  int flying_numbers_scale;
#endif
  SDL_Rect dest;
  Uint32 last_time;
  
 
#ifndef EMBEDDED
  if (mode == TITLE_OPTION_TWO_PLAYER_VS)
    vs_mode = 1;
  else
#endif
    vs_mode = 0;


#ifdef EMBEDDED
  if (mode != TITLE_OPTION_CONTINUE)
  {
    can_continue = 0;
  }
#endif
  
  
  
  /* Draw background screen: */
  
  dest.x = 0;
  dest.y = 0;
  dest.w = 640;
  dest.h = 480;
  erase(dest);
  
 
#ifdef EMBEDDED
  if (can_continue == 0)
  {
#endif

  /* Init. game variables: */
  
  for (i = 0; i < 2; i++)
    {
      score[i] = 0;
      one_up_score[i] = 1000;
      level[i] = 1;
      half_level[i] = 0;
      past_level_8[i] = 0;
      x[i] = 32;
      old_x[i] = 32;
      have_highscore[i] = 0;
    }

  if (mode == TITLE_OPTION_TWO_PLAYERS)
    num_players = 2;
  else
    num_players = 1;
  
  num_buckets[0] = 3;
  if (num_players == 2)
    num_buckets[1] = 3;
  else
    num_buckets[1] = 0;
  
  player = 0;
  
  bomber_x = 640-64;
  old_bomber_x = 640-64;
  bomber_go = 0;
  bomber_happy = 1;
  bombs_left = 0;
  bomber_xm = 0;
  bomber_xm_time = 0;
  explode_the_bombs = 0;
  
  for (i = 0; i < MAX_BOMBS; i++)
    bombs[i].alive = 0;

  for (i = 0; i < MAX_DROPS; i++)
    drops[i].alive = 0;

#ifdef EMBEDDED
  }
#endif
  
  drawscore(score[player], player);
  my_updaterect(screen, 0, 0, 640, 480);
  
  
  /* Main game loop! */
  
  frame = 0;
  key = SDLK_LAST;
  left_down = 0;
  right_down = 0;
  bomber_left_left_down = 0;
  bomber_left_down = 0;
  bomber_right_down = 0;
  bomber_right_right_down = 0;
  drop_bomb = 0;
  done = 0;
  quit = 0;
  game_over = 0;
#ifndef EMBEDDED
  flying_numbers_scale = 1;
#endif


#ifdef EMBEDDED
  can_continue = 1;
#endif
  
  
  do
    {
      num_rects = 0;
      last_time = SDL_GetTicks();
      frame++;
      
      
      /* Get events: */
      
      fire = 0;
      
      while (SDL_PollEvent(&event))
      {
        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;
            }
#ifndef EMBEDDED
            else if (key == SDLK_LEFT)
            left_down = 1;
            else if (key == SDLK_RIGHT)
            right_down = 1;
#else
            else if (key == SDLK_UP)
            left_down = 1;
            else if (key == SDLK_DOWN)
            right_down = 1;
#endif
            else if (key == SDLK_1)
            bomber_left_left_down = 1;
            else if (key == SDLK_2)
            bomber_left_down = 1;
            else if (key == SDLK_3)
            bomber_right_down = 1;
            else if (key == SDLK_4)
            bomber_right_right_down = 1;
            else if (key == SDLK_SPACE || key == SDLK_RETURN)
            fire = 1;
            else if (key == SDLK_TAB || key == SDLK_p)
            {
              /* Tab or P pauses: */
              
              if (game_over == 0)
                {
                  done = pausescreen();
                  
                  if (done == 2)
                  quit = 1;
                  
                  left_down = 0;
                  right_down = 0;
                }
            }
          }
        else if (event.type == SDL_KEYUP)
          {
            /* A key-release (for movement keys): */
            
            key = event.key.keysym.sym;
           
#ifndef EMBEDDED
            if (key == SDLK_LEFT)
            left_down = 0;
            else if (key == SDLK_RIGHT)
            right_down = 0;
#else
            if (key == SDLK_UP)
            left_down = 0;
            else if (key == SDLK_DOWN)
            right_down = 0;
#endif
            else if (key == SDLK_1)
            bomber_left_left_down = 0;
            else if (key == SDLK_2)
            bomber_left_down = 0;
            else if (key == SDLK_3)
            bomber_right_down = 0;
            else if (key == SDLK_4)
            bomber_right_right_down = 0;
          }
        else if (event.type == SDL_MOUSEMOTION)
          {
            /* Mouse movement - move the bucket: */
           
#ifndef EMBEDDED
            x[player] = event.motion.x - (16 * width[player]);
            if (x[player] < 32)
            x[player] = 32;
            else if (x[player] > 608 - (width[player] * 32))
            x[player] = 608 - (width[player] * 32);
#else
            x[player] = event.motion.y * 2 - (16 * width[player]);
            if (x[player] < 32)
            x[player] = 32;
            else if (x[player] > 608 - (width[player] * 32))
            x[player] = 608 - (width[player] * 32);
#endif
          }
        else if (event.type == SDL_MOUSEBUTTONDOWN)
          {
            /* Mouse click - fire! */
            
            fire = 1;
          }
        else if (event.type == SDL_QUIT)
          {
            /* Window close - quit the program completely: */
            
            quit = 1;
          }
      }


      /* Fire button activates the bomber: */
      
      if (fire == 1)
      {
        if (num_buckets[0] != 0 || num_buckets[1] != 0)
          {         
            if (bomber_go == 0 && no_active_bombs == 1)
            {
              /* Decide how many we're to drop this turn: */
              
              bombs_left = bombs_per_level[level[player] - 1];
              drop_bomb = 0;
              
              
              /* (On a half-level?) */
              
              if (half_level[player])
                bombs_left = bombs_left / 2;
              
              half_level[player] = 0;
              
              
              /* Turn on the mad bomber! */
              
              bomber_go = 1;
              frame = 0;
              bomber_happy = 0;

              
              /* Erase the "Press Fire" message: */
              
#ifndef EMBEDDED
              dest.x = (640 - (images[IMG_PRESS_FIRE] -> w)) / 2;
              dest.y = 480 - (images[IMG_PRESS_FIRE] -> h);
              dest.w = images[IMG_PRESS_FIRE] -> w;
              dest.h = images[IMG_PRESS_FIRE] -> h;
#else
              dest.x = (640 - (images[IMG_PRESS_FIRE] -> h * 2)) / 2;
              dest.y = 480 - (images[IMG_PRESS_FIRE] -> w * 2);
              dest.w = images[IMG_PRESS_FIRE] -> h * 2;
              dest.h = images[IMG_PRESS_FIRE] -> w * 2;
#endif
              
              erase(dest);
              addrect(dest);
            }
          }
      }
      
      
      /* Move bucket(s): */
      
      if (left_down == 1 && right_down == 0)
      {
        x[player] = x[player] - 24;
        if (x[player] < 32)
          x[player] = 32;
      }
      else if (right_down == 1 && left_down == 0)
      {
        x[player] = x[player] + 24;
        if (x[player] > 608 - (width[player] * 32))
          x[player] = 608 - (width[player] * 32);
      }
      
      
      /* Move the bomber: */
     
#ifndef EMBEDDED
      if (mode != TITLE_OPTION_TWO_PLAYER_VS)
#endif
      {
        if (bomber_go == 1 && bombs_left > 0)
          {
            bomber_x = bomber_x + bomber_xm;
            
            if (bomber_x < 32)
            {
              bomber_x = 32;
              bomber_xm_time = 0;
            }
            else if (bomber_x > 576)
            {
              bomber_x = 576;
              bomber_xm_time = 0;
            }
            
            bomber_xm_time--;
            if (bomber_xm_time <= 0)
            {
              do
                {
                  bomber_xm = ((rand() % 8) - 4) * (level[player] * 2);
                }
              while (bomber_xm == 0);
              
              bomber_xm_time = (rand() % (level[player] * 10)) + 5;
            }
          }
      }
#ifndef EMBEDDED
      else
      {
        if (bomber_left_left_down == 1)
          bomber_x = bomber_x - 32;
        else if (bomber_left_down == 1)
          bomber_x = bomber_x - 16;
        
        if (bomber_x < 32)
          bomber_x = 32;
        
        if (bomber_right_right_down == 1)
          bomber_x = bomber_x + 32;
        else if (bomber_right_down == 1)
          bomber_x = bomber_x + 16;
        
        if (bomber_x > 576)
          bomber_x = 576;
      }
#endif
      
      
      /* Drop bombs: */
      
      if (bomber_go == 1 && bombs_left > 0)
      {
        if ((frame % (10 - level[player])) == 0)
          {
            if ((level[player] % 2) == 1)
            drop_bomb = 1 - drop_bomb;
            else
            drop_bomb = 1;
            
            if (drop_bomb == 1)
            {
              addbomb(bomber_x);
              bombs_left--;
            }
          }
      }
      
      
      /* Go to next level? */
      
      no_active_bombs = 1;
      for (i = 0; i < MAX_BOMBS; i++)
      {
        if (bombs[i].alive)
          no_active_bombs = 0;
      }
      
      if (bomber_go == 1 && bombs_left == 0 && no_active_bombs == 1)
      {
        bomber_go = 0;
        level[player]++;
        
        if (level[player] > 8)
          {
            level[player] = 8;
            if (past_level_8[player] == 0)
            {
              past_level_8[player] = 1;
              playsound(SND_LEVEL8, 3);
            }
          }
#ifndef EMBEDDED
        else
          {
            flying_numbers_scale = 1;
          }
#endif
      }
      
      
      /* Erase bombs: */
      
      for (i = 0; i < MAX_BOMBS; i++)
      {
        if (bombs[i].alive == 1)
          {
            dest.x = bombs[i].x;
            dest.y = bombs[i].y;
            dest.w = 32;
            dest.h = 32;
            
            erase(dest);
            addrect(dest);
          }
      }


      /* Erase drops: */
      
      for (i = 0; i < MAX_DROPS; i++)
      {
        if (drops[i].alive == 1)
          {
            dest.x = drops[i].x;
            dest.y = drops[i].y;
            dest.w = 8;
            dest.h = 8;
            
            erase(dest);
            addrect(dest);
          }
      }
      
      
      /* Erase bucket(s): */
      
      if (x != old_x)
      {
        dest.x = old_x[player];
        dest.y = 352;
        dest.w = 64;
        dest.h = 96;
        
        erase(dest);
        addrect(dest);
        
        old_x[player] = x[player];
      }
      
      
      /* Erase the mad bomber: */
      
      if (bomber_x != old_bomber_x)
      {
        dest.x = old_bomber_x;
        dest.y = 67;
        dest.w = 32;
        dest.h = 64;
        
        erase(dest);
        addrect(dest);
        
        old_bomber_x = bomber_x;
      }
      

#ifndef EMBEDDED
      /* Erase and resize flying numbers: */
      
      if (flying_numbers_scale != 0 && game_over == 0)
      {
        erase_flying_numbers(flying_numbers_scale);
        
        if (half_level[player] == 0)
          flying_numbers_scale++;
        else
          flying_numbers_scale--;
        
        if (flying_numbers_scale > 20)
          flying_numbers_scale = 0;
      }
#endif
      
      
      /* Move bombs: */
      
      for (i = 0; i < MAX_BOMBS; i++)
      {
        if (bombs[i].alive)
          {
            /* Move bomb downwards: */
            
            bombs[i].y = bombs[i].y + (level[player] + 1) * 2;
            
            
            /* Blow bombs up when they hit bottom! */
            
            if (bombs[i].y >= 416)
            {
              explode_the_bombs = 1;
            }
            
            
            /* Catch bombs: */
            
            if (bombs[i].y >= 336 &&
              bombs[i].y <= 336 + (num_buckets[player] * 32) &&
              bombs[i].x >= x[player] - 32 &&
              bombs[i].x <= x[player] + (32 * width[player]))
            {
              /* Get rid of the bomb: */
              
              bombs[i].alive = 0;
              
              
              /* Make a splash: */
              
              addsplash(bombs[i].x + 16,
                      (((bombs[i].y - 336) / 32) * 32) + 352);
              playsound(SND_SPLASH1 + level[player] - 1, 1);
              
              
              /* Add some score and update the score display: */
              
              score[player] = score[player] + level[player];
              drawscore(score[player], player);
              
              
              /* Did they get a high score? */
              
              if (score[player] >= highscore
#ifndef EMBEDDED
                  && mode != TITLE_OPTION_TWO_PLAYER_VS
#endif
                  )
                {
                  highscore = score[player];
                  
                  
                  /* Did they just get the high score? */
                  
                  if (have_highscore[player] == 0)
                  {
                    have_highscore[player] = 1;
                    playsound(SND_HIGHSCORE, 3);
                  }
                }
              else
                {
                  have_highscore[player] = 0;
                }
              
              
              /* Add a one-up if we hit the 1000 mark! */
              
              if (score[player] >= one_up_score[player])
                {
                  /* Add another bucket! */
                  
                  if (num_buckets[player] < 3)
                  num_buckets[player]++;
                  
                  
                  /* Play a sound: */
                  
                  playsound(SND_ONEUP, 3);
                  
                  
                  /* Set the next higher one-up threshold: */
                  
                  one_up_score[player] = one_up_score[player] + 1000;
                }
            }
          }
      }
      
      
      /* Move drops: */
      
      for (i = 0; i < MAX_DROPS; i++)
      {
        if (drops[i].alive)
          {
            /* Move drops: */
            
            drops[i].x = drops[i].x + drops[i].xm;
            drops[i].y = drops[i].y + drops[i].ym;
            
            
            /* Be influenced by gravity: */
            
            drops[i].ym++;
            
            
            /* Count-down: */
            
            drops[i].timer--;
            
            
            /* Kill drop */
            
            if (drops[i].y >= 440 || drops[i].timer <= 0 ||
              drops[i].x < 32 || drops[i].x >= 600)
            drops[i].alive = 0;
          }
      }
      
      
      /* Draw bucket(s): */
      
      for (i = 0; i < num_buckets[player]; i++)
      {
        dest.x = x[player];
        dest.y = 352 + i * 32;
        dest.w = 32 * width[player];
        dest.h = 32;
        
        my_blit(images[IMG_BUCKET1 + (((frame / 3) + i) % 3) +
              (player * 3) + 12 - (width[player] * 6)],
              NULL, screen, &dest);
        addrect(dest);
      }
      
      
      /* Draw the mad bomber: */
      
      dest.x = bomber_x;
      dest.y = 67;
      dest.w = 32;
      dest.h = 64;
      
      if (score[player] < 10000 || vs_mode == 1)
      my_blit(images[IMG_BOMBER_SAD + bomber_happy],
            NULL, screen, &dest);
      else
      my_blit(images[IMG_BOMBER_AMAZED],
            NULL, screen, &dest);
      addrect(dest);
      
      
      /* Draw a bomb in the bomber's hand: */
      
      if (bomber_happy == 0 && bomber_go == 0)
      {
        dest.x = bomber_x;
        dest.y = 99;
        dest.w = 32;
        dest.h = 32;
        
        my_blit(images[IMG_BOMB0], NULL, screen, &dest);
      }
      
      
      /* Draw bombs: */
      
      for (i = 0; i < MAX_BOMBS; i++)
      {
        if (bombs[i].alive == 1)
          {
            dest.x = bombs[i].x;
            dest.y = bombs[i].y;
            dest.w = 32;
            dest.h = 32;
            
            if (((frame + i) % 2) == 0)
            my_blit(images[IMG_BOMB0], NULL, screen, &dest);
            else
            my_blit(images[IMG_BOMB1 + (rand() % 3)],
                        NULL, screen, &dest);
            
            addrect(dest);
          }
      }
      
      
      /* Draw drops: */
      
      for (i = 0; i < MAX_DROPS; i++)
      {
        if (drops[i].alive == 1)
          {
            dest.x = drops[i].x;
            dest.y = drops[i].y;
            dest.w = 8;
            dest.h = 8;
            
            if (drops[i].xm > 1)
            {
              if (drops[i].ym >= 0)
                img = IMG_DROP_RIGHT_DOWN;
              else
                img = IMG_DROP_RIGHT_UP;
            }
            else if (drops[i].xm < -1)
            {
              if (drops[i].ym >= 0)
                img = IMG_DROP_LEFT_DOWN;
              else
                img = IMG_DROP_LEFT_UP;
            }
            else
            {
              if (drops[i].ym < 0)
                img = IMG_DROP_UP;
              else
                img = IMG_DROP_DOWN;
            }
            
            my_blit(images[img], NULL, screen, &dest);
            addrect(dest);
          }
      }
      
      
      /* If everyone's died, make the bomber happy and show score(s): */
      
      if (num_buckets[0] == 0 && num_buckets[1] == 0)
      {
        /* Display "GAME OVER" text: */
        
        if (game_over == 0)
          {
            game_over = 1;
            bomber_happy = 1;

#ifndef EMBEDDED        
            dest.x = (640 - (images[IMG_GAME_OVER] -> w)) / 2;
            dest.y = (480 - (images[IMG_GAME_OVER] -> h)) / 2;
            dest.w = images[IMG_GAME_OVER] -> w;
            dest.h = images[IMG_GAME_OVER] -> h;
#else
            dest.x = (640 - (images[IMG_GAME_OVER] -> h * 2)) / 2;
            dest.y = (480 - (images[IMG_GAME_OVER] -> w * 2)) / 2;
            dest.w = images[IMG_GAME_OVER] -> h * 2;
            dest.h = images[IMG_GAME_OVER] -> w * 2;
#endif
            
            my_blit(images[IMG_GAME_OVER], NULL, screen, &dest);
            addrect(dest);

#ifdef EMBEDDED
            can_continue = 0;
#endif
          }
        
        
        /* Toggle between player one's and two's scores: */
        
        if (num_players == 2 && (frame % 40) == 0)
          {
            player = 1 - player;
            drawscore(score[player], player);
          }
        
        
        /* Flash "Press ESCAPE" message: */
        
        if ((frame % 30) == 0)
          {
#ifndef EMBEDDED
            dest.x = (640 - (images[IMG_PRESS_ESCAPE] -> w)) / 2;
            dest.y = 480 - (images[IMG_PRESS_ESCAPE] -> h);
            dest.w = images[IMG_PRESS_ESCAPE] -> w;
            dest.h = images[IMG_PRESS_ESCAPE] -> h;
#else
            dest.x = (640 - (images[IMG_PRESS_ESCAPE] -> h * 2)) / 2;
            dest.y = 480 - (images[IMG_PRESS_ESCAPE] -> w * 2);
            dest.w = images[IMG_PRESS_ESCAPE] -> h * 2;
            dest.h = images[IMG_PRESS_ESCAPE] -> w * 2;
#endif
            
            my_blit(images[IMG_PRESS_ESCAPE], NULL, screen, &dest);
            addrect(dest);
          }
        else if ((frame % 15) == 0)
          {
#ifndef EMBEDDED
            dest.x = (640 - (images[IMG_PRESS_ESCAPE] -> w)) / 2;
            dest.y = 480 - (images[IMG_PRESS_ESCAPE] -> h);
            dest.w = images[IMG_PRESS_ESCAPE] -> w;
            dest.h = images[IMG_PRESS_ESCAPE] -> h;
#else
            dest.x = (640 - (images[IMG_PRESS_ESCAPE] -> h * 2)) / 2;
            dest.y = 480 - (images[IMG_PRESS_ESCAPE] -> w * 2);
            dest.w = images[IMG_PRESS_ESCAPE] -> h * 2;
            dest.h = images[IMG_PRESS_ESCAPE] -> w * 2;
#endif
            
            erase(dest);
            addrect(dest);
          }
      }
      

#ifndef EMBEDDED
      /* Draw flying numbers: */
      
      if (flying_numbers_scale != 0 && game_over == 0)
      {
        draw_flying_numbers(level[player] - 1, flying_numbers_scale,
                        (rand() % 128) + 128,   
                        (rand() % 128) + 128,
                        (rand() % 128) + 128);
      }
#endif
      
      
      /* Flash "Press Fire" message: */
      
      if (bomber_go == 0 && (num_buckets[0] != 0 || num_buckets[1] != 0) &&
        no_active_bombs == 1)
      {
        if ((frame % 30) == 0)
          {
#ifndef EMBEDDED
            dest.x = (640 - (images[IMG_PRESS_FIRE] -> w)) / 2;
            dest.y = 480 - (images[IMG_PRESS_FIRE] -> h);
            dest.w = images[IMG_PRESS_FIRE] -> w;
            dest.h = images[IMG_PRESS_FIRE] -> h;
#else
            dest.x = (640 - (images[IMG_PRESS_FIRE] -> h * 2)) / 2;
            dest.y = 480 - (images[IMG_PRESS_FIRE] -> w * 2);
            dest.w = images[IMG_PRESS_FIRE] -> h * 2;
            dest.h = images[IMG_PRESS_FIRE] -> w * 2;
#endif
            
            my_blit(images[IMG_PRESS_FIRE], NULL, screen, &dest);
            addrect(dest);
          }
        else if ((frame % 15) == 0)
          {
#ifndef EMBEDDED
            dest.x = (640 - (images[IMG_PRESS_FIRE] -> w)) / 2;
            dest.y = 480 - (images[IMG_PRESS_FIRE] -> h);
            dest.w = images[IMG_PRESS_FIRE] -> w;
            dest.h = images[IMG_PRESS_FIRE] -> h;
#else
            dest.x = (640 - (images[IMG_PRESS_FIRE] -> h * 2)) / 2;
            dest.y = 480 - (images[IMG_PRESS_FIRE] -> w * 2);
            dest.w = images[IMG_PRESS_FIRE] -> h * 2;
            dest.h = images[IMG_PRESS_FIRE] -> w * 2;
#endif
            
            erase(dest);
            addrect(dest);
          }
      }
      
      
      /* Did the bombs hit the ground? Deal with it! */
      
      if (explode_the_bombs == 1)
      {
        /* Update the screen: */
        
        SDL_UpdateRects(screen, num_rects, rects);
        num_rects = 0;
        
        explode_the_bombs = 0;
        
        
        /* Draw happy bomber: */
        
        dest.x = bomber_x;
        dest.y = 67;
        dest.w = 32;
        dest.h = 64;
        
        if (score[player] < 10000 || vs_mode == 1)
          my_blit(images[IMG_BOMBER_HAPPY], NULL, screen, &dest);
        else
          my_blit(images[IMG_BOMBER_AMAZED], NULL, screen, &dest);
        my_updaterect(screen, dest.x, dest.y, dest.w, dest.h);
        
        
        /* Explode the bombs! */
        
        explodebombs();
        
        
        /* Turn off all bombs: */
        
        for (i = 0; i < MAX_BOMBS; i++)
          bombs[i].alive = 0;
        
        
        /* Turn off the mad bomber: */
        
        bomber_go = 0;
        
        
        /* Jump back a level: */
        
        if (level[player] > 1)
          {
            level[player]--;
            half_level[player] = 1;
#ifndef EMBEDDED
            flying_numbers_scale = 20;
#endif
          }
        
        
        /* Remove a bucket: */
        
        num_buckets[player]--;
        
        
        /* Switch to the other player: */
        
        if (num_players == 2)
          {
            /* If the other player is still alive... */
            
            if (num_buckets[1 - player])
            {
              /* Erase the last player's bucket bucket: */
              
              dest.x = x[player];
              dest.y = 352;
              dest.w = 64;
              dest.h = 96;
              
              erase(dest);
              addrect(dest);
              
              
              /* Switch to the new player: */
              
              player = 1 - player;
              
              
              /* Draw the new player's score: */
              
              drawscore(score[player], player);
            }
          }
      }
      
      
      /* Update the screen: */
      
      SDL_UpdateRects(screen, num_rects, rects);
      
      
#ifndef NOSOUND
      /* Play hissing noise: */
      
      if (use_sound == 1)
      {
        if (no_active_bombs == 0)
          {
            if ((frame % 5) == 0 || Mix_Playing(2) == 0)
            playsound(SND_FUSE, 2);
          }
        else
          {
#ifndef SDL_MIXER_BUG
            if (Mix_Playing(2) != 0)
            Mix_HaltChannel(2);
#endif
          }
      }
      

      /* Keep playing music: */

      if (use_sound == 1)
      {
        if (!Mix_PlayingMusic())
          {
            Mix_PlayMusic(game_musics[rand() % NUM_GAME_MUSICS], 0);
            Mix_VolumeMusic(music_volume * 16);
          }
      }
#endif
      
      /* Pause: */
      
      if (SDL_GetTicks() < last_time + 33)
      SDL_Delay(last_time + 45 - SDL_GetTicks());
    }
  while (done == 0 && quit == 0);
  
  
#ifndef NOSOUND
  /* Stop sound effects: */
  
  if (use_sound == 1)
    Mix_HaltChannel(-1);

  /* Stop music: */
  
  if (use_sound == 1)
    Mix_HaltMusic();
#endif
  
  
  /* Did anyone get the high score? */
  
  if (have_highscore[0])
    quit = sign_highscore(0);
  else if (num_players == 2 && have_highscore[1])
    quit = sign_highscore(1);


#ifndef NOSOUND
  /* Stop sound effects: */
  
  if (use_sound == 1)
    Mix_HaltChannel(-1);

  /* Stop music: */
  
  if (use_sound == 1)
    Mix_HaltMusic();
#endif
  
  return(quit);
}


/* Title loop: */

int title(void)
{
  SDL_Rect dest;
  SDL_Event event;
  SDLKey key;
  int i, y, option, old_option;
  int bx, by;
  int title_option_y[NUM_TITLE_OPTIONS];
  
  
  /* Draw title screen: */
  
#ifndef EMBEDDED
  dest.x = 0;
  dest.y = 0;
  dest.w = 640;
  dest.h = images[IMG_TITLE_TITLE] -> h;
  
  my_blit(images[IMG_TITLE_TITLE], NULL, screen, &dest);
  
  dest.x = 0;
  dest.y = images[IMG_TITLE_TITLE] -> h;
  dest.w = 640;
  dest.h = (480 - (images[IMG_TITLE_TITLE] -> h));
#else  
  dest.x = 0;
  dest.y = 0;
  dest.w = 640;
  dest.h = images[IMG_TITLE_TITLE] -> w * 2;
  
  my_blit(images[IMG_TITLE_TITLE], NULL, screen, &dest);
  
  dest.x = 0;
  dest.y = images[IMG_TITLE_TITLE] -> w * 2;
  dest.w = 640;
  dest.h = (480 - (images[IMG_TITLE_TITLE] -> w * 2));
#endif
  
  my_fillrect(screen, &dest,
            SDL_MapRGB(screen->format, 0x00, 0x00, 0x00));
  
  
  /* Draw controls: */
  
  y = option_box.y + 2;
  
  for (i = 0; i < NUM_TITLE_OPTIONS; i++)
    {
#ifndef EMBEDDED
      dest.x = (640 - (images[title_option_images[i]] -> w)) / 2;
      dest.y = y;
      dest.w = images[title_option_images[i]] -> w;
      dest.h = images[title_option_images[i]] -> h;
#else
      dest.x = (640 - (images[title_option_images[i]] -> h * 2)) / 2;
      dest.y = y;
      dest.w = images[title_option_images[i]] -> h * 2;
      dest.h = images[title_option_images[i]] -> w * 2;
#endif

#ifdef EMBEDDED
      if (can_continue || i != TITLE_OPTION_CONTINUE)
#endif 
        my_blit(images[title_option_images[i] + 1], NULL, screen, &dest);
      
      title_option_y[i] = y;
     
#ifndef EMBEDDED
      y = y + (images[title_option_images[i]] -> h);
#else
      y = y + (images[title_option_images[i]] -> w * 2);
#endif
    }


  my_updaterect(screen, 0, 0, 640, 480);
  
  
  /* Title screen loop: */
  
  option = 0;
  old_option = -1;
  key = SDLK_LAST;
  
  do
    {
      while (SDL_PollEvent(&event))
      {
        if (event.type == SDL_KEYDOWN)
          {
            key = event.key.keysym.sym;
            
#ifndef EMBEDDED
            if (key == SDLK_UP && option > 0)
            option--;
            else if (key == SDLK_DOWN && option < NUM_TITLE_OPTIONS - 1)
            option++;
#else
            if (key == SDLK_RIGHT && option > 0)
            option--;
            else if (key == SDLK_LEFT && option < NUM_TITLE_OPTIONS - 1)
            option++;
#endif
            else if (key == SDLK_ESCAPE)
            option = TITLE_OPTION_EXIT;

#ifdef EMBEDDED
            if (option == TITLE_OPTION_CONTINUE && !can_continue)
            {
            if (key == SDLK_RIGHT)
              option--;
            else if (key == SDLK_LEFT)
                option++;
            }
#endif
          }
        else if (event.type == SDL_MOUSEBUTTONDOWN)
          {
#ifndef EMBEDDED
            bx = event.button.x;
            by = event.button.y;
#else
              bx = event.button.y * 2;
            by = 480 - event.button.x * 2;
#endif

            if (bx >= option_box.x &&
              bx <= option_box.x + option_box.w)
            {
              for (i = 0; i < NUM_TITLE_OPTIONS; i++)
                {
                  if (by >= title_option_y[i] &&
                    (by <=
                     (title_option_y[i] +
#ifndef EMBEDDED
                      images[title_option_images[i]] -> h)))
#else
                      images[title_option_images[i]] -> w * 2)))
#endif
                  {
#ifdef EMBEDDED
                    if (i != TITLE_OPTION_CONTINUE || can_continue)
                    {
#endif
                      option = i;
                      key = SDLK_RETURN;
#ifdef EMBEDDED
                    }
#endif
                  }
                }
            }
          }
        else if (event.type == SDL_QUIT)
          {
            option = TITLE_OPTION_EXIT;
            key = SDLK_ESCAPE;
          }
      }


      /* Update the control box: */
      
      if (old_option != option)
      {
        if (old_option != -1)
          {
            /* Unhighlight the old option: */
            
#ifndef EMBEDDED
            dest.x = (640 -
                  (images[title_option_images[old_option]] -> w)) / 2;
            dest.y = title_option_y[old_option];
            dest.w = images[title_option_images[old_option]] -> w;
            dest.h = images[title_option_images[old_option]] -> h;
#else
            dest.x = ((640 -
                   (images[title_option_images[old_option]] -> h) * 2)
                  / 2);
            dest.y = title_option_y[old_option];
            dest.w = images[title_option_images[old_option]] -> h * 2;
            dest.h = images[title_option_images[old_option]] -> w * 2;
#endif
            
            my_blit(images[title_option_images[old_option] + 1],
                        NULL, screen, &dest);
          }
        
        
        /* Highlight the new option: */
        
#ifndef EMBEDDED
        dest.x = (640 -
                (images[title_option_images[option]] -> w)) / 2;
        dest.y = title_option_y[option];
        dest.w = images[title_option_images[option]] -> w;
        dest.h = images[title_option_images[option]] -> h;
#else
        dest.x = ((640 -
                 (images[title_option_images[option]] -> h) * 2)
                / 2);
        dest.y = title_option_y[option];
        dest.w = images[title_option_images[option]] -> h * 2;
        dest.h = images[title_option_images[option]] -> w * 2;
#endif


        
        my_blit(images[title_option_images[option]],
                    NULL, screen, &dest);
        
        
        /* Update the screen: */
        
        my_updaterect(screen, option_box.x, option_box.y,
                   option_box.w, option_box.h);

        
        if (old_option != -1)
          {
            /* Play selection sound: */
            
            playsound(SND_SELECT, -1);
          }
        

        /* Keep track of old option: */
        
        old_option = option;
      }
      
      
      /* Keep playing music: */
      
#ifndef NOSOUND
      if (use_sound == 1)
      {
        if (!Mix_PlayingMusic())
          {
            Mix_PlayMusic(title_music, 0);
            Mix_VolumeMusic(music_volume * 16);
          }
      }
#endif
      
      
      /* Pause: */
      
      SDL_Delay(50);
    }
  while (key != SDLK_RETURN && key != SDLK_SPACE && key != SDLK_ESCAPE);
  
  
  /* Confirm sound! */
  
  playsound(SND_CONFIRM, -1);
  
  
  return(option);
}


/* Initialize SDL, load graphics and sound: */

void setup(void)
{
  int i;
  SDL_Rect dest;
  SDL_Surface * image;
  
  
  /* Init SDL Video: */
  
  if (SDL_Init(SDL_INIT_VIDEO) < 0)
    {
      fprintf(stderr,
            "\nError: I could not initialize video!\n"
            "The Simple DirectMedia error that occured was:\n"
            "%s\n\n", SDL_GetError());
      exit(1);
    }

  
  /* Init SDL Audio: */
  
  if (use_sound == 1)
    {
      if (SDL_Init(SDL_INIT_AUDIO) < 0)
      {
        fprintf(stderr,
              "\nWarning: I could not initialize audio!\n"
              "The Simple DirectMedia error that occured was:\n"
              "%s\n\n", SDL_GetError());
        use_sound = 0;
      }
    }
  
  
  /* Open sound: */
  
#ifndef NOSOUND
  if (use_sound == 1)
    {
      if (Mix_OpenAudio(22050, AUDIO_S16, 2, 256) < 0)
      {
          fprintf(stderr,
                  "\nWarning: I could not set up audio for 22050 Hz "
              "16-bit stereo.\n"
                  "The Simple DirectMedia error that occured was:\n"
                  "%s\n\n", SDL_GetError());
          use_sound = 0;
        }
    }
#endif
  
  
  /* Open display: */
  
  if (use_fullscreen == 1)
    {
      screen = SDL_SetVideoMode(640, 480, 16, SDL_FULLSCREEN);
      if (screen == NULL)
      {
        fprintf(stderr,
              "\nWarning: I could not set up fullscreen video for "
              "640x480 mode.\n"
              "The Simple DirectMedia error that occured was:\n"
              "%s\n\n", SDL_GetError());
        use_fullscreen = 0;
      }
    }
  
  if (use_fullscreen == 0)
    {
#ifndef EMBEDDED
      screen = SDL_SetVideoMode(640, 480, 16, 0);
      
      if (screen == NULL)
      {
        fprintf(stderr,
              "\nError: I could not set up video for 640x480 mode.\n"
              "The Simple DirectMedia error that occured was:\n"
              "%s\n\n", SDL_GetError());
        exit(1);
      }
#else
      screen = SDL_SetVideoMode(240, 320, 16, 0);
      
      if (screen == NULL)
      {
        fprintf(stderr,
              "\nError: I could not set up video for 240x320 mode.\n"
              "The Simple DirectMedia error that occured was:\n"
              "%s\n\n", SDL_GetError());
        exit(1);
      }
#endif
    }
  
  seticon();
  
  
  /* Set window manager stuff: */
  
  SDL_WM_SetCaption("Mad Bomber", "Mad Bomber");
  /* SDL_ShowCursor(0); */
  
  
  /* Load graphics: */
  
  for (i = 0; i < NUM_IMAGES; i++)
    {
      /* Load image file: */
     
#ifndef EMBEDDED
      image = IMG_Load(image_names[i]);
      
      if (image == NULL)
      {
        fprintf(stderr,
                  "\nError: I couldn't load a graphics file:\n"
                  "%s\n"
                  "The Simple DirectMedia error that occured was:\n"
                  "%s\n\n", image_names[i], SDL_GetError());
          exit(1);
      }
#else
      image = SDL_LoadBMP(image_names[i]);
      
      if (image == NULL)
      {
        fprintf(stderr,
                  "\nError: I couldn't load a graphics file:\n"
                  "%s\n"
                  "The Simple DirectMedia error that occured was:\n"
                  "%s\n\n", image_names[i], SDL_GetError());
          exit(1);
      }
#endif
      
      
      /* Set transparency: */
      
/* #ifndef EMBEDDED */
      images[i] = SDL_DisplayFormat(image);
      if (images[i] == NULL)
      {
        fprintf(stderr,
              "\nError: I couldn't convert a file to the display format:\n"
              "%s\n"
              "The Simple DirectMedia error that occured was:\n"
              "%s\n\n", image_names[i], SDL_GetError());
        exit(1);
      }
/* #endif */
      
      if (SDL_SetColorKey(images[i], (SDL_SRCCOLORKEY | SDL_RLEACCEL),
                    SDL_MapRGB(images[i] -> format,
                             0xFF, 0xFF, 0xFF)) == -1)
      {
        fprintf(stderr,
              "\nError: I could not set the color key for the file:\n"
              "%s\n"
              "The Simple DirectMedia error that occured was:\n"
              "%s\n\n", image_names[i], SDL_GetError());
        exit(1);
      }
     
#ifndef EMBEDDED
      SDL_FreeSurface(image);
#endif
      
      
      /* Show "loading" and percentage bar: */
      
      if (i == IMG_LOADING)
      {
#ifndef EMBEDDED
        dest.x = (640 - (images[IMG_LOADING] -> w)) / 2;
        dest.y = (480 - (images[IMG_LOADING] -> h)) / 2;
        dest.w = images[IMG_LOADING] -> w;
        dest.h = images[IMG_LOADING] -> h;
#else
        dest.x = (640 - (images[IMG_LOADING] -> h * 2)) / 2;
        dest.y = (480 - (images[IMG_LOADING] -> w * 2)) / 2;
        dest.w = images[IMG_LOADING] -> h * 2;
        dest.h = images[IMG_LOADING] -> w * 2;
#endif
        
        my_blit(images[IMG_LOADING], NULL, screen, &dest);
        my_updaterect(screen, dest.x, dest.y, dest.w, dest.h);
      }
      else if (i >= IMG_BAR)
      {
#ifndef EMBEDDED
        dest.x = (((640 - (images[IMG_BAR] -> w)) * i) /
                (NUM_IMAGES + NUM_SOUNDS));
        dest.y = (((480 - (images[IMG_LOADING] -> h)) / 2) +
                (images[IMG_LOADING] -> h));
        dest.w = images[IMG_BAR] -> w;
        dest.h = images[IMG_BAR] -> h;
#else
        dest.x = (((640 - (images[IMG_BAR] -> h * 2)) * i) /
                (NUM_IMAGES + NUM_SOUNDS));
        dest.y = (((480 - (images[IMG_LOADING] -> w * 2)) / 2) +
                (images[IMG_LOADING] -> w * 2));
        dest.w = images[IMG_BAR] -> h * 2;
        dest.h = images[IMG_BAR] -> w * 2;
#endif
        
        my_blit(images[IMG_BAR], NULL, screen, &dest);
        my_updaterect(screen, dest.x, dest.y, dest.w, dest.h);
      }
    }
  
  
  /* Create zen background: */
  
  image = SDL_CreateRGBSurface(SDL_SWSURFACE, 640, 480, 16, 0, 0, 0, 0);
  
  dest.x = 0;
  dest.y = 0;
  dest.w = 640;
  dest.h = 480;
  
  my_fillrect(image, &dest,
             SDL_MapRGB(image->format, 0x00, 0x00, 0x00));

  dest.x = 31;
  dest.y = 39;
  dest.w = 577;
  dest.h = 88;
  
  my_fillrect(image, &dest,
             SDL_MapRGB(image->format, 165, 165, 165));
  
  dest.x = 31;
  dest.y = 127;
  dest.w = 577;
  dest.h = 313;
  
  my_fillrect(image, &dest,
             SDL_MapRGB(image->format, 74, 115, 24));
  
  my_updaterect(image, 0, 0, 640, 480);
  
  zen_background = SDL_DisplayFormat(image);

  
  /* Determine widest title screen option image: */

#ifndef EMBEDDED  
  option_box.w = (widest(images[IMG_TITLE_ONE_PLAYER] -> w,
             widest(images[IMG_TITLE_TWO_PLAYERS] -> w,
            widest(images[IMG_TITLE_TWO_PLAYER_VS] -> w,
             widest(images[IMG_TITLE_OPTIONS] -> w,
            widest(images[IMG_TITLE_HIGHSCORE]->w,
                 images[IMG_TITLE_EXIT]->w)))))
              + 4);

  option_box.h = ((images[IMG_TITLE_ONE_PLAYER] -> h) +
              (images[IMG_TITLE_TWO_PLAYERS] -> h) +
              (images[IMG_TITLE_TWO_PLAYER_VS] -> h) +
              (images[IMG_TITLE_OPTIONS] -> h) +
              (images[IMG_TITLE_HIGHSCORE] -> h) +
              (images[IMG_TITLE_EXIT] -> h));
#else
  option_box.w = (widest(images[IMG_TITLE_ONE_PLAYER] -> h * 2,
             widest(images[IMG_TITLE_TWO_PLAYERS] -> h * 2,
             widest(images[IMG_TITLE_CONTINUE] -> h * 2,
             widest(images[IMG_TITLE_OPTIONS] -> h * 2,
            widest(images[IMG_TITLE_HIGHSCORE]->h * 2,
           images[IMG_TITLE_EXIT]->h * 2))))) + 4);
  
  option_box.h = ((images[IMG_TITLE_ONE_PLAYER] -> w * 2) +
              (images[IMG_TITLE_TWO_PLAYERS] -> w * 2) +
              (images[IMG_TITLE_CONTINUE] -> w * 2) +
              (images[IMG_TITLE_OPTIONS] -> w * 2) +
              (images[IMG_TITLE_HIGHSCORE] -> w * 2) +
              (images[IMG_TITLE_EXIT] -> w * 2));
#endif

  
  option_box.x = (640 - option_box.w) / 2;
  option_box.y = (640 - option_box.h) / 2;
  
  
#ifndef NOSOUND
  /* Load sounds: */
  
  if (use_sound == 1)
    {
      for (i = 0; i < NUM_SOUNDS; i++)
      {
        sounds[i] = Mix_LoadWAV(sound_names[i]);
        if (sounds[i] == NULL)
          {
            fprintf(stderr,
                  "\nError: I could not load the sound file:\n"
                  "%s\n"
                  "The Simple DirectMedia error that occured was:\n"
                  "%s\n\n", sound_names[i], SDL_GetError());
            exit(1);
          }
        
        
        /* Draw percentage bar: */
        
#ifndef EMBEDDED
        dest.x = (((640 - (images[IMG_BAR] -> w)) * (i + NUM_IMAGES)) /
                (NUM_IMAGES + NUM_SOUNDS));
        dest.y = (((480 - (images[IMG_LOADING] -> h)) / 2) +
                (images[IMG_LOADING] -> h));
        dest.w = images[IMG_BAR] -> w;
        dest.h = images[IMG_BAR] -> h;
#else
        dest.x = (((640 - (images[IMG_BAR] -> h * 2)) * (i + NUM_IMAGES)) /
                (NUM_IMAGES + NUM_SOUNDS));
        dest.y = (((480 - (images[IMG_LOADING] -> w * 2)) / 2) +
                (images[IMG_LOADING] -> w * 2));
        dest.w = images[IMG_BAR] -> h * 2;
        dest.h = images[IMG_BAR] -> w * 2;
#endif
        
        my_blit(images[IMG_BAR], NULL, screen, &dest);
        my_updaterect(screen, dest.x, dest.y, dest.w, dest.h);
      }
    }

  
  /* Load music: */
  
  if (use_sound == 1)
    {
      title_music = Mix_LoadMUS(MUS_TITLE);
      if (title_music == NULL)
      {
        fprintf(stderr,
              "\nError: I could not load the music file:\n"
              "%s\n"
              "The Simple DirectMedia error that occured was:\n"
              "%s\n\n", MUS_TITLE, SDL_GetError());
        exit(1);
      }
      
     
#ifndef EMBEDDED
      highscore_music = Mix_LoadMUS(MUS_HIGHSCORE);
      if (highscore_music == NULL)
      {
        fprintf(stderr,
              "\nError: I could not load the music file:\n"
              "%s\n"
              "The Simple DirectMedia error that occured was:\n"
              "%s\n\n", MUS_TITLE, SDL_GetError());
        exit(1);
      }
#endif
      
      
      for (i = 0; i < NUM_GAME_MUSICS; i++)
      {
        game_musics[i] = Mix_LoadMUS(game_music_names[i]);
        if (game_musics[i] == NULL)
          {
            fprintf(stderr,
                  "\nError: I could not load the music file:\n"
                  "%s\n"
                  "The Simple DirectMedia error that occured was:\n"
                  "%s\n\n", game_music_names[i], SDL_GetError());
            exit(1);
          }
      }
    }
#endif


  /* Seed random generator: */
  
  srand(SDL_GetTicks());
  
  
  spray_count = 0;
}


/* Clean up and prepare to quit: */

void mb_shutdown(void)
{
  int i;
  
  /* Not really necessary, but.. I'm nice: */
  
  for (i = 0; i < NUM_IMAGES; i++)
    {
      SDL_FreeSurface(images[i]);
    }
  
  
  /* Close sound: */
  
#ifndef NOSOUND
  if (use_sound == 1)
    Mix_CloseAudio();
#endif
  
  SDL_Quit();
}


/* Of two widths, which is widest? */

int widest(int w1, int w2)
{
  if (w1 > w2)
    return(w1);
  else
    return(w2);
}


/* Add another rectangle: */

void addrect(SDL_Rect rect)
{
#ifndef EMBEDDED
  rects[num_rects].x = rect.x;
  rects[num_rects].y = rect.y;
  rects[num_rects].w = rect.w;
  rects[num_rects].h = rect.h;
#else
  rects[num_rects].x = 240 - rect.y / 2 - rect.h / 2;
  rects[num_rects].y = rect.x / 2;
  rects[num_rects].w = rect.h / 2;
  rects[num_rects].h = rect.w / 2;
#endif

  num_rects++;
}


/* Add a bomb: */

void addbomb(int x)
{
  int i, found;
  
  
  /* Find a free slot: */
  
  found = -1;
  for (i = 0; i < MAX_BOMBS && found == -1; i++)
    {
      if (bombs[i].alive == 0)
      found = i;
    }
  
  
  /* Add a bomb: */
  
  if (found != -1)
    {
      bombs[found].alive = 1;
      bombs[found].x = x;
      bombs[found].y = 96;
    }
}


/* Make a splash (add a bunch of drops): */

void addsplash(int x, int y)
{
  int i, offset;
  
  for (i = 0; i < 8; i++)
    {
      offset = (rand() % 32) - 16;
      
      adddrop(x + offset, y, offset / 6);
    }
}


/* Add one drop: */

void adddrop(int x, int y, int xm)
{
  int i, found;
  
  
  /* Find a free slot: */
  
  found = -1;
  for (i = 0; i < MAX_DROPS && found == -1; i++)
    {
      if (drops[i].alive == 0)
      found = i;
    }
  
  
  /* Add a drop: */
  
  if (found != -1)
    {
      drops[found].alive = 1;
      drops[found].x = x;
      drops[found].y = y;
      drops[found].xm = xm;
      drops[found].ym = -((rand() % 6) + 2);
      drops[found].timer = (rand() % 15) + 30;
    }
}


/* Play a sound file: */

void playsound(int snd, int chan)
{
#ifndef NOSOUND
  if (use_sound == 1)
    {
#ifdef SDL_MIXER_BUG
      chan = -1;
#endif
      Mix_PlayChannel(chan, sounds[snd], 0);
    }
#endif
}


/* Draw score: */

void drawscore(int score, int player)
{
  SDL_Rect dest;
  int i;
  char str[10];
  
  
  /* Erase where the score was: */
  
  dest.x = 416;
  dest.y = 2;
  dest.w = 192;
  dest.h = 32;
  
  erase(dest);
  addrect(dest);

  
  /* Draw the score: */
  
  sprintf(str, "%6d", score);
  
  for (i = 0; i < 6; i++)
    {
      dest.x = 416 + (i * 32);
      dest.y = 2;
      dest.w = 32;
      dest.h = 32;
      
      if (str[i] != ' ')
      {
        my_blit(images[IMG_0 + (str[i] - '0') + (player * 10)],
                    NULL, screen, &dest);
      }
    }
  
  
  /* Draw (or erase) high score message: */

#ifndef EMBEDDED  
  dest.x = 416 - (images[IMG_HIGHSCORE] -> w);
  dest.y = 2;
  dest.w = (images[IMG_HIGHSCORE] -> w);
  dest.h = (images[IMG_HIGHSCORE] -> h);
#else
  dest.x = 416 - (images[IMG_HIGHSCORE] -> h * 2);
  dest.y = 2;
  dest.w = (images[IMG_HIGHSCORE] -> h * 2);
  dest.h = (images[IMG_HIGHSCORE] -> w * 2);
#endif
  
  if (score >= highscore)
    my_blit(images[IMG_HIGHSCORE], NULL, screen, &dest);
  else
    erase(dest);
  
  addrect(dest);
}


/* Pause screen: */

int pausescreen(void)
{
  SDL_Event event;
  SDLKey key;
  SDL_Rect dest;
  int done, quit;
  
  
  /* Stop sound effects: */
  
#ifndef NOSOUND
  if (use_sound == 1)
    Mix_HaltChannel(-1);
#endif
  
  
  /* Draw "PAUSED" message: */

#ifndef EMBEDDED  
  dest.x = (640 - (images[IMG_PAUSED] -> w)) / 2;
  dest.y = (480 - (images[IMG_PAUSED] -> h)) / 2;
  dest.w = images[IMG_PAUSED] -> w;
  dest.h = images[IMG_PAUSED] -> h;
#else
  dest.x = (640 - (images[IMG_PAUSED] -> h * 2)) / 2;
  dest.y = (480 - (images[IMG_PAUSED] -> w * 2)) / 2;
  dest.w = images[IMG_PAUSED] -> h * 2;
  dest.h = images[IMG_PAUSED] -> w * 2;
#endif
  
  my_blit(images[IMG_PAUSED], NULL, screen, &dest);
  my_updaterect(screen, dest.x, dest.y, dest.w, dest.h);
  
  
  /* Pause loop: */
  
  done = 0;
  quit = 0;
  
  do
    {
      /* TAB or "P" key unpause: */
      
      while (SDL_PollEvent(&event))
      {
        if (event.type == SDL_KEYDOWN)
          {
            key = event.key.keysym.sym;
            
            if (key == SDLK_TAB || key == SDLK_p)
            done = 1;
            else if (key == SDLK_ESCAPE)
            {
              done = 1;
              quit = 1;
            }
          }
        else if (event.type == SDL_QUIT)
          {
            done = 1;
            quit = 2;
          }
      }
      
      SDL_Delay(50);


#ifndef NOSOUND
      if (use_sound == 1)
      {
        if (!Mix_PlayingMusic())
          {
            Mix_PlayMusic(game_musics[rand() % NUM_GAME_MUSICS], 0);
            Mix_VolumeMusic(music_volume * 16);
          }
      }
#endif
    }
  while (done == 0);
  
  
  /* Erase "PAUSED" message: */

#ifndef EMBEDDED  
  dest.x = (640 - (images[IMG_PAUSED] -> w)) / 2;
  dest.y = (480 - (images[IMG_PAUSED] -> h)) / 2;
  dest.w = images[IMG_PAUSED] -> w;
  dest.h = images[IMG_PAUSED] -> h;
#else
  dest.x = (640 - (images[IMG_PAUSED] -> h * 2)) / 2;
  dest.y = (480 - (images[IMG_PAUSED] -> w * 2)) / 2;
  dest.w = images[IMG_PAUSED] -> h * 2;
  dest.h = images[IMG_PAUSED] -> w * 2;
#endif
  
  erase(dest);
  my_updaterect(screen, dest.x, dest.y, dest.w, dest.h);
  
  
  /* Return whether or not we ended pause because we're quitting: */

  return(quit);
}


/* Option screen: */

int optionscreen(void)
{
  SDL_Event event;
  SDLKey key;
  SDL_Rect dest;
  int done, quit, which_option, old_which_option;
  int bx, by;
  
  
  /* Erase screen: */
  
  dest.x = 0;
  dest.y = 0;
  dest.w = 640;
  dest.h = 480;
  
  my_fillrect(screen, &dest,
             SDL_MapRGB(screen->format, 0x00, 0x00, 0x00));
  
  
  /* Draw "OPTIONS" title: */

#ifndef EMBEDDED  
  dest.x = (640 - (images[IMG_OPTIONS_OPTIONS] -> w)) / 2;
  dest.y = 0;
  dest.w = images[IMG_OPTIONS_OPTIONS] -> w;
  dest.h = images[IMG_OPTIONS_OPTIONS] -> h;
#else
  dest.x = (640 - (images[IMG_OPTIONS_OPTIONS] -> h * 2)) / 2;
  dest.y = 0;
  dest.w = images[IMG_OPTIONS_OPTIONS] -> h * 2;
  dest.h = images[IMG_OPTIONS_OPTIONS] -> w * 2;
#endif
  my_blit(images[IMG_OPTIONS_OPTIONS], NULL, screen, &dest);
  
  
  /* Draw "Detail": */

  dest.x = 0;
  dest.y = 84;
#ifndef EMBEDDED
  dest.w = images[IMG_OPTIONS_DETAIL] -> w;
  dest.h = images[IMG_OPTIONS_DETAIL] -> h;
#else
  dest.w = images[IMG_OPTIONS_DETAIL] -> h * 2;
  dest.h = images[IMG_OPTIONS_DETAIL] -> w * 2;
#endif
  my_blit(images[IMG_OPTIONS_DETAIL], NULL, screen, &dest);
  
  show_option_img(1, 84, IMG_OPTIONS_NORMAL + zen * 2);
  
  
  /* Draw "Player One" and "Player Two": */

#ifndef EMBEDDED  
  show_option_img(0, 198 - (images[IMG_OPTIONS_PLAYER_ONE] -> h),
              IMG_OPTIONS_PLAYER_ONE);
  show_option_img(1, 198 - (images[IMG_OPTIONS_PLAYER_TWO] -> h),
              IMG_OPTIONS_PLAYER_TWO);
#else
  show_option_img(0, 198 - (images[IMG_OPTIONS_PLAYER_ONE] -> w * 2),
              IMG_OPTIONS_PLAYER_ONE);
  show_option_img(1, 198 - (images[IMG_OPTIONS_PLAYER_TWO] -> w * 2),
              IMG_OPTIONS_PLAYER_TWO);
#endif
  
  
  /* Draw "Difficulty": */
  
  dest.x = 0;
  dest.y = 198;
#ifndef EMBEDDED
  dest.w = images[IMG_OPTIONS_DIFFICULTY] -> w;
  dest.h = images[IMG_OPTIONS_DIFFICULTY] -> h;
#else
  dest.w = images[IMG_OPTIONS_DIFFICULTY] -> h * 2;
  dest.h = images[IMG_OPTIONS_DIFFICULTY] -> w * 2;
#endif
  my_blit(images[IMG_OPTIONS_DIFFICULTY], NULL, screen, &dest);


  /* Draw players' difficulty settings: */
  
  if (width[0] == 1)
    show_option_img(0, 198, IMG_OPTIONS_HARD_OFF);
  else
    show_option_img(0, 198, IMG_OPTIONS_NORMAL_OFF);

  if (width[1] == 1)
    show_option_img(1, 198, IMG_OPTIONS_HARD_OFF);
  else
    show_option_img(1, 198, IMG_OPTIONS_NORMAL_OFF);
  

#ifndef NOSOUND_CONTROLS
  if (use_sound)
    {
      /* Draw "Effects" and "Music": */
      
      show_option_img(0, 312 - (images[IMG_OPTIONS_EFFECTS] -> h),
                  IMG_OPTIONS_EFFECTS);
      show_option_img(1, 312 - (images[IMG_OPTIONS_MUSIC] -> h),
                  IMG_OPTIONS_MUSIC);
      
      
      /* Draw "Volume": */
      
      dest.x = 0;
      dest.y = 312;
      dest.w = images[IMG_OPTIONS_VOLUME] -> w;
      dest.h = images[IMG_OPTIONS_VOLUME] -> h;
      my_blit(images[IMG_OPTIONS_VOLUME], NULL, screen, &dest);
      
      
      /* Draw volume settings: */
      
      show_option_meter(0, effects_volume, 0);
      show_option_meter(1, music_volume, 0);
    }
#endif
  
  
  /* Draw OK button: */

#ifndef EMBEDDED  
  dest.x = (640 - (images[IMG_OPTIONS_OK] -> w)) / 2;
  dest.y = 480 - (images[IMG_OPTIONS_OK] -> h);
  dest.w = images[IMG_OPTIONS_OK] -> w;
  dest.h = images[IMG_OPTIONS_OK] -> h;
#else
  dest.x = (640 - (images[IMG_OPTIONS_OK] -> h * 2)) / 2;
  dest.y = 480 - (images[IMG_OPTIONS_OK] -> w * 2);
  dest.w = images[IMG_OPTIONS_OK] -> h * 2;
  dest.h = images[IMG_OPTIONS_OK] -> w * 2;
#endif
  
  my_blit(images[IMG_OPTIONS_OK_OFF], NULL, screen, &dest);
  

  /* Update screen: */
  
  my_updaterect(screen, 0, 0, 640, 480);
  
  
  /* Pause loop: */
  
  done = 0;
  quit = 0;
  which_option = OPTIONS_OPTION_DETAIL;
  old_which_option = OPTIONS_OPTION_DETAIL;
  
  do
    {
      while (SDL_PollEvent(&event))
      {
        if (event.type == SDL_KEYDOWN)
          {
            key = event.key.keysym.sym;
      
            if (key == SDLK_ESCAPE)
            {
              which_option = OPTIONS_OPTION_OK;
              done = 1;
            }
#ifndef EMBEDDED
            else if (key == SDLK_UP)
#else
            else if (key == SDLK_RIGHT)
#endif
            {
              if (which_option > 0)
                which_option--;


              /* Don't select sound options if we have no sound! */
              
#ifdef NOSOUND_CONTROLS
              if (which_option >= OPTIONS_OPTION_EFFECTS &&
                  which_option != OPTIONS_OPTION_OK)
                which_option = OPTIONS_OPTION_EFFECTS - 1;
#endif
             
              if (use_sound == 0)
                {
                  if (which_option >= OPTIONS_OPTION_EFFECTS &&
                    which_option != OPTIONS_OPTION_OK)
                  which_option = OPTIONS_OPTION_EFFECTS - 1;
                }
            }
#ifndef EMBEDDED
            else if (key == SDLK_DOWN)
#else
            else if (key == SDLK_LEFT)
#endif
            {
              if (which_option < NUM_OPTIONS_OPTIONS - 1)
                which_option++;
              
              
              /* Don't select sound options if we have no sound! */
              
#ifdef NOSOUND_CONTROLS
              if (which_option >= OPTIONS_OPTION_EFFECTS &&
                  which_option != OPTIONS_OPTION_OK)
                which_option = OPTIONS_OPTION_OK;
#endif
              
              if (use_sound == 0)
                {
                  if (which_option >= OPTIONS_OPTION_EFFECTS &&
                    which_option != OPTIONS_OPTION_OK)
                  which_option = OPTIONS_OPTION_OK;
                }
            }
#ifndef EMBEDDED
            else if (key == SDLK_LEFT || key == SDLK_RIGHT ||
#else
            else if (key == SDLK_DOWN || key == SDLK_UP ||
#endif
                   key == SDLK_SPACE || key == SDLK_RETURN)
            {
              /* Any of the keys control toggles: */
              
              if (which_option == OPTIONS_OPTION_DETAIL)
                zen = 1 - zen;
              else if (which_option == OPTIONS_OPTION_PLAYER_ONE)
                width[0] = 3 - width[0];
              else if (which_option == OPTIONS_OPTION_PLAYER_TWO)
                width[1] = 3 - width[1];
              
              
              if (which_option == OPTIONS_OPTION_OK)
                done = 1;
              
#ifndef NOSOUND_CONTROLS
              if (use_sound)
                {
                  if (key == SDLK_LEFT)
                  {
                    /* Left reduces volumes: */
                    
                    if (which_option == OPTIONS_OPTION_EFFECTS)
                      {
                        effects_volume--;
                        if (effects_volume < 0)
                        effects_volume = 0;
                      }
                    else if (which_option == OPTIONS_OPTION_MUSIC)
                      {
                        music_volume--;
                        if (music_volume < 0)
                        music_volume = 0;
                      }
                  }
                  else if (key == SDLK_RIGHT)
                  {
                    /* Right increases volumes: */
                    
                    if (which_option == OPTIONS_OPTION_EFFECTS)
                      {
                        effects_volume++;
                        if (effects_volume > 8)
                        effects_volume = 8;
                      }
                    else if (which_option == OPTIONS_OPTION_MUSIC)
                      {
                        music_volume++;
                        if (music_volume > 8)
                        music_volume = 8;
                      }
                  }
                  
                  
                  /* Adjust sound: */
                  
                  if (which_option == OPTIONS_OPTION_EFFECTS)
                  {
                    Mix_Volume(-1, effects_volume * 16);
                  }
                  else if (which_option == OPTIONS_OPTION_MUSIC)
                  {
                    Mix_VolumeMusic(music_volume * 16);
                  }
                }
#endif

              old_which_option = -1;
            }
          }
        else if (event.type == SDL_MOUSEBUTTONDOWN)
          {
#ifndef EMBEDDED
            bx = event.button.x;
            by = event.button.y;
#else
              bx = event.button.y * 2;
            by = 480 - event.button.x * 2;
#endif
            /* Click - figure out where! */
            
#ifndef EMBEDDED
            if (by >= 84 &&
              by <= 84 + (images[IMG_OPTIONS_NORMAL] -> h) &&
              bx >= 640 - (images[IMG_OPTIONS_NORMAL] -> w))
#else
            if (by >= 84 &&
              by <= 84 + (images[IMG_OPTIONS_NORMAL] -> w * 2) &&
              bx >= 640 - (images[IMG_OPTIONS_NORMAL] -> h * 2))
#endif
            {
              /* Detail: */
              
              zen = 1 - zen;
              
              which_option = OPTIONS_OPTION_DETAIL;
              if (old_which_option == which_option)
                old_which_option = -1;
            }
            else if (by >= 198 &&
#ifndef EMBEDDED
                   by <= (198 + (images[IMG_OPTIONS_NORMAL] -> h)))
#else
                   by <= (198 + (images[IMG_OPTIONS_NORMAL] -> w * 2)))
#endif
            {
              /* Difficulty: */
              
              if (bx >= 220 &&
#ifndef EMBEDDED
                  bx <= (220 + (images[IMG_OPTIONS_NORMAL] -> w)))
#else
                  bx <= (220 + (images[IMG_OPTIONS_NORMAL] -> h * 2)))
#endif
                {
                  /* Player one: */
                  
                  width[0] = 3 - width[0];
                  
                  which_option = OPTIONS_OPTION_PLAYER_ONE;
                  if (old_which_option == which_option)
                  old_which_option = -1;
                }
#ifndef EMBEDDED
              else if (bx >= (640 - (images[IMG_OPTIONS_NORMAL] -> w)))
#else
              else if (bx >= (640 - (images[IMG_OPTIONS_NORMAL] -> h * 2)))
#endif
                {
                  /* Player two: */
                  
                  width[1] = 3 - width[1];
                  
                  which_option = OPTIONS_OPTION_PLAYER_TWO;
                  if (old_which_option == which_option)
                  old_which_option = -1;
                }
            }
#ifndef EMBEDDED
            else if (by >= 480 - (images[IMG_OPTIONS_OK] -> h) &&
                   bx >= (640 - (images[IMG_OPTIONS_OK] -> w)) / 2 &&
                   bx <= ((640 - (images[IMG_OPTIONS_OK] -> w))
                                / 2) + (images[IMG_OPTIONS_OK] -> w))
#else
            else if (by >= 480 - (images[IMG_OPTIONS_OK] -> w * 2) &&
                   bx >= (640 - (images[IMG_OPTIONS_OK] -> h * 2)) / 2 &&
                   bx <= ((640 - (images[IMG_OPTIONS_OK] -> h * 2))
                    / 2) + (images[IMG_OPTIONS_OK] -> h * 2))
#endif
            {
              /* OK button: */
              
              which_option = OPTIONS_OPTION_OK;
              if (old_which_option == which_option)
                old_which_option = -1;
              
              done = 1;
            }
        
        
#ifndef NOSOUND_CONTROLS
            if (use_sound == 1)
            {
              if (event.button.y >= 312 &&
                  event.button.y <= (312 +
                               (images[IMG_OPTIONS_0PERCENT] -> h)))
                {
                  /* Volume controls: */
                  
                  if (event.button.x >= 220 &&
                    event.button.x <= (220 +
                                   ((images[IMG_OPTIONS_0PERCENT] ->
                                     w) * 9)))
                  {
                    /* Effects: */
                    
                    effects_volume = ((event.button.x - 220) /
                                  (images[IMG_OPTIONS_0PERCENT] ->
                                   w));
                    Mix_Volume(-1, effects_volume * 16);
                    
                    which_option = OPTIONS_OPTION_EFFECTS;
                    if (old_which_option == which_option)
                      old_which_option = -1;
                  }
                  else if (event.button.x >= (640 -
                                      ((images[IMG_OPTIONS_0PERCENT]
                                        -> w) * 9)))
                  {
                    /* Music: */
                    
                    music_volume = ((event.button.x - 
                                 (640 - ((images[IMG_OPTIONS_0PERCENT]
                                        -> w) * 9))) /
                                (images[IMG_OPTIONS_0PERCENT] -> w));
                    
                    Mix_VolumeMusic(music_volume * 16);

                    which_option = OPTIONS_OPTION_MUSIC;
                    if (old_which_option == which_option)
                      old_which_option = -1;
                  }
                }
            }
#endif
          }
        else if (event.type == SDL_QUIT)
          {
            done = 1;
            quit = 1;
          }
      }
      
      
      /* Draw a new option? */
      
      if (which_option != old_which_option)
      {
        /* Erase the previously-selected option: */
        
        if (old_which_option == OPTIONS_OPTION_DETAIL)
          show_option_img(1, 84, IMG_OPTIONS_NORMAL_OFF + zen * 2);
        else if (old_which_option == OPTIONS_OPTION_PLAYER_ONE)
          {
            if (width[0] == 1)
            show_option_img(0, 198, IMG_OPTIONS_HARD_OFF);
            else
            show_option_img(0, 198, IMG_OPTIONS_NORMAL_OFF);
          }
        else if (old_which_option == OPTIONS_OPTION_PLAYER_TWO)
          {
            if (width[1] == 1)
            show_option_img(1, 198, IMG_OPTIONS_HARD_OFF);
            else
            show_option_img(1, 198, IMG_OPTIONS_NORMAL_OFF);
          }
        else if (old_which_option == OPTIONS_OPTION_EFFECTS)
          {
            show_option_meter(0, effects_volume, 0);
          }
        else if (old_which_option == OPTIONS_OPTION_MUSIC)
          {
            show_option_meter(1, music_volume, 0);
          }
        else if (old_which_option == OPTIONS_OPTION_OK)
          {
#ifndef EMBEDDED
            dest.x = (640 - (images[IMG_OPTIONS_OK] -> w)) / 2;
            dest.y = 480 - (images[IMG_OPTIONS_OK] -> h);
            dest.w = images[IMG_OPTIONS_OK] -> w;
            dest.h = images[IMG_OPTIONS_OK] -> h;
#else
            dest.x = (640 - (images[IMG_OPTIONS_OK] -> h * 2)) / 2;
            dest.y = 480 - (images[IMG_OPTIONS_OK] -> w * 2);
            dest.w = images[IMG_OPTIONS_OK] -> h * 2;
            dest.h = images[IMG_OPTIONS_OK] -> w * 2;
#endif       
            
            my_blit(images[IMG_OPTIONS_OK_OFF], NULL, screen, &dest);
            my_updaterect(screen, dest.x, dest.y, dest.w, dest.h);
            my_updaterect(screen, 0, 0, 640, 480);
          }
        
        
        /* Draw the newly-selected option: */
        
        if (which_option == OPTIONS_OPTION_DETAIL)
          show_option_img(1, 84, IMG_OPTIONS_NORMAL + zen * 2);
        else if (which_option == OPTIONS_OPTION_PLAYER_ONE)
          {
            if (width[0] == 1)
            show_option_img(0, 198, IMG_OPTIONS_HARD);
            else
            show_option_img(0, 198, IMG_OPTIONS_NORMAL);
          }
        else if (which_option == OPTIONS_OPTION_PLAYER_TWO)
          {
            if (width[1] == 1)
            show_option_img(1, 198, IMG_OPTIONS_HARD);
            else
            show_option_img(1, 198, IMG_OPTIONS_NORMAL);
          }
        else if (which_option == OPTIONS_OPTION_EFFECTS)
          {
            show_option_meter(0, effects_volume, 1);
          }
        else if (which_option == OPTIONS_OPTION_MUSIC)
          {
            show_option_meter(1, music_volume, 1);
          }
        else if (which_option == OPTIONS_OPTION_OK)
          {
#ifndef EMBEDDED
            dest.x = (640 - (images[IMG_OPTIONS_OK] -> w)) / 2;
            dest.y = 480 - (images[IMG_OPTIONS_OK] -> h);
            dest.w = images[IMG_OPTIONS_OK] -> w;
            dest.h = images[IMG_OPTIONS_OK] -> h;
#else
            dest.x = (640 - (images[IMG_OPTIONS_OK] -> h * 2)) / 2;
            dest.y = 480 - (images[IMG_OPTIONS_OK] -> w * 2);
            dest.w = images[IMG_OPTIONS_OK] -> h * 2;
            dest.h = images[IMG_OPTIONS_OK] -> w * 2;
#endif

            my_blit(images[IMG_OPTIONS_OK], NULL, screen, &dest);
            my_updaterect(screen, dest.x, dest.y, dest.w, dest.h);
            my_updaterect(screen, 0, 0, 640, 480);
          }
        
        
        /* Play selection sound: */
        
        playsound(SND_SELECT, -1);
        
        old_which_option = which_option;
      }
      
      
#ifndef NOSOUND
      /* Keep playing music: */
      
      if (use_sound == 1)
      {
        if (!Mix_PlayingMusic())
          {
            Mix_PlayMusic(title_music, 0);
            Mix_VolumeMusic(music_volume * 16);
          }
      }
#endif


      /* Pause: */
      
      SDL_Delay(50);
    }
  while (done == 0);
  
  
  /* Return whether or not we ended pause because we're quitting: */

  return(quit);
}


/* Explode all of the bombs (self-contained animation loop): */

void explodebombs(void)
{
  int i, bottom_most, lowest;
  SDL_Rect dest;
  
  
  /* Explode each bomb, one at a time: */
  
  do
    {
      /* Find the bottom-most bomb: */
      
      bottom_most = -1;
      lowest = 0;
      
      for (i = 0; i < MAX_BOMBS; i++)
      {
        if (bombs[i].alive == 1)
          {
            if (bombs[i].y > lowest)
            {
              lowest = bombs[i].y;
              bottom_most = i;
            }
          }
      }
      
      
      /* Explode it! */
      
      if (bottom_most != -1)
      {
        /* Turn the bomb off: */
        
        bombs[bottom_most].alive = 0;
        
        
        /* Play an explosion sound: */
        
        playsound(SND_EXPLOSION, 1);
        
        
        /* Draw the explosion animation: */
        
        for (i = 0; i < 4; i++)
          {
            dest.x = bombs[bottom_most].x;
            dest.y = bombs[bottom_most].y;
            dest.w = 32;
            dest.h = 32;
            
            my_blit(images[IMG_EXPLOSION1 + (i % 2)],
                        NULL, screen, &dest);
            my_updaterect(screen, dest.x, dest.y, dest.w, dest.h);
            
            SDL_Delay(30);
          }
        
        
        /* Erase the explosion animation: */
        
        dest.x = bombs[bottom_most].x;
        dest.y = bombs[bottom_most].y;
        dest.w = 32;
        dest.h = 32;
        
        erase(dest);
        my_updaterect(screen, dest.x, dest.y, dest.w, dest.h);
        
        
        /* Make sure the bomber doesn't get cropped: */
        
        dest.x = bomber_x;
        dest.y = 67;
        dest.w = 32;
        dest.h = 64;
        
        if (score[player] < 10000 || vs_mode == 1)
          my_blit(images[IMG_BOMBER_HAPPY],
                      NULL, screen, &dest);
        else
          my_blit(images[IMG_BOMBER_AMAZED],
                      NULL, screen, &dest);
        my_updaterect(screen, dest.x, dest.y, dest.w, dest.h);


        /* Make sure the buckets don't get cropped: */
        
        for (i = 0; i < num_buckets[player]; i++)
          {
            dest.x = x[player];
            dest.y = 352 + i * 32;
            dest.w = 32 * width[player];
            dest.h = 32;
            
            my_blit(images[IMG_BUCKET1 + (((frame / 3) + i) % 3) +
                            (player * 3) + 12 - (width[player] * 6)],
                        NULL, screen, &dest);
            my_updaterect(screen, dest.x, dest.y, dest.w, dest.h);
          }
      }
    }
  while (bottom_most != -1);


  /* Play a BIG explosion sound: */
  
  playsound(SND_BIGEXPLOSION, 1);
  
  
  /* Flash screen: */

  dest.x = 0;
  dest.y = 0;
  dest.w = 640;
  dest.h = 480;
  
  
  /* (draw white) */
  
  my_fillrect(screen, &dest,
             SDL_MapRGB(screen->format, 0xFF, 0xFF, 0xFF));
  my_updaterect(screen, 0, 0, 640, 480);
  
  
  /* (wait a brief moment) */
  
  SDL_Delay(50);
  
  
  /* (return to normal) */
  
  /* ((redraw background)) */
  
  erase(dest);
  
  
  /* ((redraw bomber)) */
  
  dest.x = bomber_x;
  dest.y = 67;
  dest.w = 32;
  dest.h = 64;
  
  if (score[player] < 10000 || vs_mode == 1)
    my_blit(images[IMG_BOMBER_HAPPY],
                NULL, screen, &dest);
  else
    my_blit(images[IMG_BOMBER_AMAZED],
                NULL, screen, &dest);
  

  /* ((redraw buckets)) */
  
  for (i = 0; i < num_buckets[player] - 1; i++)
    {
      dest.x = x[player];
      dest.y = 352 + i * 32;
      dest.w = 32 * width[player];
      dest.h = 32;
      
      my_blit(images[IMG_BUCKET1 + (((frame / 3) + i) % 3) +
                      (player * 3) + 12 - (width[player] * 6)],
                  NULL, screen, &dest);
    }
  
  
  /* ((redraw score)) */

  drawscore(score[player], player);
  
  
  /* ((update it all)) */
  
  my_updaterect(screen, 0, 0, 640, 480);
  
  
#ifndef NOSOUND
  if (use_sound == 1)
    {
      do
      {
        /* Wait... */
        SDL_Delay(30);
      }
      while (Mix_Playing(1));
    }
#endif
}


/* Erase part of the screen back to the background: */

void erase(SDL_Rect dest)
{
  /* Copy the background bitmap onto the screen: */
  
  if (zen == 0)
    {
      my_blit(images[IMG_BACKGROUND],
            &dest, screen, &dest);
    }
  else
    {
      my_blit(zen_background, &dest, screen, &dest);
    }
}


/* Open the option file: */

FILE * open_option_file(char * mode)
{
  char * filename, * home;
  FILE * fi;
  
  
#ifndef WIN32
  /* Get home directory (from $HOME variable)... if we can't determine it,
     use the current directory ("."): */

  if (getenv("HOME") != NULL)
    home = getenv("HOME");
  else
    home = ".";
  
  
  /* Create the buffer for the filename: */
  
  filename = (char *) malloc(sizeof(char) * (strlen(home) +
                                   strlen("/.madbomber") + 1));
  
  strcpy(filename, home);
  strcat(filename, "/.madbomber");
#else
  filename = "madbomber.dat";
#endif
  
  
  /* Try opening the file: */
  
  fi = fopen(filename, mode);
  
  if (fi == NULL)
    {
      fprintf(stderr, "\nWarning: I could not open the options file "); 
      
      if (strcmp(mode, "r") == 0)
      fprintf(stderr, "for read:");
      else if (strcmp(mode, "w") == 0)
      fprintf(stderr, "for write:");
      
     fprintf(stderr, "\n%s\n"
            "The error that occured was:\n"
            "%s\n\n", filename, strerror(errno));
    }
  
  return(fi);
}


#ifdef EMBEDDED
/* Open the state file: */

FILE * open_state_file(char * mode)
{
  char * filename, * home;
  FILE * fi;
  
  
  /* Get home directory (from $HOME variable)... if we can't determine it,
     use the current directory ("."): */

  if (getenv("HOME") != NULL)
    home = getenv("HOME");
  else
    home = ".";
  
  
  /* Create the buffer for the filename: */
  
  filename = (char *) malloc(sizeof(char) * (strlen(home) +
                                   strlen("/.madbomber-state") + 1));
  
  strcpy(filename, home);
  strcat(filename, "/.madbomber-state");
  
  
  /* Try opening the file: */
  
  fi = fopen(filename, mode);
  
  if (fi == NULL)
    {
      fprintf(stderr, "\nWarning: I could not open the state file "); 
      
      if (strcmp(mode, "r") == 0)
      fprintf(stderr, "for read:");
      else if (strcmp(mode, "w") == 0)
      fprintf(stderr, "for write:");
      
     fprintf(stderr, "\n%s\n"
            "The error that occured was:\n"
            "%s\n\n", filename, strerror(errno));
    }
  
  return(fi);
}

#endif



/* Show an option image: */

void show_option_img(int horiz, int y, int img)
{
  SDL_Rect dest;
  
  
  /* Determine horizontal location: */
  
  if (horiz == 0)
    dest.x = 220;
  else
#ifndef EMBEDDED
    dest.x = 640 - (images[img] -> w);
#else
    dest.x = 640 - (images[img] -> h * 2);
#endif
  
  dest.y = y;
#ifndef EMBEDDED
  dest.w = images[img] -> w;
  dest.h = images[img] -> h;
#else
  dest.w = images[img] -> h * 2;
  dest.h = images[img] -> w * 2;
#endif
  
  
  /* Draw or erase the spot: */
  
  my_blit(images[img], NULL, screen, &dest);
  my_updaterect(screen, dest.x, dest.y, dest.w, dest.h);
}


/* Display a volume meter: */

void show_option_meter(int horiz, int value, int selected)
{
  int img, i, x;
  SDL_Rect dest;
  
  
  /* Determine horizontal location: */
  
  if (horiz == 0)
    x = 220;
  else
    x = 640 - ((images[IMG_OPTIONS_0PERCENT] -> w) * 9);

  
  /* Erase meter: */
  
  dest.x = x;
  dest.y = 312;
  dest.w = (images[IMG_OPTIONS_0PERCENT] -> w) * 9;
  dest.h = images[IMG_OPTIONS_0PERCENT] -> h;
  
  my_fillrect(screen, &dest,
             SDL_MapRGB(screen->format, 0x00, 0x00, 0x00));
  
  
  /* Draw the meter: */
  
  for (i = 0; i <= value; i++)
    {
      img = IMG_OPTIONS_0PERCENT + ((i / 2) * 2) + (1 - selected);
      
      dest.x = x + i * (images[IMG_OPTIONS_0PERCENT] -> w);
      dest.y = 312;
      dest.w = images[IMG_OPTIONS_0PERCENT] -> w;
      dest.h = images[IMG_OPTIONS_0PERCENT] -> h;
      
      my_blit(images[img], NULL, screen, &dest);
    }
  
  
  /* Update the screen: */
  
  my_updaterect(screen, x, 312,
             (images[IMG_OPTIONS_0PERCENT] -> w) * 9,
             images[IMG_OPTIONS_0PERCENT] -> h);
}


#ifndef EMBEDDED

/* Draw flying numbers on the screen: */

void draw_flying_numbers(int number, int scale, int r, int g, int b)
{
  SDL_Rect dest;
  int i;
  
  for (i = 0; i < 7; i++)
    {
      /* If this "light" of the LED is on, then draw it: */
      
      if (flying_number_layouts[number][i])
      {
        /* Determine where the "light" is: */
        
        if (i == 0 || i == 1 || i == 3 || i == 4 || i == 6)
          dest.x = 320 + (-scale * 5);
        else
          dest.x = 320 + (scale * 5);
        
        if (i == 0 || i == 1 || i == 2)
          dest.y = 240 + (-scale * 10);
        else if (i == 3 || i == 4 || i == 5)
          dest.y = 240;
        else if (i == 6)
          dest.y = 240 + (scale * 10);
        
        
        /* ...And what shape it is: */
        
        if (i == 0 || i == 3 || i == 6)
          {
            dest.w = scale * 8;
            dest.h = scale * 2;
          }
        else
          {
            dest.w = scale * 2;
            dest.h = scale * 8;
          }
        
        
        /* Draw it: */
        
        my_fillrect(screen, &dest,
                   SDL_MapRGB(screen->format, r, g, b));
        addrect(dest);
      }
    }
}


/* Erase flying numbers: */

void erase_flying_numbers(int scale)
{
  SDL_Rect dest;
  
  dest.x = 320 + (-scale * 5);
  dest.y = 240 + (-scale * 10);
  dest.w = scale * 15;
  dest.h = scale * 22;
  
  erase(dest);
  addrect(dest);
}

#endif


/* High Score Screen: */

int highscorescreen(void)
{
  int done, i, img, y;
  char temp[10];
  SDL_Event event;
  SDLKey key;
  SDL_Rect src, dest;
  
  
  /* Draw game background: */
  
  my_blit(images[IMG_BACKGROUND], NULL, screen, NULL);
  my_updaterect(screen, 0, 0, 640, 480);
  
  
  /* Clear all spray drips: */
  
  for (i = 0; i < MAX_SPRAYDRIPS; i++)
    {
      spraydrips[i].alive = 0;
    }
  
  
  /* Draw text onto it: */
  
  quick_spray = 0;
  
  done = spraytext("HIGH SCORE", 175, IMG_SPRAY_CYAN, 5);
  
  if (done == 0)
    done = spraytext(highscorer, 225, IMG_SPRAY_BLACK, 7);
  
  if (done == 0)
    {
      sprintf(temp, "%d", highscore);
      done = spraytext(temp, 300, IMG_SPRAY_BLUE, 7);
    }
  
  
  /* Which bomber will we draw? */
  
  if (highscore >= 10000)
    img = IMG_BOMBER_AMAZED;
  else if (highscore > 5000)
    img = IMG_BOMBER_SAD;
  else
    img = IMG_BOMBER_HAPPY;
  
  y = 0;
  
  
  if (done == 0)
    {  
      do
      {
        /* Handle events: */
        
        while (SDL_PollEvent(&event))
          {
            if (event.type == SDL_KEYDOWN)
            {
              key = event.key.keysym.sym;
              
              if (key == SDLK_ESCAPE)
                done = 1;
            }
            else if (event.type == SDL_QUIT)
            done = 2;
            else if (event.type == SDL_MOUSEBUTTONDOWN)
            done = 1;
          }
        
        
        /* Handle spray drips: */
        
        handle_spraydrips();
        
        
        /* Draw bomber: */
        
        if (y < 64)
          {
            y++;
       
#ifndef EMBEDDED
            src.x = 0;
            src.y = 0;
            src.w = 32;
            src.h = y;
            
            dest.x = 500;
            if (y < 61)
            dest.y = 126 - y;
            else
            dest.y = 67;
            
            dest.w = 32;
            dest.h = y;
            
            
            my_blit(images[IMG_BACKGROUND], &dest, screen, &dest);
            my_blit(images[img], &src, screen, &dest);
            my_updaterect(screen, dest.x, dest.y, dest.w, dest.h);
#else
            src.x = 32 - (y / 2);
            src.y = 0;
            src.w = y / 2;
            src.h = 32;

            if (y < 61)
              dest.x = 240 - 63;
            else
            dest.x = 240 - 64;
            dest.y = 250;
            
            dest.w = y / 2;
            dest.h = 32;


            SDL_BlitSurface(images[IMG_BACKGROUND], &dest, screen, &dest);
            SDL_BlitSurface(images[img], &src, screen, &dest);
            SDL_UpdateRect(screen, dest.x, dest.y, dest.w, dest.h);
#endif
          }
        

#ifndef NOSOUND
        /* Keep playing music: */
        
        if (use_sound == 1)
          {
            if (!Mix_PlayingMusic())
            {
              Mix_PlayMusic(title_music, 0);
              Mix_VolumeMusic(music_volume * 16);
            }
          }
#endif
        
        
        SDL_Delay(33);
      }
      while (done == 0);
    }
  
  
  /* Return whether or not we're done because the user requested a quit: */
  
  if (done == 0 || done == 1)
    return(0);
  else
    return(1);
}


/* Animate spraying of text onto the screen: */

int spraytext(char * str, int y, int img, int scale)
{
  int ltr, line, c, x, z;
  SDL_Event event;
  SDLKey key;
  
  
  /* Play shaking-can noise: */
  
#ifndef NOSOUND
  if (use_sound == 1)
    {
      if (quick_spray == 0)
      {
        playsound(SND_CAN_SHAKE, 2);
        
        do
          {
            SDL_Delay(100);
          }
        while (Mix_Playing(2));
      }
    }
#endif
  
  
  /* Place our virtual cursor (we want each line centered): */
  
  x = (640 - (strlen(str) * (scale * 6))) / 2;
  
  
  /* Draw each letter: */
  
  for (ltr = 0; ltr < strlen(str); ltr++)
    {
      c = str[ltr];
      
      
      /* Where in our graffiti array is this particular character? */
      
      if (c >= 'A' && c <= 'Z')
      c = c - 'A' + 10;
      else if (c >= '0' && c <= '9')
      c = c - '0';
      else
      c = -1;
      
      
      /* If it's a valid character, draw it! */
      
      if (c != -1)
      {
        for (line = 0; line < 5 && graffiti[c][line][0][0] != -1; line++)
          {
            z = rand() % 6;
            
            sprayline(graffiti[c][line][0][0] * scale + x,
                  graffiti[c][line][0][1] * scale + y + z,
                  graffiti[c][line][1][0] * scale + x,
                  graffiti[c][line][1][1] * scale + y + z, img);
          }
      }
      
      
      /* Move the virtual cursor over one character: */
      
      x = x + (scale * 6);
    
#ifndef EMBEDDED
      SDL_Delay(30);
#endif
      
      
      /* Handle events: */
      
      while (SDL_PollEvent(&event))
      {
        if (event.type == SDL_KEYDOWN)
          {
            key = event.key.keysym.sym;
            
            if (key == SDLK_ESCAPE)
            return(1);
            else
            quick_spray = 1;
          }
        else if (event.type == SDL_QUIT)
          return(2);
        else if (event.type == SDL_MOUSEBUTTONDOWN)
          quick_spray = 1;
      }
    }
  
  SDL_Delay(100);
  
#ifndef NOSOUND
#ifndef SDL_MIXER_BUG
  if (use_sound == 1)
    Mix_HaltChannel(2);
#endif
#endif
  
  return(0);
}


/* Draw a line with spray paint: */

void sprayline(int x1, int y1, int x2, int y2, int img)
{
  int x, y, z, steep, e, dx, dy, i;
  
  
  /* Play spraying noise: */
  
#ifndef NOSOUND
  if (use_sound == 1)
    {
      if (quick_spray == 0)
      {
        if (!Mix_Playing(2))
          playsound(SND_SPRAY, 2);
      }
    }
#endif
  
  
  /* Draw the line: */
  
  if (x1 == x2)
    {
      /* Vertical line: */
      
      if (y1 > y2)
      {
        z = y1;
        y1 = y2;
        y2 = z;
      }
      
      for (y = y1; y <= y2; y++)
      spraydot(x1, y, img);
    }
  else if (y1 == y2)
    {
      /* Horizontal line: */
      
      if (x1 > x2)
      {
        z = x1;
        x1 = x2;
        x2 = z;
      }
      
      for (x = x1; x <= x2; x++)
      spraydot(x, y1, img);
    }
  else
    {
      /* Angled line: */
      
      steep = 0;
      
      dx = abs(x2 - x1);
      x = ((x2 - x1) > 0) ? 1 : -1;
      
      dy = abs(y2 - y1);
      y = ((y2 - y1) > 0) ? 1 : -1;
      
      
      if (dy > dx)
      {
        steep = 1;
        
        z = x1;
        x1 = y1;
        y1 = z;
        
        z = dy;
        dy = dx;
        dx = z;
        
        z = y;
        y = x;
        x = z;
      }
      
      e = 2 * dy - dx;
      
      for (i = 0; i < dx; i++)
      {
        if (steep == 1)
          spraydot(y1, x1, img);
        else
          spraydot(x1, y1, img);
        
        while (e >= 0)
          {
            y1 = y1 + y;
            e = e - 2 * dx;
          }
        
        x1 = x1 + x;
        e = e + 2 * dy;
      }
      
      spraydot(x2, y2, img);
    }

#ifdef EMBEDDED
  SDL_Flip(screen);
#endif
}


/* Spray one dot: */

void spraydot(int x, int y, int img)
{
  SDL_Rect src, dest;
  
  
  /* Pick a semi-random spot with a random spray bit: */
 
#ifndef EMBEDDED
  dest.x = x + (rand() % 3);
  dest.y = y + (rand() % 4);
  dest.w = 4;
  dest.h = 4;
  
  src.x = (rand() % ((images[img] -> w) - 4));
  src.y = (rand() % ((images[img] -> h) - 4));
  src.w = 4;
  src.h = 4;
 
  
  /* Draw it: */
  
  my_blit(images[img], &src, screen, &dest);
  
  my_updaterect(screen, dest.x, dest.y, dest.w, dest.h);
#else
  dest.x = 240 - y / 2 - 2;
  dest.y = x / 2;
  dest.w = 2;
  dest.h = 2;

  src.x = (rand() % 6);
  src.y = (rand() % 6);
  src.w = 2;
  src.h = 2;


  SDL_BlitSurface(images[img], &src, screen, &dest);
  /* SDL_UpdateRect(screen, dest.x, dest.y, dest.w, dest.h); */
#endif
  
  
  /* Pause: */
  
  spray_count = spray_count++;
  
  if ((spray_count % 3) == 0 && quick_spray == 0)
    SDL_Delay(10);
  
  
  /* Make a drip: */
  
  if ((rand() % 10) == 0)
    {
#ifndef EMBEDDED
      add_spraydrip(dest.x, dest.y, img);
#else
      add_spraydrip(x, y, img);
#endif
    }

  
  /* Handle spray drips: */
  
  handle_spraydrips();
}


void handle_spraydrips(void)
{
  int i;
  SDL_Rect src, dest;
  
  
  for (i = 0; i < MAX_SPRAYDRIPS; i++)
    {
      if (spraydrips[i].alive)
      {
        /* Move drip: */
        
        spraydrips[i].y++;
        
        
        /* Make drip run out of time: */
        
        spraydrips[i].timer--;
        
        if (spraydrips[i].timer <= 0)
          spraydrips[i].alive = 0;
        
        
        /* Draw spraydrip: */
        
#ifndef EMBEDDED
        src.x = (rand() % ((images[spraydrips[i].img] -> w) - 2));
        src.y = (rand() % ((images[spraydrips[i].img] -> h) - 2));
        src.w = 2;
        src.h = 2;
        
        dest.x = spraydrips[i].x;
        dest.y = spraydrips[i].y;
        dest.w = 2;
        dest.h = 2;
        
        my_blit(images[spraydrips[i].img], &src, screen, &dest);
        my_updaterect(screen, dest.x, dest.y, dest.w, dest.h);
#else
        dest.x = 240 - spraydrips[i].y / 2 - 1;
        dest.y = spraydrips[i].x / 2;
        dest.w = 1;
        dest.h = 1;

        src.x = (rand() % 6);
        src.y = (rand() % 6);
        src.w = 1;
        src.h = 1;


        SDL_BlitSurface(images[spraydrips[i].img], &src, screen, &dest);
/*      SDL_UpdateRect(screen, dest.x, dest.y, dest.w, dest.h); */
#endif
      }
    }
}


/* Turn a spraydrip on: */

void add_spraydrip(int x, int y, int img)
{
  int found;
  
  found = (rand() % MAX_SPRAYDRIPS);
  
  spraydrips[found].alive = 1;
  spraydrips[found].timer = (rand() % 10) + 5;
  spraydrips[found].img = img;
  spraydrips[found].x = x;
  spraydrips[found].y = y;
}


/* Have player sign their name for a high score: */

int sign_highscore(int player)
{
  SDL_Rect src, dest;
  int done, l, draw_text, i;
  SDL_Event event;
  SDLKey key;
  
  
  /* Draw high score signature screen: */
  
  dest.x = 0;
  dest.y = 0;
  dest.w = 640;
  dest.h = 480;
  
  my_fillrect(screen, &dest,
             SDL_MapRGB(screen->format, 0, 0, 0));
  
  
  dest.x = 0;
  dest.y = 0;
  dest.w = 640;
#ifndef EMBEDDED
  dest.h = images[IMG_HIGHSCORE_HIGHSCORE] -> h;
#else
  dest.h = images[IMG_HIGHSCORE_HIGHSCORE] -> w * 2;
#endif
  
  my_blit(images[IMG_HIGHSCORE_HIGHSCORE], NULL, screen, &dest);
  
  my_updaterect(screen, 0, 0, 640, 480);
  
  strcpy(highscorer, "");
  l = 0;
  
  done = 0;
  draw_text = 1;
  
  do
    {
      /* Handle events: */
      
      while (SDL_PollEvent(&event))
      {
        if (event.type == SDL_KEYDOWN)
          {
            key = event.key.keysym.sym;
            
            if (key == SDLK_ESCAPE)
            return(0);
            else if (key == SDLK_DELETE || key == SDLK_BACKSPACE)
            {
              if (l > 0)
                {
                  l--;
                  highscorer[l] = '\0';
                  
                  draw_text = 1;
                  playsound(SND_CONFIRM, 0);
                }
            }
            else if ((key >= SDLK_a && key <= SDLK_z) ||
                   (key >= SDLK_0 && key <= SDLK_9) ||
                   key == SDLK_SPACE)
            {
              if (l < sizeof (highscorer))
                {
                  if (key >= SDLK_a && key <= SDLK_z)
                  key = key - SDLK_a + 'A';
                  
                  highscorer[l] = key;
                  l++;
                  highscorer[l] = '\0';
                  
                  draw_text = 1;
                  playsound(SND_SELECT, 0);
                }
            }
            else if (key == SDLK_RETURN)
            {
              done = 1;
              playsound(SND_EXPLOSION, 0);
            }
          }
        else if (event.type == SDL_QUIT)
          return(2);
      }
      
      
      /* Draw text? */
      
      if (draw_text == 1)
      {
        /* Erase first: */
        
        dest.x = 0;
        dest.y = 200;
        dest.w = 640;
#ifndef EMBEDDED
        dest.h = images[IMG_HIGHSCORE_LETTERS] -> h;
#else
        dest.h = images[IMG_HIGHSCORE_LETTERS] -> w * 2;
#endif
        
        my_fillrect(screen, &dest,
                   SDL_MapRGB(screen->format, 0, 0, 0));
        
        
        /* Now draw each letter: */
        
        for (i = 0; i < strlen(highscorer); i++)
          {
            if (highscorer[i] != ' ')
            {
#ifndef EMBEDDED
              if (highscorer[i] >= '0' && highscorer[i] <= '9')
                src.x = ((highscorer[i] - '0') *
                       (images[IMG_HIGHSCORE_LETTERS] -> w) / 36);
              else if (highscorer[i] >= 'A' && highscorer[i] <= 'Z')
                src.x = ((highscorer[i] - 'A' + 10) *
                       (images[IMG_HIGHSCORE_LETTERS] -> w) / 36);

              src.y = 0;
              src.w = (images[IMG_HIGHSCORE_LETTERS] -> w) / 36;
              src.h = images[IMG_HIGHSCORE_LETTERS] -> h;

              dest.x = ((640 - (strlen(highscorer) *
                            ((images[IMG_HIGHSCORE_LETTERS] -> w) /
                             36)))
                      / 2) + (i * (images[IMG_HIGHSCORE_LETTERS] -> w) /
                            36);
              dest.y = 200;
              dest.w = src.w;
              dest.h = src.h;

              my_blit(images[IMG_HIGHSCORE_LETTERS], &src,
                          screen, &dest);
#else
              if (highscorer[i] >= '0' && highscorer[i] <= '9')
                src.y = ((highscorer[i] - '0') *
                       (images[IMG_HIGHSCORE_LETTERS] -> h) / 36);
              else if (highscorer[i] >= 'A' && highscorer[i] <= 'Z')
                src.y = ((highscorer[i] - 'A' + 10) *
                       (images[IMG_HIGHSCORE_LETTERS] -> h) / 36);

              src.x = 0;
              src.h = (images[IMG_HIGHSCORE_LETTERS] -> h) / 36;
              src.w = images[IMG_HIGHSCORE_LETTERS] -> w;
              
              dest.y = ((320 - (strlen(highscorer) *
                            ((images[IMG_HIGHSCORE_LETTERS] -> h) /
                             36)))
                      / 2) + (i * (images[IMG_HIGHSCORE_LETTERS] -> h) /
                            36);
              dest.x = 100;
              dest.w = src.w;
              dest.h = src.h;

              SDL_BlitSurface(images[IMG_HIGHSCORE_LETTERS] , &src,
                          screen, &dest);
#endif
              
            }
          }
        
        
        /* Update the screen: */
        
        dest.x = 0;
        dest.y = 200;
        dest.w = 640;
#ifndef EMBEDDED
        dest.h = images[IMG_HIGHSCORE_LETTERS] -> h;
#else
        dest.h = images[IMG_HIGHSCORE_LETTERS] -> w * 2;
#endif
       
        my_updaterect(screen, 0, 200,
                   640, dest.h);
        
        draw_text = 0;
      }
      
      
#ifndef NOSOUND
#ifndef EMBEDDED
      /* Keep playing music: */
      
      if (use_sound == 1)
      {
        if (!Mix_PlayingMusic())
          {
            Mix_PlayMusic(highscore_music, 0);
            Mix_VolumeMusic(music_volume * 16);
          }
      }
#endif
#endif
      
      
      /* Pause: */
      
      SDL_Delay(50);
    }
  while (done == 0);
  
  if (done == 0 || done == 1)
    return(0);
  else
    return(1);
}


/* Set the application's icon: */

void seticon(void)
{
#ifndef EMBEDDED
  int masklen;
  Uint8 * mask;
  SDL_Surface * icon;
  
 
  /* Load icon into a surface: */
  
  icon = IMG_Load(DATA_PREFIX "images/icon.png");
  if (icon == NULL)
    {
      fprintf(stderr,
            "\nError: I could not load the icon image: %s\n"
            "The Simple DirectMedia error that occured was:\n"
            "%s\n\n", DATA_PREFIX "images/icon.png", SDL_GetError());
      exit(1);
    }
  
  
  /* Create mask: */
  
  masklen = (((icon -> w) + 7) / 8) * (icon -> h);
  mask = malloc(masklen * sizeof(Uint8));
  memset(mask, 0xFF, masklen);
  
  
  /* Set icon: */
  
  SDL_WM_SetIcon(icon, mask);
  
  
  /* Free icon surface & mask: */
  
  free(mask);
  SDL_FreeSurface(icon);
#endif
}


void my_blit(SDL_Surface * src_img, SDL_Rect * src_rect,
           SDL_Surface * dest_img, SDL_Rect * dest_rect)
{
#ifdef EMBEDDED
  SDL_Rect src_rect2, dest_rect2;

  if (src_rect != NULL)
  {
    src_rect2.x = 240 - src_rect->y / 2 - src_rect->h / 2;
    src_rect2.y = src_rect->x / 2;
    src_rect2.w = src_rect->h / 2;
    src_rect2.h = src_rect->w / 2;
    src_rect = &src_rect2;
  }

  if (dest_rect != NULL)
  {
    dest_rect2.x = 240 - dest_rect->y / 2 - dest_rect->h / 2;
    dest_rect2.y = dest_rect->x / 2;
    dest_rect2.w = dest_rect->h / 2;
    dest_rect2.h = dest_rect->w / 2;
    dest_rect = &dest_rect2;
  }
#endif
  
  SDL_BlitSurface(src_img, src_rect, dest_img, dest_rect);
}


void my_updaterect(SDL_Surface * surf, int x, int y, int w, int h)
{
#ifndef EMBEDDED
  SDL_UpdateRect(surf, x, y, w, h);
#else
  SDL_UpdateRect(surf, 240 - y / 2 - h / 2, x / 2, h / 2, w / 2);
#endif
}


void my_fillrect(SDL_Surface * surf, SDL_Rect * dest, Uint32 color)
{
#ifdef EMBEDDED
  SDL_Rect dest2;
  
  dest2.x = 240 - dest->y / 2 - dest->h / 2;
  dest2.y = dest->x / 2;
  dest2.w = dest->h / 2;
  dest2.h = dest->w / 2;
  
  dest = &dest2;
#endif

  SDL_FillRect(surf, dest, color);  
}


Generated by  Doxygen 1.6.0   Back to index