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