home *** CD-ROM | disk | FTP | other *** search
/ Amiga ACS 1998 #6 / amigaacscoverdisc1998-061998.iso / games / descent / source / main / gamesave.c < prev    next >
Text File  |  1998-06-08  |  59KB  |  2,170 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/gamesave.c $
  15.  * $Revision: 2.2 $
  16.  * $Author: john $
  17.  * $Date: 1995/04/23 14:53:12 $
  18.  * 
  19.  * Save game information
  20.  * 
  21.  * $Log: gamesave.c $
  22.  * Revision 2.2  1995/04/23  14:53:12  john
  23.  * Made some mine structures read in with no structure packing problems.
  24.  * 
  25.  * Revision 2.1  1995/03/20  18:15:43  john
  26.  * Added code to not store the normals in the segment structure.
  27.  * 
  28.  * Revision 2.0  1995/02/27  11:29:50  john
  29.  * New version 2.0, which has no anonymous unions, builds with
  30.  * Watcom 10.0, and doesn't require parsing BITMAPS.TBL.
  31.  * 
  32.  * Revision 1.207  1995/02/23  10:17:36  allender
  33.  * fixed parameter mismatch with compute_segment_center
  34.  * 
  35.  * Revision 1.206  1995/02/22  14:51:17  allender
  36.  * fixed some things that I missed
  37.  * 
  38.  * Revision 1.205  1995/02/22  13:31:38  allender
  39.  * remove anonymous unions from object structure
  40.  * 
  41.  * Revision 1.204  1995/02/01  20:58:08  john
  42.  * Made editor check hog.
  43.  * 
  44.  * Revision 1.203  1995/01/28  17:40:34  mike
  45.  * correct level names (use rdl, sdl) for dumpmine stuff.
  46.  * 
  47.  * Revision 1.202  1995/01/25  20:03:46  matt
  48.  * Moved matrix check to avoid orthogonalizing an uninitialize matrix
  49.  * 
  50.  * Revision 1.201  1995/01/20  16:56:53  mike
  51.  * remove some mprintfs.
  52.  * 
  53.  * Revision 1.200  1995/01/15  19:42:13  matt
  54.  * Ripped out hostage faces for registered version
  55.  * 
  56.  * Revision 1.199  1995/01/05  16:59:09  yuan
  57.  * Make it so if editor is loaded, don't get error from typo
  58.  * in filename.
  59.  * 
  60.  * Revision 1.198  1994/12/19  12:49:46  mike
  61.  * Change fgets to cfgets.  fgets was getting a pointer mismatch warning.
  62.  * 
  63.  * Revision 1.197  1994/12/12  01:20:03  matt
  64.  * Took out object size hack for green claw guys
  65.  * 
  66.  * Revision 1.196  1994/12/11  13:19:37  matt
  67.  * Restored calls to fix_object_segs() when debugging is turned off, since
  68.  * it's not a big routine, and could fix some possibly bad problems.
  69.  * 
  70.  * Revision 1.195  1994/12/10  16:17:24  mike
  71.  * fix editor bug that was converting transparent walls into rock.
  72.  * 
  73.  * Revision 1.194  1994/12/09  14:59:27  matt
  74.  * Added system to attach a fireball to another object for rendering purposes,
  75.  * so the fireball always renders on top of (after) the object.
  76.  * 
  77.  * Revision 1.193  1994/12/08  17:19:02  yuan
  78.  * Cfiling stuff.
  79.  * 
  80.  * Revision 1.192  1994/12/02  20:01:05  matt
  81.  * Always give vulcan cannon powerup same amount of ammo, regardless of
  82.  * how much it was saved with
  83.  * 
  84.  * Revision 1.191  1994/11/30  17:45:57  yuan
  85.  * Saving files now creates RDL/SDLs instead of CDLs.
  86.  * 
  87.  * Revision 1.190  1994/11/30  17:22:14  matt
  88.  * Ripped out hostage faces in shareware version
  89.  * 
  90.  * Revision 1.189  1994/11/28  00:09:30  allender
  91.  * commented out call to newdemo_record_start_demo in load_level...what is
  92.  * this doing here anyway?????
  93.  * 
  94.  * Revision 1.188  1994/11/27  23:13:48  matt
  95.  * Made changes for new mprintf calling convention
  96.  * 
  97.  * Revision 1.187  1994/11/27  18:06:20  matt
  98.  * Cleaned up LVL/CDL file loading
  99.  * 
  100.  * Revision 1.186  1994/11/25  22:46:29  matt
  101.  * Allow ESC out of compiled/normal menu (esc=compiled).
  102.  * 
  103.  * Revision 1.185  1994/11/23  12:18:35  mike
  104.  * move level names here...a more logical place than dumpmine.
  105.  * 
  106.  * Revision 1.184  1994/11/21  20:29:19  matt
  107.  * If hostage info is bad, fix it.
  108.  * 
  109.  * Revision 1.183  1994/11/21  20:26:07  matt
  110.  * Fixed bug, I hope
  111.  * 
  112.  * Revision 1.182  1994/11/21  20:20:37  matt
  113.  * Fixed stupid mistake
  114.  * 
  115.  * Revision 1.181  1994/11/21  20:18:40  matt
  116.  * Fixed (hopefully) totally bogus writing of hostage data
  117.  * 
  118.  * Revision 1.180  1994/11/20  14:11:56  matt
  119.  * Gracefully handle two hostages having same id
  120.  * 
  121.  * Revision 1.179  1994/11/19  23:55:05  mike
  122.  * remove Assert, put in comment for Matt.
  123.  * 
  124.  * Revision 1.178  1994/11/19  19:53:24  matt
  125.  * Added code to full support different hostage head clip & message for
  126.  * each hostage.
  127.  * 
  128.  * Revision 1.177  1994/11/19  15:15:21  mike
  129.  * remove unused code and data
  130.  * 
  131.  * Revision 1.176  1994/11/19  10:28:28  matt
  132.  * Took out write routines when editor compiled out
  133.  * 
  134.  * Revision 1.175  1994/11/17  20:38:25  john
  135.  * Took out warning.
  136.  * 
  137.  * Revision 1.174  1994/11/17  20:36:34  john
  138.  * Made it so that saving a mine will write the .cdl even
  139.  * if .lvl gets error.
  140.  * 
  141.  * Revision 1.173  1994/11/17  20:26:19  john
  142.  * Made the game load whichever of .cdl or .lvl exists,
  143.  * and if they both exist, prompt the user for which one.
  144.  * 
  145.  * Revision 1.172  1994/11/17  20:11:20  john
  146.  * Fixed warning.
  147.  * 
  148.  * Revision 1.171  1994/11/17  20:09:26  john
  149.  * Added new compiled level format.
  150.  * 
  151.  * Revision 1.170  1994/11/17  14:57:21  mike
  152.  * moved segment validation functions from editor to main.
  153.  * 
  154.  * Revision 1.169  1994/11/17  11:39:21  matt
  155.  * Ripped out code to load old mines
  156.  * 
  157.  * Revision 1.168  1994/11/16  11:24:53  matt
  158.  * Made attack-type robots have smaller radius, so they get closer to player
  159.  * 
  160.  * Revision 1.167  1994/11/15  21:42:47  mike
  161.  * better error messages.
  162.  * 
  163.  * Revision 1.166  1994/11/15  15:30:41  matt
  164.  * Save ptr to name of level being loaded
  165.  * 
  166.  * Revision 1.165  1994/11/14  20:47:46  john
  167.  * Attempted to strip out all the code in the game 
  168.  * directory that uses any ui code.
  169.  * 
  170.  * Revision 1.164  1994/11/14  14:34:23  matt
  171.  * Fixed up handling when textures can't be found during remap
  172.  * 
  173.  * Revision 1.163  1994/11/10  14:02:49  matt
  174.  * Hacked in support for player ships with different textures
  175.  * 
  176.  * Revision 1.162  1994/11/06  14:38:17  mike
  177.  * Remove an apparently unnecessary mprintf.
  178.  * 
  179.  * Revision 1.161  1994/10/30  14:11:28  mike
  180.  * ripout local segments stuff.
  181.  * 
  182.  * Revision 1.160  1994/10/28  12:10:41  matt
  183.  * Check that was supposed to happen only when editor was in was happening
  184.  * only when editor was out.
  185.  * 
  186.  * Revision 1.159  1994/10/27  11:25:32  matt
  187.  * Only do connectivity error check when editor in
  188.  * 
  189.  * Revision 1.158  1994/10/27  10:54:00  matt
  190.  * Made connectivity error checking put up warning if errors found
  191.  * 
  192.  * Revision 1.157  1994/10/25  10:50:54  matt
  193.  * Vulcan cannon powerups now contain ammo count
  194.  * 
  195.  * Revision 1.156  1994/10/23  02:10:43  matt
  196.  * Got rid of obsolete hostage_info stuff
  197.  * 
  198.  * Revision 1.155  1994/10/22  18:57:26  matt
  199.  * Added call to check_segment_connections()
  200.  * 
  201.  * Revision 1.154  1994/10/21  12:19:23  matt
  202.  * Clear transient objects when saving (& loading) games
  203.  * 
  204.  * Revision 1.153  1994/10/21  11:25:10  mike
  205.  * Use new constant IMMORTAL_TIME.
  206.  * 
  207.  * Revision 1.152  1994/10/20  12:46:59  matt
  208.  * Replace old save files (MIN/SAV/HOT) with new LVL files
  209.  * 
  210.  * Revision 1.151  1994/10/19  19:26:32  matt
  211.  * Fixed stupid bug
  212.  * 
  213.  * Revision 1.150  1994/10/19  16:46:21  matt
  214.  * Made tmap overrides for robots remap texture numbers
  215.  * 
  216.  * Revision 1.149  1994/10/18  08:50:27  yuan
  217.  * Fixed correct variable this time.
  218.  * 
  219.  * Revision 1.148  1994/10/18  08:45:02  yuan
  220.  * Oops. forgot load function.
  221.  * 
  222.  * Revision 1.147  1994/10/18  08:42:10  yuan
  223.  * Avoid the int3.
  224.  * 
  225.  * Revision 1.146  1994/10/17  21:34:57  matt
  226.  * Added support for new Control Center/Main Reactor
  227.  * 
  228.  * Revision 1.145  1994/10/15  19:06:34  mike
  229.  * Fix bug, maybe, having to do with something or other, ...
  230.  * 
  231.  * Revision 1.144  1994/10/12  21:07:33  matt
  232.  * Killed unused field in object structure
  233.  * 
  234.  * Revision 1.143  1994/10/06  14:52:55  mike
  235.  * Put check in to detect possibly bogus walls in last segment which leaked through an earlier check
  236.  * due to misuse of Highest_segment_index.
  237.  * 
  238.  * Revision 1.142  1994/10/05  22:12:44  mike
  239.  * Put in cleanup for matcen/fuelcen links.
  240.  * 
  241.  * Revision 1.141  1994/10/03  11:30:05  matt
  242.  * Make sure player in a valid segment before saving
  243.  * 
  244.  * Revision 1.140  1994/09/28  11:14:41  mike
  245.  * Better error messaging on bogus mines: Only bring up dialog box if a "real" (level??.*) level.
  246.  * 
  247.  * Revision 1.139  1994/09/28  09:22:58  mike
  248.  * Comment out a mprintf.
  249.  * 
  250.  * Revision 1.138  1994/09/27  17:08:36  mike
  251.  * Message boxes when you load bogus mines.
  252.  * 
  253.  * Revision 1.137  1994/09/27  15:43:45  mike
  254.  * Move the dump stuff to dumpmine.
  255.  * 
  256.  * Revision 1.136  1994/09/27  00:02:31  mike
  257.  * Dump text files (".txm") when loading a mine, showing all kinds of useful mine info.
  258.  * 
  259.  * Revision 1.135  1994/09/26  11:30:41  matt
  260.  * Took out code which loaded bogus player structure
  261.  * 
  262.  * Revision 1.134  1994/09/26  11:18:44  john
  263.  * Fixed some conflicts with newseg.
  264.  * 
  265.  * Revision 1.133  1994/09/26  10:56:58  matt
  266.  * Fixed inconsistancies in lifeleft for immortal objects
  267.  * 
  268.  * Revision 1.132  1994/09/25  23:41:10  matt
  269.  * Changed the object load & save code to read/write the structure fields one
  270.  * at a time (rather than the whole structure at once).  This mean that the
  271.  * object structure can be changed without breaking the load/save functions.
  272.  * As a result of this change, the local_object data can be and has been 
  273.  * incorporated into the object array.  Also, timeleft is now a property 
  274.  * of all objects, and the object structure has been otherwise cleaned up.
  275.  * 
  276.  */
  277.  
  278. #pragma off (unreferenced)
  279. static char rcsid[] = "$Id: gamesave.c 2.2 1995/04/23 14:53:12 john Exp $";
  280. #pragma on (unreferenced)
  281.  
  282.  
  283. #include <io.h>
  284. #include <stdio.h>
  285. #include <stdlib.h>
  286. #include <math.h>
  287. #include <string.h>
  288.  
  289. #include "mono.h"
  290. #include "key.h"
  291. #include "gr.h"
  292. #include "palette.h"
  293. #include "newmenu.h"
  294.  
  295. #include "inferno.h"
  296. #ifdef EDITOR
  297. #include "editor\editor.h"
  298. #endif
  299. #include "error.h"
  300. #include "object.h"
  301. #include "game.h"
  302. #include "screens.h"
  303. #include "wall.h"
  304. #include "gamemine.h"
  305. #include "robot.h"
  306.  
  307.  
  308. #include "cflib.h"
  309. #include "cfile.h"
  310. #include "bm.h"
  311. #include "menu.h"
  312. #include "switch.h"
  313. #include "fuelcen.h"
  314. #include "powerup.h"
  315. #include "hostage.h"
  316. #include "weapon.h"
  317. #include "newdemo.h"
  318. #include "gameseq.h"
  319. #include "automap.h"
  320. #include "polyobj.h"
  321. #include "text.h"
  322. #include "gamefont.h"
  323. #include "gamesave.h"
  324.  
  325. #ifdef EDITOR
  326. #ifdef SHAREWARE
  327. char *Shareware_level_names[NUM_SHAREWARE_LEVELS] = {
  328.     "level01.sdl",
  329.     "level02.sdl",
  330.     "level03.sdl",
  331.     "level04.sdl",
  332.     "level05.sdl",
  333.     "level06.sdl",
  334.     "level07.sdl"
  335. };
  336. #else
  337. char *Shareware_level_names[NUM_SHAREWARE_LEVELS] = {
  338.     "level01.rdl",
  339.     "level02.rdl",
  340.     "level03.rdl",
  341.     "level04.rdl",
  342.     "level05.rdl",
  343.     "level06.rdl",
  344.     "level07.rdl"
  345. };
  346. #endif
  347.  
  348. char *Registered_level_names[NUM_REGISTERED_LEVELS] = {
  349.     "level08.rdl",
  350.     "level09.rdl",
  351.     "level10.rdl",
  352.     "level11.rdl",
  353.     "level12.rdl",
  354.     "level13.rdl",
  355.     "level14.rdl",
  356.     "level15.rdl",
  357.     "level16.rdl",
  358.     "level17.rdl",
  359.     "level18.rdl",
  360.     "level19.rdl",
  361.     "level20.rdl",
  362.     "level21.rdl",
  363.     "level22.rdl",
  364.     "level23.rdl",
  365.     "level24.rdl",
  366.     "level25.rdl",
  367.     "level26.rdl",
  368.     "level27.rdl",
  369.     "levels1.rdl",
  370.     "levels2.rdl",
  371.     "levels3.rdl"
  372. };
  373. #endif
  374.  
  375. char Gamesave_current_filename[128];
  376.  
  377. #define GAME_VERSION                    25
  378. #define GAME_COMPATIBLE_VERSION    22
  379.  
  380. #define MENU_CURSOR_X_MIN            MENU_X
  381. #define MENU_CURSOR_X_MAX            MENU_X+6
  382.  
  383. #define HOSTAGE_DATA_VERSION    0
  384.  
  385. //Start old wall structures
  386.  
  387. typedef struct v16_wall {
  388.     byte  type;                   // What kind of special wall.
  389.     byte    flags;                // Flags for the wall.        
  390.     fix   hps;                      // "Hit points" of the wall. 
  391.     byte    trigger;                // Which trigger is associated with the wall.
  392.     byte    clip_num;            // Which    animation associated with the wall. 
  393.     byte    keys;
  394.     } v16_wall;
  395.  
  396. typedef struct v19_wall {
  397.     int    segnum,sidenum;    // Seg & side for this wall
  398.     byte    type;                   // What kind of special wall.
  399.     byte    flags;                // Flags for the wall.        
  400.     fix   hps;                      // "Hit points" of the wall. 
  401.     byte    trigger;                // Which trigger is associated with the wall.
  402.     byte    clip_num;            // Which    animation associated with the wall. 
  403.     byte    keys;
  404.     int    linked_wall;        // number of linked wall
  405.     } v19_wall;
  406.  
  407. typedef struct v19_door {
  408.     int        n_parts;                    // for linked walls
  409.     short     seg[2];                     // Segment pointer of door.
  410.     short     side[2];                    // Side number of door.
  411.     short     type[2];                    // What kind of door animation.
  412.     fix         open;                        //    How long it has been open.
  413. } v19_door;
  414.  
  415. //End old wall structures
  416.  
  417. struct {
  418.     ushort     fileinfo_signature;
  419.     ushort    fileinfo_version;
  420.     int        fileinfo_sizeof;
  421. } game_top_fileinfo;    // Should be same as first two fields below...
  422.  
  423. struct {
  424.     ushort     fileinfo_signature;
  425.     ushort    fileinfo_version;
  426.     int        fileinfo_sizeof;
  427.     char        mine_filename[15];
  428.     int        level;
  429.     int        player_offset;                // Player info
  430.     int        player_sizeof;
  431.     int        object_offset;                // Object info
  432.     int        object_howmany;        
  433.     int        object_sizeof;  
  434.     int        walls_offset;
  435.     int        walls_howmany;
  436.     int        walls_sizeof;
  437.     int        doors_offset;
  438.     int        doors_howmany;
  439.     int        doors_sizeof;
  440.     int        triggers_offset;
  441.     int        triggers_howmany;
  442.     int        triggers_sizeof;
  443.     int        links_offset;
  444.     int        links_howmany;
  445.     int        links_sizeof;
  446.     int        control_offset;
  447.     int        control_howmany;
  448.     int        control_sizeof;
  449.     int        matcen_offset;
  450.     int        matcen_howmany;
  451.     int        matcen_sizeof;
  452. } game_fileinfo;
  453.  
  454. #ifdef EDITOR
  455. extern char mine_filename[];
  456. extern int save_mine_data_compiled(FILE * SaveFile);
  457. //--unused-- #else
  458. //--unused-- char mine_filename[128];
  459. #endif
  460.  
  461. int Gamesave_num_org_robots = 0;
  462. //--unused-- grs_bitmap * Gamesave_saved_bitmap = NULL;
  463.  
  464. #ifdef EDITOR
  465. //    Return true if this level has a name of the form "level??"
  466. //    Note that a pathspec can appear at the beginning of the filename.
  467. int is_real_level(char *filename)
  468. {
  469.     int    len = strlen(filename);
  470.  
  471.     if (len < 6)
  472.         return 0;
  473.  
  474.     //mprintf((0, "String = [%s]\n", &filename[len-11]));
  475.     return !strnicmp(&filename[len-11], "level", 5);
  476.  
  477. }
  478.  
  479. void convert_name_to_CDL( char *dest, char *src )
  480. {
  481.     int i;
  482.  
  483.     strcpy (dest, src);
  484.  
  485. #ifdef SHAREWARE
  486.     for (i=1; i<strlen(dest); i++ )
  487.     {
  488.         if (dest[i]=='.'||dest[i]==' '||dest[i]==0)
  489.         {
  490.             dest[i]='.';
  491.             dest[i+1]='S';
  492.             dest[i+2]= 'D';
  493.             dest[i+3]= 'L';
  494.             dest[i+4]=0;
  495.             return;
  496.         }
  497.     }
  498.  
  499.     if (i < 123)
  500.     {
  501.         dest[i]='.';
  502.         dest[i+1]='S';
  503.         dest[i+2]= 'D';
  504.         dest[i+3]= 'L';
  505.         dest[i+4]=0;
  506.         return;
  507.     }
  508. #else
  509.     for (i=1; i<strlen(dest); i++ )
  510.     {
  511.         if (dest[i]=='.'||dest[i]==' '||dest[i]==0)
  512.         {
  513.             dest[i]='.';
  514.             dest[i+1]='R';
  515.             dest[i+2]= 'D';
  516.             dest[i+3]= 'L';
  517.             dest[i+4]=0;
  518.             return;
  519.         }
  520.     }
  521.  
  522.     if (i < 123)
  523.     {
  524.         dest[i]='.';
  525.         dest[i+1]='R';
  526.         dest[i+2]= 'D';
  527.         dest[i+3]= 'L';
  528.         dest[i+4]=0;
  529.         return;
  530.     }
  531. #endif
  532.  
  533.  
  534.  
  535.  
  536. }
  537. #endif
  538.  
  539. void convert_name_to_LVL( char *dest, char *src )
  540. {
  541.     int i;
  542.  
  543.     strcpy (dest, src);
  544.  
  545.     for (i=1; i<strlen(dest); i++ )
  546.     {
  547.         if (dest[i]=='.'||dest[i]==' '||dest[i]==0)
  548.         {
  549.             dest[i]='.';
  550.             dest[i+1]='L';
  551.             dest[i+2]= 'V';
  552.             dest[i+3]= 'L';
  553.             dest[i+4]=0;
  554.             return;
  555.         }
  556.     }
  557.  
  558.     if (i < 123)
  559.     {
  560.         dest[i]='.';
  561.         dest[i+1]='L';
  562.         dest[i+2]= 'V';
  563.         dest[i+3]= 'L';
  564.         dest[i+4]=0;
  565.         return;
  566.     }
  567. }
  568.  
  569. //--unused-- vms_angvec zero_angles={0,0,0};
  570.  
  571. #define vm_angvec_zero(v) do {(v)->p=(v)->b=(v)->h=0;} while (0)
  572.  
  573. int Gamesave_num_players=0;
  574.  
  575. int N_save_pof_names=25;
  576. char Save_pof_names[MAX_POLYGON_MODELS][13];
  577.  
  578. check_and_fix_matrix(vms_matrix *m);
  579.  
  580. void verify_object( object * obj )    {
  581.  
  582.     obj->lifeleft = IMMORTAL_TIME;        //all loaded object are immortal, for now
  583.  
  584.     if ( obj->type == OBJ_ROBOT )    {
  585.         Gamesave_num_org_robots++;
  586.  
  587.         // Make sure valid id...
  588.         if ( obj->id >= N_robot_types )
  589.             obj->id = obj->id % N_robot_types;
  590.  
  591.         // Make sure model number & size are correct...        
  592.         if ( obj->render_type == RT_POLYOBJ ) {
  593.             obj->rtype.pobj_info.model_num = Robot_info[obj->id].model_num;
  594.             obj->size = Polygon_models[obj->rtype.pobj_info.model_num].rad;
  595.  
  596.             //@@if (obj->control_type==CT_AI && Robot_info[obj->id].attack_type)
  597.             //@@    obj->size = obj->size*3/4;
  598.         }
  599.  
  600.         if (obj->movement_type == MT_PHYSICS) {
  601.             obj->mtype.phys_info.mass = Robot_info[obj->id].mass;
  602.             obj->mtype.phys_info.drag = Robot_info[obj->id].drag;
  603.         }
  604.     }
  605.     else {        //Robots taken care of above
  606.  
  607.         if ( obj->render_type == RT_POLYOBJ ) {
  608.             int i;
  609.             char *name = Save_pof_names[obj->rtype.pobj_info.model_num];
  610.  
  611.             for (i=0;i<N_polygon_models;i++)
  612.                 if (!stricmp(Pof_names[i],name)) {        //found it!    
  613.                     // mprintf((0,"Mapping <%s> to %d (was %d)\n",name,i,obj->rtype.pobj_info.model_num));
  614.                     obj->rtype.pobj_info.model_num = i;
  615.                     break;
  616.                 }
  617.         }
  618.     }
  619.  
  620.     if ( obj->type == OBJ_POWERUP ) {
  621.         if ( obj->id >= N_powerup_types )    {
  622.             obj->id = 0;
  623.             Assert( obj->render_type != RT_POLYOBJ );
  624.         }
  625.         obj->control_type = CT_POWERUP;
  626.  
  627.         obj->size = Powerup_info[obj->id].size;
  628.     }
  629.  
  630.     //if ( obj->type == OBJ_HOSTAGE )    {
  631.     //    if ( obj->id >= N_hostage_types )    {
  632.     //        obj->id = 0;
  633.     //        Assert( obj->render_type == RT_POLYOBJ );
  634.     //    }
  635.     //}
  636.  
  637.     if ( obj->type == OBJ_WEAPON )    {
  638.         if ( obj->id >= N_weapon_types )    {
  639.             obj->id = 0;
  640.             Assert( obj->render_type != RT_POLYOBJ );
  641.         }
  642.     }
  643.  
  644.     if ( obj->type == OBJ_CNTRLCEN )    {
  645.         int i;
  646.  
  647.         obj->render_type = RT_POLYOBJ;
  648.         obj->control_type = CT_CNTRLCEN;
  649.  
  650.         // Make model number is correct...    
  651.         for (i=0; i<Num_total_object_types; i++ )    
  652.             if ( ObjType[i] == OL_CONTROL_CENTER )        {
  653.                 obj->rtype.pobj_info.model_num = ObjId[i];
  654.                 obj->shields = ObjStrength[i];
  655.                 break;        
  656.             }
  657.     }
  658.  
  659.     if ( obj->type == OBJ_PLAYER )    {
  660.         //int i;
  661.  
  662.         //Assert(obj == Player);
  663.  
  664.         if ( obj == ConsoleObject )        
  665.             init_player_object();
  666.         else
  667.             if (obj->render_type == RT_POLYOBJ)    //recover from Matt's pof file matchup bug
  668.                 obj->rtype.pobj_info.model_num = Player_ship->model_num;
  669.  
  670.         //Make sure orient matrix is orthogonal
  671.         check_and_fix_matrix(&obj->orient);
  672.  
  673.         obj->id = Gamesave_num_players++;
  674.     }
  675.  
  676.     if (obj->type == OBJ_HOSTAGE) {
  677.  
  678.         if (obj->id > N_hostage_types)
  679.             obj->id = 0;
  680.  
  681.         obj->render_type = RT_HOSTAGE;
  682.         obj->control_type = CT_POWERUP;
  683.         //obj->vclip_info.vclip_num = Hostage_vclip_num[Hostages[obj->id].type];
  684.         //obj->vclip_info.frametime = Vclip[obj->vclip_info.vclip_num].frame_time;
  685.         //obj->vclip_info.framenum = 0;
  686.     }
  687.  
  688. }
  689.  
  690. static int read_int(CFILE *file)
  691. {
  692.     int i;
  693.  
  694.     if (cfread( &i, sizeof(i), 1, file) != 1)
  695.         Error( "Error reading int in gamesave.c" );
  696.  
  697.     return i;
  698. }
  699.  
  700. static fix read_fix(CFILE *file)
  701. {
  702.     fix f;
  703.  
  704.     if (cfread( &f, sizeof(f), 1, file) != 1)
  705.         Error( "Error reading fix in gamesave.c" );
  706.  
  707.     return f;
  708. }
  709.  
  710. static short read_short(CFILE *file)
  711. {
  712.     short s;
  713.  
  714.     if (cfread( &s, sizeof(s), 1, file) != 1)
  715.         Error( "Error reading short in gamesave.c" );
  716.  
  717.     return s;
  718. }
  719.  
  720. static short read_fixang(CFILE *file)
  721. {
  722.     fixang f;
  723.  
  724.     if (cfread( &f, sizeof(f), 1, file) != 1)
  725.         Error( "Error reading fixang in gamesave.c" );
  726.  
  727.     return f;
  728. }
  729.  
  730. static byte read_byte(CFILE *file)
  731. {
  732.     byte b;
  733.  
  734.     if (cfread( &b, sizeof(b), 1, file) != 1)
  735.         Error( "Error reading byte in gamesave.c" );
  736.  
  737.     return b;
  738. }
  739.  
  740. static void read_vector(vms_vector *v,CFILE *file)
  741. {
  742.     v->x = read_fix(file);
  743.     v->y = read_fix(file);
  744.     v->z = read_fix(file);
  745. }
  746.  
  747. static void read_matrix(vms_matrix *m,CFILE *file)
  748. {
  749.     read_vector(&m->rvec,file);
  750.     read_vector(&m->uvec,file);
  751.     read_vector(&m->fvec,file);
  752. }
  753.  
  754. static void read_angvec(vms_angvec *v,CFILE *file)
  755. {
  756.     v->p = read_fixang(file);
  757.     v->b = read_fixang(file);
  758.     v->h = read_fixang(file);
  759. }
  760.  
  761. //static gs_skip(int len,CFILE *file)
  762. //{
  763. //
  764. //    cfseek(file,len,SEEK_CUR);
  765. //}
  766.  
  767. #ifdef EDITOR
  768. static void gs_write_int(int i,FILE *file)
  769. {
  770.     if (fwrite( &i, sizeof(i), 1, file) != 1)
  771.         Error( "Error reading int in gamesave.c" );
  772.  
  773. }
  774.  
  775. static void gs_write_fix(fix f,FILE *file)
  776. {
  777.     if (fwrite( &f, sizeof(f), 1, file) != 1)
  778.         Error( "Error reading fix in gamesave.c" );
  779.  
  780. }
  781.  
  782. static void gs_write_short(short s,FILE *file)
  783. {
  784.     if (fwrite( &s, sizeof(s), 1, file) != 1)
  785.         Error( "Error reading short in gamesave.c" );
  786.  
  787. }
  788.  
  789. static void gs_write_fixang(fixang f,FILE *file)
  790. {
  791.     if (fwrite( &f, sizeof(f), 1, file) != 1)
  792.         Error( "Error reading fixang in gamesave.c" );
  793.  
  794. }
  795.  
  796. static void gs_write_byte(byte b,FILE *file)
  797. {
  798.     if (fwrite( &b, sizeof(b), 1, file) != 1)
  799.         Error( "Error reading byte in gamesave.c" );
  800.  
  801. }
  802.  
  803. static void gr_write_vector(vms_vector *v,FILE *file)
  804. {
  805.     gs_write_fix(v->x,file);
  806.     gs_write_fix(v->y,file);
  807.     gs_write_fix(v->z,file);
  808. }
  809.  
  810. static void gs_write_matrix(vms_matrix *m,FILE *file)
  811. {
  812.     gr_write_vector(&m->rvec,file);
  813.     gr_write_vector(&m->uvec,file);
  814.     gr_write_vector(&m->fvec,file);
  815. }
  816.  
  817. static void gs_write_angvec(vms_angvec *v,FILE *file)
  818. {
  819.     gs_write_fixang(v->p,file);
  820.     gs_write_fixang(v->b,file);
  821.     gs_write_fixang(v->h,file);
  822. }
  823.  
  824. #endif
  825.  
  826. //reads one object of the given version from the given file
  827. read_object(object *obj,CFILE *f,int version)
  828. {
  829.     obj->type                = read_byte(f);
  830.     obj->id                    = read_byte(f);
  831.  
  832.     obj->control_type        = read_byte(f);
  833.     obj->movement_type    = read_byte(f);
  834.     obj->render_type        = read_byte(f);
  835.     obj->flags                = read_byte(f);
  836.  
  837.     obj->segnum                = read_short(f);
  838.     obj->attached_obj        = -1;
  839.  
  840.     read_vector(&obj->pos,f);
  841.     read_matrix(&obj->orient,f);
  842.  
  843.     obj->size                = read_fix(f);
  844.     obj->shields            = read_fix(f);
  845.  
  846.     read_vector(&obj->last_pos,f);
  847.  
  848.     obj->contains_type    = read_byte(f);
  849.     obj->contains_id        = read_byte(f);
  850.     obj->contains_count    = read_byte(f);
  851.  
  852.     switch (obj->movement_type) {
  853.  
  854.         case MT_PHYSICS:
  855.  
  856.             read_vector(&obj->mtype.phys_info.velocity,f);
  857.             read_vector(&obj->mtype.phys_info.thrust,f);
  858.  
  859.             obj->mtype.phys_info.mass        = read_fix(f);
  860.             obj->mtype.phys_info.drag        = read_fix(f);
  861.             obj->mtype.phys_info.brakes    = read_fix(f);
  862.  
  863.             read_vector(&obj->mtype.phys_info.rotvel,f);
  864.             read_vector(&obj->mtype.phys_info.rotthrust,f);
  865.  
  866.             obj->mtype.phys_info.turnroll    = read_fixang(f);
  867.             obj->mtype.phys_info.flags        = read_short(f);
  868.  
  869.             break;
  870.  
  871.         case MT_SPINNING:
  872.  
  873.             read_vector(&obj->mtype.spin_rate,f);
  874.             break;
  875.  
  876.         case MT_NONE:
  877.             break;
  878.  
  879.         default:
  880.             Int3();
  881.     }
  882.  
  883.     switch (obj->control_type) {
  884.  
  885.         case CT_AI: {
  886.             int i;
  887.  
  888.             obj->ctype.ai_info.behavior                = read_byte(f);
  889.  
  890.             for (i=0;i<MAX_AI_FLAGS;i++)
  891.                 obj->ctype.ai_info.flags[i]            = read_byte(f);
  892.  
  893.             obj->ctype.ai_info.hide_segment            = read_short(f);
  894.             obj->ctype.ai_info.hide_index                = read_short(f);
  895.             obj->ctype.ai_info.path_length            = read_short(f);
  896.             obj->ctype.ai_info.cur_path_index        = read_short(f);
  897.  
  898.             obj->ctype.ai_info.follow_path_start_seg    = read_short(f);
  899.             obj->ctype.ai_info.follow_path_end_seg        = read_short(f);
  900.  
  901.             break;
  902.         }
  903.  
  904.         case CT_EXPLOSION:
  905.  
  906.             obj->ctype.expl_info.spawn_time        = read_fix(f);
  907.             obj->ctype.expl_info.delete_time        = read_fix(f);
  908.             obj->ctype.expl_info.delete_objnum    = read_short(f);
  909.             obj->ctype.expl_info.next_attach = obj->ctype.expl_info.prev_attach = obj->ctype.expl_info.attach_parent = -1;
  910.  
  911.             break;
  912.  
  913.         case CT_WEAPON:
  914.  
  915.             //do I really need to read these?  Are they even saved to disk?
  916.  
  917.             obj->ctype.laser_info.parent_type        = read_short(f);
  918.             obj->ctype.laser_info.parent_num            = read_short(f);
  919.             obj->ctype.laser_info.parent_signature    = read_int(f);
  920.  
  921.             break;
  922.  
  923.         case CT_LIGHT:
  924.  
  925.             obj->ctype.light_info.intensity = read_fix(f);
  926.             break;
  927.  
  928.         case CT_POWERUP:
  929.  
  930.             if (version >= 25)
  931.                 obj->ctype.powerup_info.count = read_int(f);
  932.             else
  933.                 obj->ctype.powerup_info.count = 1;
  934.  
  935.             if (obj->id == POW_VULCAN_WEAPON)
  936.                     obj->ctype.powerup_info.count = VULCAN_WEAPON_AMMO_AMOUNT;
  937.  
  938.             break;
  939.  
  940.  
  941.         case CT_NONE:
  942.         case CT_FLYING:
  943.         case CT_DEBRIS:
  944.             break;
  945.  
  946.         case CT_SLEW:        //the player is generally saved as slew
  947.             break;
  948.  
  949.         case CT_CNTRLCEN:
  950.             break;
  951.  
  952.         case CT_MORPH:
  953.         case CT_FLYTHROUGH:
  954.         case CT_REPAIRCEN:
  955.         default:
  956.             Int3();
  957.     
  958.     }
  959.  
  960.     switch (obj->render_type) {
  961.  
  962.         case RT_NONE:
  963.             break;
  964.  
  965.         case RT_MORPH:
  966.         case RT_POLYOBJ: {
  967.             int i,tmo;
  968.  
  969.             obj->rtype.pobj_info.model_num        = read_int(f);
  970.  
  971.             for (i=0;i<MAX_SUBMODELS;i++)
  972.                 read_angvec(&obj->rtype.pobj_info.anim_angles[i],f);
  973.  
  974.             obj->rtype.pobj_info.subobj_flags    = read_int(f);
  975.  
  976.             tmo = read_int(f);
  977.  
  978.             #ifndef EDITOR
  979.             obj->rtype.pobj_info.tmap_override    = tmo;
  980.             #else
  981.             if (tmo==-1)
  982.                 obj->rtype.pobj_info.tmap_override    = -1;
  983.             else {
  984.                 int xlated_tmo = tmap_xlate_table[tmo];
  985.                 if (xlated_tmo < 0)    {
  986.                     mprintf( (0, "Couldn't find texture for demo object, model_num = %d\n", obj->rtype.pobj_info.model_num));
  987.                     Int3();
  988.                     xlated_tmo = 0;
  989.                 }
  990.                 obj->rtype.pobj_info.tmap_override    = xlated_tmo;
  991.             }
  992.             #endif
  993.  
  994.             obj->rtype.pobj_info.alt_textures    = 0;
  995.  
  996.             break;
  997.         }
  998.  
  999.         case RT_WEAPON_VCLIP:
  1000.         case RT_HOSTAGE:
  1001.         case RT_POWERUP:
  1002.         case RT_FIREBALL:
  1003.  
  1004.             obj->rtype.vclip_info.vclip_num    = read_int(f);
  1005.             obj->rtype.vclip_info.frametime    = read_fix(f);
  1006.             obj->rtype.vclip_info.framenum    = read_byte(f);
  1007.  
  1008.             break;
  1009.  
  1010.         case RT_LASER:
  1011.             break;
  1012.  
  1013.         default:
  1014.             Int3();
  1015.  
  1016.     }
  1017.  
  1018. }
  1019.  
  1020. #ifdef EDITOR
  1021.  
  1022. //writes one object to the given file
  1023. write_object(object *obj,FILE *f)
  1024. {
  1025.     gs_write_byte(obj->type,f);
  1026.     gs_write_byte(obj->id,f);
  1027.  
  1028.     gs_write_byte(obj->control_type,f);
  1029.     gs_write_byte(obj->movement_type,f);
  1030.     gs_write_byte(obj->render_type,f);
  1031.     gs_write_byte(obj->flags,f);
  1032.  
  1033.     gs_write_short(obj->segnum,f);
  1034.  
  1035.     gr_write_vector(&obj->pos,f);
  1036.     gs_write_matrix(&obj->orient,f);
  1037.  
  1038.     gs_write_fix(obj->size,f);
  1039.     gs_write_fix(obj->shields,f);
  1040.  
  1041.     gr_write_vector(&obj->last_pos,f);
  1042.  
  1043.     gs_write_byte(obj->contains_type,f);
  1044.     gs_write_byte(obj->contains_id,f);
  1045.     gs_write_byte(obj->contains_count,f);
  1046.  
  1047.     switch (obj->movement_type) {
  1048.  
  1049.         case MT_PHYSICS:
  1050.  
  1051.              gr_write_vector(&obj->mtype.phys_info.velocity,f);
  1052.             gr_write_vector(&obj->mtype.phys_info.thrust,f);
  1053.  
  1054.             gs_write_fix(obj->mtype.phys_info.mass,f);
  1055.             gs_write_fix(obj->mtype.phys_info.drag,f);
  1056.             gs_write_fix(obj->mtype.phys_info.brakes,f);
  1057.  
  1058.             gr_write_vector(&obj->mtype.phys_info.rotvel,f);
  1059.             gr_write_vector(&obj->mtype.phys_info.rotthrust,f);
  1060.  
  1061.             gs_write_fixang(obj->mtype.phys_info.turnroll,f);
  1062.             gs_write_short(obj->mtype.phys_info.flags,f);
  1063.  
  1064.             break;
  1065.  
  1066.         case MT_SPINNING:
  1067.  
  1068.             gr_write_vector(&obj->mtype.spin_rate,f);
  1069.             break;
  1070.  
  1071.         case MT_NONE:
  1072.             break;
  1073.  
  1074.         default:
  1075.             Int3();
  1076.     }
  1077.  
  1078.     switch (obj->control_type) {
  1079.  
  1080.         case CT_AI: {
  1081.             int i;
  1082.  
  1083.             gs_write_byte(obj->ctype.ai_info.behavior,f);
  1084.  
  1085.             for (i=0;i<MAX_AI_FLAGS;i++)
  1086.                 gs_write_byte(obj->ctype.ai_info.flags[i],f);
  1087.  
  1088.             gs_write_short(obj->ctype.ai_info.hide_segment,f);
  1089.             gs_write_short(obj->ctype.ai_info.hide_index,f);
  1090.             gs_write_short(obj->ctype.ai_info.path_length,f);
  1091.             gs_write_short(obj->ctype.ai_info.cur_path_index,f);
  1092.  
  1093.             gs_write_short(obj->ctype.ai_info.follow_path_start_seg,f);
  1094.             gs_write_short(obj->ctype.ai_info.follow_path_end_seg,f);
  1095.  
  1096.             break;
  1097.         }
  1098.  
  1099.         case CT_EXPLOSION:
  1100.  
  1101.             gs_write_fix(obj->ctype.expl_info.spawn_time,f);
  1102.             gs_write_fix(obj->ctype.expl_info.delete_time,f);
  1103.             gs_write_short(obj->ctype.expl_info.delete_objnum,f);
  1104.  
  1105.             break;
  1106.  
  1107.         case CT_WEAPON:
  1108.  
  1109.             //do I really need to write these objects?
  1110.  
  1111.             gs_write_short(obj->ctype.laser_info.parent_type,f);
  1112.             gs_write_short(obj->ctype.laser_info.parent_num,f);
  1113.             gs_write_int(obj->ctype.laser_info.parent_signature,f);
  1114.  
  1115.             break;
  1116.  
  1117.             break;
  1118.  
  1119.         case CT_LIGHT:
  1120.  
  1121.             gs_write_fix(obj->ctype.light_info.intensity,f);
  1122.             break;
  1123.  
  1124.         case CT_POWERUP:
  1125.  
  1126.             gs_write_int(obj->ctype.powerup_info.count,f);
  1127.             break;
  1128.  
  1129.         case CT_NONE:
  1130.         case CT_FLYING:
  1131.         case CT_DEBRIS:
  1132.             break;
  1133.  
  1134.         case CT_SLEW:        //the player is generally saved as slew
  1135.             break;
  1136.  
  1137.         case CT_CNTRLCEN:
  1138.             break;            //control center object.
  1139.  
  1140.         case CT_MORPH:
  1141.         case CT_REPAIRCEN:
  1142.         case CT_FLYTHROUGH:
  1143.         default:
  1144.             Int3();
  1145.     
  1146.     }
  1147.  
  1148.     switch (obj->render_type) {
  1149.  
  1150.         case RT_NONE:
  1151.             break;
  1152.  
  1153.         case RT_MORPH:
  1154.         case RT_POLYOBJ: {
  1155.             int i;
  1156.  
  1157.             gs_write_int(obj->rtype.pobj_info.model_num,f);
  1158.  
  1159.             for (i=0;i<MAX_SUBMODELS;i++)
  1160.                 gs_write_angvec(&obj->rtype.pobj_info.anim_angles[i],f);
  1161.  
  1162.             gs_write_int(obj->rtype.pobj_info.subobj_flags,f);
  1163.  
  1164.             gs_write_int(obj->rtype.pobj_info.tmap_override,f);
  1165.  
  1166.             break;
  1167.         }
  1168.  
  1169.         case RT_WEAPON_VCLIP:
  1170.         case RT_HOSTAGE:
  1171.         case RT_POWERUP:
  1172.         case RT_FIREBALL:
  1173.  
  1174.             gs_write_int(obj->rtype.vclip_info.vclip_num,f);
  1175.             gs_write_fix(obj->rtype.vclip_info.frametime,f);
  1176.             gs_write_byte(obj->rtype.vclip_info.framenum,f);
  1177.  
  1178.             break;
  1179.  
  1180.         case RT_LASER:
  1181.             break;
  1182.  
  1183.         default:
  1184.             Int3();
  1185.  
  1186.     }
  1187.  
  1188. }
  1189. #endif
  1190.  
  1191. // -----------------------------------------------------------------------------
  1192. // Load game 
  1193. // Loads all the relevant data for a level.
  1194. // If level != -1, it loads the filename with extension changed to .min
  1195. // Otherwise it loads the appropriate level mine.
  1196. // returns 0=everything ok, 1=old version, -1=error
  1197. load_game_data(CFILE *LoadFile)
  1198. {
  1199.     int i,j;
  1200.     int start_offset;
  1201.  
  1202.     start_offset = cftell(LoadFile);
  1203.  
  1204.     //===================== READ FILE INFO ========================
  1205.  
  1206.     // Set default values
  1207.     game_fileinfo.level                    =    -1;
  1208.     game_fileinfo.player_offset        =    -1;
  1209.     game_fileinfo.player_sizeof        =    sizeof(player);
  1210.      game_fileinfo.object_offset        =    -1;
  1211.     game_fileinfo.object_howmany        =    0;
  1212.     game_fileinfo.object_sizeof        =    sizeof(object);  
  1213.     game_fileinfo.walls_offset            =    -1;
  1214.     game_fileinfo.walls_howmany        =    0;
  1215.     game_fileinfo.walls_sizeof            =    sizeof(wall);  
  1216.     game_fileinfo.doors_offset            =    -1;
  1217.     game_fileinfo.doors_howmany        =    0;
  1218.     game_fileinfo.doors_sizeof            =    sizeof(active_door);  
  1219.     game_fileinfo.triggers_offset        =    -1;
  1220.     game_fileinfo.triggers_howmany    =    0;
  1221.     game_fileinfo.triggers_sizeof        =    sizeof(trigger);  
  1222.     game_fileinfo.control_offset        =    -1;
  1223.     game_fileinfo.control_howmany        =    0;
  1224.     game_fileinfo.control_sizeof        =    sizeof(control_center_triggers);
  1225.     game_fileinfo.matcen_offset        =    -1;
  1226.     game_fileinfo.matcen_howmany        =    0;
  1227.     game_fileinfo.matcen_sizeof        =    sizeof(matcen_info);
  1228.  
  1229.     // Read in game_top_fileinfo to get size of saved fileinfo.
  1230.  
  1231.     if (cfseek( LoadFile, start_offset, SEEK_SET )) 
  1232.         Error( "Error seeking in gamesave.c" ); 
  1233.  
  1234.     if (cfread( &game_top_fileinfo, sizeof(game_top_fileinfo), 1, LoadFile) != 1)
  1235.         Error( "Error reading game_top_fileinfo in gamesave.c" );
  1236.  
  1237.     // Check signature
  1238.     if (game_top_fileinfo.fileinfo_signature != 0x6705)
  1239.         return -1;
  1240.  
  1241.     // Check version number
  1242.     if (game_top_fileinfo.fileinfo_version < GAME_COMPATIBLE_VERSION )
  1243.         return -1;
  1244.  
  1245.     // Now, Read in the fileinfo
  1246.     if (cfseek( LoadFile, start_offset, SEEK_SET )) 
  1247.         Error( "Error seeking to game_fileinfo in gamesave.c" );
  1248.  
  1249.     game_fileinfo.fileinfo_signature = read_short(LoadFile);
  1250.  
  1251.     game_fileinfo.fileinfo_version = read_short(LoadFile);
  1252.     game_fileinfo.fileinfo_sizeof = read_int(LoadFile);
  1253.     for(i=0; i<15; i++)
  1254.         game_fileinfo.mine_filename[i] = read_byte(LoadFile);
  1255.     game_fileinfo.level = read_int(LoadFile);
  1256.     game_fileinfo.player_offset = read_int(LoadFile);                // Player info
  1257.     game_fileinfo.player_sizeof = read_int(LoadFile);
  1258.     game_fileinfo.object_offset = read_int(LoadFile);                // Object info
  1259.     game_fileinfo.object_howmany = read_int(LoadFile);        
  1260.     game_fileinfo.object_sizeof = read_int(LoadFile);  
  1261.     game_fileinfo.walls_offset = read_int(LoadFile);
  1262.     game_fileinfo.walls_howmany = read_int(LoadFile);
  1263.     game_fileinfo.walls_sizeof = read_int(LoadFile);
  1264.     game_fileinfo.doors_offset = read_int(LoadFile);
  1265.     game_fileinfo.doors_howmany = read_int(LoadFile);
  1266.     game_fileinfo.doors_sizeof = read_int(LoadFile);
  1267.     game_fileinfo.triggers_offset = read_int(LoadFile);
  1268.     game_fileinfo.triggers_howmany = read_int(LoadFile);
  1269.     game_fileinfo.triggers_sizeof = read_int(LoadFile);
  1270.     game_fileinfo.links_offset = read_int(LoadFile);
  1271.     game_fileinfo.links_howmany = read_int(LoadFile);
  1272.     game_fileinfo.links_sizeof = read_int(LoadFile);
  1273.     game_fileinfo.control_offset = read_int(LoadFile);
  1274.     game_fileinfo.control_howmany = read_int(LoadFile);
  1275.     game_fileinfo.control_sizeof = read_int(LoadFile);
  1276.     game_fileinfo.matcen_offset = read_int(LoadFile);
  1277.     game_fileinfo.matcen_howmany = read_int(LoadFile);
  1278.     game_fileinfo.matcen_sizeof = read_int(LoadFile);
  1279.  
  1280. //    if (cfread( &game_fileinfo, game_top_fileinfo.fileinfo_sizeof, 1, LoadFile )!=1)
  1281. //        Error( "Error reading game_fileinfo in gamesave.c" );
  1282.  
  1283.     if (game_top_fileinfo.fileinfo_version >= 14) {    //load mine filename
  1284.         char *p=Current_level_name;
  1285.         //must do read one char at a time, since no cfgets()
  1286.         do *p = cfgetc(LoadFile); while (*p++!=0);
  1287.     }
  1288.     else
  1289.         Current_level_name[0]=0;
  1290.  
  1291.     if (game_top_fileinfo.fileinfo_version >= 19) {    //load pof names
  1292.         cfread(&N_save_pof_names,2,1,LoadFile);
  1293.         cfread(Save_pof_names,N_save_pof_names,13,LoadFile);
  1294.     }
  1295.  
  1296.     //===================== READ PLAYER INFO ==========================
  1297.     Object_next_signature = 0;
  1298.  
  1299.     //===================== READ OBJECT INFO ==========================
  1300.  
  1301.     Gamesave_num_org_robots = 0;
  1302.     Gamesave_num_players = 0;
  1303.  
  1304.     if (game_fileinfo.object_offset > -1) {
  1305.         if (cfseek( LoadFile, game_fileinfo.object_offset, SEEK_SET )) 
  1306.             Error( "Error seeking to object_offset in gamesave.c" );
  1307.     
  1308.         for (i=0;i<game_fileinfo.object_howmany;i++)    {
  1309.  
  1310.             read_object(&Objects[i],LoadFile,game_top_fileinfo.fileinfo_version);
  1311.  
  1312.             Objects[i].signature = Object_next_signature++;
  1313.             verify_object( &Objects[i] );
  1314.         }
  1315.  
  1316.     }
  1317.  
  1318.     //===================== READ WALL INFO ============================
  1319.  
  1320.     if (game_fileinfo.walls_offset > -1)
  1321.     {
  1322.  
  1323.         if (!cfseek( LoadFile, game_fileinfo.walls_offset,SEEK_SET ))    {
  1324.             for (i=0;i<game_fileinfo.walls_howmany;i++) {
  1325.  
  1326.                 if (game_top_fileinfo.fileinfo_version >= 20) {
  1327.  
  1328.                     Assert(sizeof(Walls[i]) == game_fileinfo.walls_sizeof);
  1329.  
  1330.                     if (cfread(&Walls[i], game_fileinfo.walls_sizeof, 1,LoadFile)!=1)
  1331.                         Error( "Error reading Walls[%d] in gamesave.c", i);
  1332.                 }
  1333.                 else if (game_top_fileinfo.fileinfo_version >= 17) {
  1334.                     v19_wall w;
  1335.  
  1336.                     Assert(sizeof(w) == game_fileinfo.walls_sizeof);
  1337.  
  1338.                     if (cfread(&w, game_fileinfo.walls_sizeof, 1,LoadFile)!=1)
  1339.                         Error( "Error reading Walls[%d] in gamesave.c", i);
  1340.  
  1341.                     Walls[i].segnum        = w.segnum;
  1342.                     Walls[i].sidenum        = w.sidenum;
  1343.                     Walls[i].linked_wall    = w.linked_wall;
  1344.  
  1345.                     Walls[i].type            = w.type;
  1346.                     Walls[i].flags            = w.flags;
  1347.                     Walls[i].hps            = w.hps;
  1348.                     Walls[i].trigger        = w.trigger;
  1349.                     Walls[i].clip_num        = w.clip_num;
  1350.                     Walls[i].keys            = w.keys;
  1351.  
  1352.                     Walls[i].state            = WALL_DOOR_CLOSED;
  1353.                 }
  1354.                 else {
  1355.                     v16_wall w;
  1356.  
  1357.                     Assert(sizeof(w) == game_fileinfo.walls_sizeof);
  1358.  
  1359.                     if (cfread(&w, game_fileinfo.walls_sizeof, 1,LoadFile)!=1)
  1360.                         Error( "Error reading Walls[%d] in gamesave.c", i);
  1361.  
  1362.                     Walls[i].segnum = Walls[i].sidenum = Walls[i].linked_wall = -1;
  1363.  
  1364.                     Walls[i].type        = w.type;
  1365.                     Walls[i].flags        = w.flags;
  1366.                     Walls[i].hps        = w.hps;
  1367.                     Walls[i].trigger    = w.trigger;
  1368.                     Walls[i].clip_num    = w.clip_num;
  1369.                     Walls[i].keys        = w.keys;
  1370.                 }
  1371.  
  1372.             }
  1373.         }
  1374.     }
  1375.  
  1376.     //===================== READ DOOR INFO ============================
  1377.  
  1378.     if (game_fileinfo.doors_offset > -1)
  1379.     {
  1380.         if (!cfseek( LoadFile, game_fileinfo.doors_offset,SEEK_SET ))    {
  1381.  
  1382.             for (i=0;i<game_fileinfo.doors_howmany;i++) {
  1383.  
  1384.                 if (game_top_fileinfo.fileinfo_version >= 20) {
  1385.  
  1386.                     Assert(sizeof(ActiveDoors[i]) == game_fileinfo.doors_sizeof);
  1387.  
  1388.                     if (cfread(&ActiveDoors[i], game_fileinfo.doors_sizeof,1,LoadFile)!=1)
  1389.                         Error( "Error reading ActiveDoors[%d] in gamesave.c", i);
  1390.                 }
  1391.                 else {
  1392.                     v19_door d;
  1393.                     int p;
  1394.  
  1395.                     Assert(sizeof(d) == game_fileinfo.doors_sizeof);
  1396.  
  1397.                     if (cfread(&d, game_fileinfo.doors_sizeof, 1,LoadFile)!=1)
  1398.                         Error( "Error reading Doors[%d] in gamesave.c", i);
  1399.  
  1400.                     ActiveDoors[i].n_parts = d.n_parts;
  1401.  
  1402.                     for (p=0;p<d.n_parts;p++) {
  1403.                         int cseg,cside;
  1404.  
  1405.                         cseg = Segments[d.seg[p]].children[d.side[p]];
  1406.                         cside = find_connect_side(&Segments[d.seg[p]],&Segments[cseg]);
  1407.  
  1408.                         ActiveDoors[i].front_wallnum[p] = Segments[d.seg[p]].sides[d.side[p]].wall_num;
  1409.                         ActiveDoors[i].back_wallnum[p] = Segments[cseg].sides[cside].wall_num;
  1410.                     }
  1411.                 }
  1412.  
  1413.             }
  1414.         }
  1415.     }
  1416.  
  1417.     //==================== READ TRIGGER INFO ==========================
  1418.  
  1419.     if (game_fileinfo.triggers_offset > -1)        {
  1420.         if (!cfseek( LoadFile, game_fileinfo.triggers_offset,SEEK_SET ))    {
  1421.             for (i=0;i<game_fileinfo.triggers_howmany;i++)    {
  1422.                 //Assert( sizeof(Triggers[i]) == game_fileinfo.triggers_sizeof );
  1423.                 //if (cfread(&Triggers[i], game_fileinfo.triggers_sizeof,1,LoadFile)!=1)
  1424.                 //    Error( "Error reading Triggers[%d] in gamesave.c", i);
  1425.                 Triggers[i].type = read_byte(LoadFile);
  1426.                 Triggers[i].flags = read_short(LoadFile);
  1427.                 Triggers[i].value = read_int(LoadFile);
  1428.                 Triggers[i].time = read_int(LoadFile);
  1429.                 Triggers[i].link_num = read_byte(LoadFile);
  1430.                 Triggers[i].num_links = read_short(LoadFile);
  1431.                 for (j=0; j<MAX_WALLS_PER_LINK; j++ )    
  1432.                     Triggers[i].seg[j] = read_short(LoadFile);
  1433.                 for (j=0; j<MAX_WALLS_PER_LINK; j++ )
  1434.                     Triggers[i].side[j] = read_short(LoadFile);
  1435.             }
  1436.         }
  1437.     }
  1438.  
  1439.     //================ READ CONTROL CENTER TRIGGER INFO ===============
  1440.  
  1441.     if (game_fileinfo.control_offset > -1)
  1442.     {
  1443.         if (!cfseek( LoadFile, game_fileinfo.control_offset,SEEK_SET ))    {
  1444.             for (i=0;i<game_fileinfo.control_howmany;i++)
  1445.                 if ( sizeof(ControlCenterTriggers) == game_fileinfo.control_sizeof )    {
  1446.                     if (cfread(&ControlCenterTriggers, game_fileinfo.control_sizeof,1,LoadFile)!=1)
  1447.                          Error( "Error reading ControlCenterTriggers in gamesave.c", i);
  1448.                 } else {
  1449.                     ControlCenterTriggers.num_links = read_short( LoadFile );
  1450.                     for (j=0; j<MAX_WALLS_PER_LINK; j++ );
  1451.                         ControlCenterTriggers.seg[j] = read_short( LoadFile );
  1452.                     for (j=0; j<MAX_WALLS_PER_LINK; j++ );
  1453.                         ControlCenterTriggers.side[j] = read_short( LoadFile );
  1454.                 }
  1455.         }
  1456.     }
  1457.  
  1458.  
  1459.     //================ READ MATERIALOGRIFIZATIONATORS INFO ===============
  1460.  
  1461.     if (game_fileinfo.matcen_offset > -1)
  1462.     {    int    j;
  1463.  
  1464.         if (!cfseek( LoadFile, game_fileinfo.matcen_offset,SEEK_SET ))    {
  1465.             // mprintf((0, "Reading %i materialization centers.\n", game_fileinfo.matcen_howmany));
  1466.             for (i=0;i<game_fileinfo.matcen_howmany;i++) {
  1467.                 Assert( sizeof(RobotCenters[i]) == game_fileinfo.matcen_sizeof );
  1468.                 if (cfread(&RobotCenters[i], game_fileinfo.matcen_sizeof,1,LoadFile)!=1)
  1469.                     Error( "Error reading RobotCenters in gamesave.c", i);
  1470.                 //    Set links in RobotCenters to Station array
  1471.                 for (j=0; j<=Highest_segment_index; j++)
  1472.                     if (Segments[j].special == SEGMENT_IS_ROBOTMAKER)
  1473.                         if (Segments[j].matcen_num == i)
  1474.                             RobotCenters[i].fuelcen_num = Segments[j].value;
  1475.  
  1476.                 // mprintf((0, "   %i: flags = %08x\n", i, RobotCenters[i].robot_flags));
  1477.             }
  1478.         }
  1479.     }
  1480.  
  1481.  
  1482.     //========================= UPDATE VARIABLES ======================
  1483.  
  1484.     reset_objects(game_fileinfo.object_howmany);
  1485.  
  1486.     for (i=0; i<MAX_OBJECTS; i++) {
  1487.         Objects[i].next = Objects[i].prev = -1;
  1488.         if (Objects[i].type != OBJ_NONE) {
  1489.             int objsegnum = Objects[i].segnum;
  1490.  
  1491.             if (objsegnum > Highest_segment_index)        //bogus object
  1492.                 Objects[i].type = OBJ_NONE;
  1493.             else {
  1494.                 Objects[i].segnum = -1;            //avoid Assert()
  1495.                 obj_link(i,objsegnum);
  1496.             }
  1497.         }
  1498.     }
  1499.  
  1500.     clear_transient_objects(1);        //1 means clear proximity bombs
  1501.  
  1502.     // Make sure non-transparent doors are set correctly.
  1503.     for (i=0; i< Num_segments; i++)
  1504.         for (j=0;j<MAX_SIDES_PER_SEGMENT;j++) {
  1505.             side    *sidep = &Segments[i].sides[j];
  1506.             if ((sidep->wall_num != -1) && (Walls[sidep->wall_num].clip_num != -1)) {
  1507.                 //mprintf((0, "Checking Wall %d\n", Segments[i].sides[j].wall_num));
  1508.                 if (WallAnims[Walls[sidep->wall_num].clip_num].flags & WCF_TMAP1) {
  1509.                     //mprintf((0, "Fixing non-transparent door.\n"));
  1510.                     sidep->tmap_num = WallAnims[Walls[sidep->wall_num].clip_num].frames[0];
  1511.                     sidep->tmap_num2 = 0;
  1512.                 }
  1513.             }
  1514.         }
  1515.  
  1516.  
  1517.     Num_walls = game_fileinfo.walls_howmany;
  1518.     reset_walls();
  1519.  
  1520.     Num_open_doors = game_fileinfo.doors_howmany;
  1521.     Num_triggers = game_fileinfo.triggers_howmany;
  1522.  
  1523.     Num_robot_centers = game_fileinfo.matcen_howmany;
  1524.  
  1525.     //fix old wall structs
  1526.     if (game_top_fileinfo.fileinfo_version < 17) {
  1527.         int segnum,sidenum,wallnum;
  1528.  
  1529.         for (segnum=0; segnum<=Highest_segment_index; segnum++)
  1530.             for (sidenum=0;sidenum<6;sidenum++)
  1531.                 if ((wallnum=Segments[segnum].sides[sidenum].wall_num) != -1) {
  1532.                     Walls[wallnum].segnum = segnum;
  1533.                     Walls[wallnum].sidenum = sidenum;
  1534.                 }
  1535.     }
  1536.  
  1537.     #ifndef NDEBUG
  1538.     {
  1539.         int    sidenum;
  1540.         for (sidenum=0; sidenum<6; sidenum++) {
  1541.             int    wallnum = Segments[Highest_segment_index].sides[sidenum].wall_num;
  1542.             if (wallnum != -1)
  1543.                 if ((Walls[wallnum].segnum != Highest_segment_index) || (Walls[wallnum].sidenum != sidenum))
  1544.                     Int3();    //    Error.  Bogus walls in this segment.
  1545.                                 // Consult Yuan or Mike.
  1546.         }
  1547.     }
  1548.     #endif
  1549.  
  1550.     //create_local_segment_data();
  1551.  
  1552.     fix_object_segs();
  1553.  
  1554.     #ifndef NDEBUG
  1555.     dump_mine_info();
  1556.     #endif
  1557.  
  1558.     if (game_top_fileinfo.fileinfo_version < GAME_VERSION)
  1559.         return 1;        //means old version
  1560.     else
  1561.         return 0;
  1562. }
  1563.  
  1564.  
  1565. int check_segment_connections(void);
  1566.  
  1567. // -----------------------------------------------------------------------------
  1568. //loads from an already-open file
  1569. // returns 0=everything ok, 1=old version, -1=error
  1570. int load_mine_data(CFILE *LoadFile);
  1571. int load_mine_data_compiled(CFILE *LoadFile);
  1572.  
  1573. #define LEVEL_FILE_VERSION        1
  1574.  
  1575. #ifndef RELEASE
  1576. char *Level_being_loaded=NULL;
  1577. #endif
  1578.  
  1579. #ifdef COMPACT_SEGS
  1580. extern void ncache_flush();
  1581. #endif
  1582.  
  1583. //loads a level (.LVL) file from disk
  1584. int load_level(char * filename_passed)
  1585. {
  1586.     #ifdef EDITOR
  1587.     int use_compiled_level=1;
  1588.     #endif
  1589.     CFILE * LoadFile;
  1590.     char filename[128];
  1591.     int sig,version,minedata_offset,gamedata_offset,hostagetext_offset;
  1592.     int mine_err,game_err;
  1593.  
  1594.     #ifdef COMPACT_SEGS
  1595.     ncache_flush();
  1596.     #endif
  1597.  
  1598.     #ifndef RELEASE
  1599.     Level_being_loaded = filename_passed;
  1600.     #endif
  1601.  
  1602.     strcpy(filename,filename_passed);
  1603.  
  1604.     #ifdef EDITOR
  1605.     //check extension to see what file type this is
  1606.     strupr(filename);
  1607.  
  1608.     if (strstr(filename,".LVL"))
  1609.         use_compiled_level = 0;
  1610.         #ifdef SHAREWARE
  1611.     else if (!strstr(filename,".SDL")) {
  1612.         convert_name_to_CDL(filename,filename_passed);
  1613.         use_compiled_level = 1;
  1614.     }
  1615.         #else
  1616.     else if (!strstr(filename,".RDL")) {
  1617.         convert_name_to_CDL(filename,filename_passed);
  1618.         use_compiled_level = 1;
  1619.     }
  1620.         #endif
  1621.  
  1622.     // If we're trying to load a CDL, and we can't find it, and we have
  1623.     // the editor compiled in, then load the LVL.
  1624.     if ( (!cfexist(filename)) && use_compiled_level )    {
  1625.         convert_name_to_LVL(filename,filename_passed);
  1626.         use_compiled_level = 0;
  1627.     }        
  1628.     #endif
  1629.  
  1630.     LoadFile = cfopen( filename, "rb" );
  1631. //CF_READ_MODE );
  1632.  
  1633. #ifdef EDITOR
  1634.     if (!LoadFile)    {
  1635.         mprintf((0,"Can't open file <%s>\n", filename));
  1636.         return 1;
  1637.     }
  1638. #else
  1639.     if (!LoadFile)
  1640.         Error("Can't open file <%s>\n",filename);
  1641. #endif
  1642.  
  1643.     strcpy( Gamesave_current_filename, filename );
  1644.  
  1645. //    #ifdef NEWDEMO
  1646. //    if ( Newdemo_state == ND_STATE_RECORDING )
  1647. //        newdemo_record_start_demo();
  1648. //    #endif
  1649.  
  1650.     sig                        = read_int(LoadFile);
  1651.     version                    = read_int(LoadFile);
  1652.     minedata_offset        = read_int(LoadFile);
  1653.     gamedata_offset        = read_int(LoadFile);
  1654.     hostagetext_offset    = read_int(LoadFile);
  1655.  
  1656.     Assert(sig == 'PLVL');
  1657.  
  1658.     cfseek(LoadFile,minedata_offset,SEEK_SET);
  1659.     #ifdef EDITOR
  1660.     if (!use_compiled_level)
  1661.         mine_err = load_mine_data(LoadFile);
  1662.     else
  1663.     #endif
  1664.         //NOTE LINK TO ABOVE!!
  1665.         mine_err = load_mine_data_compiled(LoadFile);
  1666.  
  1667.     if (mine_err == -1)    //error!!
  1668.         return 1;
  1669.  
  1670.     cfseek(LoadFile,gamedata_offset,SEEK_SET);
  1671.     game_err = load_game_data(LoadFile);
  1672.  
  1673.     if (game_err == -1)    //error!!
  1674.         return 1;
  1675.  
  1676.     #ifdef HOSTAGE_FACES
  1677.     cfseek(LoadFile,hostagetext_offset,SEEK_SET);
  1678.     load_hostage_data(LoadFile,(version>=1));
  1679.     #endif
  1680.  
  1681.     //======================== CLOSE FILE =============================
  1682.  
  1683.     cfclose( LoadFile );
  1684.  
  1685.     #ifdef EDITOR
  1686.     write_game_text_file(filename);
  1687.     if (Errors_in_mine) {
  1688.         if (is_real_level(filename)) {
  1689.             char  ErrorMessage[200];
  1690.  
  1691.             sprintf( ErrorMessage, "Warning: %i errors in %s!\n", Errors_in_mine, Level_being_loaded );
  1692.             stop_time();
  1693.             gr_palette_load(gr_palette);
  1694.             nm_messagebox( NULL, 1, "Continue", ErrorMessage );
  1695.             start_time();
  1696.         } else
  1697.             mprintf((1, "Error: %i errors in %s.\n", Errors_in_mine, Level_being_loaded));
  1698.     }
  1699.     #endif
  1700.  
  1701.     #ifdef EDITOR
  1702.     //If an old version, ask the use if he wants to save as new version
  1703.     if (((LEVEL_FILE_VERSION>1) && version<LEVEL_FILE_VERSION) || mine_err==1 || game_err==1) {
  1704.         char  ErrorMessage[200];
  1705.  
  1706.         sprintf( ErrorMessage, "You just loaded a old version level.  Would\n"
  1707.                         "you like to save it as a current version level?");
  1708.  
  1709.         stop_time();
  1710.         gr_palette_load(gr_palette);
  1711.         if (nm_messagebox( NULL, 2, "Don't Save", "Save", ErrorMessage )==1)
  1712.             save_level(filename);
  1713.         start_time();
  1714.     }
  1715.     #endif
  1716.  
  1717.     #ifdef EDITOR
  1718.     if (Function_mode == FMODE_EDITOR)
  1719.         editor_status("Loaded NEW mine %s, \"%s\"",filename,Current_level_name);
  1720.     #endif
  1721.  
  1722.     #ifdef EDITOR
  1723.     if (check_segment_connections())
  1724.         nm_messagebox( "ERROR", 1, "Ok", 
  1725.                 "Connectivity errors detected in\n"
  1726.                 "mine.  See monochrome screen for\n"
  1727.                 "details, and contact Matt or Mike." );
  1728.     #endif
  1729.  
  1730.     return 0;
  1731. }
  1732.  
  1733. #ifdef EDITOR
  1734. void get_level_name()
  1735. {
  1736. //NO_UI!!!    UI_WINDOW                 *NameWindow = NULL;
  1737. //NO_UI!!!    UI_GADGET_INPUTBOX    *NameText;
  1738. //NO_UI!!!    UI_GADGET_BUTTON         *QuitButton;
  1739. //NO_UI!!!
  1740. //NO_UI!!!    // Open a window with a quit button
  1741. //NO_UI!!!    NameWindow = ui_open_window( 20, 20, 300, 110, WIN_DIALOG );
  1742. //NO_UI!!!    QuitButton = ui_add_gadget_button( NameWindow, 150-24, 60, 48, 40, "Done", NULL );
  1743. //NO_UI!!!
  1744. //NO_UI!!!    ui_wprintf_at( NameWindow, 10, 12,"Please enter a name for this mine:" );
  1745. //NO_UI!!!    NameText = ui_add_gadget_inputbox( NameWindow, 10, 30, LEVEL_NAME_LEN, LEVEL_NAME_LEN, Current_level_name );
  1746. //NO_UI!!!
  1747. //NO_UI!!!    NameWindow->keyboard_focus_gadget = (UI_GADGET *)NameText;
  1748. //NO_UI!!!    QuitButton->hotkey = KEY_ENTER;
  1749. //NO_UI!!!
  1750. //NO_UI!!!    ui_gadget_calc_keys(NameWindow);
  1751. //NO_UI!!!
  1752. //NO_UI!!!    while (!QuitButton->pressed && last_keypress!=KEY_ENTER) {
  1753. //NO_UI!!!        ui_mega_process();
  1754. //NO_UI!!!        ui_window_do_gadgets(NameWindow);
  1755. //NO_UI!!!    }
  1756. //NO_UI!!!
  1757. //NO_UI!!!    strcpy( Current_level_name, NameText->text );
  1758. //NO_UI!!!
  1759. //NO_UI!!!    if ( NameWindow!=NULL )    {
  1760. //NO_UI!!!        ui_close_window( NameWindow );
  1761. //NO_UI!!!        NameWindow = NULL;
  1762. //NO_UI!!!    }
  1763. //NO_UI!!!
  1764.  
  1765.     newmenu_item m[2];
  1766.  
  1767.     m[0].type = NM_TYPE_TEXT; m[0].text = "Please enter a name for this mine:";
  1768.     m[1].type = NM_TYPE_INPUT; m[1].text = Current_level_name; m[1].text_len = LEVEL_NAME_LEN;
  1769.  
  1770.     newmenu_do( NULL, "Enter mine name", 2, m, NULL );
  1771.  
  1772. }
  1773. #endif
  1774.  
  1775.  
  1776. #ifdef EDITOR
  1777.  
  1778. int    Errors_in_mine;
  1779.  
  1780. // -----------------------------------------------------------------------------
  1781. // Save game
  1782. int save_game_data(FILE * SaveFile)
  1783. {
  1784.     int  player_offset, object_offset, walls_offset, doors_offset, triggers_offset, control_offset, matcen_offset; //, links_offset;
  1785.     int start_offset,end_offset;
  1786.  
  1787.     start_offset = ftell(SaveFile);
  1788.  
  1789.     //===================== SAVE FILE INFO ========================
  1790.  
  1791.     game_fileinfo.fileinfo_signature =    0x6705;
  1792.     game_fileinfo.fileinfo_version    =    GAME_VERSION;
  1793.     game_fileinfo.level                    =  Current_level_num;
  1794.     game_fileinfo.fileinfo_sizeof        =    sizeof(game_fileinfo);
  1795.     game_fileinfo.player_offset        =    -1;
  1796.     game_fileinfo.player_sizeof        =    sizeof(player);
  1797.     game_fileinfo.object_offset        =    -1;
  1798.     game_fileinfo.object_howmany        =    Highest_object_index+1;
  1799.     game_fileinfo.object_sizeof        =    sizeof(object);
  1800.     game_fileinfo.walls_offset            =    -1;
  1801.     game_fileinfo.walls_howmany        =    Num_walls;
  1802.     game_fileinfo.walls_sizeof            =    sizeof(wall);
  1803.     game_fileinfo.doors_offset            =    -1;
  1804.     game_fileinfo.doors_howmany        =    Num_open_doors;
  1805.     game_fileinfo.doors_sizeof            =    sizeof(active_door);
  1806.     game_fileinfo.triggers_offset        =    -1;
  1807.     game_fileinfo.triggers_howmany    =    Num_triggers;
  1808.     game_fileinfo.triggers_sizeof        =    sizeof(trigger);
  1809.     game_fileinfo.control_offset        =    -1;
  1810.     game_fileinfo.control_howmany        =  1;
  1811.     game_fileinfo.control_sizeof        =  sizeof(control_center_triggers);
  1812.      game_fileinfo.matcen_offset        =    -1;
  1813.     game_fileinfo.matcen_howmany        =    Num_robot_centers;
  1814.     game_fileinfo.matcen_sizeof        =    sizeof(matcen_info);
  1815.  
  1816.     // Write the fileinfo
  1817.     fwrite( &game_fileinfo, sizeof(game_fileinfo), 1, SaveFile );
  1818.  
  1819.     // Write the mine name
  1820.     fprintf(SaveFile,Current_level_name);
  1821.     fputc(0,SaveFile);        //terminator for string
  1822.  
  1823.     fwrite(&N_save_pof_names,2,1,SaveFile);
  1824.     fwrite(Pof_names,N_polygon_models,13,SaveFile);
  1825.  
  1826.     //==================== SAVE PLAYER INFO ===========================
  1827.  
  1828.     player_offset = ftell(SaveFile);
  1829.     fwrite( &Players[Player_num], sizeof(player), 1, SaveFile );
  1830.  
  1831.     //==================== SAVE OBJECT INFO ===========================
  1832.  
  1833.     object_offset = ftell(SaveFile);
  1834.     //fwrite( &Objects, sizeof(object), game_fileinfo.object_howmany, SaveFile );
  1835.     {
  1836.         int i;
  1837.         for (i=0;i<game_fileinfo.object_howmany;i++)
  1838.             write_object(&Objects[i],SaveFile);
  1839.     }
  1840.  
  1841.     //==================== SAVE WALL INFO =============================
  1842.  
  1843.     walls_offset = ftell(SaveFile);
  1844.     fwrite( Walls, sizeof(wall), game_fileinfo.walls_howmany, SaveFile );
  1845.  
  1846.     //==================== SAVE DOOR INFO =============================
  1847.  
  1848.     doors_offset = ftell(SaveFile);
  1849.     fwrite( ActiveDoors, sizeof(active_door), game_fileinfo.doors_howmany, SaveFile );
  1850.  
  1851.     //==================== SAVE TRIGGER INFO =============================
  1852.  
  1853.     triggers_offset = ftell(SaveFile);
  1854.     fwrite( Triggers, sizeof(trigger), game_fileinfo.triggers_howmany, SaveFile );
  1855.  
  1856.     //================ SAVE CONTROL CENTER TRIGGER INFO ===============
  1857.  
  1858.     control_offset = ftell(SaveFile);
  1859.     fwrite( &ControlCenterTriggers, sizeof(control_center_triggers), 1, SaveFile );
  1860.  
  1861.  
  1862.     //================ SAVE MATERIALIZATION CENTER TRIGGER INFO ===============
  1863.  
  1864.     matcen_offset = ftell(SaveFile);
  1865.     // mprintf((0, "Writing %i materialization centers\n", game_fileinfo.matcen_howmany));
  1866.     // { int i;
  1867.     // for (i=0; i<game_fileinfo.matcen_howmany; i++)
  1868.     //     mprintf((0, "   %i: robot_flags = %08x\n", i, RobotCenters[i].robot_flags));
  1869.     // }
  1870.     fwrite( RobotCenters, sizeof(matcen_info), game_fileinfo.matcen_howmany, SaveFile );
  1871.  
  1872.     //============= REWRITE FILE INFO, TO SAVE OFFSETS ===============
  1873.  
  1874.     // Update the offset fields
  1875.     game_fileinfo.player_offset        =    player_offset;
  1876.     game_fileinfo.object_offset        =    object_offset;
  1877.     game_fileinfo.walls_offset            =    walls_offset;
  1878.     game_fileinfo.doors_offset            =    doors_offset;
  1879.     game_fileinfo.triggers_offset        =    triggers_offset;
  1880.     game_fileinfo.control_offset        =    control_offset;
  1881.     game_fileinfo.matcen_offset        =    matcen_offset;
  1882.  
  1883.  
  1884.     end_offset = ftell(SaveFile);
  1885.  
  1886.     // Write the fileinfo
  1887.     fseek(  SaveFile, start_offset, SEEK_SET );  // Move to TOF
  1888.     fwrite( &game_fileinfo, sizeof(game_fileinfo), 1, SaveFile );
  1889.  
  1890.     // Go back to end of data
  1891.     fseek(SaveFile,end_offset,SEEK_SET);
  1892.  
  1893.     return 0;
  1894. }
  1895.  
  1896. int save_mine_data(FILE * SaveFile);
  1897.  
  1898. // -----------------------------------------------------------------------------
  1899. // Save game
  1900. int save_level_sub(char * filename, int compiled_version)
  1901. {
  1902.     FILE * SaveFile;
  1903.     char temp_filename[128];
  1904.     int sig = 'PLVL',version=LEVEL_FILE_VERSION;
  1905.     int minedata_offset,gamedata_offset,hostagetext_offset;
  1906.  
  1907.     if ( !compiled_version )    {
  1908.         write_game_text_file(filename);
  1909.  
  1910.         if (Errors_in_mine) {
  1911.             if (is_real_level(filename)) {
  1912.                 char  ErrorMessage[200];
  1913.     
  1914.                 sprintf( ErrorMessage, "Warning: %i errors in this mine!\n", Errors_in_mine );
  1915.                 stop_time();
  1916.                 gr_palette_load(gr_palette);
  1917.      
  1918.                 if (nm_messagebox( NULL, 2, "Cancel Save", "Save", ErrorMessage )!=1)    {
  1919.                     start_time();
  1920.                     return 1;
  1921.                 }
  1922.                 start_time();
  1923.             } else
  1924.                 mprintf((1, "Error: %i errors in this mine.  See the 'txm' file.\n", Errors_in_mine));
  1925.         }
  1926.         convert_name_to_LVL(temp_filename,filename);
  1927.     } else {
  1928.         convert_name_to_CDL(temp_filename,filename);
  1929.     }
  1930.  
  1931.     SaveFile = fopen( temp_filename, "wb" );
  1932.     if (!SaveFile)
  1933.     {
  1934.         char ErrorMessage[256];
  1935.  
  1936.         char fname[20];
  1937.         _splitpath( temp_filename, NULL, NULL, fname, NULL );
  1938.  
  1939.         sprintf( ErrorMessage, \
  1940.             "ERROR: Cannot write to '%s'.\nYou probably need to check out a locked\nversion of the file. You should save\nthis under a different filename, and then\ncheck out a locked copy by typing\n\'co -l %s.lvl'\nat the DOS prompt.\n" 
  1941.             , temp_filename, fname );
  1942.         stop_time();
  1943.         gr_palette_load(gr_palette);
  1944.         nm_messagebox( NULL, 1, "Ok", ErrorMessage );
  1945.         start_time();
  1946.         return 1;
  1947.     }
  1948.  
  1949.     if (Current_level_name[0] == 0)
  1950.         strcpy(Current_level_name,"Untitled");
  1951.  
  1952.     clear_transient_objects(1);        //1 means clear proximity bombs
  1953.  
  1954.     compress_objects();        //after this, Highest_object_index == num objects
  1955.  
  1956.     //make sure player is in a segment
  1957.     if (update_object_seg(&Objects[Players[0].objnum]) == 0) {
  1958.         if (ConsoleObject->segnum > Highest_segment_index)
  1959.             ConsoleObject->segnum = 0;
  1960.         compute_segment_center(&ConsoleObject->pos,&(Segments[ConsoleObject->segnum]));
  1961.     }
  1962.  
  1963.     fix_object_segs();
  1964.  
  1965.     //Write the header
  1966.  
  1967.     gs_write_int(sig,SaveFile);
  1968.     gs_write_int(version,SaveFile);
  1969.  
  1970.     //save placeholders
  1971.     gs_write_int(minedata_offset,SaveFile);
  1972.     gs_write_int(gamedata_offset,SaveFile);
  1973.     gs_write_int(hostagetext_offset,SaveFile);
  1974.  
  1975.     //Now write the damn data
  1976.  
  1977.     minedata_offset = ftell(SaveFile);
  1978.     if ( !compiled_version )    
  1979.         save_mine_data(SaveFile);
  1980.     else
  1981.         save_mine_data_compiled(SaveFile);
  1982.     gamedata_offset = ftell(SaveFile);
  1983.     save_game_data(SaveFile);
  1984.     hostagetext_offset = ftell(SaveFile);
  1985.  
  1986.     #ifdef HOSTAGE_FACES
  1987.     save_hostage_data(SaveFile);
  1988.     #endif
  1989.  
  1990.     fseek(SaveFile,sizeof(sig)+sizeof(version),SEEK_SET);
  1991.     gs_write_int(minedata_offset,SaveFile);
  1992.     gs_write_int(gamedata_offset,SaveFile);
  1993.     gs_write_int(hostagetext_offset,SaveFile);
  1994.  
  1995.     //==================== CLOSE THE FILE =============================
  1996.     fclose(SaveFile);
  1997.  
  1998.     if ( !compiled_version )    {
  1999.         if (Function_mode == FMODE_EDITOR)
  2000.             editor_status("Saved mine %s, \"%s\"",filename,Current_level_name);
  2001.     }
  2002.  
  2003.     return 0;
  2004.  
  2005. }
  2006.  
  2007. int save_level(char * filename)
  2008. {
  2009.     int r1;
  2010.  
  2011.     // Save normal version...
  2012.     r1 = save_level_sub(filename, 0);
  2013.  
  2014.     // Save compiled version...
  2015.     save_level_sub(filename, 1);
  2016.  
  2017.     return r1;
  2018. }
  2019.  
  2020.  
  2021. #ifdef HOSTAGE_FACES
  2022. void save_hostage_data(FILE * fp)
  2023. {
  2024.     int i,num_hostages=0;
  2025.  
  2026.     // Find number of hostages in mine...
  2027.     for (i=0; i<=Highest_object_index; i++ )    {
  2028.         int num;
  2029.         if ( Objects[i].type == OBJ_HOSTAGE )    {
  2030.             num = Objects[i].id;
  2031.             #ifndef SHAREWARE
  2032.             if (num<0 || num>=MAX_HOSTAGES || Hostage_face_clip[Hostages[num].vclip_num].num_frames<=0)
  2033.                 num=0;
  2034.             #else
  2035.             num = 0;
  2036.             #endif
  2037.             if (num+1 > num_hostages)
  2038.                 num_hostages = num+1;
  2039.         }
  2040.     }
  2041.  
  2042.     gs_write_int(HOSTAGE_DATA_VERSION,fp);
  2043.  
  2044.     for (i=0; i<num_hostages; i++ )    {
  2045.         gs_write_int(Hostages[i].vclip_num,fp);
  2046.         fputs(Hostages[i].text,fp);
  2047.         fputc('\n',fp);        //fgets wants a newline
  2048.     }
  2049. }
  2050. #endif    //HOSTAGE_FACES
  2051.  
  2052. #endif    //EDITOR
  2053.  
  2054. #ifndef NDEBUG
  2055. void dump_mine_info(void)
  2056. {
  2057.     int    segnum, sidenum;
  2058.     fix    min_u, max_u, min_v, max_v, min_l, max_l, max_sl;
  2059.  
  2060.     min_u = F1_0*1000;
  2061.     min_v = min_u;
  2062.     min_l = min_u;
  2063.  
  2064.     max_u = -min_u;
  2065.     max_v = max_u;
  2066.     max_l = max_u;
  2067.  
  2068.     max_sl = 0;
  2069.  
  2070.     for (segnum=0; segnum<=Highest_segment_index; segnum++) {
  2071.         for (sidenum=0; sidenum<MAX_SIDES_PER_SEGMENT; sidenum++) {
  2072.             int    vertnum;
  2073.             side    *sidep = &Segments[segnum].sides[sidenum];
  2074.  
  2075.             if (Segments[segnum].static_light > max_sl)
  2076.                 max_sl = Segments[segnum].static_light;
  2077.  
  2078.             for (vertnum=0; vertnum<4; vertnum++) {
  2079.                 if (sidep->uvls[vertnum].u < min_u)
  2080.                     min_u = sidep->uvls[vertnum].u;
  2081.                 else if (sidep->uvls[vertnum].u > max_u)
  2082.                     max_u = sidep->uvls[vertnum].u;
  2083.  
  2084.                 if (sidep->uvls[vertnum].v < min_v)
  2085.                     min_v = sidep->uvls[vertnum].v;
  2086.                 else if (sidep->uvls[vertnum].v > max_v)
  2087.                     max_v = sidep->uvls[vertnum].v;
  2088.  
  2089.                 if (sidep->uvls[vertnum].l < min_l)
  2090.                     min_l = sidep->uvls[vertnum].l;
  2091.                 else if (sidep->uvls[vertnum].l > max_l)
  2092.                     max_l = sidep->uvls[vertnum].l;
  2093.             }
  2094.  
  2095.         }
  2096.     }
  2097.  
  2098. //    mprintf((0, "Smallest uvl = %7.3f %7.3f %7.3f.  Largest uvl = %7.3f %7.3f %7.3f\n", f2fl(min_u), f2fl(min_v), f2fl(min_l), f2fl(max_u), f2fl(max_v), f2fl(max_l)));
  2099. //    mprintf((0, "Static light maximum = %7.3f\n", f2fl(max_sl)));
  2100. //    mprintf((0, "Number of walls: %i\n", Num_walls));
  2101.  
  2102. }
  2103.  
  2104. #endif
  2105.  
  2106. #ifdef HOSTAGE_FACES
  2107. void load_hostage_data(CFILE * fp,int do_read)
  2108. {
  2109.     int version,i,num,num_hostages;
  2110.  
  2111.     hostage_init_all();
  2112.  
  2113.     num_hostages = 0;
  2114.  
  2115.     // Find number of hostages in mine...
  2116.     for (i=0; i<=Highest_object_index; i++ )    {
  2117.         if ( Objects[i].type == OBJ_HOSTAGE )    {
  2118.             num = Objects[i].id;
  2119.             if (num+1 > num_hostages)
  2120.                 num_hostages = num+1;
  2121.  
  2122.             if (Hostages[num].objnum != -1) {        //slot already used
  2123.                 num = hostage_get_next_slot();        //..so get new slot
  2124.                 if (num+1 > num_hostages)
  2125.                     num_hostages = num+1;
  2126.                 Objects[i].id = num;
  2127.             }
  2128.  
  2129.             if ( num > -1 && num < MAX_HOSTAGES )    {
  2130.                 Assert(Hostages[num].objnum == -1);        //make sure not used
  2131.                 // -- Matt -- commented out by MK on 11/19/94, hit often in level 3, level 4.  Assert(Hostages[num].objnum == -1);        //make sure not used
  2132.                 Hostages[num].objnum = i;
  2133.                 Hostages[num].objsig = Objects[i].signature;
  2134.             }
  2135.         }
  2136.     }
  2137.  
  2138.     if (do_read) {
  2139.         version = read_int(fp);
  2140.  
  2141.         for (i=0;i<num_hostages;i++) {
  2142.  
  2143.             Assert(Hostages[i].objnum != -1);        //make sure slot filled in
  2144.  
  2145.             Hostages[i].vclip_num = read_int(fp);
  2146.  
  2147.             #ifndef SHAREWARE
  2148.             if (Hostages[i].vclip_num<0 || Hostages[i].vclip_num>=MAX_HOSTAGES || Hostage_face_clip[Hostages[i].vclip_num].num_frames<=0)
  2149.                 Hostages[i].vclip_num=0;
  2150.  
  2151.             Assert(Hostage_face_clip[Hostages[i].vclip_num].num_frames);
  2152.             #endif
  2153.  
  2154.             cfgets(Hostages[i].text, HOSTAGE_MESSAGE_LEN, fp);
  2155.  
  2156.             if (Hostages[i].text[strlen(Hostages[i].text)-1]=='\n')
  2157.                 Hostages[i].text[strlen(Hostages[i].text)-1] = 0;
  2158.         }
  2159.     }
  2160.     else
  2161.         for (i=0;i<num_hostages;i++) {
  2162.             Assert(Hostages[i].objnum != -1);        //make sure slot filled in
  2163.             Hostages[i].vclip_num = 0;
  2164.         }
  2165.  
  2166. }
  2167. #endif    //HOSTAGE_FACES
  2168.  
  2169. 
  2170.