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