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.
16 * Mine specific editing functions, such as load_mine, save_mine
37 #include "ui.h" // Because texpage.h need UI_WINDOW type
40 #define REMOVE_EXT(s) (*(strchr( (s), '.' ))='\0')
42 int CreateDefaultNewSegment();
43 int save_mine_data(CFILE * SaveFile);
45 static char current_tmap_list[MAX_TEXTURES][13];
47 int New_file_format_save = 1;
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)
55 case 137: return 0; // grey rock001
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
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
77 case 144: return 25; //devil:35
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
88 case 136: return 44; //devil:135
93 case 146: return 49; //devil:60
94 case 131: return 50; //devil:138
99 case 165: return 55; //devil:193
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)
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)
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;
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;
300 return orient | convert_to_d1_tmap_num(tmap_num_part);
303 Warning("can't convert unknown texture #%d to descent 1.\n", tmap_num_part);
310 // -----------------------------------------------------------------------------
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.
317 int med_save_mine(char * filename)
320 char ErrorMessage[256];
322 SaveFile = cfopen( filename, CF_WRITE_MODE );
325 #if 0 //ndef __linux__
327 _splitpath( filename, NULL, NULL, fname, NULL );
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"
333 sprintf( ErrorMessage, "ERROR: Unable to open %s\n", filename );
334 MessageBox( -2, -2, 1, ErrorMessage, "Ok" );
338 save_mine_data(SaveFile);
340 //==================== CLOSE THE FILE =============================
347 // -----------------------------------------------------------------------------
348 // saves to an already-open file
349 int save_mine_data(CFILE * SaveFile)
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;
357 warn_if_concave_segments();
359 for (i=0;i<NumTextures;i++)
360 strncpy(current_tmap_list[i], TmapInfo[i].filename, 13);
362 //=================== Calculate offsets into file ==================
364 header_offset = 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);
375 //===================== SAVE FILE INFO ========================
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);
403 // Write the fileinfo
404 cfwrite( &mine_fileinfo, sizeof(mine_fileinfo), 1, SaveFile );
406 //===================== SAVE HEADER INFO ========================
408 mine_header.num_vertices = Num_vertices;
409 mine_header.num_segments = Num_segments;
411 // Write the editor info
412 if (header_offset != cftell(SaveFile))
413 Error( "OFFSETS WRONG IN MINE.C!" );
415 cfwrite( &mine_header, sizeof(mine_header), 1, SaveFile );
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);
422 // Next 3 vars added 10/07 by JAS
423 mine_editor.Curside = Curside;
425 mine_editor.Markedsegp = SEGMENT_NUMBER(Markedsegp);
427 mine_editor.Markedsegp = -1;
428 mine_editor.Markedside = Markedside;
430 mine_editor.Groupsegp[i] = SEGMENT_NUMBER(Groupsegp[i]);
432 mine_editor.Groupside[i] = Groupside[i];
434 if (editor_offset != cftell(SaveFile))
435 Error( "OFFSETS WRONG IN MINE.C!" );
436 cfwrite( &mine_editor, sizeof(mine_editor), 1, SaveFile );
438 //===================== SAVE TEXTURE INFO ==========================
440 if (texture_offset != cftell(SaveFile))
441 Error( "OFFSETS WRONG IN MINE.C!" );
442 cfwrite( current_tmap_list, 13, NumTextures, SaveFile );
444 //===================== SAVE VERTEX INFO ==========================
446 if (vertex_offset != cftell(SaveFile))
447 Error( "OFFSETS WRONG IN MINE.C!" );
448 cfwrite( Vertices, sizeof(vms_vector), Num_vertices, SaveFile );
450 //===================== SAVE SEGMENT INFO =========================
452 if (segment_offset != cftell(SaveFile))
453 Error( "OFFSETS WRONG IN MINE.C!" );
454 cfwrite( Segments, sizeof(segment), Num_segments, SaveFile );
456 //===================== SAVE NEWSEGMENT INFO ======================
458 if (newsegment_offset != cftell(SaveFile))
459 Error( "OFFSETS WRONG IN MINE.C!" );
460 cfwrite( &New_segment, sizeof(segment), 1, SaveFile );
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 );
466 //==================== CLOSE THE FILE =============================
474 #define COMPILED_MINE_VERSION 0
476 void dump_fix_as_short( fix value, int nbits, PHYSFS_file *SaveFile )
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));
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));
491 short_value = (short)int_value;
493 PHYSFS_writeSLE16(SaveFile, short_value);
496 //version of dump for unsigned values
497 void dump_fix_as_ushort( fix value, int nbits, PHYSFS_file *SaveFile )
503 mprintf((1, "Warning: fix (%8x) is signed...setting to zero.\n", value));
504 Int3(); //hey---show this to Matt
508 int_value = value >> nbits;
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));
515 short_value = int_value;
517 PHYSFS_writeULE16(SaveFile, short_value);
520 void write_children(segment *seg, ubyte bit_mask, PHYSFS_file *SaveFile)
524 for (bit = 0; bit < MAX_SIDES_PER_SEGMENT; bit++)
526 if (bit_mask & (1 << bit))
527 PHYSFS_writeSLE16(SaveFile, seg->children[bit]);
531 void write_verts(segment *seg, PHYSFS_file *SaveFile)
535 for (i = 0; i < MAX_VERTICES_PER_SEGMENT; i++)
536 PHYSFS_writeSLE16(SaveFile, seg->verts[i]);
539 void write_special(segment2 *seg2, ubyte bit_mask, PHYSFS_file *SaveFile)
541 if (bit_mask & (1 << MAX_SIDES_PER_SEGMENT))
543 PHYSFSX_writeU8(SaveFile, seg2->special);
544 PHYSFSX_writeU8(SaveFile, seg2->matcen_num);
545 PHYSFS_writeSLE16(SaveFile, seg2->value);
548 // -----------------------------------------------------------------------------
549 // saves compiled mine data to an already-open file...
550 int save_mine_data_compiled(PHYSFS_file *SaveFile)
552 short i, segnum, sidenum;
553 ubyte version = COMPILED_MINE_VERSION;
557 warn_if_concave_segments();
559 if (Highest_segment_index >= MAX_SEGMENTS) {
561 sprintf(message, "Error: Too many segments (%i > %i) for game (not editor)", Highest_segment_index+1, MAX_SEGMENTS);
562 MessageBox( -2, -2, 1, message, "Ok" );
565 if (Highest_vertex_index >= MAX_VERTICES) {
567 sprintf(message, "Error: Too many vertices (%i > %i) for game (not editor)", Highest_vertex_index+1, MAX_VERTICES);
568 MessageBox( -2, -2, 1, message, "Ok" );
571 //=============================== Writing part ==============================
572 PHYSFSX_writeU8(SaveFile, version); // 1 byte = compiled version
573 if (New_file_format_save)
575 PHYSFS_writeSLE16(SaveFile, Num_vertices); // 2 bytes = Num_vertices
576 PHYSFS_writeSLE16(SaveFile, Num_segments); // 2 bytes = Num_segments
580 PHYSFS_writeSLE32(SaveFile, Num_vertices); // 4 bytes = Num_vertices
581 PHYSFS_writeSLE32(SaveFile, Num_segments); // 4 bytes = Num_segments
584 for (i = 0; i < Num_vertices; i++)
585 PHYSFSX_writeVector(SaveFile, &(Vertices[i]));
587 for (segnum = 0; segnum < Num_segments; segnum++)
589 segment *seg = &Segments[segnum];
590 segment2 *seg2 = &Segment2s[segnum];
592 for (sidenum = 0; sidenum < MAX_SIDES_PER_SEGMENT; sidenum++)
594 if (seg->children[sidenum] != -1)
595 bit_mask |= (1 << sidenum);
598 if ((seg2->special != 0) || (seg2->matcen_num != 0) || (seg2->value != 0))
599 bit_mask |= (1 << MAX_SIDES_PER_SEGMENT);
601 if (New_file_format_save)
602 PHYSFSX_writeU8(SaveFile, bit_mask);
606 if (Gamesave_current_version == 5) // d2 SHAREWARE level
608 write_special(seg2, bit_mask, SaveFile);
609 write_verts(seg, SaveFile);
610 write_children(seg, bit_mask, SaveFile);
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);
620 if (Gamesave_current_version <= 5) // descent 1 thru d2 SHAREWARE level
621 dump_fix_as_ushort(seg2->static_light, 4, SaveFile);
623 // Write the walls as a 6 byte array
625 for (sidenum = 0; sidenum < MAX_SIDES_PER_SEGMENT; sidenum++)
629 if (seg->sides[sidenum].wall_num >= 0)
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!!!
636 if (New_file_format_save)
637 PHYSFSX_writeU8(SaveFile, bit_mask);
641 for (sidenum = 0; sidenum < MAX_SIDES_PER_SEGMENT; sidenum++)
643 if (bit_mask & (1 << sidenum))
644 PHYSFSX_writeU8(SaveFile, seg->sides[sidenum].wall_num);
647 for (sidenum = 0; sidenum < MAX_SIDES_PER_SEGMENT; sidenum++)
649 if ((seg->children[sidenum] == -1) || (seg->sides[sidenum].wall_num != -1))
651 ushort tmap_num, tmap_num2;
653 tmap_num = seg->sides[sidenum].tmap_num;
654 tmap_num2 = seg->sides[sidenum].tmap_num2;
656 if (Gamesave_current_version <= 3) // convert texture numbers back to d1
658 tmap_num = convert_to_d1_tmap_num(tmap_num);
660 tmap_num2 = convert_to_d1_tmap_num(tmap_num2);
663 if (tmap_num2 != 0 && New_file_format_save)
666 PHYSFS_writeSLE16(SaveFile, tmap_num);
667 if (tmap_num2 != 0 || !New_file_format_save)
668 PHYSFS_writeSLE16(SaveFile, tmap_num2);
670 for (i = 0; i < 4; i++)
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);
681 if (Gamesave_current_version > 5)
682 for (i = 0; i < Num_segments; i++)
683 segment2_write(&Segment2s[i], SaveFile);