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