]> icculus.org git repositories - btb/d2x.git/blob - main/config.c
restore MovieHires after writing config
[btb/d2x.git] / main / config.c
1 /*
2 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
3 SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
4 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
5 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
6 IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
7 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
8 FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
9 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
10 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
11 COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
12 */
13
14 /*
15  *
16  * contains routine(s) to read in the configuration file which contains
17  * game configuration stuff like detail level, sound card, etc
18  *
19  */
20
21 #ifdef HAVE_CONFIG_H
22 #include <conf.h>
23 #endif
24
25 #ifndef MACINTOSH                       // I'm going to totally seperate these routines -- yeeech!!!!
26                                                         // see end of file for macintosh equivs
27
28 #ifdef WINDOWS
29 #define WIN32_LEAN_AND_MEAN
30 #include <windows.h>
31 #include "winapp.h"
32 #else
33 #endif
34
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <ctype.h>
39
40 #include <physfs.h>
41
42 #include "pstypes.h"
43 #include "game.h"
44 #include "menu.h"
45 #include "movie.h"
46 #include "digi.h"
47 #include "kconfig.h"
48 #include "palette.h"
49 #include "joy.h"
50 #include "songs.h"
51 #include "args.h"
52 #include "player.h"
53 #include "mission.h"
54 #include "mono.h"
55
56 #include "physfsx.h"
57
58
59 ubyte Config_control_type = 0;
60 ubyte Config_joystick_sensitivity = 8;
61
62
63 #ifdef __MSDOS__
64 cvar_t Config_digi_type         = { "DigiDeviceID8", "0", 1 };
65 cvar_t digi_driver_board_16     = { "DigiDeviceID16", "0", 1 };
66 //cvar_t digi_driver_port         = { "DigiPort", "0", 1 };
67 //cvar_t digi_driver_irq          = { "DigiIrq", "0", 1 };
68 cvar_t Config_digi_dma          = { "DigiDma8", "0", 1 };
69 cvar_t digi_driver_dma_16       = { "DigiDma16", "0", 1 };
70 cvar_t Config_midi_type         = { "MidiDeviceID", "0", 1 };
71 //cvar_t digi_midi_port           = { "MidiPort", "0", 1 };
72 #endif
73 cvar_t Config_digi_volume       = { "DigiVolume", "8", 1 };
74 cvar_t Config_midi_volume       = { "MidiVolume", "8", 1 };
75 cvar_t Config_redbook_volume    = { "RedbookVolume", "8", 1 };
76 cvar_t Config_detail_level      = { "DetailLevel", "4", 1 };
77 cvar_t Config_gamma_level       = { "GammaLevel", "0", 1 };
78 cvar_t Config_channels_reversed = { "StereoReverse", "0", 1 };
79 cvar_t Config_joystick_min      = { "JoystickMin", "0,0,0,0", 1 };
80 cvar_t Config_joystick_max      = { "JoystickMax", "0,0,0,0", 1 };
81 cvar_t Config_joystick_cen      = { "JoystickCen", "0,0,0,0", 1 };
82 cvar_t config_last_player       = { "LastPlayer", "", 1 };
83 cvar_t config_last_mission      = { "LastMission", "", 1 };
84 cvar_t Config_vr_type           = { "VR_type", "0", 1 };
85 cvar_t Config_vr_resolution     = { "VR_resolution", "0", 1 };
86 cvar_t Config_vr_tracking       = { "VR_tracking", "0", 1 };
87
88
89 #define _CRYSTAL_LAKE_8_ST              0xe201
90 #define _CRYSTAL_LAKE_16_ST     0xe202
91 #define _AWE32_8_ST                             0xe208
92 #define _AWE32_16_ST                            0xe209
93
94
95 #ifdef WINDOWS
96 int      DOSJoySaveMin[4];
97 int      DOSJoySaveCen[4];
98 int      DOSJoySaveMax[4];
99
100 char win95_current_joyname[256];
101 #endif
102
103
104 extern sbyte Object_complexity, Object_detail, Wall_detail, Wall_render_depth, Debris_amount, SoundChannels;
105
106 void set_custom_detail_vars(void);
107
108
109 #define CL_MC0 0xF8F
110 #define CL_MC1 0xF8D
111 /*
112 void CrystalLakeWriteMCP( ushort mc_addr, ubyte mc_data )
113 {
114         _disable();
115         outp( CL_MC0, 0xE2 );                           // Write password
116         outp( mc_addr, mc_data );               // Write data
117         _enable();
118 }
119
120 ubyte CrystalLakeReadMCP( ushort mc_addr )
121 {
122         ubyte value;
123         _disable();
124         outp( CL_MC0, 0xE2 );           // Write password
125         value = inp( mc_addr );         // Read data
126         _enable();
127         return value;
128 }
129
130 void CrystalLakeSetSB()
131 {
132         ubyte tmp;
133         tmp = CrystalLakeReadMCP( CL_MC1 );
134         tmp &= 0x7F;
135         CrystalLakeWriteMCP( CL_MC1, tmp );
136 }
137
138 void CrystalLakeSetWSS()
139 {
140         ubyte tmp;
141         tmp = CrystalLakeReadMCP( CL_MC1 );
142         tmp |= 0x80;
143         CrystalLakeWriteMCP( CL_MC1, tmp );
144 }
145 */
146 //MovieHires might be changed by -nohighres, so save a "real" copy of it
147 int SaveMovieHires;
148 int save_redbook_enabled;
149
150 #ifdef WINDOWS
151 void CheckMovieAttributes()
152 {
153                 HKEY hKey;
154                 DWORD len, type, val;
155                 long lres;
156  
157                 lres = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Parallax\\Descent II\\1.1\\INSTALL",
158                                                         0, KEY_READ, &hKey);
159                 if (lres == ERROR_SUCCESS) {
160                         len = sizeof(val);
161                         lres = RegQueryValueEx(hKey, "HIRES", NULL, &type, &val, &len);
162                         if (lres == ERROR_SUCCESS) {
163                                 cvar_setint( &MovieHires, val );
164                                 logentry("HIRES=%d\n", val);
165                         }
166                         RegCloseKey(hKey);
167                 }
168 }
169 #endif
170
171
172 static int config_initialized;
173
174 static void config_init(void)
175 {
176         /* make sure our cvars are registered */
177         cvar_registervariable(&Config_digi_volume);
178         cvar_registervariable(&Config_midi_volume);
179         cvar_registervariable(&Redbook_enabled);
180         cvar_registervariable(&Config_redbook_volume);
181         cvar_registervariable(&Config_channels_reversed);
182         cvar_registervariable(&Config_gamma_level);
183         cvar_registervariable(&Config_detail_level);
184         cvar_registervariable(&Config_joystick_min);
185         cvar_registervariable(&Config_joystick_cen);
186         cvar_registervariable(&Config_joystick_max);
187         cvar_registervariable(&config_last_player);
188         cvar_registervariable(&config_last_mission);
189         cvar_registervariable(&Config_vr_type);
190         cvar_registervariable(&Config_vr_resolution);
191         cvar_registervariable(&Config_vr_tracking);
192         cvar_registervariable(&MovieHires);
193
194         config_initialized = 1;
195 }
196
197
198 int ReadConfigFile()
199 {
200         int joy_axis_min[7];
201         int joy_axis_center[7];
202         int joy_axis_max[7];
203         int i;
204
205         if (!config_initialized)
206                 config_init();
207
208         cvar_set_cvar( &config_last_player, "" );
209
210         joy_axis_min[0] = joy_axis_min[1] = joy_axis_min[2] = joy_axis_min[3] = 0;
211         joy_axis_max[0] = joy_axis_max[1] = joy_axis_max[2] = joy_axis_max[3] = 0;
212         joy_axis_center[0] = joy_axis_center[1] = joy_axis_center[2] = joy_axis_center[3] = 0;
213
214 #ifdef WINDOWS
215         memset(&joy_axis_min[0], 0, sizeof(int)*7);
216         memset(&joy_axis_max[0], 0, sizeof(int)*7);
217         memset(&joy_axis_center[0], 0, sizeof(int)*7);
218 //@@    joy_set_cal_vals(joy_axis_min, joy_axis_center, joy_axis_max);
219 #else
220         joy_set_cal_vals(joy_axis_min, joy_axis_center, joy_axis_max);
221 #endif
222
223 #if 0
224         cvar_setint(&digi_driver_board, 0);
225         cvar_setint(&digi_driver_port, 0);
226         cvar_setint(&digi_driver_irq, 0);
227         cvar_setint(&digi_driver_dma, 0);
228         cvar_setint(&digi_midi_type, 0);
229         cvar_setint(&digi_midi_port, 0);
230 #endif
231
232         cvar_setint( &Config_digi_volume, 8 );
233         cvar_setint( &Config_midi_volume, 8 );
234         cvar_setint( &Config_redbook_volume, 8 );
235         Config_control_type = 0;
236         cvar_setint( &Config_channels_reversed, 0);
237
238         //set these here in case no cfg file
239         SaveMovieHires = MovieHires.intval;
240         save_redbook_enabled = Redbook_enabled.intval;
241
242         cmd_append("exec descent.cfg");
243         cmd_queue_process();
244
245         /* TODO: allow cvars to define a callback that will carry out these initialization things on change. */
246
247         gr_palette_set_gamma( Config_gamma_level.intval );
248
249         Detail_level = strtol(Config_detail_level.string, NULL, 10);
250         if (Detail_level == NUM_DETAIL_LEVELS - 1) {
251                 int count,dummy,oc,od,wd,wrd,da,sc;
252
253                 count = sscanf (Config_detail_level.string, "%d,%d,%d,%d,%d,%d,%d\n",&dummy,&oc,&od,&wd,&wrd,&da,&sc);
254
255                 if (count == 7) {
256                         Object_complexity = oc;
257                         Object_detail = od;
258                         Wall_detail = wd;
259                         Wall_render_depth = wrd;
260                         Debris_amount = da;
261                         SoundChannels = sc;
262                         set_custom_detail_vars();
263                 }
264         }
265
266         sscanf( Config_joystick_min.string, "%d,%d,%d,%d", &joy_axis_min[0], &joy_axis_min[1], &joy_axis_min[2], &joy_axis_min[3] );
267         sscanf( Config_joystick_max.string, "%d,%d,%d,%d", &joy_axis_max[0], &joy_axis_max[1], &joy_axis_max[2], &joy_axis_max[3] );
268         sscanf( Config_joystick_cen.string, "%d,%d,%d,%d", &joy_axis_center[0], &joy_axis_center[1], &joy_axis_center[2], &joy_axis_center[3] );
269
270
271 #ifdef WINDOWS
272         for (i=0;i<4;i++)
273         {
274          DOSJoySaveMin[i]=joy_axis_min[i];
275          DOSJoySaveCen[i]=joy_axis_center[i];
276          DOSJoySaveMax[i]=joy_axis_max[i];
277         }
278 #else
279         joy_set_cal_vals(joy_axis_min, joy_axis_center, joy_axis_max);
280 #endif
281
282         i = FindArg( "-volume" );
283         
284         if ( i > 0 )    {
285                 i = atoi( Args[i+1] );
286                 if ( i < 0 ) i = 0;
287                 if ( i > 100 ) i = 100;
288                 cvar_setint( &Config_digi_volume, (i * 8) / 100 );
289                 cvar_setint( &Config_midi_volume, (i * 8) / 100 );
290                 cvar_setint( &Config_redbook_volume, (i * 8) / 100 );
291         }
292
293         if ( Config_digi_volume.intval > 8 ) cvar_setint( &Config_digi_volume, 8 );
294         if ( Config_midi_volume.intval > 8 ) cvar_setint( &Config_midi_volume, 8 );
295         if ( Config_redbook_volume.intval > 8 ) cvar_setint( &Config_redbook_volume, 8 );
296
297         digi_set_volume( (Config_digi_volume.intval * 32768) / 8, (Config_midi_volume.intval * 128) / 8 );
298
299 #if 0
300         printf( "DigiDeviceID: 0x%x\n", digi_driver_board );
301         printf( "DigiPort: 0x%x\n", digi_driver_port.intval );
302         printf( "DigiIrq: 0x%x\n",  digi_driver_irq.intval );
303         printf( "DigiDma: 0x%x\n",      digi_driver_dma.intval );
304         printf( "MidiDeviceID: 0x%x\n", digi_midi_type.intval );
305         printf( "MidiPort: 0x%x\n", digi_midi_port.intval );
306         key_getch();
307
308         cvar_setint( &Config_midi_type, digi_midi_type );
309         cvar_setint( &Config_digi_type, digi_driver_board );
310         cvar_setint( &Config_digi_dma, digi_driver_dma );
311 #endif
312
313 #if 0
314         if (digi_driver_board_16.intval > 0 && !FindArg("-no16bit") && digi_driver_board_16.intval != _GUS_16_ST) {
315                 digi_driver_board = digi_driver_board_16.intval;
316                 digi_driver_dma = digi_driver_dma_16.intval;
317         }
318
319         // HACK!!!
320         //Hack to make some cards look like others, such as
321         //the Crytal Lake look like Microsoft Sound System
322         if ( digi_driver_board == _CRYSTAL_LAKE_8_ST )  {
323                 ubyte tmp;
324                 tmp = CrystalLakeReadMCP( CL_MC1 );
325                 if ( !(tmp & 0x80) )
326                         atexit( CrystalLakeSetSB );             // Restore to SB when done.
327                 CrystalLakeSetWSS();
328                 digi_driver_board = _MICROSOFT_8_ST;
329         } else if ( digi_driver_board == _CRYSTAL_LAKE_16_ST )  {
330                 ubyte tmp;
331                 tmp = CrystalLakeReadMCP( CL_MC1 );
332                 if ( !(tmp & 0x80) )
333                         atexit( CrystalLakeSetSB );             // Restore to SB when done.
334                 CrystalLakeSetWSS();
335                 digi_driver_board = _MICROSOFT_16_ST;
336         } else if ( digi_driver_board == _AWE32_8_ST )  {
337                 digi_driver_board = _SB16_8_ST;
338         } else if ( digi_driver_board == _AWE32_16_ST ) {
339                 digi_driver_board = _SB16_16_ST;
340         } else
341                 digi_driver_board               = digi_driver_board;
342 #else
343
344         if (cfexist("descentw.cfg")) {
345                 cmd_append("exec descentw.cfg");
346                 cmd_queue_process();
347
348                 sscanf( Config_joystick_min.string, "%d,%d,%d,%d,%d,%d,%d", &joy_axis_min[0], &joy_axis_min[1], &joy_axis_min[2], &joy_axis_min[3], &joy_axis_min[4], &joy_axis_min[5], &joy_axis_min[6] );
349                 sscanf( Config_joystick_max.string, "%d,%d,%d,%d,%d,%d,%d", &joy_axis_max[0], &joy_axis_max[1], &joy_axis_max[2], &joy_axis_max[3], &joy_axis_max[4], &joy_axis_max[5], &joy_axis_max[6] );
350                 sscanf( Config_joystick_cen.string, "%d,%d,%d,%d,%d,%d,%d", &joy_axis_center[0], &joy_axis_center[1], &joy_axis_center[2], &joy_axis_center[3], &joy_axis_center[4], &joy_axis_center[5], &joy_axis_center[6] );
351         }
352 #endif
353
354         return 0;
355 }
356
357 int WriteConfigFile()
358 {
359         PHYSFS_file *outfile;
360         int joy_axis_min[7];
361         int joy_axis_center[7];
362         int joy_axis_max[7];
363         
364         joy_get_cal_vals(joy_axis_min, joy_axis_center, joy_axis_max);
365
366 #ifdef WINDOWS
367         for (i=0;i<4;i++)
368    {
369          joy_axis_min[i]=DOSJoySaveMin[i];
370          joy_axis_center[i]=DOSJoySaveCen[i];
371          joy_axis_max[i]=DOSJoySaveMax[i];
372    }
373 #endif
374
375         if (FindArg("-noredbook"))
376                 cvar_setint( &Redbook_enabled, save_redbook_enabled );
377
378         cvar_setint( &Config_gamma_level, gr_palette_get_gamma() );
379
380         if (Detail_level == NUM_DETAIL_LEVELS-1)
381                 cvar_set_cvarf( &Config_detail_level, "%d,%d,%d,%d,%d,%d,%d", Detail_level,
382                                            Object_complexity,Object_detail,Wall_detail,Wall_render_depth,Debris_amount,SoundChannels );
383         else
384                 cvar_setint( &Config_detail_level, Detail_level );
385
386         cvar_set_cvarf( &Config_joystick_min, "%d,%d,%d,%d", joy_axis_min[0], joy_axis_min[1], joy_axis_min[2], joy_axis_min[3] );
387         cvar_set_cvarf( &Config_joystick_cen, "%d,%d,%d,%d", joy_axis_center[0], joy_axis_center[1], joy_axis_center[2], joy_axis_center[3] );
388         cvar_set_cvarf( &Config_joystick_max, "%d,%d,%d,%d", joy_axis_max[0], joy_axis_max[1], joy_axis_max[2], joy_axis_max[3] );
389
390         cvar_set_cvar( &config_last_player, Players[Player_num].callsign );
391
392         cvar_setint( &MovieHires, SaveMovieHires );
393
394         outfile = PHYSFSX_openWriteBuffered("descent.cfg");
395         if (outfile == NULL)
396                 return 1;
397         cvar_write(outfile);
398         PHYSFS_close(outfile);
399
400         if (FindArg("-nohires") || FindArg("-nohighres") || FindArg("-lowresmovies"))
401                 cvar_setint( &MovieHires, 0 );
402
403 #ifdef WINDOWS
404 {
405 //      Save Windows Config File
406         char str[256];
407                                                 
408
409         joy_get_cal_vals(joy_axis_min, joy_axis_center, joy_axis_max);
410         
411         outfile = PHYSFSX_openWriteBuffered("descentw.cfg");
412         if (outfile == NULL) return 1;
413
414         sprintf(str, "%s=%d,%d,%d,%d,%d,%d,%d\n", Config_joystick_min.name,
415                         joy_axis_min[0], joy_axis_min[1], joy_axis_min[2], joy_axis_min[3],
416                         joy_axis_min[4], joy_axis_min[5], joy_axis_min[6]);
417         PHYSFSX_puts(outfile, str);
418         sprintf(str, "%s=%d,%d,%d,%d,%d,%d,%d\n", Config_joystick_cen.name,
419                         joy_axis_center[0], joy_axis_center[1], joy_axis_center[2], joy_axis_center[3],
420                         joy_axis_center[4], joy_axis_center[5], joy_axis_center[6]);
421         PHYSFSX_puts(outfile, str);
422         sprintf(str, "%s=%d,%d,%d,%d,%d,%d,%d\n", Config_joystick_max.name,
423                         joy_axis_max[0], joy_axis_max[1], joy_axis_max[2], joy_axis_max[3],
424                         joy_axis_max[4], joy_axis_max[5], joy_axis_max[6]);
425         PHYSFSX_puts(outfile, str);
426
427         cfclose(outfile);
428 }
429         CheckMovieAttributes();
430 #endif
431
432         return 0;
433 }               
434
435 #else           // !defined(MACINTOSH)
436
437 #include <stdio.h>
438 #include <stdlib.h>
439 #include <string.h>
440 #include <ctype.h>
441
442 #include <Memory.h>
443 #include <Folders.h>
444 #include <GestaltEqu.h>
445 #include <Errors.h>
446 #include <Processes.h>
447 #include <Resources.h>
448 #include <LowMem.h>
449
450 #include "error.h"
451 #include "pstypes.h"
452 #include "game.h"
453 #include "digi.h"
454 #include "kconfig.h"
455 #include "palette.h"
456 #include "joy.h"
457 #include "args.h"
458 #include "player.h"
459 #include "mission.h"
460 #include "prefs.h"                      // prefs file for configuration stuff -- from DeSalvo
461
462 #define MAX_CTB_LEN     512
463
464 typedef struct preferences {
465         ubyte   digi_volume;
466         ubyte   midi_volume;
467         ubyte   stereo_reverse;
468         ubyte   detail_level;
469         ubyte   oc;                                     // object complexity
470         ubyte   od;                                     // object detail
471         ubyte   wd;                                     // wall detail
472         ubyte   wrd;                            // wall render depth
473         ubyte   da;                                     // debris amount
474         ubyte   sc;                                     // sound channels
475         ubyte   gamma_level;
476         ubyte   pixel_double;
477         int             joy_axis_min[4];
478         int             joy_axis_max[4];
479         int             joy_axis_center[4];
480         char    lastplayer[CALLSIGN_LEN+1];
481         char    lastmission[MISSION_NAME_LEN+1];
482         char    ctb_config[MAX_CTB_LEN];
483         int             ctb_tool;
484         ubyte   master_volume;
485         ubyte   display_dialog;
486         ubyte   change_resolution;
487         ubyte   nosound;
488         ubyte   nomidi;
489         ubyte   sound_11k;
490         ubyte   no_movies;
491         ubyte   game_monitor;
492         ubyte   redbook_volume;
493         ubyte   enable_rave;
494         ubyte   enable_input_sprockets;
495 } Preferences;
496
497 char config_last_player[CALLSIGN_LEN+1] = "";
498 char config_last_mission[MISSION_NAME_LEN+1] = "";
499 char config_last_ctb_cfg[MAX_CTB_LEN] = "";
500 int config_last_ctb_tool;
501 ubyte Config_master_volume = 4;
502 ubyte Config_digi_volume = 8;
503 ubyte Config_midi_volume = 8;
504 ubyte Config_redbook_volume = 8;
505 ubyte Config_control_type = 0;
506 ubyte Config_channels_reversed = 0;
507 ubyte Config_joystick_sensitivity = 8;
508
509 int Config_vr_type = 0;
510 int Config_vr_resolution = 0;
511 int Config_vr_tracking = 0;
512
513 extern sbyte Object_complexity, Object_detail, Wall_detail, Wall_render_depth, Debris_amount, SoundChannels;
514 extern void digi_set_master_volume( int volume );
515
516 void set_custom_detail_vars(void);
517
518 static ubyte have_prefs = 0;
519
520 //¥     ------------------------------  Private Definitions
521 //¥     ------------------------------  Private Types
522
523 typedef struct
524 {
525         Str31   fileName;
526         OSType  creator;
527         OSType  fileType;
528         OSType  resType;
529         short   resID;
530 } PrefsInfo, *PrefsInfoPtr, **PrefsInfoHandle;
531
532 //¥     ------------------------------  Private Variables
533
534 static PrefsInfo                prefsInfo;
535 static Boolean          prefsInited = 0;
536
537 //¥     ------------------------------  Private Functions
538
539 static void Pstrcpy(StringPtr dst, StringPtr src);
540 static void Pstrcat(StringPtr dst, StringPtr src);
541 static Boolean FindPrefsFile(short *prefVRefNum, long *prefDirID);
542
543 //¥     --------------------    Pstrcpy
544
545 static void
546 Pstrcpy(StringPtr dst, StringPtr src)
547 {
548         BlockMove(src, dst, (*src) + 1);
549 }
550
551 //¥     --------------------    Pstrcat
552
553 static void
554 Pstrcat(StringPtr dst, StringPtr src)
555 {
556         BlockMove(src + 1, dst + (*dst) + 1, *src);
557         *dst += *src;
558 }
559
560 //¥     --------------------    FindPrefsFile
561
562 static Boolean
563 FindPrefsFile(short *prefVRefNum, long *prefDirID)
564 {
565 OSErr           theErr;
566 long                    response;
567 CInfoPBRec      infoPB;
568
569         if (! prefsInited)
570                 return (0);
571                 
572         theErr = Gestalt(gestaltFindFolderAttr, &response);
573         if (theErr == noErr && ((response >> gestaltFindFolderPresent) & 1))
574         {
575                 //¥     Find (or make) it the easy way...
576                 theErr = FindFolder(kOnSystemDisk, kPreferencesFolderType, kCreateFolder, prefVRefNum, prefDirID);
577         }
578         else
579         {
580         SysEnvRec       theSysEnv;
581         StringPtr               prefFolderName = "\pPreferences";
582
583                 //¥     yeachh -- we have to do it all by hand!
584                 theErr = SysEnvirons(1, &theSysEnv);
585                 if (theErr != noErr)
586                         return (0);
587                         
588                 *prefVRefNum = theSysEnv.sysVRefNum;
589                 
590                 //¥     Check whether Preferences folder already exists
591                 infoPB.hFileInfo.ioCompletion   = 0;
592                 infoPB.hFileInfo.ioNamePtr      = prefFolderName;
593                 infoPB.hFileInfo.ioVRefNum      = *prefVRefNum;
594                 infoPB.hFileInfo.ioFDirIndex    = 0;
595                 infoPB.hFileInfo.ioDirID                = 0;
596
597                 theErr = PBGetCatInfo(&infoPB, 0);
598                 if (theErr == noErr)
599                 {
600                         *prefDirID = infoPB.hFileInfo.ioDirID;
601                 }
602                 else if (theErr == fnfErr)              //¥     Preferences doesn't already exist
603                 {
604                 HParamBlockRec  dirPB;
605                 
606                         //¥     Create "Preferences" folder
607                         dirPB.fileParam.ioCompletion    = 0;
608                         dirPB.fileParam.ioVRefNum       = *prefVRefNum;
609                         dirPB.fileParam.ioNamePtr       = prefFolderName;
610                         dirPB.fileParam.ioDirID         = 0;
611
612                         theErr = PBDirCreate(&dirPB, 0);
613                         if (theErr == noErr)
614                                 *prefDirID = dirPB.fileParam.ioDirID;
615                 }
616         }
617         
618         //¥     If we make it here OK, create Preferences file if necessary
619         if (theErr == noErr)
620         {
621                 infoPB.hFileInfo.ioCompletion   = 0;
622                 infoPB.hFileInfo.ioNamePtr      = prefsInfo.fileName;
623                 infoPB.hFileInfo.ioVRefNum      = *prefVRefNum;
624                 infoPB.hFileInfo.ioFDirIndex    = 0;
625                 infoPB.hFileInfo.ioDirID                = *prefDirID;
626
627                 theErr = PBGetCatInfo(&infoPB, 0);
628                 if (theErr == fnfErr)
629                 {
630                         theErr = HCreate(*prefVRefNum, *prefDirID, prefsInfo.fileName, prefsInfo.creator, prefsInfo.fileType);
631                         if (theErr == noErr)
632                         {
633                                 HCreateResFile(*prefVRefNum, *prefDirID, prefsInfo.fileName);
634                                 theErr = ResError();
635                         }
636                 }
637         }
638         
639         return (theErr == noErr);
640 }
641
642 //¥     --------------------    InitPrefsFile
643
644 #define UNKNOWN_TYPE 0x3f3f3f3f
645
646 void
647 InitPrefsFile(OSType creator)
648 {
649         OSErr err;
650 PrefsInfoHandle         piHdl;
651         
652         if ((piHdl = (PrefsInfoHandle) GetResource('PRFI', 0)) == nil)
653         {
654         ProcessSerialNumber     thePSN;
655         ProcessInfoRec                  thePIR;
656         FSSpec                          appSpec;
657         StringPtr                       app_string;
658
659 #if 0   
660                 GetCurrentProcess(&thePSN);
661                 thePIR.processName = nil;
662                 thePIR.processAppSpec = &appSpec;
663                 
664                 //¥     Set default to 'ÇApplicationÈ Prefs', PREF 0
665                 err = GetProcessInformation(&thePSN, &thePIR);
666                 if (err)
667                         Int3();
668 #endif
669                 app_string = LMGetCurApName();
670 //              Pstrcpy(prefsInfo.fileName, appSpec.name);
671                 Pstrcpy(prefsInfo.fileName, app_string);
672                 Pstrcat(prefsInfo.fileName, "\p Preferences");
673                 
674                 //¥     Set creator to calling application's signature (should be able to
675                 //¥     Determine this automatically, but unable to for some reason)
676                 prefsInfo.creator = creator;
677                 prefsInfo.fileType = 'pref';
678                 prefsInfo.resType = 'pref';
679                 prefsInfo.resID = 0;
680         }
681         else
682         {
683                 //¥     Get Preferences file setup from PRFI 0
684                 BlockMove(*piHdl, &prefsInfo, sizeof (prefsInfo));
685                 ReleaseResource((Handle) piHdl);
686                 
687                 if (prefsInfo.creator == UNKNOWN_TYPE)
688                         prefsInfo.creator = creator;
689         }
690         
691         prefsInited = 1;
692 }
693
694 //¥     --------------------    LoadPrefsFile
695
696 OSErr
697 LoadPrefsFile(Handle prefsHdl)
698 {
699 short   prefVRefNum, prefRefNum;
700 long            prefDirID;
701 OSErr   theErr = noErr;
702 Handle  origHdl;
703 Size            prefSize, origSize;
704
705         if (prefsHdl == nil)
706                 return (nilHandleErr);
707
708         prefSize = GetHandleSize(prefsHdl);
709                 
710         if (! FindPrefsFile(&prefVRefNum, &prefDirID))
711                 return (fnfErr);
712
713         prefRefNum = HOpenResFile(prefVRefNum, prefDirID, prefsInfo.fileName, fsRdWrPerm);
714         if (prefRefNum == -1)
715                 return (ResError());
716         
717         //¥     Not finding the resource is not an error -- caller will use default data
718         if ((origHdl = Get1Resource(prefsInfo.resType, prefsInfo.resID)) != nil)
719         {
720                 origSize = GetHandleSize(origHdl);
721                 if (origSize > prefSize)                        //¥     Extend handle for extra stored data
722                         SetHandleSize(prefsHdl, origSize);
723
724                 BlockMove(*origHdl, *prefsHdl, origSize);
725                 ReleaseResource(origHdl);
726         }
727         
728         CloseResFile(prefRefNum);
729
730         if (theErr == noErr)
731                 theErr = ResError();
732         
733         return (theErr);
734 }
735
736 //¥     --------------------    SavePrefsFile
737
738 OSErr
739 SavePrefsFile(Handle prefHdl)
740 {
741 short   prefVRefNum, prefRefNum;
742 long            prefDirID;
743 Handle  origHdl = nil;
744 Size            origSize, prefSize;
745 OSErr   theErr = noErr;
746         
747         if (! FindPrefsFile(&prefVRefNum, &prefDirID))
748                 return (fnfErr);
749         
750         if (prefHdl == nil)
751                 return (nilHandleErr);
752
753         prefSize = GetHandleSize(prefHdl);
754
755         prefRefNum = HOpenResFile(prefVRefNum, prefDirID, prefsInfo.fileName, fsRdWrPerm);
756         if (prefRefNum == -1)
757                 return (ResError());
758                 
759         if ((origHdl = Get1Resource(prefsInfo.resType, prefsInfo.resID)) != nil)
760         {
761                 //¥     Overwrite existing preferences
762                 origSize = GetHandleSize(origHdl);
763                 if (prefSize > origSize)
764                         SetHandleSize(origHdl, prefSize);
765                         
766                 BlockMove(*prefHdl, *origHdl, prefSize);
767                 ChangedResource(origHdl);
768                 WriteResource(origHdl);
769                 ReleaseResource(origHdl);
770         }
771         else
772         {
773                 //¥     Store specified preferences for the first time
774                 AddResource(prefHdl, prefsInfo.resType, prefsInfo.resID, "\p");
775                 WriteResource(prefHdl);
776                 DetachResource(prefHdl);
777         }
778         
779         CloseResFile(prefRefNum);
780
781         if (theErr == noErr)
782                 theErr = ResError();
783         
784         return (theErr);
785 }
786
787 //¥     -------------------------------------------------------------------------------------------
788
789 /*
790
791         This module provides the ability to save and load a preferences file in the
792         Preferences folder in the System Folder.  An optional resource, PRFI 0,
793         is used to provide specifications for the preferences file (creator, etc.).
794
795         Three functions are provided:
796
797                 void InitPrefsFile(OSType creator)
798
799         This function will initialize the preferences file, that is, it will create
800         it in the appropriate place if it doesn't currently exist.  It should be
801         called with the creator code for the application.  Note that the creator
802         code specified in PRFI 0 (if any) will be used only if the creator code
803         passed to this function is '????'.  Without the PRFI 0 resource, the default
804         specifications are:
805
806         File Name: "{Application} Prefs" (i.e., the name of the app plus " Prefs"
807         Creator: the creator passed to InitPrefsFile
808         Type: 'PREF'
809         Pref Resource Type: 'PREF'
810         Pref Resource ID: 0
811
812         The PRFI 0 resource allows you to specify overrides for each of the above
813         values.  This is useful for development, since the application name might
814         go through changes, but the preferences file name is held constant.
815
816                 OSErr LoadPrefsFile(Handle prefsHndl)
817
818         This function will attempt to copy the data stored in the preferences
819         file to the given handle (which must be pre-allocated).  If the handle is too
820         small, then it will be enlarged.  If it is too large, it will not be resized.
821         The data in the preferences file (normally in PREF 0) will then be copied
822         into the handle.  If the preferences file did not exist, the original data
823         in the handle will not change.
824
825                 OSErr SavePrefsFile(Handle prefsHndl)
826
827         This function will attempt to save the given handle to the preferences
828         file.  Its contents will completely replace the previous data (normally
829         the PREF 0 resource).
830
831         In typical use, you will use InitPrefsFile once, then allocate a handle large
832         enough to contain your preferences data, and initialize it with default values.
833         Throughout the course of your program, the handle will undergo modification as
834         user preferences change.  You can use SavePrefsFile anytime to update the
835         preferences file, or wait until program exit to do so.
836
837 */
838
839 int ReadConfigFile()
840 {
841         int i;
842         OSErr err;
843         Handle prefs_handle;
844         Preferences *prefs;
845         char *p;
846         
847         if (!have_prefs) {                      // not initialized....get a handle to the preferences file
848                 InitPrefsFile('DCT2');
849                 have_prefs = 1;
850         }
851         
852         prefs_handle = NewHandleClear(sizeof(Preferences));             // new prefs handle
853         if (prefs_handle == NULL)
854                 return;
855                 
856         prefs = (Preferences *)(*prefs_handle);
857         err = LoadPrefsFile(prefs_handle);
858         if (err) {
859                 DisposeHandle(prefs_handle);
860                 return -1;
861         }
862
863         p = (char *)prefs;
864         for (i = 0; i < sizeof(Preferences); i++) {
865                 if (*p != 0)
866                         break;
867                 p++;
868         }
869         if ( i == sizeof(Preferences) )
870                 return -1;
871         
872         Config_digi_volume = prefs->digi_volume;
873         Config_midi_volume = prefs->midi_volume;
874         Config_master_volume = prefs->master_volume;
875         Config_redbook_volume = prefs->redbook_volume;
876         Config_channels_reversed = prefs->stereo_reverse;
877         gr_palette_set_gamma( (int)(prefs->gamma_level) );
878
879         Scanline_double = (int)prefs->pixel_double;
880         if ( PAEnabled )
881                 Scanline_double = 0;            // can't double with hardware acceleration
882                 
883         Detail_level = prefs->detail_level;
884         if (Detail_level == NUM_DETAIL_LEVELS-1) {
885                 Object_complexity = prefs->oc;
886                 Object_detail = prefs->od;
887                 Wall_detail = prefs->wd;
888                 Wall_render_depth = prefs->wrd;
889                 Debris_amount = prefs->da;
890                 SoundChannels = prefs->sc;
891                 set_custom_detail_vars();
892         }
893
894         strncpy( config_last_player, prefs->lastplayer, CALLSIGN_LEN );
895         p = strchr(config_last_player, '\n' );
896         if (p) *p = 0;
897         
898         strncpy(config_last_mission, prefs->lastmission, MISSION_NAME_LEN);
899         p = strchr(config_last_mission, '\n' );
900         if (p) *p = 0;
901
902         strcpy(config_last_ctb_cfg, prefs->ctb_config);
903         
904         if ( Config_digi_volume > 8 ) Config_digi_volume = 8;
905
906         if ( Config_midi_volume > 8 ) Config_midi_volume = 8;
907
908         joy_set_cal_vals( prefs->joy_axis_min, prefs->joy_axis_center, prefs->joy_axis_max);
909         digi_set_volume( (Config_digi_volume*256)/8, (Config_midi_volume*256)/8 );
910         digi_set_master_volume(Config_master_volume);
911         
912         gConfigInfo.mDoNotDisplayOptions = prefs->display_dialog;
913         gConfigInfo.mUse11kSounds = prefs->sound_11k;
914         gConfigInfo.mDisableSound = prefs->nosound;
915         gConfigInfo.mDisableMIDIMusic = prefs->nomidi;
916         gConfigInfo.mChangeResolution = prefs->change_resolution;
917         gConfigInfo.mDoNotPlayMovies = prefs->no_movies;
918         gConfigInfo.mGameMonitor = prefs->game_monitor;
919         gConfigInfo.mAcceleration = prefs->enable_rave;
920         gConfigInfo.mInputSprockets = prefs->enable_input_sprockets;
921         
922         DisposeHandle(prefs_handle);
923         return 0;
924 }
925
926 int WriteConfigFile()
927 {
928         OSErr err;
929         Handle prefs_handle;
930         Preferences *prefs;
931         
932         prefs_handle = NewHandleClear(sizeof(Preferences));             // new prefs handle
933         if (prefs_handle == NULL)
934                 return;
935                 
936         prefs = (Preferences *)(*prefs_handle);
937         
938         joy_get_cal_vals(prefs->joy_axis_min, prefs->joy_axis_center, prefs->joy_axis_max);
939         prefs->digi_volume = Config_digi_volume;
940         prefs->midi_volume = Config_midi_volume;
941         prefs->stereo_reverse = Config_channels_reversed;
942         prefs->detail_level = Detail_level;
943         if (Detail_level == NUM_DETAIL_LEVELS-1) {
944                 prefs->oc = Object_complexity;
945                 prefs->od = Object_detail;
946                 prefs->wd = Wall_detail;
947                 prefs->wrd = Wall_render_depth;
948                 prefs->da = Debris_amount;
949                 prefs->sc = SoundChannels;
950         }
951         prefs->gamma_level = (ubyte)gr_palette_get_gamma();
952
953         if ( !PAEnabled )
954                 prefs->pixel_double = (ubyte)Scanline_double;           // hmm..don't write this out if doing hardware accel.
955                 
956         strncpy( prefs->lastplayer, Players[Player_num].callsign, CALLSIGN_LEN );
957         strncpy( prefs->lastmission, config_last_mission, MISSION_NAME_LEN );
958         strcpy( prefs->ctb_config, config_last_ctb_cfg);
959         prefs->ctb_tool = config_last_ctb_tool;
960         prefs->master_volume = Config_master_volume;
961         prefs->display_dialog = gConfigInfo.mDoNotDisplayOptions;
962         prefs->change_resolution = gConfigInfo.mChangeResolution;
963         prefs->nosound = gConfigInfo.mDisableSound;
964         prefs->nomidi = gConfigInfo.mDisableMIDIMusic;
965         prefs->sound_11k = gConfigInfo.mUse11kSounds;
966         prefs->no_movies = gConfigInfo.mDoNotPlayMovies;
967         prefs->game_monitor = gConfigInfo.mGameMonitor;
968         prefs->redbook_volume = Config_redbook_volume;
969         prefs->enable_rave = gConfigInfo.mAcceleration;
970         prefs->enable_input_sprockets = gConfigInfo.mInputSprockets;
971
972         err = SavePrefsFile(prefs_handle);
973         DisposeHandle(prefs_handle);
974         return (int)err;
975 }
976
977 #endif
978