1 /* $Id: gamesave.c,v 1.21 2003-06-16 07:15:59 btb Exp $ */
3 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
4 SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO
5 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
6 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
7 IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
8 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
9 FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
10 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS
11 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
12 COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
17 * Save game information
20 * Revision 1.3 1996/02/21 13:59:17 allender
21 * check Data folder when can't open a level file from a hog
23 * Revision 1.2 1995/10/31 10:23:23 allender
26 * Revision 1.1 1995/05/16 15:25:37 allender
29 * Revision 2.2 1995/04/23 14:53:12 john
30 * Made some mine structures read in with no structure packing problems.
32 * Revision 2.1 1995/03/20 18:15:43 john
33 * Added code to not store the normals in the segment structure.
35 * Revision 2.0 1995/02/27 11:29:50 john
36 * New version 2.0, which has no anonymous unions, builds with
37 * Watcom 10.0, and doesn't require parsing BITMAPS.TBL.
39 * Revision 1.207 1995/02/23 10:17:36 allender
40 * fixed parameter mismatch with compute_segment_center
42 * Revision 1.206 1995/02/22 14:51:17 allender
43 * fixed some things that I missed
45 * Revision 1.205 1995/02/22 13:31:38 allender
46 * remove anonymous unions from object structure
48 * Revision 1.204 1995/02/01 20:58:08 john
49 * Made editor check hog.
51 * Revision 1.203 1995/01/28 17:40:34 mike
52 * correct level names (use rdl, sdl) for dumpmine stuff.
54 * Revision 1.202 1995/01/25 20:03:46 matt
55 * Moved matrix check to avoid orthogonalizing an uninitialize matrix
57 * Revision 1.201 1995/01/20 16:56:53 mike
58 * remove some mprintfs.
60 * Revision 1.200 1995/01/15 19:42:13 matt
61 * Ripped out hostage faces for registered version
63 * Revision 1.199 1995/01/05 16:59:09 yuan
64 * Make it so if editor is loaded, don't get error from typo
67 * Revision 1.198 1994/12/19 12:49:46 mike
68 * Change fgets to cfgets. fgets was getting a pointer mismatch warning.
70 * Revision 1.197 1994/12/12 01:20:03 matt
71 * Took out object size hack for green claw guys
73 * Revision 1.196 1994/12/11 13:19:37 matt
74 * Restored calls to fix_object_segs() when debugging is turned off, since
75 * it's not a big routine, and could fix some possibly bad problems.
77 * Revision 1.195 1994/12/10 16:17:24 mike
78 * fix editor bug that was converting transparent walls into rock.
80 * Revision 1.194 1994/12/09 14:59:27 matt
81 * Added system to attach a fireball to another object for rendering purposes,
82 * so the fireball always renders on top of (after) the object.
84 * Revision 1.193 1994/12/08 17:19:02 yuan
87 * Revision 1.192 1994/12/02 20:01:05 matt
88 * Always give vulcan cannon powerup same amount of ammo, regardless of
89 * how much it was saved with
91 * Revision 1.191 1994/11/30 17:45:57 yuan
92 * Saving files now creates RDL/SDLs instead of CDLs.
94 * Revision 1.190 1994/11/30 17:22:14 matt
95 * Ripped out hostage faces in shareware version
97 * Revision 1.189 1994/11/28 00:09:30 allender
98 * commented out call to newdemo_record_start_demo in load_level...what is
99 * this doing here anyway?????
101 * Revision 1.188 1994/11/27 23:13:48 matt
102 * Made changes for new mprintf calling convention
104 * Revision 1.187 1994/11/27 18:06:20 matt
105 * Cleaned up LVL/CDL file loading
107 * Revision 1.186 1994/11/25 22:46:29 matt
108 * Allow ESC out of compiled/normal menu (esc=compiled).
110 * Revision 1.185 1994/11/23 12:18:35 mike
111 * move level names here...a more logical place than dumpmine.
113 * Revision 1.184 1994/11/21 20:29:19 matt
114 * If hostage info is bad, fix it.
116 * Revision 1.183 1994/11/21 20:26:07 matt
119 * Revision 1.182 1994/11/21 20:20:37 matt
120 * Fixed stupid mistake
122 * Revision 1.181 1994/11/21 20:18:40 matt
123 * Fixed (hopefully) totally bogus writing of hostage data
125 * Revision 1.180 1994/11/20 14:11:56 matt
126 * Gracefully handle two hostages having same id
128 * Revision 1.179 1994/11/19 23:55:05 mike
129 * remove Assert, put in comment for Matt.
131 * Revision 1.178 1994/11/19 19:53:24 matt
132 * Added code to full support different hostage head clip & message for
135 * Revision 1.177 1994/11/19 15:15:21 mike
136 * remove unused code and data
138 * Revision 1.176 1994/11/19 10:28:28 matt
139 * Took out write routines when editor compiled out
141 * Revision 1.175 1994/11/17 20:38:25 john
144 * Revision 1.174 1994/11/17 20:36:34 john
145 * Made it so that saving a mine will write the .cdl even
146 * if .lvl gets error.
148 * Revision 1.173 1994/11/17 20:26:19 john
149 * Made the game load whichever of .cdl or .lvl exists,
150 * and if they both exist, prompt the user for which one.
152 * Revision 1.172 1994/11/17 20:11:20 john
155 * Revision 1.171 1994/11/17 20:09:26 john
156 * Added new compiled level format.
158 * Revision 1.170 1994/11/17 14:57:21 mike
159 * moved segment validation functions from editor to main.
161 * Revision 1.169 1994/11/17 11:39:21 matt
162 * Ripped out code to load old mines
164 * Revision 1.168 1994/11/16 11:24:53 matt
165 * Made attack-type robots have smaller radius, so they get closer to player
167 * Revision 1.167 1994/11/15 21:42:47 mike
168 * better error messages.
170 * Revision 1.166 1994/11/15 15:30:41 matt
171 * Save ptr to name of level being loaded
173 * Revision 1.165 1994/11/14 20:47:46 john
174 * Attempted to strip out all the code in the game
175 * directory that uses any ui code.
177 * Revision 1.164 1994/11/14 14:34:23 matt
178 * Fixed up handling when textures can't be found during remap
180 * Revision 1.163 1994/11/10 14:02:49 matt
181 * Hacked in support for player ships with different textures
183 * Revision 1.162 1994/11/06 14:38:17 mike
184 * Remove an apparently unnecessary mprintf.
186 * Revision 1.161 1994/10/30 14:11:28 mike
187 * ripout local segments stuff.
189 * Revision 1.160 1994/10/28 12:10:41 matt
190 * Check that was supposed to happen only when editor was in was happening
191 * only when editor was out.
193 * Revision 1.159 1994/10/27 11:25:32 matt
194 * Only do connectivity error check when editor in
196 * Revision 1.158 1994/10/27 10:54:00 matt
197 * Made connectivity error checking put up warning if errors found
199 * Revision 1.157 1994/10/25 10:50:54 matt
200 * Vulcan cannon powerups now contain ammo count
202 * Revision 1.156 1994/10/23 02:10:43 matt
203 * Got rid of obsolete hostage_info stuff
205 * Revision 1.155 1994/10/22 18:57:26 matt
206 * Added call to check_segment_connections()
208 * Revision 1.154 1994/10/21 12:19:23 matt
209 * Clear transient objects when saving (& loading) games
211 * Revision 1.153 1994/10/21 11:25:10 mike
212 * Use new constant IMMORTAL_TIME.
214 * Revision 1.152 1994/10/20 12:46:59 matt
215 * Replace old save files (MIN/SAV/HOT) with new LVL files
217 * Revision 1.151 1994/10/19 19:26:32 matt
220 * Revision 1.150 1994/10/19 16:46:21 matt
221 * Made tmap overrides for robots remap texture numbers
223 * Revision 1.149 1994/10/18 08:50:27 yuan
224 * Fixed correct variable this time.
226 * Revision 1.148 1994/10/18 08:45:02 yuan
227 * Oops. forgot load function.
229 * Revision 1.147 1994/10/18 08:42:10 yuan
232 * Revision 1.146 1994/10/17 21:34:57 matt
233 * Added support for new Control Center/Main Reactor
235 * Revision 1.145 1994/10/15 19:06:34 mike
236 * Fix bug, maybe, having to do with something or other, ...
238 * Revision 1.144 1994/10/12 21:07:33 matt
239 * Killed unused field in object structure
241 * Revision 1.143 1994/10/06 14:52:55 mike
242 * Put check in to detect possibly bogus walls in last segment which leaked through an earlier check
243 * due to misuse of Highest_segment_index.
245 * Revision 1.142 1994/10/05 22:12:44 mike
246 * Put in cleanup for matcen/fuelcen links.
248 * Revision 1.141 1994/10/03 11:30:05 matt
249 * Make sure player in a valid segment before saving
251 * Revision 1.140 1994/09/28 11:14:41 mike
252 * Better error messaging on bogus mines: Only bring up dialog box if a "real" (level??.*) level.
254 * Revision 1.139 1994/09/28 09:22:58 mike
255 * Comment out a mprintf.
257 * Revision 1.138 1994/09/27 17:08:36 mike
258 * Message boxes when you load bogus mines.
260 * Revision 1.137 1994/09/27 15:43:45 mike
261 * Move the dump stuff to dumpmine.
263 * Revision 1.136 1994/09/27 00:02:31 mike
264 * Dump text files (".txm") when loading a mine, showing all kinds of useful mine info.
266 * Revision 1.135 1994/09/26 11:30:41 matt
267 * Took out code which loaded bogus player structure
269 * Revision 1.134 1994/09/26 11:18:44 john
270 * Fixed some conflicts with newseg.
272 * Revision 1.133 1994/09/26 10:56:58 matt
273 * Fixed inconsistancies in lifeleft for immortal objects
275 * Revision 1.132 1994/09/25 23:41:10 matt
276 * Changed the object load & save code to read/write the structure fields one
277 * at a time (rather than the whole structure at once). This mean that the
278 * object structure can be changed without breaking the load/save functions.
279 * As a result of this change, the local_object data can be and has been
280 * incorporated into the object array. Also, timeleft is now a property
281 * of all objects, and the object structure has been otherwise cleaned up.
290 char gamesave_rcsid[] = "$Id: gamesave.c,v 1.21 2003-06-16 07:15:59 btb Exp $";
306 #include "editor/editor.h"
313 #include "gamemine.h"
322 #include "cntrlcen.h"
330 #include "gamefont.h"
331 #include "gamesave.h"
334 #include "byteswap.h"
338 char Gamesave_current_filename[128];
340 int Gamesave_current_version;
342 #define GAME_VERSION 32
343 #define GAME_COMPATIBLE_VERSION 22
345 //version 28->29 add delta light support
346 //version 27->28 controlcen id now is reactor number, not model number
348 //version 29->30 changed trigger structure
349 //version 30->31 changed trigger structure some more
350 //version 31->32 change segment structure, make it 512 bytes w/o editor, add Segment2s array.
352 #define MENU_CURSOR_X_MIN MENU_X
353 #define MENU_CURSOR_X_MAX MENU_X+6
356 ushort fileinfo_signature;
357 ushort fileinfo_version;
359 } game_top_fileinfo; // Should be same as first two fields below...
362 ushort fileinfo_signature;
363 ushort fileinfo_version;
365 char mine_filename[15];
367 int player_offset; // Player info
369 int object_offset; // Object info
379 int triggers_howmany;
390 int dl_indices_offset;
391 int dl_indices_howmany;
392 int dl_indices_sizeof;
393 int delta_light_offset;
394 int delta_light_howmany;
395 int delta_light_sizeof;
398 // LINT: adding function prototypes
399 void read_object(object *obj, CFILE *f, int version);
401 void write_object(object *obj, FILE *f);
402 void do_load_save_levels(int save);
405 void dump_mine_info(void);
408 extern char MaxPowerupsAllowed[MAX_POWERUP_TYPES];
409 extern char PowerupsInMine[MAX_POWERUP_TYPES];
412 extern char mine_filename[];
413 extern int save_mine_data_compiled(FILE * SaveFile);
415 //--unused-- char mine_filename[128];
418 int Gamesave_num_org_robots = 0;
419 //--unused-- grs_bitmap * Gamesave_saved_bitmap = NULL;
422 // Return true if this level has a name of the form "level??"
423 // Note that a pathspec can appear at the beginning of the filename.
424 int is_real_level(char *filename)
426 int len = strlen(filename);
431 //mprintf((0, "String = [%s]\n", &filename[len-11]));
432 return !strnicmp(&filename[len-11], "level", 5);
437 void change_filename_extension( char *dest, char *src, char *new_ext )
446 for (i=1; i<strlen(dest); i++ )
447 if (dest[i]=='.'||dest[i]==' '||dest[i]==0)
452 dest[i+1]=new_ext[0];
453 dest[i+2]=new_ext[1];
454 dest[i+3]=new_ext[2];
460 //--unused-- vms_angvec zero_angles={0,0,0};
462 #define vm_angvec_zero(v) do {(v)->p=(v)->b=(v)->h=0;} while (0)
464 int Gamesave_num_players=0;
466 int N_save_pof_names;
467 char Save_pof_names[MAX_POLYGON_MODELS][FILENAME_LEN];
469 void check_and_fix_matrix(vms_matrix *m);
471 void verify_object( object * obj ) {
473 obj->lifeleft = IMMORTAL_TIME; //all loaded object are immortal, for now
475 if ( obj->type == OBJ_ROBOT ) {
476 Gamesave_num_org_robots++;
478 // Make sure valid id...
479 if ( obj->id >= N_robot_types )
480 obj->id = obj->id % N_robot_types;
482 // Make sure model number & size are correct...
483 if ( obj->render_type == RT_POLYOBJ ) {
484 Assert(Robot_info[obj->id].model_num != -1);
485 //if you fail this assert, it means that a robot in this level
486 //hasn't been loaded, possibly because he's marked as
487 //non-shareware. To see what robot number, print obj->id.
489 Assert(Robot_info[obj->id].always_0xabcd == 0xabcd);
490 //if you fail this assert, it means that the robot_ai for
491 //a robot in this level hasn't been loaded, possibly because
492 //it's marked as non-shareware. To see what robot number,
495 obj->rtype.pobj_info.model_num = Robot_info[obj->id].model_num;
496 obj->size = Polygon_models[obj->rtype.pobj_info.model_num].rad;
498 //@@Took out this ugly hack 1/12/96, because Mike has added code
499 //@@that should fix it in a better way.
500 //@@//this is a super-ugly hack. Since the baby stripe robots have
501 //@@//their firing point on their bounding sphere, the firing points
502 //@@//can poke through a wall if the robots are very close to it. So
503 //@@//we make their radii bigger so the guns can't get too close to
505 //@@if (Robot_info[obj->id].flags & RIF_BIG_RADIUS)
506 //@@ obj->size = (obj->size*3)/2;
508 //@@if (obj->control_type==CT_AI && Robot_info[obj->id].attack_type)
509 //@@ obj->size = obj->size*3/4;
512 if (obj->id == 65) //special "reactor" robots
513 obj->movement_type = MT_NONE;
515 if (obj->movement_type == MT_PHYSICS) {
516 obj->mtype.phys_info.mass = Robot_info[obj->id].mass;
517 obj->mtype.phys_info.drag = Robot_info[obj->id].drag;
520 else { //Robots taken care of above
522 if ( obj->render_type == RT_POLYOBJ ) {
524 char *name = Save_pof_names[obj->rtype.pobj_info.model_num];
526 for (i=0;i<N_polygon_models;i++)
527 if (!stricmp(Pof_names[i],name)) { //found it!
528 // mprintf((0,"Mapping <%s> to %d (was %d)\n",name,i,obj->rtype.pobj_info.model_num));
529 obj->rtype.pobj_info.model_num = i;
535 if ( obj->type == OBJ_POWERUP ) {
536 if ( obj->id >= N_powerup_types ) {
538 Assert( obj->render_type != RT_POLYOBJ );
540 obj->control_type = CT_POWERUP;
541 obj->size = Powerup_info[obj->id].size;
542 obj->ctype.powerup_info.creation_time = 0;
545 if (Game_mode & GM_NETWORK)
547 if (multi_powerup_is_4pack(obj->id))
549 PowerupsInMine[obj->id-1]+=4;
550 MaxPowerupsAllowed[obj->id-1]+=4;
552 PowerupsInMine[obj->id]++;
553 MaxPowerupsAllowed[obj->id]++;
554 mprintf ((0,"PowerupLimiter: ID=%d\n",obj->id));
555 if (obj->id>MAX_POWERUP_TYPES)
556 mprintf ((1,"POWERUP: Overwriting array bounds!! Get JL!\n"));
562 if ( obj->type == OBJ_WEAPON ) {
563 if ( obj->id >= N_weapon_types ) {
565 Assert( obj->render_type != RT_POLYOBJ );
568 if (obj->id == PMINE_ID) { //make sure pmines have correct values
570 obj->mtype.phys_info.mass = Weapon_info[obj->id].mass;
571 obj->mtype.phys_info.drag = Weapon_info[obj->id].drag;
572 obj->mtype.phys_info.flags |= PF_FREE_SPINNING;
574 // Make sure model number & size are correct...
575 Assert( obj->render_type == RT_POLYOBJ );
577 obj->rtype.pobj_info.model_num = Weapon_info[obj->id].model_num;
578 obj->size = Polygon_models[obj->rtype.pobj_info.model_num].rad;
582 if ( obj->type == OBJ_CNTRLCEN ) {
584 obj->render_type = RT_POLYOBJ;
585 obj->control_type = CT_CNTRLCEN;
587 if (Gamesave_current_version <= 1) { // descent 1 reactor
588 obj->id = 0; // used to be only one kind of reactor
589 obj->rtype.pobj_info.model_num = Reactors[0].model_num;// descent 1 reactor
591 //@@// Make model number is correct...
592 //@@for (i=0; i<Num_total_object_types; i++ )
593 //@@ if ( ObjType[i] == OL_CONTROL_CENTER ) {
594 //@@ obj->rtype.pobj_info.model_num = ObjId[i];
595 //@@ obj->shields = ObjStrength[i];
602 // Check, and set, strength of reactor
603 for (i=0; i<Num_total_object_types; i++ )
604 if ( ObjType[i]==OL_CONTROL_CENTER && ObjId[i] == obj->id ) {
605 obj->shields = ObjStrength[i];
608 Assert(i < Num_total_object_types); //make sure we found it
613 if ( obj->type == OBJ_PLAYER ) {
616 //Assert(obj == Player);
618 if ( obj == ConsoleObject )
619 init_player_object();
621 if (obj->render_type == RT_POLYOBJ) //recover from Matt's pof file matchup bug
622 obj->rtype.pobj_info.model_num = Player_ship->model_num;
624 //Make sure orient matrix is orthogonal
625 check_and_fix_matrix(&obj->orient);
627 obj->id = Gamesave_num_players++;
630 if (obj->type == OBJ_HOSTAGE) {
632 //@@if (obj->id > N_hostage_types)
635 obj->render_type = RT_HOSTAGE;
636 obj->control_type = CT_POWERUP;
641 //static gs_skip(int len,CFILE *file)
644 // cfseek(file,len,SEEK_CUR);
648 static void gs_write_int(int i,FILE *file)
650 if (fwrite( &i, sizeof(i), 1, file) != 1)
651 Error( "Error reading int in gamesave.c" );
655 static void gs_write_fix(fix f,FILE *file)
657 if (fwrite( &f, sizeof(f), 1, file) != 1)
658 Error( "Error reading fix in gamesave.c" );
662 static void gs_write_short(short s,FILE *file)
664 if (fwrite( &s, sizeof(s), 1, file) != 1)
665 Error( "Error reading short in gamesave.c" );
669 static void gs_write_fixang(fixang f,FILE *file)
671 if (fwrite( &f, sizeof(f), 1, file) != 1)
672 Error( "Error reading fixang in gamesave.c" );
676 static void gs_write_byte(byte b,FILE *file)
678 if (fwrite( &b, sizeof(b), 1, file) != 1)
679 Error( "Error reading byte in gamesave.c" );
683 static void gr_write_vector(vms_vector *v,FILE *file)
685 gs_write_fix(v->x,file);
686 gs_write_fix(v->y,file);
687 gs_write_fix(v->z,file);
690 static void gs_write_matrix(vms_matrix *m,FILE *file)
692 gr_write_vector(&m->rvec,file);
693 gr_write_vector(&m->uvec,file);
694 gr_write_vector(&m->fvec,file);
697 static void gs_write_angvec(vms_angvec *v,FILE *file)
699 gs_write_fixang(v->p,file);
700 gs_write_fixang(v->b,file);
701 gs_write_fixang(v->h,file);
707 extern int multi_powerup_is_4pack(int);
708 //reads one object of the given version from the given file
709 void read_object(object *obj,CFILE *f,int version)
712 obj->type = cfile_read_byte(f);
713 obj->id = cfile_read_byte(f);
715 obj->control_type = cfile_read_byte(f);
716 obj->movement_type = cfile_read_byte(f);
717 obj->render_type = cfile_read_byte(f);
718 obj->flags = cfile_read_byte(f);
720 obj->segnum = cfile_read_short(f);
721 obj->attached_obj = -1;
723 cfile_read_vector(&obj->pos,f);
724 cfile_read_matrix(&obj->orient,f);
726 obj->size = cfile_read_fix(f);
727 obj->shields = cfile_read_fix(f);
729 cfile_read_vector(&obj->last_pos,f);
731 obj->contains_type = cfile_read_byte(f);
732 obj->contains_id = cfile_read_byte(f);
733 obj->contains_count = cfile_read_byte(f);
735 switch (obj->movement_type) {
739 cfile_read_vector(&obj->mtype.phys_info.velocity,f);
740 cfile_read_vector(&obj->mtype.phys_info.thrust,f);
742 obj->mtype.phys_info.mass = cfile_read_fix(f);
743 obj->mtype.phys_info.drag = cfile_read_fix(f);
744 obj->mtype.phys_info.brakes = cfile_read_fix(f);
746 cfile_read_vector(&obj->mtype.phys_info.rotvel,f);
747 cfile_read_vector(&obj->mtype.phys_info.rotthrust,f);
749 obj->mtype.phys_info.turnroll = cfile_read_fixang(f);
750 obj->mtype.phys_info.flags = cfile_read_short(f);
756 cfile_read_vector(&obj->mtype.spin_rate,f);
766 switch (obj->control_type) {
771 obj->ctype.ai_info.behavior = cfile_read_byte(f);
773 for (i=0;i<MAX_AI_FLAGS;i++)
774 obj->ctype.ai_info.flags[i] = cfile_read_byte(f);
776 obj->ctype.ai_info.hide_segment = cfile_read_short(f);
777 obj->ctype.ai_info.hide_index = cfile_read_short(f);
778 obj->ctype.ai_info.path_length = cfile_read_short(f);
779 obj->ctype.ai_info.cur_path_index = cfile_read_short(f);
782 cfile_read_short(f); // obj->ctype.ai_info.follow_path_start_seg =
783 cfile_read_short(f); // obj->ctype.ai_info.follow_path_end_seg =
791 obj->ctype.expl_info.spawn_time = cfile_read_fix(f);
792 obj->ctype.expl_info.delete_time = cfile_read_fix(f);
793 obj->ctype.expl_info.delete_objnum = cfile_read_short(f);
794 obj->ctype.expl_info.next_attach = obj->ctype.expl_info.prev_attach = obj->ctype.expl_info.attach_parent = -1;
800 //do I really need to read these? Are they even saved to disk?
802 obj->ctype.laser_info.parent_type = cfile_read_short(f);
803 obj->ctype.laser_info.parent_num = cfile_read_short(f);
804 obj->ctype.laser_info.parent_signature = cfile_read_int(f);
810 obj->ctype.light_info.intensity = cfile_read_fix(f);
816 obj->ctype.powerup_info.count = cfile_read_int(f);
818 obj->ctype.powerup_info.count = 1;
820 if (obj->id == POW_VULCAN_WEAPON)
821 obj->ctype.powerup_info.count = VULCAN_WEAPON_AMMO_AMOUNT;
823 if (obj->id == POW_GAUSS_WEAPON)
824 obj->ctype.powerup_info.count = VULCAN_WEAPON_AMMO_AMOUNT;
826 if (obj->id == POW_OMEGA_WEAPON)
827 obj->ctype.powerup_info.count = MAX_OMEGA_CHARGE;
837 case CT_SLEW: //the player is generally saved as slew
851 switch (obj->render_type) {
860 obj->rtype.pobj_info.model_num = cfile_read_int(f);
862 for (i=0;i<MAX_SUBMODELS;i++)
863 cfile_read_angvec(&obj->rtype.pobj_info.anim_angles[i],f);
865 obj->rtype.pobj_info.subobj_flags = cfile_read_int(f);
867 tmo = cfile_read_int(f);
870 obj->rtype.pobj_info.tmap_override = tmo;
873 obj->rtype.pobj_info.tmap_override = -1;
875 int xlated_tmo = tmap_xlate_table[tmo];
876 if (xlated_tmo < 0) {
877 mprintf( (0, "Couldn't find texture for demo object, model_num = %d\n", obj->rtype.pobj_info.model_num));
881 obj->rtype.pobj_info.tmap_override = xlated_tmo;
885 obj->rtype.pobj_info.alt_textures = 0;
890 case RT_WEAPON_VCLIP:
895 obj->rtype.vclip_info.vclip_num = cfile_read_int(f);
896 obj->rtype.vclip_info.frametime = cfile_read_fix(f);
897 obj->rtype.vclip_info.framenum = cfile_read_byte(f);
913 //writes one object to the given file
914 void write_object(object *obj,FILE *f)
916 gs_write_byte(obj->type,f);
917 gs_write_byte(obj->id,f);
919 gs_write_byte(obj->control_type,f);
920 gs_write_byte(obj->movement_type,f);
921 gs_write_byte(obj->render_type,f);
922 gs_write_byte(obj->flags,f);
924 gs_write_short(obj->segnum,f);
926 gr_write_vector(&obj->pos,f);
927 gs_write_matrix(&obj->orient,f);
929 gs_write_fix(obj->size,f);
930 gs_write_fix(obj->shields,f);
932 gr_write_vector(&obj->last_pos,f);
934 gs_write_byte(obj->contains_type,f);
935 gs_write_byte(obj->contains_id,f);
936 gs_write_byte(obj->contains_count,f);
938 switch (obj->movement_type) {
942 gr_write_vector(&obj->mtype.phys_info.velocity,f);
943 gr_write_vector(&obj->mtype.phys_info.thrust,f);
945 gs_write_fix(obj->mtype.phys_info.mass,f);
946 gs_write_fix(obj->mtype.phys_info.drag,f);
947 gs_write_fix(obj->mtype.phys_info.brakes,f);
949 gr_write_vector(&obj->mtype.phys_info.rotvel,f);
950 gr_write_vector(&obj->mtype.phys_info.rotthrust,f);
952 gs_write_fixang(obj->mtype.phys_info.turnroll,f);
953 gs_write_short(obj->mtype.phys_info.flags,f);
959 gr_write_vector(&obj->mtype.spin_rate,f);
969 switch (obj->control_type) {
974 gs_write_byte(obj->ctype.ai_info.behavior,f);
976 for (i=0;i<MAX_AI_FLAGS;i++)
977 gs_write_byte(obj->ctype.ai_info.flags[i],f);
979 gs_write_short(obj->ctype.ai_info.hide_segment,f);
980 gs_write_short(obj->ctype.ai_info.hide_index,f);
981 gs_write_short(obj->ctype.ai_info.path_length,f);
982 gs_write_short(obj->ctype.ai_info.cur_path_index,f);
984 // -- unused! mk, 08/13/95 -- gs_write_short(obj->ctype.ai_info.follow_path_start_seg,f);
985 // -- unused! mk, 08/13/95 -- gs_write_short(obj->ctype.ai_info.follow_path_end_seg,f);
992 gs_write_fix(obj->ctype.expl_info.spawn_time,f);
993 gs_write_fix(obj->ctype.expl_info.delete_time,f);
994 gs_write_short(obj->ctype.expl_info.delete_objnum,f);
1000 //do I really need to write these objects?
1002 gs_write_short(obj->ctype.laser_info.parent_type,f);
1003 gs_write_short(obj->ctype.laser_info.parent_num,f);
1004 gs_write_int(obj->ctype.laser_info.parent_signature,f);
1010 gs_write_fix(obj->ctype.light_info.intensity,f);
1015 gs_write_int(obj->ctype.powerup_info.count,f);
1023 case CT_SLEW: //the player is generally saved as slew
1027 break; //control center object.
1037 switch (obj->render_type) {
1046 gs_write_int(obj->rtype.pobj_info.model_num,f);
1048 for (i=0;i<MAX_SUBMODELS;i++)
1049 gs_write_angvec(&obj->rtype.pobj_info.anim_angles[i],f);
1051 gs_write_int(obj->rtype.pobj_info.subobj_flags,f);
1053 gs_write_int(obj->rtype.pobj_info.tmap_override,f);
1058 case RT_WEAPON_VCLIP:
1063 gs_write_int(obj->rtype.vclip_info.vclip_num,f);
1064 gs_write_fix(obj->rtype.vclip_info.frametime,f);
1065 gs_write_byte(obj->rtype.vclip_info.framenum,f);
1080 extern int remove_trigger_num(int trigger_num);
1082 // -----------------------------------------------------------------------------
1084 // Loads all the relevant data for a level.
1085 // If level != -1, it loads the filename with extension changed to .min
1086 // Otherwise it loads the appropriate level mine.
1087 // returns 0=everything ok, 1=old version, -1=error
1088 int load_game_data(CFILE *LoadFile)
1093 start_offset = cftell(LoadFile);
1095 //===================== READ FILE INFO ========================
1097 // Set default values
1098 game_fileinfo.level = -1;
1099 game_fileinfo.player_offset = -1;
1100 game_fileinfo.player_sizeof = sizeof(player);
1101 game_fileinfo.object_offset = -1;
1102 game_fileinfo.object_howmany = 0;
1103 game_fileinfo.object_sizeof = sizeof(object);
1104 game_fileinfo.walls_offset = -1;
1105 game_fileinfo.walls_howmany = 0;
1106 game_fileinfo.walls_sizeof = sizeof(wall);
1107 game_fileinfo.doors_offset = -1;
1108 game_fileinfo.doors_howmany = 0;
1109 game_fileinfo.doors_sizeof = sizeof(active_door);
1110 game_fileinfo.triggers_offset = -1;
1111 game_fileinfo.triggers_howmany = 0;
1112 game_fileinfo.triggers_sizeof = sizeof(trigger);
1113 game_fileinfo.control_offset = -1;
1114 game_fileinfo.control_howmany = 0;
1115 game_fileinfo.control_sizeof = sizeof(control_center_triggers);
1116 game_fileinfo.matcen_offset = -1;
1117 game_fileinfo.matcen_howmany = 0;
1118 game_fileinfo.matcen_sizeof = sizeof(matcen_info);
1120 game_fileinfo.dl_indices_offset = -1;
1121 game_fileinfo.dl_indices_howmany = 0;
1122 game_fileinfo.dl_indices_sizeof = sizeof(dl_index);
1124 game_fileinfo.delta_light_offset = -1;
1125 game_fileinfo.delta_light_howmany = 0;
1126 game_fileinfo.delta_light_sizeof = sizeof(delta_light);
1128 // Read in game_top_fileinfo to get size of saved fileinfo.
1130 if (cfseek( LoadFile, start_offset, SEEK_SET ))
1131 Error( "Error seeking in gamesave.c" );
1133 // if (cfread( &game_top_fileinfo, sizeof(game_top_fileinfo), 1, LoadFile) != 1)
1134 // Error( "Error reading game_top_fileinfo in gamesave.c" );
1136 game_top_fileinfo.fileinfo_signature = cfile_read_short(LoadFile);
1137 game_top_fileinfo.fileinfo_version = cfile_read_short(LoadFile);
1138 game_top_fileinfo.fileinfo_sizeof = cfile_read_int(LoadFile);
1141 if (game_top_fileinfo.fileinfo_signature != 0x6705)
1144 // Check version number
1145 if (game_top_fileinfo.fileinfo_version < GAME_COMPATIBLE_VERSION )
1148 // Now, Read in the fileinfo
1149 if (cfseek( LoadFile, start_offset, SEEK_SET ))
1150 Error( "Error seeking to game_fileinfo in gamesave.c" );
1152 // if (cfread( &game_fileinfo, game_top_fileinfo.fileinfo_sizeof, 1, LoadFile )!=1)
1153 // Error( "Error reading game_fileinfo in gamesave.c" );
1155 game_fileinfo.fileinfo_signature = cfile_read_short(LoadFile);
1156 game_fileinfo.fileinfo_version = cfile_read_short(LoadFile);
1157 game_fileinfo.fileinfo_sizeof = cfile_read_int(LoadFile);
1159 game_fileinfo.mine_filename[i] = cfile_read_byte(LoadFile);
1160 game_fileinfo.level = cfile_read_int(LoadFile);
1161 game_fileinfo.player_offset = cfile_read_int(LoadFile); // Player info
1162 game_fileinfo.player_sizeof = cfile_read_int(LoadFile);
1163 game_fileinfo.object_offset = cfile_read_int(LoadFile); // Object info
1164 game_fileinfo.object_howmany = cfile_read_int(LoadFile);
1165 game_fileinfo.object_sizeof = cfile_read_int(LoadFile);
1166 game_fileinfo.walls_offset = cfile_read_int(LoadFile);
1167 game_fileinfo.walls_howmany = cfile_read_int(LoadFile);
1168 game_fileinfo.walls_sizeof = cfile_read_int(LoadFile);
1169 game_fileinfo.doors_offset = cfile_read_int(LoadFile);
1170 game_fileinfo.doors_howmany = cfile_read_int(LoadFile);
1171 game_fileinfo.doors_sizeof = cfile_read_int(LoadFile);
1172 game_fileinfo.triggers_offset = cfile_read_int(LoadFile);
1173 game_fileinfo.triggers_howmany = cfile_read_int(LoadFile);
1174 game_fileinfo.triggers_sizeof = cfile_read_int(LoadFile);
1175 game_fileinfo.links_offset = cfile_read_int(LoadFile);
1176 game_fileinfo.links_howmany = cfile_read_int(LoadFile);
1177 game_fileinfo.links_sizeof = cfile_read_int(LoadFile);
1178 game_fileinfo.control_offset = cfile_read_int(LoadFile);
1179 game_fileinfo.control_howmany = cfile_read_int(LoadFile);
1180 game_fileinfo.control_sizeof = cfile_read_int(LoadFile);
1181 game_fileinfo.matcen_offset = cfile_read_int(LoadFile);
1182 game_fileinfo.matcen_howmany = cfile_read_int(LoadFile);
1183 game_fileinfo.matcen_sizeof = cfile_read_int(LoadFile);
1185 if (game_top_fileinfo.fileinfo_version >= 29) {
1186 game_fileinfo.dl_indices_offset = cfile_read_int(LoadFile);
1187 game_fileinfo.dl_indices_howmany = cfile_read_int(LoadFile);
1188 game_fileinfo.dl_indices_sizeof = cfile_read_int(LoadFile);
1190 game_fileinfo.delta_light_offset = cfile_read_int(LoadFile);
1191 game_fileinfo.delta_light_howmany = cfile_read_int(LoadFile);
1192 game_fileinfo.delta_light_sizeof = cfile_read_int(LoadFile);
1195 if (game_top_fileinfo.fileinfo_version >= 31) { //load mine filename
1196 // read newline-terminated string, not sure what version this changed.
1197 cfgets(Current_level_name,sizeof(Current_level_name),LoadFile);
1199 if (Current_level_name[strlen(Current_level_name)-1] == '\n')
1200 Current_level_name[strlen(Current_level_name)-1] = 0;
1202 else if (game_top_fileinfo.fileinfo_version >= 14) { //load mine filename
1203 // read null-terminated string
1204 char *p=Current_level_name;
1205 //must do read one char at a time, since no cfgets()
1206 do *p = cfgetc(LoadFile); while (*p++!=0);
1209 Current_level_name[0]=0;
1211 if (game_top_fileinfo.fileinfo_version >= 19) { //load pof names
1212 N_save_pof_names = cfile_read_short(LoadFile);
1213 if (N_save_pof_names != 0x614d && N_save_pof_names != 0x5547) { // "Ma"de w/DMB beta/"GU"ILE
1214 Assert(N_save_pof_names < MAX_POLYGON_MODELS);
1215 cfread(Save_pof_names,N_save_pof_names,FILENAME_LEN,LoadFile);
1219 //===================== READ PLAYER INFO ==========================
1220 Object_next_signature = 0;
1222 //===================== READ OBJECT INFO ==========================
1224 Gamesave_num_org_robots = 0;
1225 Gamesave_num_players = 0;
1227 if (game_fileinfo.object_offset > -1) {
1228 if (cfseek( LoadFile, game_fileinfo.object_offset, SEEK_SET ))
1229 Error( "Error seeking to object_offset in gamesave.c" );
1231 for (i=0;i<game_fileinfo.object_howmany;i++) {
1233 read_object(&Objects[i], LoadFile, game_top_fileinfo.fileinfo_version);
1235 Objects[i].signature = Object_next_signature++;
1236 verify_object( &Objects[i] );
1241 //===================== READ WALL INFO ============================
1243 if (game_fileinfo.walls_offset > -1)
1246 if (!cfseek( LoadFile, game_fileinfo.walls_offset,SEEK_SET )) {
1247 for (i=0;i<game_fileinfo.walls_howmany;i++) {
1249 if (game_top_fileinfo.fileinfo_version >= 20)
1250 wall_read(&Walls[i], LoadFile); // v20 walls and up.
1251 else if (game_top_fileinfo.fileinfo_version >= 17) {
1254 v19_wall_read(&w, LoadFile);
1256 Walls[i].segnum = w.segnum;
1257 Walls[i].sidenum = w.sidenum;
1258 Walls[i].linked_wall = w.linked_wall;
1260 Walls[i].type = w.type;
1261 Walls[i].flags = w.flags;
1262 Walls[i].hps = w.hps;
1263 Walls[i].trigger = w.trigger;
1264 Walls[i].clip_num = w.clip_num;
1265 Walls[i].keys = w.keys;
1267 Walls[i].state = WALL_DOOR_CLOSED;
1271 v16_wall_read(&w, LoadFile);
1273 Walls[i].segnum = Walls[i].sidenum = Walls[i].linked_wall = -1;
1275 Walls[i].type = w.type;
1276 Walls[i].flags = w.flags;
1277 Walls[i].hps = w.hps;
1278 Walls[i].trigger = w.trigger;
1279 Walls[i].clip_num = w.clip_num;
1280 Walls[i].keys = w.keys;
1287 //===================== READ DOOR INFO ============================
1289 if (game_fileinfo.doors_offset > -1)
1291 if (!cfseek( LoadFile, game_fileinfo.doors_offset,SEEK_SET )) {
1293 for (i=0;i<game_fileinfo.doors_howmany;i++) {
1295 if (game_top_fileinfo.fileinfo_version >= 20)
1296 active_door_read(&ActiveDoors[i], LoadFile); // version 20 and up
1301 v19_door_read(&d, LoadFile);
1303 ActiveDoors[i].n_parts = d.n_parts;
1305 for (p=0;p<d.n_parts;p++) {
1308 cseg = Segments[d.seg[p]].children[d.side[p]];
1309 cside = find_connect_side(&Segments[d.seg[p]],&Segments[cseg]);
1311 ActiveDoors[i].front_wallnum[p] = Segments[d.seg[p]].sides[d.side[p]].wall_num;
1312 ActiveDoors[i].back_wallnum[p] = Segments[cseg].sides[cside].wall_num;
1320 //==================== READ TRIGGER INFO ==========================
1323 // for MACINTOSH -- assume all triggers >= verion 31 triggers.
1325 if (game_fileinfo.triggers_offset > -1)
1327 if (!cfseek( LoadFile, game_fileinfo.triggers_offset,SEEK_SET )) {
1328 for (i=0;i<game_fileinfo.triggers_howmany;i++)
1329 if (game_top_fileinfo.fileinfo_version < 31) {
1335 if (game_top_fileinfo.fileinfo_version < 30) {
1339 v29_trigger_read(&trig29, LoadFile);
1341 trig.flags = trig29.flags;
1342 trig.num_links = trig29.num_links;
1343 trig.num_links = trig29.num_links;
1344 trig.value = trig29.value;
1345 trig.time = trig29.time;
1347 for (t=0;t<trig.num_links;t++) {
1348 trig.seg[t] = trig29.seg[t];
1349 trig.side[t] = trig29.side[t];
1353 v30_trigger_read(&trig, LoadFile);
1355 //Assert(trig.flags & TRIGGER_ON);
1356 trig.flags &= ~TRIGGER_ON;
1358 if (trig.flags & TRIGGER_CONTROL_DOORS)
1359 type = TT_OPEN_DOOR;
1360 else if (trig.flags & TRIGGER_SHIELD_DAMAGE)
1362 else if (trig.flags & TRIGGER_ENERGY_DRAIN)
1364 else if (trig.flags & TRIGGER_EXIT)
1366 else if (trig.flags & TRIGGER_ONE_SHOT)
1368 else if (trig.flags & TRIGGER_MATCEN)
1370 else if (trig.flags & TRIGGER_ILLUSION_OFF)
1371 type = TT_ILLUSION_OFF;
1372 else if (trig.flags & TRIGGER_SECRET_EXIT)
1373 type = TT_SECRET_EXIT;
1374 else if (trig.flags & TRIGGER_ILLUSION_ON)
1375 type = TT_ILLUSION_ON;
1376 else if (trig.flags & TRIGGER_UNLOCK_DOORS)
1377 type = TT_UNLOCK_DOOR;
1378 else if (trig.flags & TRIGGER_OPEN_WALL)
1379 type = TT_OPEN_WALL;
1380 else if (trig.flags & TRIGGER_CLOSE_WALL)
1381 type = TT_CLOSE_WALL;
1382 else if (trig.flags & TRIGGER_ILLUSORY_WALL)
1383 type = TT_ILLUSORY_WALL;
1387 Triggers[i].type = type;
1388 Triggers[i].flags = 0;
1389 Triggers[i].num_links = trig.num_links;
1390 Triggers[i].num_links = trig.num_links;
1391 Triggers[i].value = trig.value;
1392 Triggers[i].time = trig.time;
1394 for (t=0;t<trig.num_links;t++) {
1395 Triggers[i].seg[t] = trig.seg[t];
1396 Triggers[i].side[t] = trig.side[t];
1400 trigger_read(&Triggers[i], LoadFile);
1404 //================ READ CONTROL CENTER TRIGGER INFO ===============
1406 if (game_fileinfo.control_offset > -1)
1407 if (!cfseek(LoadFile, game_fileinfo.control_offset, SEEK_SET))
1409 Assert(game_fileinfo.control_sizeof == sizeof(control_center_triggers));
1410 control_center_triggers_read_n(&ControlCenterTriggers, game_fileinfo.control_howmany, LoadFile);
1413 //================ READ MATERIALOGRIFIZATIONATORS INFO ===============
1415 if (game_fileinfo.matcen_offset > -1)
1418 if (!cfseek( LoadFile, game_fileinfo.matcen_offset,SEEK_SET )) {
1419 // mprintf((0, "Reading %i materialization centers.\n", game_fileinfo.matcen_howmany));
1420 for (i=0;i<game_fileinfo.matcen_howmany;i++) {
1421 if (game_top_fileinfo.fileinfo_version < 27) {
1424 old_matcen_info_read(&m, LoadFile);
1426 RobotCenters[i].robot_flags[0] = m.robot_flags;
1427 RobotCenters[i].robot_flags[1] = 0;
1428 RobotCenters[i].hit_points = m.hit_points;
1429 RobotCenters[i].interval = m.interval;
1430 RobotCenters[i].segnum = m.segnum;
1431 RobotCenters[i].fuelcen_num = m.fuelcen_num;
1434 matcen_info_read(&RobotCenters[i], LoadFile);
1436 // Set links in RobotCenters to Station array
1438 for (j=0; j<=Highest_segment_index; j++)
1439 if (Segment2s[j].special == SEGMENT_IS_ROBOTMAKER)
1440 if (Segment2s[j].matcen_num == i)
1441 RobotCenters[i].fuelcen_num = Segment2s[j].value;
1443 // mprintf((0, " %i: flags = %08x\n", i, RobotCenters[i].robot_flags));
1449 //================ READ DL_INDICES INFO ===============
1451 Num_static_lights = 0;
1453 if (game_fileinfo.dl_indices_offset > -1) {
1456 if (!cfseek( LoadFile, game_fileinfo.dl_indices_offset, SEEK_SET )) {
1457 Num_static_lights = game_fileinfo.dl_indices_howmany;
1458 for (i=0; i<game_fileinfo.dl_indices_howmany; i++) {
1459 if (game_top_fileinfo.fileinfo_version < 29) {
1460 mprintf((0, "Warning: Old mine version. Not reading Dl_indices info.\n"));
1461 Int3(); //shouldn't be here!!!
1463 dl_index_read(&Dl_indices[i], LoadFile);
1468 // Indicate that no light has been subtracted from any vertices.
1469 clear_light_subtracted();
1471 //================ READ DELTA LIGHT INFO ===============
1473 if (game_fileinfo.delta_light_offset > -1) {
1476 if (!cfseek( LoadFile, game_fileinfo.delta_light_offset, SEEK_SET )) {
1477 for (i=0; i<game_fileinfo.delta_light_howmany; i++) {
1478 if (game_top_fileinfo.fileinfo_version < 29) {
1479 mprintf((0, "Warning: Old mine version. Not reading delta light info.\n"));
1481 delta_light_read(&Delta_lights[i], LoadFile);
1486 //========================= UPDATE VARIABLES ======================
1488 reset_objects(game_fileinfo.object_howmany);
1490 for (i=0; i<MAX_OBJECTS; i++) {
1491 Objects[i].next = Objects[i].prev = -1;
1492 if (Objects[i].type != OBJ_NONE) {
1493 int objsegnum = Objects[i].segnum;
1495 if (objsegnum > Highest_segment_index) //bogus object
1496 Objects[i].type = OBJ_NONE;
1498 Objects[i].segnum = -1; //avoid Assert()
1499 obj_link(i,objsegnum);
1504 clear_transient_objects(1); //1 means clear proximity bombs
1506 // Make sure non-transparent doors are set correctly.
1507 for (i=0; i< Num_segments; i++)
1508 for (j=0;j<MAX_SIDES_PER_SEGMENT;j++) {
1509 side *sidep = &Segments[i].sides[j];
1510 if ((sidep->wall_num != -1) && (Walls[sidep->wall_num].clip_num != -1)) {
1511 //mprintf((0, "Checking Wall %d\n", Segments[i].sides[j].wall_num));
1512 if (WallAnims[Walls[sidep->wall_num].clip_num].flags & WCF_TMAP1) {
1513 //mprintf((0, "Fixing non-transparent door.\n"));
1514 sidep->tmap_num = WallAnims[Walls[sidep->wall_num].clip_num].frames[0];
1515 sidep->tmap_num2 = 0;
1521 Num_walls = game_fileinfo.walls_howmany;
1524 Num_open_doors = game_fileinfo.doors_howmany;
1525 Num_triggers = game_fileinfo.triggers_howmany;
1527 //go through all walls, killing references to invalid triggers
1528 for (i=0;i<Num_walls;i++)
1529 if (Walls[i].trigger >= Num_triggers) {
1530 mprintf((0,"Removing reference to invalid trigger %d from wall %d\n",Walls[i].trigger,i));
1531 Walls[i].trigger = -1; //kill trigger
1534 //go through all triggers, killing unused ones
1535 for (i=0;i<Num_triggers;) {
1538 // Find which wall this trigger is connected to.
1539 for (w=0; w<Num_walls; w++)
1540 if (Walls[w].trigger == i)
1544 if (w == Num_walls) {
1545 mprintf((0,"Removing unreferenced trigger %d\n",i));
1546 remove_trigger_num(i);
1553 // MK, 10/17/95: Make walls point back at the triggers that control them.
1554 // Go through all triggers, stuffing controlling_trigger field in Walls.
1557 for (i=0; i<Num_walls; i++)
1558 Walls[i].controlling_trigger = -1;
1560 for (t=0; t<Num_triggers; t++) {
1562 for (l=0; l<Triggers[t].num_links; l++) {
1563 int seg_num, side_num, wall_num;
1565 seg_num = Triggers[t].seg[l];
1566 side_num = Triggers[t].side[l];
1567 wall_num = Segments[seg_num].sides[side_num].wall_num;
1569 // -- if (Walls[wall_num].controlling_trigger != -1)
1572 //check to see that if a trigger requires a wall that it has one,
1573 //and if it requires a matcen that it has one
1575 if (Triggers[t].type == TT_MATCEN) {
1576 if (Segment2s[seg_num].special != SEGMENT_IS_ROBOTMAKER)
1577 Int3(); //matcen trigger doesn't point to matcen
1579 else if (Triggers[t].type != TT_LIGHT_OFF && Triggers[t].type != TT_LIGHT_ON) { //light triggers don't require walls
1581 Int3(); // This is illegal. This trigger requires a wall
1583 Walls[wall_num].controlling_trigger = t;
1589 Num_robot_centers = game_fileinfo.matcen_howmany;
1591 //fix old wall structs
1592 if (game_top_fileinfo.fileinfo_version < 17) {
1593 int segnum,sidenum,wallnum;
1595 for (segnum=0; segnum<=Highest_segment_index; segnum++)
1596 for (sidenum=0;sidenum<6;sidenum++)
1597 if ((wallnum=Segments[segnum].sides[sidenum].wall_num) != -1) {
1598 Walls[wallnum].segnum = segnum;
1599 Walls[wallnum].sidenum = sidenum;
1606 for (sidenum=0; sidenum<6; sidenum++) {
1607 int wallnum = Segments[Highest_segment_index].sides[sidenum].wall_num;
1609 if ((Walls[wallnum].segnum != Highest_segment_index) || (Walls[wallnum].sidenum != sidenum))
1610 Int3(); // Error. Bogus walls in this segment.
1611 // Consult Yuan or Mike.
1616 //create_local_segment_data();
1624 if (game_top_fileinfo.fileinfo_version < GAME_VERSION && !(game_top_fileinfo.fileinfo_version==25 && GAME_VERSION==26))
1625 return 1; //means old version
1631 int check_segment_connections(void);
1633 extern void set_ambient_sound_flags(void);
1635 // ----------------------------------------------------------------------------
1637 #define LEVEL_FILE_VERSION 8
1638 //1 -> 2 add palette name
1639 //2 -> 3 add control center explosion time
1640 //3 -> 4 add reactor strength
1641 //4 -> 5 killed hostage text stuff
1642 //5 -> 6 added Secret_return_segment and Secret_return_orient
1643 //6 -> 7 added flickering lights
1644 //7 -> 8 made version 8 to be not compatible with D2 1.0 & 1.1
1647 char *Level_being_loaded=NULL;
1651 extern void ncache_flush();
1654 extern int Slide_segs_computed;
1656 int no_old_level_file_error=0;
1658 //loads a level (.LVL) file from disk
1659 //returns 0 if success, else error code
1660 int load_level(char * filename_passed)
1663 int use_compiled_level=1;
1667 int sig, minedata_offset, gamedata_offset;
1668 int mine_err, game_err;
1673 Slide_segs_computed = 0;
1676 if (Game_mode & GM_NETWORK)
1678 for (i=0;i<MAX_POWERUP_TYPES;i++)
1680 MaxPowerupsAllowed[i]=0;
1681 PowerupsInMine[i]=0;
1691 Level_being_loaded = filename_passed;
1694 strcpy(filename,filename_passed);
1697 //if we have the editor, try the LVL first, no matter what was passed.
1698 //if we don't have an LVL, try RDL
1699 //if we don't have the editor, we just use what was passed
1701 change_filename_extension(filename,filename_passed,".lvl");
1702 use_compiled_level = 0;
1704 if (!cfexist(filename)) {
1705 change_filename_extension(filename,filename,".rl2");
1706 use_compiled_level = 1;
1710 LoadFile = cfopen( filename, "rb" );
1714 mprintf((0,"Can't open level file <%s>\n", filename));
1717 Error("Can't open file <%s>\n",filename);
1721 strcpy( Gamesave_current_filename, filename );
1724 // if ( Newdemo_state == ND_STATE_RECORDING )
1725 // newdemo_record_start_demo();
1728 sig = cfile_read_int(LoadFile);
1729 Gamesave_current_version = cfile_read_int(LoadFile);
1730 mprintf((0, "Gamesave_current_version = %d\n", Gamesave_current_version));
1731 minedata_offset = cfile_read_int(LoadFile);
1732 gamedata_offset = cfile_read_int(LoadFile);
1734 Assert(sig == MAKE_SIG('P','L','V','L'));
1736 if (Gamesave_current_version >= 8) { //read dummy data
1737 cfile_read_int(LoadFile);
1738 cfile_read_short(LoadFile);
1739 cfile_read_byte(LoadFile);
1742 if (Gamesave_current_version < 5)
1743 cfile_read_int(LoadFile); //was hostagetext_offset
1745 if (Gamesave_current_version > 1) {
1746 cfgets(Current_level_palette,sizeof(Current_level_palette),LoadFile);
1747 if (Current_level_palette[strlen(Current_level_palette)-1] == '\n')
1748 Current_level_palette[strlen(Current_level_palette)-1] = 0;
1750 if (Gamesave_current_version <= 1 || Current_level_palette[0]==0) // descent 1 level
1751 strcpy(Current_level_palette, DEFAULT_LEVEL_PALETTE);
1753 if (Gamesave_current_version >= 3)
1754 Base_control_center_explosion_time = cfile_read_int(LoadFile);
1756 Base_control_center_explosion_time = DEFAULT_CONTROL_CENTER_EXPLOSION_TIME;
1758 if (Gamesave_current_version >= 4)
1759 Reactor_strength = cfile_read_int(LoadFile);
1761 Reactor_strength = -1; //use old defaults
1763 if (Gamesave_current_version >= 7) {
1766 Num_flickering_lights = cfile_read_int(LoadFile);
1767 Assert((Num_flickering_lights >= 0) && (Num_flickering_lights < MAX_FLICKERING_LIGHTS));
1768 for (i = 0; i < Num_flickering_lights; i++)
1769 flickering_light_read(&Flickering_lights[i], LoadFile);
1772 Num_flickering_lights = 0;
1774 if (Gamesave_current_version < 6) {
1775 Secret_return_segment = 0;
1776 Secret_return_orient.rvec.x = F1_0;
1777 Secret_return_orient.rvec.y = 0;
1778 Secret_return_orient.rvec.z = 0;
1779 Secret_return_orient.fvec.x = 0;
1780 Secret_return_orient.fvec.y = F1_0;
1781 Secret_return_orient.fvec.z = 0;
1782 Secret_return_orient.uvec.x = 0;
1783 Secret_return_orient.uvec.y = 0;
1784 Secret_return_orient.uvec.z = F1_0;
1786 Secret_return_segment = cfile_read_int(LoadFile);
1787 Secret_return_orient.rvec.x = cfile_read_int(LoadFile);
1788 Secret_return_orient.rvec.y = cfile_read_int(LoadFile);
1789 Secret_return_orient.rvec.z = cfile_read_int(LoadFile);
1790 Secret_return_orient.fvec.x = cfile_read_int(LoadFile);
1791 Secret_return_orient.fvec.y = cfile_read_int(LoadFile);
1792 Secret_return_orient.fvec.z = cfile_read_int(LoadFile);
1793 Secret_return_orient.uvec.x = cfile_read_int(LoadFile);
1794 Secret_return_orient.uvec.y = cfile_read_int(LoadFile);
1795 Secret_return_orient.uvec.z = cfile_read_int(LoadFile);
1798 cfseek(LoadFile,minedata_offset,SEEK_SET);
1800 if (!use_compiled_level) {
1801 mine_err = load_mine_data(LoadFile);
1802 #if 0 // get from d1src if needed
1803 // Compress all uv coordinates in mine, improves texmap precision. --MK, 02/19/96
1804 compress_uv_coordinates_all();
1808 //NOTE LINK TO ABOVE!!
1809 mine_err = load_mine_data_compiled(LoadFile);
1811 if (mine_err == -1) { //error!!
1816 cfseek(LoadFile,gamedata_offset,SEEK_SET);
1817 game_err = load_game_data(LoadFile);
1819 if (game_err == -1) { //error!!
1824 //======================== CLOSE FILE =============================
1826 cfclose( LoadFile );
1828 set_ambient_sound_flags();
1831 write_game_text_file(filename);
1832 if (Errors_in_mine) {
1833 if (is_real_level(filename)) {
1834 char ErrorMessage[200];
1836 sprintf( ErrorMessage, "Warning: %i errors in %s!\n", Errors_in_mine, Level_being_loaded );
1838 gr_palette_load(gr_palette);
1839 nm_messagebox( NULL, 1, "Continue", ErrorMessage );
1842 mprintf((1, "Error: %i errors in %s.\n", Errors_in_mine, Level_being_loaded));
1847 //If an old version, ask the use if he wants to save as new version
1848 if (!no_old_level_file_error && (Function_mode == FMODE_EDITOR) && (((LEVEL_FILE_VERSION > 3) && Gamesave_current_version < LEVEL_FILE_VERSION) || mine_err == 1 || game_err == 1)) {
1849 char ErrorMessage[200];
1851 sprintf( ErrorMessage,
1852 "You just loaded a old version\n"
1853 "level. Would you like to save\n"
1854 "it as a current version level?");
1857 gr_palette_load(gr_palette);
1858 if (nm_messagebox( NULL, 2, "Don't Save", "Save", ErrorMessage )==1)
1859 save_level(filename);
1865 if (Function_mode == FMODE_EDITOR)
1866 editor_status("Loaded NEW mine %s, \"%s\"",filename,Current_level_name);
1870 if (check_segment_connections())
1871 nm_messagebox( "ERROR", 1, "Ok",
1872 "Connectivity errors detected in\n"
1873 "mine. See monochrome screen for\n"
1874 "details, and contact Matt or Mike." );
1881 void get_level_name()
1883 //NO_UI!!! UI_WINDOW *NameWindow = NULL;
1884 //NO_UI!!! UI_GADGET_INPUTBOX *NameText;
1885 //NO_UI!!! UI_GADGET_BUTTON *QuitButton;
1887 //NO_UI!!! // Open a window with a quit button
1888 //NO_UI!!! NameWindow = ui_open_window( 20, 20, 300, 110, WIN_DIALOG );
1889 //NO_UI!!! QuitButton = ui_add_gadget_button( NameWindow, 150-24, 60, 48, 40, "Done", NULL );
1891 //NO_UI!!! ui_wprintf_at( NameWindow, 10, 12,"Please enter a name for this mine:" );
1892 //NO_UI!!! NameText = ui_add_gadget_inputbox( NameWindow, 10, 30, LEVEL_NAME_LEN, LEVEL_NAME_LEN, Current_level_name );
1894 //NO_UI!!! NameWindow->keyboard_focus_gadget = (UI_GADGET *)NameText;
1895 //NO_UI!!! QuitButton->hotkey = KEY_ENTER;
1897 //NO_UI!!! ui_gadget_calc_keys(NameWindow);
1899 //NO_UI!!! while (!QuitButton->pressed && last_keypress!=KEY_ENTER) {
1900 //NO_UI!!! ui_mega_process();
1901 //NO_UI!!! ui_window_do_gadgets(NameWindow);
1904 //NO_UI!!! strcpy( Current_level_name, NameText->text );
1906 //NO_UI!!! if ( NameWindow!=NULL ) {
1907 //NO_UI!!! ui_close_window( NameWindow );
1908 //NO_UI!!! NameWindow = NULL;
1914 m[0].type = NM_TYPE_TEXT; m[0].text = "Please enter a name for this mine:";
1915 m[1].type = NM_TYPE_INPUT; m[1].text = Current_level_name; m[1].text_len = LEVEL_NAME_LEN;
1917 newmenu_do( NULL, "Enter mine name", 2, m, NULL );
1927 // -----------------------------------------------------------------------------
1928 int compute_num_delta_light_records(void)
1933 for (i=0; i<Num_static_lights; i++) {
1934 total += Dl_indices[i].count;
1941 // -----------------------------------------------------------------------------
1943 int save_game_data(FILE * SaveFile)
1945 int player_offset, object_offset, walls_offset, doors_offset, triggers_offset, control_offset, matcen_offset; //, links_offset;
1946 int dl_indices_offset, delta_light_offset;
1947 int start_offset,end_offset;
1949 start_offset = ftell(SaveFile);
1951 //===================== SAVE FILE INFO ========================
1953 game_fileinfo.fileinfo_signature = 0x6705;
1954 game_fileinfo.fileinfo_version = GAME_VERSION;
1955 game_fileinfo.level = Current_level_num;
1956 game_fileinfo.fileinfo_sizeof = sizeof(game_fileinfo);
1957 game_fileinfo.player_offset = -1;
1958 game_fileinfo.player_sizeof = sizeof(player);
1959 game_fileinfo.object_offset = -1;
1960 game_fileinfo.object_howmany = Highest_object_index+1;
1961 game_fileinfo.object_sizeof = sizeof(object);
1962 game_fileinfo.walls_offset = -1;
1963 game_fileinfo.walls_howmany = Num_walls;
1964 game_fileinfo.walls_sizeof = sizeof(wall);
1965 game_fileinfo.doors_offset = -1;
1966 game_fileinfo.doors_howmany = Num_open_doors;
1967 game_fileinfo.doors_sizeof = sizeof(active_door);
1968 game_fileinfo.triggers_offset = -1;
1969 game_fileinfo.triggers_howmany = Num_triggers;
1970 game_fileinfo.triggers_sizeof = sizeof(trigger);
1971 game_fileinfo.control_offset = -1;
1972 game_fileinfo.control_howmany = 1;
1973 game_fileinfo.control_sizeof = sizeof(control_center_triggers);
1974 game_fileinfo.matcen_offset = -1;
1975 game_fileinfo.matcen_howmany = Num_robot_centers;
1976 game_fileinfo.matcen_sizeof = sizeof(matcen_info);
1978 game_fileinfo.dl_indices_offset = -1;
1979 game_fileinfo.dl_indices_howmany = Num_static_lights;
1980 game_fileinfo.dl_indices_sizeof = sizeof(dl_index);
1982 game_fileinfo.delta_light_offset = -1;
1983 game_fileinfo.delta_light_howmany = compute_num_delta_light_records();
1984 game_fileinfo.delta_light_sizeof = sizeof(delta_light);
1986 // Write the fileinfo
1987 fwrite( &game_fileinfo, sizeof(game_fileinfo), 1, SaveFile );
1989 // Write the mine name
1990 fprintf(SaveFile,"%s\n",Current_level_name);
1992 fwrite(&N_polygon_models,2,1,SaveFile);
1993 fwrite(Pof_names,N_polygon_models,sizeof(*Pof_names),SaveFile);
1995 //==================== SAVE PLAYER INFO ===========================
1997 player_offset = ftell(SaveFile);
1998 fwrite( &Players[Player_num], sizeof(player), 1, SaveFile );
2000 //==================== SAVE OBJECT INFO ===========================
2002 object_offset = ftell(SaveFile);
2003 //fwrite( &Objects, sizeof(object), game_fileinfo.object_howmany, SaveFile );
2006 for (i=0;i<game_fileinfo.object_howmany;i++)
2007 write_object(&Objects[i],SaveFile);
2010 //==================== SAVE WALL INFO =============================
2012 walls_offset = ftell(SaveFile);
2013 fwrite( Walls, sizeof(wall), game_fileinfo.walls_howmany, SaveFile );
2015 //==================== SAVE DOOR INFO =============================
2017 doors_offset = ftell(SaveFile);
2018 fwrite( ActiveDoors, sizeof(active_door), game_fileinfo.doors_howmany, SaveFile );
2020 //==================== SAVE TRIGGER INFO =============================
2022 triggers_offset = ftell(SaveFile);
2023 fwrite( Triggers, sizeof(trigger), game_fileinfo.triggers_howmany, SaveFile );
2025 //================ SAVE CONTROL CENTER TRIGGER INFO ===============
2027 control_offset = ftell(SaveFile);
2028 fwrite( &ControlCenterTriggers, sizeof(control_center_triggers), 1, SaveFile );
2031 //================ SAVE MATERIALIZATION CENTER TRIGGER INFO ===============
2033 matcen_offset = ftell(SaveFile);
2034 // mprintf((0, "Writing %i materialization centers\n", game_fileinfo.matcen_howmany));
2036 // for (i=0; i<game_fileinfo.matcen_howmany; i++)
2037 // mprintf((0, " %i: robot_flags = %08x\n", i, RobotCenters[i].robot_flags));
2039 fwrite( RobotCenters, sizeof(matcen_info), game_fileinfo.matcen_howmany, SaveFile );
2041 //================ SAVE DELTA LIGHT INFO ===============
2042 dl_indices_offset = ftell(SaveFile);
2043 fwrite( Dl_indices, sizeof(dl_index), game_fileinfo.dl_indices_howmany, SaveFile );
2045 delta_light_offset = ftell(SaveFile);
2046 fwrite( Delta_lights, sizeof(delta_light), game_fileinfo.delta_light_howmany, SaveFile );
2048 //============= REWRITE FILE INFO, TO SAVE OFFSETS ===============
2050 // Update the offset fields
2051 game_fileinfo.player_offset = player_offset;
2052 game_fileinfo.object_offset = object_offset;
2053 game_fileinfo.walls_offset = walls_offset;
2054 game_fileinfo.doors_offset = doors_offset;
2055 game_fileinfo.triggers_offset = triggers_offset;
2056 game_fileinfo.control_offset = control_offset;
2057 game_fileinfo.matcen_offset = matcen_offset;
2058 game_fileinfo.dl_indices_offset = dl_indices_offset;
2059 game_fileinfo.delta_light_offset = delta_light_offset;
2062 end_offset = ftell(SaveFile);
2064 // Write the fileinfo
2065 fseek( SaveFile, start_offset, SEEK_SET ); // Move to TOF
2066 fwrite( &game_fileinfo, sizeof(game_fileinfo), 1, SaveFile );
2068 // Go back to end of data
2069 fseek(SaveFile,end_offset,SEEK_SET);
2074 int save_mine_data(FILE * SaveFile);
2076 // -----------------------------------------------------------------------------
2078 int save_level_sub(char * filename, int compiled_version)
2081 char temp_filename[128];
2082 int sig = MAKE_SIG('P','L','V','L'),version=LEVEL_FILE_VERSION;
2083 int minedata_offset=0,gamedata_offset=0;
2085 if ( !compiled_version ) {
2086 write_game_text_file(filename);
2088 if (Errors_in_mine) {
2089 if (is_real_level(filename)) {
2090 char ErrorMessage[200];
2092 sprintf( ErrorMessage, "Warning: %i errors in this mine!\n", Errors_in_mine );
2094 gr_palette_load(gr_palette);
2096 if (nm_messagebox( NULL, 2, "Cancel Save", "Save", ErrorMessage )!=1) {
2102 mprintf((1, "Error: %i errors in this mine. See the 'txm' file.\n", Errors_in_mine));
2104 change_filename_extension(temp_filename,filename,".LVL");
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");
2112 change_filename_extension(temp_filename,filename,".RL2");
2116 SaveFile = fopen( temp_filename, "wb" );
2119 char ErrorMessage[256];
2122 _splitpath( temp_filename, NULL, NULL, fname, NULL );
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 );
2128 gr_palette_load(gr_palette);
2129 nm_messagebox( NULL, 1, "Ok", ErrorMessage );
2134 if (Current_level_name[0] == 0)
2135 strcpy(Current_level_name,"Untitled");
2137 clear_transient_objects(1); //1 means clear proximity bombs
2139 compress_objects(); //after this, Highest_object_index == num objects
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]));
2152 gs_write_int(sig,SaveFile);
2153 gs_write_int(version,SaveFile);
2156 gs_write_int(minedata_offset,SaveFile);
2157 gs_write_int(gamedata_offset,SaveFile);
2159 //Now write the damn data
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);
2166 // Write the palette file name
2167 fprintf(SaveFile,"%s\n",Current_level_palette);
2169 gs_write_int(Base_control_center_explosion_time,SaveFile);
2170 gs_write_int(Reactor_strength,SaveFile);
2172 gs_write_int(Num_flickering_lights,SaveFile);
2173 fwrite(Flickering_lights,sizeof(*Flickering_lights),Num_flickering_lights,SaveFile);
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);
2186 minedata_offset = ftell(SaveFile);
2187 if ( !compiled_version )
2188 save_mine_data(SaveFile);
2190 save_mine_data_compiled(SaveFile);
2191 gamedata_offset = ftell(SaveFile);
2192 save_game_data(SaveFile);
2194 fseek(SaveFile,sizeof(sig)+sizeof(version),SEEK_SET);
2195 gs_write_int(minedata_offset,SaveFile);
2196 gs_write_int(gamedata_offset,SaveFile);
2198 //==================== CLOSE THE FILE =============================
2201 if ( !compiled_version ) {
2202 if (Function_mode == FMODE_EDITOR)
2203 editor_status("Saved mine %s, \"%s\"",filename,Current_level_name);
2210 #if 0 //dunno - 3rd party stuff?
2211 extern void compress_uv_coordinates_all(void);
2214 int save_level(char * filename)
2218 // Save normal version...
2219 r1 = save_level_sub(filename, 0);
2221 // Save compiled version...
2222 save_level_sub(filename, 1);
2230 void dump_mine_info(void)
2232 int segnum, sidenum;
2233 fix min_u, max_u, min_v, max_v, min_l, max_l, max_sl;
2245 for (segnum=0; segnum<=Highest_segment_index; segnum++) {
2246 for (sidenum=0; sidenum<MAX_SIDES_PER_SEGMENT; sidenum++) {
2248 side *sidep = &Segments[segnum].sides[sidenum];
2250 if (Segment2s[segnum].static_light > max_sl)
2251 max_sl = Segment2s[segnum].static_light;
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;
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;
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;
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));
2283 //read in every level in mission and save out compiled version
2284 void save_all_compiled_levels(void)
2286 do_load_save_levels(1);
2289 //read in every level in mission
2290 void load_all_levels(void)
2292 do_load_save_levels(0);
2296 void do_load_save_levels(int save)
2300 if (! SafetyCheck())
2303 no_old_level_file_error=1;
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
2309 save_level_sub(Level_names[level_num-1],1);
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
2316 save_level_sub(Secret_level_names[-level_num-1],1);
2319 no_old_level_file_error=0;