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