]> icculus.org git repositories - btb/d2x.git/blob - main/gamesave.c
fix a bug introduced with change of 2004-06-26
[btb/d2x.git] / main / gamesave.c
1 /* $Id: gamesave.c,v 1.23 2004-08-17 18:02:43 schaffner 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.23 2004-08-17 18:02:43 schaffner 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 #if 0
356 struct {
357         ushort  fileinfo_signature;
358         ushort  fileinfo_version;
359         int     fileinfo_sizeof;
360 } game_top_fileinfo;    // Should be same as first two fields below...
361
362 struct {
363         ushort  fileinfo_signature;
364         ushort  fileinfo_version;
365         int     fileinfo_sizeof;
366         char    mine_filename[15];
367         int     level;
368         int     player_offset;              // Player info
369         int     player_sizeof;
370         int     object_offset;              // Object info
371         int     object_howmany;
372         int     object_sizeof;
373         int     walls_offset;
374         int     walls_howmany;
375         int     walls_sizeof;
376         int     doors_offset;
377         int     doors_howmany;
378         int     doors_sizeof;
379         int     triggers_offset;
380         int     triggers_howmany;
381         int     triggers_sizeof;
382         int     links_offset;
383         int     links_howmany;
384         int     links_sizeof;
385         int     control_offset;
386         int     control_howmany;
387         int     control_sizeof;
388         int     matcen_offset;
389         int     matcen_howmany;
390         int     matcen_sizeof;
391         int     dl_indices_offset;
392         int     dl_indices_howmany;
393         int     dl_indices_sizeof;
394         int     delta_light_offset;
395         int     delta_light_howmany;
396         int     delta_light_sizeof;
397 } game_fileinfo;
398 #endif // 0
399
400 //  LINT: adding function prototypes
401 void read_object(object *obj, CFILE *f, int version);
402 #ifdef EDITOR
403 void write_object(object *obj, FILE *f);
404 void do_load_save_levels(int save);
405 #endif
406 #ifndef NDEBUG
407 void dump_mine_info(void);
408 #endif
409
410 extern char MaxPowerupsAllowed[MAX_POWERUP_TYPES];
411 extern char PowerupsInMine[MAX_POWERUP_TYPES];
412
413 #ifdef EDITOR
414 extern char mine_filename[];
415 extern int save_mine_data_compiled(FILE * SaveFile);
416 //--unused-- #else
417 //--unused-- char mine_filename[128];
418 #endif
419
420 int Gamesave_num_org_robots = 0;
421 //--unused-- grs_bitmap * Gamesave_saved_bitmap = NULL;
422
423 #ifdef EDITOR
424 // Return true if this level has a name of the form "level??"
425 // Note that a pathspec can appear at the beginning of the filename.
426 int is_real_level(char *filename)
427 {
428         int len = strlen(filename);
429
430         if (len < 6)
431                 return 0;
432
433         //mprintf((0, "String = [%s]\n", &filename[len-11]));
434         return !strnicmp(&filename[len-11], "level", 5);
435
436 }
437 #endif
438
439 void change_filename_extension( char *dest, char *src, char *new_ext )
440 {
441         int i;
442
443         strcpy (dest, src);
444
445         if (new_ext[0]=='.')
446                 new_ext++;
447
448         for (i=1; i<strlen(dest); i++ )
449                 if (dest[i]=='.'||dest[i]==' '||dest[i]==0)
450                         break;
451
452         if (i < 123) {
453                 dest[i]='.';
454                 dest[i+1]=new_ext[0];
455                 dest[i+2]=new_ext[1];
456                 dest[i+3]=new_ext[2];
457                 dest[i+4]=0;
458                 return;
459         }
460 }
461
462 //--unused-- vms_angvec zero_angles={0,0,0};
463
464 #define vm_angvec_zero(v) do {(v)->p=(v)->b=(v)->h=0;} while (0)
465
466 int Gamesave_num_players=0;
467
468 int N_save_pof_names;
469 char Save_pof_names[MAX_POLYGON_MODELS][FILENAME_LEN];
470
471 void check_and_fix_matrix(vms_matrix *m);
472
473 void verify_object( object * obj )      {
474
475         obj->lifeleft = IMMORTAL_TIME;          //all loaded object are immortal, for now
476
477         if ( obj->type == OBJ_ROBOT )   {
478                 Gamesave_num_org_robots++;
479
480                 // Make sure valid id...
481                 if ( obj->id >= N_robot_types )
482                         obj->id = obj->id % N_robot_types;
483
484                 // Make sure model number & size are correct...
485                 if ( obj->render_type == RT_POLYOBJ ) {
486                         Assert(Robot_info[obj->id].model_num != -1);
487                                 //if you fail this assert, it means that a robot in this level
488                                 //hasn't been loaded, possibly because he's marked as
489                                 //non-shareware.  To see what robot number, print obj->id.
490
491                         Assert(Robot_info[obj->id].always_0xabcd == 0xabcd);
492                                 //if you fail this assert, it means that the robot_ai for
493                                 //a robot in this level hasn't been loaded, possibly because
494                                 //it's marked as non-shareware.  To see what robot number,
495                                 //print obj->id.
496
497                         obj->rtype.pobj_info.model_num = Robot_info[obj->id].model_num;
498                         obj->size = Polygon_models[obj->rtype.pobj_info.model_num].rad;
499
500                         //@@Took out this ugly hack 1/12/96, because Mike has added code
501                         //@@that should fix it in a better way.
502                         //@@//this is a super-ugly hack.  Since the baby stripe robots have
503                         //@@//their firing point on their bounding sphere, the firing points
504                         //@@//can poke through a wall if the robots are very close to it. So
505                         //@@//we make their radii bigger so the guns can't get too close to 
506                         //@@//the walls
507                         //@@if (Robot_info[obj->id].flags & RIF_BIG_RADIUS)
508                         //@@    obj->size = (obj->size*3)/2;
509
510                         //@@if (obj->control_type==CT_AI && Robot_info[obj->id].attack_type)
511                         //@@    obj->size = obj->size*3/4;
512                 }
513
514                 if (obj->id == 65)                                              //special "reactor" robots
515                         obj->movement_type = MT_NONE;
516
517                 if (obj->movement_type == MT_PHYSICS) {
518                         obj->mtype.phys_info.mass = Robot_info[obj->id].mass;
519                         obj->mtype.phys_info.drag = Robot_info[obj->id].drag;
520                 }
521         }
522         else {          //Robots taken care of above
523
524                 if ( obj->render_type == RT_POLYOBJ ) {
525                         int i;
526                         char *name = Save_pof_names[obj->rtype.pobj_info.model_num];
527
528                         for (i=0;i<N_polygon_models;i++)
529                                 if (!stricmp(Pof_names[i],name)) {              //found it!     
530                                         // mprintf((0,"Mapping <%s> to %d (was %d)\n",name,i,obj->rtype.pobj_info.model_num));
531                                         obj->rtype.pobj_info.model_num = i;
532                                         break;
533                                 }
534                 }
535         }
536
537         if ( obj->type == OBJ_POWERUP ) {
538                 if ( obj->id >= N_powerup_types )       {
539                         obj->id = 0;
540                         Assert( obj->render_type != RT_POLYOBJ );
541                 }
542                 obj->control_type = CT_POWERUP;
543                 obj->size = Powerup_info[obj->id].size;
544                 obj->ctype.powerup_info.creation_time = 0;
545
546 #ifdef NETWORK
547                 if (Game_mode & GM_NETWORK)
548                         {
549                           if (multi_powerup_is_4pack(obj->id))
550                                 {
551                                  PowerupsInMine[obj->id-1]+=4;
552                                  MaxPowerupsAllowed[obj->id-1]+=4;
553                                 }
554                           PowerupsInMine[obj->id]++;
555                      MaxPowerupsAllowed[obj->id]++;
556                           mprintf ((0,"PowerupLimiter: ID=%d\n",obj->id));
557                           if (obj->id>MAX_POWERUP_TYPES)
558                                 mprintf ((1,"POWERUP: Overwriting array bounds!! Get JL!\n"));
559                         }
560 #endif
561
562         }
563
564         if ( obj->type == OBJ_WEAPON )  {
565                 if ( obj->id >= N_weapon_types )        {
566                         obj->id = 0;
567                         Assert( obj->render_type != RT_POLYOBJ );
568                 }
569
570                 if (obj->id == PMINE_ID) {              //make sure pmines have correct values
571
572                         obj->mtype.phys_info.mass = Weapon_info[obj->id].mass;
573                         obj->mtype.phys_info.drag = Weapon_info[obj->id].drag;
574                         obj->mtype.phys_info.flags |= PF_FREE_SPINNING;
575
576                         // Make sure model number & size are correct...         
577                         Assert( obj->render_type == RT_POLYOBJ );
578
579                         obj->rtype.pobj_info.model_num = Weapon_info[obj->id].model_num;
580                         obj->size = Polygon_models[obj->rtype.pobj_info.model_num].rad;
581                 }
582         }
583
584         if ( obj->type == OBJ_CNTRLCEN ) {
585
586                 obj->render_type = RT_POLYOBJ;
587                 obj->control_type = CT_CNTRLCEN;
588
589                 if (Gamesave_current_version <= 1) { // descent 1 reactor
590                         obj->id = 0;                         // used to be only one kind of reactor
591                         obj->rtype.pobj_info.model_num = Reactors[0].model_num;// descent 1 reactor
592                 }
593                 //@@// Make model number is correct...
594                 //@@for (i=0; i<Num_total_object_types; i++ )
595                 //@@    if ( ObjType[i] == OL_CONTROL_CENTER ) {
596                 //@@            obj->rtype.pobj_info.model_num = ObjId[i];
597                 //@@            obj->shields = ObjStrength[i];
598                 //@@            break;
599                 //@@    }
600
601                 #ifdef EDITOR
602                 {
603                 int i;
604                 // Check, and set, strength of reactor
605                 for (i=0; i<Num_total_object_types; i++ )       
606                         if ( ObjType[i]==OL_CONTROL_CENTER && ObjId[i] == obj->id ) {
607                                 obj->shields = ObjStrength[i];
608                                 break;          
609                         }
610                 Assert(i < Num_total_object_types);             //make sure we found it
611                 }
612                 #endif
613         }
614
615         if ( obj->type == OBJ_PLAYER )  {
616                 //int i;
617
618                 //Assert(obj == Player);
619
620                 if ( obj == ConsoleObject )             
621                         init_player_object();
622                 else
623                         if (obj->render_type == RT_POLYOBJ)     //recover from Matt's pof file matchup bug
624                                 obj->rtype.pobj_info.model_num = Player_ship->model_num;
625
626                 //Make sure orient matrix is orthogonal
627                 check_and_fix_matrix(&obj->orient);
628
629                 obj->id = Gamesave_num_players++;
630         }
631
632         if (obj->type == OBJ_HOSTAGE) {
633
634                 //@@if (obj->id > N_hostage_types)
635                 //@@    obj->id = 0;
636
637                 obj->render_type = RT_HOSTAGE;
638                 obj->control_type = CT_POWERUP;
639         }
640
641 }
642
643 //static gs_skip(int len,CFILE *file)
644 //{
645 //
646 //      cfseek(file,len,SEEK_CUR);
647 //}
648
649 #ifdef EDITOR
650 static void gs_write_int(int i,FILE *file)
651 {
652         if (fwrite( &i, sizeof(i), 1, file) != 1)
653                 Error( "Error reading int in gamesave.c" );
654
655 }
656
657 static void gs_write_fix(fix f,FILE *file)
658 {
659         if (fwrite( &f, sizeof(f), 1, file) != 1)
660                 Error( "Error reading fix in gamesave.c" );
661
662 }
663
664 static void gs_write_short(short s,FILE *file)
665 {
666         if (fwrite( &s, sizeof(s), 1, file) != 1)
667                 Error( "Error reading short in gamesave.c" );
668
669 }
670
671 static void gs_write_fixang(fixang f,FILE *file)
672 {
673         if (fwrite( &f, sizeof(f), 1, file) != 1)
674                 Error( "Error reading fixang in gamesave.c" );
675
676 }
677
678 static void gs_write_byte(byte b,FILE *file)
679 {
680         if (fwrite( &b, sizeof(b), 1, file) != 1)
681                 Error( "Error reading byte in gamesave.c" );
682
683 }
684
685 static void gr_write_vector(vms_vector *v,FILE *file)
686 {
687         gs_write_fix(v->x,file);
688         gs_write_fix(v->y,file);
689         gs_write_fix(v->z,file);
690 }
691
692 static void gs_write_matrix(vms_matrix *m,FILE *file)
693 {
694         gr_write_vector(&m->rvec,file);
695         gr_write_vector(&m->uvec,file);
696         gr_write_vector(&m->fvec,file);
697 }
698
699 static void gs_write_angvec(vms_angvec *v,FILE *file)
700 {
701         gs_write_fixang(v->p,file);
702         gs_write_fixang(v->b,file);
703         gs_write_fixang(v->h,file);
704 }
705
706 #endif
707
708
709 extern int multi_powerup_is_4pack(int);
710 //reads one object of the given version from the given file
711 void read_object(object *obj,CFILE *f,int version)
712 {
713
714         obj->type           = cfile_read_byte(f);
715         obj->id             = cfile_read_byte(f);
716
717         obj->control_type   = cfile_read_byte(f);
718         obj->movement_type  = cfile_read_byte(f);
719         obj->render_type    = cfile_read_byte(f);
720         obj->flags          = cfile_read_byte(f);
721
722         obj->segnum         = cfile_read_short(f);
723         obj->attached_obj   = -1;
724
725         cfile_read_vector(&obj->pos,f);
726         cfile_read_matrix(&obj->orient,f);
727
728         obj->size           = cfile_read_fix(f);
729         obj->shields        = cfile_read_fix(f);
730
731         cfile_read_vector(&obj->last_pos,f);
732
733         obj->contains_type  = cfile_read_byte(f);
734         obj->contains_id    = cfile_read_byte(f);
735         obj->contains_count = cfile_read_byte(f);
736
737         switch (obj->movement_type) {
738
739                 case MT_PHYSICS:
740
741                         cfile_read_vector(&obj->mtype.phys_info.velocity,f);
742                         cfile_read_vector(&obj->mtype.phys_info.thrust,f);
743
744                         obj->mtype.phys_info.mass               = cfile_read_fix(f);
745                         obj->mtype.phys_info.drag               = cfile_read_fix(f);
746                         obj->mtype.phys_info.brakes     = cfile_read_fix(f);
747
748                         cfile_read_vector(&obj->mtype.phys_info.rotvel,f);
749                         cfile_read_vector(&obj->mtype.phys_info.rotthrust,f);
750
751                         obj->mtype.phys_info.turnroll   = cfile_read_fixang(f);
752                         obj->mtype.phys_info.flags              = cfile_read_short(f);
753
754                         break;
755
756                 case MT_SPINNING:
757
758                         cfile_read_vector(&obj->mtype.spin_rate,f);
759                         break;
760
761                 case MT_NONE:
762                         break;
763
764                 default:
765                         Int3();
766         }
767
768         switch (obj->control_type) {
769
770                 case CT_AI: {
771                         int i;
772
773                         obj->ctype.ai_info.behavior                             = cfile_read_byte(f);
774
775                         for (i=0;i<MAX_AI_FLAGS;i++)
776                                 obj->ctype.ai_info.flags[i]                     = cfile_read_byte(f);
777
778                         obj->ctype.ai_info.hide_segment                 = cfile_read_short(f);
779                         obj->ctype.ai_info.hide_index                   = cfile_read_short(f);
780                         obj->ctype.ai_info.path_length                  = cfile_read_short(f);
781                         obj->ctype.ai_info.cur_path_index               = cfile_read_short(f);
782
783                         if (version <= 25) {
784                                 cfile_read_short(f);    //                              obj->ctype.ai_info.follow_path_start_seg        = 
785                                 cfile_read_short(f);    //                              obj->ctype.ai_info.follow_path_end_seg          = 
786                         }
787
788                         break;
789                 }
790
791                 case CT_EXPLOSION:
792
793                         obj->ctype.expl_info.spawn_time         = cfile_read_fix(f);
794                         obj->ctype.expl_info.delete_time                = cfile_read_fix(f);
795                         obj->ctype.expl_info.delete_objnum      = cfile_read_short(f);
796                         obj->ctype.expl_info.next_attach = obj->ctype.expl_info.prev_attach = obj->ctype.expl_info.attach_parent = -1;
797
798                         break;
799
800                 case CT_WEAPON:
801
802                         //do I really need to read these?  Are they even saved to disk?
803
804                         obj->ctype.laser_info.parent_type               = cfile_read_short(f);
805                         obj->ctype.laser_info.parent_num                = cfile_read_short(f);
806                         obj->ctype.laser_info.parent_signature  = cfile_read_int(f);
807
808                         break;
809
810                 case CT_LIGHT:
811
812                         obj->ctype.light_info.intensity = cfile_read_fix(f);
813                         break;
814
815                 case CT_POWERUP:
816
817                         if (version >= 25)
818                                 obj->ctype.powerup_info.count = cfile_read_int(f);
819                         else
820                                 obj->ctype.powerup_info.count = 1;
821
822                         if (obj->id == POW_VULCAN_WEAPON)
823                                         obj->ctype.powerup_info.count = VULCAN_WEAPON_AMMO_AMOUNT;
824
825                         if (obj->id == POW_GAUSS_WEAPON)
826                                         obj->ctype.powerup_info.count = VULCAN_WEAPON_AMMO_AMOUNT;
827
828                         if (obj->id == POW_OMEGA_WEAPON)
829                                         obj->ctype.powerup_info.count = MAX_OMEGA_CHARGE;
830
831                         break;
832
833
834                 case CT_NONE:
835                 case CT_FLYING:
836                 case CT_DEBRIS:
837                         break;
838
839                 case CT_SLEW:           //the player is generally saved as slew
840                         break;
841
842                 case CT_CNTRLCEN:
843                         break;
844
845                 case CT_MORPH:
846                 case CT_FLYTHROUGH:
847                 case CT_REPAIRCEN:
848                 default:
849                         Int3();
850         
851         }
852
853         switch (obj->render_type) {
854
855                 case RT_NONE:
856                         break;
857
858                 case RT_MORPH:
859                 case RT_POLYOBJ: {
860                         int i,tmo;
861
862                         obj->rtype.pobj_info.model_num          = cfile_read_int(f);
863
864                         for (i=0;i<MAX_SUBMODELS;i++)
865                                 cfile_read_angvec(&obj->rtype.pobj_info.anim_angles[i],f);
866
867                         obj->rtype.pobj_info.subobj_flags       = cfile_read_int(f);
868
869                         tmo = cfile_read_int(f);
870
871                         #ifndef EDITOR
872                         obj->rtype.pobj_info.tmap_override      = tmo;
873                         #else
874                         if (tmo==-1)
875                                 obj->rtype.pobj_info.tmap_override      = -1;
876                         else {
877                                 int xlated_tmo = tmap_xlate_table[tmo];
878                                 if (xlated_tmo < 0)     {
879                                         mprintf( (0, "Couldn't find texture for demo object, model_num = %d\n", obj->rtype.pobj_info.model_num));
880                                         Int3();
881                                         xlated_tmo = 0;
882                                 }
883                                 obj->rtype.pobj_info.tmap_override      = xlated_tmo;
884                         }
885                         #endif
886
887                         obj->rtype.pobj_info.alt_textures       = 0;
888
889                         break;
890                 }
891
892                 case RT_WEAPON_VCLIP:
893                 case RT_HOSTAGE:
894                 case RT_POWERUP:
895                 case RT_FIREBALL:
896
897                         obj->rtype.vclip_info.vclip_num = cfile_read_int(f);
898                         obj->rtype.vclip_info.frametime = cfile_read_fix(f);
899                         obj->rtype.vclip_info.framenum  = cfile_read_byte(f);
900
901                         break;
902
903                 case RT_LASER:
904                         break;
905
906                 default:
907                         Int3();
908
909         }
910
911 }
912
913 #ifdef EDITOR
914
915 //writes one object to the given file
916 void write_object(object *obj,FILE *f)
917 {
918         gs_write_byte(obj->type,f);
919         gs_write_byte(obj->id,f);
920
921         gs_write_byte(obj->control_type,f);
922         gs_write_byte(obj->movement_type,f);
923         gs_write_byte(obj->render_type,f);
924         gs_write_byte(obj->flags,f);
925
926         gs_write_short(obj->segnum,f);
927
928         gr_write_vector(&obj->pos,f);
929         gs_write_matrix(&obj->orient,f);
930
931         gs_write_fix(obj->size,f);
932         gs_write_fix(obj->shields,f);
933
934         gr_write_vector(&obj->last_pos,f);
935
936         gs_write_byte(obj->contains_type,f);
937         gs_write_byte(obj->contains_id,f);
938         gs_write_byte(obj->contains_count,f);
939
940         switch (obj->movement_type) {
941
942                 case MT_PHYSICS:
943
944                         gr_write_vector(&obj->mtype.phys_info.velocity,f);
945                         gr_write_vector(&obj->mtype.phys_info.thrust,f);
946
947                         gs_write_fix(obj->mtype.phys_info.mass,f);
948                         gs_write_fix(obj->mtype.phys_info.drag,f);
949                         gs_write_fix(obj->mtype.phys_info.brakes,f);
950
951                         gr_write_vector(&obj->mtype.phys_info.rotvel,f);
952                         gr_write_vector(&obj->mtype.phys_info.rotthrust,f);
953
954                         gs_write_fixang(obj->mtype.phys_info.turnroll,f);
955                         gs_write_short(obj->mtype.phys_info.flags,f);
956
957                         break;
958
959                 case MT_SPINNING:
960
961                         gr_write_vector(&obj->mtype.spin_rate,f);
962                         break;
963
964                 case MT_NONE:
965                         break;
966
967                 default:
968                         Int3();
969         }
970
971         switch (obj->control_type) {
972
973                 case CT_AI: {
974                         int i;
975
976                         gs_write_byte(obj->ctype.ai_info.behavior,f);
977
978                         for (i=0;i<MAX_AI_FLAGS;i++)
979                                 gs_write_byte(obj->ctype.ai_info.flags[i],f);
980
981                         gs_write_short(obj->ctype.ai_info.hide_segment,f);
982                         gs_write_short(obj->ctype.ai_info.hide_index,f);
983                         gs_write_short(obj->ctype.ai_info.path_length,f);
984                         gs_write_short(obj->ctype.ai_info.cur_path_index,f);
985
986                         // -- unused! mk, 08/13/95 -- gs_write_short(obj->ctype.ai_info.follow_path_start_seg,f);
987                         // -- unused! mk, 08/13/95 -- gs_write_short(obj->ctype.ai_info.follow_path_end_seg,f);
988
989                         break;
990                 }
991
992                 case CT_EXPLOSION:
993
994                         gs_write_fix(obj->ctype.expl_info.spawn_time,f);
995                         gs_write_fix(obj->ctype.expl_info.delete_time,f);
996                         gs_write_short(obj->ctype.expl_info.delete_objnum,f);
997
998                         break;
999
1000                 case CT_WEAPON:
1001
1002                         //do I really need to write these objects?
1003
1004                         gs_write_short(obj->ctype.laser_info.parent_type,f);
1005                         gs_write_short(obj->ctype.laser_info.parent_num,f);
1006                         gs_write_int(obj->ctype.laser_info.parent_signature,f);
1007
1008                         break;
1009
1010                 case CT_LIGHT:
1011
1012                         gs_write_fix(obj->ctype.light_info.intensity,f);
1013                         break;
1014
1015                 case CT_POWERUP:
1016
1017                         gs_write_int(obj->ctype.powerup_info.count,f);
1018                         break;
1019
1020                 case CT_NONE:
1021                 case CT_FLYING:
1022                 case CT_DEBRIS:
1023                         break;
1024
1025                 case CT_SLEW:           //the player is generally saved as slew
1026                         break;
1027
1028                 case CT_CNTRLCEN:
1029                         break;                  //control center object.
1030
1031                 case CT_MORPH:
1032                 case CT_REPAIRCEN:
1033                 case CT_FLYTHROUGH:
1034                 default:
1035                         Int3();
1036         
1037         }
1038
1039         switch (obj->render_type) {
1040
1041                 case RT_NONE:
1042                         break;
1043
1044                 case RT_MORPH:
1045                 case RT_POLYOBJ: {
1046                         int i;
1047
1048                         gs_write_int(obj->rtype.pobj_info.model_num,f);
1049
1050                         for (i=0;i<MAX_SUBMODELS;i++)
1051                                 gs_write_angvec(&obj->rtype.pobj_info.anim_angles[i],f);
1052
1053                         gs_write_int(obj->rtype.pobj_info.subobj_flags,f);
1054
1055                         gs_write_int(obj->rtype.pobj_info.tmap_override,f);
1056
1057                         break;
1058                 }
1059
1060                 case RT_WEAPON_VCLIP:
1061                 case RT_HOSTAGE:
1062                 case RT_POWERUP:
1063                 case RT_FIREBALL:
1064
1065                         gs_write_int(obj->rtype.vclip_info.vclip_num,f);
1066                         gs_write_fix(obj->rtype.vclip_info.frametime,f);
1067                         gs_write_byte(obj->rtype.vclip_info.framenum,f);
1068
1069                         break;
1070
1071                 case RT_LASER:
1072                         break;
1073
1074                 default:
1075                         Int3();
1076
1077         }
1078
1079 }
1080 #endif
1081
1082 extern int remove_trigger_num(int trigger_num);
1083
1084 // --------------------------------------------------------------------
1085 // Load game 
1086 // Loads all the relevant data for a level.
1087 // If level != -1, it loads the filename with extension changed to .min
1088 // Otherwise it loads the appropriate level mine.
1089 // returns 0=everything ok, 1=old version, -1=error
1090 int load_game_data(CFILE *LoadFile)
1091 {
1092         int i,j;
1093
1094         short game_top_fileinfo_version;
1095         int object_offset;
1096         int gs_num_objects;
1097         int num_delta_lights;
1098         int trig_size;
1099
1100         //===================== READ FILE INFO ========================
1101
1102 #if 0
1103         cfread(&game_top_fileinfo, sizeof(game_top_fileinfo), 1, LoadFile);
1104 #endif
1105
1106         // Check signature
1107         if (cfile_read_short(LoadFile) != 0x6705)
1108                 return -1;
1109
1110         // Read and check version number
1111         game_top_fileinfo_version = cfile_read_short(LoadFile);
1112         if (game_top_fileinfo_version < GAME_COMPATIBLE_VERSION )
1113                 return -1;
1114
1115         // We skip some parts of the former game_top_fileinfo
1116         cfseek(LoadFile, 31, SEEK_CUR);
1117
1118         object_offset = cfile_read_int(LoadFile);
1119         gs_num_objects = cfile_read_int(LoadFile);
1120         cfseek(LoadFile, 8, SEEK_CUR);
1121
1122         Num_walls = cfile_read_int(LoadFile);
1123         cfseek(LoadFile, 20, SEEK_CUR);
1124
1125         Num_triggers = cfile_read_int(LoadFile);
1126         cfseek(LoadFile, 24, SEEK_CUR);
1127
1128         trig_size = cfile_read_int(LoadFile);
1129         Assert(trig_size == sizeof(ControlCenterTriggers));
1130         cfseek(LoadFile, 4, SEEK_CUR);
1131
1132         Num_robot_centers = cfile_read_int(LoadFile);
1133         cfseek(LoadFile, 4, SEEK_CUR);
1134
1135         if (game_top_fileinfo_version >= 29) {
1136                 cfseek(LoadFile, 4, SEEK_CUR);
1137                 Num_static_lights = cfile_read_int(LoadFile);
1138                 cfseek(LoadFile, 8, SEEK_CUR);
1139                 num_delta_lights = cfile_read_int(LoadFile);
1140                 cfseek(LoadFile, 4, SEEK_CUR);
1141         } else {
1142                 Num_static_lights = 0;
1143                 num_delta_lights = 0;
1144         }
1145
1146         if (game_top_fileinfo_version >= 31) { //load mine filename
1147                 // read newline-terminated string, not sure what version this changed.
1148                 cfgets(Current_level_name,sizeof(Current_level_name),LoadFile);
1149
1150                 if (Current_level_name[strlen(Current_level_name)-1] == '\n')
1151                         Current_level_name[strlen(Current_level_name)-1] = 0;
1152         }
1153         else if (game_top_fileinfo_version >= 14) { //load mine filename
1154                 // read null-terminated string
1155                 char *p=Current_level_name;
1156                 //must do read one char at a time, since no cfgets()
1157                 do *p = cfgetc(LoadFile); while (*p++!=0);
1158         }
1159         else
1160                 Current_level_name[0]=0;
1161
1162         if (game_top_fileinfo_version >= 19) {  //load pof names
1163                 N_save_pof_names = cfile_read_short(LoadFile);
1164                 if (N_save_pof_names != 0x614d && N_save_pof_names != 0x5547) { // "Ma"de w/DMB beta/"GU"ILE
1165                         Assert(N_save_pof_names < MAX_POLYGON_MODELS);
1166                         cfread(Save_pof_names,N_save_pof_names,FILENAME_LEN,LoadFile);
1167                 }
1168         }
1169
1170         //===================== READ PLAYER INFO ==========================
1171         Object_next_signature = 0;
1172
1173         //===================== READ OBJECT INFO ==========================
1174
1175         Gamesave_num_org_robots = 0;
1176         Gamesave_num_players = 0;
1177
1178         if (object_offset > -1) {
1179                 if (cfseek( LoadFile, object_offset, SEEK_SET ))
1180                         Error( "Error seeking to object_offset in gamesave.c" );
1181
1182                 for (i = 0; i < gs_num_objects; i++) {
1183
1184                         read_object(&Objects[i], LoadFile, game_top_fileinfo_version);
1185
1186                         Objects[i].signature = Object_next_signature++;
1187                         verify_object( &Objects[i] );
1188                 }
1189
1190         }
1191
1192         //===================== READ WALL INFO ============================
1193
1194         for (i = 0; i < Num_walls; i++) {
1195                 if (game_top_fileinfo_version >= 20)
1196                         wall_read(&Walls[i], LoadFile); // v20 walls and up.
1197                 else if (game_top_fileinfo_version >= 17) {
1198                         v19_wall w;
1199                         v19_wall_read(&w, LoadFile);
1200                         Walls[i].segnum         = w.segnum;
1201                         Walls[i].sidenum        = w.sidenum;
1202                         Walls[i].linked_wall    = w.linked_wall;
1203                         Walls[i].type           = w.type;
1204                         Walls[i].flags          = w.flags;
1205                         Walls[i].hps            = w.hps;
1206                         Walls[i].trigger        = w.trigger;
1207                         Walls[i].clip_num       = w.clip_num;
1208                         Walls[i].keys           = w.keys;
1209                         Walls[i].state          = WALL_DOOR_CLOSED;
1210                 } else {
1211                         v16_wall w;
1212                         v16_wall_read(&w, LoadFile);
1213                         Walls[i].segnum = Walls[i].sidenum = Walls[i].linked_wall = -1;
1214                         Walls[i].type           = w.type;
1215                         Walls[i].flags          = w.flags;
1216                         Walls[i].hps            = w.hps;
1217                         Walls[i].trigger        = w.trigger;
1218                         Walls[i].clip_num       = w.clip_num;
1219                         Walls[i].keys           = w.keys;
1220                 }
1221         }
1222
1223 #if 0
1224         //===================== READ DOOR INFO ============================
1225
1226         if (game_fileinfo.doors_offset > -1)
1227         {
1228                 if (!cfseek( LoadFile, game_fileinfo.doors_offset,SEEK_SET ))   {
1229
1230                         for (i=0;i<game_fileinfo.doors_howmany;i++) {
1231
1232                                 if (game_top_fileinfo_version >= 20)
1233                                         active_door_read(&ActiveDoors[i], LoadFile); // version 20 and up
1234                                 else {
1235                                         v19_door d;
1236                                         int p;
1237
1238                                         v19_door_read(&d, LoadFile);
1239
1240                                         ActiveDoors[i].n_parts = d.n_parts;
1241
1242                                         for (p=0;p<d.n_parts;p++) {
1243                                                 int cseg,cside;
1244
1245                                                 cseg = Segments[d.seg[p]].children[d.side[p]];
1246                                                 cside = find_connect_side(&Segments[d.seg[p]],&Segments[cseg]);
1247
1248                                                 ActiveDoors[i].front_wallnum[p] = Segments[d.seg[p]].sides[d.side[p]].wall_num;
1249                                                 ActiveDoors[i].back_wallnum[p] = Segments[cseg].sides[cside].wall_num;
1250                                         }
1251                                 }
1252
1253                         }
1254                 }
1255         }
1256 #endif // 0
1257
1258         //==================== READ TRIGGER INFO ==========================
1259
1260
1261 // for MACINTOSH -- assume all triggers >= verion 31 triggers.
1262
1263         for (i = 0; i < Num_triggers; i++)
1264         {
1265                 if (game_top_fileinfo_version < 31)
1266                 {
1267                         v30_trigger trig;
1268                         int t,type;
1269                         type=0;
1270
1271                         if (game_top_fileinfo_version < 30) {
1272                                 v29_trigger trig29;
1273                                 int t;
1274                                 v29_trigger_read(&trig29, LoadFile);
1275                                 trig.flags      = trig29.flags;
1276                                 trig.num_links  = trig29.num_links;
1277                                 trig.num_links  = trig29.num_links;
1278                                 trig.value      = trig29.value;
1279                                 trig.time       = trig29.time;
1280
1281                                 for (t=0;t<trig.num_links;t++) {
1282                                         trig.seg[t]  = trig29.seg[t];
1283                                         trig.side[t] = trig29.side[t];
1284                                 }
1285                         }
1286                         else
1287                                 v30_trigger_read(&trig, LoadFile);
1288
1289                         //Assert(trig.flags & TRIGGER_ON);
1290                         trig.flags &= ~TRIGGER_ON;
1291
1292                         if (trig.flags & TRIGGER_CONTROL_DOORS)
1293                                 type = TT_OPEN_DOOR;
1294                         else if (trig.flags & TRIGGER_SHIELD_DAMAGE)
1295                                 Int3();
1296                         else if (trig.flags & TRIGGER_ENERGY_DRAIN)
1297                                 Int3();
1298                         else if (trig.flags & TRIGGER_EXIT)
1299                                 type = TT_EXIT;
1300                         else if (trig.flags & TRIGGER_ONE_SHOT)
1301                                 Int3();
1302                         else if (trig.flags & TRIGGER_MATCEN)
1303                                 type = TT_MATCEN;
1304                         else if (trig.flags & TRIGGER_ILLUSION_OFF)
1305                                 type = TT_ILLUSION_OFF;
1306                         else if (trig.flags & TRIGGER_SECRET_EXIT)
1307                                 type = TT_SECRET_EXIT;
1308                         else if (trig.flags & TRIGGER_ILLUSION_ON)
1309                                 type = TT_ILLUSION_ON;
1310                         else if (trig.flags & TRIGGER_UNLOCK_DOORS)
1311                                 type = TT_UNLOCK_DOOR;
1312                         else if (trig.flags & TRIGGER_OPEN_WALL)
1313                                 type = TT_OPEN_WALL;
1314                         else if (trig.flags & TRIGGER_CLOSE_WALL)
1315                                 type = TT_CLOSE_WALL;
1316                         else if (trig.flags & TRIGGER_ILLUSORY_WALL)
1317                                 type = TT_ILLUSORY_WALL;
1318                         else
1319                                 Int3();
1320                         Triggers[i].type        = type;
1321                         Triggers[i].flags       = 0;
1322                         Triggers[i].num_links   = trig.num_links;
1323                         Triggers[i].num_links   = trig.num_links;
1324                         Triggers[i].value       = trig.value;
1325                         Triggers[i].time        = trig.time;
1326                         for (t=0;t<trig.num_links;t++) {
1327                                 Triggers[i].seg[t] = trig.seg[t];
1328                                 Triggers[i].side[t] = trig.side[t];
1329                         }
1330                 }
1331                 else
1332                         trigger_read(&Triggers[i], LoadFile);
1333         }
1334
1335         //================ READ CONTROL CENTER TRIGGER INFO ===============
1336
1337 #if 0
1338         if (game_fileinfo.control_offset > -1)
1339                 if (!cfseek(LoadFile, game_fileinfo.control_offset, SEEK_SET))
1340                 {
1341                         Assert(game_fileinfo.control_sizeof == sizeof(control_center_triggers));
1342 #endif // 0
1343         control_center_triggers_read_n(&ControlCenterTriggers, 1, LoadFile);
1344
1345         //================ READ MATERIALOGRIFIZATIONATORS INFO ===============
1346
1347         // mprintf((0, "Reading %i materialization centers.\n", game_fileinfo.matcen_howmany));
1348         for (i = 0; i < Num_robot_centers; i++) {
1349                 if (game_top_fileinfo_version < 27) {
1350                         old_matcen_info m;
1351                         old_matcen_info_read(&m, LoadFile);
1352                         RobotCenters[i].robot_flags[0] = m.robot_flags;
1353                         RobotCenters[i].robot_flags[1] = 0;
1354                         RobotCenters[i].hit_points = m.hit_points;
1355                         RobotCenters[i].interval = m.interval;
1356                         RobotCenters[i].segnum = m.segnum;
1357                         RobotCenters[i].fuelcen_num = m.fuelcen_num;
1358                 }
1359                 else
1360                         matcen_info_read(&RobotCenters[i], LoadFile);
1361                         //      Set links in RobotCenters to Station array
1362                         for (j = 0; j <= Highest_segment_index; j++)
1363                         if (Segment2s[j].special == SEGMENT_IS_ROBOTMAKER)
1364                                 if (Segment2s[j].matcen_num == i)
1365                                         RobotCenters[i].fuelcen_num = Segment2s[j].value;
1366                         // mprintf((0, "   %i: flags = %08x\n", i, RobotCenters[i].robot_flags));
1367         }
1368
1369         //================ READ DL_INDICES INFO ===============
1370
1371         for (i = 0; i < Num_static_lights; i++) {
1372                 if (game_top_fileinfo_version < 29) {
1373                         mprintf((0, "Warning: Old mine version.  Not reading Dl_indices info.\n"));
1374                         Int3(); //shouldn't be here!!!
1375                 } else
1376                         dl_index_read(&Dl_indices[i], LoadFile);
1377         }
1378
1379         //      Indicate that no light has been subtracted from any vertices.
1380         clear_light_subtracted();
1381
1382         //================ READ DELTA LIGHT INFO ===============
1383
1384         for (i = 0; i < num_delta_lights; i++) {
1385                 if (game_top_fileinfo_version < 29) {
1386                         mprintf((0, "Warning: Old mine version.  Not reading delta light info.\n"));
1387                 } else
1388                         delta_light_read(&Delta_lights[i], LoadFile);
1389         }
1390
1391         //========================= UPDATE VARIABLES ======================
1392
1393         reset_objects(gs_num_objects);
1394
1395         for (i=0; i<MAX_OBJECTS; i++) {
1396                 Objects[i].next = Objects[i].prev = -1;
1397                 if (Objects[i].type != OBJ_NONE) {
1398                         int objsegnum = Objects[i].segnum;
1399
1400                         if (objsegnum > Highest_segment_index)          //bogus object
1401                                 Objects[i].type = OBJ_NONE;
1402                         else {
1403                                 Objects[i].segnum = -1;                 //avoid Assert()
1404                                 obj_link(i,objsegnum);
1405                         }
1406                 }
1407         }
1408
1409         clear_transient_objects(1);             //1 means clear proximity bombs
1410
1411         // Make sure non-transparent doors are set correctly.
1412         for (i=0; i< Num_segments; i++)
1413                 for (j=0;j<MAX_SIDES_PER_SEGMENT;j++) {
1414                         side    *sidep = &Segments[i].sides[j];
1415                         if ((sidep->wall_num != -1) && (Walls[sidep->wall_num].clip_num != -1)) {
1416                                 //mprintf((0, "Checking Wall %d\n", Segments[i].sides[j].wall_num));
1417                                 if (WallAnims[Walls[sidep->wall_num].clip_num].flags & WCF_TMAP1) {
1418                                         //mprintf((0, "Fixing non-transparent door.\n"));
1419                                         sidep->tmap_num = WallAnims[Walls[sidep->wall_num].clip_num].frames[0];
1420                                         sidep->tmap_num2 = 0;
1421                                 }
1422                         }
1423                 }
1424
1425
1426         reset_walls();
1427
1428 #if 0
1429         Num_open_doors = game_fileinfo.doors_howmany;
1430 #endif // 0
1431         Num_open_doors = 0;
1432
1433         //go through all walls, killing references to invalid triggers
1434         for (i=0;i<Num_walls;i++)
1435                 if (Walls[i].trigger >= Num_triggers) {
1436                         mprintf((0,"Removing reference to invalid trigger %d from wall %d\n",Walls[i].trigger,i));
1437                         Walls[i].trigger = -1;  //kill trigger
1438                 }
1439
1440         //go through all triggers, killing unused ones
1441         for (i=0;i<Num_triggers;) {
1442                 int w;
1443
1444                 //      Find which wall this trigger is connected to.
1445                 for (w=0; w<Num_walls; w++)
1446                         if (Walls[w].trigger == i)
1447                                 break;
1448
1449         #ifdef EDITOR
1450                 if (w == Num_walls) {
1451                         mprintf((0,"Removing unreferenced trigger %d\n",i));
1452                         remove_trigger_num(i);
1453                 }
1454                 else
1455         #endif
1456                         i++;
1457         }
1458
1459         //      MK, 10/17/95: Make walls point back at the triggers that control them.
1460         //      Go through all triggers, stuffing controlling_trigger field in Walls.
1461         {       int t;
1462
1463         for (i=0; i<Num_walls; i++)
1464                 Walls[i].controlling_trigger = -1;
1465
1466         for (t=0; t<Num_triggers; t++) {
1467                 int     l;
1468                 for (l=0; l<Triggers[t].num_links; l++) {
1469                         int     seg_num, side_num, wall_num;
1470
1471                         seg_num = Triggers[t].seg[l];
1472                         side_num = Triggers[t].side[l];
1473                         wall_num = Segments[seg_num].sides[side_num].wall_num;
1474
1475                         // -- if (Walls[wall_num].controlling_trigger != -1)
1476                         // --   Int3();
1477
1478                         //check to see that if a trigger requires a wall that it has one,
1479                         //and if it requires a matcen that it has one
1480
1481                         if (Triggers[t].type == TT_MATCEN) {
1482                                 if (Segment2s[seg_num].special != SEGMENT_IS_ROBOTMAKER)
1483                                         Int3();         //matcen trigger doesn't point to matcen
1484                         }
1485                         else if (Triggers[t].type != TT_LIGHT_OFF && Triggers[t].type != TT_LIGHT_ON) { //light triggers don't require walls
1486                                 if (wall_num == -1)
1487                                         Int3(); //      This is illegal.  This trigger requires a wall
1488                                 else
1489                                         Walls[wall_num].controlling_trigger = t;
1490                         }
1491                 }
1492         }
1493         }
1494
1495         //fix old wall structs
1496         if (game_top_fileinfo_version < 17) {
1497                 int segnum,sidenum,wallnum;
1498
1499                 for (segnum=0; segnum<=Highest_segment_index; segnum++)
1500                         for (sidenum=0;sidenum<6;sidenum++)
1501                                 if ((wallnum=Segments[segnum].sides[sidenum].wall_num) != -1) {
1502                                         Walls[wallnum].segnum = segnum;
1503                                         Walls[wallnum].sidenum = sidenum;
1504                                 }
1505         }
1506
1507         #ifndef NDEBUG
1508         {
1509                 int     sidenum;
1510                 for (sidenum=0; sidenum<6; sidenum++) {
1511                         int     wallnum = Segments[Highest_segment_index].sides[sidenum].wall_num;
1512                         if (wallnum != -1)
1513                                 if ((Walls[wallnum].segnum != Highest_segment_index) || (Walls[wallnum].sidenum != sidenum))
1514                                         Int3(); //      Error.  Bogus walls in this segment.
1515                                                                 // Consult Yuan or Mike.
1516                 }
1517         }
1518         #endif
1519
1520         //create_local_segment_data();
1521
1522         fix_object_segs();
1523
1524         #ifndef NDEBUG
1525         dump_mine_info();
1526         #endif
1527
1528         if (game_top_fileinfo_version < GAME_VERSION
1529             && !(game_top_fileinfo_version == 25 && GAME_VERSION == 26))
1530                 return 1;               //means old version
1531         else
1532                 return 0;
1533 }
1534
1535
1536 int check_segment_connections(void);
1537
1538 extern void     set_ambient_sound_flags(void);
1539
1540 // ----------------------------------------------------------------------------
1541
1542 #define LEVEL_FILE_VERSION      8
1543 //1 -> 2  add palette name
1544 //2 -> 3  add control center explosion time
1545 //3 -> 4  add reactor strength
1546 //4 -> 5  killed hostage text stuff
1547 //5 -> 6  added Secret_return_segment and Secret_return_orient
1548 //6 -> 7  added flickering lights
1549 //7 -> 8  made version 8 to be not compatible with D2 1.0 & 1.1
1550
1551 #ifndef RELEASE
1552 char *Level_being_loaded=NULL;
1553 #endif
1554
1555 #ifdef COMPACT_SEGS
1556 extern void ncache_flush();
1557 #endif
1558
1559 extern int Slide_segs_computed;
1560
1561 int no_old_level_file_error=0;
1562
1563 //loads a level (.LVL) file from disk
1564 //returns 0 if success, else error code
1565 int load_level(char * filename_passed)
1566 {
1567 #ifdef EDITOR
1568         int use_compiled_level=1;
1569 #endif
1570         CFILE * LoadFile;
1571         char filename[128];
1572         int sig, minedata_offset, gamedata_offset;
1573         int mine_err, game_err;
1574 #ifdef NETWORK
1575         int i;
1576 #endif
1577
1578         Slide_segs_computed = 0;
1579
1580 #ifdef NETWORK
1581    if (Game_mode & GM_NETWORK)
1582          {
1583           for (i=0;i<MAX_POWERUP_TYPES;i++)
1584                 {
1585                         MaxPowerupsAllowed[i]=0;
1586                         PowerupsInMine[i]=0;
1587                 }
1588          }
1589 #endif
1590
1591         #ifdef COMPACT_SEGS
1592         ncache_flush();
1593         #endif
1594
1595         #ifndef RELEASE
1596         Level_being_loaded = filename_passed;
1597         #endif
1598
1599         strcpy(filename,filename_passed);
1600
1601         #ifdef EDITOR
1602                 //if we have the editor, try the LVL first, no matter what was passed.
1603                 //if we don't have an LVL, try RDL  
1604                 //if we don't have the editor, we just use what was passed
1605         
1606                 change_filename_extension(filename,filename_passed,".lvl");
1607                 use_compiled_level = 0;
1608         
1609                 if (!cfexist(filename)) {
1610                         change_filename_extension(filename,filename,".rl2");
1611                         use_compiled_level = 1;
1612                 }               
1613         #endif
1614
1615         LoadFile = cfopen( filename, "rb" );
1616
1617         if (!LoadFile)  {
1618                 #ifdef EDITOR
1619                         mprintf((0,"Can't open level file <%s>\n", filename));
1620                         return 1;
1621                 #else
1622                         Error("Can't open file <%s>\n",filename);
1623                 #endif
1624         }
1625
1626         strcpy( Gamesave_current_filename, filename );
1627
1628 //      #ifdef NEWDEMO
1629 //      if ( Newdemo_state == ND_STATE_RECORDING )
1630 //              newdemo_record_start_demo();
1631 //      #endif
1632
1633         sig                      = cfile_read_int(LoadFile);
1634         Gamesave_current_version = cfile_read_int(LoadFile);
1635         mprintf((0, "Gamesave_current_version = %d\n", Gamesave_current_version));
1636         minedata_offset          = cfile_read_int(LoadFile);
1637         gamedata_offset          = cfile_read_int(LoadFile);
1638
1639         Assert(sig == MAKE_SIG('P','L','V','L'));
1640
1641         if (Gamesave_current_version >= 8) {    //read dummy data
1642                 cfile_read_int(LoadFile);
1643                 cfile_read_short(LoadFile);
1644                 cfile_read_byte(LoadFile);
1645         }
1646
1647         if (Gamesave_current_version < 5)
1648                 cfile_read_int(LoadFile);       //was hostagetext_offset
1649
1650         if (Gamesave_current_version > 1) {
1651                 cfgets(Current_level_palette,sizeof(Current_level_palette),LoadFile);
1652                 if (Current_level_palette[strlen(Current_level_palette)-1] == '\n')
1653                         Current_level_palette[strlen(Current_level_palette)-1] = 0;
1654         }
1655         if (Gamesave_current_version <= 1 || Current_level_palette[0]==0) // descent 1 level
1656                 strcpy(Current_level_palette, DEFAULT_LEVEL_PALETTE);
1657
1658         if (Gamesave_current_version >= 3)
1659                 Base_control_center_explosion_time = cfile_read_int(LoadFile);
1660         else
1661                 Base_control_center_explosion_time = DEFAULT_CONTROL_CENTER_EXPLOSION_TIME;
1662
1663         if (Gamesave_current_version >= 4)
1664                 Reactor_strength = cfile_read_int(LoadFile);
1665         else
1666                 Reactor_strength = -1;  //use old defaults
1667
1668         if (Gamesave_current_version >= 7) {
1669                 int i;
1670
1671                 Num_flickering_lights = cfile_read_int(LoadFile);
1672                 Assert((Num_flickering_lights >= 0) && (Num_flickering_lights < MAX_FLICKERING_LIGHTS));
1673                 for (i = 0; i < Num_flickering_lights; i++)
1674                         flickering_light_read(&Flickering_lights[i], LoadFile);
1675         }
1676         else
1677                 Num_flickering_lights = 0;
1678
1679         if (Gamesave_current_version < 6) {
1680                 Secret_return_segment = 0;
1681                 Secret_return_orient.rvec.x = F1_0;
1682                 Secret_return_orient.rvec.y = 0;
1683                 Secret_return_orient.rvec.z = 0;
1684                 Secret_return_orient.fvec.x = 0;
1685                 Secret_return_orient.fvec.y = F1_0;
1686                 Secret_return_orient.fvec.z = 0;
1687                 Secret_return_orient.uvec.x = 0;
1688                 Secret_return_orient.uvec.y = 0;
1689                 Secret_return_orient.uvec.z = F1_0;
1690         } else {
1691                 Secret_return_segment = cfile_read_int(LoadFile);
1692                 Secret_return_orient.rvec.x = cfile_read_int(LoadFile);
1693                 Secret_return_orient.rvec.y = cfile_read_int(LoadFile);
1694                 Secret_return_orient.rvec.z = cfile_read_int(LoadFile);
1695                 Secret_return_orient.fvec.x = cfile_read_int(LoadFile);
1696                 Secret_return_orient.fvec.y = cfile_read_int(LoadFile);
1697                 Secret_return_orient.fvec.z = cfile_read_int(LoadFile);
1698                 Secret_return_orient.uvec.x = cfile_read_int(LoadFile);
1699                 Secret_return_orient.uvec.y = cfile_read_int(LoadFile);
1700                 Secret_return_orient.uvec.z = cfile_read_int(LoadFile);
1701         }
1702
1703         cfseek(LoadFile,minedata_offset,SEEK_SET);
1704         #ifdef EDITOR
1705         if (!use_compiled_level) {
1706                 mine_err = load_mine_data(LoadFile);
1707 #if 0 // get from d1src if needed
1708                 // Compress all uv coordinates in mine, improves texmap precision. --MK, 02/19/96
1709                 compress_uv_coordinates_all();
1710 #endif
1711         } else
1712         #endif
1713                 //NOTE LINK TO ABOVE!!
1714                 mine_err = load_mine_data_compiled(LoadFile);
1715
1716         if (mine_err == -1) {   //error!!
1717                 cfclose(LoadFile);
1718                 return 2;
1719         }
1720
1721         cfseek(LoadFile,gamedata_offset,SEEK_SET);
1722         game_err = load_game_data(LoadFile);
1723
1724         if (game_err == -1) {   //error!!
1725                 cfclose(LoadFile);
1726                 return 3;
1727         }
1728
1729         //======================== CLOSE FILE =============================
1730
1731         cfclose( LoadFile );
1732
1733         set_ambient_sound_flags();
1734
1735         #ifdef EDITOR
1736         write_game_text_file(filename);
1737         if (Errors_in_mine) {
1738                 if (is_real_level(filename)) {
1739                         char  ErrorMessage[200];
1740
1741                         sprintf( ErrorMessage, "Warning: %i errors in %s!\n", Errors_in_mine, Level_being_loaded );
1742                         stop_time();
1743                         gr_palette_load(gr_palette);
1744                         nm_messagebox( NULL, 1, "Continue", ErrorMessage );
1745                         start_time();
1746                 } else
1747                         mprintf((1, "Error: %i errors in %s.\n", Errors_in_mine, Level_being_loaded));
1748         }
1749         #endif
1750
1751         #ifdef EDITOR
1752         //If an old version, ask the use if he wants to save as new version
1753         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)) {
1754                 char  ErrorMessage[200];
1755
1756                 sprintf( ErrorMessage,
1757                                         "You just loaded a old version\n"
1758                                         "level.  Would you like to save\n"
1759                                         "it as a current version level?");
1760
1761                 stop_time();
1762                 gr_palette_load(gr_palette);
1763                 if (nm_messagebox( NULL, 2, "Don't Save", "Save", ErrorMessage )==1)
1764                         save_level(filename);
1765                 start_time();
1766         }
1767         #endif
1768
1769         #ifdef EDITOR
1770         if (Function_mode == FMODE_EDITOR)
1771                 editor_status("Loaded NEW mine %s, \"%s\"",filename,Current_level_name);
1772         #endif
1773
1774         #ifdef EDITOR
1775         if (check_segment_connections())
1776                 nm_messagebox( "ERROR", 1, "Ok", 
1777                                 "Connectivity errors detected in\n"
1778                                 "mine.  See monochrome screen for\n"
1779                                 "details, and contact Matt or Mike." );
1780         #endif
1781
1782         return 0;
1783 }
1784
1785 #ifdef EDITOR
1786 void get_level_name()
1787 {
1788 //NO_UI!!!      UI_WINDOW                               *NameWindow = NULL;
1789 //NO_UI!!!      UI_GADGET_INPUTBOX      *NameText;
1790 //NO_UI!!!      UI_GADGET_BUTTON                *QuitButton;
1791 //NO_UI!!!
1792 //NO_UI!!!      // Open a window with a quit button
1793 //NO_UI!!!      NameWindow = ui_open_window( 20, 20, 300, 110, WIN_DIALOG );
1794 //NO_UI!!!      QuitButton = ui_add_gadget_button( NameWindow, 150-24, 60, 48, 40, "Done", NULL );
1795 //NO_UI!!!
1796 //NO_UI!!!      ui_wprintf_at( NameWindow, 10, 12,"Please enter a name for this mine:" );
1797 //NO_UI!!!      NameText = ui_add_gadget_inputbox( NameWindow, 10, 30, LEVEL_NAME_LEN, LEVEL_NAME_LEN, Current_level_name );
1798 //NO_UI!!!
1799 //NO_UI!!!      NameWindow->keyboard_focus_gadget = (UI_GADGET *)NameText;
1800 //NO_UI!!!      QuitButton->hotkey = KEY_ENTER;
1801 //NO_UI!!!
1802 //NO_UI!!!      ui_gadget_calc_keys(NameWindow);
1803 //NO_UI!!!
1804 //NO_UI!!!      while (!QuitButton->pressed && last_keypress!=KEY_ENTER) {
1805 //NO_UI!!!              ui_mega_process();
1806 //NO_UI!!!              ui_window_do_gadgets(NameWindow);
1807 //NO_UI!!!      }
1808 //NO_UI!!!
1809 //NO_UI!!!      strcpy( Current_level_name, NameText->text );
1810 //NO_UI!!!
1811 //NO_UI!!!      if ( NameWindow!=NULL ) {
1812 //NO_UI!!!              ui_close_window( NameWindow );
1813 //NO_UI!!!              NameWindow = NULL;
1814 //NO_UI!!!      }
1815 //NO_UI!!!
1816
1817         newmenu_item m[2];
1818
1819         m[0].type = NM_TYPE_TEXT; m[0].text = "Please enter a name for this mine:";
1820         m[1].type = NM_TYPE_INPUT; m[1].text = Current_level_name; m[1].text_len = LEVEL_NAME_LEN;
1821
1822         newmenu_do( NULL, "Enter mine name", 2, m, NULL );
1823
1824 }
1825 #endif
1826
1827
1828 #ifdef EDITOR
1829
1830 int     Errors_in_mine;
1831
1832 // -----------------------------------------------------------------------------
1833 int compute_num_delta_light_records(void)
1834 {
1835         int     i;
1836         int     total = 0;
1837
1838         for (i=0; i<Num_static_lights; i++) {
1839                 total += Dl_indices[i].count;
1840         }
1841
1842         return total;
1843
1844 }
1845
1846 // -----------------------------------------------------------------------------
1847 // Save game
1848 int save_game_data(FILE * SaveFile)
1849 {
1850         int  player_offset, object_offset, walls_offset, doors_offset, triggers_offset, control_offset, matcen_offset; //, links_offset;
1851         int     dl_indices_offset, delta_light_offset;
1852         int start_offset,end_offset;
1853
1854         start_offset = ftell(SaveFile);
1855
1856         //===================== SAVE FILE INFO ========================
1857
1858         game_fileinfo.fileinfo_signature =      0x6705;
1859         game_fileinfo.fileinfo_version  =       GAME_VERSION;
1860         game_fileinfo.level                                     =  Current_level_num;
1861         game_fileinfo.fileinfo_sizeof           =       sizeof(game_fileinfo);
1862         game_fileinfo.player_offset             =       -1;
1863         game_fileinfo.player_sizeof             =       sizeof(player);
1864         game_fileinfo.object_offset             =       -1;
1865         game_fileinfo.object_howmany            =       Highest_object_index+1;
1866         game_fileinfo.object_sizeof             =       sizeof(object);
1867         game_fileinfo.walls_offset                      =       -1;
1868         game_fileinfo.walls_howmany             =       Num_walls;
1869         game_fileinfo.walls_sizeof                      =       sizeof(wall);
1870         game_fileinfo.doors_offset                      =       -1;
1871         game_fileinfo.doors_howmany             =       Num_open_doors;
1872         game_fileinfo.doors_sizeof                      =       sizeof(active_door);
1873         game_fileinfo.triggers_offset           =       -1;
1874         game_fileinfo.triggers_howmany  =       Num_triggers;
1875         game_fileinfo.triggers_sizeof           =       sizeof(trigger);
1876         game_fileinfo.control_offset            =       -1;
1877         game_fileinfo.control_howmany           =  1;
1878         game_fileinfo.control_sizeof            =  sizeof(control_center_triggers);
1879         game_fileinfo.matcen_offset             =       -1;
1880         game_fileinfo.matcen_howmany            =       Num_robot_centers;
1881         game_fileinfo.matcen_sizeof             =       sizeof(matcen_info);
1882
1883         game_fileinfo.dl_indices_offset         =       -1;
1884         game_fileinfo.dl_indices_howmany                =       Num_static_lights;
1885         game_fileinfo.dl_indices_sizeof         =       sizeof(dl_index);
1886
1887         game_fileinfo.delta_light_offset                =       -1;
1888         game_fileinfo.delta_light_howmany       =       compute_num_delta_light_records();
1889         game_fileinfo.delta_light_sizeof                =       sizeof(delta_light);
1890
1891         // Write the fileinfo
1892         fwrite( &game_fileinfo, sizeof(game_fileinfo), 1, SaveFile );
1893
1894         // Write the mine name
1895         fprintf(SaveFile,"%s\n",Current_level_name);
1896
1897         fwrite(&N_polygon_models,2,1,SaveFile);
1898         fwrite(Pof_names,N_polygon_models,sizeof(*Pof_names),SaveFile);
1899
1900         //==================== SAVE PLAYER INFO ===========================
1901
1902         player_offset = ftell(SaveFile);
1903         fwrite( &Players[Player_num], sizeof(player), 1, SaveFile );
1904
1905         //==================== SAVE OBJECT INFO ===========================
1906
1907         object_offset = ftell(SaveFile);
1908         //fwrite( &Objects, sizeof(object), game_fileinfo.object_howmany, SaveFile );
1909         {
1910                 int i;
1911                 for (i=0;i<game_fileinfo.object_howmany;i++)
1912                         write_object(&Objects[i],SaveFile);
1913         }
1914
1915         //==================== SAVE WALL INFO =============================
1916
1917         walls_offset = ftell(SaveFile);
1918         fwrite( Walls, sizeof(wall), game_fileinfo.walls_howmany, SaveFile );
1919
1920         //==================== SAVE DOOR INFO =============================
1921
1922         doors_offset = ftell(SaveFile);
1923         fwrite( ActiveDoors, sizeof(active_door), game_fileinfo.doors_howmany, SaveFile );
1924
1925         //==================== SAVE TRIGGER INFO =============================
1926
1927         triggers_offset = ftell(SaveFile);
1928         fwrite( Triggers, sizeof(trigger), game_fileinfo.triggers_howmany, SaveFile );
1929
1930         //================ SAVE CONTROL CENTER TRIGGER INFO ===============
1931
1932         control_offset = ftell(SaveFile);
1933         fwrite( &ControlCenterTriggers, sizeof(control_center_triggers), 1, SaveFile );
1934
1935
1936         //================ SAVE MATERIALIZATION CENTER TRIGGER INFO ===============
1937
1938         matcen_offset = ftell(SaveFile);
1939         // mprintf((0, "Writing %i materialization centers\n", game_fileinfo.matcen_howmany));
1940         // { int i;
1941         // for (i=0; i<game_fileinfo.matcen_howmany; i++)
1942         //      mprintf((0, "   %i: robot_flags = %08x\n", i, RobotCenters[i].robot_flags));
1943         // }
1944         fwrite( RobotCenters, sizeof(matcen_info), game_fileinfo.matcen_howmany, SaveFile );
1945
1946         //================ SAVE DELTA LIGHT INFO ===============
1947         dl_indices_offset = ftell(SaveFile);
1948         fwrite( Dl_indices, sizeof(dl_index), game_fileinfo.dl_indices_howmany, SaveFile );
1949
1950         delta_light_offset = ftell(SaveFile);
1951         fwrite( Delta_lights, sizeof(delta_light), game_fileinfo.delta_light_howmany, SaveFile );
1952
1953         //============= REWRITE FILE INFO, TO SAVE OFFSETS ===============
1954
1955         // Update the offset fields
1956         game_fileinfo.player_offset             =       player_offset;
1957         game_fileinfo.object_offset             =       object_offset;
1958         game_fileinfo.walls_offset                      =       walls_offset;
1959         game_fileinfo.doors_offset                      =       doors_offset;
1960         game_fileinfo.triggers_offset           =       triggers_offset;
1961         game_fileinfo.control_offset            =       control_offset;
1962         game_fileinfo.matcen_offset             =       matcen_offset;
1963         game_fileinfo.dl_indices_offset =       dl_indices_offset;
1964         game_fileinfo.delta_light_offset        =       delta_light_offset;
1965
1966
1967         end_offset = ftell(SaveFile);
1968
1969         // Write the fileinfo
1970         fseek(  SaveFile, start_offset, SEEK_SET );  // Move to TOF
1971         fwrite( &game_fileinfo, sizeof(game_fileinfo), 1, SaveFile );
1972
1973         // Go back to end of data
1974         fseek(SaveFile,end_offset,SEEK_SET);
1975
1976         return 0;
1977 }
1978
1979 int save_mine_data(FILE * SaveFile);
1980
1981 // -----------------------------------------------------------------------------
1982 // Save game
1983 int save_level_sub(char * filename, int compiled_version)
1984 {
1985         FILE * SaveFile;
1986         char temp_filename[128];
1987         int sig = MAKE_SIG('P','L','V','L'),version=LEVEL_FILE_VERSION;
1988         int minedata_offset=0,gamedata_offset=0;
1989
1990         if ( !compiled_version )        {
1991                 write_game_text_file(filename);
1992
1993                 if (Errors_in_mine) {
1994                         if (is_real_level(filename)) {
1995                                 char  ErrorMessage[200];
1996         
1997                                 sprintf( ErrorMessage, "Warning: %i errors in this mine!\n", Errors_in_mine );
1998                                 stop_time();
1999                                 gr_palette_load(gr_palette);
2000          
2001                                 if (nm_messagebox( NULL, 2, "Cancel Save", "Save", ErrorMessage )!=1)   {
2002                                         start_time();
2003                                         return 1;
2004                                 }
2005                                 start_time();
2006                         } else
2007                                 mprintf((1, "Error: %i errors in this mine.  See the 'txm' file.\n", Errors_in_mine));
2008                 }
2009                 change_filename_extension(temp_filename,filename,".LVL");
2010         }
2011         else
2012         {
2013                 // macs are using the regular hog/rl2 files for shareware
2014                 #if defined(SHAREWARE) && !defined(MACINTOSH)
2015                         change_filename_extension(temp_filename,filename,".SL2");
2016                 #else
2017                         change_filename_extension(temp_filename,filename,".RL2");
2018                 #endif
2019         }
2020
2021         SaveFile = fopen( temp_filename, "wb" );
2022         if (!SaveFile)
2023         {
2024                 char ErrorMessage[256];
2025
2026                 char fname[20];
2027                 _splitpath( temp_filename, NULL, NULL, fname, NULL );
2028
2029                 sprintf( ErrorMessage, \
2030                         "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" 
2031                         , temp_filename, fname );
2032                 stop_time();
2033                 gr_palette_load(gr_palette);
2034                 nm_messagebox( NULL, 1, "Ok", ErrorMessage );
2035                 start_time();
2036                 return 1;
2037         }
2038
2039         if (Current_level_name[0] == 0)
2040                 strcpy(Current_level_name,"Untitled");
2041
2042         clear_transient_objects(1);             //1 means clear proximity bombs
2043
2044         compress_objects();             //after this, Highest_object_index == num objects
2045
2046         //make sure player is in a segment
2047         if (update_object_seg(&Objects[Players[0].objnum]) == 0) {
2048                 if (ConsoleObject->segnum > Highest_segment_index)
2049                         ConsoleObject->segnum = 0;
2050                 compute_segment_center(&ConsoleObject->pos,&(Segments[ConsoleObject->segnum]));
2051         }
2052  
2053         fix_object_segs();
2054
2055         //Write the header
2056
2057         gs_write_int(sig,SaveFile);
2058         gs_write_int(version,SaveFile);
2059
2060         //save placeholders
2061         gs_write_int(minedata_offset,SaveFile);
2062         gs_write_int(gamedata_offset,SaveFile);
2063
2064         //Now write the damn data
2065
2066         //write the version 8 data (to make file unreadable by 1.0 & 1.1)
2067         gs_write_int(GameTime,SaveFile);
2068         gs_write_short(FrameCount,SaveFile);
2069         gs_write_byte(FrameTime,SaveFile);
2070
2071         // Write the palette file name
2072         fprintf(SaveFile,"%s\n",Current_level_palette);
2073
2074         gs_write_int(Base_control_center_explosion_time,SaveFile);
2075         gs_write_int(Reactor_strength,SaveFile);
2076
2077         gs_write_int(Num_flickering_lights,SaveFile);
2078         fwrite(Flickering_lights,sizeof(*Flickering_lights),Num_flickering_lights,SaveFile);
2079         
2080         gs_write_int(Secret_return_segment, SaveFile);
2081         gs_write_int(Secret_return_orient.rvec.x, SaveFile);
2082         gs_write_int(Secret_return_orient.rvec.y, SaveFile);
2083         gs_write_int(Secret_return_orient.rvec.z, SaveFile);
2084         gs_write_int(Secret_return_orient.fvec.x, SaveFile);
2085         gs_write_int(Secret_return_orient.fvec.y, SaveFile);
2086         gs_write_int(Secret_return_orient.fvec.z, SaveFile);
2087         gs_write_int(Secret_return_orient.uvec.x, SaveFile);
2088         gs_write_int(Secret_return_orient.uvec.y, SaveFile);
2089         gs_write_int(Secret_return_orient.uvec.z, SaveFile);
2090
2091         minedata_offset = ftell(SaveFile);
2092         if ( !compiled_version )        
2093                 save_mine_data(SaveFile);
2094         else
2095                 save_mine_data_compiled(SaveFile);
2096         gamedata_offset = ftell(SaveFile);
2097         save_game_data(SaveFile);
2098
2099         fseek(SaveFile,sizeof(sig)+sizeof(version),SEEK_SET);
2100         gs_write_int(minedata_offset,SaveFile);
2101         gs_write_int(gamedata_offset,SaveFile);
2102
2103         //==================== CLOSE THE FILE =============================
2104         fclose(SaveFile);
2105
2106         if ( !compiled_version )        {
2107                 if (Function_mode == FMODE_EDITOR)
2108                         editor_status("Saved mine %s, \"%s\"",filename,Current_level_name);
2109         }
2110
2111         return 0;
2112
2113 }
2114
2115 #if 0 //dunno - 3rd party stuff?
2116 extern void compress_uv_coordinates_all(void);
2117 #endif
2118
2119 int save_level(char * filename)
2120 {
2121         int r1;
2122
2123         // Save normal version...
2124         r1 = save_level_sub(filename, 0);
2125
2126         // Save compiled version...
2127         save_level_sub(filename, 1);
2128
2129         return r1;
2130 }
2131
2132 #endif  //EDITOR
2133
2134 #ifndef NDEBUG
2135 void dump_mine_info(void)
2136 {
2137         int     segnum, sidenum;
2138         fix     min_u, max_u, min_v, max_v, min_l, max_l, max_sl;
2139
2140         min_u = F1_0*1000;
2141         min_v = min_u;
2142         min_l = min_u;
2143
2144         max_u = -min_u;
2145         max_v = max_u;
2146         max_l = max_u;
2147
2148         max_sl = 0;
2149
2150         for (segnum=0; segnum<=Highest_segment_index; segnum++) {
2151                 for (sidenum=0; sidenum<MAX_SIDES_PER_SEGMENT; sidenum++) {
2152                         int     vertnum;
2153                         side    *sidep = &Segments[segnum].sides[sidenum];
2154
2155                         if (Segment2s[segnum].static_light > max_sl)
2156                                 max_sl = Segment2s[segnum].static_light;
2157
2158                         for (vertnum=0; vertnum<4; vertnum++) {
2159                                 if (sidep->uvls[vertnum].u < min_u)
2160                                         min_u = sidep->uvls[vertnum].u;
2161                                 else if (sidep->uvls[vertnum].u > max_u)
2162                                         max_u = sidep->uvls[vertnum].u;
2163
2164                                 if (sidep->uvls[vertnum].v < min_v)
2165                                         min_v = sidep->uvls[vertnum].v;
2166                                 else if (sidep->uvls[vertnum].v > max_v)
2167                                         max_v = sidep->uvls[vertnum].v;
2168
2169                                 if (sidep->uvls[vertnum].l < min_l)
2170                                         min_l = sidep->uvls[vertnum].l;
2171                                 else if (sidep->uvls[vertnum].l > max_l)
2172                                         max_l = sidep->uvls[vertnum].l;
2173                         }
2174
2175                 }
2176         }
2177
2178 //      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)));
2179 //      mprintf((0, "Static light maximum = %7.3f\n", f2fl(max_sl)));
2180 //      mprintf((0, "Number of walls: %i\n", Num_walls));
2181
2182 }
2183
2184 #endif
2185
2186 #ifdef EDITOR
2187
2188 //read in every level in mission and save out compiled version 
2189 void save_all_compiled_levels(void)
2190 {
2191         do_load_save_levels(1);
2192 }
2193
2194 //read in every level in mission
2195 void load_all_levels(void)
2196 {
2197         do_load_save_levels(0);
2198 }
2199
2200
2201 void do_load_save_levels(int save)
2202 {
2203         int level_num;
2204
2205         if (! SafetyCheck())
2206                 return;
2207
2208         no_old_level_file_error=1;
2209
2210         for (level_num=1;level_num<=Last_level;level_num++) {
2211                 load_level(Level_names[level_num-1]);
2212                 load_palette(Current_level_palette,1,1);                //don't change screen
2213                 if (save)
2214                         save_level_sub(Level_names[level_num-1],1);
2215         }
2216
2217         for (level_num=-1;level_num>=Last_secret_level;level_num--) {
2218                 load_level(Secret_level_names[-level_num-1]);
2219                 load_palette(Current_level_palette,1,1);                //don't change screen
2220                 if (save)
2221                         save_level_sub(Secret_level_names[-level_num-1],1);
2222         }
2223
2224         no_old_level_file_error=0;
2225
2226 }
2227
2228 #endif