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