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