- /* 
-  * Portions of this file are copyright Rebirth contributors and licensed as 
-  * described in COPYING.txt. 
-  * Portions of this file are copyright Parallax Software and licensed 
-  * according to the Parallax license below. 
-  * See COPYING.txt for license details. 
-   
- THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX 
- SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO 
- END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A 
- ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS 
- IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS 
- SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE 
- FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE 
- CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS 
- AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. 
- COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED. 
- */ 
-   
- /* 
-  * 
-  * Routines to parse bitmaps.tbl 
-  * Only used for editor, since the registered version of descent 1. 
-  * 
-  */ 
-   
- #include <algorithm> 
- #include <string> 
- #include <stdio.h> 
- #include <stdlib.h> 
- #include <stdarg.h> 
- #include <string.h> 
- #include <ctype.h> 
-   
- #include "pstypes.h" 
- #include "gr.h" 
- #include "bm.h" 
- #include "u_mem.h" 
- #include "dxxerror.h" 
- #include "object.h" 
- #include "physfsx.h" 
- #include "vclip.h" 
- #include "effects.h" 
- #include "polyobj.h" 
- #include "wall.h" 
- #include "textures.h" 
- #include "game.h" 
- #include "iff.h" 
- #include "hostage.h" 
- #include "powerup.h" 
- #include "laser.h" 
- #include "sounds.h" 
- #include "piggy.h" 
- #include "aistruct.h" 
- #include "robot.h" 
- #include "weapon.h" 
- #include "gauges.h" 
- #include "player.h" 
- #include "endlevel.h" 
- #include "cntrlcen.h" 
- #include "physfs-serial.h" 
- #include "args.h" 
- #include "text.h" 
- #if defined(DXX_BUILD_DESCENT_I) 
- #include "fuelcen.h" 
- #elif defined(DXX_BUILD_DESCENT_II) 
- #include "gamepal.h" 
- #include "interp.h" 
- #endif 
- #include "strutil.h" 
- #if DXX_USE_EDITOR 
- #include "editor/texpage.h" 
- #endif 
-   
- #include "compiler-cf_assert.h" 
- #include "compiler-range_for.h" 
- #include "partial_range.h" 
- #include "d_enumerate.h" 
- #include "d_range.h" 
-   
- using std::min; 
-   
- #define BM_NONE                 -1 
- #define BM_COCKPIT               0 
- #define BM_TEXTURES              2 
- #define BM_UNUSED                        3 
- #define BM_VCLIP                         4 
- #define BM_EFFECTS          5 
- #define BM_ECLIP                         6 
- #define BM_WEAPON                        7 
- #define BM_DEMO                  8 
- #define BM_ROBOTEX          9 
- #define BM_WALL_ANIMS   12 
- #define BM_WCLIP                        13 
- #define BM_ROBOT                        14 
- #define BM_GAUGES                       20 
-   
- namespace { 
-   
- uint8_t wall_explodes_flag; 
- uint8_t wall_blastable_flag; 
- uint8_t wall_hidden_flag; 
- uint8_t tmap1_flag;             //flag if this is used as tmap_num (not tmap_num2) 
-   
- } 
-   
- #if defined(DXX_BUILD_DESCENT_I) 
- static short            N_ObjBitmaps=0; 
- #elif defined(DXX_BUILD_DESCENT_II) 
- #define BM_GAUGES_HIRES 21 
- #endif 
-   
- static short            N_ObjBitmapPtrs=0; 
- static int                      Num_robot_ais = 0; 
- namespace dsx { 
- #if DXX_USE_EDITOR 
- powerup_names_array Powerup_names; 
- robot_names_array Robot_names; 
- #endif 
- } 
-   
- //---------------- Internal variables --------------------------- 
- static int                      SuperX = -1; 
- static int                      Installed=0; 
- static short            tmap_count = 0; 
- static short            texture_count = 0; 
- #if defined(DXX_BUILD_DESCENT_I) 
- static unsigned         clip_count; 
- static unsigned         clip_num; 
- static uint16_t         frames; 
- #elif defined(DXX_BUILD_DESCENT_II) 
- static char             *arg; 
- static short            clip_count = 0; 
- static short            clip_num; 
- static short            frames; 
- static char             *dest_bm;               //clip number to play when destroyed 
- #endif 
- static short            sound_num; 
- static float            play_time; 
- static int                      hit_sound = -1; 
- static sbyte            bm_flag = BM_NONE; 
- static int                      abm_flag = 0; 
- static int                      rod_flag = 0; 
- static short            wall_open_sound, wall_close_sound; 
- static float            vlighting=0; 
- static int                      obj_eclip; 
- static int                      dest_vclip;             //what vclip to play when exploding 
- static int                      dest_eclip;             //what eclip to play when exploding 
- static fix                      dest_size;              //3d size of explosion 
- static int                      crit_clip;              //clip number to play when destroyed 
- static int                      crit_flag;              //flag if this is a destroyed eclip 
- static int                      num_sounds=0; 
-   
- static int linenum;             //line int table currently being parsed 
-   
- //------------------- Useful macros and variables --------------- 
-   
- #define IFTOK(str) if (!strcmp(arg, str)) 
-   
- //      For the sake of LINT, defining prototypes to module's functions 
- #if defined(DXX_BUILD_DESCENT_I) 
- static void bm_read_sound(char *&arg, int skip, int pc_shareware); 
- static void bm_read_robot_ai(char *&arg, int skip); 
- static void bm_read_robot(char *&arg, int skip); 
- static void bm_read_object(char *&arg, int skip); 
- static void bm_read_player_ship(char *&arg, int skip); 
- namespace dsx { 
- static void bm_read_some_file(d_vclip_array &Vclip, const std::string &dest_bm, char *&arg, int skip); 
- } 
- static void bm_read_weapon(char *&arg, int skip, int unused_flag); 
- static void bm_read_powerup(char *&arg, int unused_flag); 
- static void bm_read_hostage(char *&arg); 
- static void verify_textures(); 
- #elif defined(DXX_BUILD_DESCENT_II) 
- static void bm_read_alias(void); 
- static void bm_read_marker(void); 
- static void bm_read_robot_ai(int skip); 
- static void bm_read_powerup(int unused_flag); 
- static void bm_read_hostage(void); 
- static void bm_read_robot(int skip); 
- static void bm_read_weapon(int skip, int unused_flag); 
- static void bm_read_reactor(void); 
- static void bm_read_exitmodel(void); 
- static void bm_read_player_ship(void); 
- namespace dsx { 
- static void bm_read_some_file(d_vclip_array &Vclip, int skip); 
- } 
- static void bm_read_sound(int skip); 
- static void clear_to_end_of_line(void); 
- static void verify_textures(void); 
- #endif 
-   
- //--------------------------------------------------------------- 
- int compute_average_pixel(grs_bitmap *n) 
- { 
-         int     total_red, total_green, total_blue; 
-   
- #if defined(DXX_BUILD_DESCENT_II) 
-         auto pptr = n->bm_data; 
- #endif 
-         const unsigned bm_h = n->bm_h, bm_w = n->bm_w; 
-   
-         total_red = 0; 
-         total_green = 0; 
-         total_blue = 0; 
-   
-         const auto product = (bm_h * bm_w); 
- #if defined(DXX_BUILD_DESCENT_I) 
-         for (unsigned row = 0; row < bm_h; row++) 
-                 for (unsigned column = 0; column < bm_w; column++) 
- #elif defined(DXX_BUILD_DESCENT_II) 
-         for (auto counter = product; counter--;) 
- #endif 
-         { 
- #if defined(DXX_BUILD_DESCENT_I) 
-                 const auto color = gr_gpixel (*n, column, row); 
-                 const auto &p = gr_palette[color]; 
- #elif defined(DXX_BUILD_DESCENT_II) 
-                 const auto &p = gr_palette[*pptr++]; 
- #endif 
-                 total_red += p.r; 
-                 total_green += p.g; 
-                 total_blue += p.b; 
-                 } 
-   
-         total_red /= product; 
-         total_green /= product; 
-         total_blue /= product; 
-   
-         return BM_XRGB(total_red/2, total_green/2, total_blue/2); 
- } 
-   
- //--------------------------------------------------------------- 
- // Loads a bitmap from either the piggy file, a r64 file, or a 
- // whatever extension is passed. 
-   
- static bitmap_index bm_load_sub(const int skip, const char *const filename) 
- { 
-         bitmap_index bitmap_num; 
-         palette_array_t newpal; 
-         int iff_error;          //reference parm to avoid warning message 
-   
-         bitmap_num.index = 0; 
-   
-         if (skip) { 
-                 return bitmap_num; 
-         } 
-   
-         std::array<char, 20> fname{}; 
- #if defined(DXX_BUILD_DESCENT_I) 
-         removeext(filename, fname); 
- #elif defined(DXX_BUILD_DESCENT_II) 
-         struct splitpath_t path; 
-         d_splitpath(  filename, &path); 
-         if (path.base_end - path.base_start >= fname.size()) 
-                 Error("File <%s> - bitmap error, filename too long", filename); 
-         memcpy(fname.data(), path.base_start, path.base_end - path.base_start); 
- #endif 
-   
-         bitmap_num = piggy_find_bitmap(fname.data()); 
-         if (bitmap_num.index)   { 
-                 return bitmap_num; 
-         } 
-   
-         grs_bitmap n; 
-         iff_error = iff_read_bitmap(filename, n, &newpal); 
-         if (iff_error != IFF_NO_ERROR)          { 
-                 Error("File <%s> - IFF error: %s, line %d",filename,iff_errormsg(iff_error),linenum); 
-         } 
-   
-         gr_remap_bitmap_good(n, newpal, iff_has_transparency ? iff_transparent_color : -1, SuperX); 
-   
- #if !DXX_USE_OGL 
-         n.avg_color = compute_average_pixel(&n); 
- #endif 
-   
-         bitmap_num = piggy_register_bitmap(n, fname.data(), 0); 
-         return bitmap_num; 
- } 
-   
- static void ab_load(int skip, const char * filename, std::array<bitmap_index, MAX_BITMAPS_PER_BRUSH> &bmp, unsigned *nframes ) 
- { 
-         bitmap_index bi; 
-         int iff_error;          //reference parm to avoid warning message 
-         palette_array_t newpal; 
-         std::array<char, 24> tempname; 
-   
-         if (skip) { 
-                 Assert( bogus_bitmap_initialized != 0 ); 
- #if defined(DXX_BUILD_DESCENT_I) 
-                 bmp[0] = piggy_register_bitmap(bogus_bitmap, "bogus", 0); 
- #elif defined(DXX_BUILD_DESCENT_II) 
-                 bmp[0].index = 0;               //index of bogus bitmap==0 (I think)            //&bogus_bitmap; 
- #endif 
-                 *nframes = 1; 
-                 return; 
-         } 
-   
-   
- #if defined(DXX_BUILD_DESCENT_I) 
-         std::array<char, 20> fname; 
-         removeext(filename, fname); 
- #elif defined(DXX_BUILD_DESCENT_II) 
-         struct splitpath_t path; 
-         d_splitpath( filename, &path); 
- #endif 
-   
-         { 
-         unsigned i; 
-         for (i=0; i<MAX_BITMAPS_PER_BRUSH; i++ )        { 
- #if defined(DXX_BUILD_DESCENT_I) 
-                 snprintf(tempname.data(), tempname.size(), "%.16s#%d", fname.data(), i); 
- #elif defined(DXX_BUILD_DESCENT_II) 
-                 snprintf(tempname.data(), tempname.size(), "%.*s#%d", DXX_ptrdiff_cast_int(path.base_end - path.base_start), path.base_start, i); 
- #endif 
-                 bi = piggy_find_bitmap(tempname.data()); 
-                 if ( !bi.index ) 
-                         break; 
-                 bmp[i] = bi; 
-         } 
-   
-         if (i) { 
-                 *nframes = i; 
-                 return; 
-         } 
-         } 
-   
- //      Note that last argument passes an address to the array newpal (which is a pointer). 
- //      type mismatch found using lint, will substitute this line with an adjusted 
- //      one.  If fatal error, then it can be easily changed. 
-         std::array<std::unique_ptr<grs_main_bitmap>, MAX_BITMAPS_PER_BRUSH> bm; 
-         iff_error = iff_read_animbrush(filename,bm,nframes,newpal); 
-         if (iff_error != IFF_NO_ERROR)  { 
-                 Error("File <%s> - IFF error: %s, line %d",filename,iff_errormsg(iff_error),linenum); 
-         } 
-   
-         const auto nf = *nframes; 
- #if defined(DXX_BUILD_DESCENT_I) 
-         if (nf >= bm.size()) 
-                 return; 
- #endif 
-         range_for (const uint_fast32_t i, xrange(nf)) 
-         { 
-                 cf_assert(i < bm.size()); 
- #if defined(DXX_BUILD_DESCENT_I) 
-                 snprintf(tempname.data(), tempname.size(), "%s#%" PRIuFAST32, fname.data(), i); 
- #elif defined(DXX_BUILD_DESCENT_II) 
-                 snprintf(tempname.data(), tempname.size(), "%.*s#%" PRIuFAST32, DXX_ptrdiff_cast_int(path.base_end - path.base_start), path.base_start, i ); 
- #endif 
-                 gr_remap_bitmap_good(*bm[i].get(), newpal, iff_has_transparency ? iff_transparent_color : -1, SuperX); 
- #if !DXX_USE_OGL 
-                 bm[i]->avg_color = compute_average_pixel(bm[i].get()); 
- #endif 
-                 bmp[i] = piggy_register_bitmap(*bm[i].get(), tempname.data(), 0); 
-         } 
- } 
-   
- int ds_load(int skip, const char * filename )   { 
-         int i; 
-         digi_sound n; 
-         char rawname[100]; 
-   
-         if (skip) { 
-                 // We tell piggy_register_sound it's in the pig file, when in actual fact it's in no file 
-                 // This just tells piggy_close not to attempt to free it 
-                 return piggy_register_sound( &bogus_sound, "bogus", 1 ); 
-         } 
-   
-         std::array<char, 20> fname; 
-         removeext(filename, fname); 
- #if defined(DXX_BUILD_DESCENT_I) 
-         snprintf(rawname, sizeof(rawname), "Sounds/%s.raw", fname.data()); 
- #elif defined(DXX_BUILD_DESCENT_II) 
-         snprintf(rawname, sizeof(rawname), "Sounds/%s.%s", fname.data(), (GameArg.SndDigiSampleRate==SAMPLE_RATE_22K) ? "r22" : "raw"); 
- #endif 
-   
-         i = piggy_find_sound(fname.data()); 
-         if (i!=255)     { 
-                 return i; 
-         } 
-         if (auto cfp = PHYSFSX_openReadBuffered(rawname)) 
-         { 
-                 n.length        = PHYSFS_fileLength( cfp ); 
-                 MALLOC( n.data, ubyte, n.length ); 
-                 PHYSFS_read( cfp, n.data, 1, n.length ); 
-                 n.bits = 8; 
-                 n.freq = 11025; 
-         } else { 
-                 return 255; 
-         } 
-         i = piggy_register_sound(&n, fname.data(), 0); 
-         return i; 
- } 
-   
- //parse a float 
- static float get_float() 
- { 
-         char *xarg; 
-   
-         xarg = strtok( NULL, space_tab ); 
-         return atof( xarg ); 
- } 
-   
- //parse an int 
- static int get_int() 
- { 
-         char *xarg; 
-   
-         xarg = strtok( NULL, space_tab ); 
-         return atoi( xarg ); 
- } 
-   
- // rotates a byte left one bit, preserving the bit falling off the right 
- //void 
- //rotate_left(char *c) 
- //{ 
- //      int found; 
- // 
- //      found = 0; 
- //      if (*c & 0x80) 
- //              found = 1; 
- //      *c = *c << 1; 
- //      if (found) 
- //              *c |= 0x01; 
- //} 
-   
- #if defined(DXX_BUILD_DESCENT_II) 
- //loads a texture and returns the texture num 
- static int get_texture(char *name) 
- { 
-         auto &TmapInfo = LevelUniqueTmapInfoState.TmapInfo; 
-         char short_name[FILENAME_LEN]; 
-         int i; 
-   
-         strcpy(short_name,name); 
-         REMOVE_DOTS(short_name); 
-         for (i=0;i<texture_count;i++) 
-                 if (!d_stricmp(TmapInfo[i].filename,short_name)) 
-                         break; 
-         if (i==texture_count) { 
-                 Textures[texture_count] = bm_load_sub(0, name); 
-                 TmapInfo[texture_count].filename.copy_if(short_name); 
-                 texture_count++; 
-                 Assert(texture_count < MAX_TEXTURES); 
-                 NumTextures = texture_count; 
-         } 
-   
-         return i; 
- } 
-   
- #define DEFAULT_PIG_PALETTE     "groupa.256" 
- #endif 
-   
- #define LINEBUF_SIZE 600 
-   
- namespace dsx { 
-   
- //----------------------------------------------------------------- 
- // Initializes all properties and bitmaps from BITMAPS.TBL file. 
- // This is called when the editor is IN. 
- // If no editor, properties_read_cmp() is called. 
- int gamedata_read_tbl(d_vclip_array &Vclip, int pc_shareware) 
- { 
-         auto &Effects = LevelUniqueEffectsClipState.Effects; 
-         auto &TmapInfo = LevelUniqueTmapInfoState.TmapInfo; 
-         auto &WallAnims = GameSharedState.WallAnims; 
-         int     have_bin_tbl; 
-   
- #if defined(DXX_BUILD_DESCENT_I) 
-         std::string dest_bm; 
-         ObjType[0] = OL_PLAYER; 
-         ObjId[0] = 0; 
-         Num_total_object_types = 1; 
- #elif defined(DXX_BUILD_DESCENT_II) 
-         // Open BITMAPS.TBL for reading. 
-         have_bin_tbl = 0; 
-         auto InfoFile = PHYSFSX_openReadBuffered("BITMAPS.TBL"); 
-         if (!InfoFile) 
-         { 
-                 InfoFile = PHYSFSX_openReadBuffered("BITMAPS.BIN"); 
-                 if (!InfoFile) 
-                         return 0;       //missing BITMAPS.TBL and BITMAPS.BIN file 
-                 have_bin_tbl = 1; 
-         } 
-   
-         gr_use_palette_table(DEFAULT_PIG_PALETTE); 
-   
-         load_palette(DEFAULT_PIG_PALETTE,-2,0);         //special: tell palette code which pig is loaded 
- #endif 
-   
-         for (unsigned i = 0; i < MAX_SOUNDS; ++i) 
-         { 
-                 Sounds[i] = 255; 
-                 AltSounds[i] = 255; 
-         } 
-   
-         DXX_MAKE_VAR_UNDEFINED(TmapInfo); 
-         range_for (auto &ti, TmapInfo) 
-         { 
-                 ti.eclip_num = eclip_none; 
-                 ti.flags = 0; 
- #if defined(DXX_BUILD_DESCENT_II) 
-                 ti.slide_u = ti.slide_v = 0; 
-                 ti.destroyed = -1; 
- #endif 
-         } 
-   
- #if defined(DXX_BUILD_DESCENT_II) 
-         DXX_MAKE_VAR_UNDEFINED(Reactors); 
-         range_for (auto &i, Reactors) 
-                 i.model_num = -1; 
- #endif 
-   
-         Num_effects = 0; 
-         DXX_MAKE_VAR_UNDEFINED(Effects); 
-         range_for (auto &ec, Effects) 
-         { 
-                 //Effects[i].bm_ptr = (grs_bitmap **) -1; 
-                 ec.changing_wall_texture = -1; 
-                 ec.changing_object_texture = -1; 
-                 ec.segnum = segment_none; 
-                 ec.vc.num_frames = -1;          //another mark of being unused 
-         } 
-   
-         for (unsigned i = 0; i < MAX_POLYGON_MODELS; ++i) 
-                 Dying_modelnums[i] = Dead_modelnums[i] = -1; 
-   
-         Num_vclips = 0; 
-         DXX_MAKE_VAR_UNDEFINED(Vclip); 
-         range_for (auto &vc, Vclip) 
-         { 
-                 vc.num_frames = -1; 
-                 vc.flags = 0; 
-         } 
-   
-         DXX_MAKE_VAR_UNDEFINED(WallAnims); 
-         range_for (auto &wa, WallAnims) 
-                 wa.num_frames = wclip_frames_none; 
-         Num_wall_anims = 0; 
-   
-         if (Installed) 
-                 return 1; 
-   
-         Installed = 1; 
-   
- #if defined(DXX_BUILD_DESCENT_I) 
-         // Open BITMAPS.TBL for reading. 
-         have_bin_tbl = 0; 
-         auto InfoFile = PHYSFSX_openReadBuffered("BITMAPS.TBL"); 
-         if (!InfoFile) 
-         { 
-                 InfoFile = PHYSFSX_openReadBuffered("BITMAPS.BIN"); 
-                 if (!InfoFile) 
-                         Error("Missing BITMAPS.TBL and BITMAPS.BIN file\n"); 
-                 have_bin_tbl = 1; 
-         } 
- #endif 
-         linenum = 0; 
-   
-         PHYSFSX_fseek( InfoFile, 0L, SEEK_SET); 
-   
-         PHYSFSX_gets_line_t<LINEBUF_SIZE> inputline; 
-         while (PHYSFSX_fgets(inputline, InfoFile)) { 
-                 int l; 
-                 const char *temp_ptr; 
-                 int skip; 
-   
-                 linenum++; 
-                 if (have_bin_tbl) {                             // is this a binary tbl file 
-                         decode_text_line (inputline); 
-                 } else { 
-                         while (inputline[(l=strlen(inputline))-2]=='\\') { 
-                                 if (!isspace(inputline[l-3])) {         //if not space before backslash... 
-                                         inputline[l-2] = ' ';                           //add one 
-                                         l++; 
-                                 } 
-                                 PHYSFSX_fgets(inputline,InfoFile,l-2); 
-                                 linenum++; 
-                         } 
-                 } 
-   
-                 REMOVE_EOL(inputline); 
-                 if (strchr(inputline, ';')!=NULL) REMOVE_COMMENTS(inputline); 
-   
-                 if (strlen(inputline) == LINEBUF_SIZE-1) 
-                         Error("Possible line truncation in BITMAPS.TBL on line %d\n",linenum); 
-   
-                 SuperX = -1; 
-   
-                 if ( (temp_ptr=strstr( inputline, "superx=" )) )        { 
-                         /* Historically, this was done with atoi, so the input 
-                          * source was allowed to have unconvertible characters. 
-                          * Accept such lines by ignoring any trailing content. 
-                          */ 
-                         SuperX = strtol(&temp_ptr[7], nullptr, 10); 
- #if defined(DXX_BUILD_DESCENT_II) 
-                         Assert(SuperX == 254); 
-                                 //the superx color isn't kept around, so the new piggy regeneration 
-                                 //code doesn't know what it is, so it assumes that it's 254, so 
-                                 //this code requires that it be 254 
- #endif 
-                 } 
-   
- #if defined(DXX_BUILD_DESCENT_I) 
-                 char *arg = strtok( inputline, space_tab ); 
- #elif defined(DXX_BUILD_DESCENT_II) 
-                 arg = strtok( inputline, space_tab ); 
- #endif 
-                 if (arg && arg[0] == '@') 
-                 { 
-                         arg++; 
-                         skip = pc_shareware; 
-                 } else 
-                         skip = 0; 
-   
-                 while (arg != NULL ) 
-                         { 
-                         // Check all possible flags and defines. 
-                         if (*arg == '$') bm_flag = BM_NONE; // reset to no flags as default. 
-   
-                         IFTOK("$COCKPIT")                       bm_flag = BM_COCKPIT; 
-                         else IFTOK("$GAUGES")           {bm_flag = BM_GAUGES;   clip_count = 0;} 
- #if defined(DXX_BUILD_DESCENT_I) 
-                         else IFTOK("$SOUND")            bm_read_sound(arg, skip, pc_shareware); 
- #elif defined(DXX_BUILD_DESCENT_II) 
-                         else IFTOK("$GAUGES_HIRES"){bm_flag = BM_GAUGES_HIRES; clip_count = 0;} 
-                         else IFTOK("$ALIAS")                    bm_read_alias(); 
-                         else IFTOK("$SOUND")            bm_read_sound(skip); 
- #endif 
-                         else IFTOK("$DOOR_ANIMS")       bm_flag = BM_WALL_ANIMS; 
-                         else IFTOK("$WALL_ANIMS")       bm_flag = BM_WALL_ANIMS; 
-                         else IFTOK("$TEXTURES")         bm_flag = BM_TEXTURES; 
-                         else IFTOK("$VCLIP")                    {bm_flag = BM_VCLIP;            vlighting = 0;  clip_count = 0;} 
-                         else IFTOK("$ECLIP") 
-                         { 
-                                 bm_flag = BM_ECLIP; 
-                                 vlighting = 0; 
-                                 clip_count = 0; 
-                                 obj_eclip=0; 
- #if defined(DXX_BUILD_DESCENT_I) 
-                                 dest_bm.clear(); 
- #elif defined(DXX_BUILD_DESCENT_II) 
-                                 dest_bm=NULL; 
- #endif 
-                                 dest_vclip=vclip_none; 
-                                 dest_eclip=eclip_none; 
-                                 dest_size=-1; 
-                                 crit_clip=-1; 
-                                 crit_flag=0; 
-                                 sound_num=sound_none; 
-                         } 
-                         else IFTOK("$WCLIP") 
-                         { 
-                                 bm_flag = BM_WCLIP; 
-                                 vlighting = 0; 
-                                 clip_count = 0; 
-                                 wall_open_sound=wall_close_sound=sound_none; 
-                                 wall_explodes_flag = 0; 
-                                 wall_blastable_flag = 0; 
-                                 tmap1_flag=0; 
-                                 wall_hidden_flag = 0; 
-                         } 
-   
-                         else IFTOK("$EFFECTS")          {bm_flag = BM_EFFECTS;  clip_num = 0;} 
-   
- #if DXX_USE_EDITOR 
-                         else IFTOK("!METALS_FLAG")              TextureMetals = texture_count; 
-                         else IFTOK("!LIGHTS_FLAG")              TextureLights = texture_count; 
-                         else IFTOK("!EFFECTS_FLAG")     TextureEffects = texture_count; 
-                         #else 
- #if defined(DXX_BUILD_DESCENT_I) 
-                         else IFTOK("!METALS_FLAG") ; 
-                         else IFTOK("!LIGHTS_FLAG") ; 
-                         else IFTOK("!EFFECTS_FLAG") ; 
- #endif 
-                         #endif 
-   
-                         else IFTOK("lighting")                  TmapInfo[texture_count-1].lighting = fl2f(get_float()); 
-                         else IFTOK("damage")                    TmapInfo[texture_count-1].damage = fl2f(get_float()); 
-                         else IFTOK("volatile")                  TmapInfo[texture_count-1].flags |= TMI_VOLATILE; 
- #if defined(DXX_BUILD_DESCENT_II) 
-                         else IFTOK("goal_blue")                 TmapInfo[texture_count-1].flags |= TMI_GOAL_BLUE; 
-                         else IFTOK("goal_red")                  TmapInfo[texture_count-1].flags |= TMI_GOAL_RED; 
-                         else IFTOK("water")                             TmapInfo[texture_count-1].flags |= TMI_WATER; 
-                         else IFTOK("force_field")               TmapInfo[texture_count-1].flags |= TMI_FORCE_FIELD; 
-                         else IFTOK("slide")                             {TmapInfo[texture_count-1].slide_u = fl2f(get_float())>>8; TmapInfo[texture_count-1].slide_v = fl2f(get_float())>>8;} 
-                         else IFTOK("destroyed")                 {int t=texture_count-1; TmapInfo[t].destroyed = get_texture(strtok( NULL, space_tab ));} 
- #endif 
-                         //else IFTOK("Num_effects")             Num_effects = get_int(); 
-                         else IFTOK("Num_wall_anims")    Num_wall_anims = get_int(); 
-                         else IFTOK("clip_num")                  clip_num = get_int(); 
- #if defined(DXX_BUILD_DESCENT_I) 
-                         else IFTOK("dest_bm") 
-                         { 
-                                 char *p = strtok( NULL, space_tab ); 
-                                 if (p) 
-                                         dest_bm = p; 
-                                 else 
-                                         dest_bm.clear(); 
-                         } 
- #elif defined(DXX_BUILD_DESCENT_II) 
-                         else IFTOK("dest_bm")                   dest_bm = strtok( NULL, space_tab ); 
- #endif 
-                         else IFTOK("dest_vclip")                dest_vclip = get_int(); 
-                         else IFTOK("dest_eclip")                dest_eclip = get_int(); 
-                         else IFTOK("dest_size")                 dest_size = fl2f(get_float()); 
-                         else IFTOK("crit_clip")                 crit_clip = get_int(); 
-                         else IFTOK("crit_flag")                 crit_flag = get_int(); 
-                         else IFTOK("sound_num")                 sound_num = get_int(); 
-                         else IFTOK("frames")                    frames = get_int(); 
-                         else IFTOK("time")                              play_time = get_float(); 
-                         else IFTOK("obj_eclip")                 obj_eclip = get_int(); 
-                         else IFTOK("hit_sound")                 hit_sound = get_int(); 
-                         else IFTOK("abm_flag")                  abm_flag = get_int(); 
-                         else IFTOK("tmap1_flag")                tmap1_flag = get_int() ? WCF_TMAP1 : 0; 
-                         else IFTOK("vlighting")                 vlighting = get_float(); 
-                         else IFTOK("rod_flag")                  rod_flag = get_int(); 
-                         else IFTOK("superx")                    get_int(); 
-                         else IFTOK("open_sound")                wall_open_sound = get_int(); 
-                         else IFTOK("close_sound")               wall_close_sound = get_int(); 
-                         else IFTOK("explodes")                  wall_explodes_flag = get_int() ? WCF_EXPLODES : 0; 
-                         else IFTOK("blastable")                 wall_blastable_flag = get_int() ? WCF_BLASTABLE : 0; 
-                         else IFTOK("hidden")                    wall_hidden_flag = get_int() ? WCF_HIDDEN : 0; 
- #if defined(DXX_BUILD_DESCENT_I) 
-                         else IFTOK("$ROBOT_AI")                 bm_read_robot_ai(arg, skip); 
-   
-                         else IFTOK("$POWERUP")                  {bm_read_powerup(arg, 0);               continue;} 
-                         else IFTOK("$POWERUP_UNUSED")   {bm_read_powerup(arg, 1);               continue;} 
-                         else IFTOK("$HOSTAGE")                  {bm_read_hostage(arg);          continue;} 
-                         else IFTOK("$ROBOT")                            {bm_read_robot(arg, skip);                      continue;} 
-                         else IFTOK("$WEAPON")                   {bm_read_weapon(arg, skip, 0);          continue;} 
-                         else IFTOK("$WEAPON_UNUSED")    {bm_read_weapon(arg, skip, 1);          continue;} 
-                         else IFTOK("$OBJECT")                   {bm_read_object(arg, skip);             continue;} 
-                         else IFTOK("$PLAYER_SHIP")              {bm_read_player_ship(arg, skip);        continue;} 
- #elif defined(DXX_BUILD_DESCENT_II) 
-                         else IFTOK("$ROBOT_AI")                 bm_read_robot_ai(skip); 
-   
-                         else IFTOK("$POWERUP")                  {bm_read_powerup(0);            continue;} 
-                         else IFTOK("$POWERUP_UNUSED")   {bm_read_powerup(1);            continue;} 
-                         else IFTOK("$HOSTAGE")                  {bm_read_hostage();             continue;} 
-                         else IFTOK("$ROBOT")                            {bm_read_robot(skip);                   continue;} 
-                         else IFTOK("$WEAPON")                   {bm_read_weapon(skip, 0);               continue;} 
-                         else IFTOK("$WEAPON_UNUSED")    {bm_read_weapon(skip, 1);               continue;} 
-                         else IFTOK("$REACTOR")                  {bm_read_reactor();             continue;} 
-                         else IFTOK("$MARKER")                   {bm_read_marker();              continue;} 
-                         else IFTOK("$PLAYER_SHIP")              {bm_read_player_ship(); continue;} 
-                         else IFTOK("$EXIT") { 
-                                 if (pc_shareware) 
-                                         bm_read_exitmodel(); 
-                                 else 
-                                         clear_to_end_of_line(); 
-                                 continue; 
-                         } 
- #endif 
-                         else    {               //not a special token, must be a bitmap! 
-   
-                                 // Remove any illegal/unwanted spaces and tabs at this point. 
-                                 while ((*arg=='\t') || (*arg==' ')) arg++; 
-                                 if (*arg == '\0') { break; } 
-   
- #if defined(DXX_BUILD_DESCENT_II) 
-                                 //check for '=' in token, indicating error 
-                                 if (strchr(arg,'=')) 
-                                         Error("Unknown token <'%s'> on line %d of BITMAPS.TBL",arg,linenum); 
- #endif 
-   
-                                 // Otherwise, 'arg' is apparently a bitmap filename. 
-                                 // Load bitmap and process it below: 
- #if defined(DXX_BUILD_DESCENT_I) 
-                                 bm_read_some_file(Vclip, dest_bm, arg, skip); 
- #elif defined(DXX_BUILD_DESCENT_II) 
-                                 bm_read_some_file(Vclip, skip); 
- #endif 
-   
-                         } 
-   
-                         arg = strtok( NULL, equal_space ); 
-                         continue; 
-       } 
-         } 
-   
-         NumTextures = texture_count; 
-         LevelUniqueTmapInfoState.Num_tmaps = tmap_count; 
-   
- #if defined(DXX_BUILD_DESCENT_II) 
-         Textures[NumTextures++].index = 0;              //entry for bogus tmap 
-         InfoFile.reset(); 
- #endif 
-         assert(LevelSharedRobotInfoState.N_robot_types == Num_robot_ais);               //should be one ai info per robot 
-   
-         verify_textures(); 
-   
-         //check for refereced but unused clip count 
-         range_for (auto &&en, enumerate(Effects)) 
-         { 
-                 auto &e = en.value; 
-                 if ((e.changing_wall_texture != -1 || e.changing_object_texture != -1) && e.vc.num_frames == ~0u) 
-                         Error("EClip %" PRIuFAST32 " referenced (by polygon object?), but not defined", en.idx); 
-         } 
-   
- #if defined(DXX_BUILD_DESCENT_II) 
-         #ifndef NDEBUG 
-         { 
-                 //make sure all alt sounds refer to valid main sounds 
-                 for (unsigned i = 0; i < num_sounds; ++i) 
-                 { 
-                         int alt = AltSounds[i]; 
-                         Assert(alt==0 || alt==-1 || Sounds[alt]!=255); 
-                 } 
-         } 
-         #endif 
-   
-         gr_use_palette_table(D2_DEFAULT_PALETTE); 
- #endif 
-   
-         return 0; 
- } 
-   
- } 
-   
- void verify_textures() 
- { 
- #if defined(DXX_BUILD_DESCENT_II) 
-         auto &Effects = LevelUniqueEffectsClipState.Effects; 
- #endif 
-         grs_bitmap * bmp; 
-         int j; 
-         j=0; 
-         const auto Num_tmaps = LevelUniqueTmapInfoState.Num_tmaps; 
-         for (uint_fast32_t i = 0; i < Num_tmaps; ++i) 
-         { 
-                 bmp = &GameBitmaps[Textures[i].index]; 
-                 if ( (bmp->bm_w!=64)||(bmp->bm_h!=64)||(bmp->bm_rowsize!=64) )  { 
-                         j++; 
-                 } 
-         } 
-         if (j) 
-                 Error("%d textures were not 64x64.",j); 
-   
- #if defined(DXX_BUILD_DESCENT_II) 
-         for (uint_fast32_t i = 0; i < Num_effects; ++i) 
-                 if (Effects[i].changing_object_texture != -1) 
-                         if (GameBitmaps[ObjBitmaps[Effects[i].changing_object_texture].index].bm_w!=64 || GameBitmaps[ObjBitmaps[Effects[i].changing_object_texture].index].bm_h!=64) 
-                                 Error("Effect %" PRIuFAST32 " is used on object, but is not 64x64",i); 
- #endif 
- } 
-   
- #if defined(DXX_BUILD_DESCENT_II) 
- void bm_read_alias() 
- { 
-         char *t; 
-   
-         Assert(Num_aliases < MAX_ALIASES); 
-   
-         t = strtok( NULL, space_tab );  strncpy(alias_list[Num_aliases].alias_name,t,sizeof(alias_list[Num_aliases].alias_name)); 
-         t = strtok( NULL, space_tab );  strncpy(alias_list[Num_aliases].file_name,t,sizeof(alias_list[Num_aliases].file_name)); 
-   
-         Num_aliases++; 
- } 
- #endif 
-   
- static void set_lighting_flag(grs_bitmap &bmp) 
- { 
-         bmp.set_flag_mask(vlighting < 0, BM_FLAG_NO_LIGHTING); 
- } 
-   
- static void set_texture_name(const char *name) 
- { 
-         auto &TmapInfo = LevelUniqueTmapInfoState.TmapInfo; 
-         TmapInfo[texture_count].filename.copy_if(name, FILENAME_LEN); 
-         REMOVE_DOTS(&TmapInfo[texture_count].filename[0u]); 
- } 
-   
- #if defined(DXX_BUILD_DESCENT_I) 
- static void bm_read_eclip(const std::string &dest_bm, const char *const arg, int skip) 
- #elif defined(DXX_BUILD_DESCENT_II) 
- static void bm_read_eclip(int skip) 
- #endif 
- { 
-         auto &Effects = LevelUniqueEffectsClipState.Effects; 
-         auto &TmapInfo = LevelUniqueTmapInfoState.TmapInfo; 
-         bitmap_index bitmap; 
-   
-         assert(clip_num < Effects.size()); 
-   
-         if (clip_num+1 > Num_effects) 
-                 Num_effects = clip_num+1; 
-   
-         Effects[clip_num].flags = 0; 
-   
- #if defined(DXX_BUILD_DESCENT_II) 
-         unsigned dest_bm_num = 0; 
-         //load the dest bitmap first, so that after this routine, the last-loaded 
-         //texture will be the monitor, so that lighting parameter will be applied 
-         //to the correct texture 
-         if (dest_bm) {                  //deal with bitmap for blown up clip 
-                 d_fname short_name; 
-                 int i; 
-                 short_name.copy_if(dest_bm, FILENAME_LEN); 
-                 REMOVE_DOTS(&short_name[0u]); 
-                 for (i=0;i<texture_count;i++) 
-                         if (!d_stricmp(TmapInfo[i].filename,short_name)) 
-                                 break; 
-                 if (i==texture_count) { 
-                         Textures[texture_count] = bm_load_sub(skip, dest_bm); 
-                         TmapInfo[texture_count].filename = short_name; 
-                         texture_count++; 
-                         Assert(texture_count < MAX_TEXTURES); 
-                         NumTextures = texture_count; 
-                 } 
-                 else if (Textures[i].index == 0)                //was found, but registered out 
-                         Textures[i] = bm_load_sub(skip, dest_bm); 
-                 dest_bm_num = i; 
-         } 
- #endif 
-   
-         if (!abm_flag) 
-         { 
-                 bitmap = bm_load_sub(skip, arg); 
-   
-                 Effects[clip_num].vc.play_time = fl2f(play_time); 
-                 Effects[clip_num].vc.num_frames = frames; 
-                 Effects[clip_num].vc.frame_time = fl2f(play_time)/frames; 
-   
-                 Assert(clip_count < frames); 
-                 Effects[clip_num].vc.frames[clip_count] = bitmap; 
-                 set_lighting_flag(GameBitmaps[bitmap.index]); 
-   
-                 Assert(!obj_eclip);             //obj eclips for non-abm files not supported! 
-                 Assert(crit_flag==0); 
-   
-                 if (clip_count == 0) { 
-                         Effects[clip_num].changing_wall_texture = texture_count; 
-                         Assert(tmap_count < MAX_TEXTURES); 
-                         tmap_count++; 
-                         Textures[texture_count] = bitmap; 
-                         set_texture_name(arg); 
-                         Assert(texture_count < MAX_TEXTURES); 
-                         texture_count++; 
-                         TmapInfo[texture_count].eclip_num = clip_num; 
-                         NumTextures = texture_count; 
-                 } 
-   
-                 clip_count++; 
-   
-         } else { 
-                 std::array<bitmap_index, MAX_BITMAPS_PER_BRUSH> bm; 
-                 abm_flag = 0; 
-   
-                 ab_load(skip, arg, bm, &Effects[clip_num].vc.num_frames ); 
-   
-                 Effects[clip_num].vc.play_time = fl2f(play_time); 
-                 Effects[clip_num].vc.frame_time = Effects[clip_num].vc.play_time/Effects[clip_num].vc.num_frames; 
-   
-                 clip_count = 0; 
-                 set_lighting_flag(GameBitmaps[bm[clip_count].index]); 
-                 Effects[clip_num].vc.frames[clip_count] = bm[clip_count]; 
-   
-                 if (!obj_eclip && !crit_flag) { 
-                         Effects[clip_num].changing_wall_texture = texture_count; 
-                         Assert(tmap_count < MAX_TEXTURES); 
-                         tmap_count++; 
-                         Textures[texture_count] = bm[clip_count]; 
-                         set_texture_name( arg ); 
-                         Assert(texture_count < MAX_TEXTURES); 
-                         TmapInfo[texture_count].eclip_num = clip_num; 
-                         texture_count++; 
-                         NumTextures = texture_count; 
-                 } 
-   
-                 if (obj_eclip) { 
-   
-                         if (Effects[clip_num].changing_object_texture == -1) {          //first time referenced 
-                                 Effects[clip_num].changing_object_texture = N_ObjBitmaps;               // XChange ObjectBitmaps 
-                                 N_ObjBitmaps++; 
-                         } 
-   
-                         ObjBitmaps[Effects[clip_num].changing_object_texture] = Effects[clip_num].vc.frames[0]; 
-                 } 
-   
-                 //if for an object, Effects_bm_ptrs set in object load 
-   
-                 for(clip_count=1;clip_count < Effects[clip_num].vc.num_frames; clip_count++) { 
-                         set_lighting_flag(GameBitmaps[bm[clip_count].index]); 
-                         Effects[clip_num].vc.frames[clip_count] = bm[clip_count]; 
-                 } 
-   
-         } 
-   
-         Effects[clip_num].crit_clip = crit_clip; 
-         Effects[clip_num].sound_num = sound_num; 
-   
- #if defined(DXX_BUILD_DESCENT_I) 
-         if (!dest_bm.empty()) 
- #elif defined(DXX_BUILD_DESCENT_II) 
-         if (dest_bm) 
- #endif 
-         {                       //deal with bitmap for blown up clip 
- #if defined(DXX_BUILD_DESCENT_I) 
-                 char short_name[13]; 
-                 int i; 
-                 strcpy(short_name,dest_bm.c_str()); 
-                 REMOVE_DOTS(short_name); 
-                 for (i=0;i<texture_count;i++) 
-                         if (!d_stricmp(static_cast<const char *>(TmapInfo[i].filename),short_name)) 
-                                 break; 
-                 if (i==texture_count) { 
-                         Textures[texture_count] = bm_load_sub(skip, dest_bm.c_str()); 
-                         TmapInfo[texture_count].filename.copy_if(short_name); 
-                         texture_count++; 
-                         Assert(texture_count < MAX_TEXTURES); 
-                         NumTextures = texture_count; 
-                 } 
-                 Effects[clip_num].dest_bm_num = i; 
- #elif defined(DXX_BUILD_DESCENT_II) 
-                 Effects[clip_num].dest_bm_num = dest_bm_num; 
- #endif 
-   
-                 if (dest_vclip==vclip_none) 
-                         Error("Desctuction vclip missing on line %d",linenum); 
-                 if (dest_size==-1) 
-                         Error("Desctuction vclip missing on line %d",linenum); 
-   
-                 Effects[clip_num].dest_vclip = dest_vclip; 
-                 Effects[clip_num].dest_size = dest_size; 
-   
-                 Effects[clip_num].dest_eclip = dest_eclip; 
-         } 
-         else { 
-                 Effects[clip_num].dest_bm_num = ~0u; 
-                 Effects[clip_num].dest_eclip = eclip_none; 
-         } 
-   
-         if (crit_flag) 
-                 Effects[clip_num].flags |= EF_CRITICAL; 
- } 
-   
- #if defined(DXX_BUILD_DESCENT_I) 
- static void bm_read_gauges(const char *const arg, int skip) 
- #elif defined(DXX_BUILD_DESCENT_II) 
- static void bm_read_gauges(int skip) 
- #endif 
- { 
-         bitmap_index bitmap; 
-         unsigned i, num_abm_frames; 
-   
-         if (!abm_flag)  { 
-                 bitmap = bm_load_sub(skip, arg); 
-                 Assert(clip_count < MAX_GAUGE_BMS); 
-                 Gauges[clip_count] = bitmap; 
-                 clip_count++; 
-         } else { 
-                 std::array<bitmap_index, MAX_BITMAPS_PER_BRUSH> bm; 
-                 abm_flag = 0; 
-                 ab_load(skip, arg, bm, &num_abm_frames ); 
-                 for (i=clip_count; i<clip_count+num_abm_frames; i++) { 
-                         Assert(i < MAX_GAUGE_BMS); 
-                         Gauges[i] = bm[i-clip_count]; 
-                 } 
-                 clip_count += num_abm_frames; 
-         } 
- } 
-   
- #if defined(DXX_BUILD_DESCENT_I) 
- static void bm_read_wclip(char *const arg, int skip) 
- #elif defined(DXX_BUILD_DESCENT_II) 
- static void bm_read_gauges_hires() 
- { 
-         bitmap_index bitmap; 
-         unsigned i, num_abm_frames; 
-   
-         if (!abm_flag)  { 
-                 bitmap = bm_load_sub(0, arg); 
-                 Assert(clip_count < MAX_GAUGE_BMS); 
-                 Gauges_hires[clip_count] = bitmap; 
-                 clip_count++; 
-         } else { 
-                 std::array<bitmap_index, MAX_BITMAPS_PER_BRUSH> bm; 
-                 abm_flag = 0; 
-                 ab_load(0, arg, bm, &num_abm_frames ); 
-                 for (i=clip_count; i<clip_count+num_abm_frames; i++) { 
-                         Assert(i < MAX_GAUGE_BMS); 
-                         Gauges_hires[i] = bm[i-clip_count]; 
-                 } 
-                 clip_count += num_abm_frames; 
-         } 
- } 
-   
- static void bm_read_wclip(int skip) 
- #endif 
- { 
-         auto &TmapInfo = LevelUniqueTmapInfoState.TmapInfo; 
-         auto &WallAnims = GameSharedState.WallAnims; 
-         bitmap_index bitmap; 
-         Assert(clip_num < MAX_WALL_ANIMS); 
-   
-         auto &wa = WallAnims[clip_num]; 
-         wa.flags = wall_explodes_flag | wall_blastable_flag | wall_hidden_flag | tmap1_flag; 
-   
-         if (!abm_flag)  { 
-                 bitmap = bm_load_sub(skip, arg); 
-                 if (wa.num_frames != wclip_frames_none && clip_count == 0) 
-                         Error( "Wall Clip %d is already used!", clip_num ); 
-                 wa.play_time = fl2f(play_time); 
-                 wa.num_frames = frames; 
-                 //WallAnims[clip_num].frame_time = fl2f(play_time)/frames; 
-                 Assert(clip_count < frames); 
-                 wa.frames[clip_count++] = texture_count; 
-                 wa.open_sound = wall_open_sound; 
-                 wa.close_sound = wall_close_sound; 
-                 Textures[texture_count] = bitmap; 
-                 set_lighting_flag(GameBitmaps[bitmap.index]); 
-                 set_texture_name( arg ); 
-                 Assert(texture_count < MAX_TEXTURES); 
-                 texture_count++; 
-                 NumTextures = texture_count; 
-                 if (clip_num >= Num_wall_anims) Num_wall_anims = clip_num+1; 
-         } else { 
-                 std::array<bitmap_index, MAX_BITMAPS_PER_BRUSH> bm; 
-                 unsigned nframes; 
-                 if (wa.num_frames != wclip_frames_none) 
-                         Error( "AB_Wall clip %d is already used!", clip_num ); 
-                 abm_flag = 0; 
- #if defined(DXX_BUILD_DESCENT_I) 
-                 ab_load(skip, arg, bm, &nframes ); 
- #elif defined(DXX_BUILD_DESCENT_II) 
-                 ab_load(0, arg, bm, &nframes ); 
- #endif 
-                 wa.num_frames = nframes; 
-                 wa.play_time = fl2f(play_time); 
-                 //WallAnims[clip_num].frame_time = fl2f(play_time)/nframes; 
-                 wa.open_sound = wall_open_sound; 
-                 wa.close_sound = wall_close_sound; 
-                 strcpy(&wa.filename[0], arg); 
-                 REMOVE_DOTS(&wa.filename[0]); 
-   
-                 if (clip_num >= Num_wall_anims) Num_wall_anims = clip_num+1; 
-   
-                 set_lighting_flag(GameBitmaps[bm[clip_count].index]); 
-   
-                 for (clip_count=0;clip_count < wa.num_frames; clip_count++)     { 
-                         Textures[texture_count] = bm[clip_count]; 
-                         set_lighting_flag(GameBitmaps[bm[clip_count].index]); 
-                         wa.frames[clip_count] = texture_count; 
-                         REMOVE_DOTS(arg); 
-                         snprintf(&TmapInfo[texture_count].filename[0u], TmapInfo[texture_count].filename.size(), "%s#%d", arg, clip_count); 
-                         Assert(texture_count < MAX_TEXTURES); 
-                         texture_count++; 
-                         NumTextures = texture_count; 
-                 } 
-         } 
- } 
-   
- namespace dsx { 
-   
- #if defined(DXX_BUILD_DESCENT_I) 
- static void bm_read_vclip(d_vclip_array &Vclip, const char *const arg, int skip) 
- #elif defined(DXX_BUILD_DESCENT_II) 
- static void bm_read_vclip(d_vclip_array &Vclip, int skip) 
- #endif 
- { 
-         bitmap_index bi; 
-         assert(clip_num < Vclip.size()); 
-   
- #if defined(DXX_BUILD_DESCENT_II) 
-         if (clip_num >= Num_vclips) 
-                 Num_vclips = clip_num+1; 
- #endif 
-   
-         if (!abm_flag)  { 
-                 if (Vclip[clip_num].num_frames != ~0u && clip_count == 0) 
-                         Error( "Vclip %d is already used!", clip_num ); 
-                 bi = bm_load_sub(skip, arg); 
-                 Vclip[clip_num].play_time = fl2f(play_time); 
-                 Vclip[clip_num].num_frames = frames; 
-                 Vclip[clip_num].frame_time = fl2f(play_time)/frames; 
-                 Vclip[clip_num].light_value = fl2f(vlighting); 
-                 Vclip[clip_num].sound_num = sound_num; 
-                 set_lighting_flag(GameBitmaps[bi.index]); 
-                 Assert(clip_count < frames); 
-                 Vclip[clip_num].frames[clip_count++] = bi; 
-                 if (rod_flag) { 
-                         rod_flag=0; 
-                         Vclip[clip_num].flags |= VF_ROD; 
-                 } 
-   
-         } else  { 
-                 std::array<bitmap_index, MAX_BITMAPS_PER_BRUSH> bm; 
-                 abm_flag = 0; 
-                 if (Vclip[clip_num].num_frames != ~0u) 
-                         Error( "AB_Vclip %d is already used!", clip_num ); 
-                 ab_load(skip, arg, bm, &Vclip[clip_num].num_frames ); 
-   
-                 if (rod_flag) { 
-                         //int i; 
-                         rod_flag=0; 
-                         Vclip[clip_num].flags |= VF_ROD; 
-                 } 
-                 Vclip[clip_num].play_time = fl2f(play_time); 
-                 Vclip[clip_num].frame_time = fl2f(play_time)/Vclip[clip_num].num_frames; 
-                 Vclip[clip_num].light_value = fl2f(vlighting); 
-                 Vclip[clip_num].sound_num = sound_num; 
-                 set_lighting_flag(GameBitmaps[bm[clip_count].index]); 
-   
-                 for (clip_count=0;clip_count < Vclip[clip_num].num_frames; clip_count++) { 
-                         set_lighting_flag(GameBitmaps[bm[clip_count].index]); 
-                         Vclip[clip_num].frames[clip_count] = bm[clip_count]; 
-                 } 
-         } 
- } 
-   
- } 
-   
- // ------------------------------------------------------------------------------ 
- static void get4fix(std::array<fix, NDL> &fixp) 
- { 
-         char    *curtext; 
-         range_for (auto &i, fixp) 
-         { 
-                 curtext = strtok(NULL, space_tab); 
-                 i = fl2f(atof(curtext)); 
-         } 
- } 
-   
- // ------------------------------------------------------------------------------ 
- static void get4byte(std::array<int8_t, NDL> &bytep) 
- { 
-         char    *curtext; 
-         range_for (auto &i, bytep) 
-         { 
-                 curtext = strtok(NULL, space_tab); 
-                 i = atoi(curtext); 
-         } 
- } 
-   
- // ------------------------------------------------------------------------------ 
- //      Convert field of view from an angle in 0..360 to cosine. 
- static void adjust_field_of_view(std::array<fix, NDL> &fovp) 
- { 
-         fixang  tt; 
-         float           ff; 
-         range_for (auto &i, fovp) 
-         { 
-                 ff = - f2fl(i); 
-                 if (ff > 179) { 
-                         ff = 179; 
-                 } 
-                 ff = ff/360; 
-                 tt = fl2f(ff); 
-                 i = fix_cos(tt); 
-         } 
- } 
-   
- #if defined(DXX_BUILD_DESCENT_I) 
- static void clear_to_end_of_line(char *&arg) 
- { 
-         arg = NULL; 
- } 
- #elif defined(DXX_BUILD_DESCENT_II) 
- static void clear_to_end_of_line() 
- { 
-         arg = strtok( NULL, space_tab ); 
-         while (arg != NULL) 
-                 arg = strtok( NULL, space_tab ); 
- } 
- #endif 
-   
- #if defined(DXX_BUILD_DESCENT_I) 
- static void bm_read_sound(char *&arg, int skip, int pc_shareware) 
- #elif defined(DXX_BUILD_DESCENT_II) 
- void bm_read_sound(int skip) 
- #endif 
- { 
-         int alt_sound_num; 
-   
-         const int read_sound_num = get_int(); 
- #if defined(DXX_BUILD_DESCENT_I) 
-         alt_sound_num = pc_shareware ? read_sound_num : get_int(); 
- #elif defined(DXX_BUILD_DESCENT_II) 
-         alt_sound_num = get_int(); 
- #endif 
-   
-         if ( read_sound_num>=MAX_SOUNDS ) 
-                 Error( "Too many sound files.\n" ); 
-   
-         if (read_sound_num >= num_sounds) 
-                 num_sounds = read_sound_num+1; 
-   
- #if defined(DXX_BUILD_DESCENT_II) 
-         if (Sounds[read_sound_num] != 255) 
-                 Error("Sound num %d already used, bitmaps.tbl, line %d\n",read_sound_num,linenum); 
- #endif 
-   
-         arg = strtok(NULL, space_tab); 
-   
-         Sounds[read_sound_num] = ds_load(skip, arg); 
-   
-         if ( alt_sound_num == 0 ) 
-                 AltSounds[read_sound_num] = sound_num; 
-         else if (alt_sound_num < 0 ) 
-                 AltSounds[read_sound_num] = 255; 
-         else 
-                 AltSounds[read_sound_num] = alt_sound_num; 
-   
-         if (Sounds[read_sound_num] == 255) 
-                 Error("Can't load soundfile <%s>",arg); 
- } 
-   
- // ------------------------------------------------------------------------------ 
- #if defined(DXX_BUILD_DESCENT_I) 
- static void bm_read_robot_ai(char *&arg, const int skip) 
- #elif defined(DXX_BUILD_DESCENT_II) 
- void bm_read_robot_ai(const int skip) 
- #endif 
- { 
-         char                    *robotnum_text; 
-         int                     robotnum; 
-   
-         robotnum_text = strtok(NULL, space_tab); 
-         robotnum = atoi(robotnum_text); 
-         Assert(robotnum < MAX_ROBOT_TYPES); 
-         auto &Robot_info = LevelSharedRobotInfoState.Robot_info; 
-         auto &robptr = Robot_info[robotnum]; 
-   
-         Assert(robotnum == Num_robot_ais);              //make sure valid number 
-   
-         if (skip) { 
-                 Num_robot_ais++; 
- #if defined(DXX_BUILD_DESCENT_I) 
-                 clear_to_end_of_line(arg); 
- #elif defined(DXX_BUILD_DESCENT_II) 
-                 clear_to_end_of_line(); 
- #endif 
-                 return; 
-         } 
-   
-         Num_robot_ais++; 
-   
-         get4fix(robptr.field_of_view); 
-         get4fix(robptr.firing_wait); 
- #if defined(DXX_BUILD_DESCENT_II) 
-         get4fix(robptr.firing_wait2); 
- #endif 
-         get4byte(robptr.rapidfire_count); 
-         get4fix(robptr.turn_time); 
- #if defined(DXX_BUILD_DESCENT_I) 
-         std::array<fix, NDL>            fire_power,                                             //      damage done by a hit from this robot 
-                 shield;                                                 //      shield strength of this robot 
-         get4fix(fire_power); 
-         get4fix(shield); 
- #elif defined(DXX_BUILD_DESCENT_II) 
- //      get4fix(robptr->fire_power); 
- //      get4fix(robptr->shield); 
- #endif 
-         get4fix(robptr.max_speed); 
-         get4fix(robptr.circle_distance); 
-         get4byte(robptr.evade_speed); 
-   
-         robptr.always_0xabcd    = 0xabcd; 
-         adjust_field_of_view(robptr.field_of_view); 
- } 
-   
- //      ---------------------------------------------------------------------------------------------- 
- //this will load a bitmap for a polygon models.  it puts the bitmap into 
- //the array ObjBitmaps[], and also deals with animating bitmaps 
- //returns a pointer to the bitmap 
- static grs_bitmap *load_polymodel_bitmap(int skip, const char *name) 
- { 
-         auto &Effects = LevelUniqueEffectsClipState.Effects; 
-         assert(N_ObjBitmaps < ObjBitmaps.size()); 
-   
- //      Assert( N_ObjBitmaps == N_ObjBitmapPtrs ); 
-   
-         if (name[0] == '%') {           //an animating bitmap! 
-                 const unsigned eclip_num = atoi(name+1); 
-   
-                 if (Effects[eclip_num].changing_object_texture == -1) {         //first time referenced 
-                         Effects[eclip_num].changing_object_texture = N_ObjBitmaps; 
-                         ObjBitmapPtrs[N_ObjBitmapPtrs++] = N_ObjBitmaps; 
-                         N_ObjBitmaps++; 
-                 } else { 
-                         ObjBitmapPtrs[N_ObjBitmapPtrs++] = Effects[eclip_num].changing_object_texture; 
-                 } 
- #if defined(DXX_BUILD_DESCENT_II) 
-                 assert(N_ObjBitmaps < ObjBitmaps.size()); 
-                 assert(N_ObjBitmapPtrs < ObjBitmapPtrs.size()); 
- #endif 
-                 return NULL; 
-         } 
-         else    { 
-                 ObjBitmaps[N_ObjBitmaps] = bm_load_sub(skip, name); 
- #if defined(DXX_BUILD_DESCENT_II) 
-                 if (GameBitmaps[ObjBitmaps[N_ObjBitmaps].index].bm_w!=64 || GameBitmaps[ObjBitmaps[N_ObjBitmaps].index].bm_h!=64) 
-                         Error("Bitmap <%s> is not 64x64",name); 
- #endif 
-                 ObjBitmapPtrs[N_ObjBitmapPtrs++] = N_ObjBitmaps; 
-                 N_ObjBitmaps++; 
- #if defined(DXX_BUILD_DESCENT_II) 
-                 assert(N_ObjBitmaps < ObjBitmaps.size()); 
-                 assert(N_ObjBitmapPtrs < ObjBitmapPtrs.size()); 
- #endif 
-                 return &GameBitmaps[ObjBitmaps[N_ObjBitmaps-1].index]; 
-         } 
- } 
-   
- #define MAX_MODEL_VARIANTS      4 
-   
- // ------------------------------------------------------------------------------ 
- #if defined(DXX_BUILD_DESCENT_I) 
- static void bm_read_robot(char *&arg, int skip) 
- #elif defined(DXX_BUILD_DESCENT_II) 
- void bm_read_robot(int skip) 
- #endif 
- { 
-         char                    *model_name[MAX_MODEL_VARIANTS]; 
-         int                     n_models,i; 
-         int                     first_bitmap_num[MAX_MODEL_VARIANTS]; 
-         char                    *equal_ptr; 
-         int exp1_vclip_num = vclip_none; 
-         int exp1_sound_num = sound_none; 
-         int exp2_vclip_num = vclip_none; 
-         int exp2_sound_num = sound_none; 
-         fix                     lighting = F1_0/2;              // Default 
-         fix                     strength = F1_0*10;             // Default strength 
-         fix                     mass = f1_0*4; 
-         fix                     drag = f1_0/2; 
-         weapon_id_type weapon_type = weapon_id_type::LASER_ID_L1; 
-         int                     contains_count=0, contains_id=0, contains_prob=0, contains_type=0; 
- #if defined(DXX_BUILD_DESCENT_II) 
-         weapon_id_type weapon_type2 = weapon_id_type::unspecified; 
-         auto behavior = ai_behavior::AIB_NORMAL; 
-         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; 
-         fix                     glow=0, aim=F1_0; 
-         int                     deathroll_sound = SOUND_BOSS_SHARE_DIE; //default 
-         int                     taunt_sound = ROBOT_SEE_SOUND_DEFAULT; 
-         ubyte flags=0; 
- #endif 
-         int                     score_value=1000; 
-         int                     cloak_type=0;           //      Default = this robot does not cloak 
-         int                     attack_type=0;          //      Default = this robot attacks by firing (1=lunge) 
-         int                     boss_flag=0;                            //      Default = robot is not a boss. 
-         int                     see_sound = ROBOT_SEE_SOUND_DEFAULT; 
-         int                     attack_sound = ROBOT_ATTACK_SOUND_DEFAULT; 
-         int                     claw_sound = ROBOT_CLAW_SOUND_DEFAULT; 
-   
-         assert(LevelSharedRobotInfoState.N_robot_types < MAX_ROBOT_TYPES); 
-   
-         auto &Robot_info = LevelSharedRobotInfoState.Robot_info; 
-         if (skip) { 
-                 auto &ri = Robot_info[LevelSharedRobotInfoState.N_robot_types++]; 
-                 ri.model_num = -1; 
- #if defined(DXX_BUILD_DESCENT_I) 
-                 Num_total_object_types++; 
-                 clear_to_end_of_line(arg); 
- #elif defined(DXX_BUILD_DESCENT_II) 
-                 clear_to_end_of_line(); 
- #endif 
-                 return; 
-         } 
-   
-         model_name[0] = strtok( NULL, space_tab ); 
-         first_bitmap_num[0] = N_ObjBitmapPtrs; 
-         n_models = 1; 
-   
-         // Process bitmaps 
-         bm_flag=BM_ROBOT; 
-         arg = strtok( NULL, space_tab ); 
-         while (arg!=NULL)       { 
-                 equal_ptr = strchr( arg, '=' ); 
-                 if ( equal_ptr )        { 
-                         *equal_ptr='\0'; 
-                         equal_ptr++; 
-                         // if we have john=cool, arg is 'john' and equal_ptr is 'cool' 
-                         if (!d_stricmp( arg, "exp1_vclip" ))    { 
-                                 exp1_vclip_num = atoi(equal_ptr); 
-                         } else if (!d_stricmp( arg, "exp2_vclip" ))     { 
-                                 exp2_vclip_num = atoi(equal_ptr); 
-                         } else if (!d_stricmp( arg, "exp1_sound" ))     { 
-                                 exp1_sound_num = atoi(equal_ptr); 
-                         } else if (!d_stricmp( arg, "exp2_sound" ))     { 
-                                 exp2_sound_num = atoi(equal_ptr); 
-                         } else if (!d_stricmp( arg, "lighting" ))       { 
-                                 lighting = fl2f(atof(equal_ptr)); 
-                                 if ( (lighting < 0) || (lighting > F1_0 )) { 
-                                         Error( "In bitmaps.tbl, lighting value of %.2f is out of range 0..1.\n", f2fl(lighting)); 
-                                 } 
-                         } else if (!d_stricmp( arg, "weapon_type" )) { 
-                                 weapon_type = static_cast<weapon_id_type>(atoi(equal_ptr)); 
-                         } 
- #if defined(DXX_BUILD_DESCENT_II) 
-                         else if (!d_stricmp( arg, "weapon_type2")) 
-                         { 
-                                 weapon_type2 = static_cast<weapon_id_type>(atoi(equal_ptr)); 
-                         } 
- #endif 
-                         else if (!d_stricmp( arg, "strength" )) { 
-                                 strength = i2f(atoi(equal_ptr)); 
-                         } else if (!d_stricmp( arg, "mass" )) { 
-                                 mass = fl2f(atof(equal_ptr)); 
-                         } else if (!d_stricmp( arg, "drag" )) { 
-                                 drag = fl2f(atof(equal_ptr)); 
-                         } else if (!d_stricmp( arg, "contains_id" )) { 
-                                 contains_id = atoi(equal_ptr); 
-                         } else if (!d_stricmp( arg, "contains_type" )) { 
-                                 contains_type = atoi(equal_ptr); 
-                         } else if (!d_stricmp( arg, "contains_count" )) { 
-                                 contains_count = atoi(equal_ptr); 
-                         } 
- #if defined(DXX_BUILD_DESCENT_II) 
-                         else if (!d_stricmp( arg, "companion" )) { 
-                                 companion = atoi(equal_ptr); 
-                         } else if (!d_stricmp( arg, "badass" )) { 
-                                 badass = atoi(equal_ptr); 
-                         } else if (!d_stricmp( arg, "lightcast" )) { 
-                                 lightcast = atoi(equal_ptr); 
-                         } else if (!d_stricmp( arg, "glow" )) { 
-                                 glow = fl2f(atof(equal_ptr)); 
-                         } else if (!d_stricmp( arg, "death_roll" )) { 
-                                 death_roll = atoi(equal_ptr); 
-                         } else if (!d_stricmp( arg, "deathroll_sound" )) { 
-                                 deathroll_sound = atoi(equal_ptr); 
-                         } else if (!d_stricmp( arg, "thief" )) { 
-                                 thief = atoi(equal_ptr); 
-                         } else if (!d_stricmp( arg, "kamikaze" )) { 
-                                 kamikaze = atoi(equal_ptr); 
-                         } else if (!d_stricmp( arg, "pursuit" )) { 
-                                 pursuit = atoi(equal_ptr); 
-                         } else if (!d_stricmp( arg, "smart_blobs" )) { 
-                                 smart_blobs = atoi(equal_ptr); 
-                         } else if (!d_stricmp( arg, "energy_blobs" )) { 
-                                 energy_blobs = atoi(equal_ptr); 
-                         } else if (!d_stricmp( arg, "energy_drain" )) { 
-                                 energy_drain = atoi(equal_ptr); 
-                         } 
- #endif 
-                         else if (!d_stricmp( arg, "contains_prob" )) { 
-                                 contains_prob = atoi(equal_ptr); 
-                         } else if (!d_stricmp( arg, "cloak_type" )) { 
-                                 cloak_type = atoi(equal_ptr); 
-                         } else if (!d_stricmp( arg, "attack_type" )) { 
-                                 attack_type = atoi(equal_ptr); 
-                         } else if (!d_stricmp( arg, "boss" )) { 
-                                 boss_flag = atoi(equal_ptr); 
-                         } else if (!d_stricmp( arg, "score_value" )) { 
-                                 score_value = atoi(equal_ptr); 
-                         } else if (!d_stricmp( arg, "see_sound" )) { 
-                                 see_sound = atoi(equal_ptr); 
-                         } else if (!d_stricmp( arg, "attack_sound" )) { 
-                                 attack_sound = atoi(equal_ptr); 
-                         } else if (!d_stricmp( arg, "claw_sound" )) { 
-                                 claw_sound = atoi(equal_ptr); 
-                         } 
- #if defined(DXX_BUILD_DESCENT_II) 
-                         else if (!d_stricmp( arg, "taunt_sound" )) { 
-                                 taunt_sound = atoi(equal_ptr); 
-                         } else if (!d_stricmp( arg, "aim" )) { 
-                                 aim = fl2f(atof(equal_ptr)); 
-                         } else if (!d_stricmp( arg, "big_radius" )) { 
-                                 if (atoi(equal_ptr)) 
-                                         flags |= RIF_BIG_RADIUS; 
-                         } else if (!d_stricmp( arg, "behavior" )) { 
-                                 if (!d_stricmp(equal_ptr, "STILL")) 
-                                         behavior = ai_behavior::AIB_STILL; 
-                                 else if (!d_stricmp(equal_ptr, "NORMAL")) 
-                                         behavior = ai_behavior::AIB_NORMAL; 
-                                 else if (!d_stricmp(equal_ptr, "BEHIND")) 
-                                         behavior = ai_behavior::AIB_BEHIND; 
-                                 else if (!d_stricmp(equal_ptr, "RUN_FROM")) 
-                                         behavior = ai_behavior::AIB_RUN_FROM; 
-                                 else if (!d_stricmp(equal_ptr, "SNIPE")) 
-                                         behavior = ai_behavior::AIB_SNIPE; 
-                                 else if (!d_stricmp(equal_ptr, "STATION")) 
-                                         behavior = ai_behavior::AIB_STATION; 
-                                 else if (!d_stricmp(equal_ptr, "FOLLOW")) 
-                                         behavior = ai_behavior::AIB_FOLLOW; 
-                                 else 
-                                         Int3(); //      Error.  Illegal behavior type for current robot. 
-                         } 
- #endif 
-                         else if (!d_stricmp( arg, "name" )) { 
- #if DXX_USE_EDITOR 
-                                 auto &name = Robot_names[LevelSharedRobotInfoState.N_robot_types]; 
-                                 const auto len = strlen(equal_ptr); 
-                                 assert(len < name.size());      //      Oops, name too long. 
-                                 memcpy(name.data(), &equal_ptr[1], len - 2); 
-                                 name[len - 2] = 0; 
- #endif 
-                         } else if (!d_stricmp( arg, "simple_model" )) { 
-                                 model_name[n_models] = equal_ptr; 
-                                 first_bitmap_num[n_models] = N_ObjBitmapPtrs; 
-                                 n_models++; 
- #if defined(DXX_BUILD_DESCENT_II) 
-                                 Assert(n_models < MAX_MODEL_VARIANTS); 
- #endif 
-                         } 
- #if defined(DXX_BUILD_DESCENT_II) 
-                         else 
-                         { 
-                                 Int3(); 
-                         } 
- #endif 
-                 } else {                        // Must be a texture specification... 
-                         load_polymodel_bitmap(skip, arg); 
-                 } 
-                 arg = strtok( NULL, space_tab ); 
-         } 
-   
-         auto ¤t_robot_info = Robot_info[LevelSharedRobotInfoState.N_robot_types]; 
-         //clear out anim info 
-         range_for (auto &g, current_robot_info.anim_states) 
-                 range_for (auto &s, g) 
-                         s.n_joints = 0; 
-   
-         first_bitmap_num[n_models] = N_ObjBitmapPtrs; 
-   
-         auto &Polygon_models = LevelSharedPolygonModelState.Polygon_models; 
-         for (i=0;i<n_models;i++) { 
-                 int n_textures; 
-                 int model_num,last_model_num=0; 
-   
-                 n_textures = first_bitmap_num[i+1] - first_bitmap_num[i]; 
-   
-                 model_num = load_polygon_model(model_name[i],n_textures,first_bitmap_num[i], (i == 0) ? ¤t_robot_info : nullptr); 
-   
-                 if (i==0) 
-                         current_robot_info.model_num = model_num; 
-                 else 
-                         Polygon_models[last_model_num].simpler_model = model_num+1; 
-   
-                 last_model_num = model_num; 
-         } 
-   
- #if defined(DXX_BUILD_DESCENT_I) 
-         ObjType[Num_total_object_types] = OL_ROBOT; 
-         ObjId[Num_total_object_types] = LevelSharedRobotInfoState.N_robot_types; 
- #elif defined(DXX_BUILD_DESCENT_II) 
-         if ((glow > i2f(15)) || (glow < 0) || (glow != 0 && glow < 0x1000)) { 
-                 Int3(); 
-         } 
- #endif 
-   
-         current_robot_info.exp1_vclip_num = exp1_vclip_num; 
-         current_robot_info.exp2_vclip_num = exp2_vclip_num; 
-         current_robot_info.exp1_sound_num = exp1_sound_num; 
-         current_robot_info.exp2_sound_num = exp2_sound_num; 
-         current_robot_info.lighting = lighting; 
-         current_robot_info.weapon_type = weapon_type; 
- #if defined(DXX_BUILD_DESCENT_II) 
-         current_robot_info.weapon_type2 = weapon_type2; 
- #endif 
-         current_robot_info.strength = strength; 
-         current_robot_info.mass = mass; 
-         current_robot_info.drag = drag; 
-         current_robot_info.cloak_type = cloak_type; 
-         current_robot_info.attack_type = attack_type; 
-         current_robot_info.boss_flag = boss_flag; 
-   
-         current_robot_info.contains_id = contains_id; 
-         current_robot_info.contains_count = contains_count; 
-         current_robot_info.contains_prob = contains_prob; 
- #if defined(DXX_BUILD_DESCENT_II) 
-         current_robot_info.companion = companion; 
-         current_robot_info.badass = badass; 
-         current_robot_info.lightcast = lightcast; 
-         current_robot_info.glow = (glow>>12);           //convert to 4:4 
-         current_robot_info.death_roll = death_roll; 
-         current_robot_info.deathroll_sound = deathroll_sound; 
-         current_robot_info.thief = thief; 
-         current_robot_info.flags = flags; 
-         current_robot_info.kamikaze = kamikaze; 
-         current_robot_info.pursuit = pursuit; 
-         current_robot_info.smart_blobs = smart_blobs; 
-         current_robot_info.energy_blobs = energy_blobs; 
-         current_robot_info.energy_drain = energy_drain; 
- #endif 
-         current_robot_info.score_value = score_value; 
-         current_robot_info.see_sound = see_sound; 
-         current_robot_info.attack_sound = attack_sound; 
-         current_robot_info.claw_sound = claw_sound; 
- #if defined(DXX_BUILD_DESCENT_II) 
-         current_robot_info.taunt_sound = taunt_sound; 
-         current_robot_info.behavior = behavior;         //      Default behavior for this robot, if coming out of matcen. 
-         current_robot_info.aim = min(f2i(aim*255), 255);                //      how well this robot type can aim.  255=perfect 
- #endif 
-   
-         if (contains_type) 
-                 current_robot_info.contains_type = OBJ_ROBOT; 
-         else 
-                 current_robot_info.contains_type = OBJ_POWERUP; 
-   
-         ++LevelSharedRobotInfoState.N_robot_types; 
- #if defined(DXX_BUILD_DESCENT_I) 
-         Num_total_object_types++; 
- #elif defined(DXX_BUILD_DESCENT_II) 
-         bm_flag = BM_NONE; 
- #endif 
- } 
-   
- #if defined(DXX_BUILD_DESCENT_I) 
- //read a polygon object of some sort 
- void bm_read_object(char *&arg, int skip) 
- #elif defined(DXX_BUILD_DESCENT_II) 
- //read a reactor model 
- void bm_read_reactor(void) 
- #endif 
- { 
-         char *model_name, *model_name_dead=NULL; 
-         int first_bitmap_num, first_bitmap_num_dead=0, n_normal_bitmaps; 
-         char *equal_ptr; 
-         short model_num; 
-         fix     lighting = F1_0/2;              // Default 
- #if defined(DXX_BUILD_DESCENT_I) 
-         int type = -1; 
-         fix strength=0; 
- #elif defined(DXX_BUILD_DESCENT_II) 
-         assert(Num_reactors < Reactors.size()); 
- #endif 
-   
-         model_name = strtok( NULL, space_tab ); 
-   
-         // Process bitmaps 
-         bm_flag = BM_NONE; 
-         arg = strtok( NULL, space_tab ); 
-         first_bitmap_num = N_ObjBitmapPtrs; 
-   
-         while (arg!=NULL)       { 
-   
-                 equal_ptr = strchr( arg, '=' ); 
-   
-                 if ( equal_ptr )        { 
-                         *equal_ptr='\0'; 
-                         equal_ptr++; 
-   
-                         // if we have john=cool, arg is 'john' and equal_ptr is 'cool' 
-   
- #if defined(DXX_BUILD_DESCENT_I) 
-                         if (!d_stricmp(arg,"type")) { 
-                                 if (!d_stricmp(equal_ptr,"controlcen")) 
-                                         type = OL_CONTROL_CENTER; 
-                                 else if (!d_stricmp(equal_ptr,"clutter")) 
-                                         type = OL_CLUTTER; 
-                                 else if (!d_stricmp(equal_ptr,"exit")) 
-                                         type = OL_EXIT; 
-                         } 
-                         else 
- #endif 
-                         if (!d_stricmp( arg, "dead_pof" ))      { 
-                                 model_name_dead = equal_ptr; 
-                                 first_bitmap_num_dead=N_ObjBitmapPtrs; 
-                         } else if (!d_stricmp( arg, "lighting" ))       { 
-                                 lighting = fl2f(atof(equal_ptr)); 
-                                 if ( (lighting < 0) || (lighting > F1_0 )) { 
-                                         Error( "In bitmaps.tbl, lighting value of %.2f is out of range 0..1.\n", f2fl(lighting)); 
-                                 } 
-                         } 
- #if defined(DXX_BUILD_DESCENT_I) 
-                         else if (!d_stricmp( arg, "strength" )) { 
-                                 strength = fl2f(atof(equal_ptr)); 
-                         } 
- #elif defined(DXX_BUILD_DESCENT_II) 
-                         else { 
-                                 Int3(); 
-                         } 
- #endif 
-                 } else {                        // Must be a texture specification... 
- #if defined(DXX_BUILD_DESCENT_I) 
-                         load_polymodel_bitmap(skip, arg); 
- #elif defined(DXX_BUILD_DESCENT_II) 
-                         load_polymodel_bitmap(0, arg); 
- #endif 
-                 } 
-                 arg = strtok( NULL, space_tab ); 
-         } 
-   
-         if ( model_name_dead ) 
-                 n_normal_bitmaps = first_bitmap_num_dead-first_bitmap_num; 
-         else 
-                 n_normal_bitmaps = N_ObjBitmapPtrs-first_bitmap_num; 
-   
-         model_num = load_polygon_model(model_name,n_normal_bitmaps,first_bitmap_num,NULL); 
-   
- #if defined(DXX_BUILD_DESCENT_I) 
-         if (type == OL_CONTROL_CENTER) 
-                 read_model_guns(model_name, Reactors[0]); 
- #endif 
-         if ( model_name_dead ) 
-                 Dead_modelnums[model_num]  = load_polygon_model(model_name_dead,N_ObjBitmapPtrs-first_bitmap_num_dead,first_bitmap_num_dead,NULL); 
-         else 
-                 Dead_modelnums[model_num] = -1; 
-   
- #if defined(DXX_BUILD_DESCENT_I) 
-         if (type == -1) 
-                 Error("No object type specfied for object in BITMAPS.TBL on line %d\n",linenum); 
-   
-         ObjType[Num_total_object_types] = type; 
-         ObjId[Num_total_object_types] = model_num; 
-         ObjStrength[Num_total_object_types] = strength; 
-   
-         Num_total_object_types++; 
-   
-         if (type == OL_EXIT) { 
-                 exit_modelnum = model_num; 
-                 destroyed_exit_modelnum = Dead_modelnums[model_num]; 
-         } 
- #elif defined(DXX_BUILD_DESCENT_II) 
-         Reactors[Num_reactors].model_num = model_num; 
-         read_model_guns(model_name, Reactors[Num_reactors]); 
-   
-         Num_reactors++; 
- #endif 
- } 
-   
- #if defined(DXX_BUILD_DESCENT_II) 
- //read the marker object 
- void bm_read_marker() 
- { 
-         char *model_name; 
-         int first_bitmap_num, n_normal_bitmaps; 
-         char *equal_ptr; 
-   
-         model_name = strtok( NULL, space_tab ); 
-   
-         // Process bitmaps 
-         bm_flag = BM_NONE; 
-         arg = strtok( NULL, space_tab ); 
-         first_bitmap_num = N_ObjBitmapPtrs; 
-   
-         while (arg!=NULL)       { 
-   
-                 equal_ptr = strchr( arg, '=' ); 
-   
-                 if ( equal_ptr )        { 
-                         *equal_ptr='\0'; 
-                         equal_ptr++; 
-   
-                         // if we have john=cool, arg is 'john' and equal_ptr is 'cool' 
-                         Int3(); 
-   
-                 } else {                        // Must be a texture specification... 
-                         load_polymodel_bitmap(0, arg); 
-                 } 
-                 arg = strtok( NULL, space_tab ); 
-         } 
-   
-         n_normal_bitmaps = N_ObjBitmapPtrs-first_bitmap_num; 
-   
-         Marker_model_num = load_polygon_model(model_name,n_normal_bitmaps,first_bitmap_num,NULL); 
- } 
-   
- //read the exit model 
- void bm_read_exitmodel() 
- { 
-         char *model_name, *model_name_dead=NULL; 
-         int first_bitmap_num=0, first_bitmap_num_dead=0, n_normal_bitmaps; 
-         char *equal_ptr; 
-         short model_num; 
-   
-         model_name = strtok( NULL, space_tab ); 
-   
-         // Process bitmaps 
-         bm_flag = BM_NONE; 
-         arg = strtok( NULL, space_tab ); 
-         first_bitmap_num = N_ObjBitmapPtrs; 
-   
-         while (arg!=NULL)       { 
-   
-                 equal_ptr = strchr( arg, '=' ); 
-   
-                 if ( equal_ptr )        { 
-                         *equal_ptr='\0'; 
-                         equal_ptr++; 
-   
-                         // if we have john=cool, arg is 'john' and equal_ptr is 'cool' 
-   
-                         if (!d_stricmp( arg, "dead_pof" ))      { 
-                                 model_name_dead = equal_ptr; 
-                                 first_bitmap_num_dead=N_ObjBitmapPtrs; 
-                         } else { 
-                                 Int3(); 
-                         } 
-                 } else {                        // Must be a texture specification... 
-                         load_polymodel_bitmap(0, arg); 
-                 } 
-                 arg = strtok( NULL, space_tab ); 
-         } 
-   
-         if ( model_name_dead ) 
-                 n_normal_bitmaps = first_bitmap_num_dead-first_bitmap_num; 
-         else 
-                 n_normal_bitmaps = N_ObjBitmapPtrs-first_bitmap_num; 
-   
-         model_num = load_polygon_model(model_name,n_normal_bitmaps,first_bitmap_num,NULL); 
-   
-         if ( model_name_dead ) 
-                 Dead_modelnums[model_num]  = load_polygon_model(model_name_dead,N_ObjBitmapPtrs-first_bitmap_num_dead,first_bitmap_num_dead,NULL); 
-         else 
-                 Dead_modelnums[model_num] = -1; 
-   
-         exit_modelnum = model_num; 
-         destroyed_exit_modelnum = Dead_modelnums[model_num]; 
-   
- } 
- #endif 
-   
- #if defined(DXX_BUILD_DESCENT_I) 
- void bm_read_player_ship(char *&arg, int skip) 
- #elif defined(DXX_BUILD_DESCENT_II) 
- void bm_read_player_ship(void) 
- #endif 
- { 
-         char    *model_name_dying=NULL; 
-         char    *model_name[MAX_MODEL_VARIANTS]; 
-         int     n_models=0,i; 
-         int     first_bitmap_num[MAX_MODEL_VARIANTS]; 
-         char *equal_ptr; 
-         robot_info ri; 
-         int last_multi_bitmap_num=-1; 
-   
-         // Process bitmaps 
-         bm_flag = BM_NONE; 
-   
-         arg = strtok( NULL, space_tab ); 
-   
-         Player_ship->mass = Player_ship->drag = 0;      //stupid defaults 
-         Player_ship->expl_vclip_num = vclip_none; 
-   
-         while (arg!=NULL)       { 
-   
-                 equal_ptr = strchr( arg, '=' ); 
-   
-                 if ( equal_ptr )        { 
-   
-                         *equal_ptr='\0'; 
-                         equal_ptr++; 
-   
-                         // if we have john=cool, arg is 'john' and equal_ptr is 'cool' 
-   
-                         if (!d_stricmp( arg, "model" )) { 
-                                 Assert(n_models==0); 
-                                 model_name[0] = equal_ptr; 
-                                 first_bitmap_num[0] = N_ObjBitmapPtrs; 
-                                 n_models = 1; 
-                         } else if (!d_stricmp( arg, "simple_model" )) { 
-                                 model_name[n_models] = equal_ptr; 
-                                 first_bitmap_num[n_models] = N_ObjBitmapPtrs; 
-                                 n_models++; 
- #if defined(DXX_BUILD_DESCENT_II) 
-                                 Assert(n_models < MAX_MODEL_VARIANTS); 
- #endif 
-   
-                                 if (First_multi_bitmap_num!=-1 && last_multi_bitmap_num==-1) 
-                                         last_multi_bitmap_num=N_ObjBitmapPtrs; 
-                         } 
-                         else if (!d_stricmp( arg, "mass" )) 
-                                 Player_ship->mass = fl2f(atof(equal_ptr)); 
-                         else if (!d_stricmp( arg, "drag" )) 
-                                 Player_ship->drag = fl2f(atof(equal_ptr)); 
- //                      else if (!d_stricmp( arg, "low_thrust" )) 
- //                              Player_ship->low_thrust = fl2f(atof(equal_ptr)); 
-                         else if (!d_stricmp( arg, "max_thrust" )) 
-                                 Player_ship->max_thrust = fl2f(atof(equal_ptr)); 
-                         else if (!d_stricmp( arg, "reverse_thrust" )) 
-                                 Player_ship->reverse_thrust = fl2f(atof(equal_ptr)); 
-                         else if (!d_stricmp( arg, "brakes" )) 
-                                 Player_ship->brakes = fl2f(atof(equal_ptr)); 
-                         else if (!d_stricmp( arg, "wiggle" )) 
-                                 Player_ship->wiggle = fl2f(atof(equal_ptr)); 
-                         else if (!d_stricmp( arg, "max_rotthrust" )) 
-                                 Player_ship->max_rotthrust = fl2f(atof(equal_ptr)); 
-                         else if (!d_stricmp( arg, "dying_pof" )) 
-                                 model_name_dying = equal_ptr; 
-                         else if (!d_stricmp( arg, "expl_vclip_num" )) 
-                                 Player_ship->expl_vclip_num=atoi(equal_ptr); 
- #if defined(DXX_BUILD_DESCENT_II) 
-                         else { 
-                                 Int3(); 
-                         } 
- #endif 
-                 } 
-                 else if (!d_stricmp( arg, "multi_textures" )) { 
-   
-                         First_multi_bitmap_num = N_ObjBitmapPtrs; 
-                         first_bitmap_num[n_models] = N_ObjBitmapPtrs; 
-   
-                 } 
-                 else                    // Must be a texture specification... 
-                 { 
- #if defined(DXX_BUILD_DESCENT_I) 
-                         load_polymodel_bitmap(skip, arg); 
- #elif defined(DXX_BUILD_DESCENT_II) 
-                         load_polymodel_bitmap(0, arg); 
- #endif 
-                 } 
-   
-                 arg = strtok( NULL, space_tab ); 
-         } 
-         if (First_multi_bitmap_num!=-1 && last_multi_bitmap_num==-1) 
-                 last_multi_bitmap_num=N_ObjBitmapPtrs; 
-   
-         if (First_multi_bitmap_num==-1) 
-                 first_bitmap_num[n_models] = N_ObjBitmapPtrs; 
-   
-         Assert(last_multi_bitmap_num-First_multi_bitmap_num == (MAX_PLAYERS-1)*2); 
-   
-         auto &Polygon_models = LevelSharedPolygonModelState.Polygon_models; 
-         for (i=0;i<n_models;i++) { 
-                 int n_textures; 
-                 int model_num,last_model_num=0; 
-   
-                 n_textures = first_bitmap_num[i+1] - first_bitmap_num[i]; 
-   
- #if defined(DXX_BUILD_DESCENT_I) 
-                 robot_info *pri = NULL; 
-                 if (i == 0) 
-                         pri = &ri; 
-                 model_num = load_polygon_model(model_name[i],n_textures,first_bitmap_num[i],pri); 
- #elif defined(DXX_BUILD_DESCENT_II) 
-                 model_num = load_polygon_model(model_name[i],n_textures,first_bitmap_num[i],(i==0) ? &ri : nullptr); 
- #endif 
-   
-                 if (i==0) 
-                         Player_ship->model_num = model_num; 
-                 else 
-                         Polygon_models[last_model_num].simpler_model = model_num+1; 
-   
-                 last_model_num = model_num; 
-         } 
-   
-         if ( model_name_dying ) { 
-                 Assert(n_models); 
-                 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); 
-         } 
-   
-         Assert(ri.n_guns == N_PLAYER_GUNS); 
-   
-         //calc player gun positions 
-   
-         { 
-                 polymodel *pm; 
-                 robot_info *r; 
-                 vms_vector pnt; 
-                 int mn;                         //submodel number 
-                 int gun_num; 
-   
-                 r = &ri; 
-                 pm = &Polygon_models[Player_ship->model_num]; 
-   
-                 for (gun_num=0;gun_num<r->n_guns;gun_num++) { 
-   
-                         pnt = r->gun_points[gun_num]; 
-                         mn = r->gun_submodels[gun_num]; 
-   
-                         //instance up the tree for this gun 
-                         while (mn != 0) { 
-                                 vm_vec_add2(pnt,pm->submodel_offsets[mn]); 
-                                 mn = pm->submodel_parents[mn]; 
-                         } 
-   
-                         Player_ship->gun_points[gun_num] = pnt; 
-   
-                 } 
-         } 
- } 
-   
- namespace dsx { 
-   
- #if defined(DXX_BUILD_DESCENT_I) 
- void bm_read_some_file(d_vclip_array &Vclip, const std::string &dest_bm, char *&arg, int skip) 
- #elif defined(DXX_BUILD_DESCENT_II) 
- void bm_read_some_file(d_vclip_array &Vclip, int skip) 
- #endif 
- { 
-   
-         switch (bm_flag) { 
- #if defined(DXX_BUILD_DESCENT_II) 
-         case BM_NONE: 
-                 Error("Trying to read bitmap <%s> with bm_flag==BM_NONE on line %d of BITMAPS.TBL",arg,linenum); 
-                 break; 
- #endif 
-         case BM_COCKPIT:        { 
-                 bitmap_index bitmap; 
-                 bitmap = bm_load_sub(skip, arg); 
-                 Assert( Num_cockpits < N_COCKPIT_BITMAPS ); 
-                 cockpit_bitmap[Num_cockpits++] = bitmap; 
-                 //bm_flag = BM_NONE; 
- #if defined(DXX_BUILD_DESCENT_II) 
-                 return; 
- #endif 
-                 } 
-                 break; 
-         case BM_GAUGES: 
- #if defined(DXX_BUILD_DESCENT_I) 
-                 bm_read_gauges(arg, skip); 
- #elif defined(DXX_BUILD_DESCENT_II) 
-                 bm_read_gauges(skip); 
-                 return; 
-                 break; 
-         case BM_GAUGES_HIRES: 
-                 bm_read_gauges_hires(); 
-                 return; 
- #endif 
-                 break; 
-         case BM_WEAPON: 
- #if defined(DXX_BUILD_DESCENT_I) 
-                 bm_read_weapon(arg, skip, 0); 
- #elif defined(DXX_BUILD_DESCENT_II) 
-                 bm_read_weapon(skip, 0); 
-                 return; 
- #endif 
-                 break; 
-         case BM_VCLIP: 
- #if defined(DXX_BUILD_DESCENT_I) 
-                 bm_read_vclip(Vclip, arg, skip); 
- #elif defined(DXX_BUILD_DESCENT_II) 
-                 bm_read_vclip(Vclip, skip); 
-                 return; 
- #endif 
-                 break; 
-         case BM_ECLIP: 
- #if defined(DXX_BUILD_DESCENT_I) 
-                 bm_read_eclip(dest_bm, arg, skip); 
- #elif defined(DXX_BUILD_DESCENT_II) 
-                 bm_read_eclip(skip); 
-                 return; 
- #endif 
-                 break; 
-         case BM_TEXTURES:                       { 
-                 bitmap_index bitmap; 
-                 bitmap = bm_load_sub(skip, arg); 
-                 Assert(tmap_count < MAX_TEXTURES); 
-                 tmap_count++; 
-                 Textures[texture_count] = bitmap; 
-                 set_texture_name( arg ); 
-                 Assert(texture_count < MAX_TEXTURES); 
-                 texture_count++; 
-                 NumTextures = texture_count; 
- #if defined(DXX_BUILD_DESCENT_II) 
-                 return; 
- #endif 
-                 } 
-                 break; 
-         case BM_WCLIP: 
- #if defined(DXX_BUILD_DESCENT_I) 
-                 bm_read_wclip(arg, skip); 
-                 break; 
-         default: 
- #elif defined(DXX_BUILD_DESCENT_II) 
-                 bm_read_wclip(skip); 
-                 return; 
- #endif 
-                 break; 
-         } 
- #if defined(DXX_BUILD_DESCENT_II) 
-         Error("Trying to read bitmap <%s> with unknown bm_flag <%x> on line %d of BITMAPS.TBL",arg,bm_flag,linenum); 
- #endif 
- } 
-   
- } 
-   
- // ------------------------------------------------------------------------------ 
- //      If unused_flag is set, then this is just a placeholder.  Don't actually reference vclips or load bbms. 
- #if defined(DXX_BUILD_DESCENT_I) 
- void bm_read_weapon(char *&arg, int skip, int unused_flag) 
- #elif defined(DXX_BUILD_DESCENT_II) 
- void bm_read_weapon(int skip, int unused_flag) 
- #endif 
- { 
-         int     i,n; 
-         int     n_models=0; 
-         char    *equal_ptr; 
-         char    *pof_file_inner=NULL; 
-         char    *model_name[MAX_MODEL_VARIANTS]; 
-         int     first_bitmap_num[MAX_MODEL_VARIANTS]; 
-         int     lighted;                                        //flag for whether is a texture is lighted 
-   
-         Assert(N_weapon_types < MAX_WEAPON_TYPES); 
-   
-         n = N_weapon_types; 
-         N_weapon_types++; 
- #if defined(DXX_BUILD_DESCENT_II) 
-         Assert(N_weapon_types <= MAX_WEAPON_TYPES); 
- #endif 
-   
-         if (unused_flag) { 
- #if defined(DXX_BUILD_DESCENT_I) 
-                 clear_to_end_of_line(arg); 
- #elif defined(DXX_BUILD_DESCENT_II) 
-                 clear_to_end_of_line(); 
- #endif 
-                 return; 
-         } 
-   
-         if (skip) { 
- #if defined(DXX_BUILD_DESCENT_I) 
-                 clear_to_end_of_line(arg); 
- #elif defined(DXX_BUILD_DESCENT_II) 
-                 clear_to_end_of_line(); 
- #endif 
-                 return; 
-         } 
-   
-         // Initialize weapon array 
-         Weapon_info[n].render_type = WEAPON_RENDER_NONE;                // 0=laser, 1=blob, 2=object 
-         Weapon_info[n].bitmap.index = 0; 
-         Weapon_info[n].model_num = -1; 
-         Weapon_info[n].model_num_inner = -1; 
-         Weapon_info[n].blob_size = 0x1000;                                                                      // size of blob 
-         Weapon_info[n].flash_vclip = vclip_none; 
-         Weapon_info[n].flash_sound = SOUND_LASER_FIRED; 
-         Weapon_info[n].flash_size = 0; 
-         Weapon_info[n].robot_hit_vclip = vclip_none; 
-         Weapon_info[n].robot_hit_sound = sound_none; 
-         Weapon_info[n].wall_hit_vclip = vclip_none; 
-         Weapon_info[n].wall_hit_sound = sound_none; 
-         Weapon_info[n].impact_size = 0; 
-         for (i=0; i<NDL; i++) { 
-                 Weapon_info[n].strength[i] = F1_0; 
-                 Weapon_info[n].speed[i] = F1_0*10; 
-         } 
-         Weapon_info[n].mass = F1_0; 
-         Weapon_info[n].thrust = 0; 
-         Weapon_info[n].drag = 0; 
-         Weapon_info[n].persistent = 0; 
-   
-         Weapon_info[n].energy_usage = 0;                                        //      How much fuel is consumed to fire this weapon. 
-         Weapon_info[n].ammo_usage = 0;                                  //      How many units of ammunition it uses. 
-         Weapon_info[n].fire_wait = F1_0/4;                              //      Time until this weapon can be fired again. 
-         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. 
-         Weapon_info[n].damage_radius = 0;                               //      Radius of damage for missiles, not lasers.  Does damage to objects within this radius of hit point. 
- //--01/19/95, mk--      Weapon_info[n].damage_force = 0;                                        //      Force (movement) due to explosion 
-         Weapon_info[n].destroyable = 1;                                 //      Weapons default to destroyable 
-         Weapon_info[n].matter = 0;                                                      //      Weapons default to not being constructed of matter (they are energy!) 
-         Weapon_info[n].bounce = 0;                                                      //      Weapons default to not bouncing off walls 
-   
- #if defined(DXX_BUILD_DESCENT_II) 
-         Weapon_info[n].flags = 0; 
- #endif 
-   
-         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. 
-   
-         Weapon_info[n].po_len_to_width_ratio = F1_0*10; 
-   
-         Weapon_info[n].picture.index = 0; 
- #if defined(DXX_BUILD_DESCENT_II) 
-         Weapon_info[n].hires_picture.index = 0; 
- #endif 
-         Weapon_info[n].homing_flag = 0; 
-   
- #if defined(DXX_BUILD_DESCENT_II) 
-         Weapon_info[n].flash = 0; 
-         Weapon_info[n].multi_damage_scale = F1_0; 
-         Weapon_info[n].afterburner_size = 0; 
-         Weapon_info[n].children = weapon_id_type::unspecified; 
- #endif 
-   
-         // Process arguments 
-         arg = strtok( NULL, space_tab ); 
-   
-         lighted = 1;                    //assume first texture is lighted 
-   
- #if defined(DXX_BUILD_DESCENT_II) 
-         Weapon_info[n].speedvar = 128; 
- #endif 
-   
-         while (arg!=NULL)       { 
-                 equal_ptr = strchr( arg, '=' ); 
-                 if ( equal_ptr )        { 
-                         *equal_ptr='\0'; 
-                         equal_ptr++; 
-                         // if we have john=cool, arg is 'john' and equal_ptr is 'cool' 
-                         if (!d_stricmp( arg, "laser_bmp" ))     { 
-                                 // Load bitmap with name equal_ptr 
-   
-                                 Weapon_info[n].bitmap = bm_load_sub(skip, equal_ptr);           //load_polymodel_bitmap(equal_ptr); 
-                                 Weapon_info[n].render_type = WEAPON_RENDER_LASER; 
-   
-                         } else if (!d_stricmp( arg, "blob_bmp" ))       { 
-                                 // Load bitmap with name equal_ptr 
-   
-                                 Weapon_info[n].bitmap = bm_load_sub(skip, equal_ptr);           //load_polymodel_bitmap(equal_ptr); 
-                                 Weapon_info[n].render_type = WEAPON_RENDER_BLOB; 
-   
-                         } else if (!d_stricmp( arg, "weapon_vclip" ))   { 
-                                 // Set vclip to play for this weapon. 
-                                 Weapon_info[n].bitmap.index = 0; 
-                                 Weapon_info[n].render_type = WEAPON_RENDER_VCLIP; 
-                                 Weapon_info[n].weapon_vclip = atoi(equal_ptr); 
-   
-                         } else if (!d_stricmp( arg, "none_bmp" )) { 
-                                 Weapon_info[n].bitmap = bm_load_sub(skip, equal_ptr); 
-                                 Weapon_info[n].render_type = WEAPON_RENDER_NONE; 
-   
-                         } else if (!d_stricmp( arg, "weapon_pof" ))     { 
-                                 // Load pof file 
-                                 Assert(n_models==0); 
-                                 model_name[0] = equal_ptr; 
-                                 first_bitmap_num[0] = N_ObjBitmapPtrs; 
-                                 n_models=1; 
-                         } else if (!d_stricmp( arg, "simple_model" )) { 
-                                 model_name[n_models] = equal_ptr; 
-                                 first_bitmap_num[n_models] = N_ObjBitmapPtrs; 
-                                 n_models++; 
- #if defined(DXX_BUILD_DESCENT_II) 
-                                 Assert(n_models < MAX_MODEL_VARIANTS); 
- #endif 
-                         } else if (!d_stricmp( arg, "weapon_pof_inner" ))       { 
-                                 // Load pof file 
-                                 pof_file_inner = equal_ptr; 
-                         } else if (!d_stricmp( arg, "strength" )) { 
-                                 for (i=0; i<NDL-1; i++) { 
- #if defined(DXX_BUILD_DESCENT_I) 
-                                         Weapon_info[n].strength[i] = i2f(atoi(equal_ptr)); 
- #elif defined(DXX_BUILD_DESCENT_II) 
-                                         Weapon_info[n].strength[i] = fl2f(atof(equal_ptr)); 
- #endif 
-                                         equal_ptr = strtok(NULL, space_tab); 
-                                 } 
-                                 Weapon_info[n].strength[i] = i2f(atoi(equal_ptr)); 
-                         } else if (!d_stricmp( arg, "mass" )) { 
-                                 Weapon_info[n].mass = fl2f(atof(equal_ptr)); 
-                         } else if (!d_stricmp( arg, "drag" )) { 
-                                 Weapon_info[n].drag = fl2f(atof(equal_ptr)); 
-                         } else if (!d_stricmp( arg, "thrust" )) { 
-                                 Weapon_info[n].thrust = fl2f(atof(equal_ptr)); 
-                         } else if (!d_stricmp( arg, "matter" )) { 
-                                 Weapon_info[n].matter = atoi(equal_ptr); 
-                         } else if (!d_stricmp( arg, "bounce" )) { 
-                                 Weapon_info[n].bounce = atoi(equal_ptr); 
-                         } else if (!d_stricmp( arg, "speed" )) { 
-                                 for (i=0; i<NDL-1; i++) { 
-                                         Weapon_info[n].speed[i] = i2f(atoi(equal_ptr)); 
-                                         equal_ptr = strtok(NULL, space_tab); 
-                                 } 
-                                 Weapon_info[n].speed[i] = i2f(atoi(equal_ptr)); 
-                         } 
- #if defined(DXX_BUILD_DESCENT_II) 
-                         else if (!d_stricmp( arg, "speedvar" )) { 
-                                 Weapon_info[n].speedvar = (atoi(equal_ptr) * 128) / 100; 
-                         } 
- #endif 
-                         else if (!d_stricmp( arg, "flash_vclip" ))      { 
-                                 Weapon_info[n].flash_vclip = atoi(equal_ptr); 
-                         } else if (!d_stricmp( arg, "flash_sound" ))    { 
-                                 Weapon_info[n].flash_sound = atoi(equal_ptr); 
-                         } else if (!d_stricmp( arg, "flash_size" ))     { 
-                                 Weapon_info[n].flash_size = fl2f(atof(equal_ptr)); 
-                         } else if (!d_stricmp( arg, "blob_size" ))      { 
-                                 Weapon_info[n].blob_size = fl2f(atof(equal_ptr)); 
-                         } else if (!d_stricmp( arg, "robot_hit_vclip" ))        { 
-                                 Weapon_info[n].robot_hit_vclip = atoi(equal_ptr); 
-                         } else if (!d_stricmp( arg, "robot_hit_sound" ))        { 
-                                 Weapon_info[n].robot_hit_sound = atoi(equal_ptr); 
-                         } else if (!d_stricmp( arg, "wall_hit_vclip" )) { 
-                                 Weapon_info[n].wall_hit_vclip = atoi(equal_ptr); 
-                         } else if (!d_stricmp( arg, "wall_hit_sound" )) { 
-                                 Weapon_info[n].wall_hit_sound = atoi(equal_ptr); 
-                         } else if (!d_stricmp( arg, "impact_size" ))    { 
-                                 Weapon_info[n].impact_size = fl2f(atof(equal_ptr)); 
-                         } else if (!d_stricmp( arg, "lighted" ))        { 
-                                 lighted = atoi(equal_ptr); 
-                         } else if (!d_stricmp( arg, "lw_ratio" ))       { 
-                                 Weapon_info[n].po_len_to_width_ratio = fl2f(atof(equal_ptr)); 
-                         } else if (!d_stricmp( arg, "lightcast" ))      { 
-                                 Weapon_info[n].light = fl2f(atof(equal_ptr)); 
-                         } else if (!d_stricmp( arg, "persistent" ))     { 
-                                 Weapon_info[n].persistent = atoi(equal_ptr); 
-                         } else if (!d_stricmp(arg, "energy_usage" )) { 
-                                 Weapon_info[n].energy_usage = fl2f(atof(equal_ptr)); 
-                         } else if (!d_stricmp(arg, "ammo_usage" )) { 
-                                 Weapon_info[n].ammo_usage = atoi(equal_ptr); 
-                         } else if (!d_stricmp(arg, "fire_wait" )) { 
-                                 Weapon_info[n].fire_wait = fl2f(atof(equal_ptr)); 
-                         } else if (!d_stricmp(arg, "fire_count" )) { 
-                                 Weapon_info[n].fire_count = atoi(equal_ptr); 
-                         } else if (!d_stricmp(arg, "damage_radius" )) { 
-                                 Weapon_info[n].damage_radius = fl2f(atof(equal_ptr)); 
- //--01/19/95, mk--                      } else if (!d_stricmp(arg, "damage_force" )) { 
- //--01/19/95, mk--                              Weapon_info[n].damage_force = fl2f(atof(equal_ptr)); 
-                         } else if (!d_stricmp(arg, "lifetime" )) { 
-                                 Weapon_info[n].lifetime = fl2f(atof(equal_ptr)); 
-                         } else if (!d_stricmp(arg, "destroyable" )) { 
-                                 Weapon_info[n].destroyable = atoi(equal_ptr); 
-                         } else if (!d_stricmp(arg, "picture" )) { 
-                                 Weapon_info[n].picture = bm_load_sub(skip, equal_ptr); 
-                         } 
- #if defined(DXX_BUILD_DESCENT_II) 
-                         else if (!d_stricmp(arg, "hires_picture" )) { 
-                                 Weapon_info[n].hires_picture = bm_load_sub(skip, equal_ptr); 
-                         } 
- #endif 
-                         else if (!d_stricmp(arg, "homing" )) { 
-                                 Weapon_info[n].homing_flag = !!atoi(equal_ptr); 
-                         } 
- #if defined(DXX_BUILD_DESCENT_II) 
-                         else if (!d_stricmp(arg, "flash" )) { 
-                                 Weapon_info[n].flash = atoi(equal_ptr); 
-                         } else if (!d_stricmp(arg, "multi_damage_scale" )) { 
-                                 Weapon_info[n].multi_damage_scale = fl2f(atof(equal_ptr)); 
-                         } else if (!d_stricmp(arg, "afterburner_size" )) { 
-                                 Weapon_info[n].afterburner_size = f2i(16*fl2f(atof(equal_ptr))); 
-                         } else if (!d_stricmp(arg, "children" )) { 
-                                 Weapon_info[n].children = static_cast<weapon_id_type>(atoi(equal_ptr)); 
-                         } else if (!d_stricmp(arg, "placable" )) { 
-                                 if (atoi(equal_ptr)) { 
-                                         Weapon_info[n].flags |= WIF_PLACABLE; 
-                                 } 
-                         } else { 
-                                 Int3(); 
-                         } 
- #endif 
-                 } else {                        // Must be a texture specification... 
-                         grs_bitmap *bm; 
-   
-                         bm = load_polymodel_bitmap(skip, arg); 
- #if defined(DXX_BUILD_DESCENT_I) 
-                         if (bm && ! lighted) 
- #elif defined(DXX_BUILD_DESCENT_II) 
-                         if (! lighted) 
- #endif 
-                                 bm->add_flags(BM_FLAG_NO_LIGHTING); 
-   
-                         lighted = 1;                    //default for next bitmap is lighted 
-                 } 
-                 arg = strtok( NULL, space_tab ); 
-         } 
-   
-         first_bitmap_num[n_models] = N_ObjBitmapPtrs; 
-   
-         auto &Polygon_models = LevelSharedPolygonModelState.Polygon_models; 
-         for (i=0;i<n_models;i++) { 
-                 int n_textures; 
-                 int model_num,last_model_num=0; 
-   
-                 n_textures = first_bitmap_num[i+1] - first_bitmap_num[i]; 
-   
-                 model_num = load_polygon_model(model_name[i],n_textures,first_bitmap_num[i],NULL); 
-   
-                 if (i==0) { 
-                         Weapon_info[n].render_type = WEAPON_RENDER_POLYMODEL; 
-                         Weapon_info[n].model_num = model_num; 
-                 } 
-                 else 
-                         Polygon_models[last_model_num].simpler_model = model_num+1; 
-   
-                 last_model_num = model_num; 
-         } 
-   
-         if ( pof_file_inner )   { 
-                 Assert(n_models); 
-                 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); 
-         } 
- } 
-   
- // ------------------------------------------------------------------------------ 
- #define DEFAULT_POWERUP_SIZE i2f(3) 
-   
- #if defined(DXX_BUILD_DESCENT_I) 
- void bm_read_powerup(char *&arg, int unused_flag) 
- #elif defined(DXX_BUILD_DESCENT_II) 
- void bm_read_powerup(int unused_flag) 
- #endif 
- { 
-         int n; 
-         char    *equal_ptr; 
-   
-         Assert(N_powerup_types < MAX_POWERUP_TYPES); 
-   
-         n = N_powerup_types; 
-         N_powerup_types++; 
-   
-         if (unused_flag) { 
- #if defined(DXX_BUILD_DESCENT_I) 
-                 clear_to_end_of_line(arg); 
- #elif defined(DXX_BUILD_DESCENT_II) 
-                 clear_to_end_of_line(); 
- #endif 
-                 return; 
-         } 
-   
-         // Initialize powerup array 
-         Powerup_info[n].light = F1_0/3;         //      Default lighting value. 
-         Powerup_info[n].vclip_num = vclip_none; 
-         Powerup_info[n].hit_sound = sound_none; 
-         Powerup_info[n].size = DEFAULT_POWERUP_SIZE; 
- #if DXX_USE_EDITOR 
-         Powerup_names[n][0] = 0; 
- #endif 
-   
-         // Process arguments 
-         arg = strtok( NULL, space_tab ); 
-   
-         while (arg!=NULL)       { 
-                 equal_ptr = strchr( arg, '=' ); 
-                 if ( equal_ptr )        { 
-                         *equal_ptr='\0'; 
-                         equal_ptr++; 
-                         // if we have john=cool, arg is 'john' and equal_ptr is 'cool' 
-                         if (!d_stricmp( arg, "vclip_num" ))     { 
-                                 Powerup_info[n].vclip_num = atoi(equal_ptr); 
-                         } else if (!d_stricmp( arg, "light" ))  { 
-                                 Powerup_info[n].light = fl2f(atof(equal_ptr)); 
-                         } else if (!d_stricmp( arg, "hit_sound" ))      { 
-                                 Powerup_info[n].hit_sound = atoi(equal_ptr); 
-                         } else if (!d_stricmp( arg, "name" )) { 
- #if DXX_USE_EDITOR 
-                                 auto &name = Powerup_names[n]; 
-                                 const auto len = strlen(equal_ptr); 
-                                 assert(len < name.size());      //      Oops, name too long. 
-                                 memcpy(name.data(), &equal_ptr[1], len - 2); 
-                                 name[len - 2] = 0; 
- #endif 
-                         } else if (!d_stricmp( arg, "size" ))   { 
-                                 Powerup_info[n].size = fl2f(atof(equal_ptr)); 
-                         } 
- #if defined(DXX_BUILD_DESCENT_II) 
-                         else { 
-                                 Int3(); 
-                         } 
- #endif 
-                 } 
- #if defined(DXX_BUILD_DESCENT_II) 
-                 else {                  // Must be a texture specification... 
-                         Int3(); 
-                 } 
- #endif 
-                 arg = strtok( NULL, space_tab ); 
-         } 
- #if defined(DXX_BUILD_DESCENT_I) 
-         ObjType[Num_total_object_types] = OL_POWERUP; 
-         ObjId[Num_total_object_types] = n; 
-         Num_total_object_types++; 
- #endif 
- } 
-   
- #if defined(DXX_BUILD_DESCENT_I) 
- void bm_read_hostage(char *&arg) 
- #elif defined(DXX_BUILD_DESCENT_II) 
- void bm_read_hostage() 
- #endif 
- { 
-         int n; 
-         char    *equal_ptr; 
-   
-         Assert(N_hostage_types < MAX_HOSTAGE_TYPES); 
-   
-         n = N_hostage_types; 
-         N_hostage_types++; 
-   
-         // Process arguments 
-         arg = strtok( NULL, space_tab ); 
-   
-         while (arg!=NULL)       { 
-                 equal_ptr = strchr( arg, '=' ); 
-                 if ( equal_ptr )        { 
-                         *equal_ptr='\0'; 
-                         equal_ptr++; 
-   
-                         if (!d_stricmp( arg, "vclip_num" )) 
-   
-                                 Hostage_vclip_num[n] = atoi(equal_ptr); 
-   
- #if defined(DXX_BUILD_DESCENT_II) 
-                         else { 
-                                 Int3(); 
-                         } 
- #endif 
-                 } 
- #if defined(DXX_BUILD_DESCENT_II) 
-                 else { 
-                         Int3(); 
-                 } 
- #endif 
-                 arg = strtok( NULL, space_tab ); 
-         } 
- #if defined(DXX_BUILD_DESCENT_I) 
-         ObjType[Num_total_object_types] = OL_HOSTAGE; 
-         ObjId[Num_total_object_types] = n; 
-         Num_total_object_types++; 
- #endif 
- } 
-   
- #if defined(DXX_BUILD_DESCENT_I) 
- 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)); 
- ASSERT_SERIAL_UDT_MESSAGE_SIZE(tmap_info, 26); 
- #elif defined(DXX_BUILD_DESCENT_II) 
- 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)); 
- ASSERT_SERIAL_UDT_MESSAGE_SIZE(tmap_info, 20); 
- #endif 
-