diff options
Diffstat (limited to 'src/setup')
30 files changed, 5602 insertions, 0 deletions
diff --git a/src/setup/.gitignore b/src/setup/.gitignore new file mode 100644 index 00000000..f41d11c7 --- /dev/null +++ b/src/setup/.gitignore @@ -0,0 +1,7 @@ +Makefile.in +Makefile +.deps +setup-manifest.xml +*.rc +tags +TAGS diff --git a/src/setup/Makefile.am b/src/setup/Makefile.am new file mode 100644 index 00000000..7fe051ee --- /dev/null +++ b/src/setup/Makefile.am @@ -0,0 +1,42 @@ + +gamesdir = $(prefix)/games + +AM_CFLAGS = @SDL_CFLAGS@ \ + @SDLMIXER_CFLAGS@ \ + -I$(top_builddir)/textscreen -I.. + +noinst_LIBRARIES = libsetup.a + +SOURCE_FILES = \ + compatibility.c compatibility.h \ + display.c display.h \ + joystick.c joystick.h \ + keyboard.c keyboard.h \ + mainmenu.c \ + mode.c mode.h \ + mouse.c mouse.h \ + multiplayer.c multiplayer.h \ + sound.c sound.h \ + execute.c execute.h \ + txt_joybinput.c txt_joybinput.h \ + txt_keyinput.c txt_keyinput.h \ + txt_mouseinput.c txt_mouseinput.h + +libsetup_a_SOURCES = $(SOURCE_FILES) + +EXTRA_DIST= \ + setup_icon.c + +appdir = $(prefix)/share/applications +app_DATA = @PROGRAM_PREFIX@setup.desktop + +@PROGRAM_PREFIX@setup.desktop : setup.desktop + cp $^ $@ + +if HAVE_PYTHON + +setup_icon.c : $(top_builddir)/data/setup8.ico + $(top_builddir)/data/convert-icon $^ $@ + +endif + diff --git a/src/setup/compatibility.c b/src/setup/compatibility.c new file mode 100644 index 00000000..722088e8 --- /dev/null +++ b/src/setup/compatibility.c @@ -0,0 +1,57 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// Copyright(C) 2006 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +// 02111-1307, USA. +// + +// Sound control menu + +#include <stdlib.h> + +#include "m_config.h" +#include "textscreen.h" +#include "mode.h" + +#include "compatibility.h" + +int vanilla_savegame_limit = 1; +int vanilla_demo_limit = 1; + +void CompatibilitySettings(void) +{ + txt_window_t *window; + + window = TXT_NewWindow("Compatibility"); + + TXT_AddWidgets(window, + TXT_NewCheckBox("Vanilla savegame limit", + &vanilla_savegame_limit), + TXT_NewCheckBox("Vanilla demo limit", + &vanilla_demo_limit), + NULL); +} + +void BindCompatibilityVariables(void) +{ + if (gamemission == doom) + { + M_BindVariable("vanilla_savegame_limit", &vanilla_savegame_limit); + M_BindVariable("vanilla_demo_limit", &vanilla_demo_limit); + } +} + diff --git a/src/setup/compatibility.h b/src/setup/compatibility.h new file mode 100644 index 00000000..386a4798 --- /dev/null +++ b/src/setup/compatibility.h @@ -0,0 +1,29 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// Copyright(C) 2006 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +// 02111-1307, USA. +// + +#ifndef SETUP_COMPATIBILITY_H +#define SETUP_COMPATIBILITY_H + +void CompatibilitySettings(void); +void BindCompatibilityVariables(void); + +#endif /* #ifndef SETUP_COMPATIBILITY_H */ + diff --git a/src/setup/display.c b/src/setup/display.c new file mode 100644 index 00000000..72f3c057 --- /dev/null +++ b/src/setup/display.c @@ -0,0 +1,826 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// Copyright(C) 2006 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +// 02111-1307, USA. +// + +#include <stdlib.h> +#include <string.h> + +#ifdef _WIN32_WCE +#include "libc_wince.h" +#endif + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +#endif + +#include "textscreen.h" +#include "m_config.h" +#include "mode.h" + +#include "display.h" + +extern void RestartTextscreen(void); + +typedef struct +{ + char *description; + int bpp; +} pixel_depth_t; + +// List of supported pixel depths. + +static pixel_depth_t pixel_depths[] = +{ + { "8-bit", 8 }, + { "16-bit", 16 }, + { "24-bit", 24 }, + { "32-bit", 32 }, +}; + +// List of strings containing supported pixel depths. + +static char **supported_bpps; +static int num_supported_bpps; + +typedef struct +{ + int w, h; +} screen_mode_t; + +// List of aspect ratio-uncorrected modes + +static screen_mode_t screen_modes_unscaled[] = +{ + { 320, 200 }, + { 640, 400 }, + { 960, 600 }, + { 1280, 800 }, + { 1600, 1000 }, + { 0, 0}, +}; + +// List of aspect ratio-corrected modes + +static screen_mode_t screen_modes_scaled[] = +{ + { 256, 200 }, + { 320, 240 }, + { 512, 400 }, + { 640, 480 }, + { 800, 600 }, + { 960, 720 }, + { 1024, 800 }, + { 1280, 960 }, + { 1280, 1000 }, + { 1600, 1200 }, + { 0, 0}, +}; + +// List of fullscreen modes generated at runtime + +static screen_mode_t *screen_modes_fullscreen = NULL; +static int num_screen_modes_fullscreen; + +static int vidmode = 0; + +static char *video_driver = ""; +static int autoadjust_video_settings = 1; +static int aspect_ratio_correct = 1; +static int fullscreen = 1; +static int screen_width = 320; +static int screen_height = 200; +static int screen_bpp = 8; +static int startup_delay = 1000; +static int graphical_startup = 1; +static int show_endoom = 1; +static int usegamma = 0; + +// These are the last screen width/height values that were chosen by the +// user. These are used when finding the "nearest" mode, so when +// changing the fullscreen / aspect ratio options, the setting does not +// jump around. + +static int selected_screen_width = 0, selected_screen_height; + +// Index into the supported_bpps of the selected pixel depth. + +static int selected_bpp = 0; + +static int system_video_env_set; + +// Set the SDL_VIDEODRIVER environment variable + +void SetDisplayDriver(void) +{ + static int first_time = 1; + + if (first_time) + { + system_video_env_set = getenv("SDL_VIDEODRIVER") != NULL; + + first_time = 0; + } + + // Don't override the command line environment, if it has been set. + + if (system_video_env_set) + { + return; + } + + // Use the value from the configuration file, if it has been set. + + if (strcmp(video_driver, "") != 0) + { + char *env_string; + + env_string = malloc(strlen(video_driver) + 30); + sprintf(env_string, "SDL_VIDEODRIVER=%s", video_driver); + putenv(env_string); + free(env_string); + } + else + { +#if defined(_WIN32) && !defined(_WIN32_WCE) + // On Windows, use DirectX over windib by default. + + putenv("SDL_VIDEODRIVER=directx"); +#endif + } +} + +// Query SDL as to whether any fullscreen modes are available for the +// specified pixel depth. + +static int PixelDepthSupported(int bpp) +{ + SDL_PixelFormat format; + SDL_Rect **modes; + + format.BitsPerPixel = bpp; + format.BytesPerPixel = (bpp + 7) / 8; + + modes = SDL_ListModes(&format, SDL_FULLSCREEN); + + return modes != NULL; +} + +// Query SDL and populate the supported_bpps array. + +static void IdentifyPixelDepths(void) +{ + unsigned int i; + unsigned int num_depths = sizeof(pixel_depths) / sizeof(*pixel_depths); + + if (supported_bpps != NULL) + { + free(supported_bpps); + } + + supported_bpps = malloc(sizeof(char *) * num_depths); + num_supported_bpps = 0; + + // Check each bit depth to determine if modes are available. + + for (i = 0; i < num_depths; ++i) + { + // If modes are available, add this bit depth to the list. + + if (PixelDepthSupported(pixel_depths[i].bpp)) + { + supported_bpps[num_supported_bpps] = pixel_depths[i].description; + ++num_supported_bpps; + } + } + + // No supported pixel depths? That's kind of a problem. Add 8bpp + // as a fallback. + + if (num_supported_bpps == 0) + { + supported_bpps[0] = pixel_depths[0].description; + ++num_supported_bpps; + } +} + +// Get the screen pixel depth corresponding to what selected_bpp is set to. + +static int GetSelectedBPP(void) +{ + unsigned int num_depths = sizeof(pixel_depths) / sizeof(*pixel_depths); + unsigned int i; + + // Find which pixel depth is selected, and set screen_bpp. + + for (i = 0; i < num_depths; ++i) + { + if (pixel_depths[i].description == supported_bpps[selected_bpp]) + { + return pixel_depths[i].bpp; + } + } + + // Default fallback value. + + return 8; +} + +// Get the index into supported_bpps of the specified pixel depth string. + +static int GetSupportedBPPIndex(char *description) +{ + unsigned int i; + + for (i = 0; i < num_supported_bpps; ++i) + { + if (supported_bpps[i] == description) + { + return i; + } + } + + return -1; +} + +// Set selected_bpp to match screen_bpp. + +static int TrySetSelectedBPP(void) +{ + unsigned int num_depths = sizeof(pixel_depths) / sizeof(*pixel_depths); + unsigned int i; + + // Search pixel_depths, find the bpp that corresponds to screen_bpp, + // then set selected_bpp to match. + + for (i = 0; i < num_depths; ++i) + { + if (pixel_depths[i].bpp == screen_bpp) + { + selected_bpp = GetSupportedBPPIndex(pixel_depths[i].description); + + if (selected_bpp >= 0) + { + return 1; + } + } + } + + return 0; +} + +static void SetSelectedBPP(void) +{ + const SDL_VideoInfo *info; + + if (TrySetSelectedBPP()) + { + return; + } + + // screen_bpp does not match any supported pixel depth. Query SDL + // to find out what it recommends using. + + info = SDL_GetVideoInfo(); + + if (info != NULL && info->vfmt != NULL) + { + screen_bpp = info->vfmt->BitsPerPixel; + } + + // Try again. + + if (!TrySetSelectedBPP()) + { + // Give up and just use the first in the list. + + selected_bpp = 0; + screen_bpp = GetSelectedBPP(); + } +} + +static void ModeSelected(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(mode)) +{ + TXT_CAST_ARG(screen_mode_t, mode); + + screen_width = mode->w; + screen_height = mode->h; + + // This is now the most recently selected screen width + + selected_screen_width = screen_width; + selected_screen_height = screen_height; +} + +static int GoodFullscreenMode(screen_mode_t *mode) +{ + int w, h; + + w = mode->w; + h = mode->h; + + // 320x200 and 640x400 are always good (special case) + + if ((w == 320 && h == 200) || (w == 640 && h == 400)) + { + return 1; + } + + // Special case: 320x240 letterboxed mode is okay (but not aspect + // ratio corrected 320x240) + + if (w == 320 && h == 240 && !aspect_ratio_correct) + { + return 1; + } + + // Ignore all modes less than 640x480 + + return w >= 640 && h >= 480; +} + +// Build screen_modes_fullscreen + +static void BuildFullscreenModesList(void) +{ + SDL_PixelFormat format; + SDL_Rect **modes; + screen_mode_t *m1; + screen_mode_t *m2; + screen_mode_t m; + int num_modes; + int i; + + // Free the existing modes list, if one exists + + if (screen_modes_fullscreen != NULL) + { + free(screen_modes_fullscreen); + } + + // Get a list of fullscreen modes and find out how many + // modes are in the list. + + format.BitsPerPixel = screen_bpp; + format.BytesPerPixel = (screen_bpp + 7) / 8; + + modes = SDL_ListModes(&format, SDL_FULLSCREEN); + + if (modes == NULL || modes == (SDL_Rect **) -1) + { + num_modes = 0; + } + else + { + for (num_modes=0; modes[num_modes] != NULL; ++num_modes); + } + + // Build the screen_modes_fullscreen array + + screen_modes_fullscreen = malloc(sizeof(screen_mode_t) * (num_modes + 1)); + + for (i=0; i<num_modes; ++i) + { + screen_modes_fullscreen[i].w = modes[i]->w; + screen_modes_fullscreen[i].h = modes[i]->h; + } + + screen_modes_fullscreen[i].w = 0; + screen_modes_fullscreen[i].h = 0; + + // Reverse the order of the modes list (smallest modes first) + + for (i=0; i<num_modes / 2; ++i) + { + m1 = &screen_modes_fullscreen[i]; + m2 = &screen_modes_fullscreen[num_modes - 1 - i]; + + memcpy(&m, m1, sizeof(screen_mode_t)); + memcpy(m1, m2, sizeof(screen_mode_t)); + memcpy(m2, &m, sizeof(screen_mode_t)); + } + + num_screen_modes_fullscreen = num_modes; +} + +static int FindBestMode(screen_mode_t *modes) +{ + int i; + int best_mode; + int best_mode_diff; + int diff; + + best_mode = -1; + best_mode_diff = 0; + + for (i=0; modes[i].w != 0; ++i) + { + if (fullscreen && !GoodFullscreenMode(&modes[i])) + { + continue; + } + + diff = (selected_screen_width - modes[i].w) + * (selected_screen_width - modes[i].w) + + (selected_screen_height - modes[i].h) + * (selected_screen_height - modes[i].h); + + if (best_mode == -1 || diff < best_mode_diff) + { + best_mode_diff = diff; + best_mode = i; + } + } + + return best_mode; +} + +static void GenerateModesTable(TXT_UNCAST_ARG(widget), + TXT_UNCAST_ARG(modes_table)) +{ + TXT_CAST_ARG(txt_table_t, modes_table); + char buf[15]; + screen_mode_t *modes; + txt_radiobutton_t *rbutton; + int i; + + // Pick which modes list to use + + if (fullscreen) + { + if (screen_modes_fullscreen == NULL) + { + BuildFullscreenModesList(); + } + + modes = screen_modes_fullscreen; + } + else if (aspect_ratio_correct) + { + modes = screen_modes_scaled; + } + else + { + modes = screen_modes_unscaled; + } + + // Build the table + + TXT_ClearTable(modes_table); + TXT_SetColumnWidths(modes_table, 14, 14, 14, 14, 14); + + for (i=0; modes[i].w != 0; ++i) + { + // Skip bad fullscreen modes + + if (fullscreen && !GoodFullscreenMode(&modes[i])) + { + continue; + } + + sprintf(buf, "%ix%i", modes[i].w, modes[i].h); + rbutton = TXT_NewRadioButton(buf, &vidmode, i); + TXT_AddWidget(modes_table, rbutton); + TXT_SignalConnect(rbutton, "selected", ModeSelected, &modes[i]); + } + + // Find the nearest mode in the list that matches the current + // settings + + vidmode = FindBestMode(modes); + + if (vidmode > 0) + { + screen_width = modes[vidmode].w; + screen_height = modes[vidmode].h; + } +} + +// Callback invoked when the BPP selector is changed. + +static void UpdateBPP(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(modes_table)) +{ + TXT_CAST_ARG(txt_table_t, modes_table); + + screen_bpp = GetSelectedBPP(); + + // Rebuild list of fullscreen modes. + + BuildFullscreenModesList(); + GenerateModesTable(NULL, modes_table); +} + +static void UpdateModeSeparator(TXT_UNCAST_ARG(widget), + TXT_UNCAST_ARG(separator)) +{ + TXT_CAST_ARG(txt_separator_t, separator); + + if (fullscreen) + { + TXT_SetSeparatorLabel(separator, "Screen mode"); + } + else + { + TXT_SetSeparatorLabel(separator, "Window size"); + } +} + +#if defined(_WIN32) && !defined(_WIN32_WCE) + +static int use_directx = 1; + +static void SetWin32VideoDriver(void) +{ + if (!strcmp(video_driver, "windib")) + { + use_directx = 0; + } + else + { + use_directx = 1; + } +} + +static void UpdateVideoDriver(TXT_UNCAST_ARG(widget), + TXT_UNCAST_ARG(modes_table)) +{ + TXT_CAST_ARG(txt_table_t, modes_table); + + if (use_directx) + { + video_driver = ""; + } + else + { + video_driver = "windib"; + } + + // When the video driver is changed, we need to restart the textscreen + // library. + + RestartTextscreen(); + + // Rebuild the list of supported pixel depths. + + IdentifyPixelDepths(); + SetSelectedBPP(); + + // Rebuild the video modes list + + BuildFullscreenModesList(); + GenerateModesTable(NULL, modes_table); +} + +#endif + +static void AdvancedDisplayConfig(TXT_UNCAST_ARG(widget), + TXT_UNCAST_ARG(modes_table)) +{ + TXT_CAST_ARG(txt_table_t, modes_table); + txt_window_t *window; + txt_checkbox_t *ar_checkbox; + + window = TXT_NewWindow("Advanced display options"); + + TXT_SetColumnWidths(window, 35); + + TXT_AddWidgets(window, + ar_checkbox = TXT_NewCheckBox("Fix aspect ratio", + &aspect_ratio_correct), + NULL); + + if (gamemission == heretic || gamemission == hexen) + { + TXT_AddWidget(window, + TXT_NewCheckBox("Graphical startup", &graphical_startup)); + } + + if (gamemission == doom || gamemission == heretic) + { + TXT_AddWidget(window, + TXT_NewCheckBox("Show ENDOOM screen on exit", + &show_endoom)); + } + + TXT_SignalConnect(ar_checkbox, "changed", GenerateModesTable, modes_table); + + // On Windows, there is an extra control to change between + // the Windows GDI and DirectX video drivers. + +#if defined(_WIN32) && !defined(_WIN32_WCE) + { + txt_radiobutton_t *dx_button, *gdi_button; + + TXT_AddWidgets(window, + TXT_NewSeparator("Windows video driver"), + dx_button = TXT_NewRadioButton("DirectX", + &use_directx, 1), + gdi_button = TXT_NewRadioButton("Windows GDI", + &use_directx, 0), + NULL); + + TXT_SignalConnect(dx_button, "selected", + UpdateVideoDriver, modes_table); + TXT_SignalConnect(gdi_button, "selected", + UpdateVideoDriver, modes_table); + SetWin32VideoDriver(); + } +#endif +} + +void ConfigDisplay(void) +{ + txt_window_t *window; + txt_table_t *modes_table; + txt_separator_t *modes_separator; + txt_table_t *bpp_table; + txt_window_action_t *advanced_button; + txt_checkbox_t *fs_checkbox; + int i; + int num_columns; + int num_rows; + int window_y; + + // What color depths are supported? Generate supported_bpps array + // and set selected_bpp to match the current value of screen_bpp. + + IdentifyPixelDepths(); + SetSelectedBPP(); + + // First time in? Initialise selected_screen_{width,height} + + if (selected_screen_width == 0) + { + selected_screen_width = screen_width; + selected_screen_height = screen_height; + } + + // Open the window + + window = TXT_NewWindow("Display Configuration"); + + // Some machines can have lots of video modes. This tries to + // keep a limit of six lines by increasing the number of + // columns. In extreme cases, the window is moved up slightly. + + BuildFullscreenModesList(); + + if (num_screen_modes_fullscreen <= 24) + { + num_columns = 3; + } + else if (num_screen_modes_fullscreen <= 40) + { + num_columns = 4; + } + else + { + num_columns = 5; + } + + modes_table = TXT_NewTable(num_columns); + + // Build window: + + TXT_AddWidget(window, + fs_checkbox = TXT_NewCheckBox("Full screen", &fullscreen)); + + if (num_supported_bpps > 1) + { + TXT_AddWidgets(window, + TXT_NewSeparator("Color depth"), + bpp_table = TXT_NewTable(4), + NULL); + + for (i = 0; i < num_supported_bpps; ++i) + { + txt_radiobutton_t *button; + + button = TXT_NewRadioButton(supported_bpps[i], + &selected_bpp, i); + + TXT_AddWidget(bpp_table, button); + TXT_SignalConnect(button, "selected", UpdateBPP, modes_table); + } + } + + TXT_AddWidgets(window, + modes_separator = TXT_NewSeparator(""), + modes_table, + NULL); + + TXT_SignalConnect(fs_checkbox, "changed", + GenerateModesTable, modes_table); + TXT_SignalConnect(fs_checkbox, "changed", + UpdateModeSeparator, modes_separator); + + // How many rows high will the configuration window be? + // Need to take into account number of fullscreen modes, and also + // number of supported pixel depths. + // The windowed modes list is four rows, so take the maximum of + // windowed and fullscreen. + + num_rows = (num_screen_modes_fullscreen + num_columns - 1) / num_columns; + + if (num_rows < 4) + { + num_rows = 4; + } + + if (num_supported_bpps > 1) + { + num_rows += 2; + } + + if (num_rows < 14) + { + window_y = 8 - ((num_rows + 1) / 2); + } + else + { + window_y = 1; + } + + // The window is set at a fixed vertical position. This keeps + // the top of the window stationary when switching between + // fullscreen and windowed mode (which causes the window's + // height to change). + + TXT_SetWindowPosition(window, TXT_HORIZ_CENTER, TXT_VERT_TOP, + TXT_SCREEN_W / 2, window_y); + + GenerateModesTable(NULL, modes_table); + UpdateModeSeparator(NULL, modes_separator); + + // Button to open "advanced" window. + // Need to pass a pointer to the modes table, as some of the options + // in there trigger a rebuild of it. + + advanced_button = TXT_NewWindowAction('a', "Advanced"); + TXT_SetWindowAction(window, TXT_HORIZ_CENTER, advanced_button); + TXT_SignalConnect(advanced_button, "pressed", + AdvancedDisplayConfig, modes_table); +} + +void BindDisplayVariables(void) +{ + M_BindVariable("autoadjust_video_settings", &autoadjust_video_settings); + M_BindVariable("aspect_ratio_correct", &aspect_ratio_correct); + M_BindVariable("fullscreen", &fullscreen); + M_BindVariable("screen_width", &screen_width); + M_BindVariable("screen_height", &screen_height); + M_BindVariable("screen_bpp", &screen_bpp); + M_BindVariable("startup_delay", &startup_delay); + M_BindVariable("video_driver", &video_driver); + M_BindVariable("usegamma", &usegamma); + + + if (gamemission == doom || gamemission == heretic) + { + M_BindVariable("show_endoom", &show_endoom); + } + + if (gamemission == heretic || gamemission == hexen) + { + M_BindVariable("graphical_startup", &graphical_startup); + } + + // Windows Vista or later? Set screen color depth to + // 32 bits per pixel, as 8-bit palettized screen modes + // don't work properly in recent versions. + +#if defined(_WIN32) && !defined(_WIN32_WCE) + { + OSVERSIONINFOEX version_info; + + ZeroMemory(&version_info, sizeof(OSVERSIONINFOEX)); + version_info.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); + + GetVersionEx((OSVERSIONINFO *) &version_info); + + if (version_info.dwPlatformId == VER_PLATFORM_WIN32_NT + && version_info.dwMajorVersion >= 6) + { + screen_bpp = 32; + } + } +#endif +} + diff --git a/src/setup/display.h b/src/setup/display.h new file mode 100644 index 00000000..2c17d8c4 --- /dev/null +++ b/src/setup/display.h @@ -0,0 +1,30 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// Copyright(C) 2006 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +// 02111-1307, USA. +// + +#ifndef SETUP_DISPLAY_H +#define SETUP_DISPLAY_H + +void ConfigDisplay(void); +void SetDisplayDriver(void); +void BindDisplayVariables(void); + +#endif /* #ifndef SETUP_DISPLAY_H */ + diff --git a/src/setup/execute.c b/src/setup/execute.c new file mode 100644 index 00000000..f85b8af4 --- /dev/null +++ b/src/setup/execute.c @@ -0,0 +1,417 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// Copyright(C) 2006 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +// 02111-1307, USA. +// + +// Code for invoking Doom + +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <sys/types.h> + +#if defined(_WIN32_WCE) +#include "libc_wince.h" +#endif + +#ifdef _WIN32 + +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +#include <process.h> + +#else + +#include <sys/wait.h> +#include <unistd.h> + +#endif + +#include "textscreen.h" + +#include "config.h" +#include "execute.h" +#include "mode.h" +#include "m_argv.h" +#include "m_config.h" + +struct execute_context_s +{ + char *response_file; + FILE *stream; +}; + +// Returns the path to a temporary file of the given name, stored +// inside the system temporary directory. + +static char *TempFile(char *s) +{ + char *result; + char *tempdir; + +#ifdef _WIN32 + // Check the TEMP environment variable to find the location. + + tempdir = getenv("TEMP"); + + if (tempdir == NULL) + { + tempdir = "."; + } +#else + // In Unix, just use /tmp. + + tempdir = "/tmp"; +#endif + + result = malloc(strlen(tempdir) + strlen(s) + 2); + sprintf(result, "%s%c%s", tempdir, DIR_SEPARATOR, s); + + return result; +} + +static int ArgumentNeedsEscape(char *arg) +{ + char *p; + + for (p = arg; *p != '\0'; ++p) + { + if (isspace(*p)) + { + return 1; + } + } + + return 0; +} + +// Arguments passed to the setup tool should be passed through to the +// game when launching a game. Calling this adds all arguments from +// myargv to the output context. + +void PassThroughArguments(execute_context_t *context) +{ + int i; + + for (i = 1; i < myargc; ++i) + { + if (ArgumentNeedsEscape(myargv[i])) + { + AddCmdLineParameter(context, "\"%s\"", myargv[i]); + } + else + { + AddCmdLineParameter(context, "%s", myargv[i]); + } + } +} + +execute_context_t *NewExecuteContext(void) +{ + execute_context_t *result; + + result = malloc(sizeof(execute_context_t)); + + result->response_file = TempFile("chocolat.rsp"); + result->stream = fopen(result->response_file, "w"); + + if (result->stream == NULL) + { + fprintf(stderr, "Error opening response file\n"); + exit(-1); + } + + return result; +} + +void AddCmdLineParameter(execute_context_t *context, char *s, ...) +{ + va_list args; + + va_start(args, s); + + vfprintf(context->stream, s, args); + fprintf(context->stream, "\n"); +} + +#if defined(_WIN32) + +// Wait for the specified process to exit. Returns the exit code. + +static unsigned int WaitForProcessExit(HANDLE subprocess) +{ + DWORD exit_code; + + for (;;) + { + WaitForSingleObject(subprocess, INFINITE); + + if (!GetExitCodeProcess(subprocess, &exit_code)) + { + return -1; + } + + if (exit_code != STILL_ACTIVE) + { + return exit_code; + } + } +} + +static void ConcatWCString(wchar_t *buf, const char *value) +{ + MultiByteToWideChar(CP_OEMCP, 0, + value, strlen(value) + 1, + buf + wcslen(buf), strlen(value) + 1); +} + +// Build the command line string, a wide character string of the form: +// +// "program" "arg" + +static wchar_t *BuildCommandLine(const char *program, const char *arg) +{ + wchar_t exe_path[MAX_PATH]; + wchar_t *result; + wchar_t *sep; + + // Get the path to this .exe file. + + GetModuleFileNameW(NULL, exe_path, MAX_PATH); + + // Allocate buffer to contain result string. + + result = calloc(wcslen(exe_path) + strlen(program) + strlen(arg) + 6, + sizeof(wchar_t)); + + wcscpy(result, L"\""); + + // Copy the path part of the filename (including ending \) + // into the result buffer: + + sep = wcsrchr(exe_path, DIR_SEPARATOR); + + if (sep != NULL) + { + wcsncpy(result + 1, exe_path, sep - exe_path + 1); + result[sep - exe_path + 2] = '\0'; + } + + // Concatenate the name of the program: + + ConcatWCString(result, program); + + // End of program name, start of argument: + + wcscat(result, L"\" \""); + + ConcatWCString(result, arg); + + wcscat(result, L"\""); + + return result; +} + +static int ExecuteCommand(const char *program, const char *arg) +{ + STARTUPINFOW startup_info; + PROCESS_INFORMATION proc_info; + wchar_t *command; + int result = 0; + + command = BuildCommandLine(program, arg); + + // Invoke the program: + + memset(&proc_info, 0, sizeof(proc_info)); + memset(&startup_info, 0, sizeof(startup_info)); + startup_info.cb = sizeof(startup_info); + + if (!CreateProcessW(NULL, command, + NULL, NULL, FALSE, 0, NULL, NULL, + &startup_info, &proc_info)) + { + result = -1; + } + else + { + // Wait for the process to finish, and save the exit code. + + result = WaitForProcessExit(proc_info.hProcess); + + CloseHandle(proc_info.hProcess); + CloseHandle(proc_info.hThread); + } + + free(command); + + return result; +} + +#else + +// Given the specified program name, get the full path to the program, +// assuming that it is in the same directory as this program is. + +static char *GetFullExePath(const char *program) +{ + char *result; + char *sep; + unsigned int path_len; + + sep = strrchr(myargv[0], DIR_SEPARATOR); + + if (sep == NULL) + { + result = strdup(program); + } + else + { + path_len = sep - myargv[0] + 1; + + result = malloc(strlen(program) + path_len + 1); + + strncpy(result, myargv[0], path_len); + result[path_len] = '\0'; + + strcat(result, program); + } + + return result; +} + +static int ExecuteCommand(const char *program, const char *arg) +{ + pid_t childpid; + int result; + const char *argv[3]; + + childpid = fork(); + + if (childpid == 0) + { + // This is the child. Execute the command. + + argv[0] = GetFullExePath(program); + argv[1] = arg; + argv[2] = NULL; + + execvp(argv[0], (char **) argv); + + exit(0x80); + } + else + { + // This is the parent. Wait for the child to finish, and return + // the status code. + + waitpid(childpid, &result, 0); + + if (WIFEXITED(result) && WEXITSTATUS(result) != 0x80) + { + return WEXITSTATUS(result); + } + else + { + return -1; + } + } +} + +#endif + +int ExecuteDoom(execute_context_t *context) +{ + char *response_file_arg; + int result; + + fclose(context->stream); + + // Build the command line + + response_file_arg = malloc(strlen(context->response_file) + 2); + sprintf(response_file_arg, "@%s", context->response_file); + + // Run Doom + + result = ExecuteCommand(GetExecutableName(), response_file_arg); + + free(response_file_arg); + + // Destroy context + remove(context->response_file); + free(context->response_file); + free(context); + + return result; +} + +static void TestCallback(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(data)) +{ + execute_context_t *exec; + char *main_cfg; + char *extra_cfg; + txt_window_t *testwindow; + txt_label_t *label; + + testwindow = TXT_NewWindow("Starting Doom"); + + label = TXT_NewLabel("Starting Doom to test the\n" + "settings. Please wait."); + TXT_SetWidgetAlign(label, TXT_HORIZ_CENTER); + TXT_AddWidget(testwindow, label); + TXT_DrawDesktop(); + + // Save temporary configuration files with the current configuration + + main_cfg = TempFile("tmp.cfg"); + extra_cfg = TempFile("extratmp.cfg"); + + M_SaveDefaultsAlternate(main_cfg, extra_cfg); + + // Run with the -testcontrols parameter + + exec = NewExecuteContext(); + AddCmdLineParameter(exec, "-testcontrols"); + AddCmdLineParameter(exec, "-config \"%s\"", main_cfg); + AddCmdLineParameter(exec, "-extraconfig \"%s\"", extra_cfg); + ExecuteDoom(exec); + + TXT_CloseWindow(testwindow); + + // Delete the temporary config files + + remove(main_cfg); + remove(extra_cfg); + free(main_cfg); + free(extra_cfg); +} + +txt_window_action_t *TestConfigAction(void) +{ + txt_window_action_t *test_action; + + test_action = TXT_NewWindowAction('t', "Test"); + TXT_SignalConnect(test_action, "pressed", TestCallback, NULL); + + return test_action; +} + diff --git a/src/setup/execute.h b/src/setup/execute.h new file mode 100644 index 00000000..25f1f10a --- /dev/null +++ b/src/setup/execute.h @@ -0,0 +1,45 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// Copyright(C) 2006 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +// 02111-1307, USA. +// + +#ifndef TESTCONFIG_H +#define TESTCONFIG_H + +#include "textscreen.h" + +typedef struct execute_context_s execute_context_t; + +#define IWAD_DOOM2 (1 << 0) /* doom2.wad */ +#define IWAD_PLUTONIA (1 << 1) /* plutonia.wad */ +#define IWAD_TNT (1 << 2) /* tnt.wad */ +#define IWAD_DOOM (1 << 3) /* doom.wad */ +#define IWAD_DOOM1 (1 << 4) /* doom1.wad */ +#define IWAD_CHEX (1 << 5) /* chex.wad */ + +execute_context_t *NewExecuteContext(void); +void AddCmdLineParameter(execute_context_t *context, char *s, ...); +void PassThroughArguments(execute_context_t *context); +int ExecuteDoom(execute_context_t *context); +int FindInstalledIWADs(void); + +txt_window_action_t *TestConfigAction(void); + +#endif /* #ifndef TESTCONFIG_H */ + diff --git a/src/setup/joystick.c b/src/setup/joystick.c new file mode 100644 index 00000000..2a7b1f79 --- /dev/null +++ b/src/setup/joystick.c @@ -0,0 +1,454 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// Copyright(C) 2007 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +// 02111-1307, USA. +// + +#include <stdio.h> +#include <stdlib.h> + +#include "doomtype.h" +#include "m_config.h" +#include "m_controls.h" +#include "textscreen.h" + +#include "execute.h" +#include "joystick.h" +#include "mode.h" +#include "txt_joybinput.h" + +typedef enum +{ + CALIBRATE_CENTER, + CALIBRATE_LEFT, + CALIBRATE_UP, +} calibration_stage_t; + +// SDL joystick successfully initialized? + +static int joystick_initted = 0; + +// Joystick enable/disable + +static int usejoystick = 0; + +// Joystick to use, as an SDL joystick index: + +int joystick_index = -1; + +// Which joystick axis to use for horizontal movement, and whether to +// invert the direction: + +static int joystick_x_axis = 0; +static int joystick_x_invert = 0; + +// Which joystick axis to use for vertical movement, and whether to +// invert the direction: + +static int joystick_y_axis = 1; +static int joystick_y_invert = 0; + +static txt_button_t *joystick_button; + +static int *all_joystick_buttons[] = { + &joybstraferight, &joybstrafeleft, &joybfire, &joybspeed, + &joybuse, &joybstrafe, &joybprevweapon, &joybnextweapon, &joybjump +}; + +// +// Calibration +// + +static txt_window_t *calibration_window; +static txt_label_t *calibration_label; +static calibration_stage_t calibrate_stage; +static SDL_Joystick **all_joysticks = NULL; + +// Set the label showing the name of the currently selected joystick + +static void SetJoystickButtonLabel(void) +{ + char *name; + + name = "None set"; + + if (joystick_initted + && joystick_index >= 0 && joystick_index < SDL_NumJoysticks()) + { + name = (char *) SDL_JoystickName(joystick_index); + } + + TXT_SetButtonLabel(joystick_button, name); +} + +// Try to open all joysticks visible to SDL. + +static int OpenAllJoysticks(void) +{ + int i; + int num_joysticks; + int result; + + if (!joystick_initted) + { + return 0; + } + + // SDL_JoystickOpen() all joysticks. + + num_joysticks = SDL_NumJoysticks(); + + all_joysticks = malloc(sizeof(SDL_Joystick *) * num_joysticks); + + result = 0; + + for (i=0; i<num_joysticks; ++i) + { + all_joysticks[i] = SDL_JoystickOpen(i); + + // If any joystick is successfully opened, return true. + + if (all_joysticks[i] != NULL) + { + result = 1; + } + } + + // Success? Turn on joystick events. + + if (result) + { + SDL_JoystickEventState(SDL_ENABLE); + } + else + { + free(all_joysticks); + all_joysticks = NULL; + } + + return result; +} + +// Close all the joysticks opened with OpenAllJoysticks() + +static void CloseAllJoysticks(void) +{ + int i; + int num_joysticks; + + num_joysticks = SDL_NumJoysticks(); + + for (i=0; i<num_joysticks; ++i) + { + if (all_joysticks[i] != NULL) + { + SDL_JoystickClose(all_joysticks[i]); + } + } + + SDL_JoystickEventState(SDL_DISABLE); + + free(all_joysticks); + all_joysticks = NULL; +} + +static void SetCalibrationLabel(void) +{ + char *message = "???"; + + switch (calibrate_stage) + { + case CALIBRATE_CENTER: + message = "Move the joystick to the\n" + "center, and press a button."; + break; + case CALIBRATE_UP: + message = "Move the joystick up,\n" + "and press a button."; + break; + case CALIBRATE_LEFT: + message = "Move the joystick to the\n" + "left, and press a button."; + break; + } + + TXT_SetLabel(calibration_label, message); +} + +static void CalibrateAxis(int *axis_index, int *axis_invert) +{ + SDL_Joystick *joystick; + int best_axis; + int best_value; + int best_invert; + Sint16 axis_value; + int i; + + joystick = all_joysticks[joystick_index]; + + // Check all axes to find which axis has the largest value. We test + // for one axis at a time, so eg. when we prompt to push the joystick + // left, whichever axis has the largest value is the left axis. + + best_axis = 0; + best_value = 0; + best_invert = 0; + + for (i=0; i<SDL_JoystickNumAxes(joystick); ++i) + { + axis_value = SDL_JoystickGetAxis(joystick, i); + + if (abs(axis_value) > best_value) + { + best_value = abs(axis_value); + best_invert = axis_value > 0; + best_axis = i; + } + } + + // Save the best values we have found + + *axis_index = best_axis; + *axis_invert = best_invert; +} + +static int CalibrationEventCallback(SDL_Event *event, void *user_data) +{ + if (event->type == SDL_JOYBUTTONDOWN + && (joystick_index == -1 || event->jbutton.which == joystick_index)) + { + switch (calibrate_stage) + { + case CALIBRATE_CENTER: + // Centering stage selects which joystick to use. + joystick_index = event->jbutton.which; + break; + + case CALIBRATE_LEFT: + CalibrateAxis(&joystick_x_axis, &joystick_x_invert); + break; + + case CALIBRATE_UP: + CalibrateAxis(&joystick_y_axis, &joystick_y_invert); + break; + } + + if (calibrate_stage == CALIBRATE_UP) + { + // Final stage; close the window + + TXT_CloseWindow(calibration_window); + } + else + { + // Advance to the next calibration stage + + ++calibrate_stage; + SetCalibrationLabel(); + } + + return 1; + } + + return 0; +} + +static void NoJoystick(void) +{ + txt_window_t *window; + + window = TXT_NewWindow(NULL); + + TXT_AddWidget(window, + TXT_NewLabel("No joysticks could be opened.\n\n" + "Try configuring your joystick from within\n" + "your OS first.")); + + TXT_SetWindowAction(window, TXT_HORIZ_LEFT, NULL); + TXT_SetWindowAction(window, TXT_HORIZ_CENTER, + TXT_NewWindowEscapeAction(window)); + TXT_SetWindowAction(window, TXT_HORIZ_RIGHT, NULL); + + joystick_index = -1; + SetJoystickButtonLabel(); +} + +static void CalibrateWindowClosed(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(unused)) +{ + CloseAllJoysticks(); + TXT_SDL_SetEventCallback(NULL, NULL); + SetJoystickButtonLabel(); +} + +static void CalibrateJoystick(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(unused)) +{ + calibrate_stage = CALIBRATE_CENTER; + + // Try to open all available joysticks. If none are opened successfully, + // bomb out with an error. + + if (!OpenAllJoysticks()) + { + NoJoystick(); + return; + } + + calibration_window = TXT_NewWindow("Joystick calibration"); + + TXT_AddWidgets(calibration_window, + TXT_NewLabel("Please follow the following instructions\n" + "in order to calibrate your joystick."), + TXT_NewStrut(0, 1), + calibration_label = TXT_NewLabel("zzz"), + TXT_NewStrut(0, 1), + NULL); + + TXT_SetWindowAction(calibration_window, TXT_HORIZ_LEFT, NULL); + TXT_SetWindowAction(calibration_window, TXT_HORIZ_CENTER, + TXT_NewWindowAbortAction(calibration_window)); + TXT_SetWindowAction(calibration_window, TXT_HORIZ_RIGHT, NULL); + + TXT_SetWidgetAlign(calibration_label, TXT_HORIZ_CENTER); + TXT_SDL_SetEventCallback(CalibrationEventCallback, NULL); + + TXT_SignalConnect(calibration_window, "closed", CalibrateWindowClosed, NULL); + + // Start calibration + + joystick_index = -1; + calibrate_stage = CALIBRATE_CENTER; + + SetCalibrationLabel(); +} + +void JoyButtonSetCallback(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(variable)) +{ + TXT_CAST_ARG(int, variable); + unsigned int i; + + // Only allow a button to be bound to one action at a time. If + // we assign a key that another action is using, set that other action + // to -1. + + for (i=0; i<arrlen(all_joystick_buttons); ++i) + { + if (variable != all_joystick_buttons[i] + && *variable == *all_joystick_buttons[i]) + { + *all_joystick_buttons[i] = -1; + } + } +} + + +// +// GUI +// + +static void JoystickWindowClosed(TXT_UNCAST_ARG(window), TXT_UNCAST_ARG(unused)) +{ + if (joystick_initted) + { + SDL_QuitSubSystem(SDL_INIT_JOYSTICK); + joystick_initted = 0; + } +} + +static void AddJoystickControl(txt_table_t *table, char *label, int *var) +{ + txt_joystick_input_t *joy_input; + + joy_input = TXT_NewJoystickInput(var); + + TXT_AddWidget(table, TXT_NewLabel(label)); + TXT_AddWidget(table, joy_input); + + TXT_SignalConnect(joy_input, "set", JoyButtonSetCallback, var); +} + +void ConfigJoystick(void) +{ + txt_window_t *window; + txt_table_t *button_table; + txt_table_t *joystick_table; + + if (!joystick_initted) + { + joystick_initted = SDL_Init(SDL_INIT_JOYSTICK) >= 0; + } + + window = TXT_NewWindow("Joystick configuration"); + + TXT_AddWidgets(window, + TXT_NewCheckBox("Enable joystick", &usejoystick), + joystick_table = TXT_NewTable(2), + TXT_NewSeparator("Joystick buttons"), + button_table = TXT_NewTable(2), + NULL); + + TXT_SetColumnWidths(joystick_table, 20, 15); + + TXT_AddWidgets(joystick_table, + TXT_NewLabel("Current joystick"), + joystick_button = TXT_NewButton("zzzz"), + NULL); + + TXT_SetColumnWidths(button_table, 20, 15); + + AddJoystickControl(button_table, "Fire/Attack", &joybfire); + AddJoystickControl(button_table, "Use", &joybuse); + + // High values of joybspeed are used to activate the "always run mode" + // trick in Vanilla Doom. If this has been enabled, not only is the + // joybspeed value meaningless, but the control itself is useless. + + if (joybspeed < 20) + { + AddJoystickControl(button_table, "Speed", &joybspeed); + } + + AddJoystickControl(button_table, "Strafe", &joybstrafe); + + AddJoystickControl(button_table, "Strafe Left", &joybstrafeleft); + AddJoystickControl(button_table, "Strafe Right", &joybstraferight); + AddJoystickControl(button_table, "Previous weapon", &joybprevweapon); + AddJoystickControl(button_table, "Next weapon", &joybnextweapon); + + if (gamemission == hexen) + { + AddJoystickControl(button_table, "Jump", &joybjump); + } + + TXT_SignalConnect(joystick_button, "pressed", CalibrateJoystick, NULL); + TXT_SignalConnect(window, "closed", JoystickWindowClosed, NULL); + + TXT_SetWindowAction(window, TXT_HORIZ_CENTER, TestConfigAction()); + + SetJoystickButtonLabel(); +} + +void BindJoystickVariables(void) +{ + M_BindVariable("use_joystick", &usejoystick); + M_BindVariable("joystick_index", &joystick_index); + M_BindVariable("joystick_x_axis", &joystick_x_axis); + M_BindVariable("joystick_y_axis", &joystick_y_axis); + M_BindVariable("joystick_x_invert", &joystick_x_invert); + M_BindVariable("joystick_y_invert", &joystick_y_invert); +} + diff --git a/src/setup/joystick.h b/src/setup/joystick.h new file mode 100644 index 00000000..b6dd09b9 --- /dev/null +++ b/src/setup/joystick.h @@ -0,0 +1,31 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// Copyright(C) 2006 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +// 02111-1307, USA. +// + +#ifndef SETUP_JOYSTICK_H +#define SETUP_JOYSTICK_H + +extern int joystick_index; + +void ConfigJoystick(void); +void BindJoystickVariables(void); + +#endif /* #ifndef SETUP_JOYSTICK_H */ + diff --git a/src/setup/keyboard.c b/src/setup/keyboard.c new file mode 100644 index 00000000..a128b3ab --- /dev/null +++ b/src/setup/keyboard.c @@ -0,0 +1,368 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// Copyright(C) 2006 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +// 02111-1307, USA. +// + +#include "textscreen.h" +#include "doomtype.h" +#include "m_config.h" +#include "m_controls.h" + +#include "execute.h" +#include "txt_keyinput.h" + +#include "mode.h" +#include "joystick.h" +#include "keyboard.h" + +static int vanilla_keyboard_mapping = 1; + +static int always_run = 0; + +// Keys within these groups cannot have the same value. + +static int *controls[] = { &key_left, &key_right, &key_up, &key_down, + &key_strafeleft, &key_straferight, &key_fire, + &key_use, &key_strafe, &key_speed, &key_jump, + &key_flyup, &key_flydown, &key_flycenter, + &key_lookup, &key_lookdown, &key_lookcenter, + &key_invleft, &key_invright, &key_useartifact, + &key_pause, + &key_weapon1, &key_weapon2, &key_weapon3, + &key_weapon4, &key_weapon5, &key_weapon6, + &key_weapon7, &key_weapon8, + &key_prevweapon, &key_nextweapon, NULL }; + +static int *menu_nav[] = { &key_menu_activate, &key_menu_up, &key_menu_down, + &key_menu_left, &key_menu_right, &key_menu_back, + &key_menu_forward, NULL }; + +static int *shortcuts[] = { &key_menu_help, &key_menu_save, &key_menu_load, + &key_menu_volume, &key_menu_detail, &key_menu_qsave, + &key_menu_endgame, &key_menu_messages, &key_spy, + &key_menu_qload, &key_menu_quit, &key_menu_gamma, + &key_menu_incscreen, &key_menu_decscreen, + &key_message_refresh, &key_multi_msg, + &key_multi_msgplayer[0], &key_multi_msgplayer[1], + &key_multi_msgplayer[2], &key_multi_msgplayer[3] }; + +static int *map_keys[] = { &key_map_north, &key_map_south, &key_map_east, + &key_map_west, &key_map_zoomin, &key_map_zoomout, + &key_map_toggle, &key_map_maxzoom, &key_map_follow, + &key_map_grid, &key_map_mark, &key_map_clearmark, + NULL }; + +static void UpdateJoybSpeed(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(var)) +{ + if (always_run) + { + /* + <Janizdreg> if you want to pick one for chocolate doom to use, + pick 29, since that is the most universal one that + also works with heretic, hexen and strife =P + + NB. This choice also works with original, ultimate and final exes. + */ + + joybspeed = 29; + } + else + { + joybspeed = 0; + } +} + +static int VarInGroup(int *variable, int **group) +{ + unsigned int i; + + for (i=0; group[i] != NULL; ++i) + { + if (group[i] == variable) + { + return 1; + } + } + + return 0; +} + +static void CheckKeyGroup(int *variable, int **group) +{ + unsigned int i; + + // Don't check unless the variable is in this group. + + if (!VarInGroup(variable, group)) + { + return; + } + + // If another variable has the same value as the new value, reset it. + + for (i=0; group[i] != NULL; ++i) + { + if (*variable == *group[i] && group[i] != variable) + { + // A different key has the same value. Clear the existing + // value. This ensures that no two keys can have the same + // value. + + *group[i] = 0; + } + } +} + +// Callback invoked when a key control is set + +static void KeySetCallback(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(variable)) +{ + TXT_CAST_ARG(int, variable); + + CheckKeyGroup(variable, controls); + CheckKeyGroup(variable, menu_nav); + CheckKeyGroup(variable, shortcuts); + CheckKeyGroup(variable, map_keys); +} + +// Add a label and keyboard input to the specified table. + +static void AddKeyControl(txt_table_t *table, char *name, int *var) +{ + txt_key_input_t *key_input; + + TXT_AddWidget(table, TXT_NewLabel(name)); + key_input = TXT_NewKeyInput(var); + TXT_AddWidget(table, key_input); + + TXT_SignalConnect(key_input, "set", KeySetCallback, var); +} + +static void AddSectionLabel(txt_table_t *table, char *title, boolean add_space) +{ + char buf[64]; + + if (add_space) + { + TXT_AddWidgets(table, TXT_NewStrut(0, 1), TXT_NewStrut(0, 1), + NULL); + } + + sprintf(buf, " - %s - ", title); + + TXT_AddWidgets(table, TXT_NewLabel(buf), TXT_NewStrut(0, 0), + NULL); +} +static void ConfigExtraKeys(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(unused)) +{ + txt_window_t *window; + txt_scrollpane_t *scrollpane; + txt_table_t *table; + boolean extra_keys = gamemission == heretic || gamemission == hexen; + + window = TXT_NewWindow("Extra keyboard controls"); + + table = TXT_NewTable(2); + + TXT_SetColumnWidths(table, 20, 9); + + if (extra_keys) + { + // When we have extra controls, a scrollable pane must be used. + + scrollpane = TXT_NewScrollPane(0, 13, table); + TXT_AddWidget(window, scrollpane); + + AddSectionLabel(table, "View", false); + + AddKeyControl(table, "Look up", &key_lookup); + AddKeyControl(table, "Look down", &key_lookdown); + AddKeyControl(table, "Center view", &key_lookcenter); + + AddSectionLabel(table, "Flying", true); + + AddKeyControl(table, "Fly up", &key_flyup); + AddKeyControl(table, "Fly down", &key_flydown); + AddKeyControl(table, "Fly center", &key_flycenter); + + AddSectionLabel(table, "Inventory", true); + + AddKeyControl(table, "Inventory left", &key_invleft); + AddKeyControl(table, "Inventory right", &key_invright); + AddKeyControl(table, "Use artifact", &key_useartifact); + } + else + { + TXT_AddWidget(window, table); + } + + AddSectionLabel(table, "Weapons", extra_keys); + + AddKeyControl(table, "Weapon 1", &key_weapon1); + AddKeyControl(table, "Weapon 2", &key_weapon2); + AddKeyControl(table, "Weapon 3", &key_weapon3); + AddKeyControl(table, "Weapon 4", &key_weapon4); + AddKeyControl(table, "Weapon 5", &key_weapon5); + AddKeyControl(table, "Weapon 6", &key_weapon6); + AddKeyControl(table, "Weapon 7", &key_weapon7); + AddKeyControl(table, "Weapon 8", &key_weapon8); + AddKeyControl(table, "Previous weapon", &key_prevweapon); + AddKeyControl(table, "Next weapon", &key_nextweapon); +} + +static void OtherKeysDialog(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(unused)) +{ + txt_window_t *window; + txt_table_t *table; + txt_scrollpane_t *scrollpane; + + window = TXT_NewWindow("Other keys"); + + table = TXT_NewTable(2); + + TXT_SetColumnWidths(table, 25, 9); + + AddSectionLabel(table, "Menu navigation", false); + + AddKeyControl(table, "Activate menu", &key_menu_activate); + AddKeyControl(table, "Move cursor up", &key_menu_up); + AddKeyControl(table, "Move cursor down", &key_menu_down); + AddKeyControl(table, "Move slider left", &key_menu_left); + AddKeyControl(table, "Move slider right", &key_menu_right); + AddKeyControl(table, "Go to previous menu", &key_menu_back); + AddKeyControl(table, "Activate menu item", &key_menu_forward); + AddKeyControl(table, "Confirm action", &key_menu_confirm); + AddKeyControl(table, "Cancel action", &key_menu_abort); + + AddSectionLabel(table, "Shortcut keys", true); + + AddKeyControl(table, "Pause game", &key_pause); + AddKeyControl(table, "Help screen", &key_menu_help); + AddKeyControl(table, "Save game", &key_menu_save); + AddKeyControl(table, "Load game", &key_menu_load); + AddKeyControl(table, "Sound volume", &key_menu_volume); + AddKeyControl(table, "Toggle detail", &key_menu_detail); + AddKeyControl(table, "Quick save", &key_menu_qsave); + AddKeyControl(table, "End game", &key_menu_endgame); + AddKeyControl(table, "Toggle messages", &key_menu_messages); + AddKeyControl(table, "Quick load", &key_menu_qload); + AddKeyControl(table, "Quit game", &key_menu_quit); + AddKeyControl(table, "Toggle gamma", &key_menu_gamma); + AddKeyControl(table, "Multiplayer spy", &key_spy); + + AddKeyControl(table, "Increase screen size", &key_menu_incscreen); + AddKeyControl(table, "Decrease screen size", &key_menu_decscreen); + + AddKeyControl(table, "Display last message", &key_message_refresh); + AddKeyControl(table, "Finish recording demo", &key_demo_quit); + + AddSectionLabel(table, "Map", true); + AddKeyControl(table, "Toggle map", &key_map_toggle); + AddKeyControl(table, "Zoom in", &key_map_zoomin); + AddKeyControl(table, "Zoom out", &key_map_zoomout); + AddKeyControl(table, "Maximum zoom out", &key_map_maxzoom); + AddKeyControl(table, "Follow mode", &key_map_follow); + AddKeyControl(table, "Pan north", &key_map_north); + AddKeyControl(table, "Pan south", &key_map_south); + AddKeyControl(table, "Pan east", &key_map_east); + AddKeyControl(table, "Pan west", &key_map_west); + AddKeyControl(table, "Toggle grid", &key_map_grid); + AddKeyControl(table, "Mark location", &key_map_mark); + AddKeyControl(table, "Clear all marks", &key_map_clearmark); + + AddSectionLabel(table, "Multiplayer", true); + + AddKeyControl(table, "Send message", &key_multi_msg); + AddKeyControl(table, "- to green", &key_multi_msgplayer[0]); + AddKeyControl(table, "- to indigo", &key_multi_msgplayer[1]); + AddKeyControl(table, "- to brown", &key_multi_msgplayer[2]); + AddKeyControl(table, "- to red", &key_multi_msgplayer[3]); + + scrollpane = TXT_NewScrollPane(0, 13, table); + + TXT_AddWidget(window, scrollpane); +} + +void ConfigKeyboard(void) +{ + txt_window_t *window; + txt_table_t *movement_table; + txt_table_t *action_table; + txt_table_t *dialogs_table; + txt_checkbox_t *run_control; + + always_run = joybspeed >= 20; + + window = TXT_NewWindow("Keyboard configuration"); + + TXT_AddWidgets(window, + TXT_NewSeparator("Movement"), + movement_table = TXT_NewTable(4), + + TXT_NewSeparator("Action"), + action_table = TXT_NewTable(4), + dialogs_table = TXT_NewTable(2), + + TXT_NewSeparator("Misc."), + run_control = TXT_NewCheckBox("Always run", &always_run), + TXT_NewInvertedCheckBox("Use native keyboard mapping", + &vanilla_keyboard_mapping), + NULL); + + TXT_SetColumnWidths(movement_table, 15, 8, 15, 8); + + TXT_SignalConnect(run_control, "changed", UpdateJoybSpeed, NULL); + + AddKeyControl(movement_table, "Move Forward", &key_up); + AddKeyControl(movement_table, " Strafe Left", &key_strafeleft); + AddKeyControl(movement_table, "Move Backward", &key_down); + AddKeyControl(movement_table, " Strafe Right", &key_straferight); + AddKeyControl(movement_table, "Turn Left", &key_left); + AddKeyControl(movement_table, " Speed On", &key_speed); + AddKeyControl(movement_table, "Turn Right", &key_right); + AddKeyControl(movement_table, " Strafe On", &key_strafe); + + if (gamemission == hexen) + { + AddKeyControl(movement_table, "Jump", &key_jump); + } + + TXT_SetColumnWidths(action_table, 15, 8, 15, 8); + + AddKeyControl(action_table, "Fire/Attack", &key_fire); + AddKeyControl(action_table, " Use", &key_use); + + // Other key bindings are stored in separate sub-dialogs: + + TXT_SetColumnWidths(dialogs_table, 24, 24); + + TXT_AddWidgets(dialogs_table, + TXT_NewButton2("More controls...", ConfigExtraKeys, NULL), + TXT_NewButton2("Other keys...", OtherKeysDialog, NULL), + NULL); + + TXT_SetWindowAction(window, TXT_HORIZ_CENTER, TestConfigAction()); + +} + +void BindKeyboardVariables(void) +{ + M_BindVariable("vanilla_keyboard_mapping", &vanilla_keyboard_mapping); +} + diff --git a/src/setup/keyboard.h b/src/setup/keyboard.h new file mode 100644 index 00000000..12059bf8 --- /dev/null +++ b/src/setup/keyboard.h @@ -0,0 +1,29 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// Copyright(C) 2006 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +// 02111-1307, USA. +// + +#ifndef SETUP_KEYBOARD_H +#define SETUP_KEYBOARD_H + +void ConfigKeyboard(void); +void BindKeyboardVariables(void); + +#endif /* #ifndef SETUP_KEYBOARD_H */ + diff --git a/src/setup/mainmenu.c b/src/setup/mainmenu.c new file mode 100644 index 00000000..55496010 --- /dev/null +++ b/src/setup/mainmenu.c @@ -0,0 +1,348 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// Copyright(C) 2006 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +// 02111-1307, USA. +// + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#ifdef _WIN32_WCE +#include "libc_wince.h" +#endif + +#include "config.h" +#include "textscreen.h" + +#include "execute.h" + +#include "m_argv.h" +#include "m_config.h" + +#include "setup_icon.c" +#include "mode.h" + +#include "compatibility.h" +#include "display.h" +#include "joystick.h" +#include "keyboard.h" +#include "mouse.h" +#include "multiplayer.h" +#include "sound.h" + +static const int cheat_sequence[] = +{ + KEY_UPARROW, KEY_UPARROW, KEY_DOWNARROW, KEY_DOWNARROW, + KEY_LEFTARROW, KEY_RIGHTARROW, KEY_LEFTARROW, KEY_RIGHTARROW, + 'b', 'a', KEY_ENTER, 0 +}; + +static unsigned int cheat_sequence_index = 0; + +// I think these are good "sensible" defaults: + +static void SensibleDefaults(void) +{ +#if 0 + // TODO for raven-branch + key_up = 'w'; + key_down = 's'; + key_strafeleft = 'a'; + key_straferight = 'd'; + mousebprevweapon = 4; + mousebnextweapon = 3; + snd_musicdevice = 3; + joybspeed = 29; + vanilla_savegame_limit = 0; + vanilla_keyboard_mapping = 0; + vanilla_demo_limit = 0; + show_endoom = 0; + dclick_use = 0; + novert = 1; +#endif +} + +static int MainMenuKeyPress(txt_window_t *window, int key, void *user_data) +{ + if (key == cheat_sequence[cheat_sequence_index]) + { + ++cheat_sequence_index; + + if (cheat_sequence[cheat_sequence_index] == 0) + { + SensibleDefaults(); + cheat_sequence_index = 0; + + window = TXT_NewWindow(NULL); + TXT_AddWidget(window, TXT_NewLabel(" \x01 ")); + TXT_SetWindowAction(window, TXT_HORIZ_RIGHT, NULL); + + return 1; + } + } + else + { + cheat_sequence_index = 0; + } + + return 0; +} + +static void DoQuit(void *widget, void *dosave) +{ + if (dosave != NULL) + { + M_SaveDefaults(); + } + + exit(0); +} + +static void QuitConfirm(void *unused1, void *unused2) +{ + txt_window_t *window; + txt_label_t *label; + txt_button_t *yes_button; + txt_button_t *no_button; + + window = TXT_NewWindow(NULL); + + TXT_AddWidgets(window, + label = TXT_NewLabel("Exiting setup.\nSave settings?"), + TXT_NewStrut(24, 0), + yes_button = TXT_NewButton2(" Yes ", DoQuit, DoQuit), + no_button = TXT_NewButton2(" No ", DoQuit, NULL), + NULL); + + TXT_SetWidgetAlign(label, TXT_HORIZ_CENTER); + TXT_SetWidgetAlign(yes_button, TXT_HORIZ_CENTER); + TXT_SetWidgetAlign(no_button, TXT_HORIZ_CENTER); + + // Only an "abort" button in the middle. + TXT_SetWindowAction(window, TXT_HORIZ_LEFT, NULL); + TXT_SetWindowAction(window, TXT_HORIZ_CENTER, + TXT_NewWindowAbortAction(window)); + TXT_SetWindowAction(window, TXT_HORIZ_RIGHT, NULL); +} + +static void LaunchDoom(void *unused1, void *unused2) +{ + execute_context_t *exec; + + // Save configuration first + + M_SaveDefaults(); + + // Shut down textscreen GUI + + TXT_Shutdown(); + + // Launch Doom + + exec = NewExecuteContext(); + PassThroughArguments(exec); + ExecuteDoom(exec); + + exit(0); +} + +static txt_button_t *GetLaunchButton(void) +{ + char *label; + + switch (gamemission) + { + case doom: + label = "Save parameters and launch DOOM"; + break; + case heretic: + label = "Save parameters and launch Heretic"; + break; + case hexen: + label = "Save parameters and launch Hexen"; + break; + default: + label = "Save parameters and launch game"; + break; + } + + return TXT_NewButton2(label, LaunchDoom, NULL); +} + +void MainMenu(void) +{ + txt_window_t *window; + txt_window_action_t *quit_action; + txt_window_action_t *warp_action; + + window = TXT_NewWindow("Main Menu"); + + TXT_AddWidgets(window, + TXT_NewButton2("Configure Display", + (TxtWidgetSignalFunc) ConfigDisplay, NULL), + TXT_NewButton2("Configure Sound", + (TxtWidgetSignalFunc) ConfigSound, NULL), + TXT_NewButton2("Configure Keyboard", + (TxtWidgetSignalFunc) ConfigKeyboard, NULL), + TXT_NewButton2("Configure Mouse", + (TxtWidgetSignalFunc) ConfigMouse, NULL), + TXT_NewButton2("Configure Joystick", + (TxtWidgetSignalFunc) ConfigJoystick, NULL), + NULL); + + // The compatibility window is only appropriate for Doom. + + if (gamemission == doom) + { + txt_button_t *button; + + button = TXT_NewButton2("Compatibility", + (TxtWidgetSignalFunc) CompatibilitySettings, + NULL); + + TXT_AddWidget(window, button); + } + + TXT_AddWidgets(window, + GetLaunchButton(), + TXT_NewStrut(0, 1), + TXT_NewButton2("Start a Network Game", + (TxtWidgetSignalFunc) StartMultiGame, NULL), + TXT_NewButton2("Join a Network Game", + (TxtWidgetSignalFunc) JoinMultiGame, NULL), + TXT_NewButton2("Multiplayer Configuration", + (TxtWidgetSignalFunc) MultiplayerConfig, NULL), + NULL); + + quit_action = TXT_NewWindowAction(KEY_ESCAPE, "Quit"); + warp_action = TXT_NewWindowAction(KEY_F1, "Warp"); + TXT_SignalConnect(quit_action, "pressed", QuitConfirm, NULL); + TXT_SignalConnect(warp_action, "pressed", + (TxtWidgetSignalFunc) WarpMenu, NULL); + TXT_SetWindowAction(window, TXT_HORIZ_LEFT, quit_action); + TXT_SetWindowAction(window, TXT_HORIZ_CENTER, warp_action); + + TXT_SetKeyListener(window, MainMenuKeyPress, NULL); +} + +// +// Initialize all configuration variables, load config file, etc +// + +static void InitConfig(void) +{ + InitBindings(); + + SetChatMacroDefaults(); + SetPlayerNameDefault(); + + M_SetConfigDir(NULL); + M_LoadDefaults(); +} + +// +// Application icon +// + +static void SetIcon(void) +{ + SDL_Surface *surface; + Uint8 *mask; + int i; + + // Generate the mask + + mask = malloc(setup_icon_w * setup_icon_h / 8); + memset(mask, 0, setup_icon_w * setup_icon_h / 8); + + for (i=0; i<setup_icon_w * setup_icon_h; ++i) + { + if (setup_icon_data[i * 3] != 0x00 + || setup_icon_data[i * 3 + 1] != 0x00 + || setup_icon_data[i * 3 + 2] != 0x00) + { + mask[i / 8] |= 1 << (7 - i % 8); + } + } + + + surface = SDL_CreateRGBSurfaceFrom(setup_icon_data, + setup_icon_w, + setup_icon_h, + 24, + setup_icon_w * 3, + 0xff << 0, + 0xff << 8, + 0xff << 16, + 0); + + SDL_WM_SetIcon(surface, mask); + SDL_FreeSurface(surface); + free(mask); +} + +// Initialize the textscreen library. + +static void InitTextscreen(void) +{ + SetDisplayDriver(); + + if (!TXT_Init()) + { + fprintf(stderr, "Failed to initialize GUI\n"); + exit(-1); + } + + TXT_SetDesktopTitle(PACKAGE_NAME " Setup ver " PACKAGE_VERSION); + SetIcon(); +} + +// Restart the textscreen library. Used when the video_driver variable +// is changed. + +void RestartTextscreen(void) +{ + TXT_Shutdown(); + InitTextscreen(); +} + +// +// Initialize and run the textscreen GUI. +// + +static void RunGUI(void) +{ + InitTextscreen(); + + TXT_GUIMainLoop(); +} + +static void MissionSet(void) +{ + InitConfig(); + MainMenu(); +} + +void D_DoomMain(void) +{ + SetupMission(MissionSet); + + RunGUI(); +} + diff --git a/src/setup/mode.c b/src/setup/mode.c new file mode 100644 index 00000000..702db67d --- /dev/null +++ b/src/setup/mode.c @@ -0,0 +1,339 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// Copyright(C) 2006 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +// 02111-1307, USA. +// + +#include <stdlib.h> +#include <string.h> + +#include "doomtype.h" + +#include "config.h" +#include "textscreen.h" + +#include "doomtype.h" +#include "d_mode.h" +#include "d_iwad.h" +#include "i_system.h" +#include "m_argv.h" +#include "m_config.h" +#include "m_controls.h" + +#include "compatibility.h" +#include "display.h" +#include "joystick.h" +#include "keyboard.h" +#include "mouse.h" +#include "multiplayer.h" +#include "sound.h" + +#include "mode.h" + +GameMission_t gamemission; +static iwad_t **iwads; + +typedef struct +{ + char *label; + GameMission_t mission; + int mask; + char *name; + char *config_file; + char *extra_config_file; + char *executable; +} mission_config_t; + +// Default mission to fall back on, if no IWADs are found at all: + +#define DEFAULT_MISSION (&mission_configs[0]) + +static mission_config_t mission_configs[] = +{ + { + "Doom", + doom, + IWAD_MASK_DOOM, + "doom", + "default.cfg", + PROGRAM_PREFIX "doom.cfg", + PROGRAM_PREFIX "doom" + }, + { + "Heretic", + heretic, + IWAD_MASK_HERETIC, + "heretic", + "heretic.cfg", + PROGRAM_PREFIX "heretic.cfg", + PROGRAM_PREFIX "heretic" + }, + { + "Hexen", + hexen, + IWAD_MASK_HEXEN, + "hexen", + "hexen.cfg", + PROGRAM_PREFIX "hexen.cfg", + PROGRAM_PREFIX "hexen" + } +}; + +static GameSelectCallback game_selected_callback; + +// Miscellaneous variables that aren't used in setup. + +static int showMessages = 1; +static int screenblocks = 9; +static int detailLevel = 0; +static char *savedir = NULL; +static char *executable = NULL; + +static void BindMiscVariables(void) +{ + M_BindVariable("screenblocks", &screenblocks); + + if (gamemission == doom) + { + M_BindVariable("detaillevel", &detailLevel); + M_BindVariable("show_messages", &showMessages); + } + + if (gamemission == hexen) + { + M_BindVariable("savedir", &savedir); + M_BindVariable("messageson", &showMessages); + } +} + +// +// Initialise all configuration file bindings. +// + +void InitBindings(void) +{ + M_ApplyPlatformDefaults(); + + // Keyboard, mouse, joystick controls + + M_BindBaseControls(); + M_BindWeaponControls(); + M_BindMapControls(); + M_BindMenuControls(); + + if (gamemission == heretic || gamemission == hexen) + { + M_BindHereticControls(); + } + + if (gamemission == hexen) + { + M_BindHexenControls(); + } + + // All other variables + + BindCompatibilityVariables(); + BindDisplayVariables(); + BindJoystickVariables(); + BindKeyboardVariables(); + BindMouseVariables(); + BindSoundVariables(); + BindMiscVariables(); + BindMultiplayerVariables(); +} + +// Set the name of the executable program to run the game: + +static void SetExecutable(mission_config_t *config) +{ + char *extension; + + free(executable); + +#ifdef _WIN32 + extension = ".exe"; +#else + extension = ""; +#endif + + executable = malloc(strlen(config->executable) + 5); + sprintf(executable, "%s%s", config->executable, extension); +} + +static void SetMission(mission_config_t *config) +{ + iwads = D_FindAllIWADs(config->mask); + gamemission = config->mission; + SetExecutable(config); + M_SetConfigFilenames(config->config_file, config->extra_config_file); +} + +static mission_config_t *GetMissionForName(char *name) +{ + int i; + + for (i=0; i<arrlen(mission_configs); ++i) + { + if (!strcmp(mission_configs[i].name, name)) + { + return &mission_configs[i]; + } + } + + return NULL; +} + +// Check the name of the executable. If it contains one of the game +// names (eg. chocolate-hexen-setup.exe) then use that game. + +static boolean CheckExecutableName(GameSelectCallback callback) +{ + mission_config_t *config; + char *exe_name; + int i; + + exe_name = M_GetExecutableName(); + + for (i=0; i<arrlen(mission_configs); ++i) + { + config = &mission_configs[i]; + + if (strstr(exe_name, config->name) != NULL) + { + SetMission(config); + callback(); + return true; + } + } + + return false; +} + +static void GameSelected(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(config)) +{ + TXT_CAST_ARG(mission_config_t, config); + + SetMission(config); + game_selected_callback(); +} + +static void OpenGameSelectDialog(GameSelectCallback callback) +{ + mission_config_t *mission = NULL; + txt_window_t *window; + iwad_t **iwads; + int num_games; + int i; + + window = TXT_NewWindow("Select game"); + + TXT_AddWidget(window, TXT_NewLabel("Select a game to configure:\n")); + num_games = 0; + + // Add a button for each game. + + for (i=0; i<arrlen(mission_configs); ++i) + { + // Do we have any IWADs for this game installed? + // If so, add a button. + + iwads = D_FindAllIWADs(mission_configs[i].mask); + + if (iwads[0] != NULL) + { + mission = &mission_configs[i]; + TXT_AddWidget(window, TXT_NewButton2(mission_configs[i].label, + GameSelected, + &mission_configs[i])); + ++num_games; + } + + free(iwads); + } + + TXT_AddWidget(window, TXT_NewStrut(0, 1)); + + // No IWADs found at all? Fall back to doom, then. + + if (num_games == 0) + { + TXT_CloseWindow(window); + SetMission(DEFAULT_MISSION); + callback(); + return; + } + + // Only one game? Use that game, and don't bother with a dialog. + + if (num_games == 1) + { + TXT_CloseWindow(window); + SetMission(mission); + callback(); + return; + } + + game_selected_callback = callback; +} + +void SetupMission(GameSelectCallback callback) +{ + mission_config_t *config; + char *mission_name; + int p; + + //! + // @arg <game> + // + // Specify the game to configure the settings for. Valid + // values are 'doom', 'heretic' and 'hexen'. + // + + p = M_CheckParm("-game"); + + if (p > 0) + { + mission_name = myargv[p + 1]; + + config = GetMissionForName(mission_name); + + if (config == NULL) + { + I_Error("Invalid parameter - '%s'", mission_name); + } + + SetMission(config); + callback(); + } + else if (!CheckExecutableName(callback)) + { + OpenGameSelectDialog(callback); + } +} + +char *GetExecutableName(void) +{ + return executable; +} + +iwad_t **GetIwads(void) +{ + return iwads; +} + diff --git a/src/setup/mode.h b/src/setup/mode.h new file mode 100644 index 00000000..44046c38 --- /dev/null +++ b/src/setup/mode.h @@ -0,0 +1,37 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// Copyright(C) 2008 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +// 02111-1307, USA. +// + +#ifndef SETUP_MODE_H +#define SETUP_MODE_H + +#include "d_mode.h" +#include "d_iwad.h" + +typedef void (*GameSelectCallback)(void); +extern GameMission_t gamemission; + +void SetupMission(GameSelectCallback callback); +void InitBindings(void); +char *GetExecutableName(void); +iwad_t **GetIwads(void); + +#endif /* #ifndef SETUP_MODE_H */ + diff --git a/src/setup/mouse.c b/src/setup/mouse.c new file mode 100644 index 00000000..5b555f88 --- /dev/null +++ b/src/setup/mouse.c @@ -0,0 +1,169 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// Copyright(C) 2006 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +// 02111-1307, USA. +// + +#include <stdlib.h> + +#include "textscreen.h" +#include "doomtype.h" +#include "m_config.h" +#include "m_controls.h" + +#include "execute.h" +#include "txt_mouseinput.h" + +#include "mode.h" +#include "mouse.h" + +static int usemouse = 1; + +static int novert = 0; +static int mouseSensitivity = 5; +static float mouse_acceleration = 2.0; +static int mouse_threshold = 10; +static int grabmouse = 1; + +static int *all_mouse_buttons[] = { + &mousebfire, + &mousebstrafe, + &mousebforward, + &mousebstrafeleft, + &mousebstraferight, + &mousebbackward, + &mousebuse, + &mousebjump, + &mousebprevweapon, + &mousebnextweapon +}; + +static void MouseSetCallback(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(variable)) +{ + TXT_CAST_ARG(int, variable); + unsigned int i; + + // Check if the same mouse button is used for a different action + // If so, set the other action(s) to -1 (unset) + + for (i=0; i<arrlen(all_mouse_buttons); ++i) + { + if (*all_mouse_buttons[i] == *variable + && all_mouse_buttons[i] != variable) + { + *all_mouse_buttons[i] = -1; + } + } +} + +static void AddMouseControl(txt_table_t *table, char *label, int *var) +{ + txt_mouse_input_t *mouse_input; + + TXT_AddWidget(table, TXT_NewLabel(label)); + + mouse_input = TXT_NewMouseInput(var); + TXT_AddWidget(table, mouse_input); + + TXT_SignalConnect(mouse_input, "set", MouseSetCallback, var); +} + +static void ConfigExtraButtons(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(unused)) +{ + txt_window_t *window; + txt_table_t *buttons_table; + + window = TXT_NewWindow("Additional mouse buttons"); + + TXT_AddWidgets(window, + buttons_table = TXT_NewTable(2), + NULL); + + TXT_SetColumnWidths(buttons_table, 29, 5); + + AddMouseControl(buttons_table, "Move backward", &mousebbackward); + AddMouseControl(buttons_table, "Use", &mousebuse); + AddMouseControl(buttons_table, "Strafe left", &mousebstrafeleft); + AddMouseControl(buttons_table, "Strafe right", &mousebstraferight); + + if (gamemission == hexen) + { + AddMouseControl(buttons_table, "Jump", &mousebjump); + } + + AddMouseControl(buttons_table, "Previous weapon", &mousebprevweapon); + AddMouseControl(buttons_table, "Next weapon", &mousebnextweapon); +} + +void ConfigMouse(void) +{ + txt_window_t *window; + txt_table_t *motion_table; + txt_table_t *buttons_table; + + window = TXT_NewWindow("Mouse configuration"); + + TXT_AddWidgets(window, + TXT_NewCheckBox("Enable mouse", &usemouse), + TXT_NewInvertedCheckBox("Allow vertical mouse movement", + &novert), + TXT_NewCheckBox("Grab mouse in windowed mode", + &grabmouse), + TXT_NewCheckBox("Double click acts as \"use\"", + &dclick_use), + + TXT_NewSeparator("Mouse motion"), + motion_table = TXT_NewTable(2), + + TXT_NewSeparator("Buttons"), + buttons_table = TXT_NewTable(2), + TXT_NewButton2("More controls...", + ConfigExtraButtons, + NULL), + NULL); + + TXT_SetColumnWidths(motion_table, 27, 5); + + TXT_AddWidgets(motion_table, + TXT_NewLabel("Speed"), + TXT_NewSpinControl(&mouseSensitivity, 1, 256), + TXT_NewLabel("Acceleration"), + TXT_NewFloatSpinControl(&mouse_acceleration, 1.0, 5.0), + TXT_NewLabel("Acceleration threshold"), + TXT_NewSpinControl(&mouse_threshold, 0, 32), + NULL); + + TXT_SetColumnWidths(buttons_table, 27, 5); + + AddMouseControl(buttons_table, "Fire/Attack", &mousebfire); + AddMouseControl(buttons_table, "Move forward", &mousebforward); + AddMouseControl(buttons_table, "Strafe on", &mousebstrafe); + + TXT_SetWindowAction(window, TXT_HORIZ_CENTER, TestConfigAction()); +} + +void BindMouseVariables(void) +{ + M_BindVariable("use_mouse", &usemouse); + M_BindVariable("novert", &novert); + M_BindVariable("mouse_sensitivity", &mouseSensitivity); + M_BindVariable("mouse_acceleration", &mouse_acceleration); + M_BindVariable("mouse_threshold", &mouse_threshold); + M_BindVariable("grabmouse", &grabmouse); +} + diff --git a/src/setup/mouse.h b/src/setup/mouse.h new file mode 100644 index 00000000..cdaa541a --- /dev/null +++ b/src/setup/mouse.h @@ -0,0 +1,29 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// Copyright(C) 2006 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +// 02111-1307, USA. +// + +#ifndef SETUP_MOUSE_H +#define SETUP_MOUSE_H + +void ConfigMouse(void); +void BindMouseVariables(void); + +#endif /* #ifndef SETUP_MOUSE_H */ + diff --git a/src/setup/multiplayer.c b/src/setup/multiplayer.c new file mode 100644 index 00000000..aed89212 --- /dev/null +++ b/src/setup/multiplayer.c @@ -0,0 +1,968 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// Copyright(C) 2006 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +// 02111-1307, USA. +// + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "doomtype.h" +#include "textscreen.h" + +#include "d_iwad.h" +#include "m_config.h" +#include "doom/d_englsh.h" +#include "m_controls.h" + +#include "multiplayer.h" +#include "mode.h" +#include "execute.h" + +#define NUM_WADS 10 +#define NUM_EXTRA_PARAMS 10 + +typedef enum +{ + WARP_ExMy, + WARP_MAPxy, +} warptype_t; + +typedef enum +{ + JOIN_AUTO_LAN, + JOIN_ADDRESS, +} jointype_t; + +// Fallback IWAD if none are found to be installed + +static iwad_t fallback_iwad = { "doom2.wad", doom2, commercial, "Doom II" }; +static iwad_t *fallback_iwad_list[2] = { &fallback_iwad, NULL }; + +// Array of IWADs found to be installed + +static iwad_t **found_iwads; +static char *iwad_labels[8]; + +// Index of the currently selected IWAD + +static int found_iwad_selected; + +// Filename to pass to '-iwad'. + +static char *iwadfile; + +static char *doom_skills[] = +{ + "I'm too young to die.", + "Hey, not too rough.", + "Hurt me plenty.", + "Ultra-Violence.", + "NIGHTMARE!", +}; + +static char *chex_skills[] = +{ + "Easy does it", + "Not so sticky", + "Gobs of goo", + "Extreme ooze", + "SUPER SLIMEY!" +}; + +static char *heretic_skills[] = +{ + "Thou needeth a wet-nurse", + "Yellowbellies-R-us", + "Bringest them oneth", + "Thou art a smite-meister", + "Black plague possesses thee" +}; + +static char *hexen_skills[] = +{ + "Squire/Altar boy/Apprentice", + "Knight/Acolyte/Enchanter", + "Warrior/Priest/Sorceror", + "Berserker/Cardinal/Warlock", + "Titan/Pope/Archimage" +}; + +static char *character_classes[] = +{ + "Fighter", + "Cleric", + "Mage" +}; + +static struct +{ + GameMission_t mission; + char **strings; +} skills[] = +{ + { doom, doom_skills }, + { heretic, heretic_skills }, + { hexen, hexen_skills } +}; + +static char *gamemodes[] = +{ + "Co-operative", + "Deathmatch", + "Deathmatch 2.0", +}; + +static char *net_player_name; +static char *chat_macros[10]; + +static int jointype = JOIN_ADDRESS; + +static char *wads[NUM_WADS]; +static char *extra_params[NUM_EXTRA_PARAMS]; +static int character_class = 0; +static int skill = 2; +static int nomonsters = 0; +static int deathmatch = 0; +static int fast = 0; +static int respawn = 0; +static int udpport = 2342; +static int timer = 0; +static int privateserver = 0; + +static txt_dropdown_list_t *skillbutton; +static txt_button_t *warpbutton; +static warptype_t warptype = WARP_MAPxy; +static int warpepisode = 1; +static int warpmap = 1; + +// Address to connect to when joining a game + +static char *connect_address = NULL; + +// Find an IWAD from its description + +static iwad_t *GetCurrentIWAD(void) +{ + return found_iwads[found_iwad_selected]; +} + +// Is the currently selected IWAD the Chex Quest chex.wad? + +static boolean IsChexQuest(iwad_t *iwad) +{ + return !strcmp(iwad->name, "chex.wad"); +} + +static void AddWADs(execute_context_t *exec) +{ + int have_wads = 0; + int i; + + for (i=0; i<NUM_WADS; ++i) + { + if (wads[i] != NULL && strlen(wads[i]) > 0) + { + if (!have_wads) + { + AddCmdLineParameter(exec, "-file"); + } + + AddCmdLineParameter(exec, "\"%s\"", wads[i]); + } + } +} + +static void AddExtraParameters(execute_context_t *exec) +{ + int i; + + for (i=0; i<NUM_EXTRA_PARAMS; ++i) + { + if (extra_params[i] != NULL && strlen(extra_params[i]) > 0) + { + AddCmdLineParameter(exec, extra_params[i]); + } + } +} + +static void AddIWADParameter(execute_context_t *exec) +{ + if (iwadfile != NULL) + { + AddCmdLineParameter(exec, "-iwad %s", iwadfile); + } +} + +// Callback function invoked to launch the game. +// This is used when starting a server and also when starting a +// single player game via the "warp" menu. + +static void StartGame(int multiplayer) +{ + execute_context_t *exec; + + exec = NewExecuteContext(); + + // Extra parameters come first, before all others; this way, + // they can override any of the options set in the dialog. + + AddExtraParameters(exec); + + AddIWADParameter(exec); + AddCmdLineParameter(exec, "-skill %i", skill + 1); + + if (gamemission == hexen) + { + AddCmdLineParameter(exec, "-class %i", character_class); + } + + if (nomonsters) + { + AddCmdLineParameter(exec, "-nomonsters"); + } + + if (fast) + { + AddCmdLineParameter(exec, "-fast"); + } + + if (respawn) + { + AddCmdLineParameter(exec, "-respawn"); + } + + if (warptype == WARP_ExMy) + { + // TODO: select IWAD based on warp type + AddCmdLineParameter(exec, "-warp %i %i", warpepisode, warpmap); + } + else if (warptype == WARP_MAPxy) + { + AddCmdLineParameter(exec, "-warp %i", warpmap); + } + + // Multiplayer-specific options: + + if (multiplayer) + { + AddCmdLineParameter(exec, "-server"); + AddCmdLineParameter(exec, "-port %i", udpport); + + if (deathmatch == 1) + { + AddCmdLineParameter(exec, "-deathmatch"); + } + else if (deathmatch == 2) + { + AddCmdLineParameter(exec, "-altdeath"); + } + + if (timer > 0) + { + AddCmdLineParameter(exec, "-timer %i", timer); + } + + if (privateserver) + { + AddCmdLineParameter(exec, "-privateserver"); + } + } + + AddWADs(exec); + + TXT_Shutdown(); + + M_SaveDefaults(); + PassThroughArguments(exec); + + ExecuteDoom(exec); + + exit(0); +} + +static void StartServerGame(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(unused)) +{ + StartGame(1); +} + +static void StartSinglePlayerGame(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(unused)) +{ + StartGame(0); +} + +static void UpdateWarpButton(void) +{ + char buf[10]; + + if (warptype == WARP_ExMy) + { + sprintf(buf, "E%iM%i", warpepisode, warpmap); + } + else if (warptype == WARP_MAPxy) + { + sprintf(buf, "MAP%02i", warpmap); + } + + TXT_SetButtonLabel(warpbutton, buf); +} + +static void UpdateSkillButton(void) +{ + iwad_t *iwad = GetCurrentIWAD(); + int i; + + if (IsChexQuest(iwad)) + { + skillbutton->values = chex_skills; + } + else + { + for (i=0; i<arrlen(skills); ++i) + { + if (gamemission == skills[i].mission) + { + skillbutton->values = skills[i].strings; + break; + } + } + } +} + +static void SetExMyWarp(TXT_UNCAST_ARG(widget), void *val) +{ + int l; + + l = (int) val; + + warpepisode = l / 10; + warpmap = l % 10; + + UpdateWarpButton(); +} + +static void SetMAPxyWarp(TXT_UNCAST_ARG(widget), void *val) +{ + int l; + + l = (int) val; + + warpmap = l; + + UpdateWarpButton(); +} + +static void CloseLevelSelectDialog(TXT_UNCAST_ARG(button), TXT_UNCAST_ARG(window)) +{ + TXT_CAST_ARG(txt_window_t, window); + + TXT_CloseWindow(window); +} + +static void LevelSelectDialog(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(user_data)) +{ + txt_window_t *window; + txt_table_t *table; + txt_button_t *button; + iwad_t *iwad; + char buf[10]; + int episodes; + int x, y; + int l; + int i; + + window = TXT_NewWindow("Select level"); + iwad = GetCurrentIWAD(); + + if (warptype == WARP_ExMy) + { + episodes = D_GetNumEpisodes(iwad->mission, iwad->mode); + table = TXT_NewTable(episodes); + + // ExMy levels + + for (y=1; y<10; ++y) + { + for (x=1; x<=episodes; ++x) + { + if (IsChexQuest(iwad) && (x > 1 || y > 5)) + { + continue; + } + + if (!D_ValidEpisodeMap(iwad->mission, iwad->mode, x, y)) + { + TXT_AddWidget(table, NULL); + continue; + } + + sprintf(buf, " E%iM%i ", x, y); + button = TXT_NewButton(buf); + TXT_SignalConnect(button, "pressed", + SetExMyWarp, (void *) (x * 10 + y)); + TXT_SignalConnect(button, "pressed", + CloseLevelSelectDialog, window); + TXT_AddWidget(table, button); + + if (warpepisode == x && warpmap == y) + { + TXT_SelectWidget(table, button); + } + } + } + } + else + { + table = TXT_NewTable(4); + + for (i=0; i<40; ++i) + { + x = i % 4; + y = i / 4; + + l = x * 10 + y + 1; + + if (!D_ValidEpisodeMap(iwad->mission, iwad->mode, 1, l)) + { + TXT_AddWidget(table, NULL); + continue; + } + + sprintf(buf, " MAP%02i ", l); + button = TXT_NewButton(buf); + TXT_SignalConnect(button, "pressed", + SetMAPxyWarp, (void *) l); + TXT_SignalConnect(button, "pressed", + CloseLevelSelectDialog, window); + TXT_AddWidget(table, button); + + if (warpmap == l) + { + TXT_SelectWidget(table, button); + } + } + } + + TXT_AddWidget(window, table); +} + +static void IWADSelected(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(unused)) +{ + iwad_t *iwad; + + // Find the iwad_t selected + + iwad = GetCurrentIWAD(); + + // Update iwadfile + + iwadfile = iwad->name; +} + +// Called when the IWAD button is changed, to update warptype. + +static void UpdateWarpType(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(unused)) +{ + warptype_t new_warptype; + iwad_t *iwad; + + // Get the selected IWAD + + iwad = GetCurrentIWAD(); + + // Find the new warp type + + if (D_IsEpisodeMap(iwad->mission)) + { + new_warptype = WARP_ExMy; + } + else + { + new_warptype = WARP_MAPxy; + } + + // Reset to E1M1 / MAP01 when the warp type is changed. + + if (new_warptype != warptype) + { + warpepisode = 1; + warpmap = 1; + } + + warptype = new_warptype; + + UpdateWarpButton(); + UpdateSkillButton(); +} + +static txt_widget_t *IWADSelector(void) +{ + txt_dropdown_list_t *dropdown; + txt_widget_t *result; + int num_iwads; + unsigned int i; + + // Find out what WADs are installed + + found_iwads = GetIwads(); + + // Build a list of the descriptions for all installed IWADs + + num_iwads = 0; + + for (i=0; found_iwads[i] != NULL; ++i) + { + iwad_labels[i] = found_iwads[i]->description; + ++num_iwads; + } + + // If no IWADs are found, provide Doom 2 as an option, but + // we're probably screwed. + + if (num_iwads == 0) + { + found_iwads = fallback_iwad_list; + num_iwads = 1; + } + + // Build a dropdown list of IWADs + + if (num_iwads < 2) + { + // We have only one IWAD. Show as a label. + + result = (txt_widget_t *) TXT_NewLabel(found_iwads[0]->description); + } + else + { + // Dropdown list allowing IWAD to be selected. + + dropdown = TXT_NewDropdownList(&found_iwad_selected, + iwad_labels, num_iwads); + + TXT_SignalConnect(dropdown, "changed", IWADSelected, NULL); + + result = (txt_widget_t *) dropdown; + } + + // Select first in the list. + + found_iwad_selected = 0; + IWADSelected(NULL, NULL); + + return result; +} + +// Create the window action button to start the game. This invokes +// a different callback depending on whether to start a multiplayer +// or single player game. + +static txt_window_action_t *StartGameAction(int multiplayer) +{ + txt_window_action_t *action; + TxtWidgetSignalFunc callback; + + action = TXT_NewWindowAction(KEY_F10, "Start"); + + if (multiplayer) + { + callback = StartServerGame; + } + else + { + callback = StartSinglePlayerGame; + } + + TXT_SignalConnect(action, "pressed", callback, NULL); + + return action; +} + +static void OpenWadsWindow(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(user_data)) +{ + txt_window_t *window; + int i; + + window = TXT_NewWindow("Add WADs"); + + for (i=0; i<NUM_WADS; ++i) + { + TXT_AddWidget(window, TXT_NewInputBox(&wads[i], 60)); + } +} + +static void OpenExtraParamsWindow(TXT_UNCAST_ARG(widget), + TXT_UNCAST_ARG(user_data)) +{ + txt_window_t *window; + int i; + + window = TXT_NewWindow("Extra command line parameters"); + + for (i=0; i<NUM_EXTRA_PARAMS; ++i) + { + TXT_AddWidget(window, TXT_NewInputBox(&extra_params[i], 70)); + } +} + +static txt_window_action_t *WadWindowAction(void) +{ + txt_window_action_t *action; + + action = TXT_NewWindowAction('w', "Add WADs"); + TXT_SignalConnect(action, "pressed", OpenWadsWindow, NULL); + + return action; +} + +// "Start game" menu. This is used for the start server window +// and the single player warp menu. The parameters specify +// the window title and whether to display multiplayer options. + +static void StartGameMenu(char *window_title, int multiplayer) +{ + txt_window_t *window; + txt_table_t *gameopt_table; + txt_table_t *advanced_table; + txt_widget_t *iwad_selector; + int num_mult_types = 2; + + window = TXT_NewWindow(window_title); + + TXT_AddWidgets(window, + gameopt_table = TXT_NewTable(2), + TXT_NewSeparator("Monster options"), + TXT_NewInvertedCheckBox("Monsters enabled", &nomonsters), + TXT_NewCheckBox("Fast monsters", &fast), + TXT_NewCheckBox("Respawning monsters", &respawn), + TXT_NewSeparator("Advanced"), + advanced_table = TXT_NewTable(2), + NULL); + + TXT_SetWindowAction(window, TXT_HORIZ_CENTER, WadWindowAction()); + TXT_SetWindowAction(window, TXT_HORIZ_RIGHT, StartGameAction(multiplayer)); + + TXT_SetColumnWidths(gameopt_table, 12, 6); + + if (gamemission == doom) + { + num_mult_types = 3; + } + else + { + num_mult_types = 2; + } + + TXT_AddWidgets(gameopt_table, + TXT_NewLabel("Game"), + iwad_selector = IWADSelector(), + TXT_NewLabel("Skill"), + skillbutton = TXT_NewDropdownList(&skill, doom_skills, 5), + TXT_NewLabel("Level warp"), + warpbutton = TXT_NewButton2("????", LevelSelectDialog, NULL), + NULL); + + if (gamemission == hexen) + { + TXT_AddWidgets(gameopt_table, + TXT_NewLabel("Character class "), + TXT_NewDropdownList(&character_class, + character_classes, 3), + NULL); + } + + if (multiplayer) + { + TXT_AddWidgets(gameopt_table, + TXT_NewLabel("Game type"), + TXT_NewDropdownList(&deathmatch, gamemodes, num_mult_types), + TXT_NewLabel("Time limit"), + TXT_NewHorizBox(TXT_NewIntInputBox(&timer, 2), + TXT_NewLabel("minutes"), + NULL), + NULL); + + TXT_AddWidget(window, + TXT_NewInvertedCheckBox("Register with master server", + &privateserver)); + + TXT_AddWidgets(advanced_table, + TXT_NewLabel("UDP port"), + TXT_NewIntInputBox(&udpport, 5), + NULL); + } + + TXT_AddWidget(window, + TXT_NewButton2("Add extra parameters...", + OpenExtraParamsWindow, NULL)); + + TXT_SetColumnWidths(advanced_table, 12, 6); + + TXT_SignalConnect(iwad_selector, "changed", UpdateWarpType, NULL); + + UpdateWarpType(NULL, NULL); + UpdateWarpButton(); +} + +void StartMultiGame(void) +{ + StartGameMenu("Start multiplayer game", 1); +} + +void WarpMenu(void) +{ + StartGameMenu("Level Warp", 0); +} + +static void DoJoinGame(void *unused1, void *unused2) +{ + execute_context_t *exec; + + exec = NewExecuteContext(); + + if (jointype == JOIN_ADDRESS) + { + AddCmdLineParameter(exec, "-connect %s", connect_address); + } + else if (jointype == JOIN_AUTO_LAN) + { + AddCmdLineParameter(exec, "-autojoin"); + } + + if (gamemission == hexen) + { + AddCmdLineParameter(exec, "-class %i", character_class); + } + + // Extra parameters come first, so that they can be used to override + // the other parameters. + + AddExtraParameters(exec); + AddIWADParameter(exec); + AddWADs(exec); + + TXT_Shutdown(); + + M_SaveDefaults(); + + PassThroughArguments(exec); + + ExecuteDoom(exec); + + exit(0); +} + +static txt_window_action_t *JoinGameAction(void) +{ + txt_window_action_t *action; + + action = TXT_NewWindowAction(KEY_F10, "Connect"); + TXT_SignalConnect(action, "pressed", DoJoinGame, NULL); + + return action; +} + +// When an address is entered, select "address" mode. + +static void SelectAddressJoin(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(unused)) +{ + jointype = JOIN_ADDRESS; +} + +void JoinMultiGame(void) +{ + txt_window_t *window; + txt_table_t *gameopt_table; + txt_table_t *serveropt_table; + txt_inputbox_t *address_box; + + window = TXT_NewWindow("Join multiplayer game"); + + TXT_AddWidgets(window, + gameopt_table = TXT_NewTable(2), + TXT_NewSeparator("Server"), + serveropt_table = TXT_NewTable(2), + TXT_NewStrut(0, 1), + TXT_NewButton2("Add extra parameters...", OpenExtraParamsWindow, NULL), + NULL); + + TXT_SetColumnWidths(gameopt_table, 12, 12); + + TXT_AddWidgets(gameopt_table, + TXT_NewLabel("Game"), + IWADSelector(), + NULL); + + if (gamemission == hexen) + { + TXT_AddWidgets(gameopt_table, + TXT_NewLabel("Character class "), + TXT_NewDropdownList(&character_class, + character_classes, 3), + NULL); + } + + TXT_AddWidgets(serveropt_table, + TXT_NewRadioButton("Connect to address:", + &jointype, JOIN_ADDRESS), + address_box = TXT_NewInputBox(&connect_address, 30), + TXT_NewRadioButton("Auto-join LAN game", + &jointype, JOIN_AUTO_LAN), + NULL); + + TXT_SignalConnect(address_box, "changed", SelectAddressJoin, NULL); + TXT_SelectWidget(window, address_box); + + TXT_SetWindowAction(window, TXT_HORIZ_CENTER, WadWindowAction()); + TXT_SetWindowAction(window, TXT_HORIZ_RIGHT, JoinGameAction()); +} + +void SetChatMacroDefaults(void) +{ + int i; + char *defaults[] = + { + HUSTR_CHATMACRO1, + HUSTR_CHATMACRO2, + HUSTR_CHATMACRO3, + HUSTR_CHATMACRO4, + HUSTR_CHATMACRO5, + HUSTR_CHATMACRO6, + HUSTR_CHATMACRO7, + HUSTR_CHATMACRO8, + HUSTR_CHATMACRO9, + HUSTR_CHATMACRO0, + }; + + // If the chat macros have not been set, initialize with defaults. + + for (i=0; i<10; ++i) + { + if (chat_macros[i] == NULL) + { + chat_macros[i] = strdup(defaults[i]); + } + } +} + +void SetPlayerNameDefault(void) +{ + if (net_player_name == NULL) + { + net_player_name = getenv("USER"); + } + + if (net_player_name == NULL) + { + net_player_name = getenv("USERNAME"); + } + + if (net_player_name == NULL) + { + net_player_name = "player"; + } +} + +void MultiplayerConfig(void) +{ + txt_window_t *window; + txt_label_t *label; + txt_table_t *table; + char buf[10]; + int i; + + window = TXT_NewWindow("Multiplayer Configuration"); + + TXT_AddWidgets(window, + TXT_NewStrut(0, 1), + TXT_NewHorizBox(TXT_NewLabel("Player name: "), + TXT_NewInputBox(&net_player_name, 25), + NULL), + TXT_NewStrut(0, 1), + TXT_NewSeparator("Chat macros"), + NULL); + + table = TXT_NewTable(2); + + for (i=0; i<10; ++i) + { + sprintf(buf, "#%i ", i + 1); + + label = TXT_NewLabel(buf); + TXT_SetFGColor(label, TXT_COLOR_BRIGHT_CYAN); + + TXT_AddWidgets(table, + label, + TXT_NewInputBox(&chat_macros[(i + 1) % 10], 40), + NULL); + } + + TXT_AddWidget(window, table); +} + +void BindMultiplayerVariables(void) +{ + char buf[15]; + int i; + +#ifdef FEATURE_MULTIPLAYER + M_BindVariable("player_name", &net_player_name); +#endif + + for (i=0; i<10; ++i) + { + sprintf(buf, "chatmacro%i", i); + M_BindVariable(buf, &chat_macros[i]); + } + + switch (gamemission) + { + case doom: + M_BindChatControls(4); + key_multi_msgplayer[0] = 'g'; + key_multi_msgplayer[1] = 'i'; + key_multi_msgplayer[2] = 'b'; + key_multi_msgplayer[3] = 'r'; + break; + + case heretic: + M_BindChatControls(4); + key_multi_msgplayer[0] = 'g'; + key_multi_msgplayer[1] = 'y'; + key_multi_msgplayer[2] = 'r'; + key_multi_msgplayer[3] = 'b'; + break; + + case hexen: + M_BindChatControls(8); + key_multi_msgplayer[0] = 'b'; + key_multi_msgplayer[1] = 'r'; + key_multi_msgplayer[2] = 'y'; + key_multi_msgplayer[3] = 'g'; + key_multi_msgplayer[4] = 'j'; + key_multi_msgplayer[5] = 'w'; + key_multi_msgplayer[6] = 'h'; + key_multi_msgplayer[7] = 'p'; + break; + + default: + break; + } +} + diff --git a/src/setup/multiplayer.h b/src/setup/multiplayer.h new file mode 100644 index 00000000..afc8a2a8 --- /dev/null +++ b/src/setup/multiplayer.h @@ -0,0 +1,36 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// Copyright(C) 2006 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +// 02111-1307, USA. +// + +#ifndef SETUP_MULTIPLAYER_H +#define SETUP_MULTIPLAYER_H + +void StartMultiGame(void); +void WarpMenu(void); +void JoinMultiGame(void); +void MultiplayerConfig(void); + +void SetChatMacroDefaults(void); +void SetPlayerNameDefault(void); + +void BindMultiplayerVariables(void); + +#endif /* #ifndef SETUP_MULTIPLAYER_H */ + diff --git a/src/setup/setup-manifest.xml.in b/src/setup/setup-manifest.xml.in new file mode 100644 index 00000000..ff879263 --- /dev/null +++ b/src/setup/setup-manifest.xml.in @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> + +<!-- Magic manifest file that should make Windows Vista/7 not + attempt to gain elevated privileges for chocolate-setup. + + Based on: + + http://www.cygwin.com/ml/cygwin/2006-12/msg00580.html + --> + +<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> + <!-- The "name" field in this tag should be the same as the executable's + name --> + <assemblyIdentity version="0.0.0.0" processorArchitecture="X86" + name="@PROGRAM_PREFIX@setup.exe" type="win32"/> + <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3"> + <security> + <requestedPrivileges> + <requestedExecutionLevel level="asInvoker" uiAccess="false" /> + </requestedPrivileges> + </security> + </trustInfo> + + <!-- Stop the Program Compatibility Assistant appearing: --> + + <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"> + <application> + <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/> <!-- 7 --> + <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/> <!-- Vista --> + </application> + </compatibility> +</assembly> + diff --git a/src/setup/setup.desktop.in b/src/setup/setup.desktop.in new file mode 100644 index 00000000..79fb38be --- /dev/null +++ b/src/setup/setup.desktop.in @@ -0,0 +1,7 @@ +[Desktop Entry] +Name=@PACKAGE_NAME@ Setup +Exec=@PROGRAM_PREFIX@setup +Icon=@PROGRAM_PREFIX@setup +Type=Application +Comment=Setup tool for @PACKAGE_NAME@ +Categories=Settings;ConsoleOnly; diff --git a/src/setup/setup_icon.c b/src/setup/setup_icon.c new file mode 100644 index 00000000..1c18c56f --- /dev/null +++ b/src/setup/setup_icon.c @@ -0,0 +1,262 @@ +static int setup_icon_w = 32; +static int setup_icon_h = 32; + +static unsigned char setup_icon_data[] = { + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0xa2,0x86,0x73, + 0xa9,0x8d,0x7a, 0xbc,0x9f,0x8c, 0xda,0xba,0xa0, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0xbe,0x8e,0x68, 0xd7,0xb9,0xa5, 0xeb,0xd8,0xcd, 0xd3,0xbf,0xae, + 0xbe,0xa1,0x8d, 0xeb,0xd8,0xcd, 0xc2,0x9d,0x86, 0x95,0x5d,0x38, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x78,0x7a,0x77, 0x78,0x7a,0x77, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x78,0x7a,0x77, 0x78,0x7a,0x77, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x9f,0x82,0x6a, + 0xc5,0x9e,0x81, 0xd1,0xb2,0x98, 0xd4,0xac,0x8e, 0xeb,0xd8,0xcd, + 0xc4,0x9b,0x79, 0xad,0x71,0x45, 0xd4,0xac,0x8e, 0xb9,0x93,0x76, + 0xa1,0x75,0x56, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x78,0x7a,0x77, 0x6d,0x6f,0x6c, 0xcb,0xce,0xca, + 0x51,0x52,0x50, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x5b,0x5d,0x5a, + 0xca,0xcc,0xc9, 0x77,0x79,0x76, 0x78,0x7a,0x77, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0xda,0xb4,0x9c, 0xd3,0xa3,0x83, + 0xaf,0x91,0x78, 0xa7,0x83,0x6d, 0xc4,0xa7,0x93, 0xee,0xe2,0xd5, + 0xeb,0xd8,0xcd, 0x8c,0x60,0x3d, 0x92,0x6f,0x59, 0xd0,0xa7,0x84, + 0x84,0x54,0x33, 0xba,0x83,0x5b, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x78,0x7a,0x77, 0xa0,0xa2,0x9f, 0xdf,0xe1,0xde, + 0x58,0x5a,0x58, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x64,0x65,0x63, + 0xdd,0xdf,0xdc, 0xa8,0xaa,0xa7, 0x78,0x7a,0x77, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0xd4,0xb5,0x9b, 0xc3,0x8c,0x63, 0xc4,0x94,0x6e, + 0x98,0x66,0x45, 0x78,0x50,0x2d, 0xd7,0xb9,0xa5, 0xee,0xdc,0xd1, + 0xc4,0x9b,0x79, 0xb6,0x80,0x58, 0x65,0x45,0x26, 0xb6,0x79,0x4d, + 0xcf,0xa5,0x83, 0x9a,0x6e,0x50, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x82,0x83,0x81, 0xbb,0xbd,0xba, 0xde,0xe0,0xdd, + 0x58,0x5a,0x58, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x64,0x65,0x63, + 0xdc,0xde,0xdb, 0xc4,0xc6,0xc3, 0x78,0x7a,0x77, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x9e,0x7b,0x65, 0xbc,0x8c,0x67, 0xaa,0x7d,0x5e, 0xa1,0x75,0x56, + 0x89,0x5f,0x41, 0xc4,0xa7,0x93, 0xb7,0x88,0x63, 0x90,0x6c,0x51, + 0x79,0x4b,0x2b, 0x8c,0x5b,0x34, 0x76,0x4e,0x31, 0x7f,0x50,0x30, + 0xcf,0xa5,0x83, 0xd4,0xac,0x8e, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x77,0x79,0x76, 0xd2,0xd4,0xd1, 0xde,0xe0,0xdd, + 0x64,0x65,0x63, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x68,0x69,0x67, + 0xdb,0xdd,0xda, 0xda,0xdc,0xd9, 0x78,0x7a,0x77, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0xd8,0xb8,0x9e, + 0xd4,0xac,0x8e, 0xc5,0x9e,0x81, 0xab,0x7e,0x5f, 0x9c,0x6f,0x4b, + 0xbe,0xa1,0x8d, 0x8c,0x60,0x3d, 0x6e,0x47,0x2b, 0x87,0x5e,0x40, + 0x5a,0x3b,0x23, 0x68,0x42,0x26, 0x65,0x40,0x23, 0x53,0x36,0x22, + 0x7e,0x55,0x38, 0xce,0x9f,0x7e, 0xc3,0x8c,0x63, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x77,0x79,0x76, 0xe1,0xe4,0xe0, 0xe1,0xe4,0xe0, + 0xc4,0xc6,0xc3, 0x83,0x85,0x82, 0x8c,0x8d,0x8a, 0xd2,0xd4,0xd1, + 0xee,0xdc,0xd1, 0xe1,0xe4,0xe0, 0x78,0x7a,0x77, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0xcb,0x9a,0x74, + 0xb6,0x80,0x58, 0x8c,0x60,0x3d, 0x76,0x4e,0x31, 0x88,0x57,0x31, + 0x83,0x53,0x33, 0x84,0x54,0x33, 0x95,0x5d,0x38, 0x79,0x4b,0x2b, + 0x5c,0x38,0x22, 0x84,0x54,0x33, 0x55,0x37,0x1e, 0x96,0x6b,0x4d, + 0xb4,0x7f,0x5c, 0xba,0x83,0x5b, 0xb8,0x7b,0x4f, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x9a,0x9b,0x98, 0xd9,0xdb,0xd7, + 0xe1,0xe4,0xe0, 0xde,0xe0,0xdd, 0xdd,0xdf,0xdc, 0xe0,0xe2,0xdf, + 0xda,0xdc,0xd9, 0xa3,0xa5,0xa1, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0xc0,0x89,0x60, + 0x89,0x5f,0x41, 0x84,0x54,0x33, 0x84,0x54,0x33, 0x8a,0x5a,0x39, + 0x8f,0x5d,0x37, 0x78,0x50,0x2d, 0x8c,0x5b,0x34, 0x5a,0x3b,0x23, + 0x5e,0x3f,0x27, 0x76,0x4e,0x31, 0x97,0x64,0x3d, 0x74,0x4b,0x29, + 0x78,0x50,0x2d, 0x7b,0x4d,0x2c, 0xb6,0x80,0x58, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x64,0x65,0x63, + 0xbe,0xc1,0xbd, 0xee,0xdc,0xd1, 0xe1,0xe4,0xe0, 0xc2,0xc4,0xc1, + 0x68,0x69,0x67, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x95,0x62,0x3b, + 0x84,0x54,0x33, 0x88,0x57,0x31, 0x7e,0x6e,0x64, 0xc4,0x94,0x6e, + 0x76,0x4e,0x31, 0x90,0x6c,0x51, 0xa1,0x7c,0x60, 0x9a,0x6e,0x50, + 0x95,0x5d,0x38, 0xbc,0x7f,0x53, 0xad,0x71,0x45, 0x76,0x4e,0x31, + 0x53,0x36,0x22, 0x4b,0x2f,0x1c, 0x70,0x49,0x2c, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x51,0x52,0x50, 0xd2,0xd4,0xd1, 0xe0,0xe2,0xdf, 0x77,0x79,0x76, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x84,0x54,0x33, + 0xa3,0x86,0x6e, 0xc4,0x94,0x6e, 0x88,0x64,0x44, 0xbc,0x8c,0x67, + 0x9c,0x6f,0x4b, 0xa1,0x6d,0x45, 0x93,0x60,0x3a, 0xad,0x71,0x3f, + 0xb4,0x7f,0x5c, 0xbc,0x8c,0x67, 0xc0,0x89,0x60, 0xb3,0x76,0x4b, + 0xb8,0x7b,0x4f, 0x88,0x64,0x44, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x4a,0x4b,0x49, 0xdc,0xde,0xdb, 0xe1,0xe4,0xe0, 0x79,0x7b,0x78, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0xa7,0x83,0x6d, + 0xac,0x86,0x6a, 0x76,0x4e,0x31, 0x84,0x54,0x33, 0x5c,0x38,0x22, + 0x57,0x38,0x20, 0x6c,0x46,0x29, 0x95,0x62,0x3b, 0xa3,0x6e,0x41, + 0xb3,0x76,0x4b, 0xb8,0x7b,0x4f, 0x9d,0x64,0x3f, 0x7e,0x4f,0x2f, + 0x63,0x3e,0x27, 0x95,0x62,0x3b, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x51,0x52,0x50, 0xdd,0xdf,0xdc, 0xe0,0xe2,0xdf, 0x82,0x83,0x81, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0xb6,0x80,0x58, + 0x98,0x74,0x59, 0x67,0x41,0x25, 0x4b,0x35,0x25, 0x81,0x52,0x31, + 0x76,0x4e,0x31, 0x7b,0x4d,0x2c, 0x7e,0x4f,0x2f, 0x84,0x54,0x33, + 0x8f,0x5d,0x37, 0x95,0x5d,0x38, 0x78,0x50,0x2d, 0x65,0x45,0x26, + 0x65,0x40,0x23, 0x7e,0x4f,0x2f, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x55,0x56,0x54, 0xee,0xdc,0xd1, 0xde,0xe0,0xdd, 0x8c,0x8d,0x8a, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0xb4,0x7f,0x5c, + 0x86,0x56,0x35, 0x8c,0x60,0x3d, 0x89,0x5f,0x41, 0x63,0x44,0x2b, + 0x57,0x38,0x20, 0x86,0x56,0x35, 0x88,0x57,0x31, 0x95,0x5d,0x38, + 0x97,0x64,0x3d, 0x63,0x3e,0x27, 0x50,0x33,0x20, 0x78,0x50,0x2d, + 0x78,0x50,0x2d, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x58,0x5a,0x58, 0xe0,0xe2,0xdf, 0xde,0xe0,0xdd, 0x8c,0x8d,0x8a, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x86,0x56,0x35, 0x63,0x3e,0x27, 0xa8,0x6d,0x42, 0x50,0x33,0x20, + 0x63,0x3e,0x27, 0x74,0x4b,0x29, 0x53,0x36,0x22, 0x78,0x50,0x2d, + 0x42,0x30,0x14, 0x4d,0x3e,0x15, 0x4d,0x3e,0x15, 0x7c,0x5b,0x29, + 0x8a,0x71,0x27, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x64,0x65,0x63, 0xe1,0xe4,0xe0, 0xe1,0xe4,0xe0, 0x91,0x93,0x90, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x6e,0x47,0x2b, 0x65,0x45,0x26, 0x5d,0x42,0x22, 0x65,0x45,0x26, + 0x78,0x50,0x2d, 0x5d,0x42,0x22, 0x5e,0x3f,0x27, 0x4d,0x3e,0x15, + 0x4d,0x3e,0x15, 0x67,0x58,0x21, 0x4f,0x44,0x19, 0x5f,0x51,0x19, + 0x8a,0x76,0x2a, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x68,0x69,0x67, 0xdf,0xe1,0xde, 0xe0,0xe2,0xdf, 0x9a,0x9b,0x98, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x8a,0x71,0x27, 0x53,0x46,0x15, + 0x53,0x46,0x15, 0x67,0x58,0x21, 0x58,0x4c,0x1b, 0x5b,0x4f,0x1d, + 0x5b,0x4f,0x1d, 0x67,0x58,0x21, 0x5b,0x4f,0x1d, 0x8a,0x71,0x27, + 0x8c,0x77,0x24, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x70,0x72,0x6f, 0xe1,0xe4,0xe0, 0xe1,0xe4,0xe0, 0x9a,0x9b,0x98, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0xac,0x93,0x39, 0x7e,0x66,0x23, + 0x69,0x5a,0x1b, 0x6b,0x5b,0x1d, 0x67,0x58,0x21, 0x53,0x46,0x15, + 0x4d,0x3e,0x15, 0x9f,0x88,0x35, 0xb7,0x9c,0x3b, 0xac,0x93,0x39, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x77,0x79,0x76, 0xdf,0xe1,0xde, 0xe0,0xe2,0xdf, 0xa3,0xa5,0xa1, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0xb1,0x97,0x36, 0x6f,0x5f,0x21, + 0x7e,0x66,0x23, 0x8c,0x77,0x24, 0x84,0x70,0x24, 0x78,0x67,0x22, + 0x8e,0x79,0x26, 0x8a,0x71,0x27, 0xb7,0x9c,0x3b, 0x9b,0x84,0x29, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x82,0x83,0x81, 0xe1,0xe4,0xe0, 0xe1,0xe4,0xe0, 0xa8,0xaa,0xa7, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0xac,0x93,0x39, 0x89,0x75,0x29, + 0x7e,0x66,0x23, 0x75,0x64,0x1f, 0x94,0x7e,0x2b, 0x7e,0x66,0x23, + 0x9f,0x88,0x35, 0xb6,0x9d,0x4a, 0xb6,0x9d,0x4a, 0xc4,0xa8,0x3f, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x82,0x83,0x81, 0xe0,0xe2,0xdf, 0xde,0xe0,0xdd, 0xab,0xad,0xaa, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x80,0x6d,0x28, + 0xac,0x93,0x39, 0x97,0x82,0x36, 0xac,0x94,0x41, 0xac,0x93,0x39, + 0x97,0x82,0x36, 0xa2,0x8a,0x30, 0xbd,0xa3,0x48, 0x8a,0x71,0x27, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x77,0x79,0x76, 0xe0,0xe2,0xdf, 0xd8,0xda,0xd6, 0xab,0xad,0xaa, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0xae,0x95,0x33, + 0x7e,0x66,0x23, 0x9f,0x88,0x35, 0x9f,0x88,0x35, 0x7e,0x66,0x23, + 0x8a,0x71,0x27, 0xaf,0x96,0x3c, 0xbd,0xa2,0x41, 0x8a,0x76,0x2a, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x68,0x69,0x67, + 0xc2,0xc4,0xc1, 0xe0,0xe2,0xdf, 0xdf,0xe1,0xde, 0xbe,0xc1,0xbd, + 0x5f,0x61,0x5e, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0xaf,0x96,0x3c, + 0x87,0x73,0x27, 0xb2,0x99,0x3f, 0x6f,0x5f,0x21, 0xa8,0x90,0x36, + 0x97,0x82,0x36, 0x9f,0x88,0x35, 0xb7,0x9c,0x3b, 0x8c,0x77,0x24, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0xa3,0xa5,0xa1, 0xeb,0xd8,0xcd, + 0xe0,0xe2,0xdf, 0xee,0xdc,0xd1, 0xdf,0xe1,0xde, 0xe1,0xe4,0xe0, + 0xda,0xdc,0xd9, 0x9a,0x9b,0x98, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0xb2,0x99,0x3f, + 0xaf,0x96,0x3c, 0x96,0x80,0x2d, 0xbd,0xa3,0x48, 0x97,0x82,0x36, + 0xb6,0x9d,0x4a, 0xb8,0xa0,0x4c, 0xc1,0xa7,0x4c, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x78,0x7a,0x77, 0xdf,0xe1,0xde, 0xe0,0xe2,0xdf, + 0xd2,0xd4,0xd1, 0x8c,0x8d,0x8a, 0x82,0x83,0x81, 0xc7,0xc9,0xc6, + 0xe1,0xe4,0xe0, 0xe1,0xe4,0xe0, 0x78,0x7a,0x77, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x96,0x80,0x2d, 0xb5,0x9c,0x49, 0xb2,0x99,0x3f, 0xb2,0x9a,0x47, + 0xb0,0x97,0x3d, 0xc1,0xa7,0x4c, 0x96,0x80,0x2d, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x78,0x7a,0x77, 0xd9,0xdb,0xd7, 0xda,0xdc,0xd9, + 0x68,0x69,0x67, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x64,0x65,0x63, + 0xdd,0xdf,0xdc, 0xd2,0xd4,0xd1, 0x78,0x7a,0x77, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x9c,0x85,0x2b, 0xaa,0x91,0x2f, 0xb1,0x97,0x36, 0xa2,0x8a,0x30, + 0x7e,0x66,0x23, 0xb1,0x97,0x36, 0xb4,0x99,0x30, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x79,0x7b,0x78, 0xc4,0xc6,0xc3, 0xd9,0xdb,0xd7, + 0x64,0x65,0x63, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x55,0x56,0x54, + 0xdf,0xe1,0xde, 0xbb,0xbd,0xba, 0x78,0x7a,0x77, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x9f,0x88,0x35, 0xb8,0x9e,0x44, 0x8a,0x71,0x27, 0xa6,0x8f,0x3c, + 0xbd,0xa3,0x48, 0x96,0x80,0x2d, 0x9f,0x88,0x35, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x82,0x83,0x81, 0xa8,0xaa,0xa7, 0xdf,0xe1,0xde, + 0x64,0x65,0x63, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x58,0x5a,0x58, + 0xee,0xdc,0xd1, 0xa0,0xa2,0x9f, 0x78,0x7a,0x77, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0xb0,0x97,0x3d, 0xb7,0x9c,0x3b, 0xac,0x94,0x41, 0xb2,0x99,0x3f, + 0xb6,0x9b,0x32, 0xb7,0x9c,0x3b, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x77,0x79,0x76, 0x77,0x79,0x76, 0xca,0xcc,0xc9, + 0x5b,0x5d,0x5a, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x51,0x52,0x50, + 0xcb,0xce,0xca, 0x68,0x69,0x67, 0x79,0x7b,0x78, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0xbd,0xa2,0x41, 0xa6,0x8f,0x3c, 0xb0,0x97,0x3d, 0xb2,0x9a,0x47, + 0xac,0x93,0x39, 0x9f,0x88,0x35, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x77,0x79,0x76, 0x78,0x7a,0x77, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x82,0x83,0x81, 0x79,0x7b,0x78, 0x00,0x00,0x00, 0x00,0x00,0x00, + +}; diff --git a/src/setup/sound.c b/src/setup/sound.c new file mode 100644 index 00000000..9e13edd9 --- /dev/null +++ b/src/setup/sound.c @@ -0,0 +1,261 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// Copyright(C) 2006 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +// 02111-1307, USA. +// + +// Sound control menu + +#include <stdlib.h> + +#include "SDL_mixer.h" + +#include "textscreen.h" +#include "m_config.h" + +#include "i_sound.h" +#include "mode.h" +#include "sound.h" + +typedef enum +{ + SFXMODE_DISABLED, + SFXMODE_DIGITAL, + SFXMODE_PCSPEAKER, + NUM_SFXMODES +} sfxmode_t; + +static char *sfxmode_strings[] = +{ + "Disabled", + "Digital", + "PC speaker" +}; + +typedef enum +{ + MUSICMODE_DISABLED, + MUSICMODE_OPL, + MUSICMODE_NATIVE, + MUSICMODE_CD, + NUM_MUSICMODES +} musicmode_t; + +static char *musicmode_strings[] = +{ + "Disabled", + "OPL (Adlib/SB)", + "Native MIDI", + "CD audio" +}; + +// Config file variables: + +int snd_sfxdevice = SNDDEVICE_SB; +int snd_musicdevice = SNDDEVICE_GENMIDI; +int snd_samplerate = 44100; +int opl_io_port = 0x388; + +static int numChannels = 8; +static int sfxVolume = 15; +static int musicVolume = 15; +static int use_libsamplerate = 0; + +// DOS specific variables: these are unused but should be maintained +// so that the config file can be shared between chocolate +// doom and doom.exe + +static int snd_sbport = 0; +static int snd_sbirq = 0; +static int snd_sbdma = 0; +static int snd_mport = 0; + +// GUI variables: + +static int snd_sfxmode; +static int snd_musicmode; + +static void UpdateSndDevices(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(data)) +{ + switch (snd_sfxmode) + { + case SFXMODE_DISABLED: + snd_sfxdevice = SNDDEVICE_NONE; + break; + case SFXMODE_PCSPEAKER: + snd_sfxdevice = SNDDEVICE_PCSPEAKER; + break; + case SFXMODE_DIGITAL: + snd_sfxdevice = SNDDEVICE_SB; + break; + } + + switch (snd_musicmode) + { + case MUSICMODE_DISABLED: + snd_musicdevice = SNDDEVICE_NONE; + break; + case MUSICMODE_NATIVE: + snd_musicdevice = SNDDEVICE_GENMIDI; + break; + case MUSICMODE_OPL: + snd_musicdevice = SNDDEVICE_SB; + break; + case MUSICMODE_CD: + break; + } +} + +void ConfigSound(void) +{ + txt_window_t *window; + txt_table_t *sfx_table; + txt_table_t *music_table; + txt_dropdown_list_t *sfx_mode_control; + txt_dropdown_list_t *music_mode_control; + int num_sfx_modes, num_music_modes; + + // Work out what sfx mode we are currently using: + + if (snd_sfxdevice == SNDDEVICE_PCSPEAKER) + { + snd_sfxmode = SFXMODE_PCSPEAKER; + } + else if (snd_sfxdevice >= SNDDEVICE_SB) + { + snd_sfxmode = SFXMODE_DIGITAL; + } + else + { + snd_sfxmode = SFXMODE_DISABLED; + } + + // Is music enabled? + + if (snd_musicdevice == SNDDEVICE_GENMIDI) + { + snd_musicmode = MUSICMODE_NATIVE; + } + else if (snd_musicmode == SNDDEVICE_CD) + { + snd_musicmode = MUSICMODE_CD; + } + else if (snd_musicdevice == SNDDEVICE_SB + || snd_musicdevice == SNDDEVICE_ADLIB + || snd_musicdevice == SNDDEVICE_AWE32) + { + snd_musicmode = MUSICMODE_OPL; + } + else + { + snd_musicmode = MUSICMODE_DISABLED; + } + + // Doom has PC speaker sound effects, but others do not: + + if (gamemission == doom) + { + num_sfx_modes = NUM_SFXMODES; + } + else + { + num_sfx_modes = NUM_SFXMODES - 1; + } + + // Hexen has CD audio; others do not. + + if (gamemission == hexen) + { + num_music_modes = NUM_MUSICMODES; + } + else + { + num_music_modes = NUM_MUSICMODES - 1; + } + + // Build the window + + window = TXT_NewWindow("Sound configuration"); + + TXT_AddWidgets(window, + TXT_NewSeparator("Sound effects"), + sfx_table = TXT_NewTable(2), + TXT_NewSeparator("Music"), + music_table = TXT_NewTable(2), + NULL); + + TXT_SetColumnWidths(sfx_table, 20, 14); + + TXT_AddWidgets(sfx_table, + TXT_NewLabel("Sound effects"), + sfx_mode_control = TXT_NewDropdownList(&snd_sfxmode, + sfxmode_strings, + num_sfx_modes), + TXT_NewLabel("Sound channels"), + TXT_NewSpinControl(&numChannels, 1, 8), + TXT_NewLabel("SFX volume"), + TXT_NewSpinControl(&sfxVolume, 0, 15), + NULL); + + TXT_SetColumnWidths(music_table, 20, 14); + + TXT_AddWidgets(music_table, + TXT_NewLabel("Music"), + music_mode_control = TXT_NewDropdownList(&snd_musicmode, + musicmode_strings, + num_music_modes), + TXT_NewLabel("Music volume"), + TXT_NewSpinControl(&musicVolume, 0, 15), + NULL); + + TXT_SignalConnect(sfx_mode_control, "changed", UpdateSndDevices, NULL); + TXT_SignalConnect(music_mode_control, "changed", UpdateSndDevices, NULL); +} + +void BindSoundVariables(void) +{ + M_BindVariable("snd_sfxdevice", &snd_sfxdevice); + M_BindVariable("snd_musicdevice", &snd_musicdevice); + M_BindVariable("snd_channels", &numChannels); + M_BindVariable("sfx_volume", &sfxVolume); + M_BindVariable("music_volume", &musicVolume); + M_BindVariable("snd_samplerate", &snd_samplerate); + M_BindVariable("use_libsamplerate", &use_libsamplerate); + + M_BindVariable("snd_sbport", &snd_sbport); + M_BindVariable("snd_sbirq", &snd_sbirq); + M_BindVariable("snd_sbdma", &snd_sbdma); + M_BindVariable("snd_mport", &snd_mport); + + // Before SDL_mixer version 1.2.11, MIDI music caused the game + // to crash when it looped. If this is an old SDL_mixer version, + // disable MIDI. + +#ifdef __MACOSX__ + { + const SDL_version *v = Mix_Linked_Version(); + + if (SDL_VERSIONNUM(v->major, v->minor, v->patch) + < SDL_VERSIONNUM(1, 2, 11)) + { + snd_musicdevice = SNDDEVICE_NONE; + } + } +#endif +} + diff --git a/src/setup/sound.h b/src/setup/sound.h new file mode 100644 index 00000000..0b183502 --- /dev/null +++ b/src/setup/sound.h @@ -0,0 +1,29 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// Copyright(C) 2006 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +// 02111-1307, USA. +// + +#ifndef SETUP_SOUND_H +#define SETUP_SOUND_H + +void ConfigSound(void); +void BindSoundVariables(void); + +#endif /* #ifndef SETUP_SOUND_H */ + diff --git a/src/setup/txt_joybinput.c b/src/setup/txt_joybinput.c new file mode 100644 index 00000000..9ad26a45 --- /dev/null +++ b/src/setup/txt_joybinput.c @@ -0,0 +1,230 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// Copyright(C) 2006 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +// 02111-1307, USA. +// + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "SDL_joystick.h" + +#include "doomkeys.h" +#include "joystick.h" + +#include "txt_joybinput.h" +#include "txt_gui.h" +#include "txt_io.h" +#include "txt_label.h" +#include "txt_sdl.h" +#include "txt_window.h" + +#define JOYSTICK_INPUT_WIDTH 10 + +// Called in response to SDL events when the prompt window is open: + +static int EventCallback(SDL_Event *event, TXT_UNCAST_ARG(joystick_input)) +{ + TXT_CAST_ARG(txt_joystick_input_t, joystick_input); + + // Got the joystick button press? + + if (event->type == SDL_JOYBUTTONDOWN) + { + *joystick_input->variable = event->jbutton.button; + + if (joystick_input->check_conflicts) + { + TXT_EmitSignal(joystick_input, "set"); + } + + TXT_CloseWindow(joystick_input->prompt_window); + return 1; + } + + return 0; +} + +// When the prompt window is closed, disable the event callback function; +// we are no longer interested in receiving notification of events. + +static void PromptWindowClosed(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(joystick)) +{ + TXT_CAST_ARG(SDL_Joystick, joystick); + + SDL_JoystickClose(joystick); + TXT_SDL_SetEventCallback(NULL, NULL); + SDL_JoystickEventState(SDL_DISABLE); + SDL_QuitSubSystem(SDL_INIT_JOYSTICK); +} + +static void OpenErrorWindow(void) +{ + txt_window_t *window; + + window = TXT_NewWindow(NULL); + + TXT_AddWidget(window, TXT_NewLabel("Please configure a joystick first!")); + + TXT_SetWindowAction(window, TXT_HORIZ_LEFT, NULL); + TXT_SetWindowAction(window, TXT_HORIZ_CENTER, + TXT_NewWindowEscapeAction(window)); + TXT_SetWindowAction(window, TXT_HORIZ_RIGHT, NULL); +} + +static void OpenPromptWindow(txt_joystick_input_t *joystick_input) +{ + txt_window_t *window; + txt_label_t *label; + SDL_Joystick *joystick; + + // Silently update when the shift button is held down. + + joystick_input->check_conflicts = !TXT_GetModifierState(TXT_MOD_SHIFT); + + if (SDL_Init(SDL_INIT_JOYSTICK) < 0) + { + return; + } + + // Check the current joystick is valid + + joystick = SDL_JoystickOpen(joystick_index); + + if (joystick == NULL) + { + OpenErrorWindow(); + return; + } + + // Open the prompt window + + window = TXT_NewWindow(NULL); + TXT_SetWindowAction(window, TXT_HORIZ_LEFT, NULL); + TXT_SetWindowAction(window, TXT_HORIZ_CENTER, + TXT_NewWindowAbortAction(window)); + TXT_SetWindowAction(window, TXT_HORIZ_RIGHT, NULL); + + label = TXT_NewLabel("Press the new joystick button..."); + + TXT_AddWidget(window, label); + TXT_SetWidgetAlign(label, TXT_HORIZ_CENTER); + TXT_SDL_SetEventCallback(EventCallback, joystick_input); + TXT_SignalConnect(window, "closed", PromptWindowClosed, joystick); + joystick_input->prompt_window = window; + + SDL_JoystickEventState(SDL_ENABLE); +} + +static void TXT_JoystickInputSizeCalc(TXT_UNCAST_ARG(joystick_input)) +{ + TXT_CAST_ARG(txt_joystick_input_t, joystick_input); + + // All joystickinputs are the same size. + + joystick_input->widget.w = JOYSTICK_INPUT_WIDTH; + joystick_input->widget.h = 1; +} + +static void GetJoystickButtonDescription(int button, char *buf) +{ + sprintf(buf, "BUTTON #%i", button + 1); +} + +static void TXT_JoystickInputDrawer(TXT_UNCAST_ARG(joystick_input), int selected) +{ + TXT_CAST_ARG(txt_joystick_input_t, joystick_input); + char buf[20]; + int i; + + if (*joystick_input->variable < 0) + { + strcpy(buf, "(none)"); + } + else + { + GetJoystickButtonDescription(*joystick_input->variable, buf); + } + + TXT_SetWidgetBG(joystick_input, selected); + TXT_FGColor(TXT_COLOR_BRIGHT_WHITE); + + TXT_DrawString(buf); + + for (i=strlen(buf); i<JOYSTICK_INPUT_WIDTH; ++i) + { + TXT_DrawString(" "); + } +} + +static void TXT_JoystickInputDestructor(TXT_UNCAST_ARG(joystick_input)) +{ +} + +static int TXT_JoystickInputKeyPress(TXT_UNCAST_ARG(joystick_input), int joystick) +{ + TXT_CAST_ARG(txt_joystick_input_t, joystick_input); + + if (joystick == KEY_ENTER) + { + // Open a window to prompt for the new joystick press + + OpenPromptWindow(joystick_input); + + return 1; + } + + return 0; +} + +static void TXT_JoystickInputMousePress(TXT_UNCAST_ARG(widget), int x, int y, int b) +{ + TXT_CAST_ARG(txt_joystick_input_t, widget); + + // Clicking is like pressing enter + + if (b == TXT_MOUSE_LEFT) + { + TXT_JoystickInputKeyPress(widget, KEY_ENTER); + } +} + +txt_widget_class_t txt_joystick_input_class = +{ + TXT_AlwaysSelectable, + TXT_JoystickInputSizeCalc, + TXT_JoystickInputDrawer, + TXT_JoystickInputKeyPress, + TXT_JoystickInputDestructor, + TXT_JoystickInputMousePress, + NULL, +}; + +txt_joystick_input_t *TXT_NewJoystickInput(int *variable) +{ + txt_joystick_input_t *joystick_input; + + joystick_input = malloc(sizeof(txt_joystick_input_t)); + + TXT_InitWidget(joystick_input, &txt_joystick_input_class); + joystick_input->variable = variable; + + return joystick_input; +} + diff --git a/src/setup/txt_joybinput.h b/src/setup/txt_joybinput.h new file mode 100644 index 00000000..69ec4a1f --- /dev/null +++ b/src/setup/txt_joybinput.h @@ -0,0 +1,47 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// Copyright(C) 2007 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +// 02111-1307, USA. +// + +#ifndef TXT_JOYB_INPUT_H +#define TXT_JOYB_INPUT_H + +typedef struct txt_joystick_input_s txt_joystick_input_t; + +#include "txt_widget.h" +#include "txt_window.h" + +// +// A joystick input is like an input box. When selected, a box pops up +// allowing a joystick button to be pressed to select it. +// + +struct txt_joystick_input_s +{ + txt_widget_t widget; + int *variable; + txt_window_t *prompt_window; + int check_conflicts; +}; + +txt_joystick_input_t *TXT_NewJoystickInput(int *variable); + +#endif /* #ifndef TXT_JOYB_INPUT_H */ + + diff --git a/src/setup/txt_keyinput.c b/src/setup/txt_keyinput.c new file mode 100644 index 00000000..6f1ee4dd --- /dev/null +++ b/src/setup/txt_keyinput.c @@ -0,0 +1,195 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// Copyright(C) 2006 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +// 02111-1307, USA. +// + +#include <stdlib.h> +#include <string.h> + +#include "doomkeys.h" + +#include "txt_keyinput.h" +#include "txt_gui.h" +#include "txt_io.h" +#include "txt_label.h" +#include "txt_window.h" + +#define KEY_INPUT_WIDTH 8 + +static int KeyPressCallback(txt_window_t *window, int key, + TXT_UNCAST_ARG(key_input)) +{ + TXT_CAST_ARG(txt_key_input_t, key_input); + + if (key != KEY_ESCAPE) + { + // Got the key press. Save to the variable and close the window. + + *key_input->variable = key; + + if (key_input->check_conflicts) + { + TXT_EmitSignal(key_input, "set"); + } + + TXT_CloseWindow(window); + + // Re-enable key mappings now that we have the key + + TXT_EnableKeyMapping(1); + + return 1; + } + else + { + return 0; + } +} + +static void ReleaseGrab(TXT_UNCAST_ARG(window), TXT_UNCAST_ARG(unused)) +{ + SDL_WM_GrabInput(SDL_GRAB_OFF); +} + +static void OpenPromptWindow(txt_key_input_t *key_input) +{ + txt_window_t *window; + txt_label_t *label; + + // Silently update when the shift button is held down. + + key_input->check_conflicts = !TXT_GetModifierState(TXT_MOD_SHIFT); + + window = TXT_NewWindow(NULL); + TXT_SetWindowAction(window, TXT_HORIZ_LEFT, NULL); + TXT_SetWindowAction(window, TXT_HORIZ_CENTER, + TXT_NewWindowAbortAction(window)); + TXT_SetWindowAction(window, TXT_HORIZ_RIGHT, NULL); + + label = TXT_NewLabel("Press the new key..."); + + TXT_AddWidget(window, label); + TXT_SetWidgetAlign(label, TXT_HORIZ_CENTER); + + TXT_SetKeyListener(window, KeyPressCallback, key_input); + + // Disable key mappings while we prompt for the key press + + TXT_EnableKeyMapping(0); + + // Grab input while reading the key. On Windows Mobile + // handheld devices, the hardware keypresses are only + // detected when input is grabbed. + + SDL_WM_GrabInput(SDL_GRAB_ON); + TXT_SignalConnect(window, "closed", ReleaseGrab, NULL); +} + +static void TXT_KeyInputSizeCalc(TXT_UNCAST_ARG(key_input)) +{ + TXT_CAST_ARG(txt_key_input_t, key_input); + + // All keyinputs are the same size. + + key_input->widget.w = KEY_INPUT_WIDTH; + key_input->widget.h = 1; +} + + +static void TXT_KeyInputDrawer(TXT_UNCAST_ARG(key_input), int selected) +{ + TXT_CAST_ARG(txt_key_input_t, key_input); + char buf[20]; + int i; + + if (*key_input->variable == 0) + { + strcpy(buf, "(none)"); + } + else + { + TXT_GetKeyDescription(*key_input->variable, buf); + } + + TXT_SetWidgetBG(key_input, selected); + TXT_FGColor(TXT_COLOR_BRIGHT_WHITE); + + TXT_DrawString(buf); + + for (i=strlen(buf); i<KEY_INPUT_WIDTH; ++i) + { + TXT_DrawString(" "); + } +} + +static void TXT_KeyInputDestructor(TXT_UNCAST_ARG(key_input)) +{ +} + +static int TXT_KeyInputKeyPress(TXT_UNCAST_ARG(key_input), int key) +{ + TXT_CAST_ARG(txt_key_input_t, key_input); + + if (key == KEY_ENTER) + { + // Open a window to prompt for the new key press + + OpenPromptWindow(key_input); + + return 1; + } + + return 0; +} + +static void TXT_KeyInputMousePress(TXT_UNCAST_ARG(widget), int x, int y, int b) +{ + TXT_CAST_ARG(txt_key_input_t, widget); + + // Clicking is like pressing enter + + if (b == TXT_MOUSE_LEFT) + { + TXT_KeyInputKeyPress(widget, KEY_ENTER); + } +} + +txt_widget_class_t txt_key_input_class = +{ + TXT_AlwaysSelectable, + TXT_KeyInputSizeCalc, + TXT_KeyInputDrawer, + TXT_KeyInputKeyPress, + TXT_KeyInputDestructor, + TXT_KeyInputMousePress, + NULL, +}; + +txt_key_input_t *TXT_NewKeyInput(int *variable) +{ + txt_key_input_t *key_input; + + key_input = malloc(sizeof(txt_key_input_t)); + + TXT_InitWidget(key_input, &txt_key_input_class); + key_input->variable = variable; + + return key_input; +} + diff --git a/src/setup/txt_keyinput.h b/src/setup/txt_keyinput.h new file mode 100644 index 00000000..5df0b2e3 --- /dev/null +++ b/src/setup/txt_keyinput.h @@ -0,0 +1,45 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// Copyright(C) 2006 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +// 02111-1307, USA. +// + +#ifndef TXT_KEY_INPUT_H +#define TXT_KEY_INPUT_H + +typedef struct txt_key_input_s txt_key_input_t; + +#include "txt_widget.h" + +// +// A key input is like an input box. When selected, a box pops up +// allowing a key to be selected. +// + +struct txt_key_input_s +{ + txt_widget_t widget; + int *variable; + int check_conflicts; +}; + +txt_key_input_t *TXT_NewKeyInput(int *variable); + +#endif /* #ifndef TXT_KEY_INPUT_H */ + + diff --git a/src/setup/txt_mouseinput.c b/src/setup/txt_mouseinput.c new file mode 100644 index 00000000..c3e17299 --- /dev/null +++ b/src/setup/txt_mouseinput.c @@ -0,0 +1,187 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// Copyright(C) 2006 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +// 02111-1307, USA. +// + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "doomkeys.h" + +#include "txt_mouseinput.h" +#include "txt_gui.h" +#include "txt_io.h" +#include "txt_label.h" +#include "txt_window.h" + +#define MOUSE_INPUT_WIDTH 8 + +static int MousePressCallback(txt_window_t *window, + int x, int y, int b, + TXT_UNCAST_ARG(mouse_input)) +{ + TXT_CAST_ARG(txt_mouse_input_t, mouse_input); + + // Got the mouse press. Save to the variable and close the window. + + *mouse_input->variable = b - TXT_MOUSE_BASE; + + if (mouse_input->check_conflicts) + { + TXT_EmitSignal(mouse_input, "set"); + } + + TXT_CloseWindow(window); + + return 1; +} + +static void OpenPromptWindow(txt_mouse_input_t *mouse_input) +{ + txt_window_t *window; + txt_label_t *label; + + // Silently update when the shift key is held down. + mouse_input->check_conflicts = !TXT_GetModifierState(TXT_MOD_SHIFT); + + window = TXT_NewWindow(NULL); + TXT_SetWindowAction(window, TXT_HORIZ_LEFT, NULL); + TXT_SetWindowAction(window, TXT_HORIZ_CENTER, + TXT_NewWindowAbortAction(window)); + TXT_SetWindowAction(window, TXT_HORIZ_RIGHT, NULL); + + label = TXT_NewLabel("Press the new mouse button..."); + + TXT_AddWidget(window, label); + TXT_SetWidgetAlign(label, TXT_HORIZ_CENTER); + + TXT_SetMouseListener(window, MousePressCallback, mouse_input); +} + +static void TXT_MouseInputSizeCalc(TXT_UNCAST_ARG(mouse_input)) +{ + TXT_CAST_ARG(txt_mouse_input_t, mouse_input); + + // All mouseinputs are the same size. + + mouse_input->widget.w = MOUSE_INPUT_WIDTH; + mouse_input->widget.h = 1; +} + +static void GetMouseButtonDescription(int button, char *buf) +{ + switch (button) + { + case 0: + strcpy(buf, "LEFT"); + break; + case 1: + strcpy(buf, "RIGHT"); + break; + case 2: + strcpy(buf, "MID"); + break; + default: + sprintf(buf, "BUTTON #%i", button + 1); + break; + } +} + +static void TXT_MouseInputDrawer(TXT_UNCAST_ARG(mouse_input), int selected) +{ + TXT_CAST_ARG(txt_mouse_input_t, mouse_input); + char buf[20]; + int i; + + if (*mouse_input->variable < 0) + { + strcpy(buf, "(none)"); + } + else + { + GetMouseButtonDescription(*mouse_input->variable, buf); + } + + TXT_SetWidgetBG(mouse_input, selected); + TXT_FGColor(TXT_COLOR_BRIGHT_WHITE); + + TXT_DrawString(buf); + + for (i=strlen(buf); i<MOUSE_INPUT_WIDTH; ++i) + { + TXT_DrawString(" "); + } +} + +static void TXT_MouseInputDestructor(TXT_UNCAST_ARG(mouse_input)) +{ +} + +static int TXT_MouseInputKeyPress(TXT_UNCAST_ARG(mouse_input), int mouse) +{ + TXT_CAST_ARG(txt_mouse_input_t, mouse_input); + + if (mouse == KEY_ENTER) + { + // Open a window to prompt for the new mouse press + + OpenPromptWindow(mouse_input); + + return 1; + } + + return 0; +} + +static void TXT_MouseInputMousePress(TXT_UNCAST_ARG(widget), int x, int y, int b) +{ + TXT_CAST_ARG(txt_mouse_input_t, widget); + + // Clicking is like pressing enter + + if (b == TXT_MOUSE_LEFT) + { + TXT_MouseInputKeyPress(widget, KEY_ENTER); + } +} + +txt_widget_class_t txt_mouse_input_class = +{ + TXT_AlwaysSelectable, + TXT_MouseInputSizeCalc, + TXT_MouseInputDrawer, + TXT_MouseInputKeyPress, + TXT_MouseInputDestructor, + TXT_MouseInputMousePress, + NULL, +}; + +txt_mouse_input_t *TXT_NewMouseInput(int *variable) +{ + txt_mouse_input_t *mouse_input; + + mouse_input = malloc(sizeof(txt_mouse_input_t)); + + TXT_InitWidget(mouse_input, &txt_mouse_input_class); + mouse_input->variable = variable; + + return mouse_input; +} + diff --git a/src/setup/txt_mouseinput.h b/src/setup/txt_mouseinput.h new file mode 100644 index 00000000..ef3ec2aa --- /dev/null +++ b/src/setup/txt_mouseinput.h @@ -0,0 +1,45 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// Copyright(C) 2006 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +// 02111-1307, USA. +// + +#ifndef TXT_MOUSE_INPUT_H +#define TXT_MOUSE_INPUT_H + +typedef struct txt_mouse_input_s txt_mouse_input_t; + +#include "txt_widget.h" + +// +// A mouse input is like an input box. When selected, a box pops up +// allowing a mouse to be selected. +// + +struct txt_mouse_input_s +{ + txt_widget_t widget; + int *variable; + int check_conflicts; +}; + +txt_mouse_input_t *TXT_NewMouseInput(int *variable); + +#endif /* #ifndef TXT_MOUSE_INPUT_H */ + + |