Subversion Repositories Games.Descent

Rev

Blame | Last modification | View Log | Download | RSS feed

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