]> icculus.org git repositories - btb/d2x.git/blob - main/config.c
remove rcs tags
[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         if (FindArg("-nohires") || FindArg("-nohighres") || FindArg("-lowresmovies"))
393                 cvar_setint( &MovieHires, SaveMovieHires );
394
395         outfile = PHYSFSX_openWriteBuffered("descent.cfg");
396         if (outfile == NULL)
397                 return 1;
398         cvar_write(outfile);
399         PHYSFS_close(outfile);
400
401
402 #ifdef WINDOWS
403 {
404 //      Save Windows Config File
405         char str[256];
406                                                 
407
408         joy_get_cal_vals(joy_axis_min, joy_axis_center, joy_axis_max);
409         
410         outfile = PHYSFSX_openWriteBuffered("descentw.cfg");
411         if (outfile == NULL) return 1;
412
413         sprintf(str, "%s=%d,%d,%d,%d,%d,%d,%d\n", Config_joystick_min.name,
414                         joy_axis_min[0], joy_axis_min[1], joy_axis_min[2], joy_axis_min[3],
415                         joy_axis_min[4], joy_axis_min[5], joy_axis_min[6]);
416         PHYSFSX_puts(outfile, str);
417         sprintf(str, "%s=%d,%d,%d,%d,%d,%d,%d\n", Config_joystick_cen.name,
418                         joy_axis_center[0], joy_axis_center[1], joy_axis_center[2], joy_axis_center[3],
419                         joy_axis_center[4], joy_axis_center[5], joy_axis_center[6]);
420         PHYSFSX_puts(outfile, str);
421         sprintf(str, "%s=%d,%d,%d,%d,%d,%d,%d\n", Config_joystick_max.name,
422                         joy_axis_max[0], joy_axis_max[1], joy_axis_max[2], joy_axis_max[3],
423                         joy_axis_max[4], joy_axis_max[5], joy_axis_max[6]);
424         PHYSFSX_puts(outfile, str);
425
426         cfclose(outfile);
427 }
428         CheckMovieAttributes();
429 #endif
430
431         return 0;
432 }               
433
434 #else           // !defined(MACINTOSH)
435
436 #include <stdio.h>
437 #include <stdlib.h>
438 #include <string.h>
439 #include <ctype.h>
440
441 #include <Memory.h>
442 #include <Folders.h>
443 #include <GestaltEqu.h>
444 #include <Errors.h>
445 #include <Processes.h>
446 #include <Resources.h>
447 #include <LowMem.h>
448
449 #include "error.h"
450 #include "pstypes.h"
451 #include "game.h"
452 #include "digi.h"
453 #include "kconfig.h"
454 #include "palette.h"
455 #include "joy.h"
456 #include "args.h"
457 #include "player.h"
458 #include "mission.h"
459 #include "prefs.h"                      // prefs file for configuration stuff -- from DeSalvo
460
461 #define MAX_CTB_LEN     512
462
463 typedef struct preferences {
464         ubyte   digi_volume;
465         ubyte   midi_volume;
466         ubyte   stereo_reverse;
467         ubyte   detail_level;
468         ubyte   oc;                                     // object complexity
469         ubyte   od;                                     // object detail
470         ubyte   wd;                                     // wall detail
471         ubyte   wrd;                            // wall render depth
472         ubyte   da;                                     // debris amount
473         ubyte   sc;                                     // sound channels
474         ubyte   gamma_level;
475         ubyte   pixel_double;
476         int             joy_axis_min[4];
477         int             joy_axis_max[4];
478         int             joy_axis_center[4];
479         char    lastplayer[CALLSIGN_LEN+1];
480         char    lastmission[MISSION_NAME_LEN+1];
481         char    ctb_config[MAX_CTB_LEN];
482         int             ctb_tool;
483         ubyte   master_volume;
484         ubyte   display_dialog;
485         ubyte   change_resolution;
486         ubyte   nosound;
487         ubyte   nomidi;
488         ubyte   sound_11k;
489         ubyte   no_movies;
490         ubyte   game_monitor;
491         ubyte   redbook_volume;
492         ubyte   enable_rave;
493         ubyte   enable_input_sprockets;
494 } Preferences;
495
496 char config_last_player[CALLSIGN_LEN+1] = "";
497 char config_last_mission[MISSION_NAME_LEN+1] = "";
498 char config_last_ctb_cfg[MAX_CTB_LEN] = "";
499 int config_last_ctb_tool;
500 ubyte Config_master_volume = 4;
501 ubyte Config_digi_volume = 8;
502 ubyte Config_midi_volume = 8;
503 ubyte Config_redbook_volume = 8;
504 ubyte Config_control_type = 0;
505 ubyte Config_channels_reversed = 0;
506 ubyte Config_joystick_sensitivity = 8;
507
508 int Config_vr_type = 0;
509 int Config_vr_resolution = 0;
510 int Config_vr_tracking = 0;
511
512 extern sbyte Object_complexity, Object_detail, Wall_detail, Wall_render_depth, Debris_amount, SoundChannels;
513 extern void digi_set_master_volume( int volume );
514
515 void set_custom_detail_vars(void);
516
517 static ubyte have_prefs = 0;
518
519 //¥     ------------------------------  Private Definitions
520 //¥     ------------------------------  Private Types
521
522 typedef struct
523 {
524         Str31   fileName;
525         OSType  creator;
526         OSType  fileType;
527         OSType  resType;
528         short   resID;
529 } PrefsInfo, *PrefsInfoPtr, **PrefsInfoHandle;
530
531 //¥     ------------------------------  Private Variables
532
533 static PrefsInfo                prefsInfo;
534 static Boolean          prefsInited = 0;
535
536 //¥     ------------------------------  Private Functions
537
538 static void Pstrcpy(StringPtr dst, StringPtr src);
539 static void Pstrcat(StringPtr dst, StringPtr src);
540 static Boolean FindPrefsFile(short *prefVRefNum, long *prefDirID);
541
542 //¥     --------------------    Pstrcpy
543
544 static void
545 Pstrcpy(StringPtr dst, StringPtr src)
546 {
547         BlockMove(src, dst, (*src) + 1);
548 }
549
550 //¥     --------------------    Pstrcat
551
552 static void
553 Pstrcat(StringPtr dst, StringPtr src)
554 {
555         BlockMove(src + 1, dst + (*dst) + 1, *src);
556         *dst += *src;
557 }
558
559 //¥     --------------------    FindPrefsFile
560
561 static Boolean
562 FindPrefsFile(short *prefVRefNum, long *prefDirID)
563 {
564 OSErr           theErr;
565 long                    response;
566 CInfoPBRec      infoPB;
567
568         if (! prefsInited)
569                 return (0);
570                 
571         theErr = Gestalt(gestaltFindFolderAttr, &response);
572         if (theErr == noErr && ((response >> gestaltFindFolderPresent) & 1))
573         {
574                 //¥     Find (or make) it the easy way...
575                 theErr = FindFolder(kOnSystemDisk, kPreferencesFolderType, kCreateFolder, prefVRefNum, prefDirID);
576         }
577         else
578         {
579         SysEnvRec       theSysEnv;
580         StringPtr               prefFolderName = "\pPreferences";
581
582                 //¥     yeachh -- we have to do it all by hand!
583                 theErr = SysEnvirons(1, &theSysEnv);
584                 if (theErr != noErr)
585                         return (0);
586                         
587                 *prefVRefNum = theSysEnv.sysVRefNum;
588                 
589                 //¥     Check whether Preferences folder already exists
590                 infoPB.hFileInfo.ioCompletion   = 0;
591                 infoPB.hFileInfo.ioNamePtr      = prefFolderName;
592                 infoPB.hFileInfo.ioVRefNum      = *prefVRefNum;
593                 infoPB.hFileInfo.ioFDirIndex    = 0;
594                 infoPB.hFileInfo.ioDirID                = 0;
595
596                 theErr = PBGetCatInfo(&infoPB, 0);
597                 if (theErr == noErr)
598                 {
599                         *prefDirID = infoPB.hFileInfo.ioDirID;
600                 }
601                 else if (theErr == fnfErr)              //¥     Preferences doesn't already exist
602                 {
603                 HParamBlockRec  dirPB;
604                 
605                         //¥     Create "Preferences" folder
606                         dirPB.fileParam.ioCompletion    = 0;
607                         dirPB.fileParam.ioVRefNum       = *prefVRefNum;
608                         dirPB.fileParam.ioNamePtr       = prefFolderName;
609                         dirPB.fileParam.ioDirID         = 0;
610
611                         theErr = PBDirCreate(&dirPB, 0);
612                         if (theErr == noErr)
613                                 *prefDirID = dirPB.fileParam.ioDirID;
614                 }
615         }
616         
617         //¥     If we make it here OK, create Preferences file if necessary
618         if (theErr == noErr)
619         {
620                 infoPB.hFileInfo.ioCompletion   = 0;
621                 infoPB.hFileInfo.ioNamePtr      = prefsInfo.fileName;
622                 infoPB.hFileInfo.ioVRefNum      = *prefVRefNum;
623                 infoPB.hFileInfo.ioFDirIndex    = 0;
624                 infoPB.hFileInfo.ioDirID                = *prefDirID;
625
626                 theErr = PBGetCatInfo(&infoPB, 0);
627                 if (theErr == fnfErr)
628                 {
629                         theErr = HCreate(*prefVRefNum, *prefDirID, prefsInfo.fileName, prefsInfo.creator, prefsInfo.fileType);
630                         if (theErr == noErr)
631                         {
632                                 HCreateResFile(*prefVRefNum, *prefDirID, prefsInfo.fileName);
633                                 theErr = ResError();
634                         }
635                 }
636         }
637         
638         return (theErr == noErr);
639 }
640
641 //¥     --------------------    InitPrefsFile
642
643 #define UNKNOWN_TYPE 0x3f3f3f3f
644
645 void
646 InitPrefsFile(OSType creator)
647 {
648         OSErr err;
649 PrefsInfoHandle         piHdl;
650         
651         if ((piHdl = (PrefsInfoHandle) GetResource('PRFI', 0)) == nil)
652         {
653         ProcessSerialNumber     thePSN;
654         ProcessInfoRec                  thePIR;
655         FSSpec                          appSpec;
656         StringPtr                       app_string;
657
658 #if 0   
659                 GetCurrentProcess(&thePSN);
660                 thePIR.processName = nil;
661                 thePIR.processAppSpec = &appSpec;
662                 
663                 //¥     Set default to 'ÇApplicationÈ Prefs', PREF 0
664                 err = GetProcessInformation(&thePSN, &thePIR);
665                 if (err)
666                         Int3();
667 #endif
668                 app_string = LMGetCurApName();
669 //              Pstrcpy(prefsInfo.fileName, appSpec.name);
670                 Pstrcpy(prefsInfo.fileName, app_string);
671                 Pstrcat(prefsInfo.fileName, "\p Preferences");
672                 
673                 //¥     Set creator to calling application's signature (should be able to
674                 //¥     Determine this automatically, but unable to for some reason)
675                 prefsInfo.creator = creator;
676                 prefsInfo.fileType = 'pref';
677                 prefsInfo.resType = 'pref';
678                 prefsInfo.resID = 0;
679         }
680         else
681         {
682                 //¥     Get Preferences file setup from PRFI 0
683                 BlockMove(*piHdl, &prefsInfo, sizeof (prefsInfo));
684                 ReleaseResource((Handle) piHdl);
685                 
686                 if (prefsInfo.creator == UNKNOWN_TYPE)
687                         prefsInfo.creator = creator;
688         }
689         
690         prefsInited = 1;
691 }
692
693 //¥     --------------------    LoadPrefsFile
694
695 OSErr
696 LoadPrefsFile(Handle prefsHdl)
697 {
698 short   prefVRefNum, prefRefNum;
699 long            prefDirID;
700 OSErr   theErr = noErr;
701 Handle  origHdl;
702 Size            prefSize, origSize;
703
704         if (prefsHdl == nil)
705                 return (nilHandleErr);
706
707         prefSize = GetHandleSize(prefsHdl);
708                 
709         if (! FindPrefsFile(&prefVRefNum, &prefDirID))
710                 return (fnfErr);
711
712         prefRefNum = HOpenResFile(prefVRefNum, prefDirID, prefsInfo.fileName, fsRdWrPerm);
713         if (prefRefNum == -1)
714                 return (ResError());
715         
716         //¥     Not finding the resource is not an error -- caller will use default data
717         if ((origHdl = Get1Resource(prefsInfo.resType, prefsInfo.resID)) != nil)
718         {
719                 origSize = GetHandleSize(origHdl);
720                 if (origSize > prefSize)                        //¥     Extend handle for extra stored data
721                         SetHandleSize(prefsHdl, origSize);
722
723                 BlockMove(*origHdl, *prefsHdl, origSize);
724                 ReleaseResource(origHdl);
725         }
726         
727         CloseResFile(prefRefNum);
728
729         if (theErr == noErr)
730                 theErr = ResError();
731         
732         return (theErr);
733 }
734
735 //¥     --------------------    SavePrefsFile
736
737 OSErr
738 SavePrefsFile(Handle prefHdl)
739 {
740 short   prefVRefNum, prefRefNum;
741 long            prefDirID;
742 Handle  origHdl = nil;
743 Size            origSize, prefSize;
744 OSErr   theErr = noErr;
745         
746         if (! FindPrefsFile(&prefVRefNum, &prefDirID))
747                 return (fnfErr);
748         
749         if (prefHdl == nil)
750                 return (nilHandleErr);
751
752         prefSize = GetHandleSize(prefHdl);
753
754         prefRefNum = HOpenResFile(prefVRefNum, prefDirID, prefsInfo.fileName, fsRdWrPerm);
755         if (prefRefNum == -1)
756                 return (ResError());
757                 
758         if ((origHdl = Get1Resource(prefsInfo.resType, prefsInfo.resID)) != nil)
759         {
760                 //¥     Overwrite existing preferences
761                 origSize = GetHandleSize(origHdl);
762                 if (prefSize > origSize)
763                         SetHandleSize(origHdl, prefSize);
764                         
765                 BlockMove(*prefHdl, *origHdl, prefSize);
766                 ChangedResource(origHdl);
767                 WriteResource(origHdl);
768                 ReleaseResource(origHdl);
769         }
770         else
771         {
772                 //¥     Store specified preferences for the first time
773                 AddResource(prefHdl, prefsInfo.resType, prefsInfo.resID, "\p");
774                 WriteResource(prefHdl);
775                 DetachResource(prefHdl);
776         }
777         
778         CloseResFile(prefRefNum);
779
780         if (theErr == noErr)
781                 theErr = ResError();
782         
783         return (theErr);
784 }
785
786 //¥     -------------------------------------------------------------------------------------------
787
788 /*
789
790         This module provides the ability to save and load a preferences file in the
791         Preferences folder in the System Folder.  An optional resource, PRFI 0,
792         is used to provide specifications for the preferences file (creator, etc.).
793
794         Three functions are provided:
795
796                 void InitPrefsFile(OSType creator)
797
798         This function will initialize the preferences file, that is, it will create
799         it in the appropriate place if it doesn't currently exist.  It should be
800         called with the creator code for the application.  Note that the creator
801         code specified in PRFI 0 (if any) will be used only if the creator code
802         passed to this function is '????'.  Without the PRFI 0 resource, the default
803         specifications are:
804
805         File Name: "{Application} Prefs" (i.e., the name of the app plus " Prefs"
806         Creator: the creator passed to InitPrefsFile
807         Type: 'PREF'
808         Pref Resource Type: 'PREF'
809         Pref Resource ID: 0
810
811         The PRFI 0 resource allows you to specify overrides for each of the above
812         values.  This is useful for development, since the application name might
813         go through changes, but the preferences file name is held constant.
814
815                 OSErr LoadPrefsFile(Handle prefsHndl)
816
817         This function will attempt to copy the data stored in the preferences
818         file to the given handle (which must be pre-allocated).  If the handle is too
819         small, then it will be enlarged.  If it is too large, it will not be resized.
820         The data in the preferences file (normally in PREF 0) will then be copied
821         into the handle.  If the preferences file did not exist, the original data
822         in the handle will not change.
823
824                 OSErr SavePrefsFile(Handle prefsHndl)
825
826         This function will attempt to save the given handle to the preferences
827         file.  Its contents will completely replace the previous data (normally
828         the PREF 0 resource).
829
830         In typical use, you will use InitPrefsFile once, then allocate a handle large
831         enough to contain your preferences data, and initialize it with default values.
832         Throughout the course of your program, the handle will undergo modification as
833         user preferences change.  You can use SavePrefsFile anytime to update the
834         preferences file, or wait until program exit to do so.
835
836 */
837
838 int ReadConfigFile()
839 {
840         int i;
841         OSErr err;
842         Handle prefs_handle;
843         Preferences *prefs;
844         char *p;
845         
846         if (!have_prefs) {                      // not initialized....get a handle to the preferences file
847                 InitPrefsFile('DCT2');
848                 have_prefs = 1;
849         }
850         
851         prefs_handle = NewHandleClear(sizeof(Preferences));             // new prefs handle
852         if (prefs_handle == NULL)
853                 return;
854                 
855         prefs = (Preferences *)(*prefs_handle);
856         err = LoadPrefsFile(prefs_handle);
857         if (err) {
858                 DisposeHandle(prefs_handle);
859                 return -1;
860         }
861
862         p = (char *)prefs;
863         for (i = 0; i < sizeof(Preferences); i++) {
864                 if (*p != 0)
865                         break;
866                 p++;
867         }
868         if ( i == sizeof(Preferences) )
869                 return -1;
870         
871         Config_digi_volume = prefs->digi_volume;
872         Config_midi_volume = prefs->midi_volume;
873         Config_master_volume = prefs->master_volume;
874         Config_redbook_volume = prefs->redbook_volume;
875         Config_channels_reversed = prefs->stereo_reverse;
876         gr_palette_set_gamma( (int)(prefs->gamma_level) );
877
878         Scanline_double = (int)prefs->pixel_double;
879         if ( PAEnabled )
880                 Scanline_double = 0;            // can't double with hardware acceleration
881                 
882         Detail_level = prefs->detail_level;
883         if (Detail_level == NUM_DETAIL_LEVELS-1) {
884                 Object_complexity = prefs->oc;
885                 Object_detail = prefs->od;
886                 Wall_detail = prefs->wd;
887                 Wall_render_depth = prefs->wrd;
888                 Debris_amount = prefs->da;
889                 SoundChannels = prefs->sc;
890                 set_custom_detail_vars();
891         }
892
893         strncpy( config_last_player, prefs->lastplayer, CALLSIGN_LEN );
894         p = strchr(config_last_player, '\n' );
895         if (p) *p = 0;
896         
897         strncpy(config_last_mission, prefs->lastmission, MISSION_NAME_LEN);
898         p = strchr(config_last_mission, '\n' );
899         if (p) *p = 0;
900
901         strcpy(config_last_ctb_cfg, prefs->ctb_config);
902         
903         if ( Config_digi_volume > 8 ) Config_digi_volume = 8;
904
905         if ( Config_midi_volume > 8 ) Config_midi_volume = 8;
906
907         joy_set_cal_vals( prefs->joy_axis_min, prefs->joy_axis_center, prefs->joy_axis_max);
908         digi_set_volume( (Config_digi_volume*256)/8, (Config_midi_volume*256)/8 );
909         digi_set_master_volume(Config_master_volume);
910         
911         gConfigInfo.mDoNotDisplayOptions = prefs->display_dialog;
912         gConfigInfo.mUse11kSounds = prefs->sound_11k;
913         gConfigInfo.mDisableSound = prefs->nosound;
914         gConfigInfo.mDisableMIDIMusic = prefs->nomidi;
915         gConfigInfo.mChangeResolution = prefs->change_resolution;
916         gConfigInfo.mDoNotPlayMovies = prefs->no_movies;
917         gConfigInfo.mGameMonitor = prefs->game_monitor;
918         gConfigInfo.mAcceleration = prefs->enable_rave;
919         gConfigInfo.mInputSprockets = prefs->enable_input_sprockets;
920         
921         DisposeHandle(prefs_handle);
922         return 0;
923 }
924
925 int WriteConfigFile()
926 {
927         OSErr err;
928         Handle prefs_handle;
929         Preferences *prefs;
930         
931         prefs_handle = NewHandleClear(sizeof(Preferences));             // new prefs handle
932         if (prefs_handle == NULL)
933                 return;
934                 
935         prefs = (Preferences *)(*prefs_handle);
936         
937         joy_get_cal_vals(prefs->joy_axis_min, prefs->joy_axis_center, prefs->joy_axis_max);
938         prefs->digi_volume = Config_digi_volume;
939         prefs->midi_volume = Config_midi_volume;
940         prefs->stereo_reverse = Config_channels_reversed;
941         prefs->detail_level = Detail_level;
942         if (Detail_level == NUM_DETAIL_LEVELS-1) {
943                 prefs->oc = Object_complexity;
944                 prefs->od = Object_detail;
945                 prefs->wd = Wall_detail;
946                 prefs->wrd = Wall_render_depth;
947                 prefs->da = Debris_amount;
948                 prefs->sc = SoundChannels;
949         }
950         prefs->gamma_level = (ubyte)gr_palette_get_gamma();
951
952         if ( !PAEnabled )
953                 prefs->pixel_double = (ubyte)Scanline_double;           // hmm..don't write this out if doing hardware accel.
954                 
955         strncpy( prefs->lastplayer, Players[Player_num].callsign, CALLSIGN_LEN );
956         strncpy( prefs->lastmission, config_last_mission, MISSION_NAME_LEN );
957         strcpy( prefs->ctb_config, config_last_ctb_cfg);
958         prefs->ctb_tool = config_last_ctb_tool;
959         prefs->master_volume = Config_master_volume;
960         prefs->display_dialog = gConfigInfo.mDoNotDisplayOptions;
961         prefs->change_resolution = gConfigInfo.mChangeResolution;
962         prefs->nosound = gConfigInfo.mDisableSound;
963         prefs->nomidi = gConfigInfo.mDisableMIDIMusic;
964         prefs->sound_11k = gConfigInfo.mUse11kSounds;
965         prefs->no_movies = gConfigInfo.mDoNotPlayMovies;
966         prefs->game_monitor = gConfigInfo.mGameMonitor;
967         prefs->redbook_volume = Config_redbook_volume;
968         prefs->enable_rave = gConfigInfo.mAcceleration;
969         prefs->enable_input_sprockets = gConfigInfo.mInputSprockets;
970
971         err = SavePrefsFile(prefs_handle);
972         DisposeHandle(prefs_handle);
973         return (int)err;
974 }
975
976 #endif
977