home *** CD-ROM | disk | FTP | other *** search
/ Amiga ACS 1998 #6 / amigaacscoverdisc1998-061998.iso / games / descent / source / main / playsave.c < prev    next >
Text File  |  1998-06-08  |  21KB  |  740 lines

  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-1998 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
  12. */
  13. /*
  14.  * $Source: f:/miner/source/main/rcs/playsave.c $
  15.  * $Revision: 2.3 $
  16.  * $Author: john $
  17.  * $Date: 1995/05/26 16:16:23 $
  18.  * 
  19.  * Functions to load & save player games
  20.  * 
  21.  * $Log: playsave.c $
  22.  * Revision 2.3  1995/05/26  16:16:23  john
  23.  * Split SATURN into define's for requiring cd, using cd, etc.
  24.  * Also started adding all the Rockwell stuff.
  25.  * 
  26.  * Revision 2.2  1995/03/24  17:48:21  john
  27.  * Made player files from saturn excrement the highest level for
  28.  * normal descent levels.
  29.  * 
  30.  * Revision 2.1  1995/03/21  14:38:49  john
  31.  * Ifdef'd out the NETWORK code.
  32.  * 
  33.  * Revision 2.0  1995/02/27  11:27:59  john
  34.  * New version 2.0, which has no anonymous unions, builds with
  35.  * Watcom 10.0, and doesn't require parsing BITMAPS.TBL.
  36.  * 
  37.  * Revision 1.57  1995/02/13  20:34:55  john
  38.  * Lintized
  39.  * 
  40.  * Revision 1.56  1995/02/13  13:23:24  john
  41.  * Fixed bug with new player joystick selection.
  42.  * 
  43.  * Revision 1.55  1995/02/13  12:01:19  john
  44.  * Fixed bug with joystick throttle still asking for 
  45.  * calibration with new pilots.
  46.  * 
  47.  * Revision 1.54  1995/02/13  10:29:12  john
  48.  * Fixed bug with creating new player not resetting everything to default.
  49.  * 
  50.  * Revision 1.53  1995/02/03  10:58:46  john
  51.  * Added code to save shareware style saved games into new format...
  52.  * Also, made new player file format not have the saved game array in it.
  53.  * 
  54.  * Revision 1.52  1995/02/02  21:09:28  matt
  55.  * Let player start of level 8 if he made it to level 7 in the shareware
  56.  * 
  57.  * Revision 1.51  1995/02/02  18:50:14  john
  58.  * Added warning for FCS when new pilot chooses.
  59.  * 
  60.  * Revision 1.50  1995/02/02  11:21:34  john
  61.  * Made joystick calibrate when new user selects.
  62.  * 
  63.  * Revision 1.49  1995/02/01  18:06:38  rob
  64.  * Put defaults macros into descent.tex
  65.  * 
  66.  * Revision 1.48  1995/01/25  14:37:53  john
  67.  * Made joystick only prompt for calibration once...
  68.  * 
  69.  * Revision 1.47  1995/01/24  19:37:12  matt
  70.  * Took out incorrect mprintf
  71.  * 
  72.  * Revision 1.46  1995/01/22  18:57:22  matt
  73.  * Made player highest level work with missions
  74.  * 
  75.  * Revision 1.45  1995/01/21  16:36:05  matt
  76.  * Made starting level system work for now, pending integration with
  77.  * mission code.
  78.  * 
  79.  * Revision 1.44  1995/01/20  22:47:32  matt
  80.  * Mission system implemented, though imcompletely
  81.  * 
  82.  * Revision 1.43  1995/01/04  14:58:39  rob
  83.  * Fixed for shareware build.
  84.  * 
  85.  * Revision 1.42  1995/01/04  11:36:43  rob
  86.  * Added compatibility with older shareware pilot files.
  87.  * 
  88.  * Revision 1.41  1995/01/03  11:01:58  rob
  89.  * fixed a default macro.
  90.  * 
  91.  * Revision 1.40  1995/01/03  10:44:06  rob
  92.  * Added default taunt macros.
  93.  * 
  94.  * Revision 1.39  1994/12/13  10:01:16  allender
  95.  * pop up message box when unable to correctly save player file
  96.  * 
  97.  * Revision 1.38  1994/12/12  11:37:14  matt
  98.  * Fixed auto leveling defaults & saving
  99.  * 
  100.  * Revision 1.37  1994/12/12  00:26:59  matt
  101.  * Added support for no-levelling option
  102.  * 
  103.  * Revision 1.36  1994/12/10  19:09:54  matt
  104.  * Added assert for valid player number when loading game
  105.  * 
  106.  * Revision 1.35  1994/12/08  10:53:07  rob
  107.  * Fixed a bug in highest_level tracking.
  108.  * 
  109.  * Revision 1.34  1994/12/08  10:01:36  john
  110.  * Changed the way the player callsign stuff works.
  111.  * 
  112.  * Revision 1.33  1994/12/07  18:30:38  rob
  113.  * Load highest level along with player (used to be only if higher)
  114.  * Capped at LAST_LEVEL in case a person loads a registered player in shareware.
  115.  * 
  116.  * Revision 1.32  1994/12/03  16:01:12  matt
  117.  * When player file has bad version, force player to choose another
  118.  * 
  119.  * Revision 1.31  1994/12/02  19:54:00  yuan
  120.  * Localization.
  121.  * 
  122.  * Revision 1.30  1994/12/02  11:01:36  yuan
  123.  * Localization.
  124.  * 
  125.  * Revision 1.29  1994/11/29  03:46:28  john
  126.  * Added joystick sensitivity; Added sound channels to detail menu.  Removed -maxchannels
  127.  * command line arg.
  128.  * 
  129.  * Revision 1.28  1994/11/29  01:10:23  john
  130.  * Took out code that allowed new players to
  131.  * configure keyboard.
  132.  * 
  133.  * Revision 1.27  1994/11/25  22:47:10  matt
  134.  * Made saved game descriptions longer
  135.  * 
  136.  * Revision 1.26  1994/11/22  12:10:42  rob
  137.  * Fixed file handle left open if player file versions don't
  138.  * match.
  139.  * 
  140.  * Revision 1.25  1994/11/21  19:35:30  john
  141.  * Replaced calls to joy_init with if (joy_present)
  142.  * 
  143.  * Revision 1.24  1994/11/21  17:29:34  matt
  144.  * Cleaned up sequencing & game saving for secret levels
  145.  * 
  146.  * Revision 1.23  1994/11/21  11:10:01  john
  147.  * Fixed bug with read-only .plr file making the config file 
  148.  * not update.
  149.  * 
  150.  * Revision 1.22  1994/11/20  19:03:08  john
  151.  * Fixed bug with if not having a joystick, default 
  152.  * player input device is cyberman.
  153.  * 
  154.  * Revision 1.21  1994/11/17  12:24:07  matt
  155.  * Made an array the right size, to fix error loading games
  156.  * 
  157.  * Revision 1.20  1994/11/14  17:52:54  allender
  158.  * add call to WriteConfigFile when player files gets written
  159.  * 
  160.  * Revision 1.19  1994/11/14  17:19:23  rob
  161.  * Removed gamma, joystick calibration, and sound settings from player file.
  162.  * Added default difficulty and multi macros.
  163.  * 
  164.  * Revision 1.18  1994/11/07  14:01:23  john
  165.  * Changed the gamma correction sequencing.
  166.  * 
  167.  * Revision 1.17  1994/11/05  17:22:49  john
  168.  * Fixed lots of sequencing problems with newdemo stuff.
  169.  * 
  170.  * Revision 1.16  1994/11/01  16:40:11  john
  171.  * Added Gamma correction.
  172.  * 
  173.  * Revision 1.15  1994/10/24  19:56:50  john
  174.  * Made the new user setup prompt for config options.
  175.  * 
  176.  * Revision 1.14  1994/10/24  17:44:21  john
  177.  * Added stereo channel reversing.
  178.  * 
  179.  * Revision 1.13  1994/10/24  16:05:12  matt
  180.  * Improved handling of player names that are the names of DOS devices
  181.  * 
  182.  * Revision 1.12  1994/10/22  00:08:51  matt
  183.  * Fixed up problems with bonus & game sequencing
  184.  * Player doesn't get credit for hostages unless he gets them out alive
  185.  * 
  186.  * Revision 1.11  1994/10/19  19:59:57  john
  187.  * Added bonus points at the end of level based on skill level.
  188.  * 
  189.  * Revision 1.10  1994/10/19  15:14:34  john
  190.  * Took % hits out of player structure, made %kills work properly.
  191.  * 
  192.  * Revision 1.9  1994/10/19  12:44:26  john
  193.  * Added hours field to player structure.
  194.  * 
  195.  * Revision 1.8  1994/10/17  17:24:34  john
  196.  * Added starting_level to player struct.
  197.  * 
  198.  * Revision 1.7  1994/10/17  13:07:15  john
  199.  * Moved the descent.cfg info into the player config file.
  200.  * 
  201.  * Revision 1.6  1994/10/09  14:54:31  matt
  202.  * Made player cockpit state & window size save/restore with saved games & automap
  203.  * 
  204.  * Revision 1.5  1994/10/08  23:08:09  matt
  205.  * Added error check & handling for game load/save disk io
  206.  * 
  207.  * Revision 1.4  1994/10/05  17:40:54  rob
  208.  * Bumped save_file_version to 5 due to change in player.h
  209.  * 
  210.  * Revision 1.3  1994/10/03  23:00:54  matt
  211.  * New file version for shorter callsigns
  212.  * 
  213.  * Revision 1.2  1994/09/28  17:25:05  matt
  214.  * Added first draft of game save/load system
  215.  * 
  216.  * Revision 1.1  1994/09/27  14:39:12  matt
  217.  * Initial revision
  218.  * 
  219.  * 
  220.  */
  221.  
  222. #pragma off (unreferenced)
  223. static char rcsid[] = "$Id: playsave.c 2.3 1995/05/26 16:16:23 john Exp $";
  224. #pragma on (unreferenced)
  225.  
  226. #include <stdio.h>
  227. #include <string.h>
  228. #include <errno.h>
  229. #include <io.h>
  230.  
  231. #include "error.h"
  232.  
  233. #include "gameseq.h"
  234. #include "player.h"
  235. #include "playsave.h"
  236. #include "joy.h"
  237. #include "kconfig.h"
  238. #include "digi.h"
  239. #include "newmenu.h"
  240. #include "joydefs.h"
  241. #include "palette.h"
  242. #include "multi.h"
  243. #include "menu.h"
  244. #include "config.h"
  245. #include "text.h"
  246. #include "mono.h"
  247. #include "state.h"
  248.  
  249. #define SAVE_FILE_ID            'DPLR'
  250.  
  251. //this is for version 5 and below
  252. typedef struct save_info_v5 {
  253.     int    id;
  254.     short    saved_game_version,player_struct_version;
  255.     int     highest_level;
  256.     int    default_difficulty_level;
  257.     int    default_leveling_on;
  258. } save_info_v5;
  259.  
  260. //this is for version 6 and above 
  261. typedef struct save_info {
  262.     int    id;
  263.     short    saved_game_version,player_struct_version;
  264.     int    n_highest_levels;                //how many highest levels are saved
  265.     int    default_difficulty_level;
  266.     int    default_leveling_on;
  267. } save_info;
  268.  
  269. typedef struct hli {
  270.     char    shortname[9];
  271.     ubyte    level_num;
  272. } hli;
  273.  
  274. int n_highest_levels;
  275.  
  276. hli highest_levels[MAX_MISSIONS];
  277.  
  278. #define SAVED_GAME_VERSION        7        //increment this every time saved_game struct changes
  279.  
  280. //version 5 -> 6: added new highest level information
  281. //version 6 -> 7: stripped out the old saved_game array.
  282.  
  283. //the shareware is level 4
  284.  
  285. #define COMPATIBLE_SAVED_GAME_VERSION        4
  286. #define COMPATIBLE_PLAYER_STRUCT_VERSION    16
  287.  
  288. typedef struct saved_game {
  289.     char        name[GAME_NAME_LEN+1];        //extra char for terminating zero
  290.     player    player;
  291.     int        difficulty_level;        //which level game is played at
  292.     int        primary_weapon;        //which weapon selected
  293.     int        secondary_weapon;        //which weapon selected
  294.     int        cockpit_mode;            //which cockpit mode selected
  295.     int        window_w,window_h;    //size of player's window
  296.     int        next_level_num;        //which level we're going to
  297.     int        auto_leveling_on;        //does player have autoleveling on?
  298. } saved_game;
  299.  
  300. saved_game saved_games[N_SAVE_SLOTS];
  301.  
  302. int Default_leveling_on=1;
  303.  
  304. void init_game_list()
  305. {
  306.     int i;
  307.  
  308.     for (i=0;i<N_SAVE_SLOTS;i++)
  309.         saved_games[i].name[0] = 0;
  310. }
  311.  
  312. int new_player_config()
  313. {
  314.     int i,j,control_choice;
  315.     newmenu_item m[7];
  316.  
  317. RetrySelection:
  318.     for (i=0; i<CONTROL_MAX_TYPES; i++ )    {
  319.         m[i].type = NM_TYPE_MENU; m[i].text = CONTROL_TEXT(i);
  320.     }
  321.     m[0].text = TXT_CONTROL_KEYBOARD;
  322.  
  323.     control_choice = Config_control_type;                // Assume keyboard
  324.  
  325.     control_choice = newmenu_do1( NULL, TXT_CHOOSE_INPUT, CONTROL_MAX_TYPES, m, NULL, control_choice );
  326.  
  327.     if ( control_choice < 0 )
  328.         return 0;
  329.  
  330.     for (i=0;i<CONTROL_MAX_TYPES; i++ )
  331.         for (j=0;j<MAX_CONTROLS; j++ )
  332.             kconfig_settings[i][j] = default_kconfig_settings[i][j];
  333.     kc_set_controls();
  334.  
  335.     Config_control_type = control_choice;
  336.  
  337.     if ( Config_control_type==CONTROL_THRUSTMASTER_FCS)    {
  338.         i = nm_messagebox( TXT_IMPORTANT_NOTE, 2, "Choose another", TXT_OK, TXT_FCS );
  339.         if (i==0) goto RetrySelection;
  340.     }
  341.     
  342.     if ( (Config_control_type>0) &&     (Config_control_type<5) )    {
  343.         joydefs_calibrate();
  344.     }
  345.  
  346.     Player_default_difficulty = 1;
  347.     Auto_leveling_on = Default_leveling_on = 1;
  348.     n_highest_levels = 1;
  349.     highest_levels[0].shortname[0] = 0;            //no name for mission 0
  350.     highest_levels[0].level_num = 1;                //was highest level in old struct
  351.     Config_joystick_sensitivity = 8;
  352.  
  353.     // Default taunt macros
  354.     #ifdef NETWORK
  355.     strcpy(Network_message_macro[0], TXT_DEF_MACRO_1);
  356.     strcpy(Network_message_macro[1], TXT_DEF_MACRO_2);
  357.     strcpy(Network_message_macro[2], TXT_DEF_MACRO_3);
  358.     strcpy(Network_message_macro[3], TXT_DEF_MACRO_4);
  359.     #endif
  360.  
  361.     return 1;
  362. }
  363.  
  364. //read in the player's saved games.  returns errno (0 == no error)
  365. int read_player_file()
  366. {
  367.     char filename[13];
  368.     FILE *file;
  369.     save_info info;
  370.     int errno_ret = EZERO;
  371.  
  372.     Assert(Player_num>=0 && Player_num<MAX_PLAYERS);
  373.  
  374.     sprintf(filename,"%8s.plr",Players[Player_num].callsign);
  375.     file = fopen(filename,"rb");
  376.  
  377.     //check filename
  378.     if (file && isatty(fileno(file))) {
  379.         //if the callsign is the name of a tty device, prepend a char
  380.         fclose(file);
  381.         sprintf(filename,"$%.7s.plr",Players[Player_num].callsign);
  382.         file = fopen(filename,"rb");
  383.     }
  384.  
  385.     if (!file) {
  386.         return errno;
  387.     }
  388.  
  389.     if (fread(&info,sizeof(info),1,file) != 1) {
  390.         errno_ret = errno;
  391.         fclose(file);
  392.         return errno_ret;
  393.     }
  394.  
  395.     if (info.id!=SAVE_FILE_ID) {
  396.         nm_messagebox(TXT_ERROR, 1, TXT_OK, "Invalid player file");
  397.         fclose(file);
  398.         return -1;
  399.     }
  400.  
  401.     if (info.saved_game_version<COMPATIBLE_SAVED_GAME_VERSION || info.player_struct_version<COMPATIBLE_PLAYER_STRUCT_VERSION) {
  402.         nm_messagebox(TXT_ERROR, 1, TXT_OK, TXT_ERROR_PLR_VERSION);
  403.         fclose(file);
  404.         return -1;
  405.     }
  406.  
  407.     if (info.saved_game_version <= 5) {
  408.  
  409.         //deal with old-style highest level info
  410.  
  411.         n_highest_levels = 1;
  412.  
  413.         highest_levels[0].shortname[0] = 0;                            //no name for mission 0
  414.         highest_levels[0].level_num = info.n_highest_levels;    //was highest level in old struct
  415.  
  416.         //This hack allows the player to start on level 8 if he's made it to
  417.         //level 7 on the shareware.  We do this because the shareware didn't
  418.         //save the information that the player finished level 7, so the most
  419.         //we know is that he made it to level 7.
  420.         if (info.n_highest_levels==7)
  421.             highest_levels[0].level_num = 8;
  422.         
  423.     }
  424.     else {    //read new highest level info
  425.  
  426.         n_highest_levels = info.n_highest_levels;
  427.  
  428.         if (fread(highest_levels,sizeof(hli),n_highest_levels,file) != n_highest_levels) {
  429.             errno_ret = errno;
  430.             fclose(file);
  431.             return errno_ret;
  432.         }
  433.     }
  434.  
  435.     Player_default_difficulty = info.default_difficulty_level;
  436.     Default_leveling_on = info.default_leveling_on;
  437.  
  438.     if ( info.saved_game_version < 7 )    {            // Read old saved games.
  439.         if (fread(saved_games,sizeof(saved_games),1,file) != 1) {
  440.             errno_ret = errno;
  441.             fclose(file);
  442.             return errno_ret;
  443.         }
  444.     }
  445.  
  446.     //read taunt macros
  447.     {
  448.         int i,len;
  449.  
  450.         len = (info.saved_game_version == 4)?SHAREWARE_MAX_MESSAGE_LEN:MAX_MESSAGE_LEN;
  451.  
  452.         #ifdef NETWORK
  453.         for (i = 0; i < 4; i++)
  454.             if (fread(Network_message_macro[i], len, 1, file) != 1)
  455.                 {errno_ret = errno; break;}
  456.         #else
  457.         i = 0;
  458.         fseek( file, 48*len, SEEK_CUR );
  459.         #endif
  460.     }
  461.  
  462.     //read kconfig data
  463.     {
  464.         if (fread( kconfig_settings, MAX_CONTROLS*CONTROL_MAX_TYPES, 1, file )!=1)
  465.             errno_ret=errno;
  466.         else if (fread(&Config_control_type, sizeof(ubyte), 1, file )!=1)
  467.             errno_ret=errno;
  468.         else if (fread(&Config_joystick_sensitivity, sizeof(ubyte), 1, file )!=1)
  469.             errno_ret=errno;
  470.  
  471.         if (errno_ret==EZERO)    {
  472.             kc_set_controls();
  473.         }
  474.     }
  475.  
  476.     if (fclose(file) && errno_ret==EZERO)
  477.         errno_ret = errno;
  478.  
  479.     if ( info.saved_game_version == COMPATIBLE_SAVED_GAME_VERSION )        {
  480.         int i;
  481.         
  482.         Assert( N_SAVE_SLOTS == 10 );
  483.  
  484.         for (i=0; i<N_SAVE_SLOTS; i++ )    {
  485.             if ( saved_games[i].name[0] )    {
  486.                 state_save_old_game(i, saved_games[i].name, &saved_games[i].player, 
  487.                      saved_games[i].difficulty_level, saved_games[i].primary_weapon, 
  488.                       saved_games[i].secondary_weapon, saved_games[i].next_level_num );
  489.             }
  490.         }
  491.         write_player_file();
  492.     }
  493.  
  494.     return errno_ret;
  495.  
  496. }
  497.  
  498. //finds entry for this level in table.  if not found, returns ptr to 
  499. //empty entry.  If no empty entries, takes over last one 
  500. int find_hli_entry()
  501. {
  502.     int i;
  503.  
  504.     for (i=0;i<n_highest_levels;i++)
  505.         if (!stricmp(highest_levels[i].shortname,Mission_list[Current_mission_num].filename))
  506.             break;
  507.  
  508.     if (i==n_highest_levels) {        //not found.  create entry
  509.  
  510.         if (i==MAX_MISSIONS)
  511.             i--;        //take last entry
  512.         else
  513.             n_highest_levels++;
  514.  
  515.         strcpy(highest_levels[i].shortname,Mission_list[Current_mission_num].filename);
  516.         highest_levels[i].level_num = 0;
  517.     }
  518.  
  519.     return i;
  520. }
  521.  
  522. //set a new highest level for player for this mission
  523. void set_highest_level(int levelnum)
  524. {
  525.     int ret,i;
  526.  
  527.     if ((ret=read_player_file()) != EZERO)
  528.         if (ret != ENOENT)        //if file doesn't exist, that's ok
  529.             return;
  530.  
  531.     i = find_hli_entry();
  532.  
  533.     if (levelnum > highest_levels[i].level_num)
  534.         highest_levels[i].level_num = levelnum;
  535.  
  536.     write_player_file();
  537. }
  538.  
  539. //gets the player's highest level from the file for this mission
  540. int get_highest_level(void)
  541. {
  542.     int i;
  543.     int highest_saturn_level = 0;
  544.     read_player_file();
  545. #ifndef DEST_SAT
  546.     if (strlen(Mission_list[Current_mission_num].filename)==0 )    {
  547.         for (i=0;i<n_highest_levels;i++)
  548.             if (!stricmp(highest_levels[i].shortname, "DESTSAT"))     //    Destination Saturn.
  549.                  highest_saturn_level = highest_levels[i].level_num; 
  550.     }
  551. #endif
  552.    i = highest_levels[find_hli_entry()].level_num;
  553.     if ( highest_saturn_level > i )
  554.        i = highest_saturn_level;
  555.     return i;
  556. }
  557.  
  558.  
  559. //write out player's saved games.  returns errno (0 == no error)
  560. int write_player_file()
  561. {
  562.     char filename[13];
  563.     FILE *file;
  564.     save_info info;
  565.     int errno_ret;
  566.  
  567.     errno_ret = WriteConfigFile();
  568.  
  569.     info.id = SAVE_FILE_ID;
  570.     info.saved_game_version = SAVED_GAME_VERSION;
  571.     info.player_struct_version = PLAYER_STRUCT_VERSION;
  572.     info.saved_game_version = SAVED_GAME_VERSION;
  573.     info.player_struct_version = PLAYER_STRUCT_VERSION;
  574.     info.default_difficulty_level = Player_default_difficulty;
  575.     info.default_leveling_on = Auto_leveling_on;
  576.  
  577.     info.n_highest_levels = n_highest_levels;
  578.  
  579.     sprintf(filename,"%s.plr",Players[Player_num].callsign);
  580.     file = fopen(filename,"wb");
  581.  
  582.     //check filename
  583.     if (file && isatty(fileno(file))) {
  584.  
  585.         //if the callsign is the name of a tty device, prepend a char
  586.  
  587.         fclose(file);
  588.         sprintf(filename,"$%.7s.plr",Players[Player_num].callsign);
  589.         file = fopen(filename,"wb");
  590.     }
  591.  
  592.     if (!file)
  593.         return errno;
  594.  
  595.     errno_ret = EZERO;
  596.  
  597.     if (fwrite(&info,sizeof(info),1,file) != 1) {
  598.         errno_ret = errno;
  599.         fclose(file);
  600.         return errno_ret;
  601.     }
  602.  
  603.     //write higest level info
  604.     if ((fwrite(highest_levels, sizeof(hli), n_highest_levels, file) != n_highest_levels)) {
  605.         errno_ret = errno;
  606.         fclose(file);
  607.         return errno_ret;
  608.     }
  609.  
  610. //    if (fwrite(saved_games,sizeof(saved_games),1,file) != 1) {
  611. //        errno_ret = errno;
  612. //        fclose(file);
  613. //        return errno_ret;
  614. //    }
  615.  
  616.     #ifdef NETWORK
  617.     if ((fwrite(Network_message_macro, MAX_MESSAGE_LEN, 4, file) != 4)) {
  618.         errno_ret = errno;
  619.         fclose(file);
  620.         return errno_ret;
  621.     }
  622.     #else
  623.     fseek( file, MAX_MESSAGE_LEN * 4, SEEK_CUR );
  624.     #endif
  625.  
  626.     //write kconfig info
  627.     {
  628.         if (fwrite( kconfig_settings, MAX_CONTROLS*CONTROL_MAX_TYPES, 1, file )!=1)
  629.             errno_ret=errno;
  630.         else if (fwrite( &Config_control_type, sizeof(ubyte), 1, file )!=1)
  631.             errno_ret=errno;
  632.         else if (fwrite( &Config_joystick_sensitivity, sizeof(ubyte), 1, file )!=1)
  633.             errno_ret=errno;
  634.     }
  635.  
  636.     if (fclose(file))
  637.         errno_ret = errno;
  638.  
  639.     if (errno_ret != EZERO) {
  640.         remove(filename);            //delete bogus file
  641.         nm_messagebox(TXT_ERROR, 1, TXT_OK, "%s\n\n%s",TXT_ERROR_WRITING_PLR, strerror(errno_ret));
  642.     }
  643.         
  644.  
  645.     return errno_ret;
  646.  
  647. }
  648.  
  649. //returns errno (0 == no error)
  650. int save_player_game(int slot_num,char *text)
  651. {
  652.     int ret;
  653.  
  654.     if ((ret=read_player_file()) != EZERO)
  655.         if (ret != ENOENT)        //if file doesn't exist, that's ok
  656.             return ret;
  657.  
  658.     Assert(slot_num < N_SAVE_SLOTS);
  659.  
  660.     strcpy(saved_games[slot_num].name,text);
  661.  
  662.     saved_games[slot_num].player = Players[Player_num];
  663.  
  664.     saved_games[slot_num].difficulty_level    = Difficulty_level;
  665.     saved_games[slot_num].auto_leveling_on    = Auto_leveling_on;
  666.     saved_games[slot_num].primary_weapon    = Primary_weapon;
  667.     saved_games[slot_num].secondary_weapon    = Secondary_weapon;
  668.     saved_games[slot_num].cockpit_mode        = Cockpit_mode;
  669.     saved_games[slot_num].window_w            = Game_window_w;
  670.     saved_games[slot_num].window_h            = Game_window_h;
  671.     saved_games[slot_num].next_level_num    = Next_level_num;
  672.  
  673.     return write_player_file();
  674. }
  675.  
  676.  
  677. //returns errno (0 == no error)
  678. int load_player_game(int slot_num)
  679. {
  680.     char save_callsign[CALLSIGN_LEN+1];
  681.     int ret;
  682.  
  683.     Assert(slot_num < N_SAVE_SLOTS);
  684.  
  685.     if ((ret=read_player_file()) != EZERO)
  686.         return ret;
  687.  
  688.     Assert(saved_games[slot_num].name[0] != 0);
  689.  
  690.     strcpy(save_callsign,Players[Player_num].callsign);
  691.     Players[Player_num] = saved_games[slot_num].player;
  692.     strcpy(Players[Player_num].callsign,save_callsign);
  693.  
  694.     Difficulty_level    = saved_games[slot_num].difficulty_level;
  695.     Auto_leveling_on    = saved_games[slot_num].auto_leveling_on;
  696.     Primary_weapon        = saved_games[slot_num].primary_weapon;
  697.     Secondary_weapon    = saved_games[slot_num].secondary_weapon;
  698.     Cockpit_mode        = saved_games[slot_num].cockpit_mode;
  699.     Game_window_w        = saved_games[slot_num].window_w;
  700.     Game_window_h        = saved_games[slot_num].window_h;
  701.  
  702.     Players[Player_num].level = saved_games[slot_num].next_level_num;
  703.  
  704.     return EZERO;
  705. }
  706.  
  707. //fills in a list of pointers to strings describing saved games
  708. //returns the number of non-empty slots
  709. //returns -1 if this is a new player
  710. int get_game_list(char *game_text[N_SAVE_SLOTS])
  711. {
  712.     int i,count,ret;
  713.  
  714.     ret = read_player_file();
  715.  
  716.     for (i=count=0;i<N_SAVE_SLOTS;i++) {
  717.         if (game_text)
  718.             game_text[i] = saved_games[i].name;
  719.  
  720.         if (saved_games[i].name[0])
  721.             count++;
  722.     }
  723.  
  724.     return (ret==EZERO)?count:-1;        //-1 means new file was created
  725.  
  726. }
  727.  
  728. //update the player's highest level.  returns errno (0 == no error)
  729. int update_player_file()
  730. {
  731.     int ret;
  732.  
  733.     if ((ret=read_player_file()) != EZERO)
  734.         if (ret != ENOENT)        //if file doesn't exist, that's ok
  735.             return ret;
  736.  
  737.     return write_player_file();
  738. }
  739. 
  740.