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