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
35 #include "bm.h" // for MAX_TEXTURES
48 #include "ui.h" // Because texpage.h need UI_WINDOW type
49 #include "texpage.h" // For texpage_goto_first
56 #define REMOVE_EXT(s) (*(strchr( (s), '.' ))='\0')
58 int CreateDefaultNewSegment();
59 int save_mine_data(CFILE * SaveFile);
61 static char current_tmap_list[MAX_TEXTURES][13];
63 int New_file_format_save = 1;
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)
71 case 137: return 0; // grey rock001
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
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
93 case 144: return 25; //devil:35
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
104 case 136: return 44; //devil:135
109 case 146: return 49; //devil:60
110 case 131: return 50; //devil:138
115 case 165: return 55; //devil:193
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)
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)
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;
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;
316 return orient | convert_to_d1_tmap_num(tmap_num_part);
319 Warning("can't convert unknown texture #%d to descent 1.\n", tmap_num_part);
326 // -----------------------------------------------------------------------------
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.
333 int med_save_mine(char * filename)
336 char ErrorMessage[256];
338 SaveFile = cfopen( filename, CF_WRITE_MODE );
341 #if 0 //ndef __linux__
343 _splitpath( filename, NULL, NULL, fname, NULL );
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"
349 sprintf( ErrorMessage, "ERROR: Unable to open %s\n", filename );
350 MessageBox( -2, -2, 1, ErrorMessage, "Ok" );
354 save_mine_data(SaveFile);
356 //==================== CLOSE THE FILE =============================
363 // -----------------------------------------------------------------------------
364 // saves to an already-open file
365 int save_mine_data(CFILE * SaveFile)
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;
373 warn_if_concave_segments();
375 for (i=0;i<NumTextures;i++)
376 strncpy(current_tmap_list[i], TmapInfo[i].filename, 13);
378 //=================== Calculate offsets into file ==================
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);
391 //===================== SAVE FILE INFO ========================
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);
419 // Write the fileinfo
420 cfwrite( &mine_fileinfo, sizeof(mine_fileinfo), 1, SaveFile );
422 //===================== SAVE HEADER INFO ========================
424 mine_header.num_vertices = Num_vertices;
425 mine_header.num_segments = Num_segments;
427 // Write the editor info
428 if (header_offset != cftell(SaveFile))
429 Error( "OFFSETS WRONG IN MINE.C!" );
431 cfwrite( &mine_header, sizeof(mine_header), 1, SaveFile );
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);
438 // Next 3 vars added 10/07 by JAS
439 mine_editor.Curside = Curside;
441 mine_editor.Markedsegp = SEGMENT_NUMBER(Markedsegp);
443 mine_editor.Markedsegp = -1;
444 mine_editor.Markedside = Markedside;
446 mine_editor.Groupsegp[i] = SEGMENT_NUMBER(Groupsegp[i]);
448 mine_editor.Groupside[i] = Groupside[i];
450 if (editor_offset != cftell(SaveFile))
451 Error( "OFFSETS WRONG IN MINE.C!" );
452 cfwrite( &mine_editor, sizeof(mine_editor), 1, SaveFile );
454 //===================== SAVE TEXTURE INFO ==========================
456 if (texture_offset != cftell(SaveFile))
457 Error( "OFFSETS WRONG IN MINE.C!" );
458 cfwrite( current_tmap_list, 13, NumTextures, SaveFile );
460 //===================== SAVE VERTEX INFO ==========================
462 if (vertex_offset != cftell(SaveFile))
463 Error( "OFFSETS WRONG IN MINE.C!" );
464 cfwrite( Vertices, sizeof(vms_vector), Num_vertices, SaveFile );
466 //===================== SAVE SEGMENT INFO =========================
468 if (segment_offset != cftell(SaveFile))
469 Error( "OFFSETS WRONG IN MINE.C!" );
470 cfwrite( Segments, sizeof(segment), Num_segments, SaveFile );
472 //===================== SAVE NEWSEGMENT INFO ======================
474 if (newsegment_offset != cftell(SaveFile))
475 Error( "OFFSETS WRONG IN MINE.C!" );
476 cfwrite( &New_segment, sizeof(segment), 1, SaveFile );
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 );
482 //==================== CLOSE THE FILE =============================
490 #define COMPILED_MINE_VERSION 0
492 void dump_fix_as_short( fix value, int nbits, PHYSFS_file *SaveFile )
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));
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));
507 short_value = (short)int_value;
509 PHYSFS_writeSLE16(SaveFile, short_value);
512 //version of dump for unsigned values
513 void dump_fix_as_ushort( fix value, int nbits, PHYSFS_file *SaveFile )
519 mprintf((1, "Warning: fix (%8x) is signed...setting to zero.\n", value));
520 Int3(); //hey---show this to Matt
524 int_value = value >> nbits;
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));
531 short_value = int_value;
533 PHYSFS_writeULE16(SaveFile, short_value);
536 void write_children(segment *seg, ubyte bit_mask, PHYSFS_file *SaveFile)
540 for (bit = 0; bit < MAX_SIDES_PER_SEGMENT; bit++)
542 if (bit_mask & (1 << bit))
543 PHYSFS_writeSLE16(SaveFile, seg->children[bit]);
547 void write_verts(segment *seg, PHYSFS_file *SaveFile)
551 for (i = 0; i < MAX_VERTICES_PER_SEGMENT; i++)
552 PHYSFS_writeSLE16(SaveFile, seg->verts[i]);
555 void write_special(segment2 *seg2, ubyte bit_mask, PHYSFS_file *SaveFile)
557 if (bit_mask & (1 << MAX_SIDES_PER_SEGMENT))
559 PHYSFSX_writeU8(SaveFile, seg2->special);
560 PHYSFSX_writeU8(SaveFile, seg2->matcen_num);
561 PHYSFS_writeSLE16(SaveFile, seg2->value);
564 // -----------------------------------------------------------------------------
565 // saves compiled mine data to an already-open file...
566 int save_mine_data_compiled(PHYSFS_file *SaveFile)
568 short i, segnum, sidenum;
569 ubyte version = COMPILED_MINE_VERSION;
573 warn_if_concave_segments();
575 if (Highest_segment_index >= MAX_SEGMENTS) {
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" );
581 if (Highest_vertex_index >= MAX_VERTICES) {
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" );
587 //=============================== Writing part ==============================
588 PHYSFSX_writeU8(SaveFile, version); // 1 byte = compiled version
589 if (New_file_format_save)
591 PHYSFS_writeSLE16(SaveFile, Num_vertices); // 2 bytes = Num_vertices
592 PHYSFS_writeSLE16(SaveFile, Num_segments); // 2 bytes = Num_segments
596 PHYSFS_writeSLE32(SaveFile, Num_vertices); // 4 bytes = Num_vertices
597 PHYSFS_writeSLE32(SaveFile, Num_segments); // 4 bytes = Num_segments
600 for (i = 0; i < Num_vertices; i++)
601 PHYSFSX_writeVector(SaveFile, &(Vertices[i]));
603 for (segnum = 0; segnum < Num_segments; segnum++)
605 segment *seg = &Segments[segnum];
606 segment2 *seg2 = &Segment2s[segnum];
608 for (sidenum = 0; sidenum < MAX_SIDES_PER_SEGMENT; sidenum++)
610 if (seg->children[sidenum] != -1)
611 bit_mask |= (1 << sidenum);
614 if ((seg2->special != 0) || (seg2->matcen_num != 0) || (seg2->value != 0))
615 bit_mask |= (1 << MAX_SIDES_PER_SEGMENT);
617 if (New_file_format_save)
618 PHYSFSX_writeU8(SaveFile, bit_mask);
622 if (Gamesave_current_version == 5) // d2 SHAREWARE level
624 write_special(seg2, bit_mask, SaveFile);
625 write_verts(seg, SaveFile);
626 write_children(seg, bit_mask, SaveFile);
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);
636 if (Gamesave_current_version <= 5) // descent 1 thru d2 SHAREWARE level
637 dump_fix_as_ushort(seg2->static_light, 4, SaveFile);
639 // Write the walls as a 6 byte array
641 for (sidenum = 0; sidenum < MAX_SIDES_PER_SEGMENT; sidenum++)
645 if (seg->sides[sidenum].wall_num >= 0)
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!!!
652 if (New_file_format_save)
653 PHYSFSX_writeU8(SaveFile, bit_mask);
657 for (sidenum = 0; sidenum < MAX_SIDES_PER_SEGMENT; sidenum++)
659 if (bit_mask & (1 << sidenum))
660 PHYSFSX_writeU8(SaveFile, seg->sides[sidenum].wall_num);
663 for (sidenum = 0; sidenum < MAX_SIDES_PER_SEGMENT; sidenum++)
665 if ((seg->children[sidenum] == -1) || (seg->sides[sidenum].wall_num != -1))
667 ushort tmap_num, tmap_num2;
669 tmap_num = seg->sides[sidenum].tmap_num;
670 tmap_num2 = seg->sides[sidenum].tmap_num2;
672 if (Gamesave_current_version <= 3) // convert texture numbers back to d1
674 tmap_num = convert_to_d1_tmap_num(tmap_num);
676 tmap_num2 = convert_to_d1_tmap_num(tmap_num2);
679 if (tmap_num2 != 0 && New_file_format_save)
682 PHYSFS_writeSLE16(SaveFile, tmap_num);
683 if (tmap_num2 != 0 || !New_file_format_save)
684 PHYSFS_writeSLE16(SaveFile, tmap_num2);
686 for (i = 0; i < 4; i++)
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);
697 if (Gamesave_current_version > 5)
698 for (i = 0; i < Num_segments; i++)
699 segment2_write(&Segment2s[i], SaveFile);