]> icculus.org git repositories - btb/d2x.git/blob - main/config.c
cfgets now always copies the terminating character to the dest buffer.
[btb/d2x.git] / main / config.c
1 /* $Id: config.c,v 1.12 2004-08-29 17:57:23 schaffner Exp $ */
2 /*
3 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
4 SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
5 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
6 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
7 IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
8 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
9 FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
10 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
11 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
12 COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
13 */
14
15 /*
16  *
17  * contains routine(s) to read in the configuration file which contains
18  * game configuration stuff like detail level, sound card, etc
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <conf.h>
24 #endif
25
26 #ifndef MACINTOSH                       // I'm going to totally seperate these routines -- yeeech!!!!
27                                                         // see end of file for macintosh equivs
28
29 #ifdef WINDOWS
30 #define WIN32_LEAN_AND_MEAN
31 #include <windows.h>
32 #include "winapp.h"
33 #else
34 #endif
35
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <ctype.h>
40
41 #include "pstypes.h"
42 #include "game.h"
43 #include "menu.h"
44 #include "movie.h"
45 #include "digi.h"
46 #include "kconfig.h"
47 #include "palette.h"
48 #include "joy.h"
49 #include "songs.h"
50 #include "args.h"
51 #include "player.h"
52 #include "mission.h"
53 #include "mono.h"
54 #include "pa_enabl.h"
55
56
57
58 #ifdef RCS
59 static char rcsid[] = "$Id: config.c,v 1.12 2004-08-29 17:57:23 schaffner Exp $";
60 #endif
61
62 ubyte Config_digi_volume = 8;
63 ubyte Config_midi_volume = 8;
64 ubyte Config_redbook_volume = 8;
65 ubyte Config_control_type = 0;
66 ubyte Config_channels_reversed = 0;
67 ubyte Config_joystick_sensitivity = 8;
68
69 #ifdef __MSDOS__
70 static char *digi_dev8_str = "DigiDeviceID8";
71 static char *digi_dev16_str = "DigiDeviceID16";
72 static char *digi_port_str = "DigiPort";
73 static char *digi_irq_str = "DigiIrq";
74 static char *digi_dma8_str = "DigiDma8";
75 static char *digi_dma16_str = "DigiDma16";
76 static char *midi_dev_str = "MidiDeviceID";
77 static char *midi_port_str = "MidiPort";
78
79 #define _CRYSTAL_LAKE_8_ST              0xe201
80 #define _CRYSTAL_LAKE_16_ST     0xe202
81 #define _AWE32_8_ST                             0xe208
82 #define _AWE32_16_ST                            0xe209
83 #endif
84 static char *digi_volume_str = "DigiVolume";
85 static char *midi_volume_str = "MidiVolume";
86 static char *redbook_enabled_str = "RedbookEnabled";
87 static char *redbook_volume_str = "RedbookVolume";
88 static char *detail_level_str = "DetailLevel";
89 static char *gamma_level_str = "GammaLevel";
90 static char *stereo_rev_str = "StereoReverse";
91 static char *joystick_min_str = "JoystickMin";
92 static char *joystick_max_str = "JoystickMax";
93 static char *joystick_cen_str = "JoystickCen";
94 static char *last_player_str = "LastPlayer";
95 static char *last_mission_str = "LastMission";
96 static char *config_vr_type_str = "VR_type";
97 static char *config_vr_resolution_str = "VR_resolution";
98 static char *config_vr_tracking_str = "VR_tracking";
99 static char *movie_hires_str = "MovieHires";
100
101 char config_last_player[CALLSIGN_LEN+1] = "";
102 char config_last_mission[MISSION_NAME_LEN+1] = "";
103
104 int Config_digi_type = 0;
105 int Config_digi_dma = 0;
106 int Config_midi_type = 0;
107
108 #ifdef WINDOWS
109 int      DOSJoySaveMin[4];
110 int      DOSJoySaveCen[4];
111 int      DOSJoySaveMax[4];
112
113 char win95_current_joyname[256];
114 #endif
115
116
117
118 int Config_vr_type = 0;
119 int Config_vr_resolution = 0;
120 int Config_vr_tracking = 0;
121
122 int digi_driver_board_16;
123 int digi_driver_dma_16;
124
125 extern sbyte Object_complexity, Object_detail, Wall_detail, Wall_render_depth, Debris_amount, SoundChannels;
126
127 void set_custom_detail_vars(void);
128
129
130 #define CL_MC0 0xF8F
131 #define CL_MC1 0xF8D
132 /*
133 void CrystalLakeWriteMCP( ushort mc_addr, ubyte mc_data )
134 {
135         _disable();
136         outp( CL_MC0, 0xE2 );                           // Write password
137         outp( mc_addr, mc_data );               // Write data
138         _enable();
139 }
140
141 ubyte CrystalLakeReadMCP( ushort mc_addr )
142 {
143         ubyte value;
144         _disable();
145         outp( CL_MC0, 0xE2 );           // Write password
146         value = inp( mc_addr );         // Read data
147         _enable();
148         return value;
149 }
150
151 void CrystalLakeSetSB()
152 {
153         ubyte tmp;
154         tmp = CrystalLakeReadMCP( CL_MC1 );
155         tmp &= 0x7F;
156         CrystalLakeWriteMCP( CL_MC1, tmp );
157 }
158
159 void CrystalLakeSetWSS()
160 {
161         ubyte tmp;
162         tmp = CrystalLakeReadMCP( CL_MC1 );
163         tmp |= 0x80;
164         CrystalLakeWriteMCP( CL_MC1, tmp );
165 }
166 */
167 //MovieHires might be changed by -nohighres, so save a "real" copy of it
168 int SaveMovieHires;
169 int save_redbook_enabled;
170
171 #ifdef WINDOWS
172 void CheckMovieAttributes()
173 {
174                 HKEY hKey;
175                 DWORD len, type, val;
176                 long lres;
177  
178                 lres = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Parallax\\Descent II\\1.1\\INSTALL",
179                                                         0, KEY_READ, &hKey);
180                 if (lres == ERROR_SUCCESS) {
181                         len = sizeof(val);
182                         lres = RegQueryValueEx(hKey, "HIRES", NULL, &type, &val, &len);
183                         if (lres == ERROR_SUCCESS) {
184                                 MovieHires = val;
185                                 logentry("HIRES=%d\n", val);
186                         }
187                         RegCloseKey(hKey);
188                 }
189 }
190 #endif
191
192
193
194 int ReadConfigFile()
195 {
196         CFILE *infile;
197         char line[80], *token, *value, *ptr;
198         ubyte gamma;
199         int joy_axis_min[7];
200         int joy_axis_center[7];
201         int joy_axis_max[7];
202         int i;
203
204         strcpy( config_last_player, "" );
205
206         joy_axis_min[0] = joy_axis_min[1] = joy_axis_min[2] = joy_axis_min[3] = 0;
207         joy_axis_max[0] = joy_axis_max[1] = joy_axis_max[2] = joy_axis_max[3] = 0;
208         joy_axis_center[0] = joy_axis_center[1] = joy_axis_center[2] = joy_axis_center[3] = 0;
209
210 #ifdef WINDOWS
211         memset(&joy_axis_min[0], 0, sizeof(int)*7);
212         memset(&joy_axis_max[0], 0, sizeof(int)*7);
213         memset(&joy_axis_center[0], 0, sizeof(int)*7);
214 //@@    joy_set_cal_vals(joy_axis_min, joy_axis_center, joy_axis_max);
215 #else
216         joy_set_cal_vals(joy_axis_min, joy_axis_center, joy_axis_max);
217 #endif
218
219         /*digi_driver_board = 0;
220         digi_driver_port = 0;
221         digi_driver_irq = 0;
222         digi_driver_dma = 0;
223
224         digi_midi_type = 0;
225         digi_midi_port = 0;*/
226
227         Config_digi_volume = 8;
228         Config_midi_volume = 8;
229         Config_redbook_volume = 8;
230         Config_control_type = 0;
231         Config_channels_reversed = 0;
232
233         //set these here in case no cfg file
234         SaveMovieHires = MovieHires;
235         save_redbook_enabled = Redbook_enabled;
236
237         infile = cfopen("descent.cfg", "rt");
238         if (infile == NULL) {
239                 WIN(CheckMovieAttributes());
240                 return 1;
241         }
242         while (!cfeof(infile))
243         {
244                 memset(line, 0, 80);
245                 cfgets(line, 80, infile);
246                 ptr = &(line[0]);
247                 while (isspace(*ptr))
248                         ptr++;
249                 if (*ptr != '\0') {
250                         token = strtok(ptr, "=");
251                         value = strtok(NULL, "=");
252 /*                      if (!strcmp(token, digi_dev8_str))
253                                 digi_driver_board = strtol(value, NULL, 16);
254                         else if (!strcmp(token, digi_dev16_str))
255                                 digi_driver_board_16 = strtol(value, NULL, 16);
256                         else if (!strcmp(token, digi_port_str))
257                                 digi_driver_port = strtol(value, NULL, 16);
258                         else if (!strcmp(token, digi_irq_str))
259                                 digi_driver_irq = strtol(value, NULL, 10);
260                         else if (!strcmp(token, digi_dma8_str))
261                                 digi_driver_dma = strtol(value, NULL, 10);
262                         else if (!strcmp(token, digi_dma16_str))
263                                 digi_driver_dma_16 = strtol(value, NULL, 10);
264                         else*/ if (!strcmp(token, digi_volume_str))
265                                 Config_digi_volume = strtol(value, NULL, 10);
266                         else/* if (!strcmp(token, midi_dev_str))
267                                 digi_midi_type = strtol(value, NULL, 16);
268                         else if (!strcmp(token, midi_port_str))
269                                 digi_midi_port = strtol(value, NULL, 16);
270                         else*/ if (!strcmp(token, midi_volume_str))
271                                 Config_midi_volume = strtol(value, NULL, 10);
272                         else if (!strcmp(token, redbook_enabled_str))
273                                 Redbook_enabled = save_redbook_enabled = strtol(value, NULL, 10);
274                         else if (!strcmp(token, redbook_volume_str))
275                                 Config_redbook_volume = strtol(value, NULL, 10);
276                         else if (!strcmp(token, stereo_rev_str))
277                                 Config_channels_reversed = strtol(value, NULL, 10);
278                         else if (!strcmp(token, gamma_level_str)) {
279                                 gamma = strtol(value, NULL, 10);
280                                 gr_palette_set_gamma( gamma );
281                         }
282                         else if (!strcmp(token, detail_level_str)) {
283                                 Detail_level = strtol(value, NULL, 10);
284                                 if (Detail_level == NUM_DETAIL_LEVELS-1) {
285                                         int count,dummy,oc,od,wd,wrd,da,sc;
286
287                                         count = sscanf (value, "%d,%d,%d,%d,%d,%d,%d\n",&dummy,&oc,&od,&wd,&wrd,&da,&sc);
288
289                                         if (count == 7) {
290                                                 Object_complexity = oc;
291                                                 Object_detail = od;
292                                                 Wall_detail = wd;
293                                                 Wall_render_depth = wrd;
294                                                 Debris_amount = da;
295                                                 SoundChannels = sc;
296                                                 set_custom_detail_vars();
297                                         }
298                                   #ifdef PA_3DFX_VOODOO   // Set to highest detail because you can't change em  
299                                            Object_complexity=Object_detail=Wall_detail=
300                                                 Wall_render_depth=Debris_amount=SoundChannels = NUM_DETAIL_LEVELS-1;
301                                                 Detail_level=NUM_DETAIL_LEVELS-1;
302                                                 set_custom_detail_vars();
303                                         #endif
304                                 }
305                         }
306                         else if (!strcmp(token, joystick_min_str))      {
307                                 sscanf( value, "%d,%d,%d,%d", &joy_axis_min[0], &joy_axis_min[1], &joy_axis_min[2], &joy_axis_min[3] );
308                         }
309                         else if (!strcmp(token, joystick_max_str))      {
310                                 sscanf( value, "%d,%d,%d,%d", &joy_axis_max[0], &joy_axis_max[1], &joy_axis_max[2], &joy_axis_max[3] );
311                         }
312                         else if (!strcmp(token, joystick_cen_str))      {
313                                 sscanf( value, "%d,%d,%d,%d", &joy_axis_center[0], &joy_axis_center[1], &joy_axis_center[2], &joy_axis_center[3] );
314                         }
315                         else if (!strcmp(token, last_player_str))       {
316                                 char * p;
317                                 strncpy( config_last_player, value, CALLSIGN_LEN );
318                                 p = strchr( config_last_player, '\n');
319                                 if ( p ) *p = 0;
320                         }
321                         else if (!strcmp(token, last_mission_str))      {
322                                 char * p;
323                                 strncpy( config_last_mission, value, MISSION_NAME_LEN );
324                                 p = strchr( config_last_mission, '\n');
325                                 if ( p ) *p = 0;
326                         } else if (!strcmp(token, config_vr_type_str)) {
327                                 Config_vr_type = strtol(value, NULL, 10);
328                         } else if (!strcmp(token, config_vr_resolution_str)) {
329                                 Config_vr_resolution = strtol(value, NULL, 10);
330                         } else if (!strcmp(token, config_vr_tracking_str)) {
331                                 Config_vr_tracking = strtol(value, NULL, 10);
332                         } else if (!strcmp(token, movie_hires_str)) {
333                                 SaveMovieHires = MovieHires = strtol(value, NULL, 10);
334                         }
335                 }
336         }
337
338         cfclose(infile);
339
340 #ifdef WINDOWS
341         for (i=0;i<4;i++)
342         {
343          DOSJoySaveMin[i]=joy_axis_min[i];
344          DOSJoySaveCen[i]=joy_axis_center[i];
345          DOSJoySaveMax[i]=joy_axis_max[i];
346         }
347 #else
348         joy_set_cal_vals(joy_axis_min, joy_axis_center, joy_axis_max);
349 #endif
350
351         i = FindArg( "-volume" );
352         
353         if ( i > 0 )    {
354                 i = atoi( Args[i+1] );
355                 if ( i < 0 ) i = 0;
356                 if ( i > 100 ) i = 100;
357                 Config_digi_volume = (i*8)/100;
358                 Config_midi_volume = (i*8)/100;
359                 Config_redbook_volume = (i*8)/100;
360         }
361
362         if ( Config_digi_volume > 8 ) Config_digi_volume = 8;
363         if ( Config_midi_volume > 8 ) Config_midi_volume = 8;
364         if ( Config_redbook_volume > 8 ) Config_redbook_volume = 8;
365
366         digi_set_volume( (Config_digi_volume*32768)/8, (Config_midi_volume*128)/8 );
367 /*
368         printf( "DigiDeviceID: 0x%x\n", digi_driver_board );
369         printf( "DigiPort: 0x%x\n", digi_driver_port            );
370         printf( "DigiIrq: 0x%x\n",  digi_driver_irq             );
371         printf( "DigiDma: 0x%x\n",      digi_driver_dma );
372         printf( "MidiDeviceID: 0x%x\n", digi_midi_type  );
373         printf( "MidiPort: 0x%x\n", digi_midi_port              );
374         key_getch();
375 */
376
377         /*Config_midi_type = digi_midi_type;
378         Config_digi_type = digi_driver_board;
379         Config_digi_dma = digi_driver_dma;*/
380
381 #if 0
382         if (digi_driver_board_16 > 0 && !FindArg("-no16bit") && digi_driver_board_16 != _GUS_16_ST) {
383                 digi_driver_board = digi_driver_board_16;
384                 digi_driver_dma = digi_driver_dma_16;
385         }
386
387         // HACK!!!
388         //Hack to make some cards look like others, such as
389         //the Crytal Lake look like Microsoft Sound System
390         if ( digi_driver_board == _CRYSTAL_LAKE_8_ST )  {
391                 ubyte tmp;
392                 tmp = CrystalLakeReadMCP( CL_MC1 );
393                 if ( !(tmp & 0x80) )
394                         atexit( CrystalLakeSetSB );             // Restore to SB when done.
395                 CrystalLakeSetWSS();
396                 digi_driver_board = _MICROSOFT_8_ST;
397         } else if ( digi_driver_board == _CRYSTAL_LAKE_16_ST )  {
398                 ubyte tmp;
399                 tmp = CrystalLakeReadMCP( CL_MC1 );
400                 if ( !(tmp & 0x80) )
401                         atexit( CrystalLakeSetSB );             // Restore to SB when done.
402                 CrystalLakeSetWSS();
403                 digi_driver_board = _MICROSOFT_16_ST;
404         } else if ( digi_driver_board == _AWE32_8_ST )  {
405                 digi_driver_board = _SB16_8_ST;
406         } else if ( digi_driver_board == _AWE32_16_ST ) {
407                 digi_driver_board = _SB16_16_ST;
408         } else
409                 digi_driver_board               = digi_driver_board;
410 #else
411         infile = cfopen("descentw.cfg", "rt");
412         if (infile) {
413                 while (!cfeof(infile))
414                 {
415                         memset(line, 0, 80);
416                         cfgets(line, 80, infile);
417                         ptr = &(line[0]);
418                         while (isspace(*ptr))
419                                 ptr++;
420                         if (*ptr != '\0') {
421                                 token = strtok(ptr, "=");
422                                 value = strtok(NULL, "=");
423                                 if (!strcmp(token, joystick_min_str))   {
424                                         sscanf( value, "%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] );
425                                 }
426                                 else if (!strcmp(token, joystick_max_str))      {
427                                         sscanf( value, "%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] );
428                                 }
429                                 else if (!strcmp(token, joystick_cen_str))      {
430                                         sscanf( value, "%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] );
431                                 }
432                         }
433                 }
434                 cfclose(infile);
435         }
436 #endif
437
438         return 0;
439 }
440
441 int WriteConfigFile()
442 {
443         CFILE *infile;
444         char str[256];
445         int joy_axis_min[7];
446         int joy_axis_center[7];
447         int joy_axis_max[7];
448         ubyte gamma = gr_palette_get_gamma();
449         
450         joy_get_cal_vals(joy_axis_min, joy_axis_center, joy_axis_max);
451
452 #ifdef WINDOWS
453         for (i=0;i<4;i++)
454    {
455          joy_axis_min[i]=DOSJoySaveMin[i];
456          joy_axis_center[i]=DOSJoySaveCen[i];
457          joy_axis_max[i]=DOSJoySaveMax[i];
458    }
459 #endif
460
461         infile = cfopen("descent.cfg", "wt");
462         if (infile == NULL) {
463                 return 1;
464         }
465         /*sprintf (str, "%s=0x%x\n", digi_dev8_str, Config_digi_type);
466         cfputs(str, infile);
467         sprintf (str, "%s=0x%x\n", digi_dev16_str, digi_driver_board_16);
468         cfputs(str, infile);
469         sprintf (str, "%s=0x%x\n", digi_port_str, digi_driver_port);
470         cfputs(str, infile);
471         sprintf (str, "%s=%d\n", digi_irq_str, digi_driver_irq);
472         cfputs(str, infile);
473         sprintf (str, "%s=%d\n", digi_dma8_str, Config_digi_dma);
474         cfputs(str, infile);
475         sprintf (str, "%s=%d\n", digi_dma16_str, digi_driver_dma_16);
476         cfputs(str, infile);*/
477         sprintf (str, "%s=%d\n", digi_volume_str, Config_digi_volume);
478         cfputs(str, infile);
479         /*sprintf (str, "%s=0x%x\n", midi_dev_str, Config_midi_type);
480         cfputs(str, infile);
481         sprintf (str, "%s=0x%x\n", midi_port_str, digi_midi_port);
482         cfputs(str, infile);*/
483         sprintf (str, "%s=%d\n", midi_volume_str, Config_midi_volume);
484         cfputs(str, infile);
485         sprintf (str, "%s=%d\n", redbook_enabled_str, FindArg("-noredbook")?save_redbook_enabled:Redbook_enabled);
486         cfputs(str, infile);
487         sprintf (str, "%s=%d\n", redbook_volume_str, Config_redbook_volume);
488         cfputs(str, infile);
489         sprintf (str, "%s=%d\n", stereo_rev_str, Config_channels_reversed);
490         cfputs(str, infile);
491         sprintf (str, "%s=%d\n", gamma_level_str, gamma);
492         cfputs(str, infile);
493         if (Detail_level == NUM_DETAIL_LEVELS-1)
494                 sprintf (str, "%s=%d,%d,%d,%d,%d,%d,%d\n", detail_level_str, Detail_level,
495                                 Object_complexity,Object_detail,Wall_detail,Wall_render_depth,Debris_amount,SoundChannels);
496         else
497                 sprintf (str, "%s=%d\n", detail_level_str, Detail_level);
498         cfputs(str, infile);
499
500         sprintf (str, "%s=%d,%d,%d,%d\n", joystick_min_str, joy_axis_min[0], joy_axis_min[1], joy_axis_min[2], joy_axis_min[3] );
501         cfputs(str, infile);
502         sprintf (str, "%s=%d,%d,%d,%d\n", joystick_cen_str, joy_axis_center[0], joy_axis_center[1], joy_axis_center[2], joy_axis_center[3] );
503         cfputs(str, infile);
504         sprintf (str, "%s=%d,%d,%d,%d\n", joystick_max_str, joy_axis_max[0], joy_axis_max[1], joy_axis_max[2], joy_axis_max[3] );
505         cfputs(str, infile);
506
507         sprintf (str, "%s=%s\n", last_player_str, Players[Player_num].callsign );
508         cfputs(str, infile);
509         sprintf (str, "%s=%s\n", last_mission_str, config_last_mission );
510         cfputs(str, infile);
511         sprintf (str, "%s=%d\n", config_vr_type_str, Config_vr_type );
512         cfputs(str, infile);
513         sprintf (str, "%s=%d\n", config_vr_resolution_str, Config_vr_resolution );
514         cfputs(str, infile);
515         sprintf (str, "%s=%d\n", config_vr_tracking_str, Config_vr_tracking );
516         cfputs(str, infile);
517         sprintf (str, "%s=%d\n", movie_hires_str, (FindArg("-nohires") || FindArg("-nohighres") || FindArg("-lowresmovies"))?SaveMovieHires:MovieHires);
518         cfputs(str, infile);
519
520         cfclose(infile);
521
522 #ifdef WINDOWS
523 {
524 //      Save Windows Config File
525         char joyname[256];
526                                                 
527
528         joy_get_cal_vals(joy_axis_min, joy_axis_center, joy_axis_max);
529         
530         infile = cfopen("descentw.cfg", "wt");
531         if (infile == NULL) return 1;
532
533         sprintf(str, "%s=%d,%d,%d,%d,%d,%d,%d\n", joystick_min_str,
534                         joy_axis_min[0], joy_axis_min[1], joy_axis_min[2], joy_axis_min[3],
535                         joy_axis_min[4], joy_axis_min[5], joy_axis_min[6]);
536         cfputs(str, infile);
537         sprintf(str, "%s=%d,%d,%d,%d,%d,%d,%d\n", joystick_cen_str,
538                         joy_axis_center[0], joy_axis_center[1], joy_axis_center[2], joy_axis_center[3],
539                         joy_axis_center[4], joy_axis_center[5], joy_axis_center[6]);
540         cfputs(str, infile);
541         sprintf(str, "%s=%d,%d,%d,%d,%d,%d,%d\n", joystick_max_str,
542                         joy_axis_max[0], joy_axis_max[1], joy_axis_max[2], joy_axis_max[3],
543                         joy_axis_max[4], joy_axis_max[5], joy_axis_max[6]);
544         cfputs(str, infile);
545
546         cfclose(infile);
547 }
548         CheckMovieAttributes();
549 #endif
550
551         return 0;
552 }               
553
554 #else           // !defined(MACINTOSH)
555
556 #include <stdio.h>
557 #include <stdlib.h>
558 #include <string.h>
559 #include <ctype.h>
560
561 #include <Memory.h>
562 #include <Folders.h>
563 #include <GestaltEqu.h>
564 #include <Errors.h>
565 #include <Processes.h>
566 #include <Resources.h>
567 #include <LowMem.h>
568
569 #include "pa_enabl.h"           // because some prefs rely on this fact
570 #include "error.h"
571 #include "pstypes.h"
572 #include "game.h"
573 #include "digi.h"
574 #include "kconfig.h"
575 #include "palette.h"
576 #include "joy.h"
577 #include "args.h"
578 #include "player.h"
579 #include "mission.h"
580 #include "prefs.h"                      // prefs file for configuration stuff -- from DeSalvo
581
582 #if defined(POLY_ACC)
583 #include "poly_acc.h"
584 #endif
585
586 #ifdef RCS
587 static char rcsid[] = "$Id: config.c,v 1.12 2004-08-29 17:57:23 schaffner Exp $";
588 #endif
589
590 #define MAX_CTB_LEN     512
591
592 typedef struct preferences {
593         ubyte   digi_volume;
594         ubyte   midi_volume;
595         ubyte   stereo_reverse;
596         ubyte   detail_level;
597         ubyte   oc;                                     // object complexity
598         ubyte   od;                                     // object detail
599         ubyte   wd;                                     // wall detail
600         ubyte   wrd;                            // wall render depth
601         ubyte   da;                                     // debris amount
602         ubyte   sc;                                     // sound channels
603         ubyte   gamma_level;
604         ubyte   pixel_double;
605         int             joy_axis_min[4];
606         int             joy_axis_max[4];
607         int             joy_axis_center[4];
608         char    lastplayer[CALLSIGN_LEN+1];
609         char    lastmission[MISSION_NAME_LEN+1];
610         char    ctb_config[MAX_CTB_LEN];
611         int             ctb_tool;
612         ubyte   master_volume;
613         ubyte   display_dialog;
614         ubyte   change_resolution;
615         ubyte   nosound;
616         ubyte   nomidi;
617         ubyte   sound_11k;
618         ubyte   no_movies;
619         ubyte   game_monitor;
620         ubyte   redbook_volume;
621         ubyte   enable_rave;
622         ubyte   enable_input_sprockets;
623 } Preferences;
624
625 char config_last_player[CALLSIGN_LEN+1] = "";
626 char config_last_mission[MISSION_NAME_LEN+1] = "";
627 char config_last_ctb_cfg[MAX_CTB_LEN] = "";
628 int config_last_ctb_tool;
629 ubyte Config_master_volume = 4;
630 ubyte Config_digi_volume = 8;
631 ubyte Config_midi_volume = 8;
632 ubyte Config_redbook_volume = 8;
633 ubyte Config_control_type = 0;
634 ubyte Config_channels_reversed = 0;
635 ubyte Config_joystick_sensitivity = 8;
636
637 int Config_vr_type = 0;
638 int Config_vr_resolution = 0;
639 int Config_vr_tracking = 0;
640
641 extern sbyte Object_complexity, Object_detail, Wall_detail, Wall_render_depth, Debris_amount, SoundChannels;
642 extern void digi_set_master_volume( int volume );
643
644 void set_custom_detail_vars(void);
645
646 static ubyte have_prefs = 0;
647
648 //¥     ------------------------------  Private Definitions
649 //¥     ------------------------------  Private Types
650
651 typedef struct
652 {
653         Str31   fileName;
654         OSType  creator;
655         OSType  fileType;
656         OSType  resType;
657         short   resID;
658 } PrefsInfo, *PrefsInfoPtr, **PrefsInfoHandle;
659
660 //¥     ------------------------------  Private Variables
661
662 static PrefsInfo                prefsInfo;
663 static Boolean          prefsInited = 0;
664
665 //¥     ------------------------------  Private Functions
666
667 static void Pstrcpy(StringPtr dst, StringPtr src);
668 static void Pstrcat(StringPtr dst, StringPtr src);
669 static Boolean FindPrefsFile(short *prefVRefNum, long *prefDirID);
670
671 //¥     --------------------    Pstrcpy
672
673 static void
674 Pstrcpy(StringPtr dst, StringPtr src)
675 {
676         BlockMove(src, dst, (*src) + 1);
677 }
678
679 //¥     --------------------    Pstrcat
680
681 static void
682 Pstrcat(StringPtr dst, StringPtr src)
683 {
684         BlockMove(src + 1, dst + (*dst) + 1, *src);
685         *dst += *src;
686 }
687
688 //¥     --------------------    FindPrefsFile
689
690 static Boolean
691 FindPrefsFile(short *prefVRefNum, long *prefDirID)
692 {
693 OSErr           theErr;
694 long                    response;
695 CInfoPBRec      infoPB;
696
697         if (! prefsInited)
698                 return (0);
699                 
700         theErr = Gestalt(gestaltFindFolderAttr, &response);
701         if (theErr == noErr && ((response >> gestaltFindFolderPresent) & 1))
702         {
703                 //¥     Find (or make) it the easy way...
704                 theErr = FindFolder(kOnSystemDisk, kPreferencesFolderType, kCreateFolder, prefVRefNum, prefDirID);
705         }
706         else
707         {
708         SysEnvRec       theSysEnv;
709         StringPtr               prefFolderName = "\pPreferences";
710
711                 //¥     yeachh -- we have to do it all by hand!
712                 theErr = SysEnvirons(1, &theSysEnv);
713                 if (theErr != noErr)
714                         return (0);
715                         
716                 *prefVRefNum = theSysEnv.sysVRefNum;
717                 
718                 //¥     Check whether Preferences folder already exists
719                 infoPB.hFileInfo.ioCompletion   = 0;
720                 infoPB.hFileInfo.ioNamePtr      = prefFolderName;
721                 infoPB.hFileInfo.ioVRefNum      = *prefVRefNum;
722                 infoPB.hFileInfo.ioFDirIndex    = 0;
723                 infoPB.hFileInfo.ioDirID                = 0;
724
725                 theErr = PBGetCatInfo(&infoPB, 0);
726                 if (theErr == noErr)
727                 {
728                         *prefDirID = infoPB.hFileInfo.ioDirID;
729                 }
730                 else if (theErr == fnfErr)              //¥     Preferences doesn't already exist
731                 {
732                 HParamBlockRec  dirPB;
733                 
734                         //¥     Create "Preferences" folder
735                         dirPB.fileParam.ioCompletion    = 0;
736                         dirPB.fileParam.ioVRefNum       = *prefVRefNum;
737                         dirPB.fileParam.ioNamePtr       = prefFolderName;
738                         dirPB.fileParam.ioDirID         = 0;
739
740                         theErr = PBDirCreate(&dirPB, 0);
741                         if (theErr == noErr)
742                                 *prefDirID = dirPB.fileParam.ioDirID;
743                 }
744         }
745         
746         //¥     If we make it here OK, create Preferences file if necessary
747         if (theErr == noErr)
748         {
749                 infoPB.hFileInfo.ioCompletion   = 0;
750                 infoPB.hFileInfo.ioNamePtr      = prefsInfo.fileName;
751                 infoPB.hFileInfo.ioVRefNum      = *prefVRefNum;
752                 infoPB.hFileInfo.ioFDirIndex    = 0;
753                 infoPB.hFileInfo.ioDirID                = *prefDirID;
754
755                 theErr = PBGetCatInfo(&infoPB, 0);
756                 if (theErr == fnfErr)
757                 {
758                         theErr = HCreate(*prefVRefNum, *prefDirID, prefsInfo.fileName, prefsInfo.creator, prefsInfo.fileType);
759                         if (theErr == noErr)
760                         {
761                                 HCreateResFile(*prefVRefNum, *prefDirID, prefsInfo.fileName);
762                                 theErr = ResError();
763                         }
764                 }
765         }
766         
767         return (theErr == noErr);
768 }
769
770 //¥     --------------------    InitPrefsFile
771
772 #define UNKNOWN_TYPE 0x3f3f3f3f
773
774 void
775 InitPrefsFile(OSType creator)
776 {
777         OSErr err;
778 PrefsInfoHandle         piHdl;
779         
780         if ((piHdl = (PrefsInfoHandle) GetResource('PRFI', 0)) == nil)
781         {
782         ProcessSerialNumber     thePSN;
783         ProcessInfoRec                  thePIR;
784         FSSpec                          appSpec;
785         StringPtr                       app_string;
786
787 #if 0   
788                 GetCurrentProcess(&thePSN);
789                 thePIR.processName = nil;
790                 thePIR.processAppSpec = &appSpec;
791                 
792                 //¥     Set default to 'ÇApplicationÈ Prefs', PREF 0
793                 err = GetProcessInformation(&thePSN, &thePIR);
794                 if (err)
795                         Int3();
796 #endif
797                 app_string = LMGetCurApName();
798 //              Pstrcpy(prefsInfo.fileName, appSpec.name);
799                 Pstrcpy(prefsInfo.fileName, app_string);
800                 Pstrcat(prefsInfo.fileName, "\p Preferences");
801                 
802                 //¥     Set creator to calling application's signature (should be able to
803                 //¥     Determine this automatically, but unable to for some reason)
804                 prefsInfo.creator = creator;
805                 prefsInfo.fileType = 'pref';
806                 prefsInfo.resType = 'pref';
807                 prefsInfo.resID = 0;
808         }
809         else
810         {
811                 //¥     Get Preferences file setup from PRFI 0
812                 BlockMove(*piHdl, &prefsInfo, sizeof (prefsInfo));
813                 ReleaseResource((Handle) piHdl);
814                 
815                 if (prefsInfo.creator == UNKNOWN_TYPE)
816                         prefsInfo.creator = creator;
817         }
818         
819         prefsInited = 1;
820 }
821
822 //¥     --------------------    LoadPrefsFile
823
824 OSErr
825 LoadPrefsFile(Handle prefsHdl)
826 {
827 short   prefVRefNum, prefRefNum;
828 long            prefDirID;
829 OSErr   theErr = noErr;
830 Handle  origHdl;
831 Size            prefSize, origSize;
832
833         if (prefsHdl == nil)
834                 return (nilHandleErr);
835
836         prefSize = GetHandleSize(prefsHdl);
837                 
838         if (! FindPrefsFile(&prefVRefNum, &prefDirID))
839                 return (fnfErr);
840
841         prefRefNum = HOpenResFile(prefVRefNum, prefDirID, prefsInfo.fileName, fsRdWrPerm);
842         if (prefRefNum == -1)
843                 return (ResError());
844         
845         //¥     Not finding the resource is not an error -- caller will use default data
846         if ((origHdl = Get1Resource(prefsInfo.resType, prefsInfo.resID)) != nil)
847         {
848                 origSize = GetHandleSize(origHdl);
849                 if (origSize > prefSize)                        //¥     Extend handle for extra stored data
850                         SetHandleSize(prefsHdl, origSize);
851
852                 BlockMove(*origHdl, *prefsHdl, origSize);
853                 ReleaseResource(origHdl);
854         }
855         
856         CloseResFile(prefRefNum);
857
858         if (theErr == noErr)
859                 theErr = ResError();
860         
861         return (theErr);
862 }
863
864 //¥     --------------------    SavePrefsFile
865
866 OSErr
867 SavePrefsFile(Handle prefHdl)
868 {
869 short   prefVRefNum, prefRefNum;
870 long            prefDirID;
871 Handle  origHdl = nil;
872 Size            origSize, prefSize;
873 OSErr   theErr = noErr;
874         
875         if (! FindPrefsFile(&prefVRefNum, &prefDirID))
876                 return (fnfErr);
877         
878         if (prefHdl == nil)
879                 return (nilHandleErr);
880
881         prefSize = GetHandleSize(prefHdl);
882
883         prefRefNum = HOpenResFile(prefVRefNum, prefDirID, prefsInfo.fileName, fsRdWrPerm);
884         if (prefRefNum == -1)
885                 return (ResError());
886                 
887         if ((origHdl = Get1Resource(prefsInfo.resType, prefsInfo.resID)) != nil)
888         {
889                 //¥     Overwrite existing preferences
890                 origSize = GetHandleSize(origHdl);
891                 if (prefSize > origSize)
892                         SetHandleSize(origHdl, prefSize);
893                         
894                 BlockMove(*prefHdl, *origHdl, prefSize);
895                 ChangedResource(origHdl);
896                 WriteResource(origHdl);
897                 ReleaseResource(origHdl);
898         }
899         else
900         {
901                 //¥     Store specified preferences for the first time
902                 AddResource(prefHdl, prefsInfo.resType, prefsInfo.resID, "\p");
903                 WriteResource(prefHdl);
904                 DetachResource(prefHdl);
905         }
906         
907         CloseResFile(prefRefNum);
908
909         if (theErr == noErr)
910                 theErr = ResError();
911         
912         return (theErr);
913 }
914
915 //¥     -------------------------------------------------------------------------------------------
916
917 /*
918
919         This module provides the ability to save and load a preferences file in the
920         Preferences folder in the System Folder.  An optional resource, PRFI 0,
921         is used to provide specifications for the preferences file (creator, etc.).
922
923         Three functions are provided:
924
925                 void InitPrefsFile(OSType creator)
926
927         This function will initialize the preferences file, that is, it will create
928         it in the appropriate place if it doesn't currently exist.  It should be
929         called with the creator code for the application.  Note that the creator
930         code specified in PRFI 0 (if any) will be used only if the creator code
931         passed to this function is '????'.  Without the PRFI 0 resource, the default
932         specifications are:
933
934         File Name: "{Application} Prefs" (i.e., the name of the app plus " Prefs"
935         Creator: the creator passed to InitPrefsFile
936         Type: 'PREF'
937         Pref Resource Type: 'PREF'
938         Pref Resource ID: 0
939
940         The PRFI 0 resource allows you to specify overrides for each of the above
941         values.  This is useful for development, since the application name might
942         go through changes, but the preferences file name is held constant.
943
944                 OSErr LoadPrefsFile(Handle prefsHndl)
945
946         This function will attempt to copy the data stored in the preferences
947         file to the given handle (which must be pre-allocated).  If the handle is too
948         small, then it will be enlarged.  If it is too large, it will not be resized.
949         The data in the preferences file (normally in PREF 0) will then be copied
950         into the handle.  If the preferences file did not exist, the original data
951         in the handle will not change.
952
953                 OSErr SavePrefsFile(Handle prefsHndl)
954
955         This function will attempt to save the given handle to the preferences
956         file.  Its contents will completely replace the previous data (normally
957         the PREF 0 resource).
958
959         In typical use, you will use InitPrefsFile once, then allocate a handle large
960         enough to contain your preferences data, and initialize it with default values.
961         Throughout the course of your program, the handle will undergo modification as
962         user preferences change.  You can use SavePrefsFile anytime to update the
963         preferences file, or wait until program exit to do so.
964
965 */
966
967 int ReadConfigFile()
968 {
969         int i;
970         OSErr err;
971         Handle prefs_handle;
972         Preferences *prefs;
973         char *p;
974         
975         if (!have_prefs) {                      // not initialized....get a handle to the preferences file
976                 InitPrefsFile('DCT2');
977                 have_prefs = 1;
978         }
979         
980         prefs_handle = NewHandleClear(sizeof(Preferences));             // new prefs handle
981         if (prefs_handle == NULL)
982                 return;
983                 
984         prefs = (Preferences *)(*prefs_handle);
985         err = LoadPrefsFile(prefs_handle);
986         if (err) {
987                 DisposeHandle(prefs_handle);
988                 return -1;
989         }
990
991         p = (char *)prefs;
992         for (i = 0; i < sizeof(Preferences); i++) {
993                 if (*p != 0)
994                         break;
995                 p++;
996         }
997         if ( i == sizeof(Preferences) )
998                 return -1;
999         
1000         Config_digi_volume = prefs->digi_volume;
1001         Config_midi_volume = prefs->midi_volume;
1002         Config_master_volume = prefs->master_volume;
1003         Config_redbook_volume = prefs->redbook_volume;
1004         Config_channels_reversed = prefs->stereo_reverse;
1005         gr_palette_set_gamma( (int)(prefs->gamma_level) );
1006
1007         Scanline_double = (int)prefs->pixel_double;
1008         if ( PAEnabled )
1009                 Scanline_double = 0;            // can't double with hardware acceleration
1010                 
1011         Detail_level = prefs->detail_level;
1012         if (Detail_level == NUM_DETAIL_LEVELS-1) {
1013                 Object_complexity = prefs->oc;
1014                 Object_detail = prefs->od;
1015                 Wall_detail = prefs->wd;
1016                 Wall_render_depth = prefs->wrd;
1017                 Debris_amount = prefs->da;
1018                 SoundChannels = prefs->sc;
1019                 set_custom_detail_vars();
1020         }
1021   #ifdef PA_3DFX_VOODOO   // Set to highest detail because you can't change em  
1022                    Object_complexity=Object_detail=Wall_detail=
1023                         Wall_render_depth=Debris_amount=SoundChannels = NUM_DETAIL_LEVELS-1;
1024                         Detail_level=NUM_DETAIL_LEVELS-1;
1025                         set_custom_detail_vars();
1026   #endif
1027
1028         strncpy( config_last_player, prefs->lastplayer, CALLSIGN_LEN );
1029         p = strchr(config_last_player, '\n' );
1030         if (p) *p = 0;
1031         
1032         strncpy(config_last_mission, prefs->lastmission, MISSION_NAME_LEN);
1033         p = strchr(config_last_mission, '\n' );
1034         if (p) *p = 0;
1035
1036         strcpy(config_last_ctb_cfg, prefs->ctb_config);
1037         
1038         if ( Config_digi_volume > 8 ) Config_digi_volume = 8;
1039
1040         if ( Config_midi_volume > 8 ) Config_midi_volume = 8;
1041
1042         joy_set_cal_vals( prefs->joy_axis_min, prefs->joy_axis_center, prefs->joy_axis_max);
1043         digi_set_volume( (Config_digi_volume*256)/8, (Config_midi_volume*256)/8 );
1044         digi_set_master_volume(Config_master_volume);
1045         
1046         gConfigInfo.mDoNotDisplayOptions = prefs->display_dialog;
1047         gConfigInfo.mUse11kSounds = prefs->sound_11k;
1048         gConfigInfo.mDisableSound = prefs->nosound;
1049         gConfigInfo.mDisableMIDIMusic = prefs->nomidi;
1050         gConfigInfo.mChangeResolution = prefs->change_resolution;
1051         gConfigInfo.mDoNotPlayMovies = prefs->no_movies;
1052         gConfigInfo.mGameMonitor = prefs->game_monitor;
1053         gConfigInfo.mAcceleration = prefs->enable_rave;
1054         gConfigInfo.mInputSprockets = prefs->enable_input_sprockets;
1055         
1056         DisposeHandle(prefs_handle);
1057         return 0;
1058 }
1059
1060 int WriteConfigFile()
1061 {
1062         OSErr err;
1063         Handle prefs_handle;
1064         Preferences *prefs;
1065         
1066         prefs_handle = NewHandleClear(sizeof(Preferences));             // new prefs handle
1067         if (prefs_handle == NULL)
1068                 return;
1069                 
1070         prefs = (Preferences *)(*prefs_handle);
1071         
1072         joy_get_cal_vals(prefs->joy_axis_min, prefs->joy_axis_center, prefs->joy_axis_max);
1073         prefs->digi_volume = Config_digi_volume;
1074         prefs->midi_volume = Config_midi_volume;
1075         prefs->stereo_reverse = Config_channels_reversed;
1076         prefs->detail_level = Detail_level;
1077         if (Detail_level == NUM_DETAIL_LEVELS-1) {
1078                 prefs->oc = Object_complexity;
1079                 prefs->od = Object_detail;
1080                 prefs->wd = Wall_detail;
1081                 prefs->wrd = Wall_render_depth;
1082                 prefs->da = Debris_amount;
1083                 prefs->sc = SoundChannels;
1084         }
1085         prefs->gamma_level = (ubyte)gr_palette_get_gamma();
1086
1087         if ( !PAEnabled )
1088                 prefs->pixel_double = (ubyte)Scanline_double;           // hmm..don't write this out if doing hardware accel.
1089                 
1090         strncpy( prefs->lastplayer, Players[Player_num].callsign, CALLSIGN_LEN );
1091         strncpy( prefs->lastmission, config_last_mission, MISSION_NAME_LEN );
1092         strcpy( prefs->ctb_config, config_last_ctb_cfg);
1093         prefs->ctb_tool = config_last_ctb_tool;
1094         prefs->master_volume = Config_master_volume;
1095         prefs->display_dialog = gConfigInfo.mDoNotDisplayOptions;
1096         prefs->change_resolution = gConfigInfo.mChangeResolution;
1097         prefs->nosound = gConfigInfo.mDisableSound;
1098         prefs->nomidi = gConfigInfo.mDisableMIDIMusic;
1099         prefs->sound_11k = gConfigInfo.mUse11kSounds;
1100         prefs->no_movies = gConfigInfo.mDoNotPlayMovies;
1101         prefs->game_monitor = gConfigInfo.mGameMonitor;
1102         prefs->redbook_volume = Config_redbook_volume;
1103         prefs->enable_rave = gConfigInfo.mAcceleration;
1104         prefs->enable_input_sprockets = gConfigInfo.mInputSprockets;
1105
1106         err = SavePrefsFile(prefs_handle);
1107         DisposeHandle(prefs_handle);
1108         return (int)err;
1109 }
1110
1111 #endif
1112