/* madbomber.c by Bill Kendrick bill@newbreedsoftware.com http://www.newbreedsoftware.com/ October 25, 1999 - March 16, 2003 */ #ifndef EMBEDDED #define VERSION "0.2.5" #else #define VERSION "0.2.5-embedded" #define SDL_MIXER_BUG #endif /* #includes: */ #include #include #include #include #include #include #include #include /* #ifdef WIN32 */ /* #include */ /* #endif */ #ifndef NOSOUND #include #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, posn; #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); #ifndef NOSOUND posn = (bombs[i].x * 255) / screen->w; Mix_SetPanning(1, 255 - posn, posn); #endif /* 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); Mix_SetPanning(chan, 255, 255); } #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; int posn; /* 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); #ifndef NOSOUND posn = (bombs[bottom_most].x * 255) / screen->w; Mix_SetPanning(1, 255 - posn, posn); #endif /* 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); Mix_SetPanning(1, 255, 255); /* 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); }