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