1 /* Emacs style mode select   -*- C++ -*-
2  *-----------------------------------------------------------------------------
3  *
4  *
5  *  PrBoom: a Doom port merged with LxDoom and LSDLDoom
6  *  based on BOOM, a modified and improved DOOM engine
7  *  Copyright (C) 1999 by
8  *  id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9  *  Copyright (C) 1999-2000 by
10  *  Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11  *  Copyright 2005, 2006 by
12  *  Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13  *
14  *  This program is free software; you can redistribute it and/or
15  *  modify it under the terms of the GNU General Public License
16  *  as published by the Free Software Foundation; either version 2
17  *  of the License, or (at your option) any later version.
18  *
19  *  This program is distributed in the hope that it will be useful,
20  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
21  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  *  GNU General Public License for more details.
23  *
24  *  You should have received a copy of the GNU General Public License
25  *  along with this program; if not, write to the Free Software
26  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27  *  02111-1307, USA.
28  *
29  * DESCRIPTION:
30  *  Main loop menu stuff.
31  *  Default Config File.
32  *  PCX Screenshots.
33  *
34  *-----------------------------------------------------------------------------*/
35 
36 #ifdef HAVE_CONFIG_H
37 #include "config.h"
38 #endif
39 
40 #include <stdio.h>
41 #include <errno.h>
42 #ifdef HAVE_UNISTD_H
43 #include <unistd.h>
44 #endif
45 #ifdef _MSC_VER
46 #include <io.h>
47 #endif
48 #include <fcntl.h>
49 #include <sys/stat.h>
50 
51 #include "doomstat.h"
52 #include "m_argv.h"
53 #include "g_game.h"
54 #include "m_menu.h"
55 #include "am_map.h"
56 #include "w_wad.h"
57 #include "i_system.h"
58 #include "i_sound.h"
59 #include "i_video.h"
60 #include "v_video.h"
61 #include "hu_stuff.h"
62 #include "st_stuff.h"
63 #include "dstrings.h"
64 #include "m_misc.h"
65 #include "s_sound.h"
66 #include "sounds.h"
67 #include "i_joy.h"
68 #include "lprintf.h"
69 #include "d_main.h"
70 #include "r_draw.h"
71 #include "r_demo.h"
72 #include "r_fps.h"
73 
74 /* cph - disk icon not implemented */
I_BeginRead(void)75 static inline void I_BeginRead(void) {}
I_EndRead(void)76 static inline void I_EndRead(void) {}
77 
78 /*
79  * M_WriteFile
80  *
81  * killough 9/98: rewritten to use stdio and to flash disk icon
82  */
83 
M_WriteFile(char const * name,void * source,int length)84 boolean M_WriteFile(char const *name, void *source, int length)
85 {
86   FILE *fp;
87 
88   errno = 0;
89 
90   if (!(fp = fopen(name, "wb")))       // Try opening file
91     return 0;                          // Could not open file for writing
92 
93   I_BeginRead();                       // Disk icon on
94   length = fwrite(source, 1, length, fp) == (size_t)length;   // Write data
95   fclose(fp);
96   I_EndRead();                         // Disk icon off
97 
98   if (!length)                         // Remove partially written file
99     remove(name);
100 
101   return length;
102 }
103 
104 /*
105  * M_ReadFile
106  *
107  * killough 9/98: rewritten to use stdio and to flash disk icon
108  */
109 
M_ReadFile(char const * name,byte ** buffer)110 int M_ReadFile(char const *name, byte **buffer)
111 {
112   FILE *fp;
113 
114   if ((fp = fopen(name, "rb")))
115     {
116       size_t length;
117 
118       I_BeginRead();
119       fseek(fp, 0, SEEK_END);
120       length = ftell(fp);
121       fseek(fp, 0, SEEK_SET);
122       *buffer = Z_Malloc(length, PU_STATIC, 0);
123       if (fread(*buffer, 1, length, fp) == length)
124         {
125           fclose(fp);
126           I_EndRead();
127           return length;
128         }
129       fclose(fp);
130     }
131 
132   /* cph 2002/08/10 - this used to return 0 on error, but that's ambiguous,
133    * because we could have a legit 0-length file. So make it -1. */
134   return -1;
135 }
136 
137 //
138 // DEFAULTS
139 //
140 
141 int usemouse;
142 boolean    precache = true; /* if true, load all graphics at start */
143 
144 extern int mousebfire;
145 extern int mousebstrafe;
146 extern int mousebforward;
147 
148 extern int viewwidth;
149 extern int viewheight;
150 #ifdef GL_DOOM
151 extern int gl_nearclip;
152 extern int gl_colorbuffer_bits;
153 extern int gl_depthbuffer_bits;
154 extern char *gl_tex_filter_string;
155 extern char *gl_tex_format_string;
156 extern int gl_drawskys;
157 extern int gl_sortsprites;
158 extern int gl_use_paletted_texture;
159 extern int gl_use_shared_texture_palette;
160 extern int gl_sprite_offset;
161 #endif
162 
163 extern int realtic_clock_rate;         // killough 4/13/98: adjustable timer
164 extern int tran_filter_pct;            // killough 2/21/98
165 
166 extern int screenblocks;
167 extern int showMessages;
168 
169 #ifndef DJGPP
170 int         mus_pause_opt; // 0 = kill music, 1 = pause, 2 = continue
171 #endif
172 
173 extern const char* chat_macros[];
174 
175 extern int endoom_mode;
176 
177 extern const char* S_music_files[]; // cournia
178 
179 /* cph - Some MBF stuff parked here for now
180  * killough 10/98
181  */
182 int map_point_coordinates;
183 
184 default_t defaults[] =
185 {
186   {"Misc settings",{NULL},{0},UL,UL,def_none,ss_none},
187   {"default_compatibility_level",{(int*)&default_compatibility_level},
188    {-1},-1,MAX_COMPATIBILITY_LEVEL-1,
189    def_int,ss_none}, // compatibility level" - CPhipps
190   {"realtic_clock_rate",{&realtic_clock_rate},{100},0,UL,
191    def_int,ss_none}, // percentage of normal speed (35 fps) realtic clock runs at
192   {"max_player_corpse", {&bodyquesize}, {32},-1,UL,   // killough 2/8/98
193    def_int,ss_none}, // number of dead bodies in view supported (-1 = no limit)
194   {"flashing_hom",{&flashing_hom},{0},0,1,
195    def_bool,ss_none}, // killough 10/98 - enable flashing HOM indicator
196   {"demo_insurance",{&default_demo_insurance},{2},0,2,  // killough 3/31/98
197    def_int,ss_none}, // 1=take special steps ensuring demo sync, 2=only during recordings
198   {"endoom_mode", {&endoom_mode},{5},0,7, // CPhipps - endoom flags
199    def_hex, ss_none}, // 0, +1 for colours, +2 for non-ascii chars, +4 for skip-last-line
200   {"level_precache",{(int*)&precache},{0},0,1,
201    def_bool,ss_none}, // precache level data?
202   {"demo_smoothturns", {&demo_smoothturns},  {0},0,1,
203    def_bool,ss_stat},
204   {"demo_smoothturnsfactor", {&demo_smoothturnsfactor},  {6},1,SMOOTH_PLAYING_MAXFACTOR,
205    def_int,ss_stat},
206 
207   {"Files",{NULL},{0},UL,UL,def_none,ss_none},
208   /* cph - MBF-like wad/deh/bex autoload code */
209   {"wadfile_1",{NULL,&wad_files[0]},{0,""},UL,UL,def_str,ss_none},
210   {"wadfile_2",{NULL,&wad_files[1]},{0,""},UL,UL,def_str,ss_none},
211   {"dehfile_1",{NULL,&deh_files[0]},{0,""},UL,UL,def_str,ss_none},
212   {"dehfile_2",{NULL,&deh_files[1]},{0,""},UL,UL,def_str,ss_none},
213 
214   {"Game settings",{NULL},{0},UL,UL,def_none,ss_none},
215   {"default_skill",{&defaultskill},{3},1,5, // jff 3/24/98 allow default skill setting
216    def_int,ss_none}, // selects default skill 1=TYTD 2=NTR 3=HMP 4=UV 5=NM
217   {"weapon_recoil",{&default_weapon_recoil},{0},0,1,
218    def_bool,ss_weap, &weapon_recoil},
219   /* killough 10/98 - toggle between SG/SSG and Fist/Chainsaw */
220   {"doom_weapon_toggles",{&doom_weapon_toggles}, {1}, 0, 1,
221    def_bool, ss_weap },
222   {"player_bobbing",{&default_player_bobbing},{1},0,1,         // phares 2/25/98
223    def_bool,ss_weap, &player_bobbing},
224   {"monsters_remember",{&default_monsters_remember},{1},0,1,   // killough 3/1/98
225    def_bool,ss_enem, &monsters_remember},
226    /* MBF AI enhancement options */
227   {"monster_infighting",{&default_monster_infighting}, {1}, 0, 1,
228    def_bool, ss_enem, &monster_infighting},
229   {"monster_backing",{&default_monster_backing}, {0}, 0, 1,
230    def_bool, ss_enem, &monster_backing},
231   {"monster_avoid_hazards",{&default_monster_avoid_hazards}, {1}, 0, 1,
232    def_bool, ss_enem, &monster_avoid_hazards},
233   {"monkeys",{&default_monkeys}, {0}, 0, 1,
234    def_bool, ss_enem, &monkeys},
235   {"monster_friction",{&default_monster_friction}, {1}, 0, 1,
236    def_bool, ss_enem, &monster_friction},
237   {"help_friends",{&default_help_friends}, {1}, 0, 1,
238    def_bool, ss_enem, &help_friends},
239   {"allow_pushers",{&default_allow_pushers},{1},0,1,
240    def_bool,ss_weap, &allow_pushers},
241   {"variable_friction",{&default_variable_friction},{1},0,1,
242    def_bool,ss_weap, &variable_friction},
243 #ifdef DOGS
244   {"player_helpers",{&default_dogs}, {0}, 0, 3,
245    def_bool, ss_enem },
246   {"friend_distance",{&default_distfriend}, {128}, 0, 999,
247    def_int, ss_enem, &distfriend},
248   {"dog_jumping",{&default_dog_jumping}, {1}, 0, 1,
249    def_bool, ss_enem, &dog_jumping},
250 #endif
251    /* End of MBF AI extras */
252 
253   {"sts_always_red",{&sts_always_red},{1},0,1, // no color changes on status bar
254    def_bool,ss_stat},
255   {"sts_pct_always_gray",{&sts_pct_always_gray},{0},0,1, // 2/23/98 chg default
256    def_bool,ss_stat}, // makes percent signs on status bar always gray
257   {"sts_traditional_keys",{&sts_traditional_keys},{0},0,1,  // killough 2/28/98
258    def_bool,ss_stat}, // disables doubled card and skull key display on status bar
259   {"show_messages",{&showMessages},{1},0,1,
260    def_bool,ss_none}, // enables message display
261   {"autorun",{&autorun},{0},0,1,  // killough 3/6/98: preserve autorun across games
262    def_bool,ss_none},
263 
264   {"Compatibility settings",{NULL},{0},UL,UL,def_none,ss_none},
265   {"comp_zombie",{&default_comp[comp_zombie]},{0},0,1,def_bool,ss_comp,&comp[comp_zombie]},
266   {"comp_infcheat",{&default_comp[comp_infcheat]},{0},0,1,def_bool,ss_comp,&comp[comp_infcheat]},
267   {"comp_stairs",{&default_comp[comp_stairs]},{0},0,1,def_bool,ss_comp,&comp[comp_stairs]},
268   {"comp_telefrag",{&default_comp[comp_telefrag]},{0},0,1,def_bool,ss_comp,&comp[comp_telefrag]},
269   {"comp_dropoff",{&default_comp[comp_dropoff]},{0},0,1,def_bool,ss_comp,&comp[comp_dropoff]},
270   {"comp_falloff",{&default_comp[comp_falloff]},{0},0,1,def_bool,ss_comp,&comp[comp_falloff]},
271   {"comp_staylift",{&default_comp[comp_staylift]},{0},0,1,def_bool,ss_comp,&comp[comp_staylift]},
272   {"comp_doorstuck",{&default_comp[comp_doorstuck]},{0},0,1,def_bool,ss_comp,&comp[comp_doorstuck]},
273   {"comp_pursuit",{&default_comp[comp_pursuit]},{0},0,1,def_bool,ss_comp,&comp[comp_pursuit]},
274   {"comp_vile",{&default_comp[comp_vile]},{0},0,1,def_bool,ss_comp,&comp[comp_vile]},
275   {"comp_pain",{&default_comp[comp_pain]},{0},0,1,def_bool,ss_comp,&comp[comp_pain]},
276   {"comp_skull",{&default_comp[comp_skull]},{0},0,1,def_bool,ss_comp,&comp[comp_skull]},
277   {"comp_blazing",{&default_comp[comp_blazing]},{0},0,1,def_bool,ss_comp,&comp[comp_blazing]},
278   {"comp_doorlight",{&default_comp[comp_doorlight]},{0},0,1,def_bool,ss_comp,&comp[comp_doorlight]},
279   {"comp_god",{&default_comp[comp_god]},{0},0,1,def_bool,ss_comp,&comp[comp_god]},
280   {"comp_skymap",{&default_comp[comp_skymap]},{0},0,1,def_bool,ss_comp,&comp[comp_skymap]},
281   {"comp_floors",{&default_comp[comp_floors]},{0},0,1,def_bool,ss_comp,&comp[comp_floors]},
282   {"comp_model",{&default_comp[comp_model]},{0},0,1,def_bool,ss_comp,&comp[comp_model]},
283   {"comp_zerotags",{&default_comp[comp_zerotags]},{0},0,1,def_bool,ss_comp,&comp[comp_zerotags]},
284   {"comp_moveblock",{&default_comp[comp_moveblock]},{0},0,1,def_bool,ss_comp,&comp[comp_moveblock]},
285   {"comp_sound",{&default_comp[comp_sound]},{0},0,1,def_bool,ss_comp,&comp[comp_sound]},
286   {"comp_666",{&default_comp[comp_666]},{0},0,1,def_bool,ss_comp,&comp[comp_666]},
287   {"comp_soul",{&default_comp[comp_soul]},{0},0,1,def_bool,ss_comp,&comp[comp_soul]},
288   {"comp_maskedanim",{&default_comp[comp_maskedanim]},{0},0,1,def_bool,ss_comp,&comp[comp_maskedanim]},
289 
290   {"Sound settings",{NULL},{0},UL,UL,def_none,ss_none},
291   {"sound_card",{&snd_card},{-1},-1,7,       // jff 1/18/98 allow Allegro drivers
292    def_int,ss_none}, // select sounds driver (DOS), -1 is autodetect, 0 is none; in Linux, non-zero enables sound
293   {"music_card",{&mus_card},{-1},-1,9,       //  to be set,  -1 = autodetect
294    def_int,ss_none}, // select music driver (DOS), -1 is autodetect, 0 is none"; in Linux, non-zero enables music
295   {"pitched_sounds",{&pitched_sounds},{0},0,1, // killough 2/21/98
296    def_bool,ss_none}, // enables variable pitch in sound effects (from id's original code)
297   {"samplerate",{&snd_samplerate},{22050},11025,48000, def_int,ss_none},
298   {"sfx_volume",{&snd_SfxVolume},{8},0,15, def_int,ss_none},
299   {"music_volume",{&snd_MusicVolume},{8},0,15, def_int,ss_none},
300   {"mus_pause_opt",{&mus_pause_opt},{2},0,2, // CPhipps - music pausing
301    def_int, ss_none}, // 0 = kill music when paused, 1 = pause music, 2 = let music continue
302   {"snd_channels",{&default_numChannels},{8},1,32,
303    def_int,ss_none}, // number of audio events simultaneously // killough
304 
305   {"Video settings",{NULL},{0},UL,UL,def_none,ss_none},
306 #ifdef GL_DOOM
307   #ifdef _MSC_VER
308     {"videomode",{NULL, &default_videomode},{0,"gl"},UL,UL,def_str,ss_none},
309   #else
310     {"videomode",{NULL, &default_videomode},{0,"8"},UL,UL,def_str,ss_none},
311   #endif
312 #else
313   {"videomode",{NULL, &default_videomode},{0,"8"},UL,UL,def_str,ss_none},
314 #endif
315   /* 640x480 default resolution */
316   {"screen_width",{&desired_screenwidth},{640}, 320, MAX_SCREENWIDTH,
317    def_int,ss_none},
318   {"screen_height",{&desired_screenheight},{480},200,MAX_SCREENHEIGHT,
319    def_int,ss_none},
320   {"use_fullscreen",{&use_fullscreen},{1},0,1, /* proff 21/05/2000 */
321    def_bool,ss_none},
322 #ifndef DISABLE_DOUBLEBUFFER
323   {"use_doublebuffer",{&use_doublebuffer},{1},0,1,             // proff 2001-7-4
324    def_bool,ss_none}, // enable doublebuffer to avoid display tearing (fullscreen)
325 #endif
326   {"translucency",{&default_translucency},{1},0,1,   // phares
327    def_bool,ss_none}, // enables translucency
328   {"tran_filter_pct",{&tran_filter_pct},{66},0,100,         // killough 2/21/98
329    def_int,ss_none}, // set percentage of foreground/background translucency mix
330   {"screenblocks",{&screenblocks},{10},3,11,  // killough 2/21/98: default to 10
331    def_int,ss_none},
332   {"usegamma",{&usegamma},{3},0,4, //jff 3/6/98 fix erroneous upper limit in range
333    def_int,ss_none}, // gamma correction level // killough 1/18/98
334   {"uncapped_framerate", {&movement_smooth},  {0},0,1,
335    def_bool,ss_stat},
336   {"filter_wall",{(int*)&drawvars.filterwall},{RDRAW_FILTER_POINT},
337    RDRAW_FILTER_POINT, RDRAW_FILTER_ROUNDED, def_int,ss_none},
338   {"filter_floor",{(int*)&drawvars.filterfloor},{RDRAW_FILTER_POINT},
339    RDRAW_FILTER_POINT, RDRAW_FILTER_ROUNDED, def_int,ss_none},
340   {"filter_sprite",{(int*)&drawvars.filtersprite},{RDRAW_FILTER_POINT},
341    RDRAW_FILTER_POINT, RDRAW_FILTER_ROUNDED, def_int,ss_none},
342   {"filter_z",{(int*)&drawvars.filterz},{RDRAW_FILTER_POINT},
343    RDRAW_FILTER_POINT, RDRAW_FILTER_LINEAR, def_int,ss_none},
344   {"filter_patch",{(int*)&drawvars.filterpatch},{RDRAW_FILTER_POINT},
345    RDRAW_FILTER_POINT, RDRAW_FILTER_ROUNDED, def_int,ss_none},
346   {"filter_threshold",{(int*)&drawvars.mag_threshold},{49152},
347    0, UL, def_int,ss_none},
348   {"sprite_edges",{(int*)&drawvars.sprite_edges},{RDRAW_MASKEDCOLUMNEDGE_SQUARE},
349    RDRAW_MASKEDCOLUMNEDGE_SQUARE, RDRAW_MASKEDCOLUMNEDGE_SLOPED, def_int,ss_none},
350   {"patch_edges",{(int*)&drawvars.patch_edges},{RDRAW_MASKEDCOLUMNEDGE_SQUARE},
351    RDRAW_MASKEDCOLUMNEDGE_SQUARE, RDRAW_MASKEDCOLUMNEDGE_SLOPED, def_int,ss_none},
352 
353 #ifdef GL_DOOM
354   {"OpenGL settings",{NULL},{0},UL,UL,def_none,ss_none},
355   {"gl_nearclip",{&gl_nearclip},{5},0,UL,
356    def_int,ss_none}, /* near clipping plane pos */
357   {"gl_colorbuffer_bits",{&gl_colorbuffer_bits},{16},16,32,
358    def_int,ss_none},
359   {"gl_depthbuffer_bits",{&gl_depthbuffer_bits},{16},16,32,
360    def_int,ss_none},
361   {"gl_tex_filter_string", {NULL,&gl_tex_filter_string}, {0,"GL_LINEAR"},UL,UL,
362    def_str,ss_none},
363   {"gl_tex_format_string", {NULL,&gl_tex_format_string}, {0,"GL_RGB5_A1"},UL,UL,
364    def_str,ss_none},
365   {"gl_drawskys",{&gl_drawskys},{1},0,1,
366    def_bool,ss_none},
367   {"gl_sortsprites",{&gl_sortsprites},{1},0,1,
368    def_bool,ss_none},
369   {"gl_use_paletted_texture",{&gl_use_paletted_texture},{0},0,1,
370    def_bool,ss_none},
371   {"gl_use_shared_texture_palette",{&gl_use_shared_texture_palette},{0},0,1,
372    def_bool,ss_none},
373 #ifdef GL_DOOM
374   {"gl_sprite_offset",{&gl_sprite_offset},{0}, 0, 5,
375    def_int,ss_none}, // amount to bring items out of floor (GL) Mead 8/13/03
376 #endif
377 #endif
378 
379   {"Mouse settings",{NULL},{0},UL,UL,def_none,ss_none},
380   {"use_mouse",{&usemouse},{1},0,1,
381    def_bool,ss_none}, // enables use of mouse with DOOM
382   //jff 4/3/98 allow unlimited sensitivity
383   {"mouse_sensitivity_horiz",{&mouseSensitivity_horiz},{10},0,UL,
384    def_int,ss_none}, /* adjust horizontal (x) mouse sensitivity killough/mead */
385   //jff 4/3/98 allow unlimited sensitivity
386   {"mouse_sensitivity_vert",{&mouseSensitivity_vert},{10},0,UL,
387    def_int,ss_none}, /* adjust vertical (y) mouse sensitivity killough/mead */
388   //jff 3/8/98 allow -1 in mouse bindings to disable mouse function
389   {"mouseb_fire",{&mousebfire},{0},-1,MAX_MOUSEB,
390    def_int,ss_keys}, // mouse button number to use for fire
391   {"mouseb_strafe",{&mousebstrafe},{1},-1,MAX_MOUSEB,
392    def_int,ss_keys}, // mouse button number to use for strafing
393   {"mouseb_forward",{&mousebforward},{2},-1,MAX_MOUSEB,
394    def_int,ss_keys}, // mouse button number to use for forward motion
395   //jff 3/8/98 end of lower range change for -1 allowed in mouse binding
396 
397 // For key bindings, the values stored in the key_* variables       // phares
398 // are the internal Doom Codes. The values stored in the default.cfg
399 // file are the keyboard codes.
400 // CPhipps - now they're the doom codes, so default.cfg can be portable
401 
402   {"Key bindings",{NULL},{0},UL,UL,def_none,ss_none},
403   {"key_right",       {&key_right},          {KEYD_RIGHTARROW},
404    0,MAX_KEY,def_key,ss_keys}, // key to turn right
405   {"key_left",        {&key_left},           {KEYD_LEFTARROW} ,
406    0,MAX_KEY,def_key,ss_keys}, // key to turn left
407   {"key_up",          {&key_up},             {KEYD_UPARROW}   ,
408    0,MAX_KEY,def_key,ss_keys}, // key to move forward
409   {"key_down",        {&key_down},           {KEYD_DOWNARROW},
410    0,MAX_KEY,def_key,ss_keys}, // key to move backward
411   {"key_menu_right",  {&key_menu_right},     {KEYD_RIGHTARROW},// phares 3/7/98
412    0,MAX_KEY,def_key,ss_keys}, // key to move right in a menu  //     |
413   {"key_menu_left",   {&key_menu_left},      {KEYD_LEFTARROW} ,//     V
414    0,MAX_KEY,def_key,ss_keys}, // key to move left in a menu
415   {"key_menu_up",     {&key_menu_up},        {KEYD_UPARROW}   ,
416    0,MAX_KEY,def_key,ss_keys}, // key to move up in a menu
417   {"key_menu_down",   {&key_menu_down},      {KEYD_DOWNARROW} ,
418    0,MAX_KEY,def_key,ss_keys}, // key to move down in a menu
419   {"key_menu_backspace",{&key_menu_backspace},{KEYD_BACKSPACE} ,
420    0,MAX_KEY,def_key,ss_keys}, // delete key in a menu
421   {"key_menu_escape", {&key_menu_escape},    {KEYD_ESCAPE}    ,
422    0,MAX_KEY,def_key,ss_keys}, // key to leave a menu      ,   // phares 3/7/98
423   {"key_menu_enter",  {&key_menu_enter},     {KEYD_ENTER}     ,
424    0,MAX_KEY,def_key,ss_keys}, // key to select from menu
425   {"key_strafeleft",  {&key_strafeleft},     {','}           ,
426    0,MAX_KEY,def_key,ss_keys}, // key to strafe left
427   {"key_straferight", {&key_straferight},    {'.'}           ,
428    0,MAX_KEY,def_key,ss_keys}, // key to strafe right
429 
430   {"key_fire",        {&key_fire},           {KEYD_RCTRL}     ,
431    0,MAX_KEY,def_key,ss_keys}, // duh
432   {"key_use",         {&key_use},            {' '}           ,
433    0,MAX_KEY,def_key,ss_keys}, // key to open a door, use a switch
434   {"key_strafe",      {&key_strafe},         {KEYD_RALT}      ,
435    0,MAX_KEY,def_key,ss_keys}, // key to use with arrows to strafe
436   {"key_speed",       {&key_speed},          {KEYD_RSHIFT}    ,
437    0,MAX_KEY,def_key,ss_keys}, // key to run
438 
439   {"key_savegame",    {&key_savegame},       {KEYD_F2}        ,
440    0,MAX_KEY,def_key,ss_keys}, // key to save current game
441   {"key_loadgame",    {&key_loadgame},       {KEYD_F3}        ,
442    0,MAX_KEY,def_key,ss_keys}, // key to restore from saved games
443   {"key_soundvolume", {&key_soundvolume},    {KEYD_F4}        ,
444    0,MAX_KEY,def_key,ss_keys}, // key to bring up sound controls
445   {"key_hud",         {&key_hud},            {KEYD_F5}        ,
446    0,MAX_KEY,def_key,ss_keys}, // key to adjust HUD
447   {"key_quicksave",   {&key_quicksave},      {KEYD_F6}        ,
448    0,MAX_KEY,def_key,ss_keys}, // key to to quicksave
449   {"key_endgame",     {&key_endgame},        {KEYD_F7}        ,
450    0,MAX_KEY,def_key,ss_keys}, // key to end the game
451   {"key_messages",    {&key_messages},       {KEYD_F8}        ,
452    0,MAX_KEY,def_key,ss_keys}, // key to toggle message enable
453   {"key_quickload",   {&key_quickload},      {KEYD_F9}        ,
454    0,MAX_KEY,def_key,ss_keys}, // key to load from quicksave
455   {"key_quit",        {&key_quit},           {KEYD_F10}       ,
456    0,MAX_KEY,def_key,ss_keys}, // key to quit game
457   {"key_gamma",       {&key_gamma},          {KEYD_F11}       ,
458    0,MAX_KEY,def_key,ss_keys}, // key to adjust gamma correction
459   {"key_spy",         {&key_spy},            {KEYD_F12}       ,
460    0,MAX_KEY,def_key,ss_keys}, // key to view from another coop player's view
461   {"key_pause",       {&key_pause},          {KEYD_PAUSE}     ,
462    0,MAX_KEY,def_key,ss_keys}, // key to pause the game
463   {"key_autorun",     {&key_autorun},        {KEYD_CAPSLOCK}  ,
464    0,MAX_KEY,def_key,ss_keys}, // key to toggle always run mode
465   {"key_chat",        {&key_chat},           {'t'}            ,
466    0,MAX_KEY,def_key,ss_keys}, // key to enter a chat message
467   {"key_backspace",   {&key_backspace},      {KEYD_BACKSPACE} ,
468    0,MAX_KEY,def_key,ss_keys}, // backspace key
469   {"key_enter",       {&key_enter},          {KEYD_ENTER}     ,
470    0,MAX_KEY,def_key,ss_keys}, // key to select from menu or see last message
471   {"key_map",         {&key_map},            {KEYD_TAB}       ,
472    0,MAX_KEY,def_key,ss_keys}, // key to toggle automap display
473   {"key_map_right",   {&key_map_right},      {KEYD_RIGHTARROW},// phares 3/7/98
474    0,MAX_KEY,def_key,ss_keys}, // key to shift automap right   //     |
475   {"key_map_left",    {&key_map_left},       {KEYD_LEFTARROW} ,//     V
476    0,MAX_KEY,def_key,ss_keys}, // key to shift automap left
477   {"key_map_up",      {&key_map_up},         {KEYD_UPARROW}   ,
478    0,MAX_KEY,def_key,ss_keys}, // key to shift automap up
479   {"key_map_down",    {&key_map_down},       {KEYD_DOWNARROW} ,
480    0,MAX_KEY,def_key,ss_keys}, // key to shift automap down
481   {"key_map_zoomin",  {&key_map_zoomin},      {'='}           ,
482    0,MAX_KEY,def_key,ss_keys}, // key to enlarge automap
483   {"key_map_zoomout", {&key_map_zoomout},     {'-'}           ,
484    0,MAX_KEY,def_key,ss_keys}, // key to reduce automap
485   {"key_map_gobig",   {&key_map_gobig},       {'0'}           ,
486    0,MAX_KEY,def_key,ss_keys},  // key to get max zoom for automap
487   {"key_map_follow",  {&key_map_follow},      {'f'}           ,
488    0,MAX_KEY,def_key,ss_keys}, // key to toggle follow mode
489   {"key_map_mark",    {&key_map_mark},        {'m'}           ,
490    0,MAX_KEY,def_key,ss_keys}, // key to drop a marker on automap
491   {"key_map_clear",   {&key_map_clear},       {'c'}           ,
492    0,MAX_KEY,def_key,ss_keys}, // key to clear all markers on automap
493   {"key_map_grid",    {&key_map_grid},        {'g'}           ,
494    0,MAX_KEY,def_key,ss_keys}, // key to toggle grid display over automap
495   {"key_map_rotate",  {&key_map_rotate},      {'r'}           ,
496    0,MAX_KEY,def_key,ss_keys}, // key to toggle rotating the automap to match the player's orientation
497   {"key_map_overlay", {&key_map_overlay},     {'o'}           ,
498    0,MAX_KEY,def_key,ss_keys}, // key to toggle overlaying the automap on the rendered display
499   {"key_reverse",     {&key_reverse},         {'/'}           ,
500    0,MAX_KEY,def_key,ss_keys}, // key to spin 180 instantly
501   {"key_zoomin",      {&key_zoomin},          {'='}           ,
502    0,MAX_KEY,def_key,ss_keys}, // key to enlarge display
503   {"key_zoomout",     {&key_zoomout},         {'-'}           ,
504    0,MAX_KEY,def_key,ss_keys}, // key to reduce display
505   {"key_chatplayer1", {&destination_keys[0]}, {'g'}            ,
506    0,MAX_KEY,def_key,ss_keys}, // key to chat with player 1
507   // killough 11/98: fix 'i'/'b' reversal
508   {"key_chatplayer2", {&destination_keys[1]}, {'i'}            ,
509    0,MAX_KEY,def_key,ss_keys}, // key to chat with player 2
510   {"key_chatplayer3", {&destination_keys[2]}, {'b'}            ,
511    0,MAX_KEY,def_key,ss_keys}, // key to chat with player 3
512   {"key_chatplayer4", {&destination_keys[3]}, {'r'}            ,
513    0,MAX_KEY,def_key,ss_keys}, // key to chat with player 4
514   {"key_weapontoggle",{&key_weapontoggle},    {'0'}            ,
515    0,MAX_KEY,def_key,ss_keys}, // key to toggle between two most preferred weapons with ammo
516   {"key_weapon1",     {&key_weapon1},         {'1'}            ,
517    0,MAX_KEY,def_key,ss_keys}, // key to switch to weapon 1 (fist/chainsaw)
518   {"key_weapon2",     {&key_weapon2},         {'2'}            ,
519    0,MAX_KEY,def_key,ss_keys}, // key to switch to weapon 2 (pistol)
520   {"key_weapon3",     {&key_weapon3},         {'3'}            ,
521    0,MAX_KEY,def_key,ss_keys}, // key to switch to weapon 3 (supershotgun/shotgun)
522   {"key_weapon4",     {&key_weapon4},         {'4'}            ,
523    0,MAX_KEY,def_key,ss_keys}, // key to switch to weapon 4 (chaingun)
524   {"key_weapon5",     {&key_weapon5},         {'5'}            ,
525    0,MAX_KEY,def_key,ss_keys}, // key to switch to weapon 5 (rocket launcher)
526   {"key_weapon6",     {&key_weapon6},         {'6'}            ,
527    0,MAX_KEY,def_key,ss_keys}, // key to switch to weapon 6 (plasma rifle)
528   {"key_weapon7",     {&key_weapon7},         {'7'}            ,
529    0,MAX_KEY,def_key,ss_keys}, // key to switch to weapon 7 (bfg9000)         //    ^
530   {"key_weapon8",     {&key_weapon8},         {'8'}            ,
531    0,MAX_KEY,def_key,ss_keys}, // key to switch to weapon 8 (chainsaw)        //    |
532   {"key_weapon9",     {&key_weapon9},         {'9'}            ,
533    0,MAX_KEY,def_key,ss_keys}, // key to switch to weapon 9 (supershotgun)    // phares
534 
535   // killough 2/22/98: screenshot key
536   {"key_screenshot",  {&key_screenshot},      {'*'}            ,
537    0,MAX_KEY,def_key,ss_keys}, // key to take a screenshot
538 
539   {"Joystick settings",{NULL},{0},UL,UL,def_none,ss_none},
540   {"use_joystick",{&usejoystick},{0},0,2,
541    def_int,ss_none}, // number of joystick to use (0 for none)
542   {"joy_left",{&joyleft},{0},  UL,UL,def_int,ss_none},
543   {"joy_right",{&joyright},{0},UL,UL,def_int,ss_none},
544   {"joy_up",  {&joyup},  {0},  UL,UL,def_int,ss_none},
545   {"joy_down",{&joydown},{0},  UL,UL,def_int,ss_none},
546   {"joyb_fire",{&joybfire},{0},0,UL,
547    def_int,ss_keys}, // joystick button number to use for fire
548   {"joyb_strafe",{&joybstrafe},{1},0,UL,
549    def_int,ss_keys}, // joystick button number to use for strafing
550   {"joyb_speed",{&joybspeed},{2},0,UL,
551    def_int,ss_keys}, // joystick button number to use for running
552   {"joyb_use",{&joybuse},{3},0,UL,
553    def_int,ss_keys}, // joystick button number to use for use/open
554 
555   {"Chat macros",{NULL},{0},UL,UL,def_none,ss_none},
556   {"chatmacro0", {0,&chat_macros[0]}, {0,HUSTR_CHATMACRO0},UL,UL,
557    def_str,ss_chat}, // chat string associated with 0 key
558   {"chatmacro1", {0,&chat_macros[1]}, {0,HUSTR_CHATMACRO1},UL,UL,
559    def_str,ss_chat}, // chat string associated with 1 key
560   {"chatmacro2", {0,&chat_macros[2]}, {0,HUSTR_CHATMACRO2},UL,UL,
561    def_str,ss_chat}, // chat string associated with 2 key
562   {"chatmacro3", {0,&chat_macros[3]}, {0,HUSTR_CHATMACRO3},UL,UL,
563    def_str,ss_chat}, // chat string associated with 3 key
564   {"chatmacro4", {0,&chat_macros[4]}, {0,HUSTR_CHATMACRO4},UL,UL,
565    def_str,ss_chat}, // chat string associated with 4 key
566   {"chatmacro5", {0,&chat_macros[5]}, {0,HUSTR_CHATMACRO5},UL,UL,
567    def_str,ss_chat}, // chat string associated with 5 key
568   {"chatmacro6", {0,&chat_macros[6]}, {0,HUSTR_CHATMACRO6},UL,UL,
569    def_str,ss_chat}, // chat string associated with 6 key
570   {"chatmacro7", {0,&chat_macros[7]}, {0,HUSTR_CHATMACRO7},UL,UL,
571    def_str,ss_chat}, // chat string associated with 7 key
572   {"chatmacro8", {0,&chat_macros[8]}, {0,HUSTR_CHATMACRO8},UL,UL,
573    def_str,ss_chat}, // chat string associated with 8 key
574   {"chatmacro9", {0,&chat_macros[9]}, {0,HUSTR_CHATMACRO9},UL,UL,
575    def_str,ss_chat}, // chat string associated with 9 key
576 
577   {"Automap settings",{NULL},{0},UL,UL,def_none,ss_none},
578   //jff 1/7/98 defaults for automap colors
579   //jff 4/3/98 remove -1 in lower range, 0 now disables new map features
580   {"mapcolor_back", {&mapcolor_back}, {247},0,255,  // black //jff 4/6/98 new black
581    def_colour,ss_auto}, // color used as background for automap
582   {"mapcolor_grid", {&mapcolor_grid}, {104},0,255,  // dk gray
583    def_colour,ss_auto}, // color used for automap grid lines
584   {"mapcolor_wall", {&mapcolor_wall}, {23},0,255,   // red-brown
585    def_colour,ss_auto}, // color used for one side walls on automap
586   {"mapcolor_fchg", {&mapcolor_fchg}, {55},0,255,   // lt brown
587    def_colour,ss_auto}, // color used for lines floor height changes across
588   {"mapcolor_cchg", {&mapcolor_cchg}, {215},0,255,  // orange
589    def_colour,ss_auto}, // color used for lines ceiling height changes across
590   {"mapcolor_clsd", {&mapcolor_clsd}, {208},0,255,  // white
591    def_colour,ss_auto}, // color used for lines denoting closed doors, objects
592   {"mapcolor_rkey", {&mapcolor_rkey}, {175},0,255,  // red
593    def_colour,ss_auto}, // color used for red key sprites
594   {"mapcolor_bkey", {&mapcolor_bkey}, {204},0,255,  // blue
595    def_colour,ss_auto}, // color used for blue key sprites
596   {"mapcolor_ykey", {&mapcolor_ykey}, {231},0,255,  // yellow
597    def_colour,ss_auto}, // color used for yellow key sprites
598   {"mapcolor_rdor", {&mapcolor_rdor}, {175},0,255,  // red
599    def_colour,ss_auto}, // color used for closed red doors
600   {"mapcolor_bdor", {&mapcolor_bdor}, {204},0,255,  // blue
601    def_colour,ss_auto}, // color used for closed blue doors
602   {"mapcolor_ydor", {&mapcolor_ydor}, {231},0,255,  // yellow
603    def_colour,ss_auto}, // color used for closed yellow doors
604   {"mapcolor_tele", {&mapcolor_tele}, {119},0,255,  // dk green
605    def_colour,ss_auto}, // color used for teleporter lines
606   {"mapcolor_secr", {&mapcolor_secr}, {252},0,255,  // purple
607    def_colour,ss_auto}, // color used for lines around secret sectors
608   {"mapcolor_exit", {&mapcolor_exit}, {0},0,255,    // none
609    def_colour,ss_auto}, // color used for exit lines
610   {"mapcolor_unsn", {&mapcolor_unsn}, {104},0,255,  // dk gray
611    def_colour,ss_auto}, // color used for lines not seen without computer map
612   {"mapcolor_flat", {&mapcolor_flat}, {88},0,255,   // lt gray
613    def_colour,ss_auto}, // color used for lines with no height changes
614   {"mapcolor_sprt", {&mapcolor_sprt}, {112},0,255,  // green
615    def_colour,ss_auto}, // color used as things
616   {"mapcolor_item", {&mapcolor_item}, {231},0,255,  // yellow
617    def_colour,ss_auto}, // color used for counted items
618   {"mapcolor_hair", {&mapcolor_hair}, {208},0,255,  // white
619    def_colour,ss_auto}, // color used for dot crosshair denoting center of map
620   {"mapcolor_sngl", {&mapcolor_sngl}, {208},0,255,  // white
621    def_colour,ss_auto}, // color used for the single player arrow
622   {"mapcolor_me",   {&mapcolor_me}, {112},0,255, // green
623    def_colour,ss_auto}, // your (player) colour
624   {"mapcolor_enemy",   {&mapcolor_enemy}, {177},0,255,
625    def_colour,ss_auto},
626   {"mapcolor_frnd",   {&mapcolor_frnd}, {112},0,255,
627    def_colour,ss_auto},
628   //jff 3/9/98 add option to not show secrets til after found
629   {"map_secret_after", {&map_secret_after}, {0},0,1, // show secret after gotten
630    def_bool,ss_auto}, // prevents showing secret sectors till after entered
631   {"map_point_coord", {&map_point_coordinates}, {0},0,1,
632    def_bool,ss_auto},
633   //jff 1/7/98 end additions for automap
634   {"automapmode", {(int*)&automapmode}, {0}, 0, 31, // CPhipps - remember automap mode
635    def_hex,ss_none}, // automap mode
636 
637   {"Heads-up display settings",{NULL},{0},UL,UL,def_none,ss_none},
638   //jff 2/16/98 defaults for color ranges in hud and status
639   {"hudcolor_titl", {&hudcolor_titl}, {5},0,9,  // gold range
640    def_int,ss_auto}, // color range used for automap level title
641   {"hudcolor_xyco", {&hudcolor_xyco}, {3},0,9,  // green range
642    def_int,ss_auto}, // color range used for automap coordinates
643   {"hudcolor_mesg", {&hudcolor_mesg}, {6},0,9,  // red range
644    def_int,ss_mess}, // color range used for messages during play
645   {"hudcolor_chat", {&hudcolor_chat}, {5},0,9,  // gold range
646    def_int,ss_mess}, // color range used for chat messages and entry
647   {"hudcolor_list", {&hudcolor_list}, {5},0,9,  // gold range  //jff 2/26/98
648    def_int,ss_mess}, // color range used for message review
649   {"hud_msg_lines", {&hud_msg_lines}, {1},1,16,  // 1 line scrolling window
650    def_int,ss_mess}, // number of messages in review display (1=disable)
651   {"hud_list_bgon", {&hud_list_bgon}, {0},0,1,  // solid window bg ena //jff 2/26/98
652    def_bool,ss_mess}, // enables background window behind message review
653   {"hud_distributed",{&hud_distributed},{0},0,1, // hud broken up into 3 displays //jff 3/4/98
654    def_bool,ss_none}, // splits HUD into three 2 line displays
655 
656   {"health_red",    {&health_red}   , {25},0,200, // below is red
657    def_int,ss_stat}, // amount of health for red to yellow transition
658   {"health_yellow", {&health_yellow}, {50},0,200, // below is yellow
659    def_int,ss_stat}, // amount of health for yellow to green transition
660   {"health_green",  {&health_green} , {100},0,200,// below is green, above blue
661    def_int,ss_stat}, // amount of health for green to blue transition
662   {"armor_red",     {&armor_red}    , {25},0,200, // below is red
663    def_int,ss_stat}, // amount of armor for red to yellow transition
664   {"armor_yellow",  {&armor_yellow} , {50},0,200, // below is yellow
665    def_int,ss_stat}, // amount of armor for yellow to green transition
666   {"armor_green",   {&armor_green}  , {100},0,200,// below is green, above blue
667    def_int,ss_stat}, // amount of armor for green to blue transition
668   {"ammo_red",      {&ammo_red}     , {25},0,100, // below 25% is red
669    def_int,ss_stat}, // percent of ammo for red to yellow transition
670   {"ammo_yellow",   {&ammo_yellow}  , {50},0,100, // below 50% is yellow, above green
671    def_int,ss_stat}, // percent of ammo for yellow to green transition
672 
673   //jff 2/16/98 HUD and status feature controls
674   {"hud_active",    {&hud_active}, {2},0,2, // 0=off, 1=small, 2=full
675    def_int,ss_none}, // 0 for HUD off, 1 for HUD small, 2 for full HUD
676   //jff 2/23/98
677   {"hud_displayed", {&hud_displayed},  {0},0,1, // whether hud is displayed
678    def_bool,ss_none}, // enables display of HUD
679   {"hud_nosecrets", {&hud_nosecrets},  {0},0,1, // no secrets/items/kills HUD line
680    def_bool,ss_stat}, // disables display of kills/items/secrets on HUD
681 
682   {"Weapon preferences",{NULL},{0},UL,UL,def_none,ss_none},
683   // killough 2/8/98: weapon preferences set by user:
684   {"weapon_choice_1", {&weapon_preferences[0][0]}, {6}, 0,9,
685    def_int,ss_weap}, // first choice for weapon (best)
686   {"weapon_choice_2", {&weapon_preferences[0][1]}, {9}, 0,9,
687    def_int,ss_weap}, // second choice for weapon
688   {"weapon_choice_3", {&weapon_preferences[0][2]}, {4}, 0,9,
689    def_int,ss_weap}, // third choice for weapon
690   {"weapon_choice_4", {&weapon_preferences[0][3]}, {3}, 0,9,
691    def_int,ss_weap}, // fourth choice for weapon
692   {"weapon_choice_5", {&weapon_preferences[0][4]}, {2}, 0,9,
693    def_int,ss_weap}, // fifth choice for weapon
694   {"weapon_choice_6", {&weapon_preferences[0][5]}, {8}, 0,9,
695    def_int,ss_weap}, // sixth choice for weapon
696   {"weapon_choice_7", {&weapon_preferences[0][6]}, {5}, 0,9,
697    def_int,ss_weap}, // seventh choice for weapon
698   {"weapon_choice_8", {&weapon_preferences[0][7]}, {7}, 0,9,
699    def_int,ss_weap}, // eighth choice for weapon
700   {"weapon_choice_9", {&weapon_preferences[0][8]}, {1}, 0,9,
701    def_int,ss_weap}, // ninth choice for weapon (worst)
702 
703   // cournia - support for arbitrary music file (defaults are mp3)
704   {"Music", {NULL},{0},UL,UL,def_none,ss_none},
705   {"mus_e1m1", {0,&S_music_files[mus_e1m1]}, {0,"e1m1.mp3"},UL,UL,
706    def_str,ss_none},
707   {"mus_e1m2", {0,&S_music_files[mus_e1m2]}, {0,"e1m2.mp3"},UL,UL,
708    def_str,ss_none},
709   {"mus_e1m3", {0,&S_music_files[mus_e1m3]}, {0,"e1m3.mp3"},UL,UL,
710    def_str,ss_none},
711   {"mus_e1m4", {0,&S_music_files[mus_e1m4]}, {0,"e1m4.mp3"},UL,UL,
712    def_str,ss_none},
713   {"mus_e1m5", {0,&S_music_files[mus_e1m5]}, {0,"e1m5.mp3"},UL,UL,
714    def_str,ss_none},
715   {"mus_e1m6", {0,&S_music_files[mus_e1m6]}, {0,"e1m6.mp3"},UL,UL,
716    def_str,ss_none},
717   {"mus_e1m7", {0,&S_music_files[mus_e1m7]}, {0,"e1m7.mp3"},UL,UL,
718    def_str,ss_none},
719   {"mus_e1m8", {0,&S_music_files[mus_e1m8]}, {0,"e1m8.mp3"},UL,UL,
720    def_str,ss_none},
721   {"mus_e1m9", {0,&S_music_files[mus_e1m9]}, {0,"e1m9.mp3"},UL,UL,
722    def_str,ss_none},
723   {"mus_e2m1", {0,&S_music_files[mus_e2m1]}, {0,"e2m1.mp3"},UL,UL,
724    def_str,ss_none},
725   {"mus_e2m2", {0,&S_music_files[mus_e2m2]}, {0,"e2m2.mp3"},UL,UL,
726    def_str,ss_none},
727   {"mus_e2m3", {0,&S_music_files[mus_e2m3]}, {0,"e2m3.mp3"},UL,UL,
728    def_str,ss_none},
729   {"mus_e2m4", {0,&S_music_files[mus_e2m4]}, {0,"e2m4.mp3"},UL,UL,
730    def_str,ss_none},
731   {"mus_e2m5", {0,&S_music_files[mus_e2m5]}, {0,"e1m7.mp3"},UL,UL,
732    def_str,ss_none},
733   {"mus_e2m6", {0,&S_music_files[mus_e2m6]}, {0,"e2m6.mp3"},UL,UL,
734    def_str,ss_none},
735   {"mus_e2m7", {0,&S_music_files[mus_e2m7]}, {0,"e2m7.mp3"},UL,UL,
736    def_str,ss_none},
737   {"mus_e2m8", {0,&S_music_files[mus_e2m8]}, {0,"e2m8.mp3"},UL,UL,
738    def_str,ss_none},
739   {"mus_e2m9", {0,&S_music_files[mus_e2m9]}, {0,"e3m1.mp3"},UL,UL,
740    def_str,ss_none},
741   {"mus_e3m1", {0,&S_music_files[mus_e3m1]}, {0,"e3m1.mp3"},UL,UL,
742    def_str,ss_none},
743   {"mus_e3m2", {0,&S_music_files[mus_e3m2]}, {0,"e3m2.mp3"},UL,UL,
744    def_str,ss_none},
745   {"mus_e3m3", {0,&S_music_files[mus_e3m3]}, {0,"e3m3.mp3"},UL,UL,
746    def_str,ss_none},
747   {"mus_e3m4", {0,&S_music_files[mus_e3m4]}, {0,"e1m8.mp3"},UL,UL,
748    def_str,ss_none},
749   {"mus_e3m5", {0,&S_music_files[mus_e3m5]}, {0,"e1m7.mp3"},UL,UL,
750    def_str,ss_none},
751   {"mus_e3m6", {0,&S_music_files[mus_e3m6]}, {0,"e1m6.mp3"},UL,UL,
752    def_str,ss_none},
753   {"mus_e3m7", {0,&S_music_files[mus_e3m7]}, {0,"e2m7.mp3"},UL,UL,
754    def_str,ss_none},
755   {"mus_e3m8", {0,&S_music_files[mus_e3m8]}, {0,"e3m8.mp3"},UL,UL,
756    def_str,ss_none},
757   {"mus_e3m9", {0,&S_music_files[mus_e3m9]}, {0,"e1m9.mp3"},UL,UL,
758    def_str,ss_none},
759   {"mus_inter", {0,&S_music_files[mus_inter]}, {0,"e2m3.mp3"},UL,UL,
760    def_str,ss_none},
761   {"mus_intro", {0,&S_music_files[mus_intro]}, {0,"intro.mp3"},UL,UL,
762    def_str,ss_none},
763   {"mus_bunny", {0,&S_music_files[mus_bunny]}, {0,"bunny.mp3"},UL,UL,
764    def_str,ss_none},
765   {"mus_victor", {0,&S_music_files[mus_victor]}, {0,"victor.mp3"},UL,UL,
766    def_str,ss_none},
767   {"mus_introa", {0,&S_music_files[mus_introa]}, {0,"intro.mp3"},UL,UL,
768    def_str,ss_none},
769   {"mus_runnin", {0,&S_music_files[mus_runnin]}, {0,"runnin.mp3"},UL,UL,
770    def_str,ss_none},
771   {"mus_stalks", {0,&S_music_files[mus_stalks]}, {0,"stalks.mp3"},UL,UL,
772    def_str,ss_none},
773   {"mus_countd", {0,&S_music_files[mus_countd]}, {0,"countd.mp3"},UL,UL,
774    def_str,ss_none},
775   {"mus_betwee", {0,&S_music_files[mus_betwee]}, {0,"betwee.mp3"},UL,UL,
776    def_str,ss_none},
777   {"mus_doom", {0,&S_music_files[mus_doom]}, {0,"doom.mp3"},UL,UL,
778    def_str,ss_none},
779   {"mus_the_da", {0,&S_music_files[mus_the_da]}, {0,"the_da.mp3"},UL,UL,
780    def_str,ss_none},
781   {"mus_shawn", {0,&S_music_files[mus_shawn]}, {0,"shawn.mp3"},UL,UL,
782    def_str,ss_none},
783   {"mus_ddtblu", {0,&S_music_files[mus_ddtblu]}, {0,"ddtblu.mp3"},UL,UL,
784    def_str,ss_none},
785   {"mus_in_cit", {0,&S_music_files[mus_in_cit]}, {0,"in_cit.mp3"},UL,UL,
786    def_str,ss_none},
787   {"mus_dead", {0,&S_music_files[mus_dead]}, {0,"dead.mp3"},UL,UL,
788    def_str,ss_none},
789   {"mus_stlks2", {0,&S_music_files[mus_stlks2]}, {0,"stalks.mp3"},UL,UL,
790    def_str,ss_none},
791   {"mus_theda2", {0,&S_music_files[mus_theda2]}, {0,"the_da.mp3"},UL,UL,
792    def_str,ss_none},
793   {"mus_doom2", {0,&S_music_files[mus_doom2]}, {0,"doom.mp3"},UL,UL,
794    def_str,ss_none},
795   {"mus_ddtbl2", {0,&S_music_files[mus_ddtbl2]}, {0,"ddtblu.mp3"},UL,UL,
796    def_str,ss_none},
797   {"mus_runni2", {0,&S_music_files[mus_runni2]}, {0,"runnin.mp3"},UL,UL,
798    def_str,ss_none},
799   {"mus_dead2", {0,&S_music_files[mus_dead2]}, {0,"dead.mp3"},UL,UL,
800    def_str,ss_none},
801   {"mus_stlks3", {0,&S_music_files[mus_stlks3]}, {0,"stalks.mp3"},UL,UL,
802    def_str,ss_none},
803   {"mus_romero", {0,&S_music_files[mus_romero]}, {0,"romero.mp3"},UL,UL,
804    def_str,ss_none},
805   {"mus_shawn2", {0,&S_music_files[mus_shawn2]}, {0,"shawn.mp3"},UL,UL,
806    def_str,ss_none},
807   {"mus_messag", {0,&S_music_files[mus_messag]}, {0,"messag.mp3"},UL,UL,
808    def_str,ss_none},
809   {"mus_count2", {0,&S_music_files[mus_count2]}, {0,"countd.mp3"},UL,UL,
810    def_str,ss_none},
811   {"mus_ddtbl3", {0,&S_music_files[mus_ddtbl3]}, {0,"ddtblu.mp3"},UL,UL,
812    def_str,ss_none},
813   {"mus_ampie", {0,&S_music_files[mus_ampie]}, {0,"ampie.mp3"},UL,UL,
814    def_str,ss_none},
815   {"mus_theda3", {0,&S_music_files[mus_theda3]}, {0,"the_da.mp3"},UL,UL,
816    def_str,ss_none},
817   {"mus_adrian", {0,&S_music_files[mus_adrian]}, {0,"adrian.mp3"},UL,UL,
818    def_str,ss_none},
819   {"mus_messg2", {0,&S_music_files[mus_messg2]}, {0,"messag.mp3"},UL,UL,
820    def_str,ss_none},
821   {"mus_romer2", {0,&S_music_files[mus_romer2]}, {0,"romero.mp3"},UL,UL,
822    def_str,ss_none},
823   {"mus_tense", {0,&S_music_files[mus_tense]}, {0,"tense.mp3"},UL,UL,
824    def_str,ss_none},
825   {"mus_shawn3", {0,&S_music_files[mus_shawn3]}, {0,"shawn.mp3"},UL,UL,
826    def_str,ss_none},
827   {"mus_openin", {0,&S_music_files[mus_openin]}, {0,"openin.mp3"},UL,UL,
828    def_str,ss_none},
829   {"mus_evil", {0,&S_music_files[mus_evil]}, {0,"evil.mp3"},UL,UL,
830    def_str,ss_none},
831   {"mus_ultima", {0,&S_music_files[mus_ultima]}, {0,"ultima.mp3"},UL,UL,
832    def_str,ss_none},
833   {"mus_read_m", {0,&S_music_files[mus_read_m]}, {0,"read_m.mp3"},UL,UL,
834    def_str,ss_none},
835   {"mus_dm2ttl", {0,&S_music_files[mus_dm2ttl]}, {0,"dm2ttl.mp3"},UL,UL,
836    def_str,ss_none},
837   {"mus_dm2int", {0,&S_music_files[mus_dm2int]}, {0,"dm2int.mp3"},UL,UL,
838    def_str,ss_none},
839 };
840 
841 int numdefaults;
842 static const char* defaultfile; // CPhipps - static, const
843 
844 //
845 // M_SaveDefaults
846 //
847 
M_SaveDefaults(void)848 void M_SaveDefaults (void)
849   {
850   int   i;
851   FILE* f;
852 
853   f = fopen (defaultfile, "w");
854   if (!f)
855     return; // can't write the file, but don't complain
856 
857   // 3/3/98 explain format of file
858 
859   fprintf(f,"# Doom config file\n");
860   fprintf(f,"# Format:\n");
861   fprintf(f,"# variable   value\n");
862 
863   for (i = 0 ; i < numdefaults ; i++) {
864     if (defaults[i].type == def_none) {
865       // CPhipps - pure headers
866       fprintf(f, "\n# %s\n", defaults[i].name);
867     } else
868     // CPhipps - modified for new default_t form
869     if (!IS_STRING(defaults[i])) //jff 4/10/98 kill super-hack on pointer value
870       {
871       // CPhipps - remove keycode hack
872       // killough 3/6/98: use spaces instead of tabs for uniform justification
873       if (defaults[i].type == def_hex)
874   fprintf (f,"%-25s 0x%x\n",defaults[i].name,*(defaults[i].location.pi));
875       else
876   fprintf (f,"%-25s %5i\n",defaults[i].name,*(defaults[i].location.pi));
877       }
878     else
879       {
880       fprintf (f,"%-25s \"%s\"\n",defaults[i].name,*(defaults[i].location.ppsz));
881       }
882     }
883 
884   fclose (f);
885   }
886 
887 /*
888  * M_LookupDefault
889  *
890  * cph - mimic MBF function for now. Yes it's crap.
891  */
892 
M_LookupDefault(const char * name)893 struct default_s *M_LookupDefault(const char *name)
894 {
895   int i;
896   for (i = 0 ; i < numdefaults ; i++)
897     if ((defaults[i].type != def_none) && !strcmp(name, defaults[i].name))
898       return &defaults[i];
899   I_Error("M_LookupDefault: %s not found",name);
900   return NULL;
901 }
902 
903 //
904 // M_LoadDefaults
905 //
906 
907 #define NUMCHATSTRINGS 10 // phares 4/13/98
908 
M_LoadDefaults(void)909 void M_LoadDefaults (void)
910 {
911   int   i;
912   int   len;
913   FILE* f;
914   char  def[80];
915   char  strparm[100];
916   char* newstring = NULL;   // killough
917   int   parm;
918   boolean isstring;
919 
920   // set everything to base values
921 
922   numdefaults = sizeof(defaults)/sizeof(defaults[0]);
923   for (i = 0 ; i < numdefaults ; i++) {
924     if (defaults[i].location.ppsz)
925       *defaults[i].location.ppsz = strdup(defaults[i].defaultvalue.psz);
926     if (defaults[i].location.pi)
927       *defaults[i].location.pi = defaults[i].defaultvalue.i;
928   }
929 
930   // check for a custom default file
931 
932   i = M_CheckParm ("-config");
933   if (i && i < myargc-1)
934     defaultfile = myargv[i+1];
935   else {
936     const char* exedir = I_DoomExeDir();
937     defaultfile = malloc(PATH_MAX+1);
938     /* get config file from same directory as executable */
939 #ifdef HAVE_SNPRINTF
940     snprintf((char *)defaultfile, PATH_MAX,
941 #else
942     sprintf ((char *)defaultfile,
943 #endif
944             "%s%s%sboom.cfg", exedir, HasTrailingSlash(exedir) ? "" : "/",
945 #if ((defined GL_DOOM) && (defined _MSC_VER))
946             "gl");
947 #else
948             "pr");
949 #endif
950   }
951 
952   lprintf (LO_CONFIRM, " default file: %s\n",defaultfile);
953 
954   // read the file in, overriding any set defaults
955 
956   f = fopen (defaultfile, "r");
957   if (f)
958     {
959     while (!feof(f))
960       {
961       isstring = false;
962       if (fscanf (f, "%79s %[^\n]\n", def, strparm) == 2)
963         {
964 
965         //jff 3/3/98 skip lines not starting with an alphanum
966 
967         if (!isalnum(def[0]))
968           continue;
969 
970         if (strparm[0] == '"') {
971           // get a string default
972 
973           isstring = true;
974           len = strlen(strparm);
975           newstring = (char *) malloc(len);
976           strparm[len-1] = 0; // clears trailing double-quote mark
977           strcpy(newstring, strparm+1); // clears leading double-quote mark
978   } else if ((strparm[0] == '0') && (strparm[1] == 'x')) {
979     // CPhipps - allow ints to be specified in hex
980     sscanf(strparm+2, "%x", &parm);
981   } else {
982           sscanf(strparm, "%i", &parm);
983     // Keycode hack removed
984   }
985 
986         for (i = 0 ; i < numdefaults ; i++)
987           if ((defaults[i].type != def_none) && !strcmp(def, defaults[i].name))
988             {
989       // CPhipps - safety check
990             if (isstring != IS_STRING(defaults[i])) {
991         lprintf(LO_WARN, "M_LoadDefaults: Type mismatch reading %s\n", defaults[i].name);
992         continue;
993       }
994             if (!isstring)
995               {
996 
997               //jff 3/4/98 range check numeric parameters
998 
999               if ((defaults[i].minvalue==UL || defaults[i].minvalue<=parm) &&
1000                   (defaults[i].maxvalue==UL || defaults[i].maxvalue>=parm))
1001                 *(defaults[i].location.pi) = parm;
1002               }
1003             else
1004               {
1005               free((char*)*(defaults[i].location.ppsz));  /* phares 4/13/98 */
1006               *(defaults[i].location.ppsz) = newstring;
1007               }
1008             break;
1009             }
1010         }
1011       }
1012 
1013     fclose (f);
1014     }
1015   //jff 3/4/98 redundant range checks for hud deleted here
1016   /* proff 2001/7/1 - added prboom.wad as last entry so it's always loaded and
1017      doesn't overlap with the cfg settings */
1018   wad_files[MAXLOADFILES-1]="prboom.wad";
1019 }
1020 
1021 
1022 //
1023 // SCREEN SHOTS
1024 //
1025 
1026 //
1027 // M_ScreenShot
1028 //
1029 // Modified by Lee Killough so that any number of shots can be taken,
1030 // the code is faster, and no annoying "screenshot" message appears.
1031 
1032 // CPhipps - modified to use its own buffer for the image
1033 //         - checks for the case where no file can be created (doesn't occur on POSIX systems, would on DOS)
1034 //         - track errors better
1035 //         - split into 2 functions
1036 
1037 //
1038 // M_DoScreenShot
1039 // Takes a screenshot into the names file
1040 
M_DoScreenShot(const char * fname)1041 void M_DoScreenShot (const char* fname)
1042 {
1043   if (I_ScreenShot(fname) != 0)
1044     doom_printf("M_ScreenShot: Error writing screenshot\n");
1045 }
1046 
1047 #ifndef SCREENSHOT_DIR
1048 #define SCREENSHOT_DIR "."
1049 #endif
1050 
1051 #ifdef HAVE_LIBPNG
1052 #define SCREENSHOT_EXT ".png"
1053 #else
1054 #define SCREENSHOT_EXT ".bmp"
1055 #endif
1056 
M_ScreenShot(void)1057 void M_ScreenShot(void)
1058 {
1059   static int shot;
1060   char       lbmname[PATH_MAX + 1];
1061   int        startshot;
1062 
1063   if (!access(SCREENSHOT_DIR,2))
1064   {
1065     startshot = shot; // CPhipps - prevent infinite loop
1066 
1067     do {
1068       sprintf(lbmname,"%s/doom%02d" SCREENSHOT_EXT, SCREENSHOT_DIR, shot++);
1069     } while (!access(lbmname,0) && (shot != startshot) && (shot < 10000));
1070 
1071     if (access(lbmname,0))
1072     {
1073       S_StartSound(NULL,gamemode==commercial ? sfx_radio : sfx_tink);
1074       M_DoScreenShot(lbmname); // cph
1075       return;
1076     }
1077   }
1078 
1079   doom_printf ("M_ScreenShot: Couldn't create screenshot");
1080   return;
1081 }
1082