1 /* $Id: playsave.c,v 1.12 2003/04/12 00:11:46 btb 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  * Functions to load & save player games
18  *
19  * Old Log:
20  * Revision 1.1  1995/12/05  16:05:47  allender
21  * Initial revision
22  *
23  * Revision 1.10  1995/11/03  12:53:24  allender
24  * shareware changes
25  *
26  * Revision 1.9  1995/10/31  10:19:12  allender
27  * shareware stuff
28  *
29  * Revision 1.8  1995/10/23  14:50:11  allender
30  * set control type for new player *before* calling kc_set_controls
31  *
32  * Revision 1.7  1995/10/21  22:25:31  allender
33  * *** empty log message ***
34  *
35  * Revision 1.6  1995/10/17  15:57:42  allender
36  * removed line setting wrong COnfig_control_type
37  *
38  * Revision 1.5  1995/10/17  13:16:44  allender
39  * new controller support
40  *
41  * Revision 1.4  1995/08/24  16:03:38  allender
42  * call joystick code when player file uses joystick
43  *
44  * Revision 1.3  1995/08/03  15:15:39  allender
45  * got player save file working (more to go for shareware)
46  *
47  * Revision 1.2  1995/08/01  13:57:20  allender
48  * macified the player file stuff -- in a seperate folder
49  *
50  * Revision 1.1  1995/05/16  15:30:00  allender
51  * Initial revision
52  *
53  * Revision 2.3  1995/05/26  16:16:23  john
54  * Split SATURN into define's for requiring cd, using cd, etc.
55  * Also started adding all the Rockwell stuff.
56  *
57  * Revision 2.2  1995/03/24  17:48:21  john
58  * Made player files from saturn excrement the highest level for
59  * normal descent levels.
60  *
61  * Revision 2.1  1995/03/21  14:38:49  john
62  * Ifdef'd out the NETWORK code.
63  *
64  * Revision 2.0  1995/02/27  11:27:59  john
65  * New version 2.0, which has no anonymous unions, builds with
66  * Watcom 10.0, and doesn't require parsing BITMAPS.TBL.
67  *
68  * Revision 1.57  1995/02/13  20:34:55  john
69  * Lintized
70  *
71  * Revision 1.56  1995/02/13  13:23:24  john
72  * Fixed bug with new player joystick selection.
73  *
74  * Revision 1.55  1995/02/13  12:01:19  john
75  * Fixed bug with joystick throttle still asking for
76  * calibration with new pilots.
77  *
78  * Revision 1.54  1995/02/13  10:29:12  john
79  * Fixed bug with creating new player not resetting everything to default.
80  *
81  * Revision 1.53  1995/02/03  10:58:46  john
82  * Added code to save shareware style saved games into new format...
83  * Also, made new player file format not have the saved game array in it.
84  *
85  * Revision 1.52  1995/02/02  21:09:28  matt
86  * Let player start of level 8 if he made it to level 7 in the shareware
87  *
88  * Revision 1.51  1995/02/02  18:50:14  john
89  * Added warning for FCS when new pilot chooses.
90  *
91  * Revision 1.50  1995/02/02  11:21:34  john
92  * Made joystick calibrate when new user selects.
93  *
94  * Revision 1.49  1995/02/01  18:06:38  rob
95  * Put defaults macros into descent.tex
96  *
97  * Revision 1.48  1995/01/25  14:37:53  john
98  * Made joystick only prompt for calibration once...
99  *
100  * Revision 1.47  1995/01/24  19:37:12  matt
101  * Took out incorrect mprintf
102  *
103  * Revision 1.46  1995/01/22  18:57:22  matt
104  * Made player highest level work with missions
105  *
106  * Revision 1.45  1995/01/21  16:36:05  matt
107  * Made starting level system work for now, pending integration with
108  * mission code.
109  *
110  * Revision 1.44  1995/01/20  22:47:32  matt
111  * Mission system implemented, though imcompletely
112  *
113  * Revision 1.43  1995/01/04  14:58:39  rob
114  * Fixed for shareware build.
115  *
116  * Revision 1.42  1995/01/04  11:36:43  rob
117  * Added compatibility with older shareware pilot files.
118  *
119  * Revision 1.41  1995/01/03  11:01:58  rob
120  * fixed a default macro.
121  *
122  * Revision 1.40  1995/01/03  10:44:06  rob
123  * Added default taunt macros.
124  *
125  * Revision 1.39  1994/12/13  10:01:16  allender
126  * pop up message box when unable to correctly save player file
127  *
128  * Revision 1.38  1994/12/12  11:37:14  matt
129  * Fixed auto leveling defaults & saving
130  *
131  * Revision 1.37  1994/12/12  00:26:59  matt
132  * Added support for no-levelling option
133  *
134  * Revision 1.36  1994/12/10  19:09:54  matt
135  * Added assert for valid player number when loading game
136  *
137  * Revision 1.35  1994/12/08  10:53:07  rob
138  * Fixed a bug in highest_level tracking.
139  *
140  * Revision 1.34  1994/12/08  10:01:36  john
141  * Changed the way the player callsign stuff works.
142  *
143  * Revision 1.33  1994/12/07  18:30:38  rob
144  * Load highest level along with player (used to be only if higher)
145  * Capped at LAST_LEVEL in case a person loads a registered player in shareware.
146  *
147  * Revision 1.32  1994/12/03  16:01:12  matt
148  * When player file has bad version, force player to choose another
149  *
150  * Revision 1.31  1994/12/02  19:54:00  yuan
151  * Localization.
152  *
153  * Revision 1.30  1994/12/02  11:01:36  yuan
154  * Localization.
155  *
156  * Revision 1.29  1994/11/29  03:46:28  john
157  * Added joystick sensitivity; Added sound channels to detail menu.  Removed -maxchannels
158  * command line arg.
159  *
160  * Revision 1.28  1994/11/29  01:10:23  john
161  * Took out code that allowed new players to
162  * configure keyboard.
163  *
164  * Revision 1.27  1994/11/25  22:47:10  matt
165  * Made saved game descriptions longer
166  *
167  * Revision 1.26  1994/11/22  12:10:42  rob
168  * Fixed file handle left open if player file versions don't
169  * match.
170  *
171  * Revision 1.25  1994/11/21  19:35:30  john
172  * Replaced calls to joy_init with if (joy_present)
173  *
174  * Revision 1.24  1994/11/21  17:29:34  matt
175  * Cleaned up sequencing & game saving for secret levels
176  *
177  * Revision 1.23  1994/11/21  11:10:01  john
178  * Fixed bug with read-only .plr file making the config file
179  * not update.
180  *
181  * Revision 1.22  1994/11/20  19:03:08  john
182  * Fixed bug with if not having a joystick, default
183  * player input device is cyberman.
184  *
185  * Revision 1.21  1994/11/17  12:24:07  matt
186  * Made an array the right size, to fix error loading games
187  *
188  * Revision 1.20  1994/11/14  17:52:54  allender
189  * add call to WriteConfigFile when player files gets written
190  *
191  * Revision 1.19  1994/11/14  17:19:23  rob
192  * Removed gamma, joystick calibration, and sound settings from player file.
193  * Added default difficulty and multi macros.
194  *
195  * Revision 1.18  1994/11/07  14:01:23  john
196  * Changed the gamma correction sequencing.
197  *
198  * Revision 1.17  1994/11/05  17:22:49  john
199  * Fixed lots of sequencing problems with newdemo stuff.
200  *
201  * Revision 1.16  1994/11/01  16:40:11  john
202  * Added Gamma correction.
203  *
204  * Revision 1.15  1994/10/24  19:56:50  john
205  * Made the new user setup prompt for config options.
206  *
207  * Revision 1.14  1994/10/24  17:44:21  john
208  * Added stereo channel reversing.
209  *
210  * Revision 1.13  1994/10/24  16:05:12  matt
211  * Improved handling of player names that are the names of DOS devices
212  *
213  * Revision 1.12  1994/10/22  00:08:51  matt
214  * Fixed up problems with bonus & game sequencing
215  * Player doesn't get credit for hostages unless he gets them out alive
216  *
217  * Revision 1.11  1994/10/19  19:59:57  john
218  * Added bonus points at the end of level based on skill level.
219  *
220  * Revision 1.10  1994/10/19  15:14:34  john
221  * Took % hits out of player structure, made %kills work properly.
222  *
223  * Revision 1.9  1994/10/19  12:44:26  john
224  * Added hours field to player structure.
225  *
226  * Revision 1.8  1994/10/17  17:24:34  john
227  * Added starting_level to player struct.
228  *
229  * Revision 1.7  1994/10/17  13:07:15  john
230  * Moved the descent.cfg info into the player config file.
231  *
232  * Revision 1.6  1994/10/09  14:54:31  matt
233  * Made player cockpit state & window size save/restore with saved games & automap
234  *
235  * Revision 1.5  1994/10/08  23:08:09  matt
236  * Added error check & handling for game load/save disk io
237  *
238  * Revision 1.4  1994/10/05  17:40:54  rob
239  * Bumped save_file_version to 5 due to change in player.h
240  *
241  * Revision 1.3  1994/10/03  23:00:54  matt
242  * New file version for shorter callsigns
243  *
244  * Revision 1.2  1994/09/28  17:25:05  matt
245  * Added first draft of game save/load system
246  *
247  * Revision 1.1  1994/09/27  14:39:12  matt
248  * Initial revision
249  *
250  */
251 
252 #ifdef HAVE_CONFIG_H
253 #include <conf.h>
254 #endif
255 
256 #ifdef WINDOWS
257 #include "desw.h"
258 #include <mmsystem.h>
259 #endif
260 
261 #include <stdio.h>
262 #include <string.h>
263 #include <unistd.h>
264 #include <errno.h>
265 
266 #include "error.h"
267 
268 #include "pa_enabl.h"
269 #include "strutil.h"
270 #include "game.h"
271 #include "gameseq.h"
272 #include "player.h"
273 #include "playsave.h"
274 #include "joy.h"
275 #include "kconfig.h"
276 #include "digi.h"
277 #include "newmenu.h"
278 #include "joydefs.h"
279 #include "palette.h"
280 #include "multi.h"
281 #include "menu.h"
282 #include "config.h"
283 #include "text.h"
284 #include "mono.h"
285 #include "state.h"
286 #include "gauges.h"
287 #include "screens.h"
288 #include "powerup.h"
289 #include "makesig.h"
290 #include "byteswap.h"
291 #include "fileutil.h"
292 #include "escort.h"
293 
294 #define SAVE_FILE_ID			MAKE_SIG('D','P','L','R')
295 
296 #ifdef MACINTOSH
297 	#include <Files.h>
298 	#include <Errors.h>			// mac doesn't have "normal" error numbers -- must use mac equivs
299 	#ifndef ENOENT
300 		#define ENOENT fnfErr
301 	#endif
302 	#ifdef POLY_ACC
303 		#include "poly_acc.h"
304 	#endif
305 	#include "isp.h"
306 #endif
307 
308 int get_lifetime_checksum (int a,int b);
309 
310 typedef struct hli {
311 	char	shortname[9];
312 	ubyte	level_num;
313 } hli;
314 
315 int n_highest_levels;
316 
317 hli highest_levels[MAX_MISSIONS];
318 
319 #define PLAYER_FILE_VERSION	25			//increment this every time the player file changes
320 
321 //version 5  ->  6: added new highest level information
322 //version 6  ->  7: stripped out the old saved_game array.
323 //version 7  ->  8: added reticle flag, & window size
324 //version 8  ->  9: removed player_struct_version
325 //version 9  -> 10: added default display mode
326 //version 10 -> 11: added all toggles in toggle menu
327 //version 11 -> 12: added weapon ordering
328 //version 12 -> 13: added more keys
329 //version 13 -> 14: took out marker key
330 //version 14 -> 15: added guided in big window
331 //version 15 -> 16: added small windows in cockpit
332 //version 16 -> 17: ??
333 //version 17 -> 18: save guidebot name
334 //version 18 -> 19: added automap-highres flag
335 //version 19 -> 20: added kconfig data for windows joysticks
336 //version 20 -> 21: save seperate config types for DOS & Windows
337 //version 21 -> 22: save lifetime netstats
338 //version 22 -> 23: ??
339 //version 23 -> 24: add name of joystick for windows version.
340 //version 24 -> 25: add d2x keys array
341 
342 #define COMPATIBLE_PLAYER_FILE_VERSION          17
343 
344 
345 int Default_leveling_on=1;
346 extern ubyte SecondaryOrder[],PrimaryOrder[];
347 extern void InitWeaponOrdering();
348 
349 #ifdef MACINTOSH
350 extern ubyte default_firebird_settings[];
351 extern ubyte default_mousestick_settings[];
352 #endif
353 
new_player_config()354 int new_player_config()
355 {
356 	int nitems;
357 	int i,j,control_choice;
358 	newmenu_item m[8];
359    int mct=CONTROL_MAX_TYPES;
360 
361    #ifndef WINDOWS
362  	 mct--;
363 	#endif
364 
365    InitWeaponOrdering ();		//setup default weapon priorities
366 
367 #if defined(MACINTOSH) && defined(USE_ISP)
368 	if (!ISpEnabled())
369 	{
370 #endif
371 RetrySelection:
372 		#if !defined(MACINTOSH) && !defined(WINDOWS)
373 		for (i=0; i<mct; i++ )	{
374 			m[i].type = NM_TYPE_MENU; m[i].text = CONTROL_TEXT(i);
375 		}
376 		#elif defined(WINDOWS)
377 			m[0].type = NM_TYPE_MENU; m[0].text = CONTROL_TEXT(0);
378 	 		m[1].type = NM_TYPE_MENU; m[1].text = CONTROL_TEXT(5);
379 			m[2].type = NM_TYPE_MENU; m[2].text = CONTROL_TEXT(7);
380 		 	i = 3;
381 		#else
382 		for (i = 0; i < 6; i++) {
383 			m[i].type = NM_TYPE_MENU; m[i].text = CONTROL_TEXT(i);
384 		}
385 		m[4].text = "Gravis Firebird/Mousetick II";
386 		m[3].text = "Thrustmaster";
387 		#endif
388 
389 		nitems = i;
390 		m[0].text = TXT_CONTROL_KEYBOARD;
391 
392 		#ifdef WINDOWS
393 			if (Config_control_type==CONTROL_NONE) control_choice = 0;
394 			else if (Config_control_type == CONTROL_MOUSE) control_choice = 1;
395 			else if (Config_control_type == CONTROL_WINJOYSTICK) control_choice = 2;
396 			else control_choice = 0;
397 		#else
398 			control_choice = Config_control_type;				// Assume keyboard
399 		#endif
400 
401 		#ifndef APPLE_DEMO
402 			control_choice = newmenu_do1( NULL, TXT_CHOOSE_INPUT, i, m, NULL, control_choice );
403 		#else
404 			control_choice = 0;
405 		#endif
406 
407 		if ( control_choice < 0 )
408 			return 0;
409 
410 #if defined(MACINTOSH) && defined(USE_ISP)
411 	}
412 	else	// !!!!NOTE ... link to above if (!ISpEnabled()), this is a really crappy function
413 	{
414 		control_choice = 0;
415 	}
416 #endif
417 
418 	for (i=0;i<CONTROL_MAX_TYPES; i++ )
419 		for (j=0;j<MAX_CONTROLS; j++ )
420 			kconfig_settings[i][j] = default_kconfig_settings[i][j];
421 	//added on 2/4/99 by Victor Rachels for new keys
422 	for(i=0; i < MAX_D2X_CONTROLS; i++)
423 		kconfig_d2x_settings[i] = default_kconfig_d2x_settings[i];
424 	//end this section addition - VR
425 	kc_set_controls();
426 
427 	Config_control_type = control_choice;
428 
429 #ifdef WINDOWS
430 	if (control_choice == 1) Config_control_type = CONTROL_MOUSE;
431 	else if (control_choice == 2) Config_control_type = CONTROL_WINJOYSTICK;
432 
433 //	if (Config_control_type == CONTROL_WINJOYSTICK)
434 //		joydefs_calibrate();
435 #else
436 	#ifndef MACINTOSH
437 	if ( Config_control_type==CONTROL_THRUSTMASTER_FCS)	{
438 		i = nm_messagebox( TXT_IMPORTANT_NOTE, 2, "Choose another", TXT_OK, TXT_FCS );
439 		if (i==0) goto RetrySelection;
440 	}
441 
442 	if ( (Config_control_type>0) && 	(Config_control_type<5))	{
443 		joydefs_calibrate();
444 	}
445 	#else		// some macintosh only stuff here
446 	if ( Config_control_type==CONTROL_THRUSTMASTER_FCS)	{
447 		extern char *tm_warning;
448 
449 		i = nm_messagebox( TXT_IMPORTANT_NOTE, 2, "Choose another", TXT_OK, tm_warning );
450 		if (i==0) goto RetrySelection;
451 	} else 	if ( Config_control_type==CONTROL_FLIGHTSTICK_PRO )	{
452 		extern char *ch_warning;
453 
454 		i = nm_messagebox( TXT_IMPORTANT_NOTE, 2, "Choose another", TXT_OK, ch_warning );
455 		if (i==0) goto RetrySelection;
456 	} else 	if ( Config_control_type==CONTROL_GRAVIS_GAMEPAD )	{
457 		extern char *ms_warning;
458 
459 		i = nm_messagebox( TXT_IMPORTANT_NOTE, 2, "Choose another", TXT_OK, ms_warning );
460 		if (i==0) goto RetrySelection;
461 		// stupid me -- get real default setting for either mousestick or firebird
462 		joydefs_set_type( Config_control_type );
463 		if (joy_have_firebird())
464 			for (i=0; i<NUM_OTHER_CONTROLS; i++ )
465 				kconfig_settings[Config_control_type][i] = default_firebird_settings[i];
466 		else
467 			for (i=0; i<NUM_OTHER_CONTROLS; i++ )
468 				kconfig_settings[Config_control_type][i] = default_mousestick_settings[i];
469 		kc_set_controls();		// reset the joystick control
470 	}
471 	if ( (Config_control_type>0) && (Config_control_type<5)  ) {
472 		joydefs_set_type( Config_control_type );
473 		joydefs_calibrate();
474 	}
475 
476 	#endif
477 #endif
478 
479 	Player_default_difficulty = 1;
480 	Auto_leveling_on = Default_leveling_on = 1;
481 	n_highest_levels = 1;
482 	highest_levels[0].shortname[0] = 0;			//no name for mission 0
483 	highest_levels[0].level_num = 1;				//was highest level in old struct
484 	Config_joystick_sensitivity = 8;
485 	Cockpit_3d_view[0]=CV_NONE;
486 	Cockpit_3d_view[1]=CV_NONE;
487 
488 	// Default taunt macros
489 	#ifdef NETWORK
490 	strcpy(Network_message_macro[0], "Why can't we all just get along?");
491 	strcpy(Network_message_macro[1], "Hey, I got a present for ya");
492 	strcpy(Network_message_macro[2], "I got a hankerin' for a spankerin'");
493 	strcpy(Network_message_macro[3], "This one's headed for Uranus");
494 	Netlife_kills=0; Netlife_killed=0;
495 	#endif
496 
497 	#ifdef MACINTOSH
498 		#ifdef POLY_ACC
499 			if (PAEnabled)
500 			{
501 				Scanline_double = 0;		// no pixel doubling for poly_acc
502 			}
503 			else
504 			{
505 				Scanline_double = 1;		// should be default for new player
506 			}
507 		#else
508 			Scanline_double = 1;			// should be default for new player
509 		#endif
510 	#endif
511 
512 	return 1;
513 }
514 
515 extern int Guided_in_big_window,Automap_always_hires;
516 
517 //this length must match the value in escort.c
518 #define GUIDEBOT_NAME_LEN 9
519 extern char guidebot_name[];
520 extern char real_guidebot_name[];
521 
522 WIN(extern char win95_current_joyname[]);
523 
524 ubyte control_type_dos,control_type_win;
525 
526 //read in the player's saved games.  returns errno (0 == no error)
read_player_file()527 int read_player_file()
528 {
529 	#ifdef MACINTOSH
530 	char filename[FILENAME_LEN+15];
531 	#else
532 	char filename[FILENAME_LEN];
533 	#endif
534 	FILE *file;
535 	int errno_ret = EZERO;
536 	int id,player_file_version,i;
537 	int rewrite_it=0;
538 	int swap = 0;
539 
540 	Assert(Player_num>=0 && Player_num<MAX_PLAYERS);
541 
542 #ifndef MACINTOSH
543 	sprintf(filename,"%.8s.plr",Players[Player_num].callsign);
544 #else
545 	sprintf(filename, ":Players:%.8s.plr",Players[Player_num].callsign);
546 #endif
547 	file = fopen(filename,"rb");
548 
549 #ifndef MACINTOSH
550 	//check filename
551 	if (file && isatty(fileno(file))) {
552 		//if the callsign is the name of a tty device, prepend a char
553 		fclose(file);
554 		sprintf(filename,"$%.7s.plr",Players[Player_num].callsign);
555 		file = fopen(filename,"rb");
556 	}
557 #endif
558 
559 	if (!file) {
560 		return errno;
561 	}
562 
563 	id = file_read_int(file);
564 
565         // SWAPINT added here because old versions of d2x
566         // used the wrong byte order.
567 	if (id!=SAVE_FILE_ID && id!=SWAPINT(SAVE_FILE_ID)) {
568 		nm_messagebox(TXT_ERROR, 1, TXT_OK, "Invalid player file");
569 		fclose(file);
570 		return -1;
571 	}
572 
573 	player_file_version = file_read_short(file);
574 
575 	if (player_file_version > 255) // bigendian file?
576 		swap = 1;
577 
578 	if (swap)
579 		player_file_version = SWAPSHORT(player_file_version);
580 
581 	if (player_file_version<COMPATIBLE_PLAYER_FILE_VERSION) {
582 		nm_messagebox(TXT_ERROR, 1, TXT_OK, TXT_ERROR_PLR_VERSION);
583 		fclose(file);
584 		return -1;
585 	}
586 
587 	Game_window_w					= file_read_short(file);
588 	Game_window_h					= file_read_short(file);
589 
590 	if (swap) {
591 		Game_window_w = SWAPSHORT(Game_window_w);
592 		Game_window_h = SWAPSHORT(Game_window_h);
593 	}
594 
595 	Player_default_difficulty	= file_read_byte(file);
596 	Default_leveling_on			= file_read_byte(file);
597 	Reticle_on						= file_read_byte(file);
598 	Cockpit_mode					= file_read_byte(file);
599 	#ifdef POLY_ACC
600 	 #ifdef PA_3DFX_VOODOO
601 		if (Cockpit_mode<2)
602 		{
603 	   	Cockpit_mode=2;
604 			Game_window_w  = 640;
605 			Game_window_h	= 480;
606 		}
607 	 #endif
608 	#endif
609 
610 	Default_display_mode			= file_read_byte(file);
611 	Missile_view_enabled			= file_read_byte(file);
612 	Headlight_active_default	= file_read_byte(file);
613 	Guided_in_big_window			= file_read_byte(file);
614 
615 	if (player_file_version >= 19)
616 		Automap_always_hires			= file_read_byte(file);
617 
618 	Auto_leveling_on = Default_leveling_on;
619 
620 	//read new highest level info
621 
622 	n_highest_levels = file_read_short(file);
623 	if (swap)
624 		n_highest_levels = SWAPSHORT(n_highest_levels);
625 
626 	if (fread(highest_levels,sizeof(hli),n_highest_levels,file) != n_highest_levels) {
627 		errno_ret			= errno;
628 		fclose(file);
629 		return errno_ret;
630 	}
631 
632 	//read taunt macros
633 	{
634 #ifdef NETWORK
635 		int i,len;
636 
637 		len			= MAX_MESSAGE_LEN;
638 
639 		for (i			= 0; i < 4; i++)
640 			if (fread(Network_message_macro[i], len, 1, file) != 1)
641 				{errno_ret			= errno; break;}
642 #else
643 		char dummy[4][MAX_MESSAGE_LEN];
644 		fread(dummy, MAX_MESSAGE_LEN, 4, file);
645 
646 #endif
647 	}
648 
649 	//read kconfig data
650 	{
651 		int n_control_types = (player_file_version<20)?7:CONTROL_MAX_TYPES;
652 
653 		if (fread( kconfig_settings, MAX_CONTROLS*n_control_types, 1, file )!=1)
654 			errno_ret=errno;
655 		else if (fread((ubyte *)&control_type_dos, sizeof(ubyte), 1, file )!=1)
656 			errno_ret=errno;
657 		else if (player_file_version >= 21 && fread((ubyte *)&control_type_win, sizeof(ubyte), 1, file )!=1)
658 			errno_ret=errno;
659 		else if (fread(&Config_joystick_sensitivity, sizeof(ubyte), 1, file )!=1)
660 			errno_ret=errno;
661 
662 		#ifdef WINDOWS
663 		Config_control_type = control_type_win;
664 		#else
665 		Config_control_type = control_type_dos;
666 		#endif
667 
668 		#ifdef MACINTOSH
669 		joydefs_set_type(Config_control_type);
670 		#endif
671 
672 		for (i=0;i<11;i++)
673 		 {
674 			PrimaryOrder[i]=file_read_byte (file);
675 			SecondaryOrder[i]=file_read_byte(file);
676 		 }
677 
678 		if (player_file_version>=16)
679 		 {
680 		  Cockpit_3d_view[0]=file_read_int(file);
681 		  Cockpit_3d_view[1]=file_read_int(file);
682 		  if (swap) {
683 			  Cockpit_3d_view[0] = SWAPINT(Cockpit_3d_view[0]);
684 			  Cockpit_3d_view[1] = SWAPINT(Cockpit_3d_view[1]);
685 		  }
686 		 }
687 
688 
689 		if (errno_ret==EZERO)	{
690 			kc_set_controls();
691 		}
692 
693 	}
694 
695    if (player_file_version>=22)
696 	 {
697 #ifdef NETWORK
698 		Netlife_kills=file_read_int (file);
699 		Netlife_killed=file_read_int (file);
700 		if (swap) {
701 			Netlife_kills = SWAPINT(Netlife_kills);
702 			Netlife_killed = SWAPINT(Netlife_killed);
703 		}
704 #else
705 		file_read_int(file); file_read_int(file);
706 #endif
707 	 }
708 #ifdef NETWORK
709    else
710 	 {
711 		 Netlife_kills=0; Netlife_killed=0;
712 	 }
713 #endif
714 
715 	if (player_file_version>=23)
716 	 {
717 	  i=file_read_int (file);
718 	  if (swap)
719 		  i = SWAPINT(i);
720 #ifdef NETWORK
721 	  mprintf ((0,"Reading: lifetime checksum is %d\n",i));
722 	  if (i!=get_lifetime_checksum (Netlife_kills,Netlife_killed))
723 		{
724 		 Netlife_kills=0; Netlife_killed=0;
725  		 nm_messagebox(NULL, 1, "Shame on me", "Trying to cheat eh?");
726 		 rewrite_it=1;
727 		}
728 #endif
729 	 }
730 
731 	//read guidebot name
732 	if (player_file_version >= 18)
733 		file_read_string(guidebot_name,file);
734 	else
735 		strcpy(guidebot_name,"GUIDE-BOT");
736 
737 	strcpy(real_guidebot_name,guidebot_name);
738 
739 	{
740 		char buf[128];
741 
742 	#ifdef WINDOWS
743 		joy95_get_name(JOYSTICKID1, buf, 127);
744 		if (player_file_version >= 24)
745 			file_read_string(win95_current_joyname, file);
746 		else
747 			strcpy(win95_current_joyname, "Old Player File");
748 
749 		mprintf((0, "Detected joystick: %s\n", buf));
750 		mprintf((0, "Player's joystick: %s\n", win95_current_joyname));
751 
752 		if (strcmp(win95_current_joyname, buf)) {
753 			for (i = 0; i < MAX_CONTROLS; i++)
754 				kconfig_settings[CONTROL_WINJOYSTICK][i] =
755 					default_kconfig_settings[CONTROL_WINJOYSTICK][i];
756 		}
757 	#else
758 		if (player_file_version >= 24)
759 			file_read_string(buf, file);			// Just read it in fpr DPS.
760 	#endif
761 	}
762 
763 	if (player_file_version >= 25)
764 		fread(kconfig_d2x_settings, MAX_D2X_CONTROLS, 1, file);
765 	else
766 		for(i=0; i < MAX_D2X_CONTROLS; i++)
767 			kconfig_d2x_settings[i] = default_kconfig_d2x_settings[i];
768 
769 	if (fclose(file) && errno_ret==EZERO)
770 		errno_ret			= errno;
771 
772 	if (rewrite_it)
773 	 write_player_file();
774 
775 	return errno_ret;
776 
777 }
778 
779 
780 //finds entry for this level in table.  if not found, returns ptr to
781 //empty entry.  If no empty entries, takes over last one
find_hli_entry()782 int find_hli_entry()
783 {
784 	int i;
785 
786 	for (i=0;i<n_highest_levels;i++)
787 		if (!stricmp(highest_levels[i].shortname,Mission_list[Current_mission_num].filename))
788 			break;
789 
790 	if (i==n_highest_levels) {		//not found.  create entry
791 
792 		if (i==MAX_MISSIONS)
793 			i--;		//take last entry
794 		else
795 			n_highest_levels++;
796 
797 		strcpy(highest_levels[i].shortname,Mission_list[Current_mission_num].filename);
798 		highest_levels[i].level_num			= 0;
799 	}
800 
801 	return i;
802 }
803 
804 //set a new highest level for player for this mission
set_highest_level(int levelnum)805 void set_highest_level(int levelnum)
806 {
807 	int ret,i;
808 
809 	if ((ret=read_player_file()) != EZERO)
810 		if (ret != ENOENT)		//if file doesn't exist, that's ok
811 			return;
812 
813 	i			= find_hli_entry();
814 
815 	if (levelnum > highest_levels[i].level_num)
816 		highest_levels[i].level_num			= levelnum;
817 
818 	write_player_file();
819 }
820 
821 //gets the player's highest level from the file for this mission
get_highest_level(void)822 int get_highest_level(void)
823 {
824 	int i;
825 	int highest_saturn_level			= 0;
826 	read_player_file();
827 #ifndef SATURN
828 	if (strlen(Mission_list[Current_mission_num].filename)==0 )	{
829 		for (i=0;i<n_highest_levels;i++)
830 			if (!stricmp(highest_levels[i].shortname, "DESTSAT")) 	//	Destination Saturn.
831 		 		highest_saturn_level			= highest_levels[i].level_num;
832 	}
833 #endif
834    i			= highest_levels[find_hli_entry()].level_num;
835 	if ( highest_saturn_level > i )
836    	i			= highest_saturn_level;
837 	return i;
838 }
839 
840 extern int Cockpit_mode_save;
841 
842 //write out player's saved games.  returns errno (0 == no error)
write_player_file()843 int write_player_file()
844 {
845 	#ifdef MACINTOSH
846 	char filename[FILENAME_LEN+15];
847 	#else
848 	char filename[FILENAME_LEN];		// because of ":Players:" path
849 	#endif
850 	FILE *file;
851 	int errno_ret,i;
852 
853 //	#ifdef APPLE_DEMO		// no saving of player files in Apple OEM version
854 //	return 0;
855 //	#endif
856 
857 	errno_ret			= WriteConfigFile();
858 
859 #ifndef MACINTOSH
860 	sprintf(filename,"%s.plr",Players[Player_num].callsign);
861 #else
862 	sprintf(filename, ":Players:%.8s.plr",Players[Player_num].callsign);
863 #endif
864 	file			= fopen(filename,"wb");
865 
866 #ifndef MACINTOSH
867 	//check filename
868 	if (file && isatty(fileno(file))) {
869 
870 		//if the callsign is the name of a tty device, prepend a char
871 
872 		fclose(file);
873 		sprintf(filename,"$%.7s.plr",Players[Player_num].callsign);
874 		file			= fopen(filename,"wb");
875 	}
876 #endif
877 
878 	if (!file)
879               return errno;
880 
881 	errno_ret			= EZERO;
882 
883 	//Write out player's info
884 	file_write_int(SAVE_FILE_ID,file);
885 	file_write_short(PLAYER_FILE_VERSION,file);
886 
887 	file_write_short(Game_window_w,file);
888 	file_write_short(Game_window_h,file);
889 
890 	file_write_byte(Player_default_difficulty,file);
891 	file_write_byte(Auto_leveling_on,file);
892 	file_write_byte(Reticle_on,file);
893 	file_write_byte((Cockpit_mode_save!=-1)?Cockpit_mode_save:Cockpit_mode,file);	//if have saved mode, write it instead of letterbox/rear view
894 	file_write_byte(Default_display_mode,file);
895 	file_write_byte(Missile_view_enabled,file);
896 	file_write_byte(Headlight_active_default,file);
897 	file_write_byte(Guided_in_big_window,file);
898 	file_write_byte(Automap_always_hires,file);
899 
900 	//write higest level info
901 	file_write_short(n_highest_levels,file);
902 	if ((fwrite(highest_levels, sizeof(hli), n_highest_levels, file) != n_highest_levels)) {
903 		errno_ret			= errno;
904 		fclose(file);
905 		return errno_ret;
906 	}
907 
908 	#ifdef NETWORK
909 	if ((fwrite(Network_message_macro, MAX_MESSAGE_LEN, 4, file) != 4)) {
910 		errno_ret			= errno;
911 		fclose(file);
912 		return errno_ret;
913 	}
914 	#else
915 	fseek( file, MAX_MESSAGE_LEN * 4, SEEK_CUR );
916 	#endif
917 
918 	//write kconfig info
919 	{
920 
921 		#ifdef WINDOWS
922 		control_type_win = Config_control_type;
923 		#else
924 		control_type_dos = Config_control_type;
925 		#endif
926 
927 		if (fwrite( kconfig_settings, MAX_CONTROLS*CONTROL_MAX_TYPES, 1, file )!=1)
928 			errno_ret=errno;
929 		else if (fwrite( &control_type_dos, sizeof(ubyte), 1, file )!=1)
930 			errno_ret=errno;
931 		else if (fwrite( &control_type_win, sizeof(ubyte), 1, file )!=1)
932 			errno_ret=errno;
933 		else if (fwrite( &Config_joystick_sensitivity, sizeof(ubyte), 1, file )!=1)
934 			errno_ret=errno;
935 
936       for (i=0;i<11;i++)
937        {
938         fwrite (&PrimaryOrder[i],sizeof(ubyte),1,file);
939         fwrite (&SecondaryOrder[i],sizeof(ubyte),1,file);
940        }
941 
942 		file_write_int (Cockpit_3d_view[0],file);
943 		file_write_int (Cockpit_3d_view[1],file);
944 
945 #ifdef NETWORK
946 		file_write_int (Netlife_kills,file);
947 		file_write_int (Netlife_killed,file);
948 		i=get_lifetime_checksum (Netlife_kills,Netlife_killed);
949 		mprintf ((0,"Writing: Lifetime checksum is %d\n",i));
950 #else
951 	   file_write_int(0, file);
952 	   file_write_int(0, file);
953 	   i = get_lifetime_checksum (0, 0);
954 #endif
955 	   file_write_int (i,file);
956 	}
957 
958 	//write guidebot name
959 	file_write_string(real_guidebot_name,file);
960 
961 	{
962 		char buf[128];
963 		#ifdef WINDOWS
964 		joy95_get_name(JOYSTICKID1, buf, 127);
965 		#else
966 		strcpy(buf, "DOS joystick");
967 		#endif
968 		file_write_string(buf, file);		// Write out current joystick for player.
969 	}
970 
971 	fwrite(kconfig_d2x_settings, MAX_D2X_CONTROLS, 1, file);
972 
973 	if (fclose(file))
974 		errno_ret			= errno;
975 
976 	if (errno_ret != EZERO) {
977 		remove(filename);			//delete bogus file
978 		nm_messagebox(TXT_ERROR, 1, TXT_OK, "%s\n\n%s",TXT_ERROR_WRITING_PLR, strerror(errno_ret));
979 	}
980 
981 	#ifdef MACINTOSH		// set filetype and creator for playerfile
982 	{
983 		FInfo finfo;
984 		Str255 pfilename;
985 		OSErr err;
986 
987 		strcpy(pfilename, filename);
988 		c2pstr(pfilename);
989 		err = HGetFInfo(0, 0, pfilename, &finfo);
990 		finfo.fdType = 'PLYR';
991 		finfo.fdCreator = 'DCT2';
992 		err = HSetFInfo(0, 0, pfilename, &finfo);
993 	}
994 	#endif
995 
996 	return errno_ret;
997 
998 }
999 
1000 //update the player's highest level.  returns errno (0 == no error)
update_player_file()1001 int update_player_file()
1002 {
1003 	int ret;
1004 
1005 	if ((ret=read_player_file()) != EZERO)
1006 		if (ret != ENOENT)		//if file doesn't exist, that's ok
1007 			return ret;
1008 
1009 	return write_player_file();
1010 }
1011 
get_lifetime_checksum(int a,int b)1012 int get_lifetime_checksum (int a,int b)
1013  {
1014   int num;
1015 
1016   // confusing enough to beat amateur disassemblers? Lets hope so
1017 
1018   num=(a<<8 ^ b);
1019   num^=(a | b);
1020   num*=num>>2;
1021   return (num);
1022  }
1023 
1024 
1025