Subversion Repositories Games.Descent

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 pmbaty 1
/*
2
 * Portions of this file are copyright Rebirth contributors and licensed as
3
 * described in COPYING.txt.
4
 * Portions of this file are copyright Parallax Software and licensed
5
 * according to the Parallax license below.
6
 * See COPYING.txt for license details.
7
 
8
THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
9
SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
10
END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
11
ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
12
IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
13
SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
14
FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
15
CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
16
AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
17
COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
18
*/
19
 
20
/*
21
 *
22
 * Functions for loading mines in the game
23
 *
24
 */
25
 
26
 
27
#include <stdio.h>
28
#include <stdlib.h>
29
#include <math.h>
30
#include <string.h>
31
 
32
#include "pstypes.h"
33
#include "inferno.h"
34
#include "segment.h"
35
#include "textures.h"
36
#include "wall.h"
37
#include "object.h"
38
#include "gamemine.h"
39
#include "dxxerror.h"
40
#include "gameseg.h"
41
#include "physfsx.h"
42
#include "switch.h"
43
#include "game.h"
44
#include "newmenu.h"
45
#if DXX_USE_EDITOR
46
#include "editor/editor.h"
47
#include "editor/esegment.h"
48
#include "d_range.h"
49
#endif
50
#include "fuelcen.h"
51
#include "hash.h"
52
#include "key.h"
53
#include "piggy.h"
54
#include "gamesave.h"
55
#include "compiler-poison.h"
56
#include "compiler-range_for.h"
57
#include "partial_range.h"
58
 
59
#define REMOVE_EXT(s)  (*(strchr( (s), '.' ))='\0')
60
 
61
int New_file_format_load = 1; // "new file format" is everything newer than d1 shareware
62
 
63
namespace dsx {
64
 
65
/*
66
 * reads a segment2 structure from a PHYSFS_File
67
 */
68
static void segment2_read(const msmusegment s2, PHYSFS_File *fp)
69
{
70
        s2.s.special = PHYSFSX_readByte(fp);
71
        s2.s.matcen_num = PHYSFSX_readByte(fp);
72
        /* station_idx is overwritten by the caller in some cases, but set
73
         * it here for compatibility with how the game previously worked */
74
        s2.s.station_idx = PHYSFSX_readByte(fp);
75
        const auto s2_flags = PHYSFSX_readByte(fp);
76
#if defined(DXX_BUILD_DESCENT_I)
77
        (void)s2_flags; // descent 2 ambient sound handling
78
        if (s2.s.special >= MAX_CENTER_TYPES)
79
                s2.s.special = SEGMENT_IS_NOTHING; // remove goals etc.
80
#elif defined(DXX_BUILD_DESCENT_II)
81
        s2.s.s2_flags = s2_flags;
82
#endif
83
        s2.u.static_light = PHYSFSX_readFix(fp);
84
}
85
 
86
#if defined(DXX_BUILD_DESCENT_I)
87
#elif defined(DXX_BUILD_DESCENT_II)
88
 
89
int d1_pig_present = 0; // can descent.pig from descent 1 be loaded?
90
 
91
/* returns nonzero if d1_tmap_num references a texture which isn't available in d2. */
92
int d1_tmap_num_unique(short d1_tmap_num) {
93
        switch (d1_tmap_num) {
94
        case   0: case   2: case   4: case   5: case   6: case   7: case   9:
95
        case  10: case  11: case  12: case  17: case  18:
96
        case  20: case  21: case  25: case  28:
97
        case  38: case  39: case  41: case  44: case  49:
98
        case  50: case  55: case  57: case  88:
99
        case 132: case 141: case 147:
100
        case 154: case 155: case 158: case 159:
101
        case 160: case 161: case 167: case 168: case 169:
102
        case 170: case 171: case 174: case 175: case 185:
103
        case 193: case 194: case 195: case 198: case 199:
104
        case 200: case 202: case 210: case 211:
105
        case 220: case 226: case 227: case 228: case 229: case 230:
106
        case 240: case 241: case 242: case 243: case 246:
107
        case 250: case 251: case 252: case 253: case 257: case 258: case 259:
108
        case 260: case 263: case 266: case 283: case 298:
109
        case 315: case 317: case 319: case 320: case 321:
110
        case 330: case 331: case 332: case 333: case 349:
111
        case 351: case 352: case 353: case 354:
112
        case 355: case 357: case 358: case 359:
113
        case 362: case 370: return 1;
114
        default: return 0;
115
        }
116
}
117
 
118
/* Converts descent 1 texture numbers to descent 2 texture numbers.
119
 * Textures from d1 which are unique to d1 have extra spaces around "return".
120
 * If we can load the original d1 pig, we make sure this function is bijective.
121
 * This function was updated using the file config/convtabl.ini from devil 2.2.
122
 */
123
short convert_d1_tmap_num(short d1_tmap_num) {
124
        switch (d1_tmap_num) {
125
        case 0: case 2: case 4: case 5:
126
                // all refer to grey rock001 (exception to bijectivity rule)
127
                return  d1_pig_present ? 137 : 43; // (devil:95)
128
        case   1: return 0;
129
        case   3: return 1; // rock021
130
        case   6:  return  270; // blue rock002
131
        case   7:  return  271; // yellow rock265
132
        case   8: return 2; // rock004
133
        case   9:  return  d1_pig_present ? 138 : 62; // purple (devil:179)
134
        case  10:  return  272; // red rock006
135
        case  11:  return  d1_pig_present ? 139 : 117;
136
        case  12:  return  d1_pig_present ? 140 : 12; //devil:43
137
        case  13: return 3; // rock014
138
        case  14: return 4; // rock019
139
        case  15: return 5; // rock020
140
        case  16: return 6;
141
        case  17:  return  d1_pig_present ? 141 : 52;
142
        case  18:  return  129;
143
        case  19: return 7;
144
        case  20:  return  d1_pig_present ? 142 : 22;
145
        case  21:  return  d1_pig_present ? 143 : 9;
146
        case  22: return 8;
147
        case  23: return 9;
148
        case  24: return 10;
149
        case  25:  return  d1_pig_present ? 144 : 12; //devil:35
150
        case  26: return 11;
151
        case  27: return 12;
152
        case  28:  return  d1_pig_present ? 145 : 11; //devil:43
153
        //range handled by default case, returns 13..21 (- 16)
154
        case  38:  return  163; //devil:27
155
        case  39:  return  147; //31
156
        case  40: return 22;
157
        case  41:  return  266;
158
        case  42: return 23;
159
        case  43: return 24;
160
        case  44:  return  136; //devil:135
161
        case  45: return 25;
162
        case  46: return 26;
163
        case  47: return 27;
164
        case  48: return 28;
165
        case  49:  return  d1_pig_present ? 146 : 43; //devil:60
166
        case  50:  return  131; //devil:138
167
        case  51: return 29;
168
        case  52: return 30;
169
        case  53: return 31;
170
        case  54: return 32;
171
        case  55:  return  165; //devil:193
172
        case  56: return 33;
173
        case  57:  return  132; //devil:119
174
        // range handled by default case, returns 34..63 (- 24)
175
        case  88:  return  197; //devil:15
176
        // range handled by default case, returns 64..106 (- 25)
177
        case 132:  return  167;
178
        // range handled by default case, returns 107..114 (- 26)
179
        case 141:  return  d1_pig_present ? 148 : 110; //devil:106
180
        case 142: return 115;
181
        case 143: return 116;
182
        case 144: return 117;
183
        case 145: return 118;
184
        case 146: return 119;
185
        case 147:  return  d1_pig_present ? 149 : 93;
186
        case 148: return 120;
187
        case 149: return 121;
188
        case 150: return 122;
189
        case 151: return 123;
190
        case 152: return 124;
191
        case 153: return 125; // rock263
192
        case 154:  return  d1_pig_present ? 150 : 27;
193
        case 155:  return  126; // rock269
194
        case 156: return 200; // metl002
195
        case 157: return 201; // metl003
196
        case 158:  return  186; //devil:227
197
        case 159:  return  190; //devil:246
198
        case 160:  return  d1_pig_present ? 151 : 206;
199
        case 161:  return  d1_pig_present ? 152 : 114; //devil:206
200
        case 162: return 202;
201
        case 163: return 203;
202
        case 164: return 204;
203
        case 165: return 205;
204
        case 166: return 206;
205
        case 167:  return  d1_pig_present ? 153 : 206;
206
        case 168:  return  d1_pig_present ? 154 : 206;
207
        case 169:  return  d1_pig_present ? 155 : 206;
208
        case 170:  return  d1_pig_present ? 156 : 227;//206;
209
        case 171:  return  d1_pig_present ? 157 : 206;//227;
210
        case 172: return 207;
211
        case 173: return 208;
212
        case 174:  return  d1_pig_present ? 158 : 202;
213
        case 175:  return  d1_pig_present ? 159 : 206;
214
        // range handled by default case, returns 209..217 (+ 33)
215
        case 185:  return  d1_pig_present ? 160 : 217;
216
        // range handled by default case, returns 218..224 (+ 32)
217
        case 193:  return  d1_pig_present ? 161 : 206;
218
        case 194:  return  d1_pig_present ? 162 : 203;//206;
219
        case 195:  return  d1_pig_present ? 166 : 234;
220
        case 196: return 225;
221
        case 197: return 226;
222
        case 198:  return  d1_pig_present ? 193 : 225;
223
        case 199:  return  d1_pig_present ? 168 : 206; //devil:204
224
        case 200:  return  d1_pig_present ? 169 : 206; //devil:204
225
        case 201: return 227;
226
        case 202:  return  d1_pig_present ? 170 : 206; //devil:227
227
        // range handled by default case, returns 228..234 (+ 25)
228
        case 210:  return  d1_pig_present ? 171 : 234; //devil:242
229
        case 211:  return  d1_pig_present ? 172 : 206; //devil:240
230
        // range handled by default case, returns 235..242 (+ 23)
231
        case 220:  return  d1_pig_present ? 173 : 242; //devil:240
232
        case 221: return 243;
233
        case 222: return 244;
234
        case 223:  return  d1_pig_present ? 174 : 313;
235
        case 224: return 245;
236
        case 225: return 246;
237
        case 226:  return  164;//247; matching names but not matching textures
238
        case 227:  return  179; //devil:181
239
        case 228:  return  196;//248; matching names but not matching textures
240
        case 229:  return  d1_pig_present ? 175 : 15; //devil:66
241
        case 230:  return  d1_pig_present ? 176 : 15; //devil:66
242
        // range handled by default case, returns 249..257 (+ 18)
243
        case 240:  return  d1_pig_present ? 177 : 6; //devil:132
244
        case 241:  return  130; //devil:131
245
        case 242:  return  d1_pig_present ? 178 : 78; //devil:15
246
        case 243:  return  d1_pig_present ? 180 : 33; //devil:38
247
        case 244: return 258;
248
        case 245: return 259;
249
        case 246:  return  d1_pig_present ? 181 : 321; // grate metl127
250
        case 247: return 260;
251
        case 248: return 261;
252
        case 249: return 262;
253
        case 250:  return  340; //  white doorframe metl126
254
        case 251:  return  412; //    red doorframe metl133
255
        case 252:  return  410; //   blue doorframe metl134
256
        case 253:  return  411; // yellow doorframe metl135
257
        case 254: return 263; // metl136
258
        case 255: return 264; // metl139
259
        case 256: return 265; // metl140
260
        case 257:  return  d1_pig_present ? 182 : 249;//246; brig001
261
        case 258:  return  d1_pig_present ? 183 : 251;//246; brig002
262
        case 259:  return  d1_pig_present ? 184 : 252;//246; brig003
263
        case 260:  return  d1_pig_present ? 185 : 256;//246; brig004
264
        case 261: return 273; // exit01
265
        case 262: return 274; // exit02
266
        case 263:  return  d1_pig_present ? 187 : 281; // ceil001
267
        case 264: return 275; // ceil002
268
        case 265: return 276; // ceil003
269
        case 266:  return  d1_pig_present ? 188 : 279; //devil:291
270
        // range handled by default case, returns 277..291 (+ 10)
271
        case 282: return 293;
272
        case 283:  return  d1_pig_present ? 189 : 295;
273
        case 284: return 295;
274
        case 285: return 296;
275
        case 286: return 298;
276
        // range handled by default case, returns 300..310 (+ 13)
277
        case 298:  return  d1_pig_present ? 191 : 364; // devil:374 misc010
278
        // range handled by default case, returns 311..326 (+ 12)
279
        case 315:  return  d1_pig_present ? 192 : 361; // bad producer misc044
280
        // range handled by default case,  returns  327..337 (+ 11)
281
        case 327: return 352; // arw01
282
        case 328: return 353; // misc17
283
        case 329: return 354; // fan01
284
        case 330:  return  380; // mntr04
285
        case 331:  return  379;//373; matching names but not matching textures
286
        case 332:  return  355;//344; matching names but not matching textures
287
        case 333:  return  409; // lava misc11 //devil:404
288
        case 334: return 356; // ctrl04
289
        case 335: return 357; // ctrl01
290
        case 336: return 358; // ctrl02
291
        case 337: return 359; // ctrl03
292
        case 338: return 360; // misc14
293
        case 339: return 361; // producer misc16
294
        case 340: return 362; // misc049
295
        case 341: return 364; // misc060
296
        case 342: return 363; // blown01
297
        case 343: return 366; // misc061
298
        case 344: return 365;
299
        case 345: return 368;
300
        case 346: return 376;
301
        case 347: return 370;
302
        case 348: return 367;
303
        case 349:  return  372;
304
        case 350: return 369;
305
        case 351:  return  374;//429; matching names but not matching textures
306
        case 352:  return  375;//387; matching names but not matching textures
307
        case 353:  return  371;
308
        case 354:  return  377;//425; matching names but not matching textures
309
        case 355:  return  408;
310
        case 356: return 378; // lava02
311
        case 357:  return  383;//384; matching names but not matching textures
312
        case 358:  return  384;//385; matching names but not matching textures
313
        case 359:  return  385;//386; matching names but not matching textures
314
        case 360: return 386;
315
        case 361: return 387;
316
        case 362:  return  d1_pig_present ? 194 : 388; // mntr04b (devil: -1)
317
        case 363: return 388;
318
        case 364: return 391;
319
        case 365: return 392;
320
        case 366: return 393;
321
        case 367: return 394;
322
        case 368: return 395;
323
        case 369: return 396;
324
        case 370:  return  d1_pig_present ? 195 : 392; // mntr04d (devil: -1)
325
        // range 371..584 handled by default case (wall01 and door frames)
326
        default:
327
                // ranges:
328
                if (d1_tmap_num >= 29 && d1_tmap_num <= 37)
329
                        return d1_tmap_num - 16;
330
                if (d1_tmap_num >= 58 && d1_tmap_num <= 87)
331
                        return d1_tmap_num - 24;
332
                if (d1_tmap_num >= 89 && d1_tmap_num <= 131)
333
                        return d1_tmap_num - 25;
334
                if (d1_tmap_num >= 133 && d1_tmap_num <= 140)
335
                        return d1_tmap_num - 26;
336
                if (d1_tmap_num >= 176 && d1_tmap_num <= 184)
337
                        return d1_tmap_num + 33;
338
                if (d1_tmap_num >= 186 && d1_tmap_num <= 192)
339
                        return d1_tmap_num + 32;
340
                if (d1_tmap_num >= 203 && d1_tmap_num <= 209)
341
                        return d1_tmap_num + 25;
342
                if (d1_tmap_num >= 212 && d1_tmap_num <= 219)
343
                        return d1_tmap_num + 23;
344
                if (d1_tmap_num >= 231 && d1_tmap_num <= 239)
345
                        return d1_tmap_num + 18;
346
                if (d1_tmap_num >= 267 && d1_tmap_num <= 281)
347
                        return d1_tmap_num + 10;
348
                if (d1_tmap_num >= 287 && d1_tmap_num <= 297)
349
                        return d1_tmap_num + 13;
350
                if (d1_tmap_num >= 299 && d1_tmap_num <= 314)
351
                        return d1_tmap_num + 12;
352
                if (d1_tmap_num >= 316 && d1_tmap_num <= 326)
353
                         return  d1_tmap_num + 11; // matching names but not matching textures
354
                // wall01 and door frames:
355
                if (d1_tmap_num > 370 && d1_tmap_num < 584) {
356
                        if (New_file_format_load) return d1_tmap_num + 64;
357
                        // d1 shareware needs special treatment:
358
                        if (d1_tmap_num < 410) return d1_tmap_num + 68;
359
                        if (d1_tmap_num < 417) return d1_tmap_num + 73;
360
                        if (d1_tmap_num < 446) return d1_tmap_num + 91;
361
                        if (d1_tmap_num < 453) return d1_tmap_num + 104;
362
                        if (d1_tmap_num < 462) return d1_tmap_num + 111;
363
                        if (d1_tmap_num < 486) return d1_tmap_num + 117;
364
                        if (d1_tmap_num < 494) return d1_tmap_num + 141;
365
                        if (d1_tmap_num < 584) return d1_tmap_num + 147;
366
                }
367
                { // handle rare case where orientation != 0
368
                        short tmap_num = d1_tmap_num &  TMAP_NUM_MASK;
369
                        short orient = d1_tmap_num & ~TMAP_NUM_MASK;
370
                        if (orient != 0) {
371
                                return orient | convert_d1_tmap_num(tmap_num);
372
                        } else {
373
                                Warning("can't convert unknown descent 1 texture #%d.\n", tmap_num);
374
                                return d1_tmap_num;
375
                        }
376
                }
377
        }
378
}
379
#endif
380
 
381
}
382
 
383
#if DXX_USE_EDITOR
384
namespace dsx {
385
tmap_xlate_table_array tmap_xlate_table;
386
}
387
struct mtfi mine_top_fileinfo; // Should be same as first two fields below...
388
struct mfi mine_fileinfo;
389
struct mh mine_header;
390
struct me mine_editor;
391
 
392
// -----------------------------------------------------------------------------
393
//loads from an already-open file
394
// returns 0=everything ok, 1=old version, -1=error
395
namespace dsx {
396
int load_mine_data(PHYSFS_File *LoadFile)
397
{
398
        auto &LevelSharedVertexState = LevelSharedSegmentState.get_vertex_state();
399
        auto &Vertices = LevelSharedVertexState.get_vertices();
400
        auto &TmapInfo = LevelUniqueTmapInfoState.TmapInfo;
401
        char old_tmap_list[MAX_TEXTURES][FILENAME_LEN];
402
        int     translate;
403
        char    *temptr;
404
        int     mine_start = PHYSFS_tell(LoadFile);
405
 
406
        fuelcen_reset();
407
 
408
#if DXX_USE_EDITOR
409
        // Create a new mine to initialize things.
410
        //texpage_goto_first();
411
        create_new_mine();
412
        #endif
413
 
414
        //===================== READ FILE INFO ========================
415
 
416
        // These are the default values... version and fileinfo_sizeof
417
        // don't have defaults.
418
        mine_fileinfo.header_offset     =   -1;
419
        mine_fileinfo.header_size       =   sizeof(mine_header);
420
        mine_fileinfo.editor_offset     =   -1;
421
        mine_fileinfo.editor_size       =   sizeof(mine_editor);
422
        mine_fileinfo.vertex_offset     =   -1;
423
        mine_fileinfo.vertex_howmany    =   0;
424
        mine_fileinfo.vertex_sizeof     =   sizeof(vms_vector);
425
        mine_fileinfo.segment_offset    =   -1;
426
        mine_fileinfo.segment_howmany   =   0;
427
        mine_fileinfo.segment_sizeof    =   sizeof(segment);
428
        mine_fileinfo.newseg_verts_offset     =   -1;
429
        mine_fileinfo.newseg_verts_howmany    =   0;
430
        mine_fileinfo.newseg_verts_sizeof     =   sizeof(vms_vector);
431
        mine_fileinfo.group_offset                =     -1;
432
        mine_fileinfo.group_howmany       =     0;
433
        mine_fileinfo.group_sizeof                =     sizeof(group);
434
        mine_fileinfo.texture_offset    =   -1;
435
        mine_fileinfo.texture_howmany   =   0;
436
        mine_fileinfo.texture_sizeof    =   FILENAME_LEN;  // num characters in a name
437
        mine_fileinfo.walls_offset                =     -1;
438
        mine_fileinfo.walls_howmany       =     0;
439
        mine_fileinfo.walls_sizeof                =     sizeof(wall);  
440
        mine_fileinfo.triggers_offset     =     -1;
441
        mine_fileinfo.triggers_howmany  =       0;
442
        mine_fileinfo.triggers_sizeof     =     sizeof(trigger);  
443
        mine_fileinfo.object_offset             =       -1;
444
        mine_fileinfo.object_howmany            =       1;
445
        mine_fileinfo.object_sizeof             =       sizeof(object);  
446
 
447
#if defined(DXX_BUILD_DESCENT_II)
448
        mine_fileinfo.level_shake_frequency             =       0;
449
        mine_fileinfo.level_shake_duration              =       0;
450
 
451
        //      Delta light stuff for blowing out light sources.
452
//      if (mine_top_fileinfo.fileinfo_version >= 19) {
453
                mine_fileinfo.dl_indices_offset         =       -1;
454
                mine_fileinfo.dl_indices_howmany                =       0;
455
                mine_fileinfo.dl_indices_sizeof         =       sizeof(dl_index);  
456
 
457
                mine_fileinfo.delta_light_offset                =       -1;
458
                mine_fileinfo.delta_light_howmany               =       0;
459
                mine_fileinfo.delta_light_sizeof                =       sizeof(delta_light);  
460
 
461
//      }
462
 
463
        mine_fileinfo.segment2_offset           = -1;
464
        mine_fileinfo.segment2_howmany  = 0;
465
        mine_fileinfo.segment2_sizeof    = 0;
466
#endif
467
 
468
        // Read in mine_top_fileinfo to get size of saved fileinfo.
469
 
470
        mine_top_fileinfo = {};
471
 
472
        if (PHYSFSX_fseek( LoadFile, mine_start, SEEK_SET ))
473
                Error( "Error moving to top of file in gamemine.c" );
474
 
475
        if (PHYSFS_read( LoadFile, &mine_top_fileinfo, sizeof(mine_top_fileinfo), 1 )!=1)
476
                Error( "Error reading mine_top_fileinfo in gamemine.c" );
477
 
478
        if (mine_top_fileinfo.fileinfo_signature != 0x2884)
479
                return -1;
480
 
481
        // Check version number
482
        if (mine_top_fileinfo.fileinfo_version < COMPATIBLE_VERSION )
483
                return -1;
484
 
485
        // Now, Read in the fileinfo
486
        if (PHYSFSX_fseek( LoadFile, mine_start, SEEK_SET ))
487
                Error( "Error seeking to top of file in gamemine.c" );
488
 
489
        if (PHYSFS_read( LoadFile, &mine_fileinfo, mine_top_fileinfo.fileinfo_sizeof, 1 )!=1)
490
                Error( "Error reading mine_fileinfo in gamemine.c" );
491
 
492
#if defined(DXX_BUILD_DESCENT_II)
493
        if (mine_top_fileinfo.fileinfo_version < 18) {
494
                LevelSharedSeismicState.Level_shake_frequency = 0;
495
                LevelSharedSeismicState.Level_shake_duration = 0;
496
                LevelSharedSegmentState.Secret_return_segment = segment_first;
497
                LevelSharedSegmentState.Secret_return_orient = vmd_identity_matrix;
498
        } else {
499
                LevelSharedSeismicState.Level_shake_frequency = mine_fileinfo.level_shake_frequency << 12;
500
                LevelSharedSeismicState.Level_shake_duration = mine_fileinfo.level_shake_duration << 12;
501
                LevelSharedSegmentState.Secret_return_segment = mine_fileinfo.secret_return_segment;
502
                LevelSharedSegmentState.Secret_return_orient = mine_fileinfo.secret_return_orient;
503
        }
504
#endif
505
 
506
        //===================== READ HEADER INFO ========================
507
 
508
        // Set default values.
509
        mine_header.num_vertices        =   0;
510
        mine_header.num_segments        =   0;
511
 
512
        if (mine_fileinfo.header_offset > -1 )
513
        {
514
                if (PHYSFSX_fseek( LoadFile, mine_fileinfo.header_offset, SEEK_SET ))
515
                        Error( "Error seeking to header_offset in gamemine.c" );
516
 
517
                if (PHYSFS_read( LoadFile, &mine_header, mine_fileinfo.header_size, 1 )!=1)
518
                        Error( "Error reading mine_header in gamemine.c" );
519
        }
520
 
521
        //===================== READ EDITOR INFO ==========================
522
 
523
        // Set default values
524
        mine_editor.current_seg         =   0;
525
        mine_editor.newsegment_offset   =   -1; // To be written
526
        mine_editor.newsegment_size     =   sizeof(segment);
527
        mine_editor.Curside             =   0;
528
        mine_editor.Markedsegp          =   -1;
529
        mine_editor.Markedside          =   0;
530
 
531
        if (mine_fileinfo.editor_offset > -1 )
532
        {
533
                if (PHYSFSX_fseek( LoadFile, mine_fileinfo.editor_offset, SEEK_SET ))
534
                        Error( "Error seeking to editor_offset in gamemine.c" );
535
 
536
                if (PHYSFS_read( LoadFile, &mine_editor, mine_fileinfo.editor_size, 1 )!=1)
537
                        Error( "Error reading mine_editor in gamemine.c" );
538
        }
539
 
540
        //===================== READ TEXTURE INFO ==========================
541
 
542
        if ( (mine_fileinfo.texture_offset > -1) && (mine_fileinfo.texture_howmany > 0))
543
        {
544
                if (PHYSFSX_fseek( LoadFile, mine_fileinfo.texture_offset, SEEK_SET ))
545
                        Error( "Error seeking to texture_offset in gamemine.c" );
546
 
547
                for (int i=0; i< mine_fileinfo.texture_howmany; i++ )
548
                {
549
                        if (PHYSFS_read( LoadFile, &old_tmap_list[i], mine_fileinfo.texture_sizeof, 1 )!=1)
550
                                Error( "Error reading old_tmap_list[i] in gamemine.c" );
551
                }
552
        }
553
 
554
        //=============== GENERATE TEXTURE TRANSLATION TABLE ===============
555
 
556
        translate = 0;
557
 
558
        Assert (NumTextures < MAX_TEXTURES);
559
 
560
        {
561
                hashtable ht;
562
                // Remove all the file extensions in the textures list
563
 
564
                for (uint_fast32_t i = 0; i < NumTextures;i++)  {
565
                        temptr = strchr(&TmapInfo[i].filename[0u], '.');
566
                        if (temptr) *temptr = '\0';
567
                        hashtable_insert( &ht, &TmapInfo[i].filename[0u], i );
568
                }
569
 
570
                // For every texture, search through the texture list
571
                // to find a matching name.
572
                for (int j=0;j<mine_fileinfo.texture_howmany;j++) {
573
                        // Remove this texture name's extension
574
                        temptr = strchr(old_tmap_list[j], '.');
575
                        if (temptr) *temptr = '\0';
576
 
577
                        tmap_xlate_table[j] = hashtable_search( &ht,old_tmap_list[j]);
578
                        if (tmap_xlate_table[j] < 0 )   {
579
                                ;
580
                        }
581
                        if (tmap_xlate_table[j] != j ) translate = 1;
582
                }
583
        }
584
 
585
        //====================== READ VERTEX INFO ==========================
586
 
587
        // New check added to make sure we don't read in too many vertices.
588
        if ( mine_fileinfo.vertex_howmany > MAX_VERTICES )
589
                mine_fileinfo.vertex_howmany = MAX_VERTICES;
590
 
591
        if ( (mine_fileinfo.vertex_offset > -1) && (mine_fileinfo.vertex_howmany > 0))
592
        {
593
                if (PHYSFSX_fseek( LoadFile, mine_fileinfo.vertex_offset, SEEK_SET ))
594
                        Error( "Error seeking to vertex_offset in gamemine.c" );
595
 
596
                range_for (auto &i, partial_range(Vertices, mine_fileinfo.vertex_howmany))
597
                {
598
                        // Set the default values for this vertex
599
                        i.x = 1;
600
                        i.y = 1;
601
                        i.z = 1;
602
 
603
                        if (PHYSFS_read(LoadFile, &i, mine_fileinfo.vertex_sizeof, 1) != 1)
604
                                Error( "Error reading Vertices[i] in gamemine.c" );
605
                }
606
        }
607
 
608
        //==================== READ SEGMENT INFO ===========================
609
 
610
        // New check added to make sure we don't read in too many segments.
611
        if ( mine_fileinfo.segment_howmany > MAX_SEGMENTS ) {
612
                mine_fileinfo.segment_howmany = MAX_SEGMENTS;
613
#if defined(DXX_BUILD_DESCENT_II)
614
                mine_fileinfo.segment2_howmany = MAX_SEGMENTS;
615
#endif
616
        }
617
 
618
        // [commented out by mk on 11/20/94 (weren't we supposed to hit final in October?) because it looks redundant.  I think I'll test it now...]  fuelcen_reset();
619
 
620
        auto &Walls = LevelUniqueWallSubsystemState.Walls;
621
        auto &vcwallptr = Walls.vcptr;
622
        if ( (mine_fileinfo.segment_offset > -1) && (mine_fileinfo.segment_howmany > 0))        {
623
 
624
                if (PHYSFSX_fseek( LoadFile, mine_fileinfo.segment_offset,SEEK_SET ))
625
 
626
                        Error( "Error seeking to segment_offset in gamemine.c" );
627
 
628
                Segments.set_count(mine_fileinfo.segment_howmany);
629
 
630
                for (segnum_t ii = 0; ii < mine_fileinfo.segment_howmany; ++ii)
631
                {
632
                        const auto &i = vmsegptridx(ii);
633
 
634
                        // Set the default values for this segment (clear to zero )
635
                        //memset( &Segments[i], 0, sizeof(segment) );
636
 
637
#if defined(DXX_BUILD_DESCENT_II)
638
                        if (mine_top_fileinfo.fileinfo_version >= 20)
639
                        {
640
                                /*
641
                                 * The format of v20 segment once matched `struct segment`, but
642
                                 * this was not enforced with a `static_assert` or even
643
                                 * commented.  The layout of `struct segment` has since changed
644
                                 * at least five times.  See commit
645
                                 * 2665869c24855040837b1864daedd4cc13ab1793 for details.
646
                                 */
647
                                Error("Sorry, v20 segment support is broken.");
648
                        }
649
                        else
650
#endif
651
                        if (mine_top_fileinfo.fileinfo_version >= 16)
652
                        {
653
                                Error("Sorry, v16 segment support is broken.");
654
#if 0
655
                                v16_segment v16_seg;
656
 
657
                                Assert(mine_fileinfo.segment_sizeof == sizeof(v16_seg));
658
 
659
#if defined(DXX_BUILD_DESCENT_I)
660
                                *i = v16_seg;
661
#elif defined(DXX_BUILD_DESCENT_II)
662
                                i->segnum = v16_seg.segnum;
663
                                // -- Segments[i].pad = v16_seg.pad;
664
 
665
                                for (int j=0; j<MAX_SIDES_PER_SEGMENT; j++)
666
                                        i->sides[j] = v16_seg.sides[j];
667
 
668
                                for (int j=0; j<MAX_SIDES_PER_SEGMENT; j++)
669
                                        i->children[j] = v16_seg.children[j];
670
 
671
                                for (int j=0; j<MAX_VERTICES_PER_SEGMENT; j++)
672
                                        i->verts[j] = v16_seg.verts[j];
673
 
674
                                i->special = v16_seg.special;
675
                                i->station_idx = v16_seg.value;
676
                                i->s2_flags = 0;
677
                                i->matcen_num = v16_seg.matcen_num;
678
                                i->static_light = v16_seg.static_light;
679
#endif
680
#endif
681
                                fuelcen_activate(i);
682
                        }
683
                        else
684
                                Error("Invalid mine version");
685
 
686
                        i->objects = object_none;
687
#if DXX_USE_EDITOR
688
                        i->group = -1;
689
                        #endif
690
 
691
                        if (translate == 1)
692
                                for (int j=0;j<MAX_SIDES_PER_SEGMENT;j++) {
693
                                        unsigned short orient;
694
                                        auto &iusidej = i->unique_segment::sides[j];
695
                                        const auto tmap_xlate = iusidej.tmap_num;
696
                                        iusidej.tmap_num = tmap_xlate_table[tmap_xlate];
697
                                        const auto render = (WALL_IS_DOORWAY(GameBitmaps, Textures, vcwallptr, i, j) & WID_RENDER_FLAG);
698
                                        if (render)
699
                                                if (iusidej.tmap_num < 0)       {
700
                                                        Int3();
701
                                                        iusidej.tmap_num = NumTextures-1;
702
                                                }
703
                                        orient = iusidej.tmap_num2 & (~TMAP_NUM_MASK);
704
                                        if (const auto tmap2_xlate = iusidej.tmap_num2 & TMAP_NUM_MASK)
705
                                        {
706
                                                int xlated_tmap = tmap_xlate_table[tmap2_xlate];
707
 
708
                                                iusidej.tmap_num2 = xlated_tmap | orient;
709
                                                if (render)
710
                                                        if (xlated_tmap <= 0)   {
711
                                                                Int3();
712
                                                                iusidej.tmap_num2 = NumTextures-1;
713
                                                        }
714
                                        }
715
                                }
716
                }
717
 
718
#if defined(DXX_BUILD_DESCENT_II)
719
                if (mine_top_fileinfo.fileinfo_version >= 20)
720
                        range_for (const auto &&segp, vmsegptridx)
721
                        {
722
                                segment2_read(segp, LoadFile);
723
                                fuelcen_activate(segp);
724
                        }
725
#endif
726
        }
727
 
728
        //===================== READ NEWSEGMENT INFO =====================
729
 
730
#if DXX_USE_EDITOR
731
 
732
        {               // Default segment created.
733
                med_create_new_segment({DEFAULT_X_SIZE, DEFAULT_Y_SIZE, DEFAULT_Z_SIZE});               // New_segment = Segments[0];
734
                //memset( &New_segment, 0, sizeof(segment) );
735
        }
736
 
737
        if (mine_editor.newsegment_offset > -1)
738
        {
739
                if (PHYSFSX_fseek( LoadFile, mine_editor.newsegment_offset,SEEK_SET ))
740
                        Error( "Error seeking to newsegment_offset in gamemine.c" );
741
                Error("Sorry, v20 segment support is broken.");
742
        }
743
 
744
        if ( (mine_fileinfo.newseg_verts_offset > -1) && (mine_fileinfo.newseg_verts_howmany > 0))
745
        {
746
                if (PHYSFSX_fseek( LoadFile, mine_fileinfo.newseg_verts_offset, SEEK_SET ))
747
                        Error( "Error seeking to newseg_verts_offset in gamemine.c" );
748
                auto &vmvertptr = Vertices.vmptr;
749
                for (unsigned i = 0; i < mine_fileinfo.newseg_verts_howmany; ++i)
750
                {
751
                        // Set the default values for this vertex
752
                        auto &v = *vmvertptr(NEW_SEGMENT_VERTICES+i);
753
                        v.x = 1;
754
                        v.y = 1;
755
                        v.z = 1;
756
                        if (PHYSFS_read(LoadFile, &v, mine_fileinfo.newseg_verts_sizeof, 1) != 1)
757
                                Error( "Error reading Vertices[NEW_SEGMENT_VERTICES+i] in gamemine.c" );
758
 
759
                        New_segment.verts[i] = NEW_SEGMENT_VERTICES+i;
760
                }
761
        }
762
 
763
        #endif
764
 
765
        //========================= UPDATE VARIABLES ======================
766
 
767
#if DXX_USE_EDITOR
768
 
769
        // Setting to Markedsegp to NULL ignores Curside and Markedside, which
770
        // we want to do when reading in an old file.
771
 
772
        Markedside = mine_editor.Markedside;
773
        Curside = mine_editor.Curside;
774
        range_for (const int i, xrange(10u))
775
                Groupside[i] = mine_editor.Groupside[i];
776
 
777
        Cursegp = mine_editor.current_seg != -1 ? imsegptridx(static_cast<segnum_t>(mine_editor.current_seg)) : imsegptridx(segment_first);
778
        Markedsegp = mine_editor.Markedsegp != -1 ? imsegptridx(static_cast<segnum_t>(mine_editor.Markedsegp)) : segment_none;
779
 
780
        num_groups = 0;
781
        current_group = -1;
782
 
783
        #endif
784
 
785
        LevelSharedVertexState.Num_vertices = mine_fileinfo.vertex_howmany;
786
        Vertices.set_count(LevelSharedVertexState.Num_vertices);
787
        LevelSharedSegmentState.Num_segments = mine_fileinfo.segment_howmany;
788
        Segments.set_count(LevelSharedSegmentState.Num_segments);
789
 
790
        reset_objects(LevelUniqueObjectState, 1);               //one object, the player
791
 
792
#if DXX_USE_EDITOR
793
        Vertices.set_count(MAX_SEGMENT_VERTICES);
794
        Segments.set_count(MAX_SEGMENTS);
795
        set_vertex_counts();
796
        Vertices.set_count(LevelSharedVertexState.Num_vertices);
797
        Segments.set_count(LevelSharedSegmentState.Num_segments);
798
 
799
        warn_if_concave_segments();
800
        #endif
801
 
802
#if DXX_USE_EDITOR
803
        validate_segment_all(LevelSharedSegmentState);
804
        #endif
805
 
806
        //create_local_segment_data();
807
 
808
        //gamemine_find_textures();
809
 
810
        if (mine_top_fileinfo.fileinfo_version < MINE_VERSION )
811
                return 1;               //old version
812
        else
813
                return 0;
814
 
815
}
816
}
817
#endif
818
 
819
#define COMPILED_MINE_VERSION 0
820
 
821
static void read_children(shared_segment &segp, const unsigned bit_mask, PHYSFS_File *const LoadFile)
822
{
823
        for (int bit=0; bit<MAX_SIDES_PER_SEGMENT; bit++) {
824
                if (bit_mask & (1 << bit)) {
825
                        segp.children[bit] = PHYSFSX_readShort(LoadFile);
826
                } else
827
                        segp.children[bit] = segment_none;
828
        }
829
}
830
 
831
static void read_verts(shared_segment &segp, PHYSFS_File *const LoadFile)
832
{
833
        // Read short Segments[segnum].verts[MAX_VERTICES_PER_SEGMENT]
834
        range_for (auto &i, segp.verts)
835
                i = PHYSFSX_readShort(LoadFile);
836
}
837
 
838
static void read_special(shared_segment &segp, const unsigned bit_mask, PHYSFS_File *const LoadFile)
839
{
840
        if (bit_mask & (1 << MAX_SIDES_PER_SEGMENT)) {
841
                // Read ubyte   Segments[segnum].special
842
                segp.special = PHYSFSX_readByte(LoadFile);
843
                // Read byte    Segments[segnum].matcen_num
844
                segp.matcen_num = PHYSFSX_readByte(LoadFile);
845
                // Read short   Segments[segnum].value
846
                segp.station_idx = PHYSFSX_readShort(LoadFile);
847
        } else {
848
                segp.special = 0;
849
                segp.matcen_num = -1;
850
                segp.station_idx = station_none;
851
        }
852
}
853
 
854
namespace dsx {
855
 
856
int load_mine_data_compiled(PHYSFS_File *LoadFile, const char *const Gamesave_current_filename)
857
{
858
        auto &LevelSharedVertexState = LevelSharedSegmentState.get_vertex_state();
859
        auto &Vertices = LevelSharedVertexState.get_vertices();
860
        ubyte   compiled_version;
861
        short   temp_short;
862
        ushort  temp_ushort = 0;
863
        ubyte   bit_mask;
864
 
865
#if defined(DXX_BUILD_DESCENT_II)
866
        LevelSharedSeismicState.Level_shake_frequency = 0;
867
        LevelSharedSeismicState.Level_shake_duration = 0;
868
        d1_pig_present = PHYSFSX_exists(D1_PIGFILE,1);
869
#endif
870
        if (!strcmp(strchr(Gamesave_current_filename, '.'), ".sdl"))
871
                New_file_format_load = 0; // descent 1 shareware
872
        else
873
                New_file_format_load = 1;
874
 
875
        //      For compiled levels, textures map to themselves, prevent tmap_override always being gray,
876
        //      bug which Matt and John refused to acknowledge, so here is Mike, fixing it.
877
        // 
878
        // Although in a cloud of arrogant glee, he forgot to ifdef it on EDITOR!
879
        // (Matt told me to write that!)
880
#if DXX_USE_EDITOR
881
        for (int i=0; i<MAX_TEXTURES; i++)
882
                tmap_xlate_table[i] = i;
883
#endif
884
 
885
//      memset( Segments, 0, sizeof(segment)*MAX_SEGMENTS );
886
        fuelcen_reset();
887
 
888
        //=============================== Reading part ==============================
889
        compiled_version = PHYSFSX_readByte(LoadFile);
890
        (void)compiled_version;
891
 
892
        DXX_POISON_VAR(Vertices, 0xfc);
893
        if (New_file_format_load)
894
                LevelSharedVertexState.Num_vertices = PHYSFSX_readShort(LoadFile);
895
        else
896
                LevelSharedVertexState.Num_vertices = PHYSFSX_readInt(LoadFile);
897
        assert(LevelSharedVertexState.Num_vertices <= MAX_VERTICES);
898
 
899
        DXX_POISON_VAR(Segments, 0xfc);
900
        if (New_file_format_load)
901
                LevelSharedSegmentState.Num_segments = PHYSFSX_readShort(LoadFile);
902
        else
903
                LevelSharedSegmentState.Num_segments = PHYSFSX_readInt(LoadFile);
904
        assert(LevelSharedSegmentState.Num_segments <= MAX_SEGMENTS);
905
 
906
        range_for (auto &i, partial_range(Vertices, LevelSharedVertexState.Num_vertices))
907
                PHYSFSX_readVector(LoadFile, i);
908
 
909
        const auto Num_segments = LevelSharedSegmentState.Num_segments;
910
        for (segnum_t segnum=0; segnum < Num_segments; segnum++ )       {
911
                const auto segp = vmsegptr(segnum);
912
 
913
#if DXX_USE_EDITOR
914
                segp->segnum = segnum;
915
                segp->group = 0;
916
                #endif
917
 
918
                if (New_file_format_load)
919
                        bit_mask = PHYSFSX_readByte(LoadFile);
920
                else
921
                        bit_mask = 0x7f; // read all six children and special stuff...
922
 
923
                if (Gamesave_current_version == 5) { // d2 SHAREWARE level
924
                        read_special(segp,bit_mask,LoadFile);
925
                        read_verts(segp,LoadFile);
926
                        read_children(segp,bit_mask,LoadFile);
927
                } else {
928
                        read_children(segp,bit_mask,LoadFile);
929
                        read_verts(segp,LoadFile);
930
                        if (Gamesave_current_version <= 1) { // descent 1 level
931
                                read_special(segp,bit_mask,LoadFile);
932
                        }
933
                }
934
 
935
                segp->objects = object_none;
936
 
937
                if (Gamesave_current_version <= 5) { // descent 1 thru d2 SHAREWARE level
938
                        // Read fix     Segments[segnum].static_light (shift down 5 bits, write as short)
939
                        temp_ushort = PHYSFSX_readShort(LoadFile);
940
                        segp->static_light      = static_cast<fix>(temp_ushort) << 4;
941
                        //PHYSFS_read( LoadFile, &Segments[segnum].static_light, sizeof(fix), 1 );
942
                }
943
 
944
                // Read the walls as a 6 byte array
945
                if (New_file_format_load)
946
                        bit_mask = PHYSFSX_readByte(LoadFile);
947
                else
948
                        bit_mask = 0x3f; // read all six sides
949
                for (int sidenum=0; sidenum<MAX_SIDES_PER_SEGMENT; sidenum++) {
950
                        ubyte byte_wallnum;
951
 
952
                        auto &sside = segp->shared_segment::sides[sidenum];
953
                        if (bit_mask & (1 << sidenum)) {
954
                                byte_wallnum = PHYSFSX_readByte(LoadFile);
955
                                if ( byte_wallnum == 255 )
956
                                        sside.wall_num = wall_none;
957
                                else
958
                                        sside.wall_num = byte_wallnum;
959
                        } else
960
                                        sside.wall_num = wall_none;
961
                }
962
 
963
                for (int sidenum=0; sidenum<MAX_SIDES_PER_SEGMENT; sidenum++ ) {
964
                        auto &uside = segp->unique_segment::sides[sidenum];
965
                        if (segp->children[sidenum] == segment_none || segp->shared_segment::sides[sidenum].wall_num != wall_none)      {
966
                                // Read short Segments[segnum].sides[sidenum].tmap_num;
967
                                temp_ushort = PHYSFSX_readShort(LoadFile);
968
#if defined(DXX_BUILD_DESCENT_I)
969
                                uside.tmap_num = convert_tmap(temp_ushort & 0x7fff);
970
 
971
                                if (New_file_format_load && !(temp_ushort & 0x8000))
972
                                        uside.tmap_num2 = 0;
973
                                else {
974
                                        // Read short Segments[segnum].sides[sidenum].tmap_num2;
975
                                        uside.tmap_num2 = PHYSFSX_readShort(LoadFile);
976
                                        uside.tmap_num2 =
977
                                                (convert_tmap(uside.tmap_num2 & 0x3fff)) |
978
                                                (uside.tmap_num2 & 0xc000);
979
                                }
980
#elif defined(DXX_BUILD_DESCENT_II)
981
                                if (New_file_format_load) {
982
                                        uside.tmap_num = temp_ushort & 0x7fff;
983
                                } else
984
                                        uside.tmap_num = temp_ushort;
985
 
986
                                if (Gamesave_current_version <= 1)
987
                                        uside.tmap_num = convert_d1_tmap_num(uside.tmap_num);
988
 
989
                                if (New_file_format_load && !(temp_ushort & 0x8000))
990
                                        uside.tmap_num2 = 0;
991
                                else {
992
                                        // Read short Segments[segnum].sides[sidenum].tmap_num2;
993
                                        uside.tmap_num2 = PHYSFSX_readShort(LoadFile);
994
                                        if (Gamesave_current_version <= 1 && uside.tmap_num2 != 0)
995
                                                uside.tmap_num2 = convert_d1_tmap_num(uside.tmap_num2);
996
                                }
997
#endif
998
 
999
                                // Read uvl Segments[segnum].sides[sidenum].uvls[4] (u,v>>5, write as short, l>>1 write as short)
1000
                                range_for (auto &i, uside.uvls) {
1001
                                        temp_short = PHYSFSX_readShort(LoadFile);
1002
                                        i.u = static_cast<fix>(temp_short) << 5;
1003
                                        temp_short = PHYSFSX_readShort(LoadFile);
1004
                                        i.v = static_cast<fix>(temp_short) << 5;
1005
                                        temp_ushort = PHYSFSX_readShort(LoadFile);
1006
                                        i.l = static_cast<fix>(temp_ushort) << 1;
1007
                                        //PHYSFS_read( LoadFile, &i.l, sizeof(fix), 1 );
1008
                                }
1009
                        } else {
1010
                                uside.tmap_num = 0;
1011
                                uside.tmap_num2 = 0;
1012
                                uside.uvls = {};
1013
                        }
1014
                }
1015
        }
1016
 
1017
        Vertices.set_count(LevelSharedVertexState.Num_vertices);
1018
        Segments.set_count(Num_segments);
1019
 
1020
        validate_segment_all(LevelSharedSegmentState);                  // Fill in side type and normals.
1021
 
1022
        range_for (const auto &&pi, vmsegptridx)
1023
        {
1024
                if (Gamesave_current_version > 5)
1025
                        segment2_read(pi, LoadFile);
1026
                fuelcen_activate(pi);
1027
        }
1028
 
1029
        reset_objects(LevelUniqueObjectState, 1);               //one object, the player
1030
 
1031
        return 0;
1032
}
1033
}