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