1 /* $Id: mine.c,v 1.9 2005-06-22 09:42:04 chris Exp $ */
3 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
4 SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO
5 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
6 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
7 IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
8 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
9 FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
10 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS
11 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
12 COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
17 * Mine specific editing functions, such as load_mine, save_mine
22 static char rcsid[] = "$Id: mine.c,v 1.9 2005-06-22 09:42:04 chris Exp $";
40 #include "bm.h" // for MAX_TEXTURES
53 #include "ui.h" // Because texpage.h need UI_WINDOW type
54 #include "texpage.h" // For texpage_goto_first
61 #define REMOVE_EXT(s) (*(strchr( (s), '.' ))='\0')
63 int CreateDefaultNewSegment();
64 int save_mine_data(CFILE * SaveFile);
66 static char current_tmap_list[MAX_TEXTURES][13];
68 int New_file_format_save = 1;
70 // Converts descent 2 texture numbers back to descent 1 texture numbers.
71 // Only works properly when the full Descent 1 texture set (descent.pig) is available.
72 short convert_to_d1_tmap_num(short tmap_num)
76 case 137: return 0; // grey rock001
78 case 1: return 3; // rock021
79 case 270: return 6; // blue rock002
80 case 271: return 7; // yellow rock265
81 case 2: return 8; // rock004
82 case 138: return 9; // purple (devil:179)
83 case 272: return 10; // red rock006
85 case 140: return 12; //devil:43
86 case 3: return 13; // rock014
87 case 4: return 14; // rock019
88 case 5: return 15; // rock020
98 case 144: return 25; //devil:35
101 case 145: return 28; //devil:43
102 //range handled by default case, returns 13..21 (- 16)
103 case 163: return 38; //devil:27
104 case 147: return 39; //31
109 case 136: return 44; //devil:135
114 case 146: return 49; //devil:60
115 case 131: return 50; //devil:138
120 case 165: return 55; //devil:193
122 case 132: return 57; //devil:119
123 // range handled by default case, returns 58..88 (+ 24)
124 case 197: return 88; //devil:15
125 // range handled by default case, returns 89..106 (- 25)
126 case 167: return 132;
127 // range handled by default case, returns 107..114 (- 26)
128 case 148: return 141; //devil:106
129 case 115: return 142;
130 case 116: return 143;
131 case 117: return 144;
132 case 118: return 145;
133 case 119: return 146;
134 case 149: return 147;
135 case 120: return 148;
136 case 121: return 149;
137 case 122: return 150;
138 case 123: return 151;
139 case 124: return 152;
140 case 125: return 153; // rock263
141 case 150: return 154;
142 case 126: return 155; // rock269
143 case 200: return 156; // metl002
144 case 201: return 157; // metl003
145 case 186: return 158; //devil:227
146 case 190: return 159; //devil:246
147 case 151: return 160;
148 case 152: return 161; //devil:206
149 case 202: return 162;
150 case 203: return 163;
151 case 204: return 164;
152 case 205: return 165;
153 case 206: return 166;
154 case 153: return 167;
155 case 154: return 168;
156 case 155: return 169;
157 case 156: return 170;//206;
158 case 157: return 171;//227;
159 case 207: return 172;
160 case 208: return 173;
161 case 158: return 174;
162 case 159: return 175;
163 // range handled by default case, returns 209..217 (+ 33)
164 case 160: return 185;
165 // range handled by default case, returns 218..224 (+ 32)
166 case 161: return 193;
167 case 162: return 194;//206;
168 case 166: return 195;
169 case 225: return 196;
170 case 226: return 197;
171 case 193: return 198;
172 case 168: return 199; //devil:204
173 case 169: return 200; //devil:204
174 case 227: return 201;
175 case 170: return 202; //devil:227
176 // range handled by default case, returns 228..234 (+ 25)
177 case 171: return 210; //devil:242
178 case 172: return 211; //devil:240
179 // range handled by default case, returns 235..242 (+ 23)
180 case 173: return 220; //devil:240
181 case 243: return 221;
182 case 244: return 222;
183 case 174: return 223;
184 case 245: return 224;
185 case 246: return 225;
186 case 164: return 226;//247; matching names but not matching textures
187 case 179: return 227; //devil:181
188 case 196: return 228;//248; matching names but not matching textures
189 case 175: return 229; //devil:66
190 case 176: return 230; //devil:66
191 // range handled by default case, returns 249..257 (+ 18)
192 case 177: return 240; //devil:132
193 case 130: return 241; //devil:131
194 case 178: return 242; //devil:15
195 case 180: return 243; //devil:38
196 case 258: return 244;
197 case 259: return 245;
198 case 181: return 246; // grate metl127
199 case 260: return 247;
200 case 261: return 248;
201 case 262: return 249;
202 case 340: return 250; // white doorframe metl126
203 case 412: return 251; // red doorframe metl133
204 case 410: return 252; // blue doorframe metl134
205 case 411: return 253; // yellow doorframe metl135
206 case 263: return 254; // metl136
207 case 264: return 255; // metl139
208 case 265: return 256; // metl140
209 case 182: return 257;//246; brig001
210 case 183: return 258;//246; brig002
211 case 184: return 259;//246; brig003
212 case 185: return 260;//246; brig004
213 case 273: return 261; // exit01
214 case 274: return 262; // exit02
215 case 187: return 263; // ceil001
216 case 275: return 264; // ceil002
217 case 276: return 265; // ceil003
218 case 188: return 266; //devil:291
219 // range handled by default case, returns 277..291 (+ 10)
220 case 293: return 282;
221 case 189: return 283;
222 case 295: return 284;
223 case 296: return 285;
224 case 298: return 286;
225 // range handled by default case, returns 300..310 (+ 13)
226 case 191: return 298; // devil:374 misc010
227 // range handled by default case, returns 311..326 (+ 12)
228 case 192: return 315; // bad producer misc044
229 // range handled by default case, returns 327..337 (+ 11)
230 case 352: return 327; // arw01
231 case 353: return 328; // misc17
232 case 354: return 329; // fan01
233 case 380: return 330; // mntr04
234 case 379: return 331;//373; matching names but not matching textures
235 case 355: return 332;//344; matching names but not matching textures
236 case 409: return 333; // lava misc11 //devil:404
237 case 356: return 334; // ctrl04
238 case 357: return 335; // ctrl01
239 case 358: return 336; // ctrl02
240 case 359: return 337; // ctrl03
241 case 360: return 338; // misc14
242 case 361: return 339; // producer misc16
243 case 362: return 340; // misc049
244 case 364: return 341; // misc060
245 case 363: return 342; // blown01
246 case 366: return 343; // misc061
247 case 365: return 344;
248 case 368: return 345;
249 case 376: return 346;
250 case 370: return 347;
251 case 367: return 348;
252 case 372: return 349;
253 case 369: return 350;
254 case 374: return 351;//429; matching names but not matching textures
255 case 375: return 352;//387; matching names but not matching textures
256 case 371: return 353;
257 case 377: return 354;//425; matching names but not matching textures
258 case 408: return 355;
259 case 378: return 356; // lava02
260 case 383: return 357;//384; matching names but not matching textures
261 case 384: return 358;//385; matching names but not matching textures
262 case 385: return 359;//386; matching names but not matching textures
263 case 386: return 360;
264 case 387: return 361;
265 case 194: return 362; // mntr04b (devil: -1)
266 case 388: return 363;
267 case 391: return 364;
268 case 392: return 365;
269 case 393: return 366;
270 case 394: return 367;
271 case 395: return 368;
272 case 396: return 369;
273 case 195: return 370; // mntr04d (devil: -1)
274 // range 371..584 handled by default case (wall01 and door frames)
277 if (tmap_num >= 13 && tmap_num <= 21)
278 return tmap_num + 16;
279 if (tmap_num >= 34 && tmap_num <= 63)
280 return tmap_num + 24;
281 if (tmap_num >= 64 && tmap_num <= 106)
282 return tmap_num + 25;
283 if (tmap_num >= 107 && tmap_num <= 114)
284 return tmap_num + 26;
285 if (tmap_num >= 209 && tmap_num <= 217)
286 return tmap_num - 33;
287 if (tmap_num >= 218 && tmap_num <= 224)
288 return tmap_num - 32;
289 if (tmap_num >= 228 && tmap_num <= 234)
290 return tmap_num - 25;
291 if (tmap_num >= 235 && tmap_num <= 242)
292 return tmap_num - 23;
293 if (tmap_num >= 249 && tmap_num <= 257)
294 return tmap_num - 18;
295 if (tmap_num >= 277 && tmap_num <= 291)
296 return tmap_num - 10;
297 if (tmap_num >= 300 && tmap_num <= 310)
298 return tmap_num - 13;
299 if (tmap_num >= 311 && tmap_num <= 326)
300 return tmap_num - 12;
301 if (tmap_num >= 327 && tmap_num <= 337)
302 return tmap_num - 11; // matching names but not matching textures
303 // wall01 and door frames:
304 if (tmap_num > 434 && tmap_num < 731)
306 if (New_file_format_save) return tmap_num - 64;
307 // d1 shareware needs special treatment:
308 if (tmap_num < 478) return tmap_num - 68;
309 if (tmap_num < 490) return tmap_num - 73;
310 if (tmap_num < 537) return tmap_num - 91;
311 if (tmap_num < 557) return tmap_num - 104;
312 if (tmap_num < 573) return tmap_num - 111;
313 if (tmap_num < 603) return tmap_num - 117;
314 if (tmap_num < 635) return tmap_num - 141;
315 if (tmap_num < 731) return tmap_num - 147;
317 { // handle rare case where orientation != 0
318 short tmap_num_part = tmap_num & TMAP_NUM_MASK;
319 short orient = tmap_num & ~TMAP_NUM_MASK;
321 return orient | convert_to_d1_tmap_num(tmap_num_part);
324 Warning("can't convert unknown texture #%d to descent 1.\n", tmap_num_part);
331 // -----------------------------------------------------------------------------
333 // 1. Write file info, header info, editor info, vertex data, segment data,
334 // and new_segment in that order, marking their file offset.
335 // 2. Go through all the fields and fill in the offset, size, and sizeof
336 // values in the headers.
338 int med_save_mine(char * filename)
341 char ErrorMessage[256];
343 SaveFile = cfopen( filename, CF_WRITE_MODE );
346 #if 0 //ndef __linux__
348 _splitpath( filename, NULL, NULL, fname, NULL );
350 sprintf( ErrorMessage, \
351 "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"
354 sprintf( ErrorMessage, "ERROR: Unable to open %s\n", filename );
355 MessageBox( -2, -2, 1, ErrorMessage, "Ok" );
359 save_mine_data(SaveFile);
361 //==================== CLOSE THE FILE =============================
368 // -----------------------------------------------------------------------------
369 // saves to an already-open file
370 int save_mine_data(CFILE * SaveFile)
372 int header_offset, editor_offset, vertex_offset, segment_offset, doors_offset, texture_offset, walls_offset, triggers_offset; //, links_offset;
373 int newseg_verts_offset;
374 int newsegment_offset;
378 warn_if_concave_segments();
380 for (i=0;i<NumTextures;i++)
381 strncpy(current_tmap_list[i], TmapInfo[i].filename, 13);
383 //=================== Calculate offsets into file ==================
385 header_offset = cftell(SaveFile) + sizeof(mine_fileinfo);
386 editor_offset = header_offset + sizeof(mine_header);
387 texture_offset = editor_offset + sizeof(mine_editor);
388 vertex_offset = texture_offset + (13*NumTextures);
389 segment_offset = vertex_offset + (sizeof(vms_vector)*Num_vertices);
390 newsegment_offset = segment_offset + (sizeof(segment)*Num_segments);
391 newseg_verts_offset = newsegment_offset + sizeof(segment);
392 walls_offset = newseg_verts_offset + (sizeof(vms_vector)*8);
393 triggers_offset = walls_offset + (sizeof(wall)*Num_walls);
394 doors_offset = triggers_offset + (sizeof(trigger)*Num_triggers);
396 //===================== SAVE FILE INFO ========================
398 mine_fileinfo.fileinfo_signature= 0x2884;
399 mine_fileinfo.fileinfo_version = MINE_VERSION;
400 mine_fileinfo.fileinfo_sizeof = sizeof(mine_fileinfo);
401 mine_fileinfo.header_offset = header_offset;
402 mine_fileinfo.header_size = sizeof(mine_header);
403 mine_fileinfo.editor_offset = editor_offset;
404 mine_fileinfo.editor_size = sizeof(mine_editor);
405 mine_fileinfo.vertex_offset = vertex_offset;
406 mine_fileinfo.vertex_howmany = Num_vertices;
407 mine_fileinfo.vertex_sizeof = sizeof(vms_vector);
408 mine_fileinfo.segment_offset = segment_offset;
409 mine_fileinfo.segment_howmany = Num_segments;
410 mine_fileinfo.segment_sizeof = sizeof(segment);
411 mine_fileinfo.newseg_verts_offset = newseg_verts_offset;
412 mine_fileinfo.newseg_verts_howmany = 8;
413 mine_fileinfo.newseg_verts_sizeof = sizeof(vms_vector);
414 mine_fileinfo.texture_offset = texture_offset;
415 mine_fileinfo.texture_howmany = NumTextures;
416 mine_fileinfo.texture_sizeof = 13; // num characters in a name
417 mine_fileinfo.walls_offset = walls_offset;
418 mine_fileinfo.walls_howmany = Num_walls;
419 mine_fileinfo.walls_sizeof = sizeof(wall);
420 mine_fileinfo.triggers_offset = triggers_offset;
421 mine_fileinfo.triggers_howmany = Num_triggers;
422 mine_fileinfo.triggers_sizeof = sizeof(trigger);
424 // Write the fileinfo
425 cfwrite( &mine_fileinfo, sizeof(mine_fileinfo), 1, SaveFile );
427 //===================== SAVE HEADER INFO ========================
429 mine_header.num_vertices = Num_vertices;
430 mine_header.num_segments = Num_segments;
432 // Write the editor info
433 if (header_offset != cftell(SaveFile))
434 Error( "OFFSETS WRONG IN MINE.C!" );
436 cfwrite( &mine_header, sizeof(mine_header), 1, SaveFile );
438 //===================== SAVE EDITOR INFO ==========================
439 mine_editor.current_seg = Cursegp - Segments;
440 mine_editor.newsegment_offset = newsegment_offset;
441 mine_editor.newsegment_size = sizeof(segment);
443 // Next 3 vars added 10/07 by JAS
444 mine_editor.Curside = Curside;
446 mine_editor.Markedsegp = Markedsegp - Segments;
448 mine_editor.Markedsegp = -1;
449 mine_editor.Markedside = Markedside;
451 mine_editor.Groupsegp[i] = Groupsegp[i] - Segments;
453 mine_editor.Groupside[i] = Groupside[i];
455 if (editor_offset != cftell(SaveFile))
456 Error( "OFFSETS WRONG IN MINE.C!" );
457 cfwrite( &mine_editor, sizeof(mine_editor), 1, SaveFile );
459 //===================== SAVE TEXTURE INFO ==========================
461 if (texture_offset != cftell(SaveFile))
462 Error( "OFFSETS WRONG IN MINE.C!" );
463 cfwrite( current_tmap_list, 13, NumTextures, SaveFile );
465 //===================== SAVE VERTEX INFO ==========================
467 if (vertex_offset != cftell(SaveFile))
468 Error( "OFFSETS WRONG IN MINE.C!" );
469 cfwrite( Vertices, sizeof(vms_vector), Num_vertices, SaveFile );
471 //===================== SAVE SEGMENT INFO =========================
473 if (segment_offset != cftell(SaveFile))
474 Error( "OFFSETS WRONG IN MINE.C!" );
475 cfwrite( Segments, sizeof(segment), Num_segments, SaveFile );
477 //===================== SAVE NEWSEGMENT INFO ======================
479 if (newsegment_offset != cftell(SaveFile))
480 Error( "OFFSETS WRONG IN MINE.C!" );
481 cfwrite( &New_segment, sizeof(segment), 1, SaveFile );
483 if (newseg_verts_offset != cftell(SaveFile))
484 Error( "OFFSETS WRONG IN MINE.C!" );
485 cfwrite( &Vertices[New_segment.verts[0]], sizeof(vms_vector), 8, SaveFile );
487 //==================== CLOSE THE FILE =============================
495 #define COMPILED_MINE_VERSION 0
497 void dump_fix_as_short( fix value, int nbits, PHYSFS_file *SaveFile )
502 int_value = (int)(value>>nbits);
503 if( int_value > 0x7fff ) {
504 short_value = 0x7fff;
505 mprintf((1, "Warning: Fix (%8x) won't fit in short. Saturating to %8x.\n", int_value, short_value<<nbits));
507 else if( int_value < -0x7fff ) {
508 short_value = -0x7fff;
509 mprintf((1, "Warning: Fix (%8x) won't fit in short. Saturating to %8x.\n", int_value, short_value<<nbits));
512 short_value = (short)int_value;
514 PHYSFS_writeSLE16(SaveFile, short_value);
517 //version of dump for unsigned values
518 void dump_fix_as_ushort( fix value, int nbits, PHYSFS_file *SaveFile )
524 mprintf((1, "Warning: fix (%8x) is signed...setting to zero.\n", value));
525 Int3(); //hey---show this to Matt
529 int_value = value >> nbits;
531 if( int_value > 0xffff ) {
532 short_value = 0xffff;
533 mprintf((1, "Warning: Fix (%8x) won't fit in unsigned short. Saturating to %8x.\n", int_value, short_value<<nbits));
536 short_value = int_value;
538 PHYSFS_writeULE16(SaveFile, short_value);
541 void write_children(segment *seg, ubyte bit_mask, PHYSFS_file *SaveFile)
545 for (bit = 0; bit < MAX_SIDES_PER_SEGMENT; bit++)
547 if (bit_mask & (1 << bit))
548 PHYSFS_writeSLE16(SaveFile, seg->children[bit]);
552 void write_verts(segment *seg, PHYSFS_file *SaveFile)
556 for (i = 0; i < MAX_VERTICES_PER_SEGMENT; i++)
557 PHYSFS_writeSLE16(SaveFile, seg->verts[i]);
560 void write_special(segment2 *seg2, ubyte bit_mask, PHYSFS_file *SaveFile)
562 if (bit_mask & (1 << MAX_SIDES_PER_SEGMENT))
564 PHYSFSX_writeU8(SaveFile, seg2->special);
565 PHYSFSX_writeU8(SaveFile, seg2->matcen_num);
566 PHYSFS_writeSLE16(SaveFile, seg2->value);
569 // -----------------------------------------------------------------------------
570 // saves compiled mine data to an already-open file...
571 int save_mine_data_compiled(PHYSFS_file *SaveFile)
573 short i, segnum, sidenum;
574 ubyte version = COMPILED_MINE_VERSION;
578 warn_if_concave_segments();
580 if (Highest_segment_index >= MAX_SEGMENTS) {
582 sprintf(message, "Error: Too many segments (%i > %i) for game (not editor)", Highest_segment_index+1, MAX_SEGMENTS);
583 MessageBox( -2, -2, 1, message, "Ok" );
586 if (Highest_vertex_index >= MAX_VERTICES) {
588 sprintf(message, "Error: Too many vertices (%i > %i) for game (not editor)", Highest_vertex_index+1, MAX_VERTICES);
589 MessageBox( -2, -2, 1, message, "Ok" );
592 //=============================== Writing part ==============================
593 PHYSFSX_writeU8(SaveFile, version); // 1 byte = compiled version
594 if (New_file_format_save)
596 PHYSFS_writeSLE16(SaveFile, Num_vertices); // 2 bytes = Num_vertices
597 PHYSFS_writeSLE16(SaveFile, Num_segments); // 2 bytes = Num_segments
601 PHYSFS_writeSLE32(SaveFile, Num_vertices); // 4 bytes = Num_vertices
602 PHYSFS_writeSLE32(SaveFile, Num_segments); // 4 bytes = Num_segments
605 for (i = 0; i < Num_vertices; i++)
606 PHYSFSX_writeVector(SaveFile, &(Vertices[i]));
608 for (segnum = 0; segnum < Num_segments; segnum++)
610 segment *seg = &Segments[segnum];
611 segment2 *seg2 = &Segment2s[segnum];
613 for (sidenum = 0; sidenum < MAX_SIDES_PER_SEGMENT; sidenum++)
615 if (seg->children[sidenum] != -1)
616 bit_mask |= (1 << sidenum);
619 if ((seg2->special != 0) || (seg2->matcen_num != 0) || (seg2->value != 0))
620 bit_mask |= (1 << MAX_SIDES_PER_SEGMENT);
622 if (New_file_format_save)
623 PHYSFSX_writeU8(SaveFile, bit_mask);
627 if (Gamesave_current_version == 5) // d2 SHAREWARE level
629 write_special(seg2, bit_mask, SaveFile);
630 write_verts(seg, SaveFile);
631 write_children(seg, bit_mask, SaveFile);
635 write_children(seg, bit_mask, SaveFile);
636 write_verts(seg, SaveFile);
637 if (Gamesave_current_version <= 1) // descent 1 level
638 write_special(seg2, bit_mask, SaveFile);
641 if (Gamesave_current_version <= 5) // descent 1 thru d2 SHAREWARE level
642 dump_fix_as_ushort(seg2->static_light, 4, SaveFile);
644 // Write the walls as a 6 byte array
646 for (sidenum = 0; sidenum < MAX_SIDES_PER_SEGMENT; sidenum++)
650 if (seg->sides[sidenum].wall_num >= 0)
652 bit_mask |= (1 << sidenum);
653 wallnum = seg->sides[sidenum].wall_num;
654 Assert( wallnum < 255 ); // Get John or Mike.. can only store up to 255 walls!!!
657 if (New_file_format_save)
658 PHYSFSX_writeU8(SaveFile, bit_mask);
662 for (sidenum = 0; sidenum < MAX_SIDES_PER_SEGMENT; sidenum++)
664 if (bit_mask & (1 << sidenum))
665 PHYSFSX_writeU8(SaveFile, seg->sides[sidenum].wall_num);
668 for (sidenum = 0; sidenum < MAX_SIDES_PER_SEGMENT; sidenum++)
670 if ((seg->children[sidenum] == -1) || (seg->sides[sidenum].wall_num != -1))
672 ushort tmap_num, tmap_num2;
674 tmap_num = seg->sides[sidenum].tmap_num;
675 tmap_num2 = seg->sides[sidenum].tmap_num2;
677 if (Gamesave_current_version <= 3) // convert texture numbers back to d1
679 tmap_num = convert_to_d1_tmap_num(tmap_num);
681 tmap_num2 = convert_to_d1_tmap_num(tmap_num2);
684 if (tmap_num2 != 0 && New_file_format_save)
687 PHYSFS_writeSLE16(SaveFile, tmap_num);
688 if (tmap_num2 != 0 || !New_file_format_save)
689 PHYSFS_writeSLE16(SaveFile, tmap_num2);
691 for (i = 0; i < 4; i++)
693 dump_fix_as_short(seg->sides[sidenum].uvls[i].u, 5, SaveFile);
694 dump_fix_as_short(seg->sides[sidenum].uvls[i].v, 5, SaveFile);
695 dump_fix_as_ushort(seg->sides[sidenum].uvls[i].l, 1, SaveFile);
702 if (Gamesave_current_version > 5)
703 for (i = 0; i < Num_segments; i++)
704 segment2_write(&Segment2s[i], SaveFile);