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  *  Auxiliary functions.
33  *
34  *-----------------------------------------------------------------------------*/
35 
36 #include "config.h"
37 
38 #include <stdio.h>
39 #include <errno.h>
40 #ifdef _MSC_VER
41 #include <io.h>
42 #include <compat/msvc.h>
43 #endif
44 #include <fcntl.h>
45 #include <sys/stat.h>
46 
47 #include "doomstat.h"
48 #include "m_argv.h"
49 #include "g_game.h"
50 #include "m_menu.h"
51 #include "am_map.h"
52 #include "w_wad.h"
53 #include "i_system.h"
54 #include "i_sound.h"
55 #include "i_video.h"
56 #include "v_video.h"
57 #include "hu_stuff.h"
58 #include "st_stuff.h"
59 #include "dstrings.h"
60 #include "m_misc.h"
61 #include "s_sound.h"
62 #include "sounds.h"
63 #include "lprintf.h"
64 #include "d_main.h"
65 #include "r_draw.h"
66 #include "r_demo.h"
67 #include "r_fps.h"
68 #include "r_sky.h"
69 
70 #ifdef _WIN32
71    #define DIR_SLASH_STR "\\"
72 #else
73    #define DIR_SLASH_STR "/"
74 #endif
75 
76 extern dbool   r_wigglefix;
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 dbool   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   length = fwrite(source, 1, length, fp) == (size_t)length;   // Write data
94   fclose(fp);
95 
96   if (!length)                         // Remove partially written file
97     remove(name);
98 
99   return length;
100 }
101 
102 /*
103  * M_ReadFile
104  *
105  * killough 9/98: rewritten to use stdio and to flash disk icon
106  */
107 
M_ReadFile(char const * name,uint8_t ** buffer)108 int M_ReadFile(char const *name, uint8_t **buffer)
109 {
110    FILE *fp;
111 
112    if ((fp = fopen(name, "rb")))
113    {
114       size_t length;
115 
116       fseek(fp, 0, SEEK_END);
117       length = ftell(fp);
118       fseek(fp, 0, SEEK_SET);
119       *buffer = Z_Malloc(length, PU_STATIC, 0);
120       if (fread(*buffer, 1, length, fp) == length)
121       {
122          fclose(fp);
123          return length;
124       }
125       fclose(fp);
126    }
127 
128    /* cph 2002/08/10 - this used to return 0 on error, but that's ambiguous,
129     * because we could have a legit 0-length file. So make it -1. */
130    return -1;
131 }
132 
133 /*
134  * M_Strupr
135  *
136  * String to Uppercase
137  */
M_Strupr(char * str)138 char* M_Strupr(char* str)
139 {
140   char* p;
141   for (p=str; *p; p++) *p = toupper(*p);
142   return str;
143 }
144 
145 
146 //
147 // DEFAULTS
148 //
149 
150 int usemouse;
151 dbool      precache = TRUE; /* if TRUE, load all graphics at start */
152 
153 extern int viewwidth;
154 extern int viewheight;
155 
156 extern int tran_filter_pct;            // killough 2/21/98
157 
158 extern int screenblocks;
159 extern int showMessages;
160 
161 extern int movement_maxviewpitch;
162 
163 int         mus_pause_opt; // 0 = kill music, 1 = pause, 2 = continue
164 int         mus_load_external; // 0 = never load external music files, 1 = always load it, 2 = only from iwads
165 
166 extern const char* chat_macros[];
167 
168 extern const char* S_music_files[]; // cournia
169 
170 /* cph - Some MBF stuff parked here for now
171  * killough 10/98
172  */
173 int map_point_coordinates;
174 
175 default_t defaults[] =
176 {
177   {"Misc settings",{NULL},{0},UL,UL,def_none,ss_none, NULL, NULL},
178   {"default_compatibility_level",{(int*)&default_compatibility_level, NULL},
179    {-1, NULL},-1,MAX_COMPATIBILITY_LEVEL-1,
180    def_int,ss_none, NULL, NULL}, // compatibility level" - CPhipps
181   {"menu_background", {(int*)&menu_background, NULL}, {1, NULL}, 0, 1,
182    def_bool,ss_gen, NULL, NULL}, // do Boom fullscreen menus have backgrounds?
183   {"max_player_corpse", {&bodyquesize, NULL}, {32, NULL},-1,UL,   // killough 2/8/98
184    def_int,ss_gen, NULL, NULL}, // number of dead bodies in view supported (-1 = no limit)
185   {"flashing_hom",{&flashing_hom, NULL},{0, NULL},0,1,
186    def_bool,ss_gen, NULL, NULL}, // killough 10/98 - enable flashing HOM indicator
187   {"demo_insurance",{&default_demo_insurance, NULL},{2, NULL},0,2,  // killough 3/31/98
188    def_int,ss_none, NULL, NULL}, // 1=take special steps ensuring demo sync, 2=only during recordings
189   {"level_precache",{(int*)&precache, NULL},{0, NULL},0,1,
190    def_bool,ss_none, NULL, NULL}, // precache level data?
191   {"demo_smoothturns", {&demo_smoothturns, NULL},  {0, NULL},0,1,
192    def_bool,ss_gen, NULL, NULL},
193   {"demo_smoothturnsfactor", {&demo_smoothturnsfactor, NULL},  {6, NULL},1,SMOOTH_PLAYING_MAXFACTOR,
194    def_int,ss_gen, NULL, NULL},
195 
196   {"Files",{NULL},{0},UL,UL,def_none,ss_none, NULL, NULL},
197   /* cph - MBF-like wad/deh/bex autoload code */
198   {"wadfile_1",{NULL,&wad_files[0]},{0,""},UL,UL,def_str,ss_gen, NULL, NULL},
199   {"wadfile_2",{NULL,&wad_files[1]},{0,""},UL,UL,def_str,ss_gen, NULL, NULL},
200   {"wadfile_3",{NULL,&wad_files[2]},{0,""},UL,UL,def_str,ss_gen, NULL, NULL},
201   {"wadfile_4",{NULL,&wad_files[3]},{0,""},UL,UL,def_str,ss_gen, NULL, NULL},
202   {"wadfile_5",{NULL,&wad_files[4]},{0,""},UL,UL,def_str,ss_gen, NULL, NULL},
203   {"wadfile_6",{NULL,&wad_files[5]},{0,""},UL,UL,def_str,ss_gen, NULL, NULL},
204   {"wadfile_7",{NULL,&wad_files[6]},{0,""},UL,UL,def_str,ss_gen, NULL, NULL},
205   {"wadfile_8",{NULL,&wad_files[7]},{0,""},UL,UL,def_str,ss_gen, NULL, NULL},
206   {"dehfile_1",{NULL,&deh_files[0]},{0,""},UL,UL,def_str,ss_gen, NULL, NULL},
207   {"dehfile_2",{NULL,&deh_files[1]},{0,""},UL,UL,def_str,ss_gen, NULL, NULL},
208 
209   {"Game settings",{NULL},{0},UL,UL,def_none,ss_none, NULL, NULL},
210   {"default_skill",{&defaultskill, NULL},{3, NULL},1,5, // jff 3/24/98 allow default skill setting
211    def_int,ss_gen, NULL, NULL}, // selects default skill 1=TYTD 2=NTR 3=HMP 4=UV 5=NM
212   {"weapon_recoil",{&default_weapon_recoil, NULL},{0, NULL},0,1,
213    def_bool,ss_weap, &weapon_recoil, NULL},
214   /* killough 10/98 - toggle between SG/SSG and Fist/Chainsaw */
215   {"doom_weapon_toggles",{&doom_weapon_toggles, NULL}, {1, NULL}, 0, 1,
216    def_bool, ss_weap, NULL, NULL },
217   {"player_bobbing",{&default_player_bobbing, NULL},{1, NULL},0,1,         // phares 2/25/98
218    def_bool,ss_weap, &player_bobbing, NULL},
219   {"monsters_remember",{&default_monsters_remember, NULL},{1, NULL},0,1,   // killough 3/1/98
220    def_bool,ss_enem, &monsters_remember, NULL},
221    /* MBF AI enhancement options */
222   {"monster_infighting",{&default_monster_infighting, NULL}, {1, NULL}, 0, 1,
223    def_bool, ss_enem, &monster_infighting, NULL},
224   {"monster_backing",{&default_monster_backing, NULL}, {0, NULL}, 0, 1,
225    def_bool, ss_enem, &monster_backing, NULL},
226   {"monster_avoid_hazards",{&default_monster_avoid_hazards, NULL}, {1, NULL}, 0, 1,
227    def_bool, ss_enem, &monster_avoid_hazards, NULL},
228   {"monkeys",{&default_monkeys, NULL}, {0, NULL}, 0, 1,
229    def_bool, ss_enem, &monkeys, NULL},
230   {"monster_friction",{&default_monster_friction, NULL}, {1, NULL}, 0, 1,
231    def_bool, ss_enem, &monster_friction, NULL},
232   {"help_friends",{&default_help_friends, NULL}, {1, NULL}, 0, 1,
233    def_bool, ss_enem, &help_friends, NULL},
234   {"allow_pushers",{&default_allow_pushers, NULL},{1, NULL},0,1,
235    def_bool,ss_weap, &allow_pushers, NULL},
236   {"variable_friction",{&default_variable_friction, NULL},{1, NULL},0,1,
237    def_bool,ss_weap, &variable_friction, NULL},
238    /* End of MBF AI extras */
239 
240   {"sts_always_red",{&sts_always_red, NULL},{1, NULL},0,1, // no color changes on status bar
241    def_bool,ss_stat, NULL, NULL},
242   {"sts_pct_always_gray",{&sts_pct_always_gray, NULL},{0, NULL},0,1, // 2/23/98 chg default
243    def_bool,ss_stat, NULL, NULL}, // makes percent signs on status bar always gray
244   {"sts_traditional_keys",{&sts_traditional_keys, NULL},{0, NULL},0,1,  // killough 2/28/98
245    def_bool,ss_stat, NULL, NULL}, // disables doubled card and skull key display on status bar
246   {"show_messages",{&showMessages, NULL},{1, NULL},0,1,
247    def_bool,ss_none, NULL, NULL}, // enables message display
248   {"autorun",{&autorun, NULL},{0, NULL},0,1,  // killough 3/6/98: preserve autorun across games
249    def_bool,ss_none, NULL, NULL},
250 
251   {"Compatibility settings",{NULL},{0},UL,UL,def_none,ss_none, NULL, NULL},
252   {"comp_zombie",{&default_comp[comp_zombie], NULL},{0, NULL},0,1,def_bool,ss_comp,&comp[comp_zombie], NULL},
253   {"comp_infcheat",{&default_comp[comp_infcheat], NULL},{0, NULL},0,1,def_bool,ss_comp,&comp[comp_infcheat], NULL},
254   {"comp_stairs",{&default_comp[comp_stairs], NULL},{0, NULL},0,1,def_bool,ss_comp,&comp[comp_stairs], NULL},
255   {"comp_telefrag",{&default_comp[comp_telefrag], NULL},{0, NULL},0,1,def_bool,ss_comp,&comp[comp_telefrag], NULL},
256   {"comp_dropoff",{&default_comp[comp_dropoff], NULL},{0, NULL},0,1,def_bool,ss_comp,&comp[comp_dropoff], NULL},
257   {"comp_falloff",{&default_comp[comp_falloff], NULL},{0, NULL},0,1,def_bool,ss_comp,&comp[comp_falloff], NULL},
258   {"comp_staylift",{&default_comp[comp_staylift], NULL},{0, NULL},0,1,def_bool,ss_comp,&comp[comp_staylift], NULL},
259   {"comp_doorstuck",{&default_comp[comp_doorstuck], NULL},{0, NULL},0,1,def_bool,ss_comp,&comp[comp_doorstuck], NULL},
260   {"comp_pursuit",{&default_comp[comp_pursuit], NULL},{0, NULL},0,1,def_bool,ss_comp,&comp[comp_pursuit], NULL},
261   {"comp_vile",{&default_comp[comp_vile], NULL},{0, NULL},0,1,def_bool,ss_comp,&comp[comp_vile], NULL},
262   {"comp_pain",{&default_comp[comp_pain], NULL},{0, NULL},0,1,def_bool,ss_comp,&comp[comp_pain], NULL},
263   {"comp_skull",{&default_comp[comp_skull], NULL},{0, NULL},0,1,def_bool,ss_comp,&comp[comp_skull], NULL},
264   {"comp_blazing",{&default_comp[comp_blazing], NULL},{0, NULL},0,1,def_bool,ss_comp,&comp[comp_blazing], NULL},
265   {"comp_doorlight",{&default_comp[comp_doorlight], NULL},{0, NULL},0,1,def_bool,ss_comp,&comp[comp_doorlight], NULL},
266   {"comp_god",{&default_comp[comp_god], NULL},{0, NULL},0,1,def_bool,ss_comp,&comp[comp_god], NULL},
267   {"comp_skymap",{&default_comp[comp_skymap], NULL},{0, NULL},0,1,def_bool,ss_comp,&comp[comp_skymap], NULL},
268   {"comp_floors",{&default_comp[comp_floors], NULL},{0, NULL},0,1,def_bool,ss_comp,&comp[comp_floors], NULL},
269   {"comp_model",{&default_comp[comp_model], NULL},{0, NULL},0,1,def_bool,ss_comp,&comp[comp_model], NULL},
270   {"comp_zerotags",{&default_comp[comp_zerotags], NULL},{0, NULL},0,1,def_bool,ss_comp,&comp[comp_zerotags], NULL},
271   {"comp_moveblock",{&default_comp[comp_moveblock], NULL},{0, NULL},0,1,def_bool,ss_comp,&comp[comp_moveblock], NULL},
272   {"comp_sound",{&default_comp[comp_sound], NULL},{0, NULL},0,1,def_bool,ss_comp,&comp[comp_sound], NULL},
273   {"comp_666",{&default_comp[comp_666], NULL},{0, NULL},0,1,def_bool,ss_comp,&comp[comp_666], NULL},
274   {"comp_soul",{&default_comp[comp_soul], NULL},{0, NULL},0,1,def_bool,ss_comp,&comp[comp_soul], NULL},
275   {"comp_maskedanim",{&default_comp[comp_maskedanim], NULL},{0, NULL},
276      0,1,def_bool,ss_comp,&comp[comp_maskedanim], NULL},
277 
278   {"Sound settings",{NULL},{0},UL,UL,def_none,ss_none, NULL, NULL},
279   {"pitched_sounds",{&pitched_sounds, NULL},{0, NULL},0,1, // killough 2/21/98
280    def_bool,ss_gen, NULL, NULL}, // enables variable pitch in sound effects (from id's original code)
281   {"samplerate",{&snd_samplerate, NULL},{11025, NULL},11025,48000, def_int,ss_none, NULL, NULL},
282   {"sfx_volume",{&snd_SfxVolume, NULL},{8, NULL},0,15, def_int,ss_none, NULL, NULL},
283   {"music_volume",{&snd_MusicVolume, NULL},{8, NULL},0,15, def_int,ss_none, NULL, NULL},
284   {"mus_pause_opt",{&mus_pause_opt, NULL},{2, NULL},0,2, // CPhipps - music pausing
285    def_int, ss_none, NULL, NULL}, // 0 = kill music when paused, 1 = pause music, 2 = let music continue
286   {"mus_load_external", {&mus_load_external, NULL},  {2, NULL},0,2,
287     def_int,ss_gen, NULL, NULL}, // 0 = never load external music files, 1 = always load it, 2 = only from iwads
288   {"snd_channels",{&default_numChannels, NULL},{8, NULL},1,32,
289    def_int,ss_gen, NULL, NULL}, // number of audio events simultaneously // killough
290 
291   {"Video settings",{NULL, NULL},{0, NULL},UL,UL,def_none,ss_none, NULL, NULL},
292   {"screenblocks",{&screenblocks, NULL},{0, NULL},0,1,  // used to be int 3-11 (now just boolean)
293    def_int,ss_none, NULL, NULL},
294   {"usegamma",{&usegamma, NULL},{0, NULL},0,4, //jff 3/6/98 fix erroneous upper limit in range
295    def_int,ss_gen, NULL, NULL}, // gamma correction level // killough 1/18/98
296   {"uncapped_framerate", {&movement_smooth, NULL},  {3, NULL},0,16,
297    def_int,ss_gen, NULL, NULL},
298   {"filter_wall",{(int*)&drawvars.filterwall, NULL},{RDRAW_FILTER_POINT, NULL},
299    RDRAW_FILTER_POINT, RDRAW_FILTER_ROUNDED, def_int,ss_gen, NULL, NULL},
300   {"filter_floor",{(int*)&drawvars.filterfloor, NULL},{RDRAW_FILTER_POINT, NULL},
301    RDRAW_FILTER_POINT, RDRAW_FILTER_ROUNDED, def_int,ss_gen, NULL, NULL},
302   {"filter_sprite",{(int*)&drawvars.filtersprite, NULL},{RDRAW_FILTER_POINT, NULL},
303    RDRAW_FILTER_POINT, RDRAW_FILTER_ROUNDED, def_int,ss_gen, NULL, NULL},
304   {"filter_z",{(int*)&drawvars.filterz, NULL},{RDRAW_FILTER_POINT, NULL},
305    RDRAW_FILTER_POINT, RDRAW_FILTER_LINEAR, def_int,ss_gen, NULL, NULL},
306   {"filter_patch",{(int*)&drawvars.filterpatch, NULL},{RDRAW_FILTER_POINT, NULL},
307    RDRAW_FILTER_POINT, RDRAW_FILTER_ROUNDED, def_int,ss_gen, NULL, NULL},
308   {"filter_threshold",{(int*)&drawvars.mag_threshold, NULL},{49152, NULL},
309    0, UL, def_int,ss_none, NULL, NULL},
310   {"sprite_edges",{(int*)&drawvars.sprite_edges, NULL},{RDRAW_MASKEDCOLUMNEDGE_SQUARE, NULL},
311    RDRAW_MASKEDCOLUMNEDGE_SQUARE, RDRAW_MASKEDCOLUMNEDGE_SLOPED, def_int,ss_gen, NULL, NULL},
312   {"patch_edges",{(int*)&drawvars.patch_edges, NULL},{RDRAW_MASKEDCOLUMNEDGE_SQUARE, NULL},
313    RDRAW_MASKEDCOLUMNEDGE_SQUARE, RDRAW_MASKEDCOLUMNEDGE_SLOPED, def_int,ss_gen, NULL, NULL},
314   {"render_stretchsky",{&r_stretchsky, NULL},{1, NULL},0,1,
315    def_bool,ss_gen,NULL, NULL},
316   {"r_wiggle_fix",{(int*)&r_wiggle_fix, NULL},{1, NULL},0,1,
317    def_bool,ss_gen,NULL, NULL},
318 
319   {"Mouse settings",{NULL, NULL},{0, NULL},UL,UL,def_none,ss_none, NULL, NULL},
320   //jff 4/3/98 allow unlimited sensitivity
321   {"mouse_sensitivity_horiz",{&mouseSensitivity_horiz, NULL},{40, NULL},0,UL,
322    def_int,ss_none, NULL, NULL}, /* adjust horizontal (x) mouse sensitivity killough/mead */
323   //jff 4/3/98 allow unlimited sensitivity
324   {"mouse_sensitivity_vert",{&mouseSensitivity_vert, NULL},{40, NULL},0,UL,
325    def_int,ss_none, NULL, NULL}, /* adjust vertical (y) mouse sensitivity killough/mead */
326   //jff 3/8/98 allow -1 in mouse bindings to disable mouse function
327   {"mouseb_fire",{&mousebfire, NULL},{0, NULL},-1,MAX_MOUSEB,
328    def_int,ss_keys, NULL, NULL}, // mouse button number to use for fire
329   {"mouseb_strafe",{&mousebstrafe, NULL},{1, NULL},-1,MAX_MOUSEB,
330    def_int,ss_keys, NULL, NULL}, // mouse button number to use for strafing
331   {"mouseb_forward",{&mousebforward, NULL},{2, NULL},-1,MAX_MOUSEB,
332    def_int,ss_keys, NULL, NULL}, // mouse button number to use for forward motion
333   {"mouseb_backward",{&mousebbackward, NULL},{-1, NULL},-1,MAX_MOUSEB,
334    def_int,ss_keys, NULL, NULL}, // mouse button number to use for backward motion
335   // Freelook settings
336   {"movement_mouselook",{&movement_mouselook, NULL},{0, NULL},0,1,
337    def_bool,ss_gen, NULL, NULL}, // enables use of mouselook
338   {"movement_mouseinvert",{&movement_mouseinvert, NULL},{0, NULL},0,1,
339    def_bool,ss_gen, NULL, NULL}, // whether to invert the mouse vertical
340   {"movement_maxviewpitch",{&movement_maxviewpitch, NULL},{32, NULL},0,80,
341    def_int,ss_gen, NULL, NULL}, // maximum/minimum pitch when looking up and down
342 
343 // For key bindings, the values stored in the key_* variables       // phares
344 // are the internal Doom Codes. The values stored in the default.cfg
345 // file are the keyboard codes.
346 // CPhipps - now they're the doom codes, so default.cfg can be portable
347 
348   {"Key bindings",{NULL},{0},UL,UL,def_none,ss_none, NULL, NULL},
349   {"key_right",       {&key_right, NULL},          {KEYD_RIGHTARROW, NULL},
350    0,MAX_KEY,def_key,ss_keys, NULL, NULL}, // key to turn right
351   {"key_left",        {&key_left, NULL},           {KEYD_LEFTARROW, NULL} ,
352    0,MAX_KEY,def_key,ss_keys, NULL, NULL}, // key to turn left
353   {"key_up",          {&key_up, NULL},             {KEYD_UPARROW, NULL}   ,
354    0,MAX_KEY,def_key,ss_keys, NULL, NULL}, // key to move forward
355   {"key_down",        {&key_down, NULL},           {KEYD_DOWNARROW, NULL},
356    0,MAX_KEY,def_key,ss_keys, NULL, NULL}, // key to move backward
357   {"key_menu_right",  {&key_menu_right, NULL},     {KEYD_RIGHTARROW, NULL},// phares 3/7/98
358    0,MAX_KEY,def_key,ss_keys, NULL, NULL}, // key to move right in a menu  //     |
359   {"key_menu_left",   {&key_menu_left, NULL},      {KEYD_LEFTARROW, NULL} ,//     V
360    0,MAX_KEY,def_key,ss_keys, NULL, NULL}, // key to move left in a menu
361   {"key_menu_up",     {&key_menu_up, NULL},        {KEYD_UPARROW, NULL}   ,
362    0,MAX_KEY,def_key,ss_keys, NULL, NULL}, // key to move up in a menu
363   {"key_menu_down",   {&key_menu_down, NULL},      {KEYD_DOWNARROW, NULL} ,
364    0,MAX_KEY,def_key,ss_keys, NULL, NULL}, // key to move down in a menu
365   {"key_menu_backspace",{&key_menu_backspace, NULL},{KEYD_BACKSPACE, NULL} ,
366    0,MAX_KEY,def_key,ss_keys, NULL, NULL}, // delete key in a menu
367   {"key_menu_escape", {&key_menu_escape, NULL},    {KEYD_ESCAPE, NULL}    ,
368    0,MAX_KEY,def_key,ss_keys, NULL, NULL}, // key to leave a menu      ,   // phares 3/7/98
369   {"key_menu_enter",  {&key_menu_enter, NULL},     {KEYD_ENTER, NULL}     ,
370    0,MAX_KEY,def_key,ss_keys, NULL, NULL}, // key to select from menu
371   {"key_setup",       {&key_setup, NULL},          {KEYD_HOME, NULL},
372    0,MAX_KEY,def_key,ss_keys, NULL, NULL}, //e6y: key for entering setup menu
373   {"key_strafeleft",  {&key_strafeleft, NULL},     {',', NULL}           ,
374    0,MAX_KEY,def_key,ss_keys, NULL, NULL}, // key to strafe left
375   {"key_straferight", {&key_straferight, NULL},    {'.', NULL}           ,
376    0,MAX_KEY,def_key,ss_keys, NULL, NULL}, // key to strafe right
377 
378   {"key_fire",        {&key_fire, NULL},           {KEYD_RCTRL, NULL}     ,
379    0,MAX_KEY,def_key,ss_keys, NULL, NULL}, // duh
380   {"key_use",         {&key_use, NULL},            {' ', NULL}           ,
381    0,MAX_KEY,def_key,ss_keys, NULL, NULL}, // key to open a door, use a switch
382   {"key_strafe",      {&key_strafe, NULL},         {KEYD_RALT, NULL}      ,
383    0,MAX_KEY,def_key,ss_keys, NULL, NULL}, // key to use with arrows to strafe
384   {"key_speed",       {&key_speed, NULL},          {KEYD_RSHIFT, NULL}    ,
385    0,MAX_KEY,def_key,ss_keys, NULL, NULL}, // key to run
386 
387   {"key_savegame",    {&key_savegame, NULL},       {KEYD_F2, NULL}        ,
388    0,MAX_KEY,def_key,ss_keys, NULL, NULL}, // key to save current game
389   {"key_loadgame",    {&key_loadgame, NULL},       {KEYD_F3, NULL}        ,
390    0,MAX_KEY,def_key,ss_keys, NULL, NULL}, // key to restore from saved games
391   {"key_soundvolume", {&key_soundvolume, NULL},    {KEYD_F4, NULL}        ,
392    0,MAX_KEY,def_key,ss_keys, NULL, NULL}, // key to bring up sound controls
393   {"key_hud",         {&key_hud, NULL},            {KEYD_F5, NULL}        ,
394    0,MAX_KEY,def_key,ss_keys, NULL, NULL}, // key to adjust HUD
395   {"key_quicksave",   {&key_quicksave, NULL},      {KEYD_F6, NULL}        ,
396    0,MAX_KEY,def_key,ss_keys, NULL, NULL}, // key to to quicksave
397   {"key_endgame",     {&key_endgame, NULL},        {KEYD_F7, NULL}        ,
398    0,MAX_KEY,def_key,ss_keys, NULL, NULL}, // key to end the game
399   {"key_messages",    {&key_messages, NULL},       {KEYD_F8, NULL}        ,
400    0,MAX_KEY,def_key,ss_keys, NULL, NULL}, // key to toggle message enable
401   {"key_quickload",   {&key_quickload, NULL},      {KEYD_F9, NULL}        ,
402    0,MAX_KEY,def_key,ss_keys, NULL, NULL}, // key to load from quicksave
403   {"key_quit",        {&key_quit, NULL},           {KEYD_F10, NULL}       ,
404    0,MAX_KEY,def_key,ss_keys, NULL, NULL}, // key to quit game
405   {"key_gamma",       {&key_gamma, NULL},          {KEYD_F11, NULL}       ,
406    0,MAX_KEY,def_key,ss_keys, NULL, NULL}, // key to adjust gamma correction
407   {"key_spy",         {&key_spy, NULL},            {KEYD_F12, NULL}       ,
408    0,MAX_KEY,def_key,ss_keys, NULL, NULL}, // key to view from another coop player's view
409   {"key_pause",       {&key_pause, NULL},          {KEYD_PAUSE, NULL}     ,
410    0,MAX_KEY,def_key,ss_keys, NULL, NULL}, // key to pause the game
411   {"key_autorun",     {&key_autorun, NULL},        {KEYD_CAPSLOCK, NULL}  ,
412    0,MAX_KEY,def_key,ss_keys, NULL, NULL}, // key to toggle always run mode
413   {"key_chat",        {&key_chat, NULL},           {'t', NULL}            ,
414    0,MAX_KEY,def_key,ss_keys, NULL, NULL}, // key to enter a chat message
415   {"key_backspace",   {&key_backspace, NULL},      {KEYD_BACKSPACE, NULL} ,
416    0,MAX_KEY,def_key,ss_keys, NULL, NULL}, // backspace key
417   {"key_enter",       {&key_enter, NULL},          {KEYD_ENTER, NULL}     ,
418    0,MAX_KEY,def_key,ss_keys, NULL, NULL}, // key to select from menu or see last message
419   {"key_map",         {&key_map, NULL},            {KEYD_TAB, NULL}       ,
420    0,MAX_KEY,def_key,ss_keys, NULL, NULL}, // key to toggle automap display
421   {"key_map_right",   {&key_map_right, NULL},      {KEYD_RIGHTARROW, NULL},// phares 3/7/98
422    0,MAX_KEY,def_key,ss_keys, NULL, NULL}, // key to shift automap right   //     |
423   {"key_map_left",    {&key_map_left, NULL},       {KEYD_LEFTARROW, NULL} ,//     V
424    0,MAX_KEY,def_key,ss_keys, NULL, NULL}, // key to shift automap left
425   {"key_map_up",      {&key_map_up, NULL},         {KEYD_UPARROW, NULL}   ,
426    0,MAX_KEY,def_key,ss_keys, NULL, NULL}, // key to shift automap up
427   {"key_map_down",    {&key_map_down, NULL},       {KEYD_DOWNARROW, NULL} ,
428    0,MAX_KEY,def_key,ss_keys, NULL, NULL}, // key to shift automap down
429   {"key_map_zoomin",  {&key_map_zoomin, NULL},      {'=', NULL}           ,
430    0,MAX_KEY,def_key,ss_keys, NULL, NULL}, // key to enlarge automap
431   {"key_map_zoomout", {&key_map_zoomout, NULL},     {'-', NULL}           ,
432    0,MAX_KEY,def_key,ss_keys, NULL, NULL}, // key to reduce automap
433   {"key_map_gobig",   {&key_map_gobig, NULL},       {'0', NULL}           ,
434    0,MAX_KEY,def_key,ss_keys, NULL, NULL},  // key to get max zoom for automap
435   {"key_map_follow",  {&key_map_follow, NULL},      {'f', NULL}           ,
436    0,MAX_KEY,def_key,ss_keys, NULL, NULL}, // key to toggle follow mode
437   {"key_map_mark",    {&key_map_mark, NULL},        {'m', NULL}           ,
438    0,MAX_KEY,def_key,ss_keys, NULL, NULL}, // key to drop a marker on automap
439   {"key_map_clear",   {&key_map_clear, NULL},       {'c', NULL}           ,
440    0,MAX_KEY,def_key,ss_keys, NULL, NULL}, // key to clear all markers on automap
441   {"key_map_grid",    {&key_map_grid, NULL},        {'g', NULL}           ,
442    0,MAX_KEY,def_key,ss_keys, NULL, NULL}, // key to toggle grid display over automap
443   {"key_map_rotate",  {&key_map_rotate, NULL},      {'r', NULL}           ,
444    0,MAX_KEY,def_key,ss_keys, NULL, NULL}, // key to toggle rotating the automap to match the player's orientation
445   {"key_map_overlay", {&key_map_overlay, NULL},     {'o', NULL}           ,
446    0,MAX_KEY,def_key,ss_keys, NULL, NULL}, // key to toggle overlaying the automap on the rendered display
447   {"key_reverse",     {&key_reverse, NULL},         {'/', NULL}           ,
448    0,MAX_KEY,def_key,ss_keys, NULL, NULL}, // key to spin 180 instantly
449   {"key_zoomin",      {&key_zoomin, NULL},          {'=', NULL}           ,
450    0,MAX_KEY,def_key,ss_keys, NULL, NULL}, // key to enlarge display
451   {"key_zoomout",     {&key_zoomout, NULL},         {'-', NULL}           ,
452    0,MAX_KEY,def_key,ss_keys, NULL, NULL}, // key to reduce display
453   {"key_chatplayer1", {&destination_keys[0], NULL}, {'g', NULL}            ,
454    0,MAX_KEY,def_key,ss_keys, NULL, NULL}, // key to chat with player 1
455   // killough 11/98: fix 'i'/'b' reversal
456   {"key_chatplayer2", {&destination_keys[1], NULL}, {'i', NULL}            ,
457    0,MAX_KEY,def_key,ss_keys, NULL, NULL}, // key to chat with player 2
458   {"key_chatplayer3", {&destination_keys[2], NULL}, {'b', NULL}            ,
459    0,MAX_KEY,def_key,ss_keys, NULL, NULL}, // key to chat with player 3
460   {"key_chatplayer4", {&destination_keys[3], NULL}, {'r', NULL}            ,
461    0,MAX_KEY,def_key,ss_keys, NULL, NULL}, // key to chat with player 4
462   {"key_weapontoggle",{&key_weapontoggle, NULL},    {'0', NULL}            ,
463    0,MAX_KEY,def_key,ss_keys, NULL, NULL}, // key to toggle between two most preferred weapons with ammo
464   {"key_weaponcycleup",{&key_weaponcycleup, NULL},     {'m', NULL}         ,
465 	  0,MAX_KEY,def_key,ss_keys, NULL, NULL}, // key to switch to the next weapon
466   {"key_weaponcycledown",{&key_weaponcycledown, NULL}, {'n', NULL}         ,
467 	  0,MAX_KEY,def_key,ss_keys, NULL, NULL}, // key to switch to the previous weapon
468   {"key_weapon1",     {&key_weapon1, NULL},         {'1', NULL}            ,
469    0,MAX_KEY,def_key,ss_keys, NULL, NULL}, // key to switch to weapon 1 (fist/chainsaw)
470   {"key_weapon2",     {&key_weapon2, NULL},         {'2', NULL}            ,
471    0,MAX_KEY,def_key,ss_keys, NULL, NULL}, // key to switch to weapon 2 (pistol)
472   {"key_weapon3",     {&key_weapon3, NULL},         {'3', NULL}            ,
473    0,MAX_KEY,def_key,ss_keys, NULL, NULL}, // key to switch to weapon 3 (supershotgun/shotgun)
474   {"key_weapon4",     {&key_weapon4, NULL},         {'4', NULL}            ,
475    0,MAX_KEY,def_key,ss_keys, NULL, NULL}, // key to switch to weapon 4 (chaingun)
476   {"key_weapon5",     {&key_weapon5, NULL},         {'5', NULL}            ,
477    0,MAX_KEY,def_key,ss_keys, NULL, NULL}, // key to switch to weapon 5 (rocket launcher)
478   {"key_weapon6",     {&key_weapon6, NULL},         {'6', NULL}            ,
479    0,MAX_KEY,def_key,ss_keys, NULL, NULL}, // key to switch to weapon 6 (plasma rifle)
480   {"key_weapon7",     {&key_weapon7, NULL},         {'7', NULL}            ,
481    0,MAX_KEY,def_key,ss_keys, NULL, NULL}, // key to switch to weapon 7 (bfg9000)         //    ^
482   {"key_weapon8",     {&key_weapon8, NULL},         {'8', NULL}            ,
483    0,MAX_KEY,def_key,ss_keys, NULL, NULL}, // key to switch to weapon 8 (chainsaw)        //    |
484   {"key_weapon9",     {&key_weapon9, NULL},         {'9', NULL}            ,
485    0,MAX_KEY,def_key,ss_keys, NULL, NULL}, // key to switch to weapon 9 (supershotgun)    // phares
486 
487   // killough 2/22/98: screenshot key
488   {"key_screenshot",  {&key_screenshot, NULL},      {'*', NULL}            ,
489    0,MAX_KEY,def_key,ss_keys, NULL, NULL}, // key to take a screenshot
490   {"Chat macros",{NULL},{0},UL,UL,def_none,ss_none, NULL, NULL},
491   {"chatmacro0", {0,&chat_macros[0]}, {0,HUSTR_CHATMACRO0},UL,UL,
492    def_str,ss_chat, NULL, NULL}, // chat string associated with 0 key
493   {"chatmacro1", {0,&chat_macros[1]}, {0,HUSTR_CHATMACRO1},UL,UL,
494    def_str,ss_chat, NULL, NULL}, // chat string associated with 1 key
495   {"chatmacro2", {0,&chat_macros[2]}, {0,HUSTR_CHATMACRO2},UL,UL,
496    def_str,ss_chat, NULL, NULL}, // chat string associated with 2 key
497   {"chatmacro3", {0,&chat_macros[3]}, {0,HUSTR_CHATMACRO3},UL,UL,
498    def_str,ss_chat, NULL, NULL}, // chat string associated with 3 key
499   {"chatmacro4", {0,&chat_macros[4]}, {0,HUSTR_CHATMACRO4},UL,UL,
500    def_str,ss_chat, NULL, NULL}, // chat string associated with 4 key
501   {"chatmacro5", {0,&chat_macros[5]}, {0,HUSTR_CHATMACRO5},UL,UL,
502    def_str,ss_chat, NULL, NULL}, // chat string associated with 5 key
503   {"chatmacro6", {0,&chat_macros[6]}, {0,HUSTR_CHATMACRO6},UL,UL,
504    def_str,ss_chat, NULL, NULL}, // chat string associated with 6 key
505   {"chatmacro7", {0,&chat_macros[7]}, {0,HUSTR_CHATMACRO7},UL,UL,
506    def_str,ss_chat, NULL, NULL}, // chat string associated with 7 key
507   {"chatmacro8", {0,&chat_macros[8]}, {0,HUSTR_CHATMACRO8},UL,UL,
508    def_str,ss_chat, NULL, NULL}, // chat string associated with 8 key
509   {"chatmacro9", {0,&chat_macros[9]}, {0,HUSTR_CHATMACRO9},UL,UL,
510    def_str,ss_chat, NULL, NULL}, // chat string associated with 9 key
511 
512   {"Automap settings",{NULL},{0},UL,UL,def_none,ss_none, NULL, NULL},
513   //jff 1/7/98 defaults for automap colors
514   //jff 4/3/98 remove -1 in lower range, 0 now disables new map features
515   {"mapcolor_back", {&mapcolor_back, NULL}, {247, NULL},0,255,  // black //jff 4/6/98 new black
516    def_colour,ss_auto, NULL, NULL}, // color used as background for automap
517   {"mapcolor_grid", {&mapcolor_grid, NULL}, {104, NULL},0,255,  // dk gray
518    def_colour,ss_auto, NULL, NULL}, // color used for automap grid lines
519   {"mapcolor_wall", {&mapcolor_wall, NULL}, {23, NULL},0,255,   // red-brown
520    def_colour,ss_auto, NULL, NULL}, // color used for one side walls on automap
521   {"mapcolor_fchg", {&mapcolor_fchg, NULL}, {55, NULL},0,255,   // lt brown
522    def_colour,ss_auto, NULL, NULL}, // color used for lines floor height changes across
523   {"mapcolor_cchg", {&mapcolor_cchg, NULL}, {215, NULL},0,255,  // orange
524    def_colour,ss_auto, NULL, NULL}, // color used for lines ceiling height changes across
525   {"mapcolor_clsd", {&mapcolor_clsd, NULL}, {208, NULL},0,255,  // white
526    def_colour,ss_auto, NULL, NULL}, // color used for lines denoting closed doors, objects
527   {"mapcolor_rkey", {&mapcolor_rkey, NULL}, {175, NULL},0,255,  // red
528    def_colour,ss_auto, NULL, NULL}, // color used for red key sprites
529   {"mapcolor_bkey", {&mapcolor_bkey, NULL}, {204, NULL},0,255,  // blue
530    def_colour,ss_auto, NULL, NULL}, // color used for blue key sprites
531   {"mapcolor_ykey", {&mapcolor_ykey, NULL}, {231, NULL},0,255,  // yellow
532    def_colour,ss_auto, NULL, NULL}, // color used for yellow key sprites
533   {"mapcolor_rdor", {&mapcolor_rdor, NULL}, {175, NULL},0,255,  // red
534    def_colour,ss_auto, NULL, NULL}, // color used for closed red doors
535   {"mapcolor_bdor", {&mapcolor_bdor, NULL}, {204, NULL},0,255,  // blue
536    def_colour,ss_auto, NULL, NULL}, // color used for closed blue doors
537   {"mapcolor_ydor", {&mapcolor_ydor, NULL}, {231, NULL},0,255,  // yellow
538    def_colour,ss_auto, NULL, NULL}, // color used for closed yellow doors
539   {"mapcolor_tele", {&mapcolor_tele, NULL}, {119, NULL},0,255,  // dk green
540    def_colour,ss_auto, NULL, NULL}, // color used for teleporter lines
541   {"mapcolor_secr", {&mapcolor_secr, NULL}, {252, NULL},0,255,  // purple
542    def_colour,ss_auto, NULL, NULL}, // color used for lines around secret sectors
543   {"mapcolor_exit", {&mapcolor_exit, NULL}, {0, NULL},0,255,    // none
544    def_colour,ss_auto, NULL, NULL}, // color used for exit lines
545   {"mapcolor_unsn", {&mapcolor_unsn, NULL}, {104, NULL},0,255,  // dk gray
546    def_colour,ss_auto, NULL, NULL}, // color used for lines not seen without computer map
547   {"mapcolor_flat", {&mapcolor_flat, NULL}, {88, NULL},0,255,   // lt gray
548    def_colour,ss_auto, NULL, NULL}, // color used for lines with no height changes
549   {"mapcolor_sprt", {&mapcolor_sprt, NULL}, {112, NULL},0,255,  // green
550    def_colour,ss_auto, NULL, NULL}, // color used as things
551   {"mapcolor_item", {&mapcolor_item, NULL}, {231, NULL},0,255,  // yellow
552    def_colour,ss_auto, NULL, NULL}, // color used for counted items
553   {"mapcolor_hair", {&mapcolor_hair, NULL}, {208, NULL},0,255,  // white
554    def_colour,ss_auto, NULL, NULL}, // color used for dot crosshair denoting center of map
555   {"mapcolor_sngl", {&mapcolor_sngl, NULL}, {208, NULL},0,255,  // white
556    def_colour,ss_auto, NULL, NULL}, // color used for the single player arrow
557   {"mapcolor_me",   {&mapcolor_me, NULL}, {112, NULL},0,255, // green
558    def_colour,ss_auto, NULL, NULL}, // your (player) colour
559   {"mapcolor_enemy",   {&mapcolor_enemy, NULL}, {177, NULL},0,255,
560    def_colour,ss_auto, NULL, NULL},
561   {"mapcolor_frnd",   {&mapcolor_frnd, NULL}, {112, NULL},0,255,
562    def_colour,ss_auto, NULL, NULL},
563   //jff 3/9/98 add option to not show secrets til after found
564   {"map_secret_after", {&map_secret_after,  NULL}, {0, NULL},0,1, // show secret after gotten
565    def_bool,ss_auto, NULL, NULL}, // prevents showing secret sectors till after entered
566   {"map_point_coord", {&map_point_coordinates, NULL}, {0, NULL},0,1,
567    def_bool,ss_auto, NULL, NULL},
568   //jff 1/7/98 end additions for automap
569   {"automapmode", {(int*)&automapmode, NULL}, {0, NULL}, 0, 31, // CPhipps - remember automap mode
570    def_hex,ss_none, NULL, NULL}, // automap mode
571 
572   {"Heads-up display settings",{NULL},{0},UL,UL,def_none,ss_none, NULL, NULL},
573   //jff 2/16/98 defaults for color ranges in hud and status
574   {"hudcolor_titl", {&hudcolor_titl, NULL}, {5, NULL},0,9,  // gold range
575    def_int,ss_auto, NULL, NULL}, // color range used for automap level title
576   {"hudcolor_xyco", {&hudcolor_xyco, NULL}, {3, NULL},0,9,  // green range
577    def_int,ss_auto, NULL, NULL}, // color range used for automap coordinates
578   {"hudcolor_mesg", {&hudcolor_mesg, NULL}, {6, NULL},0,9,  // red range
579    def_int,ss_mess, NULL, NULL}, // color range used for messages during play
580   {"hudcolor_chat", {&hudcolor_chat, NULL}, {5, NULL},0,9,  // gold range
581    def_int,ss_mess, NULL, NULL}, // color range used for chat messages and entry
582   {"hudcolor_list", {&hudcolor_list, NULL}, {5, NULL},0,9,  // gold range  //jff 2/26/98
583    def_int,ss_mess, NULL, NULL}, // color range used for message review
584   {"hud_msg_lines", {&hud_msg_lines, NULL}, {1, NULL},1,16,  // 1 line scrolling window
585    def_int,ss_mess, NULL, NULL}, // number of messages in review display (1=disable)
586   {"hud_list_bgon", {&hud_list_bgon, NULL}, {0, NULL},0,1,  // solid window bg ena //jff 2/26/98
587    def_bool,ss_mess, NULL, NULL}, // enables background window behind message review
588 
589   {"health_red",    {&health_red, NULL}   , {25, NULL},0,200, // below is red
590    def_int,ss_stat, NULL, NULL}, // amount of health for red to yellow transition
591   {"health_yellow", {&health_yellow, NULL}, {50, NULL},0,200, // below is yellow
592    def_int,ss_stat, NULL, NULL}, // amount of health for yellow to green transition
593   {"health_green",  {&health_green, NULL} , {100, NULL},0,200,// below is green, above blue
594    def_int,ss_stat, NULL, NULL}, // amount of health for green to blue transition
595   {"armor_red",     {&armor_red, NULL}    , {25, NULL},0,200, // below is red
596    def_int,ss_stat, NULL, NULL}, // amount of armor for red to yellow transition
597   {"armor_yellow",  {&armor_yellow, NULL} , {50, NULL},0,200, // below is yellow
598    def_int,ss_stat, NULL, NULL}, // amount of armor for yellow to green transition
599   {"armor_green",   {&armor_green, NULL}  , {100, NULL},0,200,// below is green, above blue
600    def_int,ss_stat, NULL, NULL}, // amount of armor for green to blue transition
601   {"ammo_red",      {&ammo_red, NULL}     , {25, NULL},0,100, // below 25% is red
602    def_int,ss_stat, NULL, NULL}, // percent of ammo for red to yellow transition
603   {"ammo_yellow",   {&ammo_yellow, NULL}  , {50, NULL},0,100, // below 50% is yellow, above green
604    def_int,ss_stat, NULL, NULL}, // percent of ammo for yellow to green transition
605 
606   // HUD and status feature controls
607   {"hud_mode", {(int*)&hud_mode, NULL},  {0, NULL},0,2, // whether & how hud is displayed
608    def_int,ss_none, NULL, NULL}, // enables and selects display mode of HUD
609   {"hud_showstats", {&hud_showstats, NULL},  {1, NULL},0,1, // show secrets/items/kills HUD line
610    def_bool,ss_stat, NULL, NULL}, // enables display of kills/items/secrets on HUD
611   {"hud_showkeys", {&hud_showkeys, NULL},  {1, NULL},0,1, // show keys HUD line
612    def_bool,ss_stat, NULL, NULL}, // enables the display of keys on HUD
613   {"hud_showweapons", {&hud_showweapons, NULL},  {1, NULL},0,1, // show weapons HUD line
614    def_bool,ss_stat, NULL, NULL}, // enables the display of weapons on HUD
615 
616   {"Weapon preferences",{NULL},{0},UL,UL,def_none,ss_none, NULL, NULL},
617   // killough 2/8/98: weapon preferences set by user:
618   {"weapon_choice_1", {&weapon_preferences[0][0], NULL}, {6, NULL}, 0,9,
619    def_int,ss_weap, NULL, NULL}, // first choice for weapon (best)
620   {"weapon_choice_2", {&weapon_preferences[0][1], NULL}, {9, NULL}, 0,9,
621    def_int,ss_weap, NULL, NULL}, // second choice for weapon
622   {"weapon_choice_3", {&weapon_preferences[0][2], NULL}, {4, NULL}, 0,9,
623    def_int,ss_weap, NULL, NULL}, // third choice for weapon
624   {"weapon_choice_4", {&weapon_preferences[0][3], NULL}, {3, NULL}, 0,9,
625    def_int,ss_weap, NULL, NULL}, // fourth choice for weapon
626   {"weapon_choice_5", {&weapon_preferences[0][4], NULL}, {2, NULL}, 0,9,
627    def_int,ss_weap, NULL, NULL}, // fifth choice for weapon
628   {"weapon_choice_6", {&weapon_preferences[0][5], NULL}, {8, NULL}, 0,9,
629    def_int,ss_weap, NULL, NULL}, // sixth choice for weapon
630   {"weapon_choice_7", {&weapon_preferences[0][6], NULL}, {5, NULL}, 0,9,
631    def_int,ss_weap, NULL, NULL}, // seventh choice for weapon
632   {"weapon_choice_8", {&weapon_preferences[0][7], NULL}, {7, NULL}, 0,9,
633    def_int,ss_weap, NULL, NULL}, // eighth choice for weapon
634   {"weapon_choice_9", {&weapon_preferences[0][8], NULL}, {1, NULL}, 0,9,
635    def_int,ss_weap, NULL, NULL}, // ninth choice for weapon (worst)
636 
637 // cournia - support for arbitrary music file (defaults are mp3)
638 
639 	{"Music", {NULL},{0},UL,UL,def_none,ss_none, NULL, NULL},
640 
641 	//Fixed support for Doom, Doom 2, and Doom Final
642 	//You must use a seperate folder for each wad to be able to have all Dooms use their correct music
643 	//In ~/RetroPie/roms/ports/ have a folder for each game, put the wad of each game in their related folder
644 	//Then put all the music in their folder
645 	//Also don't forget to include the prboom.wad into each game folder
646 
647 	//An example folder structure would be like so
648 	// roms
649 	// +ports
650 	// ++doom
651 	// +++doom.wad
652 	// +++prboom.wad
653 	// +++doomusic.mp3
654 	// ++doom2
655 	// +++doom2.wad
656 	// +++prboom.wad
657 	// +++doom2music.mp3
658 
659 	//An example launcher script in ~/RetroPie/roms/ports/*.sh would be like this
660 	// #!/bin/bash
661 	// /opt/retropie/supplementary/runcommand/runcommand.sh 0 "/opt/retropie/emulators/retroarch/bin/retroarch -L /opt/retropie/libretrocores/lr-prboom/prboom_libretro.so --config /opt/retropie/configs/doom/retroarch.cfg /home/pi/RetroPie/roms/ports/doom2/doom2.wad" "lr-prboom"
662 	//You must change the folder name and wad name for each game you want and save it as a .sh file in ~/RetroPie/roms/ports/
663 
664 	//Although all 3 games (Doom 2, Plutonia, TNT) use the same file names, the files are not the same
665 
666 	//Begin Doom 1
667 	{"mus_bunny", {0,&S_music_files[mus_bunny]}, {0,"bunny.mp3"},UL,UL,
668    def_str,ss_none, NULL, NULL},
669 	{"mus_e1m1", {0,&S_music_files[mus_e1m1]}, {0,"e1m1.mp3"},UL,UL,
670    def_str,ss_none, NULL, NULL},
671 	{"mus_e1m2", {0,&S_music_files[mus_e1m2]}, {0,"e1m2.mp3"},UL,UL,
672    def_str,ss_none, NULL, NULL},
673 	{"mus_e1m3", {0,&S_music_files[mus_e1m3]}, {0,"e1m3.mp3"},UL,UL,
674    def_str,ss_none, NULL, NULL},
675 	{"mus_e1m4", {0,&S_music_files[mus_e1m4]}, {0,"e1m4.mp3"},UL,UL,
676    def_str,ss_none, NULL, NULL},
677 	{"mus_e1m5", {0,&S_music_files[mus_e1m5]}, {0,"e1m5.mp3"},UL,UL,
678    def_str,ss_none, NULL, NULL},
679 	{"mus_e1m6", {0,&S_music_files[mus_e1m6]}, {0,"e1m6.mp3"},UL,UL,
680    def_str,ss_none, NULL, NULL},
681 	{"mus_e1m7", {0,&S_music_files[mus_e1m7]}, {0,"e1m7.mp3"},UL,UL,
682    def_str,ss_none, NULL, NULL},
683 	{"mus_e1m8", {0,&S_music_files[mus_e1m8]}, {0,"e1m8.mp3"},UL,UL,
684    def_str,ss_none, NULL, NULL},
685 	{"mus_e1m9", {0,&S_music_files[mus_e1m9]}, {0,"e1m9.mp3"},UL,UL,
686    def_str,ss_none, NULL, NULL},
687 	{"mus_e2m1", {0,&S_music_files[mus_e2m1]}, {0,"e2m1.mp3"},UL,UL,
688    def_str,ss_none, NULL, NULL},
689 	{"mus_e2m2", {0,&S_music_files[mus_e2m2]}, {0,"e2m2.mp3"},UL,UL,
690    def_str,ss_none, NULL, NULL},
691 	{"mus_e2m3", {0,&S_music_files[mus_e2m3]}, {0,"e2m3.mp3"},UL,UL,
692    def_str,ss_none, NULL, NULL},
693 	{"mus_e2m4", {0,&S_music_files[mus_e2m4]}, {0,"e2m4.mp3"},UL,UL,
694    def_str,ss_none, NULL, NULL},
695 	{"mus_e2m5", {0,&S_music_files[mus_e2m5]}, {0,"e2m5.mp3"},UL,UL,
696    def_str,ss_none, NULL, NULL},
697 	{"mus_e2m6", {0,&S_music_files[mus_e2m6]}, {0,"e2m6.mp3"},UL,UL,
698    def_str,ss_none, NULL, NULL},
699 	{"mus_e2m7", {0,&S_music_files[mus_e2m7]}, {0,"e2m7.mp3"},UL,UL,
700    def_str,ss_none, NULL, NULL},
701 	{"mus_e2m8", {0,&S_music_files[mus_e2m8]}, {0,"e2m8.mp3"},UL,UL,
702    def_str,ss_none, NULL, NULL},
703 	{"mus_e2m9", {0,&S_music_files[mus_e2m9]}, {0,"e2m9.mp3"},UL,UL,
704    def_str,ss_none, NULL, NULL},
705 	{"mus_e3m1", {0,&S_music_files[mus_e3m1]}, {0,"e3m1.mp3"},UL,UL,
706    def_str,ss_none, NULL, NULL},
707 	{"mus_e3m2", {0,&S_music_files[mus_e3m2]}, {0,"e3m2.mp3"},UL,UL,
708    def_str,ss_none, NULL, NULL},
709 	{"mus_e3m3", {0,&S_music_files[mus_e3m3]}, {0,"e3m3.mp3"},UL,UL,
710    def_str,ss_none, NULL, NULL},
711 	{"mus_e3m4", {0,&S_music_files[mus_e3m4]}, {0,"e3m4.mp3"},UL,UL,
712    def_str,ss_none, NULL, NULL},
713 	{"mus_e3m5", {0,&S_music_files[mus_e3m5]}, {0,"e3m5.mp3"},UL,UL,
714    def_str,ss_none, NULL, NULL},
715 	{"mus_e3m6", {0,&S_music_files[mus_e3m6]}, {0,"e3m6.mp3"},UL,UL,
716    def_str,ss_none, NULL, NULL},
717 	{"mus_e3m7", {0,&S_music_files[mus_e3m7]}, {0,"e3m7.mp3"},UL,UL,
718    def_str,ss_none, NULL, NULL},
719 	{"mus_e3m8", {0,&S_music_files[mus_e3m8]}, {0,"e3m8.mp3"},UL,UL,
720    def_str,ss_none, NULL, NULL},
721 	{"mus_e3m9", {0,&S_music_files[mus_e3m9]}, {0,"e3m9.mp3"},UL,UL,
722    def_str,ss_none, NULL, NULL},
723 	{"mus_e4m1", {0,&S_music_files[mus_e4m1]}, {0,"e3m4.mp3"},UL,UL,
724    def_str,ss_none, NULL, NULL},
725 	{"mus_e4m2", {0,&S_music_files[mus_e4m2]}, {0,"e3m2.mp3"},UL,UL,
726    def_str,ss_none, NULL, NULL},
727 	{"mus_e4m3", {0,&S_music_files[mus_e4m3]}, {0,"e3m3.mp3"},UL,UL,
728    def_str,ss_none, NULL, NULL},
729 	{"mus_e4m4", {0,&S_music_files[mus_e4m4]}, {0,"e1m5.mp3"},UL,UL,
730    def_str,ss_none, NULL, NULL},
731 	{"mus_e4m5", {0,&S_music_files[mus_e4m5]}, {0,"e2m7.mp3"},UL,UL,
732    def_str,ss_none, NULL, NULL},
733 	{"mus_e4m6", {0,&S_music_files[mus_e4m6]}, {0,"e2m4.mp3"},UL,UL,
734    def_str,ss_none, NULL, NULL},
735 	{"mus_e4m7", {0,&S_music_files[mus_e4m7]}, {0,"e2m6.mp3"},UL,UL,
736    def_str,ss_none, NULL, NULL},
737 	{"mus_e4m8", {0,&S_music_files[mus_e4m8]}, {0,"e2m5.mp3"},UL,UL,
738    def_str,ss_none, NULL, NULL},
739 	{"mus_e4m9", {0,&S_music_files[mus_e4m9]}, {0,"e1m9.mp3"},UL,UL,
740    def_str,ss_none, NULL, NULL},
741 	{"mus_e5m1", {0,&S_music_files[mus_e5m1]}, {0,"e5m1.mp3"},UL,UL,
742    def_str,ss_none, NULL, NULL},
743 	{"mus_e5m2", {0,&S_music_files[mus_e5m2]}, {0,"e5m2.mp3"},UL,UL,
744    def_str,ss_none, NULL, NULL},
745 	{"mus_e5m3", {0,&S_music_files[mus_e5m3]}, {0,"e5m3.mp3"},UL,UL,
746    def_str,ss_none, NULL, NULL},
747 	{"mus_e5m4", {0,&S_music_files[mus_e5m4]}, {0,"e5m4.mp3"},UL,UL,
748    def_str,ss_none, NULL, NULL},
749 	{"mus_e5m5", {0,&S_music_files[mus_e5m5]}, {0,"e5m5.mp3"},UL,UL,
750    def_str,ss_none, NULL, NULL},
751 	{"mus_e5m6", {0,&S_music_files[mus_e5m6]}, {0,"e5m6.mp3"},UL,UL,
752    def_str,ss_none, NULL, NULL},
753 	{"mus_e5m7", {0,&S_music_files[mus_e5m7]}, {0,"e5m7.mp3"},UL,UL,
754    def_str,ss_none, NULL, NULL},
755 	{"mus_e5m8", {0,&S_music_files[mus_e5m8]}, {0,"e5m8.mp3"},UL,UL,
756    def_str,ss_none, NULL, NULL},
757 	{"mus_e5m9", {0,&S_music_files[mus_e5m9]}, {0,"e5m9.mp3"},UL,UL,
758    def_str,ss_none, NULL, NULL},
759 	{"mus_inter", {0,&S_music_files[mus_inter]}, {0,"inter.mp3"},UL,UL,
760    def_str,ss_none, NULL, NULL},
761 	{"mus_introa", {0,&S_music_files[mus_introa]}, {0,"intro.mp3"},UL,UL,
762    def_str,ss_none, NULL, NULL},
763 	{"mus_intro", {0,&S_music_files[mus_intro]}, {0,"intro.mp3"},UL,UL,
764    def_str,ss_none, NULL, NULL},
765 	{"mus_victor", {0,&S_music_files[mus_victor]}, {0,"victor.mp3"},UL,UL,
766    def_str,ss_none, NULL, NULL},
767 	//End Doom 1
768 	//Begin Doom 2 & Final Doom
769 	{"mus_adrian", {0,&S_music_files[mus_adrian]}, {0,"adrian.mp3"},UL,UL,
770    def_str,ss_none, NULL, NULL},
771 	{"mus_ampie", {0,&S_music_files[mus_ampie]}, {0,"ampie.mp3"},UL,UL,
772    def_str,ss_none, NULL, NULL},
773 	{"mus_betwee", {0,&S_music_files[mus_betwee]}, {0,"betwee.mp3"},UL,UL,
774    def_str,ss_none, NULL, NULL},
775 	{"mus_count2", {0,&S_music_files[mus_count2]}, {0,"count2.mp3"},UL,UL,
776    def_str,ss_none, NULL, NULL},
777 	{"mus_countd", {0,&S_music_files[mus_countd]}, {0,"countd.mp3"},UL,UL,
778    def_str,ss_none, NULL, NULL},
779 	{"mus_ddtbl2", {0,&S_music_files[mus_ddtbl2]}, {0,"ddtbl2.mp3"},UL,UL,
780    def_str,ss_none, NULL, NULL},
781 	{"mus_ddtbl3", {0,&S_music_files[mus_ddtbl3]}, {0,"ddtbl3.mp3"},UL,UL,
782    def_str,ss_none, NULL, NULL},
783 	{"mus_ddtblu", {0,&S_music_files[mus_ddtblu]}, {0,"ddtblu.mp3"},UL,UL,
784    def_str,ss_none, NULL, NULL},
785 	{"mus_dead2", {0,&S_music_files[mus_dead2]}, {0,"dead2.mp3"},UL,UL,
786    def_str,ss_none, NULL, NULL},
787 	{"mus_dead", {0,&S_music_files[mus_dead]}, {0,"dead.mp3"},UL,UL,
788    def_str,ss_none, NULL, NULL},
789 	{"mus_dm2int", {0,&S_music_files[mus_dm2int]}, {0,"dm2int.mp3"},UL,UL,
790    def_str,ss_none, NULL, NULL},
791 	{"mus_dm2ttl", {0,&S_music_files[mus_dm2ttl]}, {0,"dm2ttl.mp3"},UL,UL,
792    def_str,ss_none, NULL, NULL},
793 	{"mus_doom2", {0,&S_music_files[mus_doom2]}, {0,"doom2.mp3"},UL,UL,
794    def_str,ss_none, NULL, NULL},
795 	{"mus_doom", {0,&S_music_files[mus_doom]}, {0,"doom.mp3"},UL,UL,
796    def_str,ss_none, NULL, NULL},
797 	{"mus_evil", {0,&S_music_files[mus_evil]}, {0,"evil.mp3"},UL,UL,
798    def_str,ss_none, NULL, NULL},
799 	{"mus_in_cit", {0,&S_music_files[mus_in_cit]}, {0,"in_cit.mp3"},UL,UL,
800    def_str,ss_none, NULL, NULL},
801 	{"mus_messag", {0,&S_music_files[mus_messag]}, {0,"messag.mp3"},UL,UL,
802    def_str,ss_none, NULL, NULL},
803 	{"mus_messg2", {0,&S_music_files[mus_messg2]}, {0,"messg2.mp3"},UL,UL,
804    def_str,ss_none, NULL, NULL},
805 	{"mus_openin", {0,&S_music_files[mus_openin]}, {0,"openin.mp3"},UL,UL,
806    def_str,ss_none, NULL, NULL},
807 	{"mus_read_m", {0,&S_music_files[mus_read_m]}, {0,"read_m.mp3"},UL,UL,
808    def_str,ss_none, NULL, NULL},
809 	{"mus_romer2", {0,&S_music_files[mus_romer2]}, {0,"romer2.mp3"},UL,UL,
810    def_str,ss_none, NULL, NULL},
811 	{"mus_romero", {0,&S_music_files[mus_romero]}, {0,"romero.mp3"},UL,UL,
812    def_str,ss_none, NULL, NULL},
813 	{"mus_runni2", {0,&S_music_files[mus_runni2]}, {0,"runni2.mp3"},UL,UL,
814    def_str,ss_none, NULL, NULL},
815 	{"mus_runnin", {0,&S_music_files[mus_runnin]}, {0,"runnin.mp3"},UL,UL,
816    def_str,ss_none, NULL, NULL},
817 	{"mus_shawn2", {0,&S_music_files[mus_shawn2]}, {0,"shawn2.mp3"},UL,UL,
818    def_str,ss_none, NULL, NULL},
819 	{"mus_shawn3", {0,&S_music_files[mus_shawn3]}, {0,"shawn3.mp3"},UL,UL,
820    def_str,ss_none, NULL, NULL},
821 	{"mus_shawn", {0,&S_music_files[mus_shawn]}, {0,"shawn.mp3"},UL,UL,
822    def_str,ss_none, NULL, NULL},
823 	{"mus_stalks", {0,&S_music_files[mus_stalks]}, {0,"stalks.mp3"},UL,UL,
824    def_str,ss_none, NULL, NULL},
825 	{"mus_stlks2", {0,&S_music_files[mus_stlks2]}, {0,"stlks2.mp3"},UL,UL,
826    def_str,ss_none, NULL, NULL},
827 	{"mus_stlks3", {0,&S_music_files[mus_stlks3]}, {0,"stlks3.mp3"},UL,UL,
828    def_str,ss_none, NULL, NULL},
829 	{"mus_tense", {0,&S_music_files[mus_tense]}, {0,"tense.mp3"},UL,UL,
830    def_str,ss_none, NULL, NULL},
831 	{"mus_theda2", {0,&S_music_files[mus_theda2]}, {0,"theda2.mp3"},UL,UL,
832    def_str,ss_none, NULL, NULL},
833 	{"mus_theda3", {0,&S_music_files[mus_theda3]}, {0,"theda3.mp3"},UL,UL,
834    def_str,ss_none, NULL, NULL},
835 	{"mus_the_da", {0,&S_music_files[mus_the_da]}, {0,"the_da.mp3"},UL,UL,
836    def_str,ss_none, NULL, NULL},
837 	{"mus_ultima", {0,&S_music_files[mus_ultima]}, {0,"ultima.mp3"},UL,UL,
838    def_str,ss_none, NULL, NULL},
839 	//End Doom 2 and Final Doom
840 };
841 
842 int numdefaults;
843 static char *defaultfile;
844 
845 //
846 // M_SaveDefaults
847 //
848 
M_SaveDefaults(void)849 void M_SaveDefaults (void)
850 {
851   int   i;
852   FILE* f;
853 
854   f = fopen (defaultfile, "w");
855   if (!f)
856     return; // can't write the file, but don't complain
857 
858   // 3/3/98 explain format of file
859 
860   fprintf(f,"# Doom config file\n"
861           "#\n"
862           "# Format:\n"
863           "#  variable   value\n"
864           "#\n"
865           "# Lines starting with '#' are comments\n"
866           "# When saved, default values are commented out\n");
867 
868   for (i = 0 ; i < numdefaults ; i++) {
869     if (defaults[i].type == def_none) {
870       // CPhipps - pure headers
871       fprintf(f, "\n## %s\n", defaults[i].name);
872     } else {
873       // CPhipps - modified for new default_t form
874       if (!IS_STRING(defaults[i])) //jff 4/10/98 kill super-hack on pointer value
875       {
876         // CPhipps - remove keycode hack
877         // killough 3/6/98: use spaces instead of tabs for uniform justification
878         if (defaults[i].type == def_hex)
879           fprintf (f,"%s%-25s 0x%x\n",
880                    (defaults[i].defaultvalue.i == *(defaults[i].location.pi))?"#":"",
881                    defaults[i].name,*(defaults[i].location.pi));
882         else
883           fprintf (f,"%s%-25s %5i\n",
884                    (defaults[i].defaultvalue.i == *(defaults[i].location.pi))?"#":"",
885                    defaults[i].name,*(defaults[i].location.pi));
886       }
887       else
888       {
889         fprintf (f,"%s%-25s \"%s\"\n",
890                  (strcmp(defaults[i].defaultvalue.psz,*(defaults[i].location.ppsz)) == 0)?"#":"",
891                  defaults[i].name,*(defaults[i].location.ppsz));
892       }
893     }
894   }
895 
896   fclose (f);
897 }
898 
899 /*
900  * M_LookupDefault
901  *
902  * cph - mimic MBF function for now. Yes it's crap.
903  */
904 
M_LookupDefault(const char * name)905 struct default_s *M_LookupDefault(const char *name)
906 {
907   int i;
908   for (i = 0 ; i < numdefaults ; i++)
909     if ((defaults[i].type != def_none) && !strcmp(name, defaults[i].name))
910       return &defaults[i];
911   I_Error("M_LookupDefault: %s not found",name);
912   return NULL;
913 }
914 
915 #define NUMCHATSTRINGS 10 // phares 4/13/98
916 
917 /*
918  * M_LoadDefaultsFile
919  *
920  * Load configuration file
921  */
922 
M_LoadDefaultsFile(char * file,dbool basedefault)923 void M_LoadDefaultsFile (char *file, dbool   basedefault)
924 {
925   int   i;
926   int   len;
927   FILE* f;
928   char  def[80];
929   char  strparm[100];
930   char* newstring = NULL;   // killough
931   int   parm;
932   dbool   isstring;
933 
934   // read the file in, overriding any set defaults
935   f = fopen (file, "r");
936   if (f)
937   {
938     while (!feof(f))
939     {
940       isstring = FALSE;
941       if (fscanf (f, "%79s %99[^\n]\n", def, strparm) == 2)
942       {
943         //jff 3/3/98 skip lines not starting with an alphanum
944 
945         if (!isalnum(def[0]))
946           continue;
947 
948         if (strparm[0] == '"') {
949           // get a string default
950 
951           isstring = TRUE;
952           len = strlen(strparm);
953           newstring = (char *) malloc(len);
954           strparm[len-1] = 0; // clears trailing double-quote mark
955           strcpy(newstring, strparm+1); // clears leading double-quote mark
956         } else if ((strparm[0] == '0') && (strparm[1] == 'x')) {
957           // CPhipps - allow ints to be specified in hex
958           sscanf(strparm+2, "%x", &parm);
959         } else {
960           sscanf(strparm, "%i", &parm);
961           // Keycode hack removed
962         }
963 
964         for (i = 0 ; i < numdefaults ; i++)
965           if ((defaults[i].type != def_none) && !strcmp(def, defaults[i].name))
966           {
967             // CPhipps - safety check
968             if (isstring != IS_STRING(defaults[i])) {
969               lprintf(LO_WARN, "M_LoadDefaults: Type mismatch reading %s\n", defaults[i].name);
970               continue;
971             }
972             if (!isstring)
973             {
974               //jff 3/4/98 range check numeric parameters
975               if ((defaults[i].minvalue==UL || defaults[i].minvalue<=parm) &&
976                   (defaults[i].maxvalue==UL || defaults[i].maxvalue>=parm))
977               {
978                 *(defaults[i].location.pi) = parm;
979                 if(basedefault)
980                   defaults[i].defaultvalue.i = parm;
981               }
982             }
983             else
984             {
985               union { const char **c; char **s; } u; // type punning via unions
986 
987               u.c = defaults[i].location.ppsz;
988               free(*(u.s));
989               *(u.s) = newstring;
990 
991               if(basedefault)
992                 defaults[i].defaultvalue.psz = strdup(newstring);
993             }
994             break;
995           }
996       }
997     }
998     fclose (f);
999   }
1000   //jff 3/4/98 redundant range checks for hud deleted here
1001 }
1002 
1003 //
1004 // M_LoadDefaults
1005 //
1006 
M_LoadDefaults(void)1007 void M_LoadDefaults (void)
1008 {
1009   int   i;
1010   char* basefile;
1011 
1012   // set everything to base values
1013 
1014   numdefaults = sizeof(defaults)/sizeof(defaults[0]);
1015   for (i = 0 ; i < numdefaults ; i++) {
1016     if (defaults[i].location.ppsz)
1017       *defaults[i].location.ppsz = strdup(defaults[i].defaultvalue.psz);
1018     if (defaults[i].location.pi)
1019       *defaults[i].location.pi = defaults[i].defaultvalue.i;
1020   }
1021 
1022 
1023   // check if a base default file was provided, to load as base values
1024 
1025   i = M_CheckParm ("-baseconfig");
1026   if (i && i < myargc-1)
1027   {
1028     basefile = strdup(myargv[i+1]);
1029     lprintf (LO_CONFIRM, " default file with base values: %s\n", basefile);
1030     M_LoadDefaultsFile(basefile, TRUE);
1031   }
1032 
1033   // check for a custom default file
1034 
1035   i = M_CheckParm ("-config");
1036   if (i && i < myargc-1)
1037     defaultfile = strdup(myargv[i+1]);
1038   else {
1039     const char* exedir = I_DoomExeDir();
1040     defaultfile = malloc(PATH_MAX+1);
1041     /* get config file from same directory as executable */
1042     snprintf(defaultfile, PATH_MAX,
1043             "%s%s%sboom.cfg", exedir,
1044             HasTrailingSlash(exedir) ? "" : DIR_SLASH_STR,
1045             "pr");
1046   }
1047 
1048   lprintf (LO_CONFIRM, " default file: %s\n",defaultfile);
1049 
1050   M_LoadDefaultsFile(defaultfile, FALSE);
1051 }
1052