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
 * Routines to parse bitmaps.tbl
23
 * Only used for editor, since the registered version of descent 1.
24
 *
25
 */
26
 
27
#include <algorithm>
28
#include <string>
29
#include <stdio.h>
30
#include <stdlib.h>
31
#include <stdarg.h>
32
#include <string.h>
33
#include <ctype.h>
34
 
35
#include "pstypes.h"
36
#include "gr.h"
37
#include "bm.h"
38
#include "u_mem.h"
39
#include "dxxerror.h"
40
#include "object.h"
41
#include "physfsx.h"
42
#include "vclip.h"
43
#include "effects.h"
44
#include "polyobj.h"
45
#include "wall.h"
46
#include "textures.h"
47
#include "game.h"
48
#include "iff.h"
49
#include "hostage.h"
50
#include "powerup.h"
51
#include "laser.h"
52
#include "sounds.h"
53
#include "piggy.h"
54
#include "aistruct.h"
55
#include "robot.h"
56
#include "weapon.h"
57
#include "gauges.h"
58
#include "player.h"
59
#include "endlevel.h"
60
#include "cntrlcen.h"
61
#include "physfs-serial.h"
62
#include "args.h"
63
#include "text.h"
64
#if defined(DXX_BUILD_DESCENT_I)
65
#include "fuelcen.h"
66
#elif defined(DXX_BUILD_DESCENT_II)
67
#include "gamepal.h"
68
#include "interp.h"
69
#endif
70
#include "strutil.h"
71
#if DXX_USE_EDITOR
72
#include "editor/texpage.h"
73
#endif
74
 
75
#include "compiler-cf_assert.h"
76
#include "compiler-range_for.h"
77
#include "partial_range.h"
78
#include "d_enumerate.h"
79
#include "d_range.h"
80
 
81
using std::min;
82
 
83
#define BM_NONE                 -1
84
#define BM_COCKPIT               0
85
#define BM_TEXTURES              2
86
#define BM_UNUSED                        3
87
#define BM_VCLIP                         4
88
#define BM_EFFECTS          5
89
#define BM_ECLIP                         6
90
#define BM_WEAPON                        7
91
#define BM_DEMO                  8
92
#define BM_ROBOTEX          9
93
#define BM_WALL_ANIMS   12
94
#define BM_WCLIP                        13
95
#define BM_ROBOT                        14
96
#define BM_GAUGES                       20
97
 
98
namespace {
99
 
100
uint8_t wall_explodes_flag;
101
uint8_t wall_blastable_flag;
102
uint8_t wall_hidden_flag;
103
uint8_t tmap1_flag;             //flag if this is used as tmap_num (not tmap_num2)
104
 
105
}
106
 
107
#if defined(DXX_BUILD_DESCENT_I)
108
static short            N_ObjBitmaps=0;
109
#elif defined(DXX_BUILD_DESCENT_II)
110
#define BM_GAUGES_HIRES 21
111
#endif
112
 
113
static short            N_ObjBitmapPtrs=0;
114
static int                      Num_robot_ais = 0;
115
namespace dsx {
116
#if DXX_USE_EDITOR
117
powerup_names_array Powerup_names;
118
robot_names_array Robot_names;
119
#endif
120
}
121
 
122
//---------------- Internal variables ---------------------------
123
static int                      SuperX = -1;
124
static int                      Installed=0;
125
static short            tmap_count = 0;
126
static short            texture_count = 0;
127
#if defined(DXX_BUILD_DESCENT_I)
128
static unsigned         clip_count;
129
static unsigned         clip_num;
130
static uint16_t         frames;
131
#elif defined(DXX_BUILD_DESCENT_II)
132
static char             *arg;
133
static short            clip_count = 0;
134
static short            clip_num;
135
static short            frames;
136
static char             *dest_bm;               //clip number to play when destroyed
137
#endif
138
static short            sound_num;
139
static float            play_time;
140
static int                      hit_sound = -1;
141
static sbyte            bm_flag = BM_NONE;
142
static int                      abm_flag = 0;
143
static int                      rod_flag = 0;
144
static short            wall_open_sound, wall_close_sound;
145
static float            vlighting=0;
146
static int                      obj_eclip;
147
static int                      dest_vclip;             //what vclip to play when exploding
148
static int                      dest_eclip;             //what eclip to play when exploding
149
static fix                      dest_size;              //3d size of explosion
150
static int                      crit_clip;              //clip number to play when destroyed
151
static int                      crit_flag;              //flag if this is a destroyed eclip
152
static int                      num_sounds=0;
153
 
154
static int linenum;             //line int table currently being parsed
155
 
156
//------------------- Useful macros and variables ---------------
157
 
158
#define IFTOK(str) if (!strcmp(arg, str))
159
 
160
//      For the sake of LINT, defining prototypes to module's functions
161
#if defined(DXX_BUILD_DESCENT_I)
162
static void bm_read_sound(char *&arg, int skip, int pc_shareware);
163
static void bm_read_robot_ai(char *&arg, int skip);
164
static void bm_read_robot(char *&arg, int skip);
165
static void bm_read_object(char *&arg, int skip);
166
static void bm_read_player_ship(char *&arg, int skip);
167
namespace dsx {
168
static void bm_read_some_file(d_vclip_array &Vclip, const std::string &dest_bm, char *&arg, int skip);
169
}
170
static void bm_read_weapon(char *&arg, int skip, int unused_flag);
171
static void bm_read_powerup(char *&arg, int unused_flag);
172
static void bm_read_hostage(char *&arg);
173
static void verify_textures();
174
#elif defined(DXX_BUILD_DESCENT_II)
175
static void bm_read_alias(void);
176
static void bm_read_marker(void);
177
static void bm_read_robot_ai(int skip);
178
static void bm_read_powerup(int unused_flag);
179
static void bm_read_hostage(void);
180
static void bm_read_robot(int skip);
181
static void bm_read_weapon(int skip, int unused_flag);
182
static void bm_read_reactor(void);
183
static void bm_read_exitmodel(void);
184
static void bm_read_player_ship(void);
185
namespace dsx {
186
static void bm_read_some_file(d_vclip_array &Vclip, int skip);
187
}
188
static void bm_read_sound(int skip);
189
static void clear_to_end_of_line(void);
190
static void verify_textures(void);
191
#endif
192
 
193
//---------------------------------------------------------------
194
int compute_average_pixel(grs_bitmap *n)
195
{
196
        int     total_red, total_green, total_blue;
197
 
198
#if defined(DXX_BUILD_DESCENT_II)
199
        auto pptr = n->bm_data;
200
#endif
201
        const unsigned bm_h = n->bm_h, bm_w = n->bm_w;
202
 
203
        total_red = 0;
204
        total_green = 0;
205
        total_blue = 0;
206
 
207
        const auto product = (bm_h * bm_w);
208
#if defined(DXX_BUILD_DESCENT_I)
209
        for (unsigned row = 0; row < bm_h; row++)
210
                for (unsigned column = 0; column < bm_w; column++)
211
#elif defined(DXX_BUILD_DESCENT_II)
212
        for (auto counter = product; counter--;)
213
#endif
214
        {
215
#if defined(DXX_BUILD_DESCENT_I)
216
                const auto color = gr_gpixel (*n, column, row);
217
                const auto &p = gr_palette[color];
218
#elif defined(DXX_BUILD_DESCENT_II)
219
                const auto &p = gr_palette[*pptr++];
220
#endif
221
                total_red += p.r;
222
                total_green += p.g;
223
                total_blue += p.b;
224
                }
225
 
226
        total_red /= product;
227
        total_green /= product;
228
        total_blue /= product;
229
 
230
        return BM_XRGB(total_red/2, total_green/2, total_blue/2);
231
}
232
 
233
//---------------------------------------------------------------
234
// Loads a bitmap from either the piggy file, a r64 file, or a
235
// whatever extension is passed.
236
 
237
static bitmap_index bm_load_sub(const int skip, const char *const filename)
238
{
239
        bitmap_index bitmap_num;
240
        palette_array_t newpal;
241
        int iff_error;          //reference parm to avoid warning message
242
 
243
        bitmap_num.index = 0;
244
 
245
        if (skip) {
246
                return bitmap_num;
247
        }
248
 
249
        std::array<char, 20> fname{};
250
#if defined(DXX_BUILD_DESCENT_I)
251
        removeext(filename, fname);
252
#elif defined(DXX_BUILD_DESCENT_II)
253
        struct splitpath_t path;
254
        d_splitpath(  filename, &path);
255
        if (path.base_end - path.base_start >= fname.size())
256
                Error("File <%s> - bitmap error, filename too long", filename);
257
        memcpy(fname.data(), path.base_start, path.base_end - path.base_start);
258
#endif
259
 
260
        bitmap_num = piggy_find_bitmap(fname.data());
261
        if (bitmap_num.index)   {
262
                return bitmap_num;
263
        }
264
 
265
        grs_bitmap n;
266
        iff_error = iff_read_bitmap(filename, n, &newpal);
267
        if (iff_error != IFF_NO_ERROR)          {
268
                Error("File <%s> - IFF error: %s, line %d",filename,iff_errormsg(iff_error),linenum);
269
        }
270
 
271
        gr_remap_bitmap_good(n, newpal, iff_has_transparency ? iff_transparent_color : -1, SuperX);
272
 
273
#if !DXX_USE_OGL
274
        n.avg_color = compute_average_pixel(&n);
275
#endif
276
 
277
        bitmap_num = piggy_register_bitmap(n, fname.data(), 0);
278
        return bitmap_num;
279
}
280
 
281
static void ab_load(int skip, const char * filename, std::array<bitmap_index, MAX_BITMAPS_PER_BRUSH> &bmp, unsigned *nframes )
282
{
283
        bitmap_index bi;
284
        int iff_error;          //reference parm to avoid warning message
285
        palette_array_t newpal;
286
        std::array<char, 24> tempname;
287
 
288
        if (skip) {
289
                Assert( bogus_bitmap_initialized != 0 );
290
#if defined(DXX_BUILD_DESCENT_I)
291
                bmp[0] = piggy_register_bitmap(bogus_bitmap, "bogus", 0);
292
#elif defined(DXX_BUILD_DESCENT_II)
293
                bmp[0].index = 0;               //index of bogus bitmap==0 (I think)            //&bogus_bitmap;
294
#endif
295
                *nframes = 1;
296
                return;
297
        }
298
 
299
 
300
#if defined(DXX_BUILD_DESCENT_I)
301
        std::array<char, 20> fname;
302
        removeext(filename, fname);
303
#elif defined(DXX_BUILD_DESCENT_II)
304
        struct splitpath_t path;
305
        d_splitpath( filename, &path);
306
#endif
307
 
308
        {
309
        unsigned i;
310
        for (i=0; i<MAX_BITMAPS_PER_BRUSH; i++ )        {
311
#if defined(DXX_BUILD_DESCENT_I)
312
                snprintf(tempname.data(), tempname.size(), "%.16s#%d", fname.data(), i);
313
#elif defined(DXX_BUILD_DESCENT_II)
314
                snprintf(tempname.data(), tempname.size(), "%.*s#%d", DXX_ptrdiff_cast_int(path.base_end - path.base_start), path.base_start, i);
315
#endif
316
                bi = piggy_find_bitmap(tempname.data());
317
                if ( !bi.index )
318
                        break;
319
                bmp[i] = bi;
320
        }
321
 
322
        if (i) {
323
                *nframes = i;
324
                return;
325
        }
326
        }
327
 
328
//      Note that last argument passes an address to the array newpal (which is a pointer).
329
//      type mismatch found using lint, will substitute this line with an adjusted
330
//      one.  If fatal error, then it can be easily changed.
331
        std::array<std::unique_ptr<grs_main_bitmap>, MAX_BITMAPS_PER_BRUSH> bm;
332
        iff_error = iff_read_animbrush(filename,bm,nframes,newpal);
333
        if (iff_error != IFF_NO_ERROR)  {
334
                Error("File <%s> - IFF error: %s, line %d",filename,iff_errormsg(iff_error),linenum);
335
        }
336
 
337
        const auto nf = *nframes;
338
#if defined(DXX_BUILD_DESCENT_I)
339
        if (nf >= bm.size())
340
                return;
341
#endif
342
        range_for (const uint_fast32_t i, xrange(nf))
343
        {
344
                cf_assert(i < bm.size());
345
#if defined(DXX_BUILD_DESCENT_I)
346
                snprintf(tempname.data(), tempname.size(), "%s#%" PRIuFAST32, fname.data(), i);
347
#elif defined(DXX_BUILD_DESCENT_II)
348
                snprintf(tempname.data(), tempname.size(), "%.*s#%" PRIuFAST32, DXX_ptrdiff_cast_int(path.base_end - path.base_start), path.base_start, i );
349
#endif
350
                gr_remap_bitmap_good(*bm[i].get(), newpal, iff_has_transparency ? iff_transparent_color : -1, SuperX);
351
#if !DXX_USE_OGL
352
                bm[i]->avg_color = compute_average_pixel(bm[i].get());
353
#endif
354
                bmp[i] = piggy_register_bitmap(*bm[i].get(), tempname.data(), 0);
355
        }
356
}
357
 
358
int ds_load(int skip, const char * filename )   {
359
        int i;
360
        digi_sound n;
361
        char rawname[100];
362
 
363
        if (skip) {
364
                // We tell piggy_register_sound it's in the pig file, when in actual fact it's in no file
365
                // This just tells piggy_close not to attempt to free it
366
                return piggy_register_sound( &bogus_sound, "bogus", 1 );
367
        }
368
 
369
        std::array<char, 20> fname;
370
        removeext(filename, fname);
371
#if defined(DXX_BUILD_DESCENT_I)
372
        snprintf(rawname, sizeof(rawname), "Sounds/%s.raw", fname.data());
373
#elif defined(DXX_BUILD_DESCENT_II)
374
        snprintf(rawname, sizeof(rawname), "Sounds/%s.%s", fname.data(), (GameArg.SndDigiSampleRate==SAMPLE_RATE_22K) ? "r22" : "raw");
375
#endif
376
 
377
        i = piggy_find_sound(fname.data());
378
        if (i!=255)     {
379
                return i;
380
        }
381
        if (auto cfp = PHYSFSX_openReadBuffered(rawname))
382
        {
383
                n.length        = PHYSFS_fileLength( cfp );
384
                MALLOC( n.data, ubyte, n.length );
385
                PHYSFS_read( cfp, n.data, 1, n.length );
386
                n.bits = 8;
387
                n.freq = 11025;
388
        } else {
389
                return 255;
390
        }
391
        i = piggy_register_sound(&n, fname.data(), 0);
392
        return i;
393
}
394
 
395
//parse a float
396
static float get_float()
397
{
398
        char *xarg;
399
 
400
        xarg = strtok( NULL, space_tab );
401
        return atof( xarg );
402
}
403
 
404
//parse an int
405
static int get_int()
406
{
407
        char *xarg;
408
 
409
        xarg = strtok( NULL, space_tab );
410
        return atoi( xarg );
411
}
412
 
413
// rotates a byte left one bit, preserving the bit falling off the right
414
//void
415
//rotate_left(char *c)
416
//{
417
//      int found;
418
//
419
//      found = 0;
420
//      if (*c & 0x80)
421
//              found = 1;
422
//      *c = *c << 1;
423
//      if (found)
424
//              *c |= 0x01;
425
//}
426
 
427
#if defined(DXX_BUILD_DESCENT_II)
428
//loads a texture and returns the texture num
429
static int get_texture(char *name)
430
{
431
        auto &TmapInfo = LevelUniqueTmapInfoState.TmapInfo;
432
        char short_name[FILENAME_LEN];
433
        int i;
434
 
435
        strcpy(short_name,name);
436
        REMOVE_DOTS(short_name);
437
        for (i=0;i<texture_count;i++)
438
                if (!d_stricmp(TmapInfo[i].filename,short_name))
439
                        break;
440
        if (i==texture_count) {
441
                Textures[texture_count] = bm_load_sub(0, name);
442
                TmapInfo[texture_count].filename.copy_if(short_name);
443
                texture_count++;
444
                Assert(texture_count < MAX_TEXTURES);
445
                NumTextures = texture_count;
446
        }
447
 
448
        return i;
449
}
450
 
451
#define DEFAULT_PIG_PALETTE     "groupa.256"
452
#endif
453
 
454
#define LINEBUF_SIZE 600
455
 
456
namespace dsx {
457
 
458
//-----------------------------------------------------------------
459
// Initializes all properties and bitmaps from BITMAPS.TBL file.
460
// This is called when the editor is IN.
461
// If no editor, properties_read_cmp() is called.
462
int gamedata_read_tbl(d_vclip_array &Vclip, int pc_shareware)
463
{
464
        auto &Effects = LevelUniqueEffectsClipState.Effects;
465
        auto &TmapInfo = LevelUniqueTmapInfoState.TmapInfo;
466
        auto &WallAnims = GameSharedState.WallAnims;
467
        int     have_bin_tbl;
468
 
469
#if defined(DXX_BUILD_DESCENT_I)
470
        std::string dest_bm;
471
        ObjType[0] = OL_PLAYER;
472
        ObjId[0] = 0;
473
        Num_total_object_types = 1;
474
#elif defined(DXX_BUILD_DESCENT_II)
475
        // Open BITMAPS.TBL for reading.
476
        have_bin_tbl = 0;
477
        auto InfoFile = PHYSFSX_openReadBuffered("BITMAPS.TBL");
478
        if (!InfoFile)
479
        {
480
                InfoFile = PHYSFSX_openReadBuffered("BITMAPS.BIN");
481
                if (!InfoFile)
482
                        return 0;       //missing BITMAPS.TBL and BITMAPS.BIN file
483
                have_bin_tbl = 1;
484
        }
485
 
486
        gr_use_palette_table(DEFAULT_PIG_PALETTE);
487
 
488
        load_palette(DEFAULT_PIG_PALETTE,-2,0);         //special: tell palette code which pig is loaded
489
#endif
490
 
491
        for (unsigned i = 0; i < MAX_SOUNDS; ++i)
492
        {
493
                Sounds[i] = 255;
494
                AltSounds[i] = 255;
495
        }
496
 
497
        DXX_MAKE_VAR_UNDEFINED(TmapInfo);
498
        range_for (auto &ti, TmapInfo)
499
        {
500
                ti.eclip_num = eclip_none;
501
                ti.flags = 0;
502
#if defined(DXX_BUILD_DESCENT_II)
503
                ti.slide_u = ti.slide_v = 0;
504
                ti.destroyed = -1;
505
#endif
506
        }
507
 
508
#if defined(DXX_BUILD_DESCENT_II)
509
        DXX_MAKE_VAR_UNDEFINED(Reactors);
510
        range_for (auto &i, Reactors)
511
                i.model_num = -1;
512
#endif
513
 
514
        Num_effects = 0;
515
        DXX_MAKE_VAR_UNDEFINED(Effects);
516
        range_for (auto &ec, Effects)
517
        {
518
                //Effects[i].bm_ptr = (grs_bitmap **) -1;
519
                ec.changing_wall_texture = -1;
520
                ec.changing_object_texture = -1;
521
                ec.segnum = segment_none;
522
                ec.vc.num_frames = -1;          //another mark of being unused
523
        }
524
 
525
        for (unsigned i = 0; i < MAX_POLYGON_MODELS; ++i)
526
                Dying_modelnums[i] = Dead_modelnums[i] = -1;
527
 
528
        Num_vclips = 0;
529
        DXX_MAKE_VAR_UNDEFINED(Vclip);
530
        range_for (auto &vc, Vclip)
531
        {
532
                vc.num_frames = -1;
533
                vc.flags = 0;
534
        }
535
 
536
        DXX_MAKE_VAR_UNDEFINED(WallAnims);
537
        range_for (auto &wa, WallAnims)
538
                wa.num_frames = wclip_frames_none;
539
        Num_wall_anims = 0;
540
 
541
        if (Installed)
542
                return 1;
543
 
544
        Installed = 1;
545
 
546
#if defined(DXX_BUILD_DESCENT_I)
547
        // Open BITMAPS.TBL for reading.
548
        have_bin_tbl = 0;
549
        auto InfoFile = PHYSFSX_openReadBuffered("BITMAPS.TBL");
550
        if (!InfoFile)
551
        {
552
                InfoFile = PHYSFSX_openReadBuffered("BITMAPS.BIN");
553
                if (!InfoFile)
554
                        Error("Missing BITMAPS.TBL and BITMAPS.BIN file\n");
555
                have_bin_tbl = 1;
556
        }
557
#endif
558
        linenum = 0;
559
 
560
        PHYSFSX_fseek( InfoFile, 0L, SEEK_SET);
561
 
562
        PHYSFSX_gets_line_t<LINEBUF_SIZE> inputline;
563
        while (PHYSFSX_fgets(inputline, InfoFile)) {
564
                int l;
565
                const char *temp_ptr;
566
                int skip;
567
 
568
                linenum++;
569
                if (have_bin_tbl) {                             // is this a binary tbl file
570
                        decode_text_line (inputline);
571
                } else {
572
                        while (inputline[(l=strlen(inputline))-2]=='\\') {
573
                                if (!isspace(inputline[l-3])) {         //if not space before backslash...
574
                                        inputline[l-2] = ' ';                           //add one
575
                                        l++;
576
                                }
577
                                PHYSFSX_fgets(inputline,InfoFile,l-2);
578
                                linenum++;
579
                        }
580
                }
581
 
582
                REMOVE_EOL(inputline);
583
                if (strchr(inputline, ';')!=NULL) REMOVE_COMMENTS(inputline);
584
 
585
                if (strlen(inputline) == LINEBUF_SIZE-1)
586
                        Error("Possible line truncation in BITMAPS.TBL on line %d\n",linenum);
587
 
588
                SuperX = -1;
589
 
590
                if ( (temp_ptr=strstr( inputline, "superx=" )) )        {
591
                        /* Historically, this was done with atoi, so the input
592
                         * source was allowed to have unconvertible characters.
593
                         * Accept such lines by ignoring any trailing content.
594
                         */
595
                        SuperX = strtol(&temp_ptr[7], nullptr, 10);
596
#if defined(DXX_BUILD_DESCENT_II)
597
                        Assert(SuperX == 254);
598
                                //the superx color isn't kept around, so the new piggy regeneration
599
                                //code doesn't know what it is, so it assumes that it's 254, so
600
                                //this code requires that it be 254
601
#endif
602
                }
603
 
604
#if defined(DXX_BUILD_DESCENT_I)
605
                char *arg = strtok( inputline, space_tab );
606
#elif defined(DXX_BUILD_DESCENT_II)
607
                arg = strtok( inputline, space_tab );
608
#endif
609
                if (arg && arg[0] == '@')
610
                {
611
                        arg++;
612
                        skip = pc_shareware;
613
                } else
614
                        skip = 0;
615
 
616
                while (arg != NULL )
617
                        {
618
                        // Check all possible flags and defines.
619
                        if (*arg == '$') bm_flag = BM_NONE; // reset to no flags as default.
620
 
621
                        IFTOK("$COCKPIT")                       bm_flag = BM_COCKPIT;
622
                        else IFTOK("$GAUGES")           {bm_flag = BM_GAUGES;   clip_count = 0;}
623
#if defined(DXX_BUILD_DESCENT_I)
624
                        else IFTOK("$SOUND")            bm_read_sound(arg, skip, pc_shareware);
625
#elif defined(DXX_BUILD_DESCENT_II)
626
                        else IFTOK("$GAUGES_HIRES"){bm_flag = BM_GAUGES_HIRES; clip_count = 0;}
627
                        else IFTOK("$ALIAS")                    bm_read_alias();
628
                        else IFTOK("$SOUND")            bm_read_sound(skip);
629
#endif
630
                        else IFTOK("$DOOR_ANIMS")       bm_flag = BM_WALL_ANIMS;
631
                        else IFTOK("$WALL_ANIMS")       bm_flag = BM_WALL_ANIMS;
632
                        else IFTOK("$TEXTURES")         bm_flag = BM_TEXTURES;
633
                        else IFTOK("$VCLIP")                    {bm_flag = BM_VCLIP;            vlighting = 0;  clip_count = 0;}
634
                        else IFTOK("$ECLIP")
635
                        {
636
                                bm_flag = BM_ECLIP;
637
                                vlighting = 0;
638
                                clip_count = 0;
639
                                obj_eclip=0;
640
#if defined(DXX_BUILD_DESCENT_I)
641
                                dest_bm.clear();
642
#elif defined(DXX_BUILD_DESCENT_II)
643
                                dest_bm=NULL;
644
#endif
645
                                dest_vclip=vclip_none;
646
                                dest_eclip=eclip_none;
647
                                dest_size=-1;
648
                                crit_clip=-1;
649
                                crit_flag=0;
650
                                sound_num=sound_none;
651
                        }
652
                        else IFTOK("$WCLIP")
653
                        {
654
                                bm_flag = BM_WCLIP;
655
                                vlighting = 0;
656
                                clip_count = 0;
657
                                wall_open_sound=wall_close_sound=sound_none;
658
                                wall_explodes_flag = 0;
659
                                wall_blastable_flag = 0;
660
                                tmap1_flag=0;
661
                                wall_hidden_flag = 0;
662
                        }
663
 
664
                        else IFTOK("$EFFECTS")          {bm_flag = BM_EFFECTS;  clip_num = 0;}
665
 
666
#if DXX_USE_EDITOR
667
                        else IFTOK("!METALS_FLAG")              TextureMetals = texture_count;
668
                        else IFTOK("!LIGHTS_FLAG")              TextureLights = texture_count;
669
                        else IFTOK("!EFFECTS_FLAG")     TextureEffects = texture_count;
670
                        #else
671
#if defined(DXX_BUILD_DESCENT_I)
672
                        else IFTOK("!METALS_FLAG") ;
673
                        else IFTOK("!LIGHTS_FLAG") ;
674
                        else IFTOK("!EFFECTS_FLAG") ;
675
#endif
676
                        #endif
677
 
678
                        else IFTOK("lighting")                  TmapInfo[texture_count-1].lighting = fl2f(get_float());
679
                        else IFTOK("damage")                    TmapInfo[texture_count-1].damage = fl2f(get_float());
680
                        else IFTOK("volatile")                  TmapInfo[texture_count-1].flags |= TMI_VOLATILE;
681
#if defined(DXX_BUILD_DESCENT_II)
682
                        else IFTOK("goal_blue")                 TmapInfo[texture_count-1].flags |= TMI_GOAL_BLUE;
683
                        else IFTOK("goal_red")                  TmapInfo[texture_count-1].flags |= TMI_GOAL_RED;
684
                        else IFTOK("water")                             TmapInfo[texture_count-1].flags |= TMI_WATER;
685
                        else IFTOK("force_field")               TmapInfo[texture_count-1].flags |= TMI_FORCE_FIELD;
686
                        else IFTOK("slide")                             {TmapInfo[texture_count-1].slide_u = fl2f(get_float())>>8; TmapInfo[texture_count-1].slide_v = fl2f(get_float())>>8;}
687
                        else IFTOK("destroyed")                 {int t=texture_count-1; TmapInfo[t].destroyed = get_texture(strtok( NULL, space_tab ));}
688
#endif
689
                        //else IFTOK("Num_effects")             Num_effects = get_int();
690
                        else IFTOK("Num_wall_anims")    Num_wall_anims = get_int();
691
                        else IFTOK("clip_num")                  clip_num = get_int();
692
#if defined(DXX_BUILD_DESCENT_I)
693
                        else IFTOK("dest_bm")
694
                        {
695
                                char *p = strtok( NULL, space_tab );
696
                                if (p)
697
                                        dest_bm = p;
698
                                else
699
                                        dest_bm.clear();
700
                        }
701
#elif defined(DXX_BUILD_DESCENT_II)
702
                        else IFTOK("dest_bm")                   dest_bm = strtok( NULL, space_tab );
703
#endif
704
                        else IFTOK("dest_vclip")                dest_vclip = get_int();
705
                        else IFTOK("dest_eclip")                dest_eclip = get_int();
706
                        else IFTOK("dest_size")                 dest_size = fl2f(get_float());
707
                        else IFTOK("crit_clip")                 crit_clip = get_int();
708
                        else IFTOK("crit_flag")                 crit_flag = get_int();
709
                        else IFTOK("sound_num")                 sound_num = get_int();
710
                        else IFTOK("frames")                    frames = get_int();
711
                        else IFTOK("time")                              play_time = get_float();
712
                        else IFTOK("obj_eclip")                 obj_eclip = get_int();
713
                        else IFTOK("hit_sound")                 hit_sound = get_int();
714
                        else IFTOK("abm_flag")                  abm_flag = get_int();
715
                        else IFTOK("tmap1_flag")                tmap1_flag = get_int() ? WCF_TMAP1 : 0;
716
                        else IFTOK("vlighting")                 vlighting = get_float();
717
                        else IFTOK("rod_flag")                  rod_flag = get_int();
718
                        else IFTOK("superx")                    get_int();
719
                        else IFTOK("open_sound")                wall_open_sound = get_int();
720
                        else IFTOK("close_sound")               wall_close_sound = get_int();
721
                        else IFTOK("explodes")                  wall_explodes_flag = get_int() ? WCF_EXPLODES : 0;
722
                        else IFTOK("blastable")                 wall_blastable_flag = get_int() ? WCF_BLASTABLE : 0;
723
                        else IFTOK("hidden")                    wall_hidden_flag = get_int() ? WCF_HIDDEN : 0;
724
#if defined(DXX_BUILD_DESCENT_I)
725
                        else IFTOK("$ROBOT_AI")                 bm_read_robot_ai(arg, skip);
726
 
727
                        else IFTOK("$POWERUP")                  {bm_read_powerup(arg, 0);               continue;}
728
                        else IFTOK("$POWERUP_UNUSED")   {bm_read_powerup(arg, 1);               continue;}
729
                        else IFTOK("$HOSTAGE")                  {bm_read_hostage(arg);          continue;}
730
                        else IFTOK("$ROBOT")                            {bm_read_robot(arg, skip);                      continue;}
731
                        else IFTOK("$WEAPON")                   {bm_read_weapon(arg, skip, 0);          continue;}
732
                        else IFTOK("$WEAPON_UNUSED")    {bm_read_weapon(arg, skip, 1);          continue;}
733
                        else IFTOK("$OBJECT")                   {bm_read_object(arg, skip);             continue;}
734
                        else IFTOK("$PLAYER_SHIP")              {bm_read_player_ship(arg, skip);        continue;}
735
#elif defined(DXX_BUILD_DESCENT_II)
736
                        else IFTOK("$ROBOT_AI")                 bm_read_robot_ai(skip);
737
 
738
                        else IFTOK("$POWERUP")                  {bm_read_powerup(0);            continue;}
739
                        else IFTOK("$POWERUP_UNUSED")   {bm_read_powerup(1);            continue;}
740
                        else IFTOK("$HOSTAGE")                  {bm_read_hostage();             continue;}
741
                        else IFTOK("$ROBOT")                            {bm_read_robot(skip);                   continue;}
742
                        else IFTOK("$WEAPON")                   {bm_read_weapon(skip, 0);               continue;}
743
                        else IFTOK("$WEAPON_UNUSED")    {bm_read_weapon(skip, 1);               continue;}
744
                        else IFTOK("$REACTOR")                  {bm_read_reactor();             continue;}
745
                        else IFTOK("$MARKER")                   {bm_read_marker();              continue;}
746
                        else IFTOK("$PLAYER_SHIP")              {bm_read_player_ship(); continue;}
747
                        else IFTOK("$EXIT") {
748
                                if (pc_shareware)
749
                                        bm_read_exitmodel();
750
                                else
751
                                        clear_to_end_of_line();
752
                                continue;
753
                        }
754
#endif
755
                        else    {               //not a special token, must be a bitmap!
756
 
757
                                // Remove any illegal/unwanted spaces and tabs at this point.
758
                                while ((*arg=='\t') || (*arg==' ')) arg++;
759
                                if (*arg == '\0') { break; }
760
 
761
#if defined(DXX_BUILD_DESCENT_II)
762
                                //check for '=' in token, indicating error
763
                                if (strchr(arg,'='))
764
                                        Error("Unknown token <'%s'> on line %d of BITMAPS.TBL",arg,linenum);
765
#endif
766
 
767
                                // Otherwise, 'arg' is apparently a bitmap filename.
768
                                // Load bitmap and process it below:
769
#if defined(DXX_BUILD_DESCENT_I)
770
                                bm_read_some_file(Vclip, dest_bm, arg, skip);
771
#elif defined(DXX_BUILD_DESCENT_II)
772
                                bm_read_some_file(Vclip, skip);
773
#endif
774
 
775
                        }
776
 
777
                        arg = strtok( NULL, equal_space );
778
                        continue;
779
      }
780
        }
781
 
782
        NumTextures = texture_count;
783
        LevelUniqueTmapInfoState.Num_tmaps = tmap_count;
784
 
785
#if defined(DXX_BUILD_DESCENT_II)
786
        Textures[NumTextures++].index = 0;              //entry for bogus tmap
787
        InfoFile.reset();
788
#endif
789
        assert(LevelSharedRobotInfoState.N_robot_types == Num_robot_ais);               //should be one ai info per robot
790
 
791
        verify_textures();
792
 
793
        //check for refereced but unused clip count
794
        range_for (auto &&en, enumerate(Effects))
795
        {
796
                auto &e = en.value;
797
                if ((e.changing_wall_texture != -1 || e.changing_object_texture != -1) && e.vc.num_frames == ~0u)
798
                        Error("EClip %" PRIuFAST32 " referenced (by polygon object?), but not defined", en.idx);
799
        }
800
 
801
#if defined(DXX_BUILD_DESCENT_II)
802
        #ifndef NDEBUG
803
        {
804
                //make sure all alt sounds refer to valid main sounds
805
                for (unsigned i = 0; i < num_sounds; ++i)
806
                {
807
                        int alt = AltSounds[i];
808
                        Assert(alt==0 || alt==-1 || Sounds[alt]!=255);
809
                }
810
        }
811
        #endif
812
 
813
        gr_use_palette_table(D2_DEFAULT_PALETTE);
814
#endif
815
 
816
        return 0;
817
}
818
 
819
}
820
 
821
void verify_textures()
822
{
823
#if defined(DXX_BUILD_DESCENT_II)
824
        auto &Effects = LevelUniqueEffectsClipState.Effects;
825
#endif
826
        grs_bitmap * bmp;
827
        int j;
828
        j=0;
829
        const auto Num_tmaps = LevelUniqueTmapInfoState.Num_tmaps;
830
        for (uint_fast32_t i = 0; i < Num_tmaps; ++i)
831
        {
832
                bmp = &GameBitmaps[Textures[i].index];
833
                if ( (bmp->bm_w!=64)||(bmp->bm_h!=64)||(bmp->bm_rowsize!=64) )  {
834
                        j++;
835
                }
836
        }
837
        if (j)
838
                Error("%d textures were not 64x64.",j);
839
 
840
#if defined(DXX_BUILD_DESCENT_II)
841
        for (uint_fast32_t i = 0; i < Num_effects; ++i)
842
                if (Effects[i].changing_object_texture != -1)
843
                        if (GameBitmaps[ObjBitmaps[Effects[i].changing_object_texture].index].bm_w!=64 || GameBitmaps[ObjBitmaps[Effects[i].changing_object_texture].index].bm_h!=64)
844
                                Error("Effect %" PRIuFAST32 " is used on object, but is not 64x64",i);
845
#endif
846
}
847
 
848
#if defined(DXX_BUILD_DESCENT_II)
849
void bm_read_alias()
850
{
851
        char *t;
852
 
853
        Assert(Num_aliases < MAX_ALIASES);
854
 
855
        t = strtok( NULL, space_tab );  strncpy(alias_list[Num_aliases].alias_name,t,sizeof(alias_list[Num_aliases].alias_name));
856
        t = strtok( NULL, space_tab );  strncpy(alias_list[Num_aliases].file_name,t,sizeof(alias_list[Num_aliases].file_name));
857
 
858
        Num_aliases++;
859
}
860
#endif
861
 
862
static void set_lighting_flag(grs_bitmap &bmp)
863
{
864
        bmp.set_flag_mask(vlighting < 0, BM_FLAG_NO_LIGHTING);
865
}
866
 
867
static void set_texture_name(const char *name)
868
{
869
        auto &TmapInfo = LevelUniqueTmapInfoState.TmapInfo;
870
        TmapInfo[texture_count].filename.copy_if(name, FILENAME_LEN);
871
        REMOVE_DOTS(&TmapInfo[texture_count].filename[0u]);
872
}
873
 
874
#if defined(DXX_BUILD_DESCENT_I)
875
static void bm_read_eclip(const std::string &dest_bm, const char *const arg, int skip)
876
#elif defined(DXX_BUILD_DESCENT_II)
877
static void bm_read_eclip(int skip)
878
#endif
879
{
880
        auto &Effects = LevelUniqueEffectsClipState.Effects;
881
        auto &TmapInfo = LevelUniqueTmapInfoState.TmapInfo;
882
        bitmap_index bitmap;
883
 
884
        assert(clip_num < Effects.size());
885
 
886
        if (clip_num+1 > Num_effects)
887
                Num_effects = clip_num+1;
888
 
889
        Effects[clip_num].flags = 0;
890
 
891
#if defined(DXX_BUILD_DESCENT_II)
892
        unsigned dest_bm_num = 0;
893
        //load the dest bitmap first, so that after this routine, the last-loaded
894
        //texture will be the monitor, so that lighting parameter will be applied
895
        //to the correct texture
896
        if (dest_bm) {                  //deal with bitmap for blown up clip
897
                d_fname short_name;
898
                int i;
899
                short_name.copy_if(dest_bm, FILENAME_LEN);
900
                REMOVE_DOTS(&short_name[0u]);
901
                for (i=0;i<texture_count;i++)
902
                        if (!d_stricmp(TmapInfo[i].filename,short_name))
903
                                break;
904
                if (i==texture_count) {
905
                        Textures[texture_count] = bm_load_sub(skip, dest_bm);
906
                        TmapInfo[texture_count].filename = short_name;
907
                        texture_count++;
908
                        Assert(texture_count < MAX_TEXTURES);
909
                        NumTextures = texture_count;
910
                }
911
                else if (Textures[i].index == 0)                //was found, but registered out
912
                        Textures[i] = bm_load_sub(skip, dest_bm);
913
                dest_bm_num = i;
914
        }
915
#endif
916
 
917
        if (!abm_flag)
918
        {
919
                bitmap = bm_load_sub(skip, arg);
920
 
921
                Effects[clip_num].vc.play_time = fl2f(play_time);
922
                Effects[clip_num].vc.num_frames = frames;
923
                Effects[clip_num].vc.frame_time = fl2f(play_time)/frames;
924
 
925
                Assert(clip_count < frames);
926
                Effects[clip_num].vc.frames[clip_count] = bitmap;
927
                set_lighting_flag(GameBitmaps[bitmap.index]);
928
 
929
                Assert(!obj_eclip);             //obj eclips for non-abm files not supported!
930
                Assert(crit_flag==0);
931
 
932
                if (clip_count == 0) {
933
                        Effects[clip_num].changing_wall_texture = texture_count;
934
                        Assert(tmap_count < MAX_TEXTURES);
935
                        tmap_count++;
936
                        Textures[texture_count] = bitmap;
937
                        set_texture_name(arg);
938
                        Assert(texture_count < MAX_TEXTURES);
939
                        texture_count++;
940
                        TmapInfo[texture_count].eclip_num = clip_num;
941
                        NumTextures = texture_count;
942
                }
943
 
944
                clip_count++;
945
 
946
        } else {
947
                std::array<bitmap_index, MAX_BITMAPS_PER_BRUSH> bm;
948
                abm_flag = 0;
949
 
950
                ab_load(skip, arg, bm, &Effects[clip_num].vc.num_frames );
951
 
952
                Effects[clip_num].vc.play_time = fl2f(play_time);
953
                Effects[clip_num].vc.frame_time = Effects[clip_num].vc.play_time/Effects[clip_num].vc.num_frames;
954
 
955
                clip_count = 0;
956
                set_lighting_flag(GameBitmaps[bm[clip_count].index]);
957
                Effects[clip_num].vc.frames[clip_count] = bm[clip_count];
958
 
959
                if (!obj_eclip && !crit_flag) {
960
                        Effects[clip_num].changing_wall_texture = texture_count;
961
                        Assert(tmap_count < MAX_TEXTURES);
962
                        tmap_count++;
963
                        Textures[texture_count] = bm[clip_count];
964
                        set_texture_name( arg );
965
                        Assert(texture_count < MAX_TEXTURES);
966
                        TmapInfo[texture_count].eclip_num = clip_num;
967
                        texture_count++;
968
                        NumTextures = texture_count;
969
                }
970
 
971
                if (obj_eclip) {
972
 
973
                        if (Effects[clip_num].changing_object_texture == -1) {          //first time referenced
974
                                Effects[clip_num].changing_object_texture = N_ObjBitmaps;               // XChange ObjectBitmaps
975
                                N_ObjBitmaps++;
976
                        }
977
 
978
                        ObjBitmaps[Effects[clip_num].changing_object_texture] = Effects[clip_num].vc.frames[0];
979
                }
980
 
981
                //if for an object, Effects_bm_ptrs set in object load
982
 
983
                for(clip_count=1;clip_count < Effects[clip_num].vc.num_frames; clip_count++) {
984
                        set_lighting_flag(GameBitmaps[bm[clip_count].index]);
985
                        Effects[clip_num].vc.frames[clip_count] = bm[clip_count];
986
                }
987
 
988
        }
989
 
990
        Effects[clip_num].crit_clip = crit_clip;
991
        Effects[clip_num].sound_num = sound_num;
992
 
993
#if defined(DXX_BUILD_DESCENT_I)
994
        if (!dest_bm.empty())
995
#elif defined(DXX_BUILD_DESCENT_II)
996
        if (dest_bm)
997
#endif
998
        {                       //deal with bitmap for blown up clip
999
#if defined(DXX_BUILD_DESCENT_I)
1000
                char short_name[13];
1001
                int i;
1002
                strcpy(short_name,dest_bm.c_str());
1003
                REMOVE_DOTS(short_name);
1004
                for (i=0;i<texture_count;i++)
1005
                        if (!d_stricmp(static_cast<const char *>(TmapInfo[i].filename),short_name))
1006
                                break;
1007
                if (i==texture_count) {
1008
                        Textures[texture_count] = bm_load_sub(skip, dest_bm.c_str());
1009
                        TmapInfo[texture_count].filename.copy_if(short_name);
1010
                        texture_count++;
1011
                        Assert(texture_count < MAX_TEXTURES);
1012
                        NumTextures = texture_count;
1013
                }
1014
                Effects[clip_num].dest_bm_num = i;
1015
#elif defined(DXX_BUILD_DESCENT_II)
1016
                Effects[clip_num].dest_bm_num = dest_bm_num;
1017
#endif
1018
 
1019
                if (dest_vclip==vclip_none)
1020
                        Error("Desctuction vclip missing on line %d",linenum);
1021
                if (dest_size==-1)
1022
                        Error("Desctuction vclip missing on line %d",linenum);
1023
 
1024
                Effects[clip_num].dest_vclip = dest_vclip;
1025
                Effects[clip_num].dest_size = dest_size;
1026
 
1027
                Effects[clip_num].dest_eclip = dest_eclip;
1028
        }
1029
        else {
1030
                Effects[clip_num].dest_bm_num = ~0u;
1031
                Effects[clip_num].dest_eclip = eclip_none;
1032
        }
1033
 
1034
        if (crit_flag)
1035
                Effects[clip_num].flags |= EF_CRITICAL;
1036
}
1037
 
1038
#if defined(DXX_BUILD_DESCENT_I)
1039
static void bm_read_gauges(const char *const arg, int skip)
1040
#elif defined(DXX_BUILD_DESCENT_II)
1041
static void bm_read_gauges(int skip)
1042
#endif
1043
{
1044
        bitmap_index bitmap;
1045
        unsigned i, num_abm_frames;
1046
 
1047
        if (!abm_flag)  {
1048
                bitmap = bm_load_sub(skip, arg);
1049
                Assert(clip_count < MAX_GAUGE_BMS);
1050
                Gauges[clip_count] = bitmap;
1051
                clip_count++;
1052
        } else {
1053
                std::array<bitmap_index, MAX_BITMAPS_PER_BRUSH> bm;
1054
                abm_flag = 0;
1055
                ab_load(skip, arg, bm, &num_abm_frames );
1056
                for (i=clip_count; i<clip_count+num_abm_frames; i++) {
1057
                        Assert(i < MAX_GAUGE_BMS);
1058
                        Gauges[i] = bm[i-clip_count];
1059
                }
1060
                clip_count += num_abm_frames;
1061
        }
1062
}
1063
 
1064
#if defined(DXX_BUILD_DESCENT_I)
1065
static void bm_read_wclip(char *const arg, int skip)
1066
#elif defined(DXX_BUILD_DESCENT_II)
1067
static void bm_read_gauges_hires()
1068
{
1069
        bitmap_index bitmap;
1070
        unsigned i, num_abm_frames;
1071
 
1072
        if (!abm_flag)  {
1073
                bitmap = bm_load_sub(0, arg);
1074
                Assert(clip_count < MAX_GAUGE_BMS);
1075
                Gauges_hires[clip_count] = bitmap;
1076
                clip_count++;
1077
        } else {
1078
                std::array<bitmap_index, MAX_BITMAPS_PER_BRUSH> bm;
1079
                abm_flag = 0;
1080
                ab_load(0, arg, bm, &num_abm_frames );
1081
                for (i=clip_count; i<clip_count+num_abm_frames; i++) {
1082
                        Assert(i < MAX_GAUGE_BMS);
1083
                        Gauges_hires[i] = bm[i-clip_count];
1084
                }
1085
                clip_count += num_abm_frames;
1086
        }
1087
}
1088
 
1089
static void bm_read_wclip(int skip)
1090
#endif
1091
{
1092
        auto &TmapInfo = LevelUniqueTmapInfoState.TmapInfo;
1093
        auto &WallAnims = GameSharedState.WallAnims;
1094
        bitmap_index bitmap;
1095
        Assert(clip_num < MAX_WALL_ANIMS);
1096
 
1097
        auto &wa = WallAnims[clip_num];
1098
        wa.flags = wall_explodes_flag | wall_blastable_flag | wall_hidden_flag | tmap1_flag;
1099
 
1100
        if (!abm_flag)  {
1101
                bitmap = bm_load_sub(skip, arg);
1102
                if (wa.num_frames != wclip_frames_none && clip_count == 0)
1103
                        Error( "Wall Clip %d is already used!", clip_num );
1104
                wa.play_time = fl2f(play_time);
1105
                wa.num_frames = frames;
1106
                //WallAnims[clip_num].frame_time = fl2f(play_time)/frames;
1107
                Assert(clip_count < frames);
1108
                wa.frames[clip_count++] = texture_count;
1109
                wa.open_sound = wall_open_sound;
1110
                wa.close_sound = wall_close_sound;
1111
                Textures[texture_count] = bitmap;
1112
                set_lighting_flag(GameBitmaps[bitmap.index]);
1113
                set_texture_name( arg );
1114
                Assert(texture_count < MAX_TEXTURES);
1115
                texture_count++;
1116
                NumTextures = texture_count;
1117
                if (clip_num >= Num_wall_anims) Num_wall_anims = clip_num+1;
1118
        } else {
1119
                std::array<bitmap_index, MAX_BITMAPS_PER_BRUSH> bm;
1120
                unsigned nframes;
1121
                if (wa.num_frames != wclip_frames_none)
1122
                        Error( "AB_Wall clip %d is already used!", clip_num );
1123
                abm_flag = 0;
1124
#if defined(DXX_BUILD_DESCENT_I)
1125
                ab_load(skip, arg, bm, &nframes );
1126
#elif defined(DXX_BUILD_DESCENT_II)
1127
                ab_load(0, arg, bm, &nframes );
1128
#endif
1129
                wa.num_frames = nframes;
1130
                wa.play_time = fl2f(play_time);
1131
                //WallAnims[clip_num].frame_time = fl2f(play_time)/nframes;
1132
                wa.open_sound = wall_open_sound;
1133
                wa.close_sound = wall_close_sound;
1134
                strcpy(&wa.filename[0], arg);
1135
                REMOVE_DOTS(&wa.filename[0]);
1136
 
1137
                if (clip_num >= Num_wall_anims) Num_wall_anims = clip_num+1;
1138
 
1139
                set_lighting_flag(GameBitmaps[bm[clip_count].index]);
1140
 
1141
                for (clip_count=0;clip_count < wa.num_frames; clip_count++)     {
1142
                        Textures[texture_count] = bm[clip_count];
1143
                        set_lighting_flag(GameBitmaps[bm[clip_count].index]);
1144
                        wa.frames[clip_count] = texture_count;
1145
                        REMOVE_DOTS(arg);
1146
                        snprintf(&TmapInfo[texture_count].filename[0u], TmapInfo[texture_count].filename.size(), "%s#%d", arg, clip_count);
1147
                        Assert(texture_count < MAX_TEXTURES);
1148
                        texture_count++;
1149
                        NumTextures = texture_count;
1150
                }
1151
        }
1152
}
1153
 
1154
namespace dsx {
1155
 
1156
#if defined(DXX_BUILD_DESCENT_I)
1157
static void bm_read_vclip(d_vclip_array &Vclip, const char *const arg, int skip)
1158
#elif defined(DXX_BUILD_DESCENT_II)
1159
static void bm_read_vclip(d_vclip_array &Vclip, int skip)
1160
#endif
1161
{
1162
        bitmap_index bi;
1163
        assert(clip_num < Vclip.size());
1164
 
1165
#if defined(DXX_BUILD_DESCENT_II)
1166
        if (clip_num >= Num_vclips)
1167
                Num_vclips = clip_num+1;
1168
#endif
1169
 
1170
        if (!abm_flag)  {
1171
                if (Vclip[clip_num].num_frames != ~0u && clip_count == 0)
1172
                        Error( "Vclip %d is already used!", clip_num );
1173
                bi = bm_load_sub(skip, arg);
1174
                Vclip[clip_num].play_time = fl2f(play_time);
1175
                Vclip[clip_num].num_frames = frames;
1176
                Vclip[clip_num].frame_time = fl2f(play_time)/frames;
1177
                Vclip[clip_num].light_value = fl2f(vlighting);
1178
                Vclip[clip_num].sound_num = sound_num;
1179
                set_lighting_flag(GameBitmaps[bi.index]);
1180
                Assert(clip_count < frames);
1181
                Vclip[clip_num].frames[clip_count++] = bi;
1182
                if (rod_flag) {
1183
                        rod_flag=0;
1184
                        Vclip[clip_num].flags |= VF_ROD;
1185
                }
1186
 
1187
        } else  {
1188
                std::array<bitmap_index, MAX_BITMAPS_PER_BRUSH> bm;
1189
                abm_flag = 0;
1190
                if (Vclip[clip_num].num_frames != ~0u)
1191
                        Error( "AB_Vclip %d is already used!", clip_num );
1192
                ab_load(skip, arg, bm, &Vclip[clip_num].num_frames );
1193
 
1194
                if (rod_flag) {
1195
                        //int i;
1196
                        rod_flag=0;
1197
                        Vclip[clip_num].flags |= VF_ROD;
1198
                }
1199
                Vclip[clip_num].play_time = fl2f(play_time);
1200
                Vclip[clip_num].frame_time = fl2f(play_time)/Vclip[clip_num].num_frames;
1201
                Vclip[clip_num].light_value = fl2f(vlighting);
1202
                Vclip[clip_num].sound_num = sound_num;
1203
                set_lighting_flag(GameBitmaps[bm[clip_count].index]);
1204
 
1205
                for (clip_count=0;clip_count < Vclip[clip_num].num_frames; clip_count++) {
1206
                        set_lighting_flag(GameBitmaps[bm[clip_count].index]);
1207
                        Vclip[clip_num].frames[clip_count] = bm[clip_count];
1208
                }
1209
        }
1210
}
1211
 
1212
}
1213
 
1214
// ------------------------------------------------------------------------------
1215
static void get4fix(std::array<fix, NDL> &fixp)
1216
{
1217
        char    *curtext;
1218
        range_for (auto &i, fixp)
1219
        {
1220
                curtext = strtok(NULL, space_tab);
1221
                i = fl2f(atof(curtext));
1222
        }
1223
}
1224
 
1225
// ------------------------------------------------------------------------------
1226
static void get4byte(std::array<int8_t, NDL> &bytep)
1227
{
1228
        char    *curtext;
1229
        range_for (auto &i, bytep)
1230
        {
1231
                curtext = strtok(NULL, space_tab);
1232
                i = atoi(curtext);
1233
        }
1234
}
1235
 
1236
// ------------------------------------------------------------------------------
1237
//      Convert field of view from an angle in 0..360 to cosine.
1238
static void adjust_field_of_view(std::array<fix, NDL> &fovp)
1239
{
1240
        fixang  tt;
1241
        float           ff;
1242
        range_for (auto &i, fovp)
1243
        {
1244
                ff = - f2fl(i);
1245
                if (ff > 179) {
1246
                        ff = 179;
1247
                }
1248
                ff = ff/360;
1249
                tt = fl2f(ff);
1250
                i = fix_cos(tt);
1251
        }
1252
}
1253
 
1254
#if defined(DXX_BUILD_DESCENT_I)
1255
static void clear_to_end_of_line(char *&arg)
1256
{
1257
        arg = NULL;
1258
}
1259
#elif defined(DXX_BUILD_DESCENT_II)
1260
static void clear_to_end_of_line()
1261
{
1262
        arg = strtok( NULL, space_tab );
1263
        while (arg != NULL)
1264
                arg = strtok( NULL, space_tab );
1265
}
1266
#endif
1267
 
1268
#if defined(DXX_BUILD_DESCENT_I)
1269
static void bm_read_sound(char *&arg, int skip, int pc_shareware)
1270
#elif defined(DXX_BUILD_DESCENT_II)
1271
void bm_read_sound(int skip)
1272
#endif
1273
{
1274
        int alt_sound_num;
1275
 
1276
        const int read_sound_num = get_int();
1277
#if defined(DXX_BUILD_DESCENT_I)
1278
        alt_sound_num = pc_shareware ? read_sound_num : get_int();
1279
#elif defined(DXX_BUILD_DESCENT_II)
1280
        alt_sound_num = get_int();
1281
#endif
1282
 
1283
        if ( read_sound_num>=MAX_SOUNDS )
1284
                Error( "Too many sound files.\n" );
1285
 
1286
        if (read_sound_num >= num_sounds)
1287
                num_sounds = read_sound_num+1;
1288
 
1289
#if defined(DXX_BUILD_DESCENT_II)
1290
        if (Sounds[read_sound_num] != 255)
1291
                Error("Sound num %d already used, bitmaps.tbl, line %d\n",read_sound_num,linenum);
1292
#endif
1293
 
1294
        arg = strtok(NULL, space_tab);
1295
 
1296
        Sounds[read_sound_num] = ds_load(skip, arg);
1297
 
1298
        if ( alt_sound_num == 0 )
1299
                AltSounds[read_sound_num] = sound_num;
1300
        else if (alt_sound_num < 0 )
1301
                AltSounds[read_sound_num] = 255;
1302
        else
1303
                AltSounds[read_sound_num] = alt_sound_num;
1304
 
1305
        if (Sounds[read_sound_num] == 255)
1306
                Error("Can't load soundfile <%s>",arg);
1307
}
1308
 
1309
// ------------------------------------------------------------------------------
1310
#if defined(DXX_BUILD_DESCENT_I)
1311
static void bm_read_robot_ai(char *&arg, const int skip)
1312
#elif defined(DXX_BUILD_DESCENT_II)
1313
void bm_read_robot_ai(const int skip)
1314
#endif
1315
{
1316
        char                    *robotnum_text;
1317
        int                     robotnum;
1318
 
1319
        robotnum_text = strtok(NULL, space_tab);
1320
        robotnum = atoi(robotnum_text);
1321
        Assert(robotnum < MAX_ROBOT_TYPES);
1322
        auto &Robot_info = LevelSharedRobotInfoState.Robot_info;
1323
        auto &robptr = Robot_info[robotnum];
1324
 
1325
        Assert(robotnum == Num_robot_ais);              //make sure valid number
1326
 
1327
        if (skip) {
1328
                Num_robot_ais++;
1329
#if defined(DXX_BUILD_DESCENT_I)
1330
                clear_to_end_of_line(arg);
1331
#elif defined(DXX_BUILD_DESCENT_II)
1332
                clear_to_end_of_line();
1333
#endif
1334
                return;
1335
        }
1336
 
1337
        Num_robot_ais++;
1338
 
1339
        get4fix(robptr.field_of_view);
1340
        get4fix(robptr.firing_wait);
1341
#if defined(DXX_BUILD_DESCENT_II)
1342
        get4fix(robptr.firing_wait2);
1343
#endif
1344
        get4byte(robptr.rapidfire_count);
1345
        get4fix(robptr.turn_time);
1346
#if defined(DXX_BUILD_DESCENT_I)
1347
        std::array<fix, NDL>            fire_power,                                             //      damage done by a hit from this robot
1348
                shield;                                                 //      shield strength of this robot
1349
        get4fix(fire_power);
1350
        get4fix(shield);
1351
#elif defined(DXX_BUILD_DESCENT_II)
1352
//      get4fix(robptr->fire_power);
1353
//      get4fix(robptr->shield);
1354
#endif
1355
        get4fix(robptr.max_speed);
1356
        get4fix(robptr.circle_distance);
1357
        get4byte(robptr.evade_speed);
1358
 
1359
        robptr.always_0xabcd    = 0xabcd;
1360
        adjust_field_of_view(robptr.field_of_view);
1361
}
1362
 
1363
//      ----------------------------------------------------------------------------------------------
1364
//this will load a bitmap for a polygon models.  it puts the bitmap into
1365
//the array ObjBitmaps[], and also deals with animating bitmaps
1366
//returns a pointer to the bitmap
1367
static grs_bitmap *load_polymodel_bitmap(int skip, const char *name)
1368
{
1369
        auto &Effects = LevelUniqueEffectsClipState.Effects;
1370
        assert(N_ObjBitmaps < ObjBitmaps.size());
1371
 
1372
//      Assert( N_ObjBitmaps == N_ObjBitmapPtrs );
1373
 
1374
        if (name[0] == '%') {           //an animating bitmap!
1375
                const unsigned eclip_num = atoi(name+1);
1376
 
1377
                if (Effects[eclip_num].changing_object_texture == -1) {         //first time referenced
1378
                        Effects[eclip_num].changing_object_texture = N_ObjBitmaps;
1379
                        ObjBitmapPtrs[N_ObjBitmapPtrs++] = N_ObjBitmaps;
1380
                        N_ObjBitmaps++;
1381
                } else {
1382
                        ObjBitmapPtrs[N_ObjBitmapPtrs++] = Effects[eclip_num].changing_object_texture;
1383
                }
1384
#if defined(DXX_BUILD_DESCENT_II)
1385
                assert(N_ObjBitmaps < ObjBitmaps.size());
1386
                assert(N_ObjBitmapPtrs < ObjBitmapPtrs.size());
1387
#endif
1388
                return NULL;
1389
        }
1390
        else    {
1391
                ObjBitmaps[N_ObjBitmaps] = bm_load_sub(skip, name);
1392
#if defined(DXX_BUILD_DESCENT_II)
1393
                if (GameBitmaps[ObjBitmaps[N_ObjBitmaps].index].bm_w!=64 || GameBitmaps[ObjBitmaps[N_ObjBitmaps].index].bm_h!=64)
1394
                        Error("Bitmap <%s> is not 64x64",name);
1395
#endif
1396
                ObjBitmapPtrs[N_ObjBitmapPtrs++] = N_ObjBitmaps;
1397
                N_ObjBitmaps++;
1398
#if defined(DXX_BUILD_DESCENT_II)
1399
                assert(N_ObjBitmaps < ObjBitmaps.size());
1400
                assert(N_ObjBitmapPtrs < ObjBitmapPtrs.size());
1401
#endif
1402
                return &GameBitmaps[ObjBitmaps[N_ObjBitmaps-1].index];
1403
        }
1404
}
1405
 
1406
#define MAX_MODEL_VARIANTS      4
1407
 
1408
// ------------------------------------------------------------------------------
1409
#if defined(DXX_BUILD_DESCENT_I)
1410
static void bm_read_robot(char *&arg, int skip)
1411
#elif defined(DXX_BUILD_DESCENT_II)
1412
void bm_read_robot(int skip)
1413
#endif
1414
{
1415
        char                    *model_name[MAX_MODEL_VARIANTS];
1416
        int                     n_models,i;
1417
        int                     first_bitmap_num[MAX_MODEL_VARIANTS];
1418
        char                    *equal_ptr;
1419
        int exp1_vclip_num = vclip_none;
1420
        int exp1_sound_num = sound_none;
1421
        int exp2_vclip_num = vclip_none;
1422
        int exp2_sound_num = sound_none;
1423
        fix                     lighting = F1_0/2;              // Default
1424
        fix                     strength = F1_0*10;             // Default strength
1425
        fix                     mass = f1_0*4;
1426
        fix                     drag = f1_0/2;
1427
        weapon_id_type weapon_type = weapon_id_type::LASER_ID_L1;
1428
        int                     contains_count=0, contains_id=0, contains_prob=0, contains_type=0;
1429
#if defined(DXX_BUILD_DESCENT_II)
1430
        weapon_id_type weapon_type2 = weapon_id_type::unspecified;
1431
        auto behavior = ai_behavior::AIB_NORMAL;
1432
        int                     companion = 0, smart_blobs=0, energy_blobs=0, badass=0, energy_drain=0, kamikaze=0, thief=0, pursuit=0, lightcast=0, death_roll=0;
1433
        fix                     glow=0, aim=F1_0;
1434
        int                     deathroll_sound = SOUND_BOSS_SHARE_DIE; //default
1435
        int                     taunt_sound = ROBOT_SEE_SOUND_DEFAULT;
1436
        ubyte flags=0;
1437
#endif
1438
        int                     score_value=1000;
1439
        int                     cloak_type=0;           //      Default = this robot does not cloak
1440
        int                     attack_type=0;          //      Default = this robot attacks by firing (1=lunge)
1441
        int                     boss_flag=0;                            //      Default = robot is not a boss.
1442
        int                     see_sound = ROBOT_SEE_SOUND_DEFAULT;
1443
        int                     attack_sound = ROBOT_ATTACK_SOUND_DEFAULT;
1444
        int                     claw_sound = ROBOT_CLAW_SOUND_DEFAULT;
1445
 
1446
        assert(LevelSharedRobotInfoState.N_robot_types < MAX_ROBOT_TYPES);
1447
 
1448
        auto &Robot_info = LevelSharedRobotInfoState.Robot_info;
1449
        if (skip) {
1450
                auto &ri = Robot_info[LevelSharedRobotInfoState.N_robot_types++];
1451
                ri.model_num = -1;
1452
#if defined(DXX_BUILD_DESCENT_I)
1453
                Num_total_object_types++;
1454
                clear_to_end_of_line(arg);
1455
#elif defined(DXX_BUILD_DESCENT_II)
1456
                clear_to_end_of_line();
1457
#endif
1458
                return;
1459
        }
1460
 
1461
        model_name[0] = strtok( NULL, space_tab );
1462
        first_bitmap_num[0] = N_ObjBitmapPtrs;
1463
        n_models = 1;
1464
 
1465
        // Process bitmaps
1466
        bm_flag=BM_ROBOT;
1467
        arg = strtok( NULL, space_tab );
1468
        while (arg!=NULL)       {
1469
                equal_ptr = strchr( arg, '=' );
1470
                if ( equal_ptr )        {
1471
                        *equal_ptr='\0';
1472
                        equal_ptr++;
1473
                        // if we have john=cool, arg is 'john' and equal_ptr is 'cool'
1474
                        if (!d_stricmp( arg, "exp1_vclip" ))    {
1475
                                exp1_vclip_num = atoi(equal_ptr);
1476
                        } else if (!d_stricmp( arg, "exp2_vclip" ))     {
1477
                                exp2_vclip_num = atoi(equal_ptr);
1478
                        } else if (!d_stricmp( arg, "exp1_sound" ))     {
1479
                                exp1_sound_num = atoi(equal_ptr);
1480
                        } else if (!d_stricmp( arg, "exp2_sound" ))     {
1481
                                exp2_sound_num = atoi(equal_ptr);
1482
                        } else if (!d_stricmp( arg, "lighting" ))       {
1483
                                lighting = fl2f(atof(equal_ptr));
1484
                                if ( (lighting < 0) || (lighting > F1_0 )) {
1485
                                        Error( "In bitmaps.tbl, lighting value of %.2f is out of range 0..1.\n", f2fl(lighting));
1486
                                }
1487
                        } else if (!d_stricmp( arg, "weapon_type" )) {
1488
                                weapon_type = static_cast<weapon_id_type>(atoi(equal_ptr));
1489
                        }
1490
#if defined(DXX_BUILD_DESCENT_II)
1491
                        else if (!d_stricmp( arg, "weapon_type2"))
1492
                        {
1493
                                weapon_type2 = static_cast<weapon_id_type>(atoi(equal_ptr));
1494
                        }
1495
#endif
1496
                        else if (!d_stricmp( arg, "strength" )) {
1497
                                strength = i2f(atoi(equal_ptr));
1498
                        } else if (!d_stricmp( arg, "mass" )) {
1499
                                mass = fl2f(atof(equal_ptr));
1500
                        } else if (!d_stricmp( arg, "drag" )) {
1501
                                drag = fl2f(atof(equal_ptr));
1502
                        } else if (!d_stricmp( arg, "contains_id" )) {
1503
                                contains_id = atoi(equal_ptr);
1504
                        } else if (!d_stricmp( arg, "contains_type" )) {
1505
                                contains_type = atoi(equal_ptr);
1506
                        } else if (!d_stricmp( arg, "contains_count" )) {
1507
                                contains_count = atoi(equal_ptr);
1508
                        }
1509
#if defined(DXX_BUILD_DESCENT_II)
1510
                        else if (!d_stricmp( arg, "companion" )) {
1511
                                companion = atoi(equal_ptr);
1512
                        } else if (!d_stricmp( arg, "badass" )) {
1513
                                badass = atoi(equal_ptr);
1514
                        } else if (!d_stricmp( arg, "lightcast" )) {
1515
                                lightcast = atoi(equal_ptr);
1516
                        } else if (!d_stricmp( arg, "glow" )) {
1517
                                glow = fl2f(atof(equal_ptr));
1518
                        } else if (!d_stricmp( arg, "death_roll" )) {
1519
                                death_roll = atoi(equal_ptr);
1520
                        } else if (!d_stricmp( arg, "deathroll_sound" )) {
1521
                                deathroll_sound = atoi(equal_ptr);
1522
                        } else if (!d_stricmp( arg, "thief" )) {
1523
                                thief = atoi(equal_ptr);
1524
                        } else if (!d_stricmp( arg, "kamikaze" )) {
1525
                                kamikaze = atoi(equal_ptr);
1526
                        } else if (!d_stricmp( arg, "pursuit" )) {
1527
                                pursuit = atoi(equal_ptr);
1528
                        } else if (!d_stricmp( arg, "smart_blobs" )) {
1529
                                smart_blobs = atoi(equal_ptr);
1530
                        } else if (!d_stricmp( arg, "energy_blobs" )) {
1531
                                energy_blobs = atoi(equal_ptr);
1532
                        } else if (!d_stricmp( arg, "energy_drain" )) {
1533
                                energy_drain = atoi(equal_ptr);
1534
                        }
1535
#endif
1536
                        else if (!d_stricmp( arg, "contains_prob" )) {
1537
                                contains_prob = atoi(equal_ptr);
1538
                        } else if (!d_stricmp( arg, "cloak_type" )) {
1539
                                cloak_type = atoi(equal_ptr);
1540
                        } else if (!d_stricmp( arg, "attack_type" )) {
1541
                                attack_type = atoi(equal_ptr);
1542
                        } else if (!d_stricmp( arg, "boss" )) {
1543
                                boss_flag = atoi(equal_ptr);
1544
                        } else if (!d_stricmp( arg, "score_value" )) {
1545
                                score_value = atoi(equal_ptr);
1546
                        } else if (!d_stricmp( arg, "see_sound" )) {
1547
                                see_sound = atoi(equal_ptr);
1548
                        } else if (!d_stricmp( arg, "attack_sound" )) {
1549
                                attack_sound = atoi(equal_ptr);
1550
                        } else if (!d_stricmp( arg, "claw_sound" )) {
1551
                                claw_sound = atoi(equal_ptr);
1552
                        }
1553
#if defined(DXX_BUILD_DESCENT_II)
1554
                        else if (!d_stricmp( arg, "taunt_sound" )) {
1555
                                taunt_sound = atoi(equal_ptr);
1556
                        } else if (!d_stricmp( arg, "aim" )) {
1557
                                aim = fl2f(atof(equal_ptr));
1558
                        } else if (!d_stricmp( arg, "big_radius" )) {
1559
                                if (atoi(equal_ptr))
1560
                                        flags |= RIF_BIG_RADIUS;
1561
                        } else if (!d_stricmp( arg, "behavior" )) {
1562
                                if (!d_stricmp(equal_ptr, "STILL"))
1563
                                        behavior = ai_behavior::AIB_STILL;
1564
                                else if (!d_stricmp(equal_ptr, "NORMAL"))
1565
                                        behavior = ai_behavior::AIB_NORMAL;
1566
                                else if (!d_stricmp(equal_ptr, "BEHIND"))
1567
                                        behavior = ai_behavior::AIB_BEHIND;
1568
                                else if (!d_stricmp(equal_ptr, "RUN_FROM"))
1569
                                        behavior = ai_behavior::AIB_RUN_FROM;
1570
                                else if (!d_stricmp(equal_ptr, "SNIPE"))
1571
                                        behavior = ai_behavior::AIB_SNIPE;
1572
                                else if (!d_stricmp(equal_ptr, "STATION"))
1573
                                        behavior = ai_behavior::AIB_STATION;
1574
                                else if (!d_stricmp(equal_ptr, "FOLLOW"))
1575
                                        behavior = ai_behavior::AIB_FOLLOW;
1576
                                else
1577
                                        Int3(); //      Error.  Illegal behavior type for current robot.
1578
                        }
1579
#endif
1580
                        else if (!d_stricmp( arg, "name" )) {
1581
#if DXX_USE_EDITOR
1582
                                auto &name = Robot_names[LevelSharedRobotInfoState.N_robot_types];
1583
                                const auto len = strlen(equal_ptr);
1584
                                assert(len < name.size());      //      Oops, name too long.
1585
                                memcpy(name.data(), &equal_ptr[1], len - 2);
1586
                                name[len - 2] = 0;
1587
#endif
1588
                        } else if (!d_stricmp( arg, "simple_model" )) {
1589
                                model_name[n_models] = equal_ptr;
1590
                                first_bitmap_num[n_models] = N_ObjBitmapPtrs;
1591
                                n_models++;
1592
#if defined(DXX_BUILD_DESCENT_II)
1593
                                Assert(n_models < MAX_MODEL_VARIANTS);
1594
#endif
1595
                        }
1596
#if defined(DXX_BUILD_DESCENT_II)
1597
                        else
1598
                        {
1599
                                Int3();
1600
                        }
1601
#endif
1602
                } else {                        // Must be a texture specification...
1603
                        load_polymodel_bitmap(skip, arg);
1604
                }
1605
                arg = strtok( NULL, space_tab );
1606
        }
1607
 
1608
        auto &current_robot_info = Robot_info[LevelSharedRobotInfoState.N_robot_types];
1609
        //clear out anim info
1610
        range_for (auto &g, current_robot_info.anim_states)
1611
                range_for (auto &s, g)
1612
                        s.n_joints = 0;
1613
 
1614
        first_bitmap_num[n_models] = N_ObjBitmapPtrs;
1615
 
1616
        auto &Polygon_models = LevelSharedPolygonModelState.Polygon_models;
1617
        for (i=0;i<n_models;i++) {
1618
                int n_textures;
1619
                int model_num,last_model_num=0;
1620
 
1621
                n_textures = first_bitmap_num[i+1] - first_bitmap_num[i];
1622
 
1623
                model_num = load_polygon_model(model_name[i],n_textures,first_bitmap_num[i], (i == 0) ? &current_robot_info : nullptr);
1624
 
1625
                if (i==0)
1626
                        current_robot_info.model_num = model_num;
1627
                else
1628
                        Polygon_models[last_model_num].simpler_model = model_num+1;
1629
 
1630
                last_model_num = model_num;
1631
        }
1632
 
1633
#if defined(DXX_BUILD_DESCENT_I)
1634
        ObjType[Num_total_object_types] = OL_ROBOT;
1635
        ObjId[Num_total_object_types] = LevelSharedRobotInfoState.N_robot_types;
1636
#elif defined(DXX_BUILD_DESCENT_II)
1637
        if ((glow > i2f(15)) || (glow < 0) || (glow != 0 && glow < 0x1000)) {
1638
                Int3();
1639
        }
1640
#endif
1641
 
1642
        current_robot_info.exp1_vclip_num = exp1_vclip_num;
1643
        current_robot_info.exp2_vclip_num = exp2_vclip_num;
1644
        current_robot_info.exp1_sound_num = exp1_sound_num;
1645
        current_robot_info.exp2_sound_num = exp2_sound_num;
1646
        current_robot_info.lighting = lighting;
1647
        current_robot_info.weapon_type = weapon_type;
1648
#if defined(DXX_BUILD_DESCENT_II)
1649
        current_robot_info.weapon_type2 = weapon_type2;
1650
#endif
1651
        current_robot_info.strength = strength;
1652
        current_robot_info.mass = mass;
1653
        current_robot_info.drag = drag;
1654
        current_robot_info.cloak_type = cloak_type;
1655
        current_robot_info.attack_type = attack_type;
1656
        current_robot_info.boss_flag = boss_flag;
1657
 
1658
        current_robot_info.contains_id = contains_id;
1659
        current_robot_info.contains_count = contains_count;
1660
        current_robot_info.contains_prob = contains_prob;
1661
#if defined(DXX_BUILD_DESCENT_II)
1662
        current_robot_info.companion = companion;
1663
        current_robot_info.badass = badass;
1664
        current_robot_info.lightcast = lightcast;
1665
        current_robot_info.glow = (glow>>12);           //convert to 4:4
1666
        current_robot_info.death_roll = death_roll;
1667
        current_robot_info.deathroll_sound = deathroll_sound;
1668
        current_robot_info.thief = thief;
1669
        current_robot_info.flags = flags;
1670
        current_robot_info.kamikaze = kamikaze;
1671
        current_robot_info.pursuit = pursuit;
1672
        current_robot_info.smart_blobs = smart_blobs;
1673
        current_robot_info.energy_blobs = energy_blobs;
1674
        current_robot_info.energy_drain = energy_drain;
1675
#endif
1676
        current_robot_info.score_value = score_value;
1677
        current_robot_info.see_sound = see_sound;
1678
        current_robot_info.attack_sound = attack_sound;
1679
        current_robot_info.claw_sound = claw_sound;
1680
#if defined(DXX_BUILD_DESCENT_II)
1681
        current_robot_info.taunt_sound = taunt_sound;
1682
        current_robot_info.behavior = behavior;         //      Default behavior for this robot, if coming out of matcen.
1683
        current_robot_info.aim = min(f2i(aim*255), 255);                //      how well this robot type can aim.  255=perfect
1684
#endif
1685
 
1686
        if (contains_type)
1687
                current_robot_info.contains_type = OBJ_ROBOT;
1688
        else
1689
                current_robot_info.contains_type = OBJ_POWERUP;
1690
 
1691
        ++LevelSharedRobotInfoState.N_robot_types;
1692
#if defined(DXX_BUILD_DESCENT_I)
1693
        Num_total_object_types++;
1694
#elif defined(DXX_BUILD_DESCENT_II)
1695
        bm_flag = BM_NONE;
1696
#endif
1697
}
1698
 
1699
#if defined(DXX_BUILD_DESCENT_I)
1700
//read a polygon object of some sort
1701
void bm_read_object(char *&arg, int skip)
1702
#elif defined(DXX_BUILD_DESCENT_II)
1703
//read a reactor model
1704
void bm_read_reactor(void)
1705
#endif
1706
{
1707
        char *model_name, *model_name_dead=NULL;
1708
        int first_bitmap_num, first_bitmap_num_dead=0, n_normal_bitmaps;
1709
        char *equal_ptr;
1710
        short model_num;
1711
        fix     lighting = F1_0/2;              // Default
1712
#if defined(DXX_BUILD_DESCENT_I)
1713
        int type = -1;
1714
        fix strength=0;
1715
#elif defined(DXX_BUILD_DESCENT_II)
1716
        assert(Num_reactors < Reactors.size());
1717
#endif
1718
 
1719
        model_name = strtok( NULL, space_tab );
1720
 
1721
        // Process bitmaps
1722
        bm_flag = BM_NONE;
1723
        arg = strtok( NULL, space_tab );
1724
        first_bitmap_num = N_ObjBitmapPtrs;
1725
 
1726
        while (arg!=NULL)       {
1727
 
1728
                equal_ptr = strchr( arg, '=' );
1729
 
1730
                if ( equal_ptr )        {
1731
                        *equal_ptr='\0';
1732
                        equal_ptr++;
1733
 
1734
                        // if we have john=cool, arg is 'john' and equal_ptr is 'cool'
1735
 
1736
#if defined(DXX_BUILD_DESCENT_I)
1737
                        if (!d_stricmp(arg,"type")) {
1738
                                if (!d_stricmp(equal_ptr,"controlcen"))
1739
                                        type = OL_CONTROL_CENTER;
1740
                                else if (!d_stricmp(equal_ptr,"clutter"))
1741
                                        type = OL_CLUTTER;
1742
                                else if (!d_stricmp(equal_ptr,"exit"))
1743
                                        type = OL_EXIT;
1744
                        }
1745
                        else
1746
#endif
1747
                        if (!d_stricmp( arg, "dead_pof" ))      {
1748
                                model_name_dead = equal_ptr;
1749
                                first_bitmap_num_dead=N_ObjBitmapPtrs;
1750
                        } else if (!d_stricmp( arg, "lighting" ))       {
1751
                                lighting = fl2f(atof(equal_ptr));
1752
                                if ( (lighting < 0) || (lighting > F1_0 )) {
1753
                                        Error( "In bitmaps.tbl, lighting value of %.2f is out of range 0..1.\n", f2fl(lighting));
1754
                                }
1755
                        }
1756
#if defined(DXX_BUILD_DESCENT_I)
1757
                        else if (!d_stricmp( arg, "strength" )) {
1758
                                strength = fl2f(atof(equal_ptr));
1759
                        }
1760
#elif defined(DXX_BUILD_DESCENT_II)
1761
                        else {
1762
                                Int3();
1763
                        }
1764
#endif
1765
                } else {                        // Must be a texture specification...
1766
#if defined(DXX_BUILD_DESCENT_I)
1767
                        load_polymodel_bitmap(skip, arg);
1768
#elif defined(DXX_BUILD_DESCENT_II)
1769
                        load_polymodel_bitmap(0, arg);
1770
#endif
1771
                }
1772
                arg = strtok( NULL, space_tab );
1773
        }
1774
 
1775
        if ( model_name_dead )
1776
                n_normal_bitmaps = first_bitmap_num_dead-first_bitmap_num;
1777
        else
1778
                n_normal_bitmaps = N_ObjBitmapPtrs-first_bitmap_num;
1779
 
1780
        model_num = load_polygon_model(model_name,n_normal_bitmaps,first_bitmap_num,NULL);
1781
 
1782
#if defined(DXX_BUILD_DESCENT_I)
1783
        if (type == OL_CONTROL_CENTER)
1784
                read_model_guns(model_name, Reactors[0]);
1785
#endif
1786
        if ( model_name_dead )
1787
                Dead_modelnums[model_num]  = load_polygon_model(model_name_dead,N_ObjBitmapPtrs-first_bitmap_num_dead,first_bitmap_num_dead,NULL);
1788
        else
1789
                Dead_modelnums[model_num] = -1;
1790
 
1791
#if defined(DXX_BUILD_DESCENT_I)
1792
        if (type == -1)
1793
                Error("No object type specfied for object in BITMAPS.TBL on line %d\n",linenum);
1794
 
1795
        ObjType[Num_total_object_types] = type;
1796
        ObjId[Num_total_object_types] = model_num;
1797
        ObjStrength[Num_total_object_types] = strength;
1798
 
1799
        Num_total_object_types++;
1800
 
1801
        if (type == OL_EXIT) {
1802
                exit_modelnum = model_num;
1803
                destroyed_exit_modelnum = Dead_modelnums[model_num];
1804
        }
1805
#elif defined(DXX_BUILD_DESCENT_II)
1806
        Reactors[Num_reactors].model_num = model_num;
1807
        read_model_guns(model_name, Reactors[Num_reactors]);
1808
 
1809
        Num_reactors++;
1810
#endif
1811
}
1812
 
1813
#if defined(DXX_BUILD_DESCENT_II)
1814
//read the marker object
1815
void bm_read_marker()
1816
{
1817
        char *model_name;
1818
        int first_bitmap_num, n_normal_bitmaps;
1819
        char *equal_ptr;
1820
 
1821
        model_name = strtok( NULL, space_tab );
1822
 
1823
        // Process bitmaps
1824
        bm_flag = BM_NONE;
1825
        arg = strtok( NULL, space_tab );
1826
        first_bitmap_num = N_ObjBitmapPtrs;
1827
 
1828
        while (arg!=NULL)       {
1829
 
1830
                equal_ptr = strchr( arg, '=' );
1831
 
1832
                if ( equal_ptr )        {
1833
                        *equal_ptr='\0';
1834
                        equal_ptr++;
1835
 
1836
                        // if we have john=cool, arg is 'john' and equal_ptr is 'cool'
1837
                        Int3();
1838
 
1839
                } else {                        // Must be a texture specification...
1840
                        load_polymodel_bitmap(0, arg);
1841
                }
1842
                arg = strtok( NULL, space_tab );
1843
        }
1844
 
1845
        n_normal_bitmaps = N_ObjBitmapPtrs-first_bitmap_num;
1846
 
1847
        Marker_model_num = load_polygon_model(model_name,n_normal_bitmaps,first_bitmap_num,NULL);
1848
}
1849
 
1850
//read the exit model
1851
void bm_read_exitmodel()
1852
{
1853
        char *model_name, *model_name_dead=NULL;
1854
        int first_bitmap_num=0, first_bitmap_num_dead=0, n_normal_bitmaps;
1855
        char *equal_ptr;
1856
        short model_num;
1857
 
1858
        model_name = strtok( NULL, space_tab );
1859
 
1860
        // Process bitmaps
1861
        bm_flag = BM_NONE;
1862
        arg = strtok( NULL, space_tab );
1863
        first_bitmap_num = N_ObjBitmapPtrs;
1864
 
1865
        while (arg!=NULL)       {
1866
 
1867
                equal_ptr = strchr( arg, '=' );
1868
 
1869
                if ( equal_ptr )        {
1870
                        *equal_ptr='\0';
1871
                        equal_ptr++;
1872
 
1873
                        // if we have john=cool, arg is 'john' and equal_ptr is 'cool'
1874
 
1875
                        if (!d_stricmp( arg, "dead_pof" ))      {
1876
                                model_name_dead = equal_ptr;
1877
                                first_bitmap_num_dead=N_ObjBitmapPtrs;
1878
                        } else {
1879
                                Int3();
1880
                        }
1881
                } else {                        // Must be a texture specification...
1882
                        load_polymodel_bitmap(0, arg);
1883
                }
1884
                arg = strtok( NULL, space_tab );
1885
        }
1886
 
1887
        if ( model_name_dead )
1888
                n_normal_bitmaps = first_bitmap_num_dead-first_bitmap_num;
1889
        else
1890
                n_normal_bitmaps = N_ObjBitmapPtrs-first_bitmap_num;
1891
 
1892
        model_num = load_polygon_model(model_name,n_normal_bitmaps,first_bitmap_num,NULL);
1893
 
1894
        if ( model_name_dead )
1895
                Dead_modelnums[model_num]  = load_polygon_model(model_name_dead,N_ObjBitmapPtrs-first_bitmap_num_dead,first_bitmap_num_dead,NULL);
1896
        else
1897
                Dead_modelnums[model_num] = -1;
1898
 
1899
        exit_modelnum = model_num;
1900
        destroyed_exit_modelnum = Dead_modelnums[model_num];
1901
 
1902
}
1903
#endif
1904
 
1905
#if defined(DXX_BUILD_DESCENT_I)
1906
void bm_read_player_ship(char *&arg, int skip)
1907
#elif defined(DXX_BUILD_DESCENT_II)
1908
void bm_read_player_ship(void)
1909
#endif
1910
{
1911
        char    *model_name_dying=NULL;
1912
        char    *model_name[MAX_MODEL_VARIANTS];
1913
        int     n_models=0,i;
1914
        int     first_bitmap_num[MAX_MODEL_VARIANTS];
1915
        char *equal_ptr;
1916
        robot_info ri;
1917
        int last_multi_bitmap_num=-1;
1918
 
1919
        // Process bitmaps
1920
        bm_flag = BM_NONE;
1921
 
1922
        arg = strtok( NULL, space_tab );
1923
 
1924
        Player_ship->mass = Player_ship->drag = 0;      //stupid defaults
1925
        Player_ship->expl_vclip_num = vclip_none;
1926
 
1927
        while (arg!=NULL)       {
1928
 
1929
                equal_ptr = strchr( arg, '=' );
1930
 
1931
                if ( equal_ptr )        {
1932
 
1933
                        *equal_ptr='\0';
1934
                        equal_ptr++;
1935
 
1936
                        // if we have john=cool, arg is 'john' and equal_ptr is 'cool'
1937
 
1938
                        if (!d_stricmp( arg, "model" )) {
1939
                                Assert(n_models==0);
1940
                                model_name[0] = equal_ptr;
1941
                                first_bitmap_num[0] = N_ObjBitmapPtrs;
1942
                                n_models = 1;
1943
                        } else if (!d_stricmp( arg, "simple_model" )) {
1944
                                model_name[n_models] = equal_ptr;
1945
                                first_bitmap_num[n_models] = N_ObjBitmapPtrs;
1946
                                n_models++;
1947
#if defined(DXX_BUILD_DESCENT_II)
1948
                                Assert(n_models < MAX_MODEL_VARIANTS);
1949
#endif
1950
 
1951
                                if (First_multi_bitmap_num!=-1 && last_multi_bitmap_num==-1)
1952
                                        last_multi_bitmap_num=N_ObjBitmapPtrs;
1953
                        }
1954
                        else if (!d_stricmp( arg, "mass" ))
1955
                                Player_ship->mass = fl2f(atof(equal_ptr));
1956
                        else if (!d_stricmp( arg, "drag" ))
1957
                                Player_ship->drag = fl2f(atof(equal_ptr));
1958
//                      else if (!d_stricmp( arg, "low_thrust" ))
1959
//                              Player_ship->low_thrust = fl2f(atof(equal_ptr));
1960
                        else if (!d_stricmp( arg, "max_thrust" ))
1961
                                Player_ship->max_thrust = fl2f(atof(equal_ptr));
1962
                        else if (!d_stricmp( arg, "reverse_thrust" ))
1963
                                Player_ship->reverse_thrust = fl2f(atof(equal_ptr));
1964
                        else if (!d_stricmp( arg, "brakes" ))
1965
                                Player_ship->brakes = fl2f(atof(equal_ptr));
1966
                        else if (!d_stricmp( arg, "wiggle" ))
1967
                                Player_ship->wiggle = fl2f(atof(equal_ptr));
1968
                        else if (!d_stricmp( arg, "max_rotthrust" ))
1969
                                Player_ship->max_rotthrust = fl2f(atof(equal_ptr));
1970
                        else if (!d_stricmp( arg, "dying_pof" ))
1971
                                model_name_dying = equal_ptr;
1972
                        else if (!d_stricmp( arg, "expl_vclip_num" ))
1973
                                Player_ship->expl_vclip_num=atoi(equal_ptr);
1974
#if defined(DXX_BUILD_DESCENT_II)
1975
                        else {
1976
                                Int3();
1977
                        }
1978
#endif
1979
                }
1980
                else if (!d_stricmp( arg, "multi_textures" )) {
1981
 
1982
                        First_multi_bitmap_num = N_ObjBitmapPtrs;
1983
                        first_bitmap_num[n_models] = N_ObjBitmapPtrs;
1984
 
1985
                }
1986
                else                    // Must be a texture specification...
1987
                {
1988
#if defined(DXX_BUILD_DESCENT_I)
1989
                        load_polymodel_bitmap(skip, arg);
1990
#elif defined(DXX_BUILD_DESCENT_II)
1991
                        load_polymodel_bitmap(0, arg);
1992
#endif
1993
                }
1994
 
1995
                arg = strtok( NULL, space_tab );
1996
        }
1997
        if (First_multi_bitmap_num!=-1 && last_multi_bitmap_num==-1)
1998
                last_multi_bitmap_num=N_ObjBitmapPtrs;
1999
 
2000
        if (First_multi_bitmap_num==-1)
2001
                first_bitmap_num[n_models] = N_ObjBitmapPtrs;
2002
 
2003
        Assert(last_multi_bitmap_num-First_multi_bitmap_num == (MAX_PLAYERS-1)*2);
2004
 
2005
        auto &Polygon_models = LevelSharedPolygonModelState.Polygon_models;
2006
        for (i=0;i<n_models;i++) {
2007
                int n_textures;
2008
                int model_num,last_model_num=0;
2009
 
2010
                n_textures = first_bitmap_num[i+1] - first_bitmap_num[i];
2011
 
2012
#if defined(DXX_BUILD_DESCENT_I)
2013
                robot_info *pri = NULL;
2014
                if (i == 0)
2015
                        pri = &ri;
2016
                model_num = load_polygon_model(model_name[i],n_textures,first_bitmap_num[i],pri);
2017
#elif defined(DXX_BUILD_DESCENT_II)
2018
                model_num = load_polygon_model(model_name[i],n_textures,first_bitmap_num[i],(i==0) ? &ri : nullptr);
2019
#endif
2020
 
2021
                if (i==0)
2022
                        Player_ship->model_num = model_num;
2023
                else
2024
                        Polygon_models[last_model_num].simpler_model = model_num+1;
2025
 
2026
                last_model_num = model_num;
2027
        }
2028
 
2029
        if ( model_name_dying ) {
2030
                Assert(n_models);
2031
                Dying_modelnums[Player_ship->model_num]  = load_polygon_model(model_name_dying,first_bitmap_num[1]-first_bitmap_num[0],first_bitmap_num[0],NULL);
2032
        }
2033
 
2034
        Assert(ri.n_guns == N_PLAYER_GUNS);
2035
 
2036
        //calc player gun positions
2037
 
2038
        {
2039
                polymodel *pm;
2040
                robot_info *r;
2041
                vms_vector pnt;
2042
                int mn;                         //submodel number
2043
                int gun_num;
2044
 
2045
                r = &ri;
2046
                pm = &Polygon_models[Player_ship->model_num];
2047
 
2048
                for (gun_num=0;gun_num<r->n_guns;gun_num++) {
2049
 
2050
                        pnt = r->gun_points[gun_num];
2051
                        mn = r->gun_submodels[gun_num];
2052
 
2053
                        //instance up the tree for this gun
2054
                        while (mn != 0) {
2055
                                vm_vec_add2(pnt,pm->submodel_offsets[mn]);
2056
                                mn = pm->submodel_parents[mn];
2057
                        }
2058
 
2059
                        Player_ship->gun_points[gun_num] = pnt;
2060
 
2061
                }
2062
        }
2063
}
2064
 
2065
namespace dsx {
2066
 
2067
#if defined(DXX_BUILD_DESCENT_I)
2068
void bm_read_some_file(d_vclip_array &Vclip, const std::string &dest_bm, char *&arg, int skip)
2069
#elif defined(DXX_BUILD_DESCENT_II)
2070
void bm_read_some_file(d_vclip_array &Vclip, int skip)
2071
#endif
2072
{
2073
 
2074
        switch (bm_flag) {
2075
#if defined(DXX_BUILD_DESCENT_II)
2076
        case BM_NONE:
2077
                Error("Trying to read bitmap <%s> with bm_flag==BM_NONE on line %d of BITMAPS.TBL",arg,linenum);
2078
                break;
2079
#endif
2080
        case BM_COCKPIT:        {
2081
                bitmap_index bitmap;
2082
                bitmap = bm_load_sub(skip, arg);
2083
                Assert( Num_cockpits < N_COCKPIT_BITMAPS );
2084
                cockpit_bitmap[Num_cockpits++] = bitmap;
2085
                //bm_flag = BM_NONE;
2086
#if defined(DXX_BUILD_DESCENT_II)
2087
                return;
2088
#endif
2089
                }
2090
                break;
2091
        case BM_GAUGES:
2092
#if defined(DXX_BUILD_DESCENT_I)
2093
                bm_read_gauges(arg, skip);
2094
#elif defined(DXX_BUILD_DESCENT_II)
2095
                bm_read_gauges(skip);
2096
                return;
2097
                break;
2098
        case BM_GAUGES_HIRES:
2099
                bm_read_gauges_hires();
2100
                return;
2101
#endif
2102
                break;
2103
        case BM_WEAPON:
2104
#if defined(DXX_BUILD_DESCENT_I)
2105
                bm_read_weapon(arg, skip, 0);
2106
#elif defined(DXX_BUILD_DESCENT_II)
2107
                bm_read_weapon(skip, 0);
2108
                return;
2109
#endif
2110
                break;
2111
        case BM_VCLIP:
2112
#if defined(DXX_BUILD_DESCENT_I)
2113
                bm_read_vclip(Vclip, arg, skip);
2114
#elif defined(DXX_BUILD_DESCENT_II)
2115
                bm_read_vclip(Vclip, skip);
2116
                return;
2117
#endif
2118
                break;
2119
        case BM_ECLIP:
2120
#if defined(DXX_BUILD_DESCENT_I)
2121
                bm_read_eclip(dest_bm, arg, skip);
2122
#elif defined(DXX_BUILD_DESCENT_II)
2123
                bm_read_eclip(skip);
2124
                return;
2125
#endif
2126
                break;
2127
        case BM_TEXTURES:                       {
2128
                bitmap_index bitmap;
2129
                bitmap = bm_load_sub(skip, arg);
2130
                Assert(tmap_count < MAX_TEXTURES);
2131
                tmap_count++;
2132
                Textures[texture_count] = bitmap;
2133
                set_texture_name( arg );
2134
                Assert(texture_count < MAX_TEXTURES);
2135
                texture_count++;
2136
                NumTextures = texture_count;
2137
#if defined(DXX_BUILD_DESCENT_II)
2138
                return;
2139
#endif
2140
                }
2141
                break;
2142
        case BM_WCLIP:
2143
#if defined(DXX_BUILD_DESCENT_I)
2144
                bm_read_wclip(arg, skip);
2145
                break;
2146
        default:
2147
#elif defined(DXX_BUILD_DESCENT_II)
2148
                bm_read_wclip(skip);
2149
                return;
2150
#endif
2151
                break;
2152
        }
2153
#if defined(DXX_BUILD_DESCENT_II)
2154
        Error("Trying to read bitmap <%s> with unknown bm_flag <%x> on line %d of BITMAPS.TBL",arg,bm_flag,linenum);
2155
#endif
2156
}
2157
 
2158
}
2159
 
2160
// ------------------------------------------------------------------------------
2161
//      If unused_flag is set, then this is just a placeholder.  Don't actually reference vclips or load bbms.
2162
#if defined(DXX_BUILD_DESCENT_I)
2163
void bm_read_weapon(char *&arg, int skip, int unused_flag)
2164
#elif defined(DXX_BUILD_DESCENT_II)
2165
void bm_read_weapon(int skip, int unused_flag)
2166
#endif
2167
{
2168
        int     i,n;
2169
        int     n_models=0;
2170
        char    *equal_ptr;
2171
        char    *pof_file_inner=NULL;
2172
        char    *model_name[MAX_MODEL_VARIANTS];
2173
        int     first_bitmap_num[MAX_MODEL_VARIANTS];
2174
        int     lighted;                                        //flag for whether is a texture is lighted
2175
 
2176
        Assert(N_weapon_types < MAX_WEAPON_TYPES);
2177
 
2178
        n = N_weapon_types;
2179
        N_weapon_types++;
2180
#if defined(DXX_BUILD_DESCENT_II)
2181
        Assert(N_weapon_types <= MAX_WEAPON_TYPES);
2182
#endif
2183
 
2184
        if (unused_flag) {
2185
#if defined(DXX_BUILD_DESCENT_I)
2186
                clear_to_end_of_line(arg);
2187
#elif defined(DXX_BUILD_DESCENT_II)
2188
                clear_to_end_of_line();
2189
#endif
2190
                return;
2191
        }
2192
 
2193
        if (skip) {
2194
#if defined(DXX_BUILD_DESCENT_I)
2195
                clear_to_end_of_line(arg);
2196
#elif defined(DXX_BUILD_DESCENT_II)
2197
                clear_to_end_of_line();
2198
#endif
2199
                return;
2200
        }
2201
 
2202
        // Initialize weapon array
2203
        Weapon_info[n].render_type = WEAPON_RENDER_NONE;                // 0=laser, 1=blob, 2=object
2204
        Weapon_info[n].bitmap.index = 0;
2205
        Weapon_info[n].model_num = -1;
2206
        Weapon_info[n].model_num_inner = -1;
2207
        Weapon_info[n].blob_size = 0x1000;                                                                      // size of blob
2208
        Weapon_info[n].flash_vclip = vclip_none;
2209
        Weapon_info[n].flash_sound = SOUND_LASER_FIRED;
2210
        Weapon_info[n].flash_size = 0;
2211
        Weapon_info[n].robot_hit_vclip = vclip_none;
2212
        Weapon_info[n].robot_hit_sound = sound_none;
2213
        Weapon_info[n].wall_hit_vclip = vclip_none;
2214
        Weapon_info[n].wall_hit_sound = sound_none;
2215
        Weapon_info[n].impact_size = 0;
2216
        for (i=0; i<NDL; i++) {
2217
                Weapon_info[n].strength[i] = F1_0;
2218
                Weapon_info[n].speed[i] = F1_0*10;
2219
        }
2220
        Weapon_info[n].mass = F1_0;
2221
        Weapon_info[n].thrust = 0;
2222
        Weapon_info[n].drag = 0;
2223
        Weapon_info[n].persistent = 0;
2224
 
2225
        Weapon_info[n].energy_usage = 0;                                        //      How much fuel is consumed to fire this weapon.
2226
        Weapon_info[n].ammo_usage = 0;                                  //      How many units of ammunition it uses.
2227
        Weapon_info[n].fire_wait = F1_0/4;                              //      Time until this weapon can be fired again.
2228
        Weapon_info[n].fire_count = 1;                                  //      Number of bursts fired from EACH GUN per firing.  For weapons which fire from both sides, 3*fire_count shots will be fired.
2229
        Weapon_info[n].damage_radius = 0;                               //      Radius of damage for missiles, not lasers.  Does damage to objects within this radius of hit point.
2230
//--01/19/95, mk--      Weapon_info[n].damage_force = 0;                                        //      Force (movement) due to explosion
2231
        Weapon_info[n].destroyable = 1;                                 //      Weapons default to destroyable
2232
        Weapon_info[n].matter = 0;                                                      //      Weapons default to not being constructed of matter (they are energy!)
2233
        Weapon_info[n].bounce = 0;                                                      //      Weapons default to not bouncing off walls
2234
 
2235
#if defined(DXX_BUILD_DESCENT_II)
2236
        Weapon_info[n].flags = 0;
2237
#endif
2238
 
2239
        Weapon_info[n].lifetime = WEAPON_DEFAULT_LIFETIME;                                      //      Number of bursts fired from EACH GUN per firing.  For weapons which fire from both sides, 3*fire_count shots will be fired.
2240
 
2241
        Weapon_info[n].po_len_to_width_ratio = F1_0*10;
2242
 
2243
        Weapon_info[n].picture.index = 0;
2244
#if defined(DXX_BUILD_DESCENT_II)
2245
        Weapon_info[n].hires_picture.index = 0;
2246
#endif
2247
        Weapon_info[n].homing_flag = 0;
2248
 
2249
#if defined(DXX_BUILD_DESCENT_II)
2250
        Weapon_info[n].flash = 0;
2251
        Weapon_info[n].multi_damage_scale = F1_0;
2252
        Weapon_info[n].afterburner_size = 0;
2253
        Weapon_info[n].children = weapon_id_type::unspecified;
2254
#endif
2255
 
2256
        // Process arguments
2257
        arg = strtok( NULL, space_tab );
2258
 
2259
        lighted = 1;                    //assume first texture is lighted
2260
 
2261
#if defined(DXX_BUILD_DESCENT_II)
2262
        Weapon_info[n].speedvar = 128;
2263
#endif
2264
 
2265
        while (arg!=NULL)       {
2266
                equal_ptr = strchr( arg, '=' );
2267
                if ( equal_ptr )        {
2268
                        *equal_ptr='\0';
2269
                        equal_ptr++;
2270
                        // if we have john=cool, arg is 'john' and equal_ptr is 'cool'
2271
                        if (!d_stricmp( arg, "laser_bmp" ))     {
2272
                                // Load bitmap with name equal_ptr
2273
 
2274
                                Weapon_info[n].bitmap = bm_load_sub(skip, equal_ptr);           //load_polymodel_bitmap(equal_ptr);
2275
                                Weapon_info[n].render_type = WEAPON_RENDER_LASER;
2276
 
2277
                        } else if (!d_stricmp( arg, "blob_bmp" ))       {
2278
                                // Load bitmap with name equal_ptr
2279
 
2280
                                Weapon_info[n].bitmap = bm_load_sub(skip, equal_ptr);           //load_polymodel_bitmap(equal_ptr);
2281
                                Weapon_info[n].render_type = WEAPON_RENDER_BLOB;
2282
 
2283
                        } else if (!d_stricmp( arg, "weapon_vclip" ))   {
2284
                                // Set vclip to play for this weapon.
2285
                                Weapon_info[n].bitmap.index = 0;
2286
                                Weapon_info[n].render_type = WEAPON_RENDER_VCLIP;
2287
                                Weapon_info[n].weapon_vclip = atoi(equal_ptr);
2288
 
2289
                        } else if (!d_stricmp( arg, "none_bmp" )) {
2290
                                Weapon_info[n].bitmap = bm_load_sub(skip, equal_ptr);
2291
                                Weapon_info[n].render_type = WEAPON_RENDER_NONE;
2292
 
2293
                        } else if (!d_stricmp( arg, "weapon_pof" ))     {
2294
                                // Load pof file
2295
                                Assert(n_models==0);
2296
                                model_name[0] = equal_ptr;
2297
                                first_bitmap_num[0] = N_ObjBitmapPtrs;
2298
                                n_models=1;
2299
                        } else if (!d_stricmp( arg, "simple_model" )) {
2300
                                model_name[n_models] = equal_ptr;
2301
                                first_bitmap_num[n_models] = N_ObjBitmapPtrs;
2302
                                n_models++;
2303
#if defined(DXX_BUILD_DESCENT_II)
2304
                                Assert(n_models < MAX_MODEL_VARIANTS);
2305
#endif
2306
                        } else if (!d_stricmp( arg, "weapon_pof_inner" ))       {
2307
                                // Load pof file
2308
                                pof_file_inner = equal_ptr;
2309
                        } else if (!d_stricmp( arg, "strength" )) {
2310
                                for (i=0; i<NDL-1; i++) {
2311
#if defined(DXX_BUILD_DESCENT_I)
2312
                                        Weapon_info[n].strength[i] = i2f(atoi(equal_ptr));
2313
#elif defined(DXX_BUILD_DESCENT_II)
2314
                                        Weapon_info[n].strength[i] = fl2f(atof(equal_ptr));
2315
#endif
2316
                                        equal_ptr = strtok(NULL, space_tab);
2317
                                }
2318
                                Weapon_info[n].strength[i] = i2f(atoi(equal_ptr));
2319
                        } else if (!d_stricmp( arg, "mass" )) {
2320
                                Weapon_info[n].mass = fl2f(atof(equal_ptr));
2321
                        } else if (!d_stricmp( arg, "drag" )) {
2322
                                Weapon_info[n].drag = fl2f(atof(equal_ptr));
2323
                        } else if (!d_stricmp( arg, "thrust" )) {
2324
                                Weapon_info[n].thrust = fl2f(atof(equal_ptr));
2325
                        } else if (!d_stricmp( arg, "matter" )) {
2326
                                Weapon_info[n].matter = atoi(equal_ptr);
2327
                        } else if (!d_stricmp( arg, "bounce" )) {
2328
                                Weapon_info[n].bounce = atoi(equal_ptr);
2329
                        } else if (!d_stricmp( arg, "speed" )) {
2330
                                for (i=0; i<NDL-1; i++) {
2331
                                        Weapon_info[n].speed[i] = i2f(atoi(equal_ptr));
2332
                                        equal_ptr = strtok(NULL, space_tab);
2333
                                }
2334
                                Weapon_info[n].speed[i] = i2f(atoi(equal_ptr));
2335
                        }
2336
#if defined(DXX_BUILD_DESCENT_II)
2337
                        else if (!d_stricmp( arg, "speedvar" )) {
2338
                                Weapon_info[n].speedvar = (atoi(equal_ptr) * 128) / 100;
2339
                        }
2340
#endif
2341
                        else if (!d_stricmp( arg, "flash_vclip" ))      {
2342
                                Weapon_info[n].flash_vclip = atoi(equal_ptr);
2343
                        } else if (!d_stricmp( arg, "flash_sound" ))    {
2344
                                Weapon_info[n].flash_sound = atoi(equal_ptr);
2345
                        } else if (!d_stricmp( arg, "flash_size" ))     {
2346
                                Weapon_info[n].flash_size = fl2f(atof(equal_ptr));
2347
                        } else if (!d_stricmp( arg, "blob_size" ))      {
2348
                                Weapon_info[n].blob_size = fl2f(atof(equal_ptr));
2349
                        } else if (!d_stricmp( arg, "robot_hit_vclip" ))        {
2350
                                Weapon_info[n].robot_hit_vclip = atoi(equal_ptr);
2351
                        } else if (!d_stricmp( arg, "robot_hit_sound" ))        {
2352
                                Weapon_info[n].robot_hit_sound = atoi(equal_ptr);
2353
                        } else if (!d_stricmp( arg, "wall_hit_vclip" )) {
2354
                                Weapon_info[n].wall_hit_vclip = atoi(equal_ptr);
2355
                        } else if (!d_stricmp( arg, "wall_hit_sound" )) {
2356
                                Weapon_info[n].wall_hit_sound = atoi(equal_ptr);
2357
                        } else if (!d_stricmp( arg, "impact_size" ))    {
2358
                                Weapon_info[n].impact_size = fl2f(atof(equal_ptr));
2359
                        } else if (!d_stricmp( arg, "lighted" ))        {
2360
                                lighted = atoi(equal_ptr);
2361
                        } else if (!d_stricmp( arg, "lw_ratio" ))       {
2362
                                Weapon_info[n].po_len_to_width_ratio = fl2f(atof(equal_ptr));
2363
                        } else if (!d_stricmp( arg, "lightcast" ))      {
2364
                                Weapon_info[n].light = fl2f(atof(equal_ptr));
2365
                        } else if (!d_stricmp( arg, "persistent" ))     {
2366
                                Weapon_info[n].persistent = atoi(equal_ptr);
2367
                        } else if (!d_stricmp(arg, "energy_usage" )) {
2368
                                Weapon_info[n].energy_usage = fl2f(atof(equal_ptr));
2369
                        } else if (!d_stricmp(arg, "ammo_usage" )) {
2370
                                Weapon_info[n].ammo_usage = atoi(equal_ptr);
2371
                        } else if (!d_stricmp(arg, "fire_wait" )) {
2372
                                Weapon_info[n].fire_wait = fl2f(atof(equal_ptr));
2373
                        } else if (!d_stricmp(arg, "fire_count" )) {
2374
                                Weapon_info[n].fire_count = atoi(equal_ptr);
2375
                        } else if (!d_stricmp(arg, "damage_radius" )) {
2376
                                Weapon_info[n].damage_radius = fl2f(atof(equal_ptr));
2377
//--01/19/95, mk--                      } else if (!d_stricmp(arg, "damage_force" )) {
2378
//--01/19/95, mk--                              Weapon_info[n].damage_force = fl2f(atof(equal_ptr));
2379
                        } else if (!d_stricmp(arg, "lifetime" )) {
2380
                                Weapon_info[n].lifetime = fl2f(atof(equal_ptr));
2381
                        } else if (!d_stricmp(arg, "destroyable" )) {
2382
                                Weapon_info[n].destroyable = atoi(equal_ptr);
2383
                        } else if (!d_stricmp(arg, "picture" )) {
2384
                                Weapon_info[n].picture = bm_load_sub(skip, equal_ptr);
2385
                        }
2386
#if defined(DXX_BUILD_DESCENT_II)
2387
                        else if (!d_stricmp(arg, "hires_picture" )) {
2388
                                Weapon_info[n].hires_picture = bm_load_sub(skip, equal_ptr);
2389
                        }
2390
#endif
2391
                        else if (!d_stricmp(arg, "homing" )) {
2392
                                Weapon_info[n].homing_flag = !!atoi(equal_ptr);
2393
                        }
2394
#if defined(DXX_BUILD_DESCENT_II)
2395
                        else if (!d_stricmp(arg, "flash" )) {
2396
                                Weapon_info[n].flash = atoi(equal_ptr);
2397
                        } else if (!d_stricmp(arg, "multi_damage_scale" )) {
2398
                                Weapon_info[n].multi_damage_scale = fl2f(atof(equal_ptr));
2399
                        } else if (!d_stricmp(arg, "afterburner_size" )) {
2400
                                Weapon_info[n].afterburner_size = f2i(16*fl2f(atof(equal_ptr)));
2401
                        } else if (!d_stricmp(arg, "children" )) {
2402
                                Weapon_info[n].children = static_cast<weapon_id_type>(atoi(equal_ptr));
2403
                        } else if (!d_stricmp(arg, "placable" )) {
2404
                                if (atoi(equal_ptr)) {
2405
                                        Weapon_info[n].flags |= WIF_PLACABLE;
2406
                                }
2407
                        } else {
2408
                                Int3();
2409
                        }
2410
#endif
2411
                } else {                        // Must be a texture specification...
2412
                        grs_bitmap *bm;
2413
 
2414
                        bm = load_polymodel_bitmap(skip, arg);
2415
#if defined(DXX_BUILD_DESCENT_I)
2416
                        if (bm && ! lighted)
2417
#elif defined(DXX_BUILD_DESCENT_II)
2418
                        if (! lighted)
2419
#endif
2420
                                bm->add_flags(BM_FLAG_NO_LIGHTING);
2421
 
2422
                        lighted = 1;                    //default for next bitmap is lighted
2423
                }
2424
                arg = strtok( NULL, space_tab );
2425
        }
2426
 
2427
        first_bitmap_num[n_models] = N_ObjBitmapPtrs;
2428
 
2429
        auto &Polygon_models = LevelSharedPolygonModelState.Polygon_models;
2430
        for (i=0;i<n_models;i++) {
2431
                int n_textures;
2432
                int model_num,last_model_num=0;
2433
 
2434
                n_textures = first_bitmap_num[i+1] - first_bitmap_num[i];
2435
 
2436
                model_num = load_polygon_model(model_name[i],n_textures,first_bitmap_num[i],NULL);
2437
 
2438
                if (i==0) {
2439
                        Weapon_info[n].render_type = WEAPON_RENDER_POLYMODEL;
2440
                        Weapon_info[n].model_num = model_num;
2441
                }
2442
                else
2443
                        Polygon_models[last_model_num].simpler_model = model_num+1;
2444
 
2445
                last_model_num = model_num;
2446
        }
2447
 
2448
        if ( pof_file_inner )   {
2449
                Assert(n_models);
2450
                Weapon_info[n].model_num_inner = load_polygon_model(pof_file_inner,first_bitmap_num[1]-first_bitmap_num[0],first_bitmap_num[0],NULL);
2451
        }
2452
}
2453
 
2454
// ------------------------------------------------------------------------------
2455
#define DEFAULT_POWERUP_SIZE i2f(3)
2456
 
2457
#if defined(DXX_BUILD_DESCENT_I)
2458
void bm_read_powerup(char *&arg, int unused_flag)
2459
#elif defined(DXX_BUILD_DESCENT_II)
2460
void bm_read_powerup(int unused_flag)
2461
#endif
2462
{
2463
        int n;
2464
        char    *equal_ptr;
2465
 
2466
        Assert(N_powerup_types < MAX_POWERUP_TYPES);
2467
 
2468
        n = N_powerup_types;
2469
        N_powerup_types++;
2470
 
2471
        if (unused_flag) {
2472
#if defined(DXX_BUILD_DESCENT_I)
2473
                clear_to_end_of_line(arg);
2474
#elif defined(DXX_BUILD_DESCENT_II)
2475
                clear_to_end_of_line();
2476
#endif
2477
                return;
2478
        }
2479
 
2480
        // Initialize powerup array
2481
        Powerup_info[n].light = F1_0/3;         //      Default lighting value.
2482
        Powerup_info[n].vclip_num = vclip_none;
2483
        Powerup_info[n].hit_sound = sound_none;
2484
        Powerup_info[n].size = DEFAULT_POWERUP_SIZE;
2485
#if DXX_USE_EDITOR
2486
        Powerup_names[n][0] = 0;
2487
#endif
2488
 
2489
        // Process arguments
2490
        arg = strtok( NULL, space_tab );
2491
 
2492
        while (arg!=NULL)       {
2493
                equal_ptr = strchr( arg, '=' );
2494
                if ( equal_ptr )        {
2495
                        *equal_ptr='\0';
2496
                        equal_ptr++;
2497
                        // if we have john=cool, arg is 'john' and equal_ptr is 'cool'
2498
                        if (!d_stricmp( arg, "vclip_num" ))     {
2499
                                Powerup_info[n].vclip_num = atoi(equal_ptr);
2500
                        } else if (!d_stricmp( arg, "light" ))  {
2501
                                Powerup_info[n].light = fl2f(atof(equal_ptr));
2502
                        } else if (!d_stricmp( arg, "hit_sound" ))      {
2503
                                Powerup_info[n].hit_sound = atoi(equal_ptr);
2504
                        } else if (!d_stricmp( arg, "name" )) {
2505
#if DXX_USE_EDITOR
2506
                                auto &name = Powerup_names[n];
2507
                                const auto len = strlen(equal_ptr);
2508
                                assert(len < name.size());      //      Oops, name too long.
2509
                                memcpy(name.data(), &equal_ptr[1], len - 2);
2510
                                name[len - 2] = 0;
2511
#endif
2512
                        } else if (!d_stricmp( arg, "size" ))   {
2513
                                Powerup_info[n].size = fl2f(atof(equal_ptr));
2514
                        }
2515
#if defined(DXX_BUILD_DESCENT_II)
2516
                        else {
2517
                                Int3();
2518
                        }
2519
#endif
2520
                }
2521
#if defined(DXX_BUILD_DESCENT_II)
2522
                else {                  // Must be a texture specification...
2523
                        Int3();
2524
                }
2525
#endif
2526
                arg = strtok( NULL, space_tab );
2527
        }
2528
#if defined(DXX_BUILD_DESCENT_I)
2529
        ObjType[Num_total_object_types] = OL_POWERUP;
2530
        ObjId[Num_total_object_types] = n;
2531
        Num_total_object_types++;
2532
#endif
2533
}
2534
 
2535
#if defined(DXX_BUILD_DESCENT_I)
2536
void bm_read_hostage(char *&arg)
2537
#elif defined(DXX_BUILD_DESCENT_II)
2538
void bm_read_hostage()
2539
#endif
2540
{
2541
        int n;
2542
        char    *equal_ptr;
2543
 
2544
        Assert(N_hostage_types < MAX_HOSTAGE_TYPES);
2545
 
2546
        n = N_hostage_types;
2547
        N_hostage_types++;
2548
 
2549
        // Process arguments
2550
        arg = strtok( NULL, space_tab );
2551
 
2552
        while (arg!=NULL)       {
2553
                equal_ptr = strchr( arg, '=' );
2554
                if ( equal_ptr )        {
2555
                        *equal_ptr='\0';
2556
                        equal_ptr++;
2557
 
2558
                        if (!d_stricmp( arg, "vclip_num" ))
2559
 
2560
                                Hostage_vclip_num[n] = atoi(equal_ptr);
2561
 
2562
#if defined(DXX_BUILD_DESCENT_II)
2563
                        else {
2564
                                Int3();
2565
                        }
2566
#endif
2567
                }
2568
#if defined(DXX_BUILD_DESCENT_II)
2569
                else {
2570
                        Int3();
2571
                }
2572
#endif
2573
                arg = strtok( NULL, space_tab );
2574
        }
2575
#if defined(DXX_BUILD_DESCENT_I)
2576
        ObjType[Num_total_object_types] = OL_HOSTAGE;
2577
        ObjId[Num_total_object_types] = n;
2578
        Num_total_object_types++;
2579
#endif
2580
}
2581
 
2582
#if defined(DXX_BUILD_DESCENT_I)
2583
DEFINE_SERIAL_UDT_TO_MESSAGE(tmap_info, t, (static_cast<const std::array<char, 13> &>(t.filename), t.flags, t.lighting, t.damage, t.eclip_num));
2584
ASSERT_SERIAL_UDT_MESSAGE_SIZE(tmap_info, 26);
2585
#elif defined(DXX_BUILD_DESCENT_II)
2586
DEFINE_SERIAL_UDT_TO_MESSAGE(tmap_info, t, (t.flags, serial::pad<3>(), t.lighting, t.damage, t.eclip_num, t.destroyed, t.slide_u, t.slide_v));
2587
ASSERT_SERIAL_UDT_MESSAGE_SIZE(tmap_info, 20);
2588
#endif