]> icculus.org git repositories - btb/d2x.git/blob - main/editor/mine.c
remove rcs tags
[btb/d2x.git] / main / editor / mine.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-1998 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
12 */
13
14 /*
15  *
16  * Mine specific editing functions, such as load_mine, save_mine
17  *
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #include "conf.h"
22 #endif
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <math.h>
27 #include <string.h>
28
29 #include "physfsx.h"
30 #include "nocfile.h"
31 #include "mono.h"
32 #include "key.h"
33 #include "gr.h"
34
35 #include "bm.h"                 // for MAX_TEXTURES
36
37 #include "inferno.h"
38 #include "segment.h"
39 #include "editor.h"
40 #include "error.h"
41 #include "textures.h"
42 #include "object.h"
43
44 #include "gamemine.h"
45 #include "gamesave.h"
46 #include "gameseg.h"
47
48 #include "ui.h"                 // Because texpage.h need UI_WINDOW type
49 #include "texpage.h"            // For texpage_goto_first
50                          
51 #include "medwall.h"
52 #include "switch.h"
53
54 #include "fuelcen.h"
55
56 #define REMOVE_EXT(s)  (*(strchr( (s), '.' ))='\0')
57
58 int CreateDefaultNewSegment();
59 int save_mine_data(CFILE * SaveFile);
60
61 static char      current_tmap_list[MAX_TEXTURES][13];
62
63 int     New_file_format_save = 1;
64
65 // Converts descent 2 texture numbers back to descent 1 texture numbers.
66 // Only works properly when the full Descent 1 texture set (descent.pig) is available.
67 short convert_to_d1_tmap_num(short tmap_num)
68 {
69         switch (tmap_num)
70         {
71                 case 137: return   0; // grey rock001
72                 case   0: return   1;
73                 case   1: return   3; // rock021
74                 case 270: return   6; // blue rock002
75                 case 271: return   7; // yellow rock265
76                 case   2: return   8; // rock004
77                 case 138: return   9; // purple (devil:179)
78                 case 272: return  10; // red rock006
79                 case 139: return  11;
80                 case 140: return  12; //devil:43
81                 case   3: return  13; // rock014
82                 case   4: return  14; // rock019
83                 case   5: return  15; // rock020
84                 case   6: return  16;
85                 case 141: return  17;
86                 case 129: return  18;
87                 case   7: return  19;
88                 case 142: return  20;
89                 case 143: return  21;
90                 case   8: return  22;
91                 case   9: return  23;
92                 case  10: return  24;
93                 case 144: return  25; //devil:35
94                 case  11: return  26;
95                 case  12: return  27;
96                 case 145: return  28; //devil:43
97                 //range handled by default case, returns 13..21 (- 16)
98                 case 163: return  38; //devil:27
99                 case 147: return  39; //31
100                 case  22: return  40;
101                 case 266: return  41;
102                 case  23: return  42;
103                 case  24: return  43;
104                 case 136: return  44; //devil:135
105                 case  25: return  45;
106                 case  26: return  46;
107                 case  27: return  47;
108                 case  28: return  48;
109                 case 146: return  49; //devil:60
110                 case 131: return  50; //devil:138
111                 case  29: return  51;
112                 case  30: return  52;
113                 case  31: return  53;
114                 case  32: return  54;
115                 case 165: return  55; //devil:193
116                 case  33: return  56;
117                 case 132: return  57; //devil:119
118                 // range handled by default case, returns 58..88 (+ 24)
119                 case 197: return  88; //devil:15
120                 // range handled by default case, returns 89..106 (- 25)
121                 case 167: return 132;
122                 // range handled by default case, returns 107..114 (- 26)
123                 case 148: return 141; //devil:106
124                 case 115: return 142;
125                 case 116: return 143;
126                 case 117: return 144;
127                 case 118: return 145;
128                 case 119: return 146;
129                 case 149: return 147;
130                 case 120: return 148;
131                 case 121: return 149;
132                 case 122: return 150;
133                 case 123: return 151;
134                 case 124: return 152;
135                 case 125: return 153; // rock263
136                 case 150: return 154;
137                 case 126: return 155; // rock269
138                 case 200: return 156; // metl002
139                 case 201: return 157; // metl003
140                 case 186: return 158; //devil:227
141                 case 190: return 159; //devil:246
142                 case 151: return 160;
143                 case 152: return 161; //devil:206
144                 case 202: return 162;
145                 case 203: return 163;
146                 case 204: return 164;
147                 case 205: return 165;
148                 case 206: return 166;
149                 case 153: return 167;
150                 case 154: return 168;
151                 case 155: return 169;
152                 case 156: return 170;//206;
153                 case 157: return 171;//227;
154                 case 207: return 172;
155                 case 208: return 173;
156                 case 158: return 174;
157                 case 159: return 175;
158                 // range handled by default case, returns 209..217 (+ 33)
159                 case 160: return 185;
160                 // range handled by default case, returns 218..224 (+ 32)
161                 case 161: return 193;
162                 case 162: return 194;//206;
163                 case 166: return 195;
164                 case 225: return 196;
165                 case 226: return 197;
166                 case 193: return 198;
167                 case 168: return 199; //devil:204
168                 case 169: return 200; //devil:204
169                 case 227: return 201;
170                 case 170: return 202; //devil:227
171                 // range handled by default case, returns 228..234 (+ 25)
172                 case 171: return 210; //devil:242
173                 case 172: return 211; //devil:240
174                 // range handled by default case, returns 235..242 (+ 23)
175                 case 173: return 220; //devil:240
176                 case 243: return 221;
177                 case 244: return 222;
178                 case 174: return 223;
179                 case 245: return 224;
180                 case 246: return 225;
181                 case 164: return 226;//247; matching names but not matching textures
182                 case 179: return 227; //devil:181
183                 case 196: return 228;//248; matching names but not matching textures
184                 case 175: return 229; //devil:66
185                 case 176: return 230; //devil:66
186                 // range handled by default case, returns 249..257 (+ 18)
187                 case 177: return 240; //devil:132
188                 case 130: return 241; //devil:131
189                 case 178: return 242; //devil:15
190                 case 180: return 243; //devil:38
191                 case 258: return 244;
192                 case 259: return 245;
193                 case 181: return 246; // grate metl127
194                 case 260: return 247;
195                 case 261: return 248;
196                 case 262: return 249;
197                 case 340: return 250; //  white doorframe metl126
198                 case 412: return 251; //    red doorframe metl133
199                 case 410: return 252; //   blue doorframe metl134
200                 case 411: return 253; // yellow doorframe metl135
201                 case 263: return 254; // metl136
202                 case 264: return 255; // metl139
203                 case 265: return 256; // metl140
204                 case 182: return 257;//246; brig001
205                 case 183: return 258;//246; brig002
206                 case 184: return 259;//246; brig003
207                 case 185: return 260;//246; brig004
208                 case 273: return 261; // exit01
209                 case 274: return 262; // exit02
210                 case 187: return 263; // ceil001
211                 case 275: return 264; // ceil002
212                 case 276: return 265; // ceil003
213                 case 188: return 266; //devil:291
214                 // range handled by default case, returns 277..291 (+ 10)
215                 case 293: return 282;
216                 case 189: return 283;
217                 case 295: return 284;
218                 case 296: return 285;
219                 case 298: return 286;
220                 // range handled by default case, returns 300..310 (+ 13)
221                 case 191: return 298; // devil:374 misc010
222                 // range handled by default case, returns 311..326 (+ 12)
223                 case 192: return 315; // bad producer misc044
224                 // range handled by default case,  returns  327..337 (+ 11)
225                 case 352: return 327; // arw01
226                 case 353: return 328; // misc17
227                 case 354: return 329; // fan01
228                 case 380: return 330; // mntr04
229                 case 379: return 331;//373; matching names but not matching textures
230                 case 355: return 332;//344; matching names but not matching textures
231                 case 409: return 333; // lava misc11 //devil:404
232                 case 356: return 334; // ctrl04
233                 case 357: return 335; // ctrl01
234                 case 358: return 336; // ctrl02
235                 case 359: return 337; // ctrl03
236                 case 360: return 338; // misc14
237                 case 361: return 339; // producer misc16
238                 case 362: return 340; // misc049
239                 case 364: return 341; // misc060
240                 case 363: return 342; // blown01
241                 case 366: return 343; // misc061
242                 case 365: return 344;
243                 case 368: return 345;
244                 case 376: return 346;
245                 case 370: return 347;
246                 case 367: return 348;
247                 case 372: return 349;
248                 case 369: return 350;
249                 case 374: return 351;//429; matching names but not matching textures
250                 case 375: return 352;//387; matching names but not matching textures
251                 case 371: return 353;
252                 case 377: return 354;//425; matching names but not matching textures
253                 case 408: return 355;
254                 case 378: return 356; // lava02
255                 case 383: return 357;//384; matching names but not matching textures
256                 case 384: return 358;//385; matching names but not matching textures
257                 case 385: return 359;//386; matching names but not matching textures
258                 case 386: return 360;
259                 case 387: return 361;
260                 case 194: return 362; // mntr04b (devil: -1)
261                 case 388: return 363;
262                 case 391: return 364;
263                 case 392: return 365;
264                 case 393: return 366;
265                 case 394: return 367;
266                 case 395: return 368;
267                 case 396: return 369;
268                 case 195: return 370; // mntr04d (devil: -1)
269                 // range 371..584 handled by default case (wall01 and door frames)
270                 default:
271                         // ranges:
272                         if (tmap_num >= 13 && tmap_num <= 21)
273                                 return tmap_num + 16;
274                         if (tmap_num >= 34 && tmap_num <= 63)
275                                 return tmap_num + 24;
276                         if (tmap_num >= 64 && tmap_num <= 106)
277                                 return tmap_num + 25;
278                         if (tmap_num >= 107 && tmap_num <= 114)
279                                 return tmap_num + 26;
280                         if (tmap_num >= 209 && tmap_num <= 217)
281                                 return tmap_num - 33;
282                         if (tmap_num >= 218 && tmap_num <= 224)
283                                 return tmap_num - 32;
284                         if (tmap_num >= 228 && tmap_num <= 234)
285                                 return tmap_num - 25;
286                         if (tmap_num >= 235 && tmap_num <= 242)
287                                 return tmap_num - 23;
288                         if (tmap_num >= 249 && tmap_num <= 257)
289                                 return tmap_num - 18;
290                         if (tmap_num >= 277 && tmap_num <= 291)
291                                 return tmap_num - 10;
292                         if (tmap_num >= 300 && tmap_num <= 310)
293                                 return tmap_num - 13;
294                         if (tmap_num >= 311 && tmap_num <= 326)
295                                 return tmap_num - 12;
296                         if (tmap_num >= 327 && tmap_num <= 337)
297                                 return tmap_num - 11; // matching names but not matching textures
298                         // wall01 and door frames:
299                         if (tmap_num > 434 && tmap_num < 731)
300                         {
301                                 if (New_file_format_save) return tmap_num - 64;
302                                 // d1 shareware needs special treatment:
303                                 if (tmap_num < 478) return tmap_num - 68;
304                                 if (tmap_num < 490) return tmap_num - 73;
305                                 if (tmap_num < 537) return tmap_num - 91;
306                                 if (tmap_num < 557) return tmap_num - 104;
307                                 if (tmap_num < 573) return tmap_num - 111;
308                                 if (tmap_num < 603) return tmap_num - 117;
309                                 if (tmap_num < 635) return tmap_num - 141;
310                                 if (tmap_num < 731) return tmap_num - 147;
311                         }
312                         { // handle rare case where orientation != 0
313                                 short tmap_num_part = tmap_num &  TMAP_NUM_MASK;
314                                 short orient = tmap_num & ~TMAP_NUM_MASK;
315                                 if (orient != 0)
316                                         return orient | convert_to_d1_tmap_num(tmap_num_part);
317                                 else
318                                 {
319                                         Warning("can't convert unknown texture #%d to descent 1.\n", tmap_num_part);
320                                         return tmap_num;
321                                 }
322                         }
323         }
324 }
325
326 // -----------------------------------------------------------------------------
327 // Save mine will:
328 // 1. Write file info, header info, editor info, vertex data, segment data,
329 //    and new_segment in that order, marking their file offset.
330 // 2. Go through all the fields and fill in the offset, size, and sizeof
331 //    values in the headers.
332
333 int med_save_mine(char * filename)
334 {
335         FILE * SaveFile;
336         char ErrorMessage[256];
337
338         SaveFile = cfopen( filename, CF_WRITE_MODE );
339         if (!SaveFile)
340         {
341 #if 0 //ndef __linux__
342                 char fname[20];
343                 _splitpath( filename, NULL, NULL, fname, NULL );
344
345                 sprintf( ErrorMessage, \
346                         "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" 
347                         , filename, fname);
348 #endif
349                 sprintf( ErrorMessage, "ERROR: Unable to open %s\n", filename );
350                 MessageBox( -2, -2, 1, ErrorMessage, "Ok" );
351                 return 1;
352         }
353
354         save_mine_data(SaveFile);
355         
356         //==================== CLOSE THE FILE =============================
357         cfclose(SaveFile);
358
359         return 0;
360
361 }
362
363 // -----------------------------------------------------------------------------
364 // saves to an already-open file
365 int save_mine_data(CFILE * SaveFile)
366 {
367         int  header_offset, editor_offset, vertex_offset, segment_offset, doors_offset, texture_offset, walls_offset, triggers_offset; //, links_offset;
368         int  newseg_verts_offset;
369         int  newsegment_offset;
370         int  i;
371
372         med_compress_mine();
373         warn_if_concave_segments();
374         
375         for (i=0;i<NumTextures;i++)
376                 strncpy(current_tmap_list[i], TmapInfo[i].filename, 13);
377
378         //=================== Calculate offsets into file ==================
379
380         header_offset = cftell(SaveFile) + sizeof(mine_fileinfo);
381         editor_offset = header_offset + sizeof(mine_header);
382         texture_offset = editor_offset + sizeof(mine_editor);
383         vertex_offset  = texture_offset + (13*NumTextures);
384         segment_offset = vertex_offset + (sizeof(vms_vector)*Num_vertices);
385         newsegment_offset = segment_offset + (sizeof(segment)*Num_segments);
386         newseg_verts_offset = newsegment_offset + sizeof(segment);
387         walls_offset = newseg_verts_offset + (sizeof(vms_vector)*8);
388         triggers_offset =       walls_offset + (sizeof(wall)*Num_walls);
389         doors_offset = triggers_offset + (sizeof(trigger)*Num_triggers);
390
391         //===================== SAVE FILE INFO ========================
392
393         mine_fileinfo.fileinfo_signature=       0x2884;
394         mine_fileinfo.fileinfo_version  =   MINE_VERSION;
395         mine_fileinfo.fileinfo_sizeof   =   sizeof(mine_fileinfo);
396         mine_fileinfo.header_offset     =   header_offset;
397         mine_fileinfo.header_size       =   sizeof(mine_header);
398         mine_fileinfo.editor_offset     =   editor_offset;
399         mine_fileinfo.editor_size       =   sizeof(mine_editor);
400         mine_fileinfo.vertex_offset     =   vertex_offset;
401         mine_fileinfo.vertex_howmany    =   Num_vertices;
402         mine_fileinfo.vertex_sizeof     =   sizeof(vms_vector);
403         mine_fileinfo.segment_offset    =   segment_offset;
404         mine_fileinfo.segment_howmany   =   Num_segments;
405         mine_fileinfo.segment_sizeof    =   sizeof(segment);
406         mine_fileinfo.newseg_verts_offset     =   newseg_verts_offset;
407         mine_fileinfo.newseg_verts_howmany    =   8;
408         mine_fileinfo.newseg_verts_sizeof     =   sizeof(vms_vector);
409         mine_fileinfo.texture_offset    =   texture_offset;
410         mine_fileinfo.texture_howmany   =   NumTextures;
411         mine_fileinfo.texture_sizeof    =   13;  // num characters in a name
412         mine_fileinfo.walls_offset                =     walls_offset;
413         mine_fileinfo.walls_howmany       =     Num_walls;
414         mine_fileinfo.walls_sizeof                =     sizeof(wall);  
415         mine_fileinfo.triggers_offset     =     triggers_offset;
416         mine_fileinfo.triggers_howmany  =       Num_triggers;
417         mine_fileinfo.triggers_sizeof     =     sizeof(trigger);  
418
419         // Write the fileinfo
420         cfwrite( &mine_fileinfo, sizeof(mine_fileinfo), 1, SaveFile );
421
422         //===================== SAVE HEADER INFO ========================
423
424         mine_header.num_vertices        =   Num_vertices;
425         mine_header.num_segments        =   Num_segments;
426
427         // Write the editor info
428         if (header_offset != cftell(SaveFile))
429                 Error( "OFFSETS WRONG IN MINE.C!" );
430
431         cfwrite( &mine_header, sizeof(mine_header), 1, SaveFile );
432
433         //===================== SAVE EDITOR INFO ==========================
434         mine_editor.current_seg         =   SEGMENT_NUMBER(Cursegp);
435         mine_editor.newsegment_offset   =   newsegment_offset; 
436         mine_editor.newsegment_size     =   sizeof(segment);
437
438         // Next 3 vars added 10/07 by JAS
439         mine_editor.Curside             =   Curside;
440         if (Markedsegp)
441                 mine_editor.Markedsegp      =   SEGMENT_NUMBER(Markedsegp);
442         else                                                                      
443                 mine_editor.Markedsegp       =   -1;
444         mine_editor.Markedside          =   Markedside;
445         for (i=0;i<10;i++)
446                 mine_editor.Groupsegp[i]    =   SEGMENT_NUMBER(Groupsegp[i]);
447         for (i=0;i<10;i++)
448                 mine_editor.Groupside[i]     =  Groupside[i];
449
450         if (editor_offset != cftell(SaveFile))
451                 Error( "OFFSETS WRONG IN MINE.C!" );
452         cfwrite( &mine_editor, sizeof(mine_editor), 1, SaveFile );
453
454         //===================== SAVE TEXTURE INFO ==========================
455
456         if (texture_offset != cftell(SaveFile))
457                 Error( "OFFSETS WRONG IN MINE.C!" );
458         cfwrite( current_tmap_list, 13, NumTextures, SaveFile );
459         
460         //===================== SAVE VERTEX INFO ==========================
461
462         if (vertex_offset != cftell(SaveFile))
463                 Error( "OFFSETS WRONG IN MINE.C!" );
464         cfwrite( Vertices, sizeof(vms_vector), Num_vertices, SaveFile );
465
466         //===================== SAVE SEGMENT INFO =========================
467
468         if (segment_offset != cftell(SaveFile))
469                 Error( "OFFSETS WRONG IN MINE.C!" );
470         cfwrite( Segments, sizeof(segment), Num_segments, SaveFile );
471
472         //===================== SAVE NEWSEGMENT INFO ======================
473
474         if (newsegment_offset != cftell(SaveFile))
475                 Error( "OFFSETS WRONG IN MINE.C!" );
476         cfwrite( &New_segment, sizeof(segment), 1, SaveFile );
477
478         if (newseg_verts_offset != cftell(SaveFile))
479                 Error( "OFFSETS WRONG IN MINE.C!" );
480         cfwrite( &Vertices[New_segment.verts[0]], sizeof(vms_vector), 8, SaveFile );
481
482         //==================== CLOSE THE FILE =============================
483
484         return 0;
485
486 }
487
488
489
490 #define COMPILED_MINE_VERSION 0
491
492 void dump_fix_as_short( fix value, int nbits, PHYSFS_file *SaveFile )
493 {
494         int int_value=0; 
495         short short_value;
496
497         int_value = (int)(value>>nbits);
498         if( int_value > 0x7fff ) {
499                 short_value = 0x7fff;
500                 mprintf((1, "Warning: Fix (%8x) won't fit in short.  Saturating to %8x.\n", int_value, short_value<<nbits));
501         }
502         else if( int_value < -0x7fff ) {
503                 short_value = -0x7fff;
504                 mprintf((1, "Warning: Fix (%8x) won't fit in short.  Saturating to %8x.\n", int_value, short_value<<nbits));
505         }
506         else
507                 short_value = (short)int_value;
508
509         PHYSFS_writeSLE16(SaveFile, short_value);
510 }
511
512 //version of dump for unsigned values
513 void dump_fix_as_ushort( fix value, int nbits, PHYSFS_file *SaveFile )
514 {
515         uint int_value=0;
516         ushort short_value;
517
518         if (value < 0) {
519                 mprintf((1, "Warning: fix (%8x) is signed...setting to zero.\n", value));
520                 Int3();         //hey---show this to Matt
521                 value = 0;
522         }
523         else
524                 int_value = value >> nbits;
525
526         if( int_value > 0xffff ) {
527                 short_value = 0xffff;
528                 mprintf((1, "Warning: Fix (%8x) won't fit in unsigned short.  Saturating to %8x.\n", int_value, short_value<<nbits));
529         }
530         else
531                 short_value = int_value;
532
533         PHYSFS_writeULE16(SaveFile, short_value);
534 }
535
536 void write_children(segment *seg, ubyte bit_mask, PHYSFS_file *SaveFile)
537 {
538         int bit;
539
540         for (bit = 0; bit < MAX_SIDES_PER_SEGMENT; bit++)
541         {
542                 if (bit_mask & (1 << bit))
543                         PHYSFS_writeSLE16(SaveFile, seg->children[bit]);
544         }
545 }
546
547 void write_verts(segment *seg, PHYSFS_file *SaveFile)
548 {
549         int i;
550
551         for (i = 0; i < MAX_VERTICES_PER_SEGMENT; i++)
552                 PHYSFS_writeSLE16(SaveFile, seg->verts[i]);
553 }
554
555 void write_special(segment2 *seg2, ubyte bit_mask, PHYSFS_file *SaveFile)
556 {
557         if (bit_mask & (1 << MAX_SIDES_PER_SEGMENT))
558         {
559                 PHYSFSX_writeU8(SaveFile, seg2->special);
560                 PHYSFSX_writeU8(SaveFile, seg2->matcen_num);
561                 PHYSFS_writeSLE16(SaveFile, seg2->value);
562         }
563 }
564 // -----------------------------------------------------------------------------
565 // saves compiled mine data to an already-open file...
566 int save_mine_data_compiled(PHYSFS_file *SaveFile)
567 {
568         short           i, segnum, sidenum;
569         ubyte   version = COMPILED_MINE_VERSION;
570         ubyte           bit_mask = 0;
571
572         med_compress_mine();
573         warn_if_concave_segments();
574
575         if (Highest_segment_index >= MAX_SEGMENTS) {
576                 char    message[128];
577                 sprintf(message, "Error: Too many segments (%i > %i) for game (not editor)", Highest_segment_index+1, MAX_SEGMENTS);
578                 MessageBox( -2, -2, 1, message, "Ok" );
579         }
580
581         if (Highest_vertex_index >= MAX_VERTICES) {
582                 char    message[128];
583                 sprintf(message, "Error: Too many vertices (%i > %i) for game (not editor)", Highest_vertex_index+1, MAX_VERTICES);
584                 MessageBox( -2, -2, 1, message, "Ok" );
585         }
586
587         //=============================== Writing part ==============================
588         PHYSFSX_writeU8(SaveFile, version);                                             // 1 byte = compiled version
589         if (New_file_format_save)
590         {
591                 PHYSFS_writeSLE16(SaveFile, Num_vertices);                                      // 2 bytes = Num_vertices
592                 PHYSFS_writeSLE16(SaveFile, Num_segments);                                      // 2 bytes = Num_segments
593         }
594         else
595         {
596                 PHYSFS_writeSLE32(SaveFile, Num_vertices);                                      // 4 bytes = Num_vertices
597                 PHYSFS_writeSLE32(SaveFile, Num_segments);                                      // 4 bytes = Num_segments
598         }
599
600         for (i = 0; i < Num_vertices; i++)
601                 PHYSFSX_writeVector(SaveFile, &(Vertices[i]));
602         
603         for (segnum = 0; segnum < Num_segments; segnum++)
604         {
605                 segment *seg = &Segments[segnum];
606                 segment2 *seg2 = &Segment2s[segnum];
607
608                 for (sidenum = 0; sidenum < MAX_SIDES_PER_SEGMENT; sidenum++)
609                 {
610                         if (seg->children[sidenum] != -1)
611                                 bit_mask |= (1 << sidenum);
612                 }
613
614                 if ((seg2->special != 0) || (seg2->matcen_num != 0) || (seg2->value != 0))
615                         bit_mask |= (1 << MAX_SIDES_PER_SEGMENT);
616
617                 if (New_file_format_save)
618                         PHYSFSX_writeU8(SaveFile, bit_mask);
619                 else
620                         bit_mask = 0x7F;
621
622                 if (Gamesave_current_version == 5)      // d2 SHAREWARE level
623                 {
624                         write_special(seg2, bit_mask, SaveFile);
625                         write_verts(seg, SaveFile);
626                         write_children(seg, bit_mask, SaveFile);
627                 }
628                 else
629                 {
630                         write_children(seg, bit_mask, SaveFile);
631                         write_verts(seg, SaveFile);
632                         if (Gamesave_current_version <= 1) // descent 1 level
633                                 write_special(seg2, bit_mask, SaveFile);
634                 }
635
636                 if (Gamesave_current_version <= 5) // descent 1 thru d2 SHAREWARE level
637                         dump_fix_as_ushort(seg2->static_light, 4, SaveFile);
638         
639                 // Write the walls as a 6 byte array
640                 bit_mask = 0;
641                 for (sidenum = 0; sidenum < MAX_SIDES_PER_SEGMENT; sidenum++)
642                 {
643                         uint wallnum;
644
645                         if (seg->sides[sidenum].wall_num >= 0)
646                         {
647                                 bit_mask |= (1 << sidenum);
648                                 wallnum = seg->sides[sidenum].wall_num;
649                                 Assert( wallnum < 255 );                // Get John or Mike.. can only store up to 255 walls!!! 
650                         }
651                 }
652                 if (New_file_format_save)
653                         PHYSFSX_writeU8(SaveFile, bit_mask);
654                 else
655                         bit_mask = 0x3F;
656
657                 for (sidenum = 0; sidenum < MAX_SIDES_PER_SEGMENT; sidenum++)
658                 {
659                         if (bit_mask & (1 << sidenum))
660                                 PHYSFSX_writeU8(SaveFile, seg->sides[sidenum].wall_num);
661                 }
662
663                 for (sidenum = 0; sidenum < MAX_SIDES_PER_SEGMENT; sidenum++)
664                 {
665                         if ((seg->children[sidenum] == -1) || (seg->sides[sidenum].wall_num != -1))
666                         {
667                                 ushort  tmap_num, tmap_num2;
668
669                                 tmap_num = seg->sides[sidenum].tmap_num;
670                                 tmap_num2 = seg->sides[sidenum].tmap_num2;
671
672                                 if (Gamesave_current_version <= 3)      // convert texture numbers back to d1
673                                 {
674                                         tmap_num = convert_to_d1_tmap_num(tmap_num);
675                                         if (tmap_num2)
676                                                 tmap_num2 = convert_to_d1_tmap_num(tmap_num2);
677                                 }
678
679                                 if (tmap_num2 != 0 && New_file_format_save)
680                                         tmap_num |= 0x8000;
681
682                                 PHYSFS_writeSLE16(SaveFile, tmap_num);
683                                 if (tmap_num2 != 0 || !New_file_format_save)
684                                         PHYSFS_writeSLE16(SaveFile, tmap_num2);
685
686                                 for (i = 0; i < 4; i++)
687                                 {
688                                         dump_fix_as_short(seg->sides[sidenum].uvls[i].u, 5, SaveFile);
689                                         dump_fix_as_short(seg->sides[sidenum].uvls[i].v, 5, SaveFile);
690                                         dump_fix_as_ushort(seg->sides[sidenum].uvls[i].l, 1, SaveFile);
691                                 }       
692                         }
693                 }
694
695         }
696
697         if (Gamesave_current_version > 5)
698                 for (i = 0; i < Num_segments; i++)
699                         segment2_write(&Segment2s[i], SaveFile);
700
701         return 0;
702 }
703
704