/**********************************************/
/* Evert Glebbeek 2002, 2004                  */
/* eglebbk@dds.nl                             */
/**********************************************/
#include <allegro.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include "playgame.h"
#include "global.h"
#include "dialog.h"
#include "gamegfx.h"
#include "gfx.h"
#include "sound.h"
#include "gmemusic.h"
#include "palette.h"
#include "network.h"
#include "ctsparse.h"

#define DELTA_HUE          45.00f
#define DELTA_SATURATION    0.75f

/* Static functions */
static char *network_lister (int i, int *size);
static char *resolution_lister (int i, int *size);
static char *colour_depth_lister (int i, int *size);
static char *input_source_lister(int i, int *size);
static char *tileset_lister(int i, int *size);
static char *starttile_lister(int i, int *size);

#define D_PASSIVE (D_USER << 1)

#ifdef ALLEGRO_LINUX
   #undef KEY_PRTSCR
   #define KEY_PRTSCR KEY_F12
#endif

struct resolution_entry {
   int w,h;
   char *s;
} resolutions[] = {
   {  800,  600, " 800x600 "  },
   { 1024,  768, "1024x768 "  },
};

struct colour_depth_entry {
   int depth;
   char *s;
} colour_depths[] = {
   { 16, "15/16 bpp" },
   { 24, "24 bpp" },
   { 32, "32 bpp" }
};

char *texture_resolution[] = { " Low", "Medium", " High" };
char *input_sources[] = {
   "None",
   "Keyboard",
   "Gamepad 1",
   "Gamepad 2",
   "Gamepad 3",
   "Gamepad 4"//,
//   "Mouse"
};
char *button_names[] = {
   "Up",
   "Down",
   "Left",
   "Right",
   "Attack",         // A
   "Dash",           // B
   "Set bomb",       // Y
   "Centre target",  // X
   "Previous",       // L
   "Next",           // R
   "Start",          // Start
   "Select"          // Select
};


static DIALOG_PLAYER *player = NULL;
static DIALOG *player_dialog = NULL;
static BITMAP *player_bmp;

/* *INDENT-OFF* */
typedef int (*BUTTCALLBACK)(int msg, DIALOG *d, int c);

static DIALOG game_quit_dialog[] = {
   /* (dialog proc) (x)     (y)  (w)      (h)   (fg) (bg) (key) (flags) (d1)  (d2)  (dp) */
   { d_mbitmap_proc,    -96,-48,   192,   136,  0,     0,   0,    0,      0,   0,    NULL },
   { d_text_proc,       -64,-36,   128,   16,   0,     7,   0,    0,      0,   0,    "Are you sure?",NULL },
   { d_butgfx_agui_proc,-63, 36,   126,   18,   0,     7,   'y',  D_EXIT, 0,   0,    "&Yes",NULL },
   { d_butgfx_agui_proc,-63, 60,   126,   18,   0,     7,   'n',  D_EXIT, 0,   0,    "&No",NULL },
   { d_keyboard_proc,     0,  0,     0,    0,   0,     0,   0,    0,      0,   KEY_PRTSCR, d_scrnshot_proc},
   { d_gamemusic_proc },
   { d_yield_proc },
   { NULL }
};

DIALOG main_menu_dialog[] = {
   /* (dialog proc) (x)      (y)  (w)   (h)   (fg) (bg) (key) (flags) (d1)  (d2)  (dp) */
   { d_mbitmap_proc,     -96,-48,192,   160,   0,    0,   0,    0,      0,   0,    NULL },
   { d_ctextbut_agui_proc,-63,-36,126,   18,  -1,    7,  's',   D_EXIT, 0,   0,    "New Game", NULL },
   { d_ctextbut_agui_proc,-63,-12,126,   18,  -1,    7,  'o',   D_EXIT, 0,   0,    "Options", NULL },
   { d_ctextbut_agui_proc,-63, 24,126,   18,  -1,    7,  'q',   D_EXIT, 0,   0,    "Quit", NULL },
   { d_keyboard_proc,     0,  0,   0,     0,   0,    0,   0,    0,      0,   KEY_PRTSCR, d_scrnshot_proc},
   { d_gamemusic_proc },
   { d_yield_proc },
   { NULL }
};

static DIALOG game_msg_dialog[] = {
   /* (dialog proc)    (x)    (y)   (w)   (h)  (fg) (bg) (key) (flags)  (d1)  (d2)  (dp) */
   { d_mbitmap_proc,   -96,   -48,  192, 136,   0,   0,   0,      0,      0,   0,      NULL },
   { d_text_proc,      -88,   -36,  128,  16,   0,   7,   0,      0,      0,   0,      NULL,NULL },
   { d_text_proc,      -88,   -20,  128,  16,   0,   7,   0,      0,      0,   0,      NULL,NULL },
   { d_text_proc,      -88,    -4,  128,  16,   0,   7,   0,      0,      0,   0,      NULL,NULL },
   { d_butgfx_agui_proc,-63,   60,  126,  18,   0,   7,   'o',    D_EXIT, 0,   0,      "&Ok",NULL },
   { d_keyboard_proc,    0,     0,    0,   0,   0,   0,    0,     0,      0,   KEY_PRTSCR, d_scrnshot_proc},
   { d_gamemusic_proc },
   { d_yield_proc },
   { NULL }
};

/* Game menu dialog box */
static DIALOG game_menu_dialog[] = {
   /* (dialog proc)    (x)    (y)   (w)   (h)  (fg) (bg) (key) (flags) (d1)  (d2)  (dp) */
   { d_mbitmap_proc,    -96, -48,   192,   136, 0,   0,    0,   0,      0,   0,      NULL },
   { d_butgfx_agui_proc,-63, -37,   126,    18, 0,   7,    'o', D_EXIT, 0,   0,      "&Options",NULL },
   { d_butgfx_agui_proc,-63, -11,   126,    18, 0,   7,    'n', D_EXIT, 0,   0,      "&New Game",NULL },
   { d_butgfx_agui_proc,-63,  13,   126,    18, 0,   7,    'l', D_EXIT, 0,   0,      "&Load Game",NULL },
   { d_butgfx_agui_proc,-63,  37,   126,    18, 0,   7,    'r', D_EXIT, 0,   0,      "&Resume",NULL },
   { d_butgfx_agui_proc,-63,  61,   126,    18, 0,   7,    'q', D_EXIT, 0,   0,      "&Quit",NULL },
   { d_keyboard_proc,     0,   0,     0,     0, 0,   0,    0,   0,      0,   KEY_PRTSCR, d_scrnshot_proc},
   { d_gamemusic_proc },
   { d_yield_proc },
   { NULL }
};

/* Game options dialog box */
static DIALOG game_options_menu_dialog[] = {
   /* (dialog proc)    (x)    (y)   (w)   (h)  (fg) (bg) (key) (flags)  (d1)  (d2)  (dp) */
   { d_mbitmap_proc,    -200, -48,  400,  136,  0,   0,    0,   0,      0,   0,      NULL },
   { d_ctextbut_agui_proc,-63,-37,  126,   18,  0,   7,   'd',  D_EXIT, 0,   0,      "Display options",NULL },
   { d_ctextbut_agui_proc,-63,-11,  126,   18,  0,   7,   's',  D_EXIT, 0,   0,      "Sound options",NULL },
   { d_ctextbut_agui_proc,-63, 15,  126,   18,  0,   7,   't',  D_EXIT, 0,   0,      "Theme",NULL },
   { d_ctextbut_agui_proc,-63, 37,  126,   18,  0,   7,    0,   D_DISABLED,0,0,      "",NULL },
   { d_ctextbut_agui_proc,-63, 61,  126,   18,  0,   7,   'r',  D_EXIT, 0,   0,      "Return",NULL },
   { d_keyboard_proc,       0,  0,    0,    0,  0,   0,    0,   0,      0,   KEY_PRTSCR, d_scrnshot_proc},
   { d_gamemusic_proc },
   { d_yield_proc },
   { NULL }
};

DIALOG newgame_menu_dialog[] = {
   /* (dialog proc) (x)      (y)  (w)   (h)   (fg) (bg) (key) (flags) (d1)  (d2)  (dp) */
   { d_mbitmap_proc,     -160,-48,320,   160,   0,    0,   0,    0,      0,   0,    NULL },
   { d_ctextbut_agui_proc,-63,-36,126,   18,  -1,    7,  'l',   D_EXIT, 0,   0,    "Local game", NULL },
   { d_ctextbut_agui_proc,-63,-12,126,   18,  -1,    7,  'n',   D_EXIT, 0,   0,    "Create Network game", NULL },
   { d_ctextbut_agui_proc,-63, 12,126,   18,  -1,    7,  'j',   D_EXIT, 0,   0,    "Join Network game", NULL },
   { d_ctextbut_agui_proc,-63, 48,126,   18,  -1,    7,  'c',   D_EXIT, 0,   0,    "Cancel", NULL },
   { d_keyboard_proc,     0,  0,   0,     0,   0,    0,   0,    0,      0,   KEY_PRTSCR, d_scrnshot_proc},
   { d_gamemusic_proc },
   { d_yield_proc },
   { NULL }
};

/* Video options dialog */
static DIALOG game_video_options_dialog[] = {
   /* (dialog proc) (x)   (y)  (w)     (h)   (fg) (bg) (key) (flags)  (d1)  (d2)  (dp) */
   { d_mbitmap_proc,-60,   0,   440,    240,   0,   0,   0,      0,     0,   0,  NULL },
   { d_ctextbut_agui_proc,19,210,126,    27,   0,   7,  'o',     D_EXIT,0,   0,  "Ok",NULL },
   { d_ctextbut_agui_proc,175,210,126,   27,   0,   7,  'c',     D_EXIT,0,   0,  "Cancel",NULL },
   /* Text captions (3-4) */
   { d_ctext_proc,  160,    8,  128,     32,   0,  -1,   0,      0,     0,   0,  "Display Options",NULL },
   { d_ctext_proc,  160,  116,  128,     32,   0,  -1,   0,      0,     0,   0,  "Resolution and colour depth",NULL },
   /* Checkbox captions (5-8) */
   { d_text_proc,    56,   36,  128,     32,   0,  -1,   0,      0,     0,   0,  "Use BMP sprites",NULL },
   { d_text_proc,    56,   57,  128,     32,   0,  -1,   0,      0,     0,   0,  "Use RLE sprites",NULL },
   { d_text_proc,    56,   78,  128,     32,   0,  -1,   0,      0,     0,   0,  "Enable hardware scrolling",NULL },
   { d_text_proc,    56,   99,  128,     32,   0,  -1,   0,      0,     0,   0,  "Run in windowed mode",NULL },
   /* Resolution lister (9-10) */
   { d_list_proc,    24,  144,  112,   3*13+4,   0,   0,   0,      0,     0,   0,  resolution_lister,NULL },
   { d_list_proc,   184,  144,  112,   4*13+4,   0,   0,   0,      0,     0,   0,  colour_depth_lister,NULL },
   /* Checkbox: enable bitmaps (11) */
   { d_gfxcheck_proc,30,   34,  15,    15,   0,    0,    0,    D_DISABLED,0,   0,    NULL  },
   /* Checkbox: enable RLE sprites (12) */
   { d_gfxcheck_proc,30,   55,  15,    15,   0,    0,    0,    D_DISABLED,0,   0,    NULL  },
   /* Checkbox: hardware scrolling (13) */
   { d_gfxcheck_proc,30,   76,  15,    15,   0,    0,    0,    D_DISABLED,0,   0,    NULL  },
   /* Checkbox: windowed mode (14) */
   { d_gfxcheck_proc,30,   97,  15,    15,   0,    0,    0,    0,     0,   0,    NULL  },

   { d_keyboard_proc,0,    0,     0,    0,   0,    0,    0,    0,     0,   KEY_PRTSCR, d_scrnshot_proc},
   { d_gamemusic_proc },
   { d_yield_proc },
   { NULL }
};

/* Network options dialog */
static DIALOG game_network_options_dialog[] = {
   /* (dialog proc) (x)   (y)  (w)     (h)   (fg) (bg) (key) (flags)  (d1)  (d2)  (dp) */
   { d_mbitmap_proc,-30,   0,   380,    240,   0,   0,   0,      0,     0,   0,  NULL },
   { d_ctextbut_agui_proc,19,210,126,    27,   0,   7,  'o',     D_EXIT,0,   0,  "Ok",NULL },
   { d_ctextbut_agui_proc,175,210,126,   27,   0,   7,  'c',     D_EXIT,0,   0,  "Cancel",NULL },
   /* Text captions (3-4) */
   { d_ctext_proc,  160,    8,  128,     32,   0,  -1,   0,      0,     0,   0,  "Connection Type",NULL },
   { d_ctext_proc,  160,  116,  128,     32,   0,  -1,   0,      0,     0,   0,  "Server name",NULL },
   /* Network driver list (5) */
   { d_list_proc,    30,   46,  320,   5*13+4,   0,   0,   0,      0,     0,   0,  network_lister,NULL },
   /* Server IP address (6) */
   { d_edit_proc,    30,  148,  320,     16,     0,   0,   0,      0,     0,   0,  NULL, NULL },
   /* Player name (7) */
   { d_edit_proc,    30,  190,  320,     16,     0,   0,   0,      0,     0,   0,  NULL, NULL },
   { d_ctext_proc,  160,  160,  128,     32,   0,  -1,   0,      0,     0,   0,  "Nickname",NULL },

   { d_keyboard_proc,0,    0,     0,    0,   0,    0,    0,    0,     0,   KEY_PRTSCR, d_scrnshot_proc},
   { d_gamemusic_proc },
   { d_yield_proc },
   { NULL }
};

/* Network options dialog */
DIALOG game_params_dialog[] = {
   /* (dialog proc) (x)   (y)  (w)     (h)   (fg) (bg) (key) (flags)  (d1)  (d2)  (dp) */
   { d_mbitmap_proc,  0,   0,   800,   600,   0,   0,   0,      0,     0,   0,  NULL },
   { d_mbitmap_proc, 40,  40,   720,   430,   0,   0,   0,      0,     0,   0,  NULL },
   /* Text buttons (2, 3) */
   { d_ctextbut_agui_proc,640,410,126,  27,   0,   7,  'o',     D_EXIT,0,   0,  "Start",NULL },
   { d_ctextbut_agui_proc,640,440,126,  27,   0,   7,  'c',     D_EXIT,0,   0,  "Cancel",NULL },
   /* Player checkboxes (4-11) */
   { d_gfxcheck_proc,60,   85,  15,    15,   0,    0,    0,    0,     0,   0,    NULL  },
   { d_gfxcheck_proc,60,  105,  15,    15,   0,    0,    0,    0,     0,   0,    NULL  },
   { d_gfxcheck_proc,60,  125,  15,    15,   0,    0,    0,    0,     0,   0,    NULL  },
   { d_gfxcheck_proc,60,  145,  15,    15,   0,    0,    0,    0,     0,   0,    NULL  },
   { d_gfxcheck_proc,60,  165,  15,    15,   0,    0,    0,    0,     0,   0,    NULL  },
   { d_gfxcheck_proc,60,  185,  15,    15,   0,    0,    0,    0,     0,   0,    NULL  },
   { d_gfxcheck_proc,60,  205,  15,    15,   0,    0,    0,    0,     0,   0,    NULL  },
   { d_gfxcheck_proc,60,  225,  15,    15,   0,    0,    0,    0,     0,   0,    NULL  },

   /* Player names (12-19) */
   { d_gfxedit_proc, 80,   85, 120,    15,   0,    0,    0,    0,    20,   0,    NULL  },
   { d_gfxedit_proc, 80,  105, 120,    15,   0,    0,    0,    0,    20,   0,    NULL  },
   { d_gfxedit_proc, 80,  125, 120,    15,   0,    0,    0,    0,    20,   0,    NULL  },
   { d_gfxedit_proc, 80,  145, 120,    15,   0,    0,    0,    0,    20,   0,    NULL  },
   { d_gfxedit_proc, 80,  165, 120,    15,   0,    0,    0,    0,    20,   0,    NULL  },
   { d_gfxedit_proc, 80,  185, 120,    15,   0,    0,    0,    0,    20,   0,    NULL  },
   { d_gfxedit_proc, 80,  205, 120,    15,   0,    0,    0,    0,    20,   0,    NULL  },
   { d_gfxedit_proc, 80,  225, 120,    15,   0,    0,    0,    0,    20,   0,    NULL  },

   /* Local game options (20) */
   { d_gfxcheck_proc,480,   85,  15,    15,   0,    0,    0,    0,     0,   0,    NULL  },
   { d_text_proc,    500,   85, 128,    32,   0,   -1,    0,    0,     0,   0,  "Auto end turn", NULL },

   /* Tileset options (22) */
   { d_checklist_proc,240, 144, 208,8*14+4,   0,    0,    0,    0,     0,   0,  tileset_lister,NULL },
   { d_text_proc,    240,  128, 208,    16,   0,   -1,    0,    0,     0,   0,  "Tilesets", NULL },

   /* Tileset options (24) */
   { d_list_proc,    240,  280, 208,4*13+4,   0,    0,    0,    0,     0,   0,  starttile_lister,NULL },
   { d_text_proc,    240,  264, 208,    16,   0,   -1,    0,    0,     0,   0,  "Start tiles", NULL },
   
   /* Score options (26-32) */
   { d_edit_proc,    480, 144,   28,    16,   0,    0,    0,    0,     4,   0,   NULL },
   { d_edit_proc,    480, 160,   28,    16,   0,    0,    0,    0,     4,   0,   NULL },
   { d_edit_proc,    480, 176,   28,    16,   0,    0,    0,    0,     4,   0,   NULL },
   { d_edit_proc,    480, 192,   28,    16,   0,    0,    0,    0,     4,   0,   NULL },
   { d_edit_proc,    480, 208,   28,    16,   0,    0,    0,    0,     4,   0,   NULL },
   { d_edit_proc,    480, 224,   28,    16,   0,    0,    0,    0,     4,   0,   NULL },
   { d_edit_proc,    480, 240,   28,    16,   0,    0,    0,    0,     4,   0,   NULL },
   /* Captions (33-39) */
   { d_text_proc,    512, 144,  128,    16,   0,   -1,    0,    0,     0,   0,  "Farm score (basic)", NULL },
   { d_text_proc,    512, 160,  128,    16,   0,   -1,    0,    0,     0,   0,  "Farm score (Pig)", NULL },
   { d_text_proc,    512, 176,  128,    16,   0,   -1,    0,    0,     0,   0,  "Cathedral multiplier (during game)", NULL },
   { d_text_proc,    512, 192,  128,    16,   0,   -1,    0,    0,     0,   0,  "Cathedral multiplier (final)", NULL },
   { d_text_proc,    512, 208,  128,    16,   0,   -1,    0,    0,     0,   0,  "Inn multiplier (during game)", NULL },
   { d_text_proc,    512, 224,  128,    16,   0,   -1,    0,    0,     0,   0,  "Inn multiplier (final)", NULL },
   { d_text_proc,    512, 240,  128,    16,   0,   -1,    0,    0,     0,   0,  "Trade monopoly", NULL },
   
   /* Men counts (40-43) */
   { d_edit_proc,    480, 260,   28,    16,   0,    0,    0,    0,     4,   0,   NULL },
   { d_edit_proc,    480, 276,   28,    16,   0,    0,    0,    0,     4,   0,   NULL },
   { d_edit_proc,    480, 292,   28,    16,   0,    0,    0,    0,     4,   0,   NULL },
   { d_edit_proc,    480, 308,   28,    16,   0,    0,    0,    0,     4,   0,   NULL },
   /* Captions (44-47) */
   { d_text_proc,    512, 260,  128,    16,   0,   -1,    0,    0,     0,   0,  "Peasants", NULL },
   { d_text_proc,    512, 276,  128,    16,   0,   -1,    0,    0,     0,   0,  "Bigmen", NULL },
   { d_text_proc,    512, 292,  128,    16,   0,   -1,    0,    0,     0,   0,  "Builders", NULL },
   { d_text_proc,    512, 308,  128,    16,   0,   -1,    0,    0,     0,   0,  "Pigs", NULL },
   
   /* Text captions */
   { d_ctext_proc,   80,   60,  128,    32,   0,  -1,   0,      0,     0,   0,  "Player Name", NULL },

   { d_keyboard_proc,0,    0,     0,    0,   0,    0,    0,    0,     0,   KEY_PRTSCR, d_scrnshot_proc},
   { d_gamemusic_proc },
   { d_yield_proc },
   { NULL }
};


/* Sound options dialog */
static DIALOG game_sound_options_dialog[] = {
   /* (dialog proc) (x)   (y)    (w)    (h)   (fg) (bg) (key)  (flags) (d1) (d2)  (dp) */
   { d_mbitmap_proc,  0,   0,    320,   240,   0,    0,   0,    0,     0,   0,   NULL },
   { d_ctextbut_agui_proc,19,190, 126,   27,   0,    7,   'o',  D_EXIT,0,   0,   "Ok",NULL },
   { d_ctextbut_agui_proc,175,190,126,   27,   0,    7,   'c',  D_EXIT,0,   0,   "Cancel",NULL },
   /* Text captions */
   { d_ctext_proc,  160,   46,   128,    32,   0,   -1,   0,    0,     0,   0,   "Sound Options",NULL },
   { d_text_proc,    28,   78,   128,    32,   0,   -1,   0,    0,     0,   0,   "Digital volume",NULL },
   { d_text_proc,    28,  110,   128,    32,   0,   -1,   0,    0,     0,   0,   "Music volume",NULL },
   { d_text_proc,    56,  160,   128,    32,   0,   -1,   0,    0,     0,   0,   "Use Digital MIDI",NULL },

   { d_box_proc,     30,  92,    260,    20,   0,    0,   0,    0,     0,   0,   NULL },
   { d_box_proc,     30, 124,    260,    20,   0,    0,   0,    0,     0,   0,   NULL },
   /* Slider bars (9, 10) */
   { d_slider_proc,  32,  94,    256,    16,   0,    0,   0,    0,     31,  0,   NULL },
   { d_slider_proc,  32, 126,    256,    16,   0,    0,   0,    0,     31,  0,   NULL },

   /* Checkbox (11) */
   { d_gfxcheck_proc,36, 158,    256,    16,   0,    0,   0,    0,     31,  0,   NULL},

   { d_keyboard_proc, 0,   0,      0,     0,   0,    0,   0,    0,     0,   KEY_PRTSCR, d_scrnshot_proc},
   { d_gamemusic_proc },
   { d_yield_proc },
   { NULL }
};

/* Map/status display */
DIALOG game_map_display_dialog[] = {
   /* (dialog proc) (x)   (y)  (w)     (h)   (fg) (bg) (key) (flags)  (d1)  (d2)  (dp) */
   { d_mbitmap_proc,  0,   0,   320,    240,   0,   0,   0,      0,     0,   0,  NULL },
   { d_ctextbut_agui_proc,19,200,126,    27,   0,   7,   0,     D_EXIT, 0,   0,  "Resume", NULL },
   { d_ctextbut_agui_proc,175,200,126,   27,   0,   7,   0,     D_EXIT, 0,   0,  "Quit", NULL },

   { d_keyboard_proc, 0,   0,      0,     0,   0,   0,   0,      0,    0,   KEY_PRTSCR, d_scrnshot_proc},
   { d_gamemusic_proc },
   { d_yield_proc },
   { NULL }
};


/* Password input dialog */
DIALOG string_input_dialog[] = {
   /* (dialog proc) (x)   (y)  (w)     (h)   (fg) (bg) (key) (flags)  (d1)  (d2)  (dp) */
   { d_mbitmap_proc,  0,  -3,   374,   300,    0,   0,   0,      0,     0,   0,  NULL },
   { d_ctextbut_agui_proc,44,256,126,   27,    0,   7,   0,      D_EXIT,0,   0,  "Ok",NULL },
   { d_ctextbut_agui_proc,199,256,126,  27,    0,   7,   0,      D_EXIT,0,   0,  "Cancel",NULL },
   { d_box_proc,      2,  -3,  370,     34,    0,   0,   0,      0,     0,   0,   NULL },
   { d_text_proc,     8,   0,  370,     30,    0,   0,   0,      0,     0,   0,  "" },

   { d_pwd_key_proc,  0, 132,   32,     30,    0,   0,  'a',     0,     0,   0,  NULL },
   { d_pwd_key_proc, 34, 132,   32,     30,    0,   0,  'b',     0,     0,   0,  NULL },
   { d_pwd_key_proc, 68, 132,   32,     30,    0,   0,  'c',     0,     0,   0,  NULL },
   { d_pwd_key_proc,102, 132,   32,     30,    0,   0,  'd',     0,     0,   0,  NULL },
   { d_pwd_key_proc,136, 132,   32,     30,    0,   0,  'e',     0,     0,   0,  NULL },
   { d_pwd_key_proc,170, 132,   32,     30,    0,   0,  'f',     0,     0,   0,  NULL },
   { d_pwd_key_proc,204, 132,   32,     30,    0,   0,  'g',     0,     0,   0,  NULL },
   { d_pwd_key_proc,238, 132,   32,     30,    0,   0,  'h',     0,     0,   0,  NULL },
   { d_pwd_key_proc,272, 132,   32,     30,    0,   0,  'i',     0,     0,   0,  NULL },
   { d_pwd_key_proc,  0, 164,   32,     30,    0,   0,  'j',     0,     0,   0,  NULL },
   { d_pwd_key_proc, 34, 164,   32,     30,    0,   0,  'k',     0,     0,   0,  NULL },
   { d_pwd_key_proc, 68, 164,   32,     30,    0,   0,  'l',     0,     0,   0,  NULL },
   { d_pwd_key_proc,102, 164,   32,     30,    0,   0,  'm',     0,     0,   0,  NULL },
   { d_pwd_key_proc,136, 164,   32,     30,    0,   0,  'n',     0,     0,   0,  NULL },
   { d_pwd_key_proc,170, 164,   32,     30,    0,   0,  'o',     0,     0,   0,  NULL },
   { d_pwd_key_proc,204, 164,   32,     30,    0,   0,  'p',     0,     0,   0,  NULL },
   { d_pwd_key_proc,238, 164,   32,     30,    0,   0,  'q',     0,     0,   0,  NULL },
   { d_pwd_key_proc,272, 164,   32,     30,    0,   0,  'r',     0,     0,   0,  NULL },
   { d_pwd_key_proc,  0, 196,   32,     30,    0,   0,  's',     0,     0,   0,  NULL },
   { d_pwd_key_proc, 34, 196,   32,     30,    0,   0,  't',     0,     0,   0,  NULL },
   { d_pwd_key_proc, 68, 196,   32,     30,    0,   0,  'u',     0,     0,   0,  NULL },
   { d_pwd_key_proc,102, 196,   32,     30,    0,   0,  'v',     0,     0,   0,  NULL },
   { d_pwd_key_proc,136, 196,   32,     30,    0,   0,  'w',     0,     0,   0,  NULL },
   { d_pwd_key_proc,170, 196,   32,     30,    0,   0,  'x',     0,     0,   0,  NULL },
   { d_pwd_key_proc,204, 196,   32,     30,    0,   0,  'y',     0,     0,   0,  NULL },
   { d_pwd_key_proc,238, 196,   32,     30,    0,   0,  'z',     0,     0,   0,  NULL },

   { d_pwd_key_proc,  0,  32,   32,     30,    0,   0,  'A',     0,     0,   0,  NULL },
   { d_pwd_key_proc, 34,  32,   32,     30,    0,   0,  'B',     0,     0,   0,  NULL },
   { d_pwd_key_proc, 68,  32,   32,     30,    0,   0,  'C',     0,     0,   0,  NULL },
   { d_pwd_key_proc,102,  32,   32,     30,    0,   0,  'D',     0,     0,   0,  NULL },
   { d_pwd_key_proc,136,  32,   32,     30,    0,   0,  'E',     0,     0,   0,  NULL },
   { d_pwd_key_proc,170,  32,   32,     30,    0,   0,  'F',     0,     0,   0,  NULL },
   { d_pwd_key_proc,204,  32,   32,     30,    0,   0,  'G',     0,     0,   0,  NULL },
   { d_pwd_key_proc,238,  32,   32,     30,    0,   0,  'H',     0,     0,   0,  NULL },
   { d_pwd_key_proc,272,  32,   32,     30,    0,   0,  'I',     0,     0,   0,  NULL },
   { d_pwd_key_proc,  0,  64,   32,     30,    0,   0,  'J',     0,     0,   0,  NULL },
   { d_pwd_key_proc, 34,  64,   32,     30,    0,   0,  'K',     0,     0,   0,  NULL },
   { d_pwd_key_proc, 68,  64,   32,     30,    0,   0,  'L',     0,     0,   0,  NULL },
   { d_pwd_key_proc,102,  64,   32,     30,    0,   0,  'M',     0,     0,   0,  NULL },
   { d_pwd_key_proc,136,  64,   32,     30,    0,   0,  'N',     0,     0,   0,  NULL },
   { d_pwd_key_proc,170,  64,   32,     30,    0,   0,  'O',     0,     0,   0,  NULL },
   { d_pwd_key_proc,204,  64,   32,     30,    0,   0,  'P',     0,     0,   0,  NULL },
   { d_pwd_key_proc,238,  64,   32,     30,    0,   0,  'Q',     0,     0,   0,  NULL },
   { d_pwd_key_proc,272,  64,   32,     30,    0,   0,  'R',     0,     0,   0,  NULL },
   { d_pwd_key_proc,  0,  96,   32,     30,    0,   0,  'S',     0,     0,   0,  NULL },
   { d_pwd_key_proc, 34,  96,   32,     30,    0,   0,  'T',     0,     0,   0,  NULL },
   { d_pwd_key_proc, 68,  96,   32,     30,    0,   0,  'U',     0,     0,   0,  NULL },
   { d_pwd_key_proc,102,  96,   32,     30,    0,   0,  'V',     0,     0,   0,  NULL },
   { d_pwd_key_proc,136,  96,   32,     30,    0,   0,  'W',     0,     0,   0,  NULL },
   { d_pwd_key_proc,170,  96,   32,     30,    0,   0,  'X',     0,     0,   0,  NULL },
   { d_pwd_key_proc,204,  96,   32,     30,    0,   0,  'Y',     0,     0,   0,  NULL },
   { d_pwd_key_proc,238,  96,   32,     30,    0,   0,  'Z',     0,     0,   0,  NULL },

   { d_pwd_key_proc,308,  32,   32,     30,    0,   0,  '1',     0,     0,   0,  NULL },
   { d_pwd_key_proc,308,  64,   32,     30,    0,   0,  '2',     0,     0,   0,  NULL },
   { d_pwd_key_proc,308,  96,   32,     30,    0,   0,  '3',     0,     0,   0,  NULL },
   { d_pwd_key_proc,308, 132,   32,     30,    0,   0,  '4',     0,     0,   0,  NULL },
   { d_pwd_key_proc,308, 164,   32,     30,    0,   0,  '5',     0,     0,   0,  NULL },
   { d_pwd_key_proc,308, 196,   32,     30,    0,   0,  '6',     0,     0,   0,  NULL },
   { d_pwd_key_proc,342,  32,   32,     30,    0,   0,  '7',     0,     0,   0,  NULL },
   { d_pwd_key_proc,342,  64,   32,     30,    0,   0,  '8',     0,     0,   0,  NULL },
   { d_pwd_key_proc,342,  96,   32,     30,    0,   0,  '9',     0,     0,   0,  NULL },
   { d_pwd_key_proc,342, 132,   32,     30,    0,   0,  '*',     0,     0,   0,  NULL },
   { d_pwd_key_proc,342, 164,   32,     30,    0,   0,  '+',     0,     0,   0,  NULL },
   { d_pwd_key_proc,342, 196,   32,     30,    0,   0,  '-',     0,     0,   0,  NULL },

   { d_pwd_key_proc,  0, 230,   32,     30,    0,   0,  8,       0,     0,   0,  NULL },

   { d_keyboard_proc, 0,   0,      0,     0,   0,   0,   0,      D_EXIT,0,   KEY_PRTSCR, d_scrnshot_proc},
   { d_gamemusic_proc },
   { d_yield_proc },
   { NULL }
};


/* Partial dialog objects */
DIALOG game_butt[] = {
   /* (dialog proc) (x)  (y)  (w)  (h) (fg) (bg) (key) (flags) (d1)  (d2)  (dp) */
   {d_butgfx_proc, -280, -108, 126, 18, 0, 7, 0, 0, 0, 0, "Menu", NULL},
   {NULL}
};

DIALOG cancel_butt[] = {
   /* (dialog proc) (x)  (y)  (w)  (h) (fg) (bg) (key) (flags) (d1)  (d2)  (dp) */
   {d_butgfx_proc, 0,0, 32, 32, 0, 7, 0, 0, 0, 0, "", NULL},
   {NULL}
};
/* *INDENT-ON* */

static char *network_lister(int i, int *size)
{
   if (i < 0) {
      *size = get_nr_network_drivers();
      return NULL;
   }
   return get_network_driver_name(i);
}


static char *resolution_lister(int i, int *size)
{
   if (i < 0) {
      *size = sizeof resolutions / sizeof *resolutions;
      return NULL;
   }
   return resolutions[i].s;
}


static char *colour_depth_lister(int i, int *size)
{
   if (i < 0) {
      *size = sizeof colour_depths / sizeof *colour_depths;
      return NULL;
   }
   return colour_depths[i].s;
}


static char *input_source_lister(int i, int *size)
{
   if (i < 0) {
      *size = sizeof input_sources / sizeof *input_sources;
      return NULL;
   }
   return input_sources[i];
}

static char *tileset_lister(int i, int *size)
{
   CTS_FILE_INFO *cts;
   
   if (i < 0) {
      *size = get_num_cts_files();
      return NULL;
   }
   cts = get_cts_info(i);
   return cts->name;
}

static char *starttile_lister(int i, int *size)
{
   CTS_FILE_INFO *cts;
   int n;
   int c;
   
   if (i < 0) {
      *size = 0;
      for (n=0; n<get_num_cts_files(); n++) {
         cts = get_cts_info(n);
         if (cts->num_start_tiles)
            (*size)++;
      }
      return NULL;
   }
   c = -1;
   for (n=0; n<get_num_cts_files(); n++) {
      cts = get_cts_info(n);
      if (cts->num_start_tiles) {
         c++;
      }
      if (c==i)
         break;
   }
   cts = get_cts_info(n);
   return cts->name;
}

/* Play button clicked sound */
static int play_button_sound(int msg, DIALOG *d, int c)
{
   if (msg==MSG_CLICK || msg==MSG_KEY) {
      play_sample(get_button_sample(), get_sfx_volume(), 127, 1000, FALSE);
   }

   return D_O_K;
}

/* Set the digital volume */
static int set_digivol_callback(void *dp3, int d2)
{
   set_sfx_volume((d2 > 31) ? 255 : (d2 * 8));
   play_button_sound(MSG_CLICK, NULL, 0);
   return D_O_K;
}

/* Set the music volume */
static int set_musicvol_callback(void *dp3, int d2)
{
   set_music_volume((d2 > 31) ? 255 : (d2 * 8));
   play_button_sound(MSG_CLICK, NULL, 0);
   return D_O_K;
}

/* Initialize the game options dialog boxes */
static void initialize_options_dialog(DIALOG *d)
{
   int c;

   for (c = 0; d[c].proc; c++) {
      d[c].x += (SCREEN_W - d[0].w) / 2;
      d[c].y += (SCREEN_H - d[0].h) / 2;
      d[c].fg = white;
      d[c].bg = -1;
      if ((d[c].proc == d_ctext_proc) || (d[c].proc == d_text_proc)) {
         d[c].dp2 = (FONT *)get_menu_bold_font();
      } else if (d[c].proc == d_gfxcheck_proc) {
         d[c].dp2 = get_cboxnch_bitmap();
         d[c].dp3 = get_cboxch_bitmap();
      } else if (d[c].proc == d_gfxradio_proc) {
         d[c].dp2 = get_obutnch_bitmap();
         d[c].dp3 = get_obutch_bitmap();
      } else if (d[c].proc == d_list_proc) {
         d[c].fg = black;
         d[c].bg = white;
      } else if (d[c].proc == d_checklist_proc) {
         d[c].fg = black;
         d[c].bg = white;
      } else if (d[c].proc == d_slider_proc) {
         d[c].dp = get_obutch_bitmap();
         d[c].bg = blue;
      } else if (d[c].proc == d_mbitmap_proc) {
         //d[c].dp = get_opt_frame_bitmap();
      } else if (d[c].proc == d_box_proc) {
         d[c].bg = black;
         d[c].fg = white;
      } else if (d[c].proc == d_ctextbut_agui_proc) {
         d[c].d1 = 0;
         d[c].dp2 = (FONT *)get_colour_font();
         d[c].dp3 = get_font_palette();
         d[c].h = text_height(font);
         d[c].fg = -1;
         d[c].bg = -1;
      }
   }
}

/* Initializes all dialog objects and prepares them for use in the current */
/*  screen mode */
void dialog_init(void)
{
   int c;

   for (c = 0; game_quit_dialog[c].proc; c++) {
      game_quit_dialog[c].x += SCREEN_W / 2;
      game_quit_dialog[c].y += SCREEN_H / 2;
      if (game_quit_dialog[c].proc == d_butgfx_agui_proc) {
         game_quit_dialog[c].dp2 = get_button_bitmap(2);
         game_quit_dialog[c].dp3 = play_button_sound;
         game_quit_dialog[c].fg = white;
         game_quit_dialog[c].bg = yellow;
      }
   }
   game_quit_dialog[1].dp2 = (FONT *)get_royal_font();
   game_quit_dialog[1].fg = black;
   game_quit_dialog[1].bg = -1;
   game_quit_dialog[0].dp = get_dframe_bitmap();
   game_quit_dialog[0].fg = black;
   game_quit_dialog[0].bg = -1;

   for (c = 0; main_menu_dialog[c].proc; c++) {
      main_menu_dialog[c].x += SCREEN_W / 2;
      main_menu_dialog[c].y += SCREEN_H / 2;
      if (main_menu_dialog[c].proc == d_ctextbut_agui_proc) {
         main_menu_dialog[c].d1 = 0;
         main_menu_dialog[c].dp2 = (FONT *)get_colour_font();
         main_menu_dialog[c].dp3 = get_font_palette();
         main_menu_dialog[c].fg = -1;
         main_menu_dialog[c].bg = -1;
      }
      if (main_menu_dialog[c].proc == d_butgfx_agui_proc) {
         main_menu_dialog[c].dp2 = get_button_bitmap(1);
         main_menu_dialog[c].dp3 = play_button_sound;
         main_menu_dialog[c].fg = white;
         main_menu_dialog[c].bg = yellow;
      }
   }

   for (c = 0; game_msg_dialog[c].proc; c++) {
      game_msg_dialog[c].x += SCREEN_W / 2;
      game_msg_dialog[c].y += SCREEN_H / 2;
      if (game_msg_dialog[c].proc == d_butgfx_agui_proc) {
         game_msg_dialog[c].dp2 = get_button_bitmap(0);
         game_msg_dialog[c].dp3 = play_button_sound;
         game_msg_dialog[c].fg = white;
         game_msg_dialog[c].bg = yellow;
      }
   }
   game_msg_dialog[0].dp = get_dframe_bitmap();
   game_msg_dialog[0].fg = black;
   game_msg_dialog[0].bg = grey;
   game_msg_dialog[1].fg = game_msg_dialog[2].fg = game_msg_dialog[3].fg =
      black;
   game_msg_dialog[1].bg = game_msg_dialog[2].bg = game_msg_dialog[3].bg = -1;

   /* game-menu dialog box */
   for (c = 0; game_menu_dialog[c].proc; c++) {
      game_menu_dialog[c].x += SCREEN_W / 2;
      game_menu_dialog[c].y += SCREEN_H / 2;
      if (game_menu_dialog[c].proc == d_butgfx_agui_proc) {
         game_menu_dialog[c].dp2 = get_button_bitmap(1);
         game_menu_dialog[c].dp3 = play_button_sound;
         game_menu_dialog[c].fg = white;
         game_menu_dialog[c].bg = yellow;
      }
   }
   game_menu_dialog[0].dp = get_alt_dframe_bitmap();
   game_menu_dialog[0].fg = black;
   game_menu_dialog[0].bg = grey;

   /* newgame-menu dialog box */
   for (c = 0; newgame_menu_dialog[c].proc; c++) {
      newgame_menu_dialog[c].x += SCREEN_W / 2;
      newgame_menu_dialog[c].y += SCREEN_H / 2;
      if (newgame_menu_dialog[c].proc == d_ctextbut_agui_proc) {
         newgame_menu_dialog[c].d1 = 0;
         newgame_menu_dialog[c].dp2 = (FONT *)get_colour_font();
         newgame_menu_dialog[c].dp3 = get_font_palette();
         newgame_menu_dialog[c].fg = -1;
         newgame_menu_dialog[c].bg = -1;
      }
      if (newgame_menu_dialog[c].proc == d_butgfx_agui_proc) {
         newgame_menu_dialog[c].dp2 = get_button_bitmap(1);
         newgame_menu_dialog[c].dp3 = play_button_sound;
         newgame_menu_dialog[c].fg = white;
         newgame_menu_dialog[c].bg = yellow;
      }
   }

   /* game option-menu dialog box */
   initialize_options_dialog(game_options_menu_dialog);
   centre_dialog(game_options_menu_dialog);
   
   /* Map-display dialog box */
   initialize_options_dialog(game_map_display_dialog);
   game_map_display_dialog[0].dp = get_opt_frame_bitmap();

   /* Password input dialog */
   initialize_options_dialog(string_input_dialog);

   /* network option-menu dialog box */
   initialize_options_dialog(game_network_options_dialog);
   game_network_options_dialog[3].dp2 =
      game_network_options_dialog[4].dp2 = 
         game_network_options_dialog[8].dp2 =(FONT *)get_colour_font();
   game_network_options_dialog[3].fg =
      game_network_options_dialog[4].fg = 
         game_network_options_dialog[8].fg = -1;
   game_network_options_dialog[6].fg = game_network_options_dialog[7].fg = black;
   game_network_options_dialog[6].bg = game_network_options_dialog[7].bg = white;
   
   /* Game settings */
   initialize_options_dialog(game_params_dialog);
   game_params_dialog[1].dp = get_opt_frame_bitmap();

   /* Prepare game video-options dialog box */
   initialize_options_dialog(game_video_options_dialog);
   game_video_options_dialog[3].dp2 =
      game_video_options_dialog[4].dp2 = (FONT *)get_colour_font();
   game_video_options_dialog[3].fg =
      game_video_options_dialog[4].fg = -1;

   /* Prepare game sound-options dialog box */
   initialize_options_dialog(game_sound_options_dialog);
   game_sound_options_dialog[9].dp2 = set_digivol_callback;
   game_sound_options_dialog[10].dp2 = set_musicvol_callback;
   game_sound_options_dialog[3].dp2 = (FONT *)get_colour_font();
   game_sound_options_dialog[3].fg = -1;

   /* Game menu button */
   game_butt->fg = white;
   game_butt->bg = yellow;
   game_butt->dp2 = get_button_bitmap(2);
   game_butt->dp3 = play_button_sound;
   game_butt->x += SCREEN_W;
   game_butt->y += SCREEN_H;

   cancel_butt->fg = white;
   cancel_butt->bg = yellow;
   cancel_butt->dp2 = get_button_bitmap(2);
   cancel_butt->dp3 = play_button_sound;
   cancel_butt->x += SCREEN_W;
   cancel_butt->y += SCREEN_H;
}

/* Custom dialog routines */

int d_gfxedit_proc(int msg, DIALOG *d, int c)
{
   int f, l, p, w, x, fg, b, scroll;
   char buf[16];
   char *s;

   if (msg==MSG_DRAW) {
      draw_sprite(screen, get_proind_bitmap(), d->x, d->y);

      s = d->dp;
      l = ustrlen(s);
      
      if (d->d2 > l) 
         d->d2 = l;

      /* calculate maximal number of displayable characters */
      if (d->d2 == l)  {
         usetc(buf+usetc(buf, ' '), 0);
         x = text_length(font, buf);
      } else {
         x = 0;
      }

      b = 0;

      for (p=d->d2; p>=0; p--) {
         usetc(buf+usetc(buf, ugetat(s, p)), 0);
         x += text_length(font, buf);
         b++;
         if (x > d->w) 
            break;
      }

      if (x <= d->w) {
         b = l; 
         scroll = FALSE;
      }  else {
         b--; 
         scroll = TRUE;
      }
      
      fg = d->fg;
      x = 0;
      if (scroll) {
         p = d->d2-b+1; 
         b = d->d2; 
      } else {
         p = 0;
      }
      
      for (; p<=b; p++) {
         f = ugetat(s, p);
         usetc(buf+usetc(buf, (f) ? f : ' '), 0);
         w = text_length(font, buf);
         if (x+w > d->w)
            break;
         f = ((p == d->d2) && (d->flags & D_GOTFOCUS));
         textout_ex(screen, font, buf, d->x+3+x, d->y+2, (f) ? 0 : fg, (f) ? fg : -1);
         x += w;
      }
      
      return D_O_K;
   }

   if (d->flags&D_DIRTY)
      return D_REDRAW;

   return d_edit_proc(msg, d, c);
}

int d_pwd_key_proc(int msg, DIALOG *d, int c)
{
   PALETTE p;
   if (msg==MSG_DRAW) {
      rectfill(screen, d->x, d->y, d->x + d->w-1, d->y + d->h-1, darkgreen);
      if (d->flags&D_GOTFOCUS) {
         rect(screen, d->x+1, d->y+1, d->x + d->w-2, d->y + d->h-2, red);
         shift_palette_hue(*get_font_palette(), p, DELTA_HUE);
         select_palette(p);
      } else {
         select_palette(*get_font_palette());
      }
      if (d->key!=8)    /* Backspace */
         textprintf_centre(screen, get_password_font(), d->x+d->w/2, d->y, -1, "%c", d->key);
      else
         textprintf_centre(screen, get_password_font(), d->x+d->w/2, d->y, -1, "<-");
      rect(screen, d->x, d->y, d->x + d->w-1, d->y + d->h-1, grey);
   }
   if (msg==MSG_WANTFOCUS) {
      return D_WANTFOCUS;
   }
   if (msg==MSG_CLICK||msg==MSG_KEY) {
      return D_CLOSE;
   }

   return D_O_K;
}

/* Doesn't exactly draw a button, but just the caption. However, it is */
/*  treated as a button. When selected, the colour from dp2 is used, */
/*  otherwise the colour from dp1. If dp2 is not NULL, then it will be */
/* interpreted as a font */
int d_textbut_agui_proc(int msg, DIALOG *d, int c)
{
   int fg;
   int state1, state2;

   FONT *used_font = font;

   if (d->flags & D_DISABLED)
      return D_O_K;

   if (msg==MSG_DRAW) {

      if (d->dp2)
         font = d->dp2;

      fg = (d->flags & D_DISABLED) ? gui_mg_color : d->fg;
      if (d->flags & D_GOTFOCUS) {
         state1 = d->bg;
         state2 = (d->flags & D_DISABLED) ? gui_mg_color : d->fg;
      } else {
         state1 = (d->flags & D_DISABLED) ? gui_mg_color : d->fg;
         state2 = d->bg;
      }

      text_mode(-1);
      /* Draw drop shadow under the text */
      gui_textout(get_monitor_bmp(), d->dp, d->x+d->w/2+1, d->y+d->h/2-text_height(font)/2+1, black, TRUE);
      gui_textout(get_monitor_bmp(), d->dp, d->x+d->w/2, d->y+d->h/2-text_height(font)/2, state1, TRUE);

      font = used_font;
      return D_O_K;
   }
   play_button_sound(msg, d, 0);
   return d_button_proc(msg, d, 0);
}


/* Similar to d_textbut_agui_proc, but it works with a coloured font */
/*  dp2 can hold a font structure                                    */
/*  dp3 holds the corresponding palette                              */
/*  d1 measures how far hue has been changed (0-100%)                */
/*  d2 holds the change in saturation (fixed)                        */
/* The palette is taken from dp2 or dp3 depending on wether it is selected */
/*  selected or not. */
int d_ctextbut_agui_proc(int msg, DIALOG *d, int c)
{
   int fg;
   FONT *used_font = font;
   PALETTE p1;
   PALETTE p2;

   if (msg==MSG_DRAW) {

      if (d->flags & D_GOTFOCUS || bitmap_color_depth(screen)!=8) {
         fg = d->bg;
      } else {
         fg = (d->flags & D_DISABLED) ? gui_mg_color : d->fg;
      }

      if (bitmap_color_depth(screen)!=8) {
         if (d->flags & D_DISABLED) {
            if (d->d1>-32) {
               d->d1-=4;
               d->flags|=D_DIRTY;
            }
            fade_interpolate(d->dp3, black_palette, p1, -d->d1, 0, 255);
            set_palette(p1);
         } else if (d->d1<0) {
            if (d->d1<0)
               d->d1+=4;
            fade_interpolate(d->dp3, black_palette, p1, -d->d1, 0, 255);
            set_palette(p1);
            d->flags|=D_DIRTY;
         } else if (d->flags & D_GOTFOCUS) {
            if (d->d1<64) {
               d->d1+=2;
               d->flags|=D_DIRTY;
            }
            shift_palette_hue(d->dp3, p2, DELTA_HUE);
            fade_interpolate(d->dp3, p2, p1, d->d1, 0, 255);
            set_palette(p1);
         } else {
            if (d->d1>0) {
               d->d1-=2;
               d->flags|=D_DIRTY;
            }
            shift_palette_hue(d->dp3, p2, DELTA_HUE);
            fade_interpolate(d->dp3, p2, p1, d->d1, 0, 255);
            set_palette(p1);
            //set_palette(d->dp3);
         }
      } else {
         if (d->flags & D_GOTFOCUS) {
            fg = yellow;
         } else {
            fg = (d->flags & D_DISABLED) ? gui_mg_color : white;
         }
      }

      if (d->dp2)
         font = d->dp2;

      text_mode(-1);
      /* Draw drop shadow under the text */
      gui_textout(get_monitor_bmp(), d->dp, d->x+d->w/2+1, d->y+d->h/2-text_height(font)/2+1, black, TRUE);
      gui_textout(get_monitor_bmp(), d->dp, d->x+d->w/2, d->y+d->h/2-text_height(font)/2, fg, TRUE);
      set_palette(d->dp3);
      
      font = used_font;
      return D_O_K;
   }

   if (d->flags & D_DISABLED)
      return D_O_K;

   play_button_sound(msg, d, 0);
   return d_button_proc(msg, d, 0);
}

/* Similar to d_text_proc, but draws the image in dp3 first */
int d_gfxtext_proc(int msg, DIALOG *d, int k)
{
   if ((msg == MSG_DRAW) && (d->dp3)) {
      BITMAP *bmp = d->dp3;

      blit(bmp, get_monitor_bmp(), 0, 0, d->x, d->y, bmp->w, bmp->h);
      //rect (get_monitor_bmp(), d->x, d->y, d->x+bmp->w, d->y+bmp->h,makecol(255,255,255));
   }
   if (d->dp)
      return d_text_proc(msg, d, k);
   else
      return D_O_K;
}

/* d_mbitmap_proc: wrapper for the allegro d_bitmap_proc function; fixes
   some compatibility issues. */
int d_mbitmap_proc(int msg, DIALOG *d, int c)
{
   BITMAP *b = (BITMAP *)d->dp;

   switch (msg) {
      case MSG_DRAW:
         if (b)
            masked_blit(b, get_monitor_bmp(), 0, 0, d->x, d->y, d->w, d->h);
         return D_O_K;
      case MSG_WANTFOCUS:
         return D_O_K;
      default:
         return D_O_K;
   }
}

/* d_tbitmap_proc: transparent bitmap. */
int d_tbitmap_proc(int msg, DIALOG *d, int c)
{
   BITMAP *b = (BITMAP *)d->dp;

   switch (msg) {
      case MSG_DRAW:
         if (b)
            masked_blit(b, get_monitor_bmp(), 0, 0, d->x, d->y, d->w, d->h);
         return D_O_K;
      case MSG_WANTFOCUS:
         return D_O_K;
      default:
         return D_O_K;
   }

}

/* Checkbox; conterary to the standard Allegro checkboxes, this doesn't */
/*  display any text string; the dp2&dp3 fields hold the graphics for the */
/*  chheckbox in checked and unchecked state respectively. */
int d_gfxcheck_proc(int msg, DIALOG *d, int c)
{
   BITMAP *bmp;

   if (msg == MSG_DRAW) {
      if (d->flags & D_SELECTED) {
         bmp = d->dp3;
      } else {
         bmp = d->dp2;
      }

      if (bmp) {
         if (d->flags & D_DISABLED)
            draw_lit_sprite(get_monitor_bmp(), bmp, d->x, d->y, 128);
         else
            draw_sprite(get_monitor_bmp(), bmp, d->x, d->y);
      }
      return D_O_K;
   }
   
   if (d->flags&D_DIRTY)
      return D_REDRAW;
   
   return d_check_proc(msg, d, c);
}

/* Radiobutton; conterary to the standard Allegro radiobuttons, this doesn't */
/*  display any text string; the dp2&dp3 fields hold the graphics for the */
/*  chheckbox in checked and unchecked state respectively. */
int d_gfxradio_proc(int msg, DIALOG *d, int c)
{
   BITMAP *bmp;

   if (msg == MSG_DRAW) {
      if (d->flags & D_SELECTED) {
         bmp = d->dp3;
      } else {
         bmp = d->dp2;
      }
      if (bmp) {
         if (d->flags & D_DISABLED)
            draw_lit_sprite(get_monitor_bmp(), bmp, d->x, d->y, 128);
         else
            draw_sprite(get_monitor_bmp(), bmp, d->x, d->y);
      }
      return D_O_K;
   }
   return d_radio_proc(msg, d, c);
}

/* Graphical button */
/* The bitmap should be passed in the dp2 field. If it is NULL, a normal
    button will be drawn instead. */
/* An optional callback function can be placed in the dp3 field that will be
    called when the button is clicked */
/* Draws a solid border in b->bg if the button is selected */
/* The graphic is stretched to the proper dimensions */
int d_butgfx_agui_proc(int msg, DIALOG *d, int c)
{
   int fg;
   int state1, state2;
   int g;
   BITMAP *bmp = d->dp2;
   BUTTCALLBACK callback = d->dp3;

   if (d->flags & D_DISABLED)
      return D_O_K;

   /* Draw normal button if no image preented */
   if (bmp == NULL)
      return d_button_proc(msg, d, 0);

   //d->w=bmp->w;
   //d->h=bmp->h;

   if (msg == MSG_DRAW) {
      if (d->flags & D_SELECTED) {
         g = 1;
         state1 = d->bg;
         state2 = (d->flags & D_DISABLED) ? gui_mg_color : d->fg;
      } else {
         g = 0;
         state1 = (d->flags & D_DISABLED) ? gui_mg_color : d->fg;
         state2 = d->bg;
      }

      /* Display graphic */
      //blit (bmp, get_monitor_bmp(), 0,0,d->x,d->y, bmp->w, bmp->h);
      stretch_blit(bmp, get_monitor_bmp(), 0, 0, bmp->w, bmp->h, d->x, d->y,
                   d->w, d->h);
      fg = (d->flags & D_DISABLED) ? gui_mg_color : d->fg;

      text_mode(-1);
      gui_textout(get_monitor_bmp(), d->dp, d->x + d->w / 2 + g,
                  d->y + d->h / 2 - (text_height(font) + 1) / 2 + g, state1,
                  TRUE);

      if ((d->flags & D_GOTFOCUS) &&
          (!(d->flags & D_SELECTED) || !(d->flags & D_EXIT)))
         rect(get_monitor_bmp(), d->x + 1 + g, d->y + 1 + g,
              d->x + d->w - 2 + g, d->y + d->h - 2 + g, state2);
      return D_O_K;
   } else {
   }

   if (callback) {
      callback(msg, d, c);
   }

   return d_button_proc(msg, d, 0);
}

/* Graphical button, incompatible with Allegro's GUI */
/* The bitmap should be passed in the dp2 field. If it is NULL, a normal
   button will be drawn instead. */
/* Draws a solid border in b->bg if the button is selected */
/* The graphic is stretched to the proper dimensions */
int d_butgfx_proc(int msg, DIALOG *d, int c)
{
   int fg;
   int state1, state2;
   int g;
   BITMAP *bmp = d->dp2;
   BUTTCALLBACK callback = d->dp3;

   if (d->flags & D_DISABLED)
      return D_O_K;

   /* Draw normal button if no image preented */
   if (bmp == NULL)
      return d_button_proc(msg, d, 0);

   //d->w=bmp->w;
   //d->h=bmp->h;

   if (msg == MSG_DRAW) {
      if (d->flags & D_SELECTED) {
         g = 1;
         state1 = d->bg;
         state2 = (d->flags & D_DISABLED) ? gui_mg_color : d->fg;
      } else {
         g = 0;
         state1 = (d->flags & D_DISABLED) ? gui_mg_color : d->fg;
         state2 = d->bg;
      }

      /* Display graphic */
      //blit (bmp, get_monitor_bmp(), 0,0,d->x,d->y, bmp->w, bmp->h);
      stretch_blit(bmp, get_screen_bmp(), 0, 0, bmp->w, bmp->h, d->x, d->y,
                   d->w, d->h);
      fg = (d->flags & D_DISABLED) ? gui_mg_color : d->fg;

      text_mode(-1);
      gui_textout(get_screen_bmp(), d->dp, d->x + d->w / 2 + g,
                  d->y + d->h / 2 - (text_height(font) + 1) / 2 + g, state1,
                  TRUE);

      if ((d->flags & D_GOTFOCUS) && !(d->flags & D_SELECTED))
         rect(get_screen_bmp(), d->x + 1 + g, d->y + 1 + g,
              d->x + d->w - 2 + g, d->y + d->h - 2 + g, state2);
      return D_O_K;
   } else {
   }

   if (callback) {
      callback(msg, d, c);
   }

   return d_button_proc(msg, d, 0);
}

/* Listbox that draws a graphical checkbox on the left */
int d_checklist_proc(int msg, DIALOG *d, int c)
{
   BITMAP *bmp;
   int height, listsize, i, len, bar, x, y, w;
   int fg_color, fg, bg;
   int res;
   int line_height;
   char *sel = d->dp2;
   char s[1024];
   
   /* typedef for the listbox callback functions */
   typedef char *(*getfuncptr)(int, int *);

   switch (msg) {
      case MSG_DRAW:
         (*(getfuncptr)d->dp)(-1, &listsize);
         
         bmp = get_cboxch_bitmap();
         line_height = MAX(bmp->h, text_height(font));
         line_height = text_height(font);
         height = (d->h-4) / line_height;
         bar = (listsize > height);
         w = (bar ? d->w-15 : d->w-3);
         fg_color = (d->flags & D_DISABLED) ? gui_mg_color : d->fg;

         /* draw box contents */
         for (i=0; i<height; i++) {
            if (d->d2+i < listsize) {
               if ((sel) && (sel[d->d2+i])) { 
                  bmp = get_cboxch_bitmap();
               } else {
                  bmp = get_cboxnch_bitmap();
	       }
               fg = fg_color;
               bg = d->bg;
               if (d->d2+i == d->d1) {
                  fg = blue;
               }


               ustrzcpy(s, sizeof(s), (*(getfuncptr)d->dp)(i+d->d2, NULL));
               x = d->x + 2;
               y = d->y + 2 + i*line_height;
               rectfill(screen, x, y, x+d->w-5, y+line_height-1, bg);
               x += 8;
               len = ustrlen(s);
               while (text_length(font, s) >= MAX(d->w-bmp->w - 1 - (bar ? 22 : 10), 1)) {
                  len--;
                  usetat(s, len, 0);
               }
               
               masked_blit(bmp, screen, 0,0, x, y-1, bmp->w, bmp->h);
               
               textout_ex(screen, font, s, x+bmp->w, y, fg, bg);
               x += text_length(font, s);
               if (x <= d->x+w) 
                  rectfill(screen, x+bmp->w, y, d->x+w, y+line_height-1, bg);
            } else {
               rectfill(screen, d->x+2,  d->y+2+i*line_height, 
                        d->x+w, d->y+1+(i+1)*line_height, d->bg);
            }
         }

         if (d->y+2+i*line_height <= d->y+d->h-3)
            rectfill(screen, d->x+2, d->y+2+i*line_height, 
                             d->x+w, d->y+d->h-3, d->bg);

	 /* draw frame, maybe with scrollbar */
	 _draw_scrollable_frame(d, listsize, d->d2, height, fg_color, d->bg);
         return D_O_K;

      case MSG_CLICK:
         d->dp2 = NULL;
         i = d->d1;
         res = d_list_proc(msg, d, c);
         d->dp2 = sel;
         if (i==d->d1)
            sel[i] = !sel[i];
         d->flags |= D_DIRTY;
         return res;

      case MSG_DCLICK:
         return D_O_K;
   }

   return d_list_proc(msg, d, c);
}

/* Transparent button compatible with the Allegro GUI */
/*  *dp3 should be the background of the previous blit or NULL  */
/*  If it is the previous background, it will be blit at the MSG_DRAW, */
/*   and destroyed; oherwise it will be ignored */
/* This will outline the bitmap when the box is selected (normal routine */
/*  simply draws a box; this is more tricky) */
int d_tbutgfx_agui_proc(int msg, DIALOG *d, int c)
{
   int fg;
   int state1, state2;
   int g;
   BITMAP *bmp = d->dp2;
   BITMAP *bgbmp = d->dp3;

   if (d->flags & D_DISABLED)
      return D_O_K;

   /* Draw normal button if no image preented */
   if (bmp == NULL)
      return d_button_proc(msg, d, 0);

   d->w = bmp->w;
   d->h = bmp->h;

   if (msg == MSG_DRAW) {
      /* Restore background */
      if (bgbmp) {
         blit(bgbmp, get_monitor_bmp(), 0, 0, d->x, d->y, bgbmp->w, bgbmp->h);
         destroy_bitmap(bgbmp);
         bgbmp = d->dp3 = NULL;
      }
      fg = (d->flags & D_DISABLED) ? gui_mg_color : d->fg;
      if ((d->flags & D_GOTFOCUS) &&
          (!(d->flags & D_SELECTED) || !(d->flags & D_EXIT))) {
         /* Outline the bitmap */
         bmp = outline_bitmap(bmp, d->bg);
         /* Store background */
         d->dp3 = bgbmp =
            create_bitmap_ex(bitmap_color_depth(get_monitor_bmp()), bmp->w,
                             bmp->h);
         blit(get_monitor_bmp(), bgbmp, d->x, d->y, 0, 0, bgbmp->w, bgbmp->h);
      }
      if (d->flags & D_SELECTED) {
         g = 1;
         state1 = d->bg;
         state2 = (d->flags & D_DISABLED) ? gui_mg_color : d->fg;
      } else {
         g = 0;
         state1 = (d->flags & D_DISABLED) ? gui_mg_color : d->fg;
         state2 = d->bg;
      }

      /* Display graphic */
      masked_blit(bmp, get_monitor_bmp(), 0, 0, d->x, d->y, bmp->w, bmp->h);

      text_mode(-1);
      gui_textout(get_monitor_bmp(), d->dp, d->x + d->w / 2 + g,
                  d->y + d->h / 2 - text_height(font) / 2 + g, state1, TRUE);

      /* Destroy bitmap if needed */
      if (bmp != d->dp2)
         destroy_bitmap(bmp);
      return D_O_K;
   } else if (msg == MSG_END) {
      /* Free background memory if needed */
      if (bgbmp) {
         destroy_bitmap(bgbmp);
         bgbmp = d->dp3 = NULL;
      }
   }

   return d_button_proc(msg, d, 0);
}

int d_gamemusic_proc(int msg, DIALOG *d, int c)
{
   if (msg == MSG_IDLE || msg == MSG_START) {
      cycle_game_music();
   }
   return D_O_K;
}

/* Screenshot capture rourine */
int d_scrnshot_proc(void)
{
   screenshot();
   return D_O_K;
}

/* Small popup dialog box with a one-line message; layout appropriate for */
/*  the game */
void game_message(char *msg, ...)
{
   FONT *f = font;
   char *s = malloc(4096);
   char *l1 = NULL;
   char *l2 = NULL;
   char *l3 = NULL;
   int c;

   va_list ap;

   va_start(ap, msg);
   uvsprintf(s, msg, ap);
   va_end(ap);

   l1 = s;
   l2 = strstr(l1, "\n");
   if (l2) {
      l2[0] = '\0';
      l2++;

      l3 = strstr(l2, "\n");
      if (l3) {
         l3[0] = '\0';
         l3++;
      }
   }
   if (l1)
      game_msg_dialog[1].dp = l1;
   else
      game_msg_dialog[1].dp = "";
   if (l2)
      game_msg_dialog[2].dp = l2;
   else
      game_msg_dialog[2].dp = "";
   if (l3)
      game_msg_dialog[3].dp = l3;
   else
      game_msg_dialog[3].dp = "";

   for (c = 1; c < 4; c++) {
      game_msg_dialog[c].dp2 = (FONT *)get_menu_bold_font();
   }

   font = (FONT *)get_menu_font();
   popup_dialog(game_msg_dialog, -1);
   font = f;

   free(s);
   //synchronize();
}

/* Basically, this is a wrapper for the Allegro Alert() dialog box */
void popup_message(char *msg, ...)
{
   char *s = malloc(4096);
   char *l1 = NULL;
   char *l2 = NULL;
   char *l3 = NULL;
   int old_fg;
   int old_bg;
   PALETTE p;

   va_list ap;

   va_start(ap, msg);
   uvsprintf(s, msg, ap);
   va_end(ap);

   l1 = s;
   l2 = strstr(l1, "\n");
   if (l2) {
      l2[0] = '\0';
      l2++;

      l3 = strstr(l2, "\n");
      if (l3) {
         l3[0] = '\0';
         l3++;
      }
   }
   old_fg = gui_fg_color;
   old_bg = gui_bg_color;
   if (bitmap_color_depth(screen) == 8) {
      get_palette(p);
      if ((p[gui_fg_color].r == p[gui_bg_color].r)
          && (p[gui_fg_color].g == p[gui_bg_color].g)
          && (p[gui_fg_color].b == p[gui_bg_color].b))
         set_palette(default_palette);
   } else {
      gui_fg_color = makecol_depth(bitmap_color_depth(screen), 0, 0, 0);
      gui_bg_color = makecol_depth(bitmap_color_depth(screen), 192, 192, 192);
   }
   alert(l1, l2, l3, "Ok", NULL, 0, 0);
   if (bitmap_color_depth(screen) == 8)
      set_palette(p);
   gui_fg_color = old_fg;
   gui_bg_color = old_bg;
   free(s);
}

/* Input password. password should be a buffer large enough for 16 characters */
/*  Returns TRUE if ok'd, false if canceled. */
int get_password(char *password)
{
   BITMAP *bmp;
   int res;
   int focus = 5;

   string_input_dialog[4].dp = password;
   string_input_dialog[4].dp2 = (FONT *)get_password_font();
   string_input_dialog[4].d1 = 16;
   string_input_dialog[4].d2 = 0;

   string_input_dialog[4].fg = -1;
   string_input_dialog[4].bg = makecol(32,32,32);

   string_input_dialog[3].fg = grey;
   string_input_dialog[3].bg = makecol(32,32,32);

   bmp = create_bitmap(string_input_dialog[0].w, string_input_dialog[0].h);
   blit (screen, bmp, string_input_dialog[0].x, string_input_dialog[0].y, 0,0,string_input_dialog[0].w, string_input_dialog[0].h);

   do {
      res = do_dialog(string_input_dialog, focus);
      focus = find_dialog_focus(string_input_dialog);
      if (strlen(password)<16 && (res>=5)) {
         if (string_input_dialog[res].key==8 && strlen(password)) {
            password[strlen(password)-1] = '\0';
         } else {
            if (key_shifts&KB_SHIFT_FLAG) {
               sprintf(password, "%s%c", password, toupper(string_input_dialog[res].key));
            } else {
               sprintf(password, "%s%c", password, string_input_dialog[res].key);
            }
         }
         rest(20);
      }
      if (strlen(password)==16)
         focus = 1;
   } while(res>4);

   blit (bmp, screen, 0,0, string_input_dialog[0].x, string_input_dialog[0].y, string_input_dialog[0].w, string_input_dialog[0].h);
   destroy_bitmap(bmp);

   return res==1;
}

/* Handle the network-options */
void popup_network_options(char *server_ip, char *playername, int *conntype)
{
   FONT *f;
   const char *s;

   f = font;
   font = (FONT *)get_menu_font();

   /* Read values from config file */
   s = get_config_string("network", "server", NULL);
   if (s) {
      snprintf(server_ip, 255, "%s", s);
   }

   s = get_config_string("network", "nickname", NULL);
   if (s) {
      snprintf(playername, 64, "%s", s);
   }
   
   game_network_options_dialog[5].d1 = get_config_int("network", "type", 2);
   
   /* Initialize the dialog structure */
   game_network_options_dialog[6].dp = server_ip;
   game_network_options_dialog[6].d1 = 255;
   game_network_options_dialog[6].d2 = strlen(server_ip);
   
   game_network_options_dialog[7].dp = playername;
   game_network_options_dialog[7].d1 = 255;
   game_network_options_dialog[7].d2 = strlen(playername);

   /* Get the new results if dialog is ok'ed */
   if (popup_dialog(game_network_options_dialog, -1) == 1) {
      *conntype = game_network_options_dialog[5].d1;
   } else {
      *conntype = -1;
   }
   font = f;

   /* Save values to config file */   
   set_config_string("network", "server", server_ip);
   set_config_string("network", "nickname", playername);
   set_config_int("network", "type", *conntype);
}

/* Handle the game-options */
static void popup_video_options(void)
{
   int win = settings.flags & WINDOWED_MODE;
   int c;
   FONT *f;

   f = font;
   font = (FONT *)get_menu_font();

   win = get_config_int("video", "windowed", win);

   /* Disable all checkboxes and radio buttons */
   for (c = 0; game_video_options_dialog[c].proc; c++) {
      if ((game_video_options_dialog[c].proc == d_gfxradio_proc) ||
          (game_video_options_dialog[c].proc == d_gfxcheck_proc))
         game_video_options_dialog[c].flags &= ~D_SELECTED;
   }

#ifdef ALLEGRO_DOS
   /* Under DOS, the `run in windowed-mode' should NEVER be enabled: the */
   /*  game will be unable to load because it can't find a windowed driver */
   game_video_options_dialog[14].flags |= D_DISABLED;
#else
   if (win)
      game_video_options_dialog[14].flags |= D_SELECTED;
#endif

   if (settings.flags & HARD_SCROLLING) {
      game_video_options_dialog[13].flags |= D_SELECTED;
   } else {
      game_video_options_dialog[13].flags &= ~D_SELECTED;
   }
   game_video_options_dialog[13].flags |= D_DISABLED;

   if (settings.flags & USE_RLES) {
      game_video_options_dialog[12].flags |= D_SELECTED;
   } else {
      game_video_options_dialog[12].flags &= ~D_SELECTED;
   }

   if (settings.flags & USE_BMPS) {
      game_video_options_dialog[11].flags |= D_SELECTED;
   } else {
      game_video_options_dialog[11].flags &= ~D_SELECTED;
   }

   for (c=0; c < sizeof colour_depths / sizeof *colour_depths; c++) {
      if (colour_depths[c].depth == settings.colour_depth) {
         game_video_options_dialog[10].d1 = c;
      }
   }

   for (c=0; c < sizeof resolutions / sizeof *resolutions; c++) {
      if ((resolutions[c].w == settings.width) && (resolutions[c].h == settings.height)) {
         game_video_options_dialog[9].d1 = c;
      }
   }

   /* Get the new results if dialog is ok'ed */
   if (popup_dialog(game_video_options_dialog, -1) == 1) {


      if ((game_video_options_dialog[14].flags & D_SELECTED) != 0) {
         settings.flags |= WINDOWED_MODE;
      } else {
         settings.flags &= ~WINDOWED_MODE;
      }

      if ((game_video_options_dialog[13].flags & D_SELECTED) != 0) {
         settings.flags |= HARD_SCROLLING;
      } else {
         settings.flags &= ~HARD_SCROLLING;
      }

      if ((game_video_options_dialog[12].flags & D_SELECTED) != 0) {
         settings.flags |= USE_RLES;
      } else {
         settings.flags &= ~USE_RLES;
      }

      if ((game_video_options_dialog[11].flags & D_SELECTED) != 0) {
         settings.flags |= USE_BMPS;
      } else {
         settings.flags &= ~USE_BMPS;
      }

      set_config_int("video", "gouraud_shading", (settings.flags & LIT_GOURAUD)==LIT_GOURAUD);
      set_config_int("video", "windowed", (settings.flags & WINDOWED_MODE)==WINDOWED_MODE);

      set_config_int("video", "rle", (settings.flags & USE_RLES)==USE_RLES);
      set_config_int("video", "bmp", (settings.flags & USE_BMPS)==USE_BMPS);
      set_config_int("video", "scroll", (settings.flags & HARD_SCROLLING)==HARD_SCROLLING);
      set_config_int("video", "windowed", (settings.flags & WINDOWED_MODE)==WINDOWED_MODE);

      c = game_video_options_dialog[10].d1;
      set_config_int("video", "depth", colour_depths[c].depth);

      c = game_video_options_dialog[9].d1;
      set_config_int("video", "width", resolutions[c].w);
      set_config_int("video", "height", resolutions[c].h);

   }
   font = f;
}

static void popup_sound_options(void)
{
   int digivol = get_sfx_volume();
   int musicvol = get_music_volume();
   char *digmidfile = malloc(1024);
   char *gamedir = malloc(1024);

   get_current_dir(gamedir, 1024);
   fix_filename_case(gamedir);
   fix_filename_slashes(gamedir);
   put_backslash(gamedir);

   uszprintf (digmidfile, 1024, "%s%s", gamedir, "digmid.dat");

   //file_select_ex("Specify patch set", digmidfile, "dat", 1024, 0, 0);

   game_sound_options_dialog[9].d2 =
      digivol * game_sound_options_dialog[9].d1 / 255;
   game_sound_options_dialog[10].d2 =
      musicvol * game_sound_options_dialog[10].d1 / 255;

   if (get_config_id("sound", "midi_card", -1) == MIDI_DIGMID) {
      game_sound_options_dialog[11].flags |= D_SELECTED;
   } else {
      game_sound_options_dialog[11].flags &= ~D_SELECTED;
   }

   if (!exists(digmidfile)) {
      game_sound_options_dialog[11].flags |= D_DISABLED;
   } else {
      game_sound_options_dialog[11].flags &= ~D_DISABLED;
   }

   if (popup_dialog(game_sound_options_dialog, -1) == 1) {
      digivol = get_digi_volume();
//         game_sound_options_dialog[9].d2 * 255 /
//         game_sound_options_dialog[9].d1;
      musicvol = get_music_volume();
//         game_sound_options_dialog[10].d2 * 255 /
//         game_sound_options_dialog[10].d1;

      set_config_int("sound", "digi_volume", digivol);
      set_config_int("sound", "midi_volume", musicvol);

      if (!(game_sound_options_dialog[11].flags & D_DISABLED)) {
         if (game_sound_options_dialog[11].flags & D_SELECTED) {
            if (get_config_id("sound", "midi_card", -1) != MIDI_DIGMID) {
               set_config_id("sound", "midi_card", MIDI_DIGMID);
               set_config_string("sound", "patches", digmidfile);
               //pause_music();
               remove_sound();
               install_sound(DIGI_AUTODETECT, MIDI_AUTODETECT, NULL);
               //resume_music();
            }
         } else {
            if (get_config_id("sound", "midi_card", -1) == MIDI_DIGMID) {
               set_config_id("sound", "midi_card", MIDI_AUTODETECT);
               //pause_music();
               remove_sound();
               install_sound(DIGI_AUTODETECT, MIDI_AUTODETECT, NULL);
               //resume_music();
            }
         }
      }
   }

   set_sfx_volume(digivol);
   set_music_volume(musicvol);

   free (gamedir);
   free (digmidfile);
}

static void popup_theme_options(void)
{
   char fname[1024];
   char *s;
   FONT *fnt;
   
   s = get_config_string("game", "theme", "deftheme.dat");
   snprintf(fname, sizeof fname / sizeof *fname, "%s", s);
   
   fnt = font;
   font = (FONT *)get_menu_font();
   if (file_select_ex("Select theme file", fname, "dat", sizeof fname, 480, 320)) {
      set_config_string("game", "theme", fname);
   }
   font = fnt;
}

void popup_options(void)
{
   FONT *f;
   int (res);

   f = font;
   font = (FONT *)get_small_font();

   do {
      res = popup_dialog(game_options_menu_dialog, -1);
      switch (res) {
         case -1:
         case 5:
            return;
         case 1:
            popup_video_options();
            break;
         case 2:
            popup_sound_options();
         case 3:
            popup_theme_options();
            break;
         default:
            break;
      }
   } while (res != 5);

   font = f;
}

/* Popup the game quit dialog, and returns TRUE if the dialog is ok'ed */
int popup_game_quit_dialog(void)
{
   return popup_dialog(game_quit_dialog, 3) == 2;
}

/* Popup the in-game menu and return the requested action */
int popup_ingame_menu(void)
{
   return popup_dialog(game_menu_dialog, -1);
}

/* Game dialog popup routine; basically a wrapper around Allegro's functions */
/*  allows for non-blocking dialogs */
int game_popup_dialog(DIALOG *dialog, int focus_obj, int block)
{
   int ret = -1;

   if (!player) {

      player_bmp = create_bitmap(dialog->w+1, dialog->h+1);

      if (player_bmp) {
         scare_mouse();
         blit(screen, player_bmp, dialog->x, dialog->y, 0, 0, dialog->w+1, dialog->h+1);
         unscare_mouse();
      } else {
         *allegro_errno = ENOMEM;
      }

      player = init_dialog(dialog, focus_obj);
      player_dialog = dialog;

      if (block) {
         while (update_dialog(player));
         ret = shutdown_dialog(player);
         player = NULL;

         if (player_bmp) {
            scare_mouse();
            blit(player_bmp, screen, 0, 0, dialog->x, dialog->y, dialog->w+1, dialog->h+1);
            unscare_mouse();
            destroy_bitmap(player_bmp);
         }
      } else {
         update_dialog(player);
//         bmp = create_bitmap(dialog->w+1, dialog->h+1);
//         scare_mouse_area(dialog->x, dialog->y, dialog->x+dialog->w, dialog->y+dialog->h);
//         blit(screen, bmp, dialog->x, dialog->y, 0, 0, dialog->w+1, dialog->h+1);
//         unscare_mouse();
//         make_floatwin(dialog->x, dialog->y, dialog->w, dialog->h, FWIN_DIALOG, 0, NULL, bmp);
      }

   }

   return ret;
}

int game_update_dialog(void)
{
   int ret = 0;
//   FLOATWIN *fwin = find_floatwin(FWIN_DIALOG);

   if ((player && !update_dialog(player)) || settings.window_close_button) {
     ret = shutdown_dialog(player);
     player = NULL;

     if (player_bmp) {
        scare_mouse();
        blit(player_bmp, screen, 0, 0, player_dialog->x, player_dialog->y, player_dialog->w+1, player_dialog->h+1);
        unscare_mouse();
        destroy_bitmap(player_bmp);
//        set_lifetime(fwin, 1);
     }
   }
   return ret;
}

int game_close_dialog(void)
{
   int ret;
   
   if (!player)
      return 0;
   
   ret = shutdown_dialog(player);
   player = NULL;
   
   if (player_bmp) {
      scare_mouse();
      blit(player_bmp, screen, 0, 0, player_dialog->x, player_dialog->y, player_dialog->w+1, player_dialog->h+1);
      unscare_mouse();
      destroy_bitmap(player_bmp);
   }
   return ret;
}

/* Returns TRUE if there is an open dialog */
int dialog_open(void)
{
   if (player)
      return TRUE;
   else
      return FALSE;
}

/* Return x location of currently open dialog */
int get_dialog_x(void)
{
   ASSERT(player);
   return player_dialog->x;
}

/* Return y location of currently open dialog */
int get_dialog_y(void)
{
   ASSERT(player);
   return player_dialog->y;
}

/* Return width of currently open dialog */
int get_dialog_w(void)
{
   ASSERT(player);
   return player_dialog->w;
}

/* Return height of currently open dialog */
int get_dialog_h(void)
{
   ASSERT(player);
   return player_dialog->h;
}
