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