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