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