Subversion Repositories Games.Descent

Rev

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

  1. /*
  2.  * This file is part of the DXX-Rebirth project <https://www.dxx-rebirth.com/>.
  3.  * It is copyright by its individual contributors, as recorded in the
  4.  * project's Git history.  See COPYING.txt at the top level for license
  5.  * terms and a link to the Git history.
  6.  */
  7. /*
  8.  * Load custom textures & robot data
  9.  */
  10.  
  11. #include <memory>
  12. #include <string.h>
  13. #include "gr.h"
  14. #include "pstypes.h"
  15. #include "piggy.h"
  16. #include "textures.h"
  17. #include "robot.h"
  18. #include "weapon.h"
  19. #include "digi.h"
  20. #include "hash.h"
  21. #include "u_mem.h"
  22. #include "custom.h"
  23. #include "physfsx.h"
  24.  
  25. #include "compiler-range_for.h"
  26. #include "partial_range.h"
  27. #include <iterator>
  28. #include <memory>
  29.  
  30. //#define D2TMAP_CONV // used for testing
  31.  
  32. namespace {
  33.  
  34. struct snd_info
  35. {
  36.         unsigned int length;
  37.         uint8_t *data;
  38. };
  39.  
  40. }
  41.  
  42. struct DiskBitmapHeader2
  43. {
  44.         char name[8];
  45.         ubyte dflags;
  46.         ubyte width;
  47.         ubyte height;
  48.         ubyte hi_wh;
  49.         ubyte flags;
  50.         ubyte avg_color;
  51.         int offset;
  52. } __pack__;
  53.  
  54. struct DiskBitmapHeader
  55. {
  56.         char name[8];
  57.         ubyte dflags;
  58.         ubyte width;
  59.         ubyte height;
  60.         ubyte flags;
  61.         ubyte avg_color;
  62.         int offset;
  63. } __pack__;
  64.  
  65. struct DiskSoundHeader
  66. {
  67.         char name[8];
  68.         int length;
  69.         int data_length;
  70.         int offset;
  71. } __pack__;
  72.  
  73. namespace {
  74.  
  75. struct custom_info
  76. {
  77.         int offset;
  78.         int repl_idx; // 0x80000000 -> sound, -1 -> n/a
  79.         unsigned int flags;
  80.         int width, height;
  81. };
  82.  
  83. }
  84.  
  85. static std::array<grs_bitmap, MAX_BITMAP_FILES> BitmapOriginal;
  86. static std::array<snd_info, MAX_SOUND_FILES> SoundOriginal;
  87.  
  88. static int load_pig1(PHYSFS_File *f, unsigned num_bitmaps, unsigned num_sounds, unsigned &num_custom, std::unique_ptr<custom_info[]> &ci)
  89. {
  90.         int data_ofs;
  91.         int i;
  92.         DiskBitmapHeader bmh;
  93.         DiskSoundHeader sndh;
  94.         char name[15];
  95.  
  96.         num_custom = 0;
  97.  
  98.         if (num_bitmaps <= MAX_BITMAP_FILES) // <v1.4 pig?
  99.         {
  100.                 PHYSFSX_fseek(f, 8, SEEK_SET);
  101.                 data_ofs = 8;
  102.         }
  103.         else if (num_bitmaps > 0 && num_bitmaps < PHYSFS_fileLength(f)) // >=v1.4 pig?
  104.         {
  105.                 PHYSFSX_fseek(f, num_bitmaps, SEEK_SET);
  106.                 data_ofs = num_bitmaps + 8;
  107.                 num_bitmaps = PHYSFSX_readInt(f);
  108.                 num_sounds = PHYSFSX_readInt(f);
  109.         }
  110.         else
  111.                 return -1; // invalid pig file
  112.  
  113.         if (num_bitmaps >= MAX_BITMAP_FILES ||
  114.                 num_sounds >= MAX_SOUND_FILES)
  115.                 return -1; // invalid pig file
  116.         ci = std::make_unique<custom_info[]>(num_bitmaps + num_sounds);
  117.         custom_info *cip = ci.get();
  118.         data_ofs += num_bitmaps * sizeof(DiskBitmapHeader) + num_sounds * sizeof(DiskSoundHeader);
  119.         i = num_bitmaps;
  120.  
  121.         while (i--)
  122.         {
  123.                 if (PHYSFS_read(f, &bmh, sizeof(DiskBitmapHeader), 1) < 1)
  124.                 {
  125.                         return -1;
  126.                 }
  127.  
  128.                 snprintf(name, sizeof(name), "%.8s%c%d", bmh.name, (bmh.dflags & DBM_FLAG_ABM) ? '#' : 0, bmh.dflags & 63);
  129.  
  130.                 cip->offset = bmh.offset + data_ofs;
  131.                 cip->repl_idx = hashtable_search(&AllBitmapsNames, name);
  132.                 cip->flags = bmh.flags & (BM_FLAG_TRANSPARENT | BM_FLAG_SUPER_TRANSPARENT | BM_FLAG_NO_LIGHTING | BM_FLAG_RLE);
  133.                 cip->width = bmh.width + ((bmh.dflags & DBM_FLAG_LARGE) ? 256 : 0);
  134.                 cip->height = bmh.height;
  135.                 cip++;
  136.         }
  137.  
  138.         i = num_sounds;
  139.  
  140.         while (i--)
  141.         {
  142.                 if (PHYSFS_read(f, &sndh, sizeof(DiskSoundHeader), 1) < 1)
  143.                 {
  144.                         return -1;
  145.                 }
  146.  
  147.                 memcpy(name, sndh.name, 8);
  148.                 name[8] = 0;
  149.                 cip->offset = sndh.offset + data_ofs;
  150.                 cip->repl_idx = hashtable_search(&AllDigiSndNames, name) | 0x80000000;
  151.                 cip->width = sndh.length;
  152.                 cip++;
  153.         }
  154.  
  155.         num_custom = num_bitmaps + num_sounds;
  156.  
  157.         return 0;
  158. }
  159.  
  160. static int load_pog(PHYSFS_File *f, int pog_sig, int pog_ver, unsigned &num_custom, std::unique_ptr<custom_info[]> &ci)
  161. {
  162.         int data_ofs;
  163.         int num_bitmaps;
  164.         int no_repl = 0;
  165.         DiskBitmapHeader2 bmh;
  166.  
  167. #ifdef D2TMAP_CONV
  168.         int x, j, N_d2tmap;
  169.         int *d2tmap = NULL;
  170.         PHYSFS_File *f2 = NULL;
  171.         if ((f2 = PHYSFSX_openReadBuffered("d2tmap.bin")))
  172.         {
  173.                 N_d2tmap = PHYSFSX_readInt(f2);
  174.                 if ((d2tmap = d_malloc(N_d2tmap * sizeof(d2tmap[0]))))
  175.                         for (i = 0; i < N_d2tmap; i++)
  176.                                 d2tmap[i] = PHYSFSX_readShort(f2);
  177.                 PHYSFS_close(f2);
  178.         }
  179. #endif
  180.  
  181.         num_custom = 0;
  182.  
  183.         if (pog_sig == 0x47495050 && pog_ver == 2) /* PPIG */
  184.                 no_repl = 1;
  185.         else if (pog_sig != 0x474f5044 || pog_ver != 1) /* DPOG */
  186.                 return -1; // no pig2/pog file/unknown version
  187.  
  188.         num_bitmaps = PHYSFSX_readInt(f);
  189.         ci = std::make_unique<custom_info[]>(num_bitmaps);
  190.         custom_info *cip = ci.get();
  191.         data_ofs = 12 + num_bitmaps * sizeof(DiskBitmapHeader2);
  192.  
  193.         if (!no_repl)
  194.         {
  195.                 for (int i = num_bitmaps; i--;)
  196.                         (cip++)->repl_idx = PHYSFSX_readShort(f);
  197.  
  198.                 cip = ci.get();
  199.                 data_ofs += num_bitmaps * 2;
  200.         }
  201.  
  202. #ifdef D2TMAP_CONV
  203.         if (d2tmap)
  204.                 for (i = 0; i < num_bitmaps; i++)
  205.                 {
  206.                         x = cip[i].repl_idx;
  207.                         cip[i].repl_idx = -1;
  208.  
  209.                         for (j = 0; j < N_d2tmap; j++)
  210.                                 if (x == d2tmap[j])
  211.                                 {
  212.                                         cip[i].repl_idx = Textures[j % NumTextures].index;
  213.                                         break;
  214.                                 }
  215.                 }
  216. #endif
  217.         for (int i = num_bitmaps; i--;)
  218.         {
  219.                 if (PHYSFS_read(f, &bmh, sizeof(DiskBitmapHeader2), 1) < 1)
  220.                 {
  221.                         return -1;
  222.                 }
  223.  
  224.                 cip->offset = bmh.offset + data_ofs;
  225.                 cip->flags = bmh.flags & (BM_FLAG_TRANSPARENT | BM_FLAG_SUPER_TRANSPARENT | BM_FLAG_NO_LIGHTING | BM_FLAG_RLE);
  226.                 cip->width = bmh.width + ((bmh.hi_wh & 15) << 8);
  227.                 cip->height = bmh.height + ((bmh.hi_wh >> 4) << 8);
  228.                 cip++;
  229.         }
  230.  
  231.         num_custom = num_bitmaps;
  232.  
  233.         return 0;
  234. }
  235.  
  236. // load custom textures/sounds from pog/pig file
  237. // returns 0 if ok, <0 on error
  238. static int load_pigpog(const d_fname &pogname)
  239. {
  240.         unsigned num_custom;
  241.         grs_bitmap *bmp;
  242.         digi_sound *snd;
  243.         uint8_t *p;
  244.         auto f = PHYSFSX_openReadBuffered(pogname);
  245.         int i, j, rc = -1;
  246.         unsigned int x = 0;
  247.  
  248.         if (!f)
  249.                 return -1; // pog file doesn't exist
  250.  
  251.         i = PHYSFSX_readInt(f);
  252.         x = PHYSFSX_readInt(f);
  253.  
  254.         std::unique_ptr<custom_info[]> ci;
  255.         if (load_pog(f, i, x, num_custom, ci) && load_pig1(f, i, x, num_custom, ci))
  256.         {
  257.                 return rc;
  258.         }
  259.  
  260.         custom_info *cip = ci.get();
  261.         i = num_custom;
  262.  
  263.         while (i--)
  264.         {
  265.                 x = cip->repl_idx;
  266.                 if (cip->repl_idx >= 0)
  267.                 {
  268.                         PHYSFSX_fseek( f, cip->offset, SEEK_SET );
  269.  
  270.                         if ( cip->flags & BM_FLAG_RLE )
  271.                                 j = PHYSFSX_readInt(f);
  272.                         else
  273.                                 j = cip->width * cip->height;
  274.  
  275.                         if (!MALLOC(p, ubyte, j))
  276.                         {
  277.                                 return rc;
  278.                         }
  279.  
  280.                         bmp = &GameBitmaps[x];
  281.  
  282.                         if (BitmapOriginal[x].get_flag_mask(0x80)) // already customized?
  283.                                 gr_free_bitmap_data(*bmp);
  284.                         else
  285.                         {
  286.                                 // save original bitmap info
  287.                                 BitmapOriginal[x] = *bmp;
  288.                                 BitmapOriginal[x].add_flags(0x80);
  289.                                 if (GameBitmapOffset[x]) // from pig?
  290.                                 {
  291.                                         BitmapOriginal[x].add_flags(BM_FLAG_PAGED_OUT);
  292.                                         BitmapOriginal[x].bm_data = reinterpret_cast<uint8_t *>(static_cast<uintptr_t>(GameBitmapOffset[x]));
  293.                                 }
  294.                         }
  295.  
  296.                         GameBitmapOffset[x] = 0; // not in pig
  297.                         *bmp = {};
  298.                         gr_init_bitmap(*bmp, bm_mode::linear, 0, 0, cip->width, cip->height, cip->width, p);
  299.                         gr_set_bitmap_flags(*bmp, cip->flags & 255);
  300. #if !DXX_USE_OGL
  301.                         bmp->avg_color = cip->flags >> 8;
  302. #endif
  303.  
  304.                         if ( cip->flags & BM_FLAG_RLE )
  305.                         {
  306.                                 int *ip = reinterpret_cast<int *>(p);
  307.                                 *ip = j;
  308.                                 p += 4;
  309.                                 j -= 4;
  310.                         }
  311.  
  312.                         if (PHYSFS_read(f, p, 1, j) < 1)
  313.                         {
  314.                                 return rc;
  315.                         }
  316.  
  317.                 }
  318.                 else if ((cip->repl_idx + 1) < 0)
  319.                 {
  320.                         PHYSFSX_fseek( f, cip->offset, SEEK_SET );
  321.                         snd = &GameSounds[x & 0x7fffffff];
  322.  
  323.                         j = cip->width;
  324.                         if (!MALLOC(p, ubyte, j))
  325.                         {
  326.                                 return rc;
  327.                         }
  328.  
  329.                         if (SoundOriginal[x & 0x7fffffff].length & 0x80000000)  // already customized?
  330.                                 d_free(snd->data);
  331.                         else
  332.                         {
  333. #ifdef ALLEGRO
  334.                                 SoundOriginal[x & 0x7fffffff].length = snd->len | 0x80000000;
  335. #else
  336.                                 SoundOriginal[x & 0x7fffffff].length = snd->length | 0x80000000;
  337. #endif
  338.                                 SoundOriginal[x & 0x7fffffff].data = snd->data;
  339.                         }
  340.  
  341. #ifdef ALLEGRO
  342.                                 snd->loop_end = snd->len = j;
  343. #else
  344.                                 snd->length = j;
  345. #endif
  346.                         snd->data = p;
  347.  
  348.                         if (PHYSFS_read(f, p, j, 1) < 1)
  349.                         {
  350.                                 return rc;
  351.                         }
  352.                 }
  353.                 cip++;
  354.         }
  355.         rc = 0;
  356.         return rc;
  357. }
  358.  
  359. static int read_d2_robot_info(PHYSFS_File *fp, robot_info &ri)
  360. {
  361.         int j, k;
  362.  
  363.         ri.model_num = PHYSFSX_readInt(fp);
  364.  
  365.         for (j = 0; j < MAX_GUNS; j++)
  366.                 PHYSFSX_readVector(fp, ri.gun_points[j]);
  367.         for (j = 0; j < MAX_GUNS; j++)
  368.                 ri.gun_submodels[j] = PHYSFSX_readByte(fp);
  369.         ri.exp1_vclip_num = PHYSFSX_readShort(fp);
  370.         ri.exp1_sound_num = PHYSFSX_readShort(fp);
  371.         ri.exp2_vclip_num = PHYSFSX_readShort(fp);
  372.         ri.exp2_sound_num = PHYSFSX_readShort(fp);
  373.         const auto weapon_type = PHYSFSX_readByte(fp);
  374.         ri.weapon_type = weapon_type < N_weapon_types ? static_cast<weapon_id_type>(weapon_type) : weapon_id_type::LASER_ID_L1;
  375.         /*ri.weapon_type2 =*/ PHYSFSX_readByte(fp);
  376.         ri.n_guns = PHYSFSX_readByte(fp);
  377.         ri.contains_id = PHYSFSX_readByte(fp);
  378.         ri.contains_count = PHYSFSX_readByte(fp);
  379.         ri.contains_prob = PHYSFSX_readByte(fp);
  380.         ri.contains_type = PHYSFSX_readByte(fp);
  381.         /*ri.kamikaze =*/ PHYSFSX_readByte(fp);
  382.         ri.score_value = PHYSFSX_readShort(fp);
  383.         /*ri.badass =*/ PHYSFSX_readByte(fp);
  384.         /*ri.energy_drain =*/ PHYSFSX_readByte(fp);
  385.         ri.lighting = PHYSFSX_readFix(fp);
  386.         ri.strength = PHYSFSX_readFix(fp);
  387.         ri.mass = PHYSFSX_readFix(fp);
  388.         ri.drag = PHYSFSX_readFix(fp);
  389.         for (j = 0; j < NDL; j++)
  390.                 ri.field_of_view[j] = PHYSFSX_readFix(fp);
  391.         for (j = 0; j < NDL; j++)
  392.                 ri.firing_wait[j] = PHYSFSX_readFix(fp);
  393.         for (j = 0; j < NDL; j++)
  394.                 /*ri.firing_wait2[j] =*/ PHYSFSX_readFix(fp);
  395.         for (j = 0; j < NDL; j++)
  396.                 ri.turn_time[j] = PHYSFSX_readFix(fp);
  397. #if 0 // not used in d1, removed in d2
  398.         for (j = 0; j < NDL; j++)
  399.                 ri.fire_power[j] = PHYSFSX_readFix(fp);
  400.         for (j = 0; j < NDL; j++)
  401.                 ri.shield[j] = PHYSFSX_readFix(fp);
  402. #endif
  403.         for (j = 0; j < NDL; j++)
  404.                 ri.max_speed[j] = PHYSFSX_readFix(fp);
  405.         for (j = 0; j < NDL; j++)
  406.                 ri.circle_distance[j] = PHYSFSX_readFix(fp);
  407.         for (j = 0; j < NDL; j++)
  408.                 ri.rapidfire_count[j] = PHYSFSX_readByte(fp);
  409.         for (j = 0; j < NDL; j++)
  410.                 ri.evade_speed[j] = PHYSFSX_readByte(fp);
  411.         ri.cloak_type = PHYSFSX_readByte(fp);
  412.         ri.attack_type = PHYSFSX_readByte(fp);
  413.         ri.see_sound = PHYSFSX_readByte(fp);
  414.         ri.attack_sound = PHYSFSX_readByte(fp);
  415.         ri.claw_sound = PHYSFSX_readByte(fp);
  416.         /*ri.taunt_sound =*/ PHYSFSX_readByte(fp);
  417.         ri.boss_flag = PHYSFSX_readByte(fp);
  418.         /*ri.companion =*/ PHYSFSX_readByte(fp);
  419.         /*ri.smart_blobs =*/ PHYSFSX_readByte(fp);
  420.         /*ri.energy_blobs =*/ PHYSFSX_readByte(fp);
  421.         /*ri.thief =*/ PHYSFSX_readByte(fp);
  422.         /*ri.pursuit =*/ PHYSFSX_readByte(fp);
  423.         /*ri.lightcast =*/ PHYSFSX_readByte(fp);
  424.         /*ri.death_roll =*/ PHYSFSX_readByte(fp);
  425.         /*ri.flags =*/ PHYSFSX_readByte(fp);
  426.         /*ri.pad[0] =*/ PHYSFSX_readByte(fp);
  427.         /*ri.pad[1] =*/ PHYSFSX_readByte(fp);
  428.         /*ri.pad[2] =*/ PHYSFSX_readByte(fp);
  429.         /*ri.deathroll_sound =*/ PHYSFSX_readByte(fp);
  430.         /*ri.glow =*/ PHYSFSX_readByte(fp);
  431.         /*ri.behavior =*/ PHYSFSX_readByte(fp);
  432.         /*ri.aim =*/ PHYSFSX_readByte(fp);
  433.  
  434.         for (j = 0; j < MAX_GUNS + 1; j++)
  435.         {
  436.                 for (k = 0; k < N_ANIM_STATES; k++)
  437.                 {
  438.                         ri.anim_states[j][k].n_joints = PHYSFSX_readShort(fp);
  439.                         ri.anim_states[j][k].offset = PHYSFSX_readShort(fp);
  440.                 }
  441.         }
  442.         ri.always_0xabcd = PHYSFSX_readInt(fp);
  443.  
  444.         return 1;
  445. }
  446.  
  447. namespace dsx {
  448.  
  449. static void load_hxm(const d_fname &hxmname)
  450. {
  451.         auto &Robot_joints = LevelSharedRobotJointState.Robot_joints;
  452.         unsigned int repl_num;
  453.         int i;
  454.         auto f = PHYSFSX_openReadBuffered(hxmname);
  455.         int n_items;
  456.  
  457.         if (!f)
  458.                 return; // hxm file doesn't exist
  459.  
  460.         if (PHYSFSX_readInt(f) != 0x21584d48) /* HMX! */
  461.         {
  462.                 // invalid hxm file
  463.                 return;
  464.         }
  465.  
  466.         if (PHYSFSX_readInt(f) != 1)
  467.         {
  468.                 // unknown version
  469.                 return;
  470.         }
  471.  
  472.         // read robot info
  473.         if ((n_items = PHYSFSX_readInt(f)) != 0)
  474.         {
  475.                 auto &Robot_info = LevelSharedRobotInfoState.Robot_info;
  476.                 for (i = 0; i < n_items; i++)
  477.                 {
  478.                         repl_num = PHYSFSX_readInt(f);
  479.  
  480.                         if (repl_num >= MAX_ROBOT_TYPES)
  481.                         {
  482.                                 PHYSFSX_fseek(f, 480, SEEK_CUR); /* sizeof d2_robot_info */
  483.                         }
  484.                         else
  485.                         {
  486.                                 if (!(read_d2_robot_info(f, Robot_info[repl_num])))
  487.                                 {
  488.                                         return;
  489.                                 }
  490.                         }
  491.                 }
  492.         }
  493.  
  494.         // read joint positions
  495.         if ((n_items = PHYSFSX_readInt(f)) != 0)
  496.         {
  497.                 for (i = 0; i < n_items; i++)
  498.                 {
  499.                         repl_num = PHYSFSX_readInt(f);
  500.  
  501.                         if (repl_num >= MAX_ROBOT_JOINTS)
  502.                                 PHYSFSX_fseek(f, sizeof(jointpos), SEEK_CUR);
  503.                         else
  504.                         {
  505.                                 jointpos_read(f, Robot_joints[repl_num]);
  506.                         }
  507.                 }
  508.         }
  509.  
  510.         // read polygon models
  511.         if ((n_items = PHYSFSX_readInt(f)) != 0)
  512.         {
  513.                 for (i = 0; i < n_items; i++)
  514.                 {
  515.                         polymodel *pm;
  516.  
  517.                         repl_num = PHYSFSX_readInt(f);
  518.                         if (repl_num >= MAX_POLYGON_MODELS)
  519.                         {
  520.                                 PHYSFSX_readInt(f); // skip n_models
  521.                                 PHYSFSX_fseek(f, 734 - 8 + PHYSFSX_readInt(f) + 8, SEEK_CUR);
  522.                         }
  523.                         else
  524.                         {
  525.                                 auto &Polygon_models = LevelSharedPolygonModelState.Polygon_models;
  526.                                 pm = &Polygon_models[repl_num];
  527.                                 polymodel_read(pm, f);
  528.                                 const auto model_data_size = pm->model_data_size;
  529.                                 pm->model_data = std::make_unique<uint8_t[]>(model_data_size);
  530.                                 if (PHYSFS_read(f, pm->model_data, model_data_size, 1) < 1)
  531.                                 {
  532.                                         pm->model_data.reset();
  533.                                         return;
  534.                                 }
  535.  
  536.                                 Dying_modelnums[repl_num] = PHYSFSX_readInt(f);
  537.                                 Dead_modelnums[repl_num] = PHYSFSX_readInt(f);
  538.                         }
  539.                 }
  540.         }
  541.  
  542.         // read object bitmaps
  543.         if ((n_items = PHYSFSX_readInt(f)) != 0)
  544.         {
  545.                 for (i = 0; i < n_items; i++)
  546.                 {
  547.                         repl_num = PHYSFSX_readInt(f);
  548.                         auto v = PHYSFSX_readShort(f);
  549.                         if (repl_num < ObjBitmaps.size())
  550.                                 ObjBitmaps[repl_num].index = v;
  551.                 }
  552.         }
  553. }
  554.  
  555. }
  556.  
  557. // undo customized items
  558. static void custom_remove()
  559. {
  560.         int i;
  561.         auto bmo = std::begin(BitmapOriginal);
  562.         auto bmp = std::begin(GameBitmaps);
  563.  
  564.         for (i = 0; i < MAX_BITMAP_FILES; bmo++, bmp++, i++)
  565.                 if (bmo->get_flag_mask(0x80))
  566.                 {
  567.                         gr_free_bitmap_data(*bmp);
  568.                         *bmp = *bmo;
  569.  
  570.                         if (bmo->get_flag_mask(BM_FLAG_PAGED_OUT))
  571.                         {
  572.                                 GameBitmapOffset[i] = static_cast<int>(reinterpret_cast<uintptr_t>(bmo->bm_data));
  573.                                 gr_set_bitmap_flags(*bmp, BM_FLAG_PAGED_OUT);
  574.                                 gr_set_bitmap_data(*bmp, nullptr);
  575.                         }
  576.                         else
  577.                         {
  578.                                 gr_set_bitmap_flags(*bmp, bmo->get_flag_mask(0x7f));
  579.                         }
  580.                         bmo->clear_flags();
  581.                 }
  582.         for (i = 0; i < MAX_SOUND_FILES; i++)
  583.                 if (SoundOriginal[i].length & 0x80000000)
  584.                 {
  585.                         d_free(GameSounds[i].data);
  586.                         GameSounds[i].data = SoundOriginal[i].data;
  587. #ifdef ALLEGRO
  588.                         GameSounds[i].len = SoundOriginal[i].length & 0x7fffffff;
  589. #else
  590.                         GameSounds[i].length = SoundOriginal[i].length & 0x7fffffff;
  591. #endif
  592.                         SoundOriginal[i].length = 0;
  593.                 }
  594. }
  595.  
  596. void load_custom_data(const d_fname &level_name)
  597. {
  598.         custom_remove();
  599.         d_fname custom_file;
  600.         using std::begin;
  601.         using std::end;
  602.         using std::copy;
  603.         using std::next;
  604.         auto bl = begin(level_name);
  605.         auto bc = begin(custom_file);
  606.         auto &pg1 = ".pg1";
  607.         copy(bl, next(bl, custom_file.size() - sizeof(pg1)), bc);
  608.         auto o = std::find(bc, next(bc, custom_file.size() - sizeof(pg1)), '.');
  609.         copy(begin(pg1), end(pg1), o);
  610.         load_pigpog(custom_file);
  611.         auto &dtx = "dtx";
  612.         ++o;
  613.         copy(begin(dtx), end(dtx), o);
  614.         load_pigpog(custom_file);
  615.         auto &hx1 = "hx1";
  616.         copy(begin(hx1), end(hx1), o);
  617.         load_hxm(custom_file);
  618. }
  619.  
  620. void custom_close()
  621. {
  622.         custom_remove();
  623. }
  624.