2014-06-01 17:55:23 +00:00
|
|
|
/*
|
|
|
|
* This file is part of the DXX-Rebirth project <http://www.dxx-rebirth.com/>.
|
|
|
|
* It is copyright by its individual contributors, as recorded in the
|
|
|
|
* project's Git history. See COPYING.txt at the top level for license
|
|
|
|
* terms and a link to the Git history.
|
|
|
|
*/
|
2006-03-20 16:43:15 +00:00
|
|
|
/*
|
|
|
|
* Load custom textures & robot data
|
|
|
|
*/
|
|
|
|
|
2014-08-05 02:32:00 +00:00
|
|
|
#include <memory>
|
2010-10-16 09:13:11 +00:00
|
|
|
#include <string.h>
|
2006-03-20 16:43:15 +00:00
|
|
|
#include "gr.h"
|
2008-01-02 03:37:13 +00:00
|
|
|
#include "pstypes.h"
|
2006-03-20 16:43:15 +00:00
|
|
|
#include "piggy.h"
|
|
|
|
#include "textures.h"
|
|
|
|
#include "polyobj.h"
|
|
|
|
#include "weapon.h"
|
|
|
|
#include "digi.h"
|
|
|
|
#include "hash.h"
|
|
|
|
#include "u_mem.h"
|
|
|
|
#include "custom.h"
|
2014-07-20 01:09:55 +00:00
|
|
|
#include "physfsx.h"
|
2006-03-20 16:43:15 +00:00
|
|
|
|
2014-07-23 02:27:22 +00:00
|
|
|
#include "compiler-begin.h"
|
2014-08-16 04:15:16 +00:00
|
|
|
#include "compiler-make_unique.h"
|
2014-08-05 02:32:00 +00:00
|
|
|
#include "compiler-range_for.h"
|
|
|
|
#include "partial_range.h"
|
|
|
|
|
2010-10-16 09:13:11 +00:00
|
|
|
//#define D2TMAP_CONV // used for testing
|
|
|
|
|
|
|
|
struct snd_info
|
|
|
|
{
|
|
|
|
unsigned int length;
|
|
|
|
ubyte *data;
|
2006-03-20 16:43:15 +00:00
|
|
|
};
|
|
|
|
|
2013-12-22 22:03:07 +00:00
|
|
|
struct DiskBitmapHeader2
|
2010-10-16 09:13:11 +00:00
|
|
|
{
|
2006-03-20 16:43:15 +00:00
|
|
|
char name[8];
|
|
|
|
ubyte dflags;
|
|
|
|
ubyte width;
|
|
|
|
ubyte height;
|
|
|
|
ubyte hi_wh;
|
|
|
|
ubyte flags;
|
|
|
|
ubyte avg_color;
|
|
|
|
int offset;
|
2013-12-22 22:03:07 +00:00
|
|
|
} __pack__;
|
2006-03-20 16:43:15 +00:00
|
|
|
|
2013-12-22 22:03:07 +00:00
|
|
|
struct DiskBitmapHeader
|
2010-10-16 09:13:11 +00:00
|
|
|
{
|
2006-03-20 16:43:15 +00:00
|
|
|
char name[8];
|
|
|
|
ubyte dflags;
|
|
|
|
ubyte width;
|
|
|
|
ubyte height;
|
|
|
|
ubyte flags;
|
|
|
|
ubyte avg_color;
|
|
|
|
int offset;
|
2013-12-22 22:03:07 +00:00
|
|
|
} __pack__;
|
2006-03-20 16:43:15 +00:00
|
|
|
|
2013-12-22 22:03:07 +00:00
|
|
|
struct DiskSoundHeader
|
2010-10-16 09:13:11 +00:00
|
|
|
{
|
2006-03-20 16:43:15 +00:00
|
|
|
char name[8];
|
|
|
|
int length;
|
|
|
|
int data_length;
|
|
|
|
int offset;
|
2013-12-22 22:03:07 +00:00
|
|
|
} __pack__;
|
2006-03-20 16:43:15 +00:00
|
|
|
|
2010-10-16 09:13:11 +00:00
|
|
|
struct custom_info
|
|
|
|
{
|
|
|
|
int offset;
|
|
|
|
int repl_idx; // 0x80000000 -> sound, -1 -> n/a
|
|
|
|
unsigned int flags;
|
|
|
|
int width, height;
|
2006-03-20 16:43:15 +00:00
|
|
|
};
|
|
|
|
|
2013-03-10 02:45:12 +00:00
|
|
|
static grs_bitmap BitmapOriginal[MAX_BITMAP_FILES];
|
|
|
|
static struct snd_info SoundOriginal[MAX_SOUND_FILES];
|
2010-10-16 09:13:11 +00:00
|
|
|
|
2014-08-05 02:32:00 +00:00
|
|
|
static int load_pig1(PHYSFS_file *f, unsigned num_bitmaps, unsigned num_sounds, unsigned &num_custom, std::unique_ptr<custom_info[]> &ci)
|
2010-10-16 09:13:11 +00:00
|
|
|
{
|
|
|
|
int data_ofs;
|
|
|
|
int i;
|
|
|
|
DiskBitmapHeader bmh;
|
|
|
|
DiskSoundHeader sndh;
|
|
|
|
char name[15];
|
|
|
|
|
2014-08-05 02:32:00 +00:00
|
|
|
num_custom = 0;
|
2010-10-16 09:13:11 +00:00
|
|
|
|
|
|
|
if ((unsigned int)num_bitmaps <= MAX_BITMAP_FILES) // <v1.4 pig?
|
|
|
|
{
|
2011-06-01 07:59:51 +00:00
|
|
|
PHYSFSX_fseek(f, 8, SEEK_SET);
|
2010-10-16 09:13:11 +00:00
|
|
|
data_ofs = 8;
|
|
|
|
}
|
2011-06-01 07:59:51 +00:00
|
|
|
else if (num_bitmaps > 0 && num_bitmaps < PHYSFS_fileLength(f)) // >=v1.4 pig?
|
2010-10-16 09:13:11 +00:00
|
|
|
{
|
2011-06-01 07:59:51 +00:00
|
|
|
PHYSFSX_fseek(f, num_bitmaps, SEEK_SET);
|
2010-10-16 09:13:11 +00:00
|
|
|
data_ofs = num_bitmaps + 8;
|
2011-06-01 07:59:51 +00:00
|
|
|
num_bitmaps = PHYSFSX_readInt(f);
|
|
|
|
num_sounds = PHYSFSX_readInt(f);
|
2010-10-16 09:13:11 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
return -1; // invalid pig file
|
|
|
|
|
|
|
|
if ((unsigned int)num_bitmaps >= MAX_BITMAP_FILES || (unsigned int)num_sounds >= MAX_SOUND_FILES)
|
|
|
|
return -1; // invalid pig file
|
2014-08-16 04:15:16 +00:00
|
|
|
ci = make_unique<custom_info[]>(num_bitmaps + num_sounds);
|
2014-08-05 02:32:00 +00:00
|
|
|
custom_info *cip = ci.get();
|
2010-10-16 09:13:11 +00:00
|
|
|
data_ofs += num_bitmaps * sizeof(DiskBitmapHeader) + num_sounds * sizeof(DiskSoundHeader);
|
2006-03-20 16:43:15 +00:00
|
|
|
i = num_bitmaps;
|
2010-10-16 09:13:11 +00:00
|
|
|
|
2006-03-20 16:43:15 +00:00
|
|
|
while (i--)
|
2010-10-16 09:13:11 +00:00
|
|
|
{
|
2011-06-01 07:59:51 +00:00
|
|
|
if (PHYSFS_read(f, &bmh, sizeof(DiskBitmapHeader), 1) < 1)
|
2010-10-16 09:13:11 +00:00
|
|
|
{
|
|
|
|
return -1;
|
2006-03-20 16:43:15 +00:00
|
|
|
}
|
2010-10-16 09:13:11 +00:00
|
|
|
|
2013-12-17 02:55:38 +00:00
|
|
|
snprintf(name, sizeof(name), "%.8s%c%d", bmh.name, (bmh.dflags & DBM_FLAG_ABM) ? '#' : 0, bmh.dflags & 63);
|
2010-10-16 09:13:11 +00:00
|
|
|
|
|
|
|
cip->offset = bmh.offset + data_ofs;
|
|
|
|
cip->repl_idx = hashtable_search(&AllBitmapsNames, name);
|
|
|
|
cip->flags = bmh.flags & (BM_FLAG_TRANSPARENT | BM_FLAG_SUPER_TRANSPARENT | BM_FLAG_NO_LIGHTING | BM_FLAG_RLE);
|
|
|
|
cip->width = bmh.width + ((bmh.dflags & DBM_FLAG_LARGE) ? 256 : 0);
|
|
|
|
cip->height = bmh.height;
|
|
|
|
cip++;
|
2006-03-20 16:43:15 +00:00
|
|
|
}
|
2010-10-16 09:13:11 +00:00
|
|
|
|
|
|
|
i = num_sounds;
|
|
|
|
|
|
|
|
while (i--)
|
|
|
|
{
|
2011-06-01 07:59:51 +00:00
|
|
|
if (PHYSFS_read(f, &sndh, sizeof(DiskSoundHeader), 1) < 1)
|
2010-10-16 09:13:11 +00:00
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(name, sndh.name, 8);
|
|
|
|
name[8] = 0;
|
|
|
|
cip->offset = sndh.offset + data_ofs;
|
|
|
|
cip->repl_idx = hashtable_search(&AllDigiSndNames, name) | 0x80000000;
|
|
|
|
cip->width = sndh.length;
|
|
|
|
cip++;
|
2006-03-20 16:43:15 +00:00
|
|
|
}
|
2010-10-16 09:13:11 +00:00
|
|
|
|
2014-08-05 02:32:00 +00:00
|
|
|
num_custom = num_bitmaps + num_sounds;
|
2010-10-16 09:13:11 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-08-05 02:32:00 +00:00
|
|
|
static int load_pog(PHYSFS_file *f, int pog_sig, int pog_ver, unsigned &num_custom, std::unique_ptr<custom_info[]> &ci)
|
2010-10-16 09:13:11 +00:00
|
|
|
{
|
|
|
|
int data_ofs;
|
|
|
|
int num_bitmaps;
|
|
|
|
int no_repl = 0;
|
|
|
|
int i;
|
|
|
|
DiskBitmapHeader2 bmh;
|
|
|
|
|
|
|
|
#ifdef D2TMAP_CONV
|
|
|
|
int x, j, N_d2tmap;
|
|
|
|
int *d2tmap = NULL;
|
2011-06-01 07:59:51 +00:00
|
|
|
PHYSFS_file *f2 = NULL;
|
|
|
|
if ((f2 = PHYSFSX_openReadBuffered("d2tmap.bin")))
|
2010-10-16 09:13:11 +00:00
|
|
|
{
|
2011-06-01 07:59:51 +00:00
|
|
|
N_d2tmap = PHYSFSX_readInt(f2);
|
2010-10-16 09:13:11 +00:00
|
|
|
if ((d2tmap = d_malloc(N_d2tmap * sizeof(d2tmap[0]))))
|
|
|
|
for (i = 0; i < N_d2tmap; i++)
|
2011-06-01 07:59:51 +00:00
|
|
|
d2tmap[i] = PHYSFSX_readShort(f2);
|
|
|
|
PHYSFS_close(f2);
|
2010-10-16 09:13:11 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2014-08-05 02:32:00 +00:00
|
|
|
num_custom = 0;
|
2010-10-16 09:13:11 +00:00
|
|
|
|
|
|
|
if (pog_sig == 0x47495050 && pog_ver == 2) /* PPIG */
|
|
|
|
no_repl = 1;
|
|
|
|
else if (pog_sig != 0x474f5044 || pog_ver != 1) /* DPOG */
|
|
|
|
return -1; // no pig2/pog file/unknown version
|
|
|
|
|
2011-06-01 07:59:51 +00:00
|
|
|
num_bitmaps = PHYSFSX_readInt(f);
|
2014-08-16 04:15:16 +00:00
|
|
|
ci = make_unique<custom_info[]>(num_bitmaps);
|
2014-08-05 02:32:00 +00:00
|
|
|
custom_info *cip = ci.get();
|
2010-10-16 09:13:11 +00:00
|
|
|
data_ofs = 12 + num_bitmaps * sizeof(DiskBitmapHeader2);
|
|
|
|
|
|
|
|
if (!no_repl)
|
|
|
|
{
|
|
|
|
i = num_bitmaps;
|
|
|
|
|
|
|
|
while (i--)
|
2011-06-01 07:59:51 +00:00
|
|
|
(cip++)->repl_idx = PHYSFSX_readShort(f);
|
2010-10-16 09:13:11 +00:00
|
|
|
|
2014-08-05 02:32:00 +00:00
|
|
|
cip = ci.get();
|
2010-10-16 09:13:11 +00:00
|
|
|
data_ofs += num_bitmaps * 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef D2TMAP_CONV
|
|
|
|
if (d2tmap)
|
|
|
|
for (i = 0; i < num_bitmaps; i++)
|
|
|
|
{
|
|
|
|
x = cip[i].repl_idx;
|
|
|
|
cip[i].repl_idx = -1;
|
|
|
|
|
|
|
|
for (j = 0; j < N_d2tmap; j++)
|
|
|
|
if (x == d2tmap[j])
|
|
|
|
{
|
|
|
|
cip[i].repl_idx = Textures[j % NumTextures].index;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
i = num_bitmaps;
|
|
|
|
|
|
|
|
while (i--)
|
|
|
|
{
|
2011-06-01 07:59:51 +00:00
|
|
|
if (PHYSFS_read(f, &bmh, sizeof(DiskBitmapHeader2), 1) < 1)
|
2010-10-16 09:13:11 +00:00
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
cip->offset = bmh.offset + data_ofs;
|
|
|
|
cip->flags = bmh.flags & (BM_FLAG_TRANSPARENT | BM_FLAG_SUPER_TRANSPARENT | BM_FLAG_NO_LIGHTING | BM_FLAG_RLE);
|
|
|
|
cip->width = bmh.width + ((bmh.hi_wh & 15) << 8);
|
|
|
|
cip->height = bmh.height + ((bmh.hi_wh >> 4) << 8);
|
|
|
|
cip++;
|
|
|
|
}
|
|
|
|
|
2014-08-05 02:32:00 +00:00
|
|
|
num_custom = num_bitmaps;
|
2010-10-16 09:13:11 +00:00
|
|
|
|
|
|
|
return 0;
|
2006-03-20 16:43:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// load custom textures/sounds from pog/pig file
|
|
|
|
// returns 0 if ok, <0 on error
|
2014-07-23 02:27:22 +00:00
|
|
|
static int load_pigpog(const d_fname &pogname)
|
2010-10-16 09:13:11 +00:00
|
|
|
{
|
2014-08-05 02:32:00 +00:00
|
|
|
unsigned num_custom;
|
2010-10-16 09:13:11 +00:00
|
|
|
grs_bitmap *bmp;
|
|
|
|
digi_sound *snd;
|
|
|
|
ubyte *p;
|
2011-06-01 07:59:51 +00:00
|
|
|
PHYSFS_file *f;
|
2010-10-16 09:13:11 +00:00
|
|
|
int i, j, rc = -1;
|
|
|
|
unsigned int x = 0;
|
|
|
|
|
2013-09-02 23:21:13 +00:00
|
|
|
if (!(f = PHYSFSX_openReadBuffered(pogname)))
|
2010-10-16 09:13:11 +00:00
|
|
|
return -1; // pog file doesn't exist
|
|
|
|
|
2011-06-01 07:59:51 +00:00
|
|
|
i = PHYSFSX_readInt(f);
|
|
|
|
x = PHYSFSX_readInt(f);
|
2010-10-16 09:13:11 +00:00
|
|
|
|
2014-08-05 02:32:00 +00:00
|
|
|
std::unique_ptr<custom_info[]> ci;
|
|
|
|
if (load_pog(f, i, x, num_custom, ci) && load_pig1(f, i, x, num_custom, ci))
|
2010-10-16 09:13:11 +00:00
|
|
|
{
|
2011-06-01 07:59:51 +00:00
|
|
|
PHYSFS_close(f);
|
2010-10-16 09:13:11 +00:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2014-08-05 02:32:00 +00:00
|
|
|
custom_info *cip = ci.get();
|
2010-10-16 09:13:11 +00:00
|
|
|
i = num_custom;
|
|
|
|
|
|
|
|
while (i--)
|
|
|
|
{
|
|
|
|
x = cip->repl_idx;
|
|
|
|
if (cip->repl_idx >= 0)
|
|
|
|
{
|
2011-06-01 07:59:51 +00:00
|
|
|
PHYSFSX_fseek( f, cip->offset, SEEK_SET );
|
2010-10-16 09:13:11 +00:00
|
|
|
|
|
|
|
if ( cip->flags & BM_FLAG_RLE )
|
2011-06-01 07:59:51 +00:00
|
|
|
j = PHYSFSX_readInt(f);
|
2010-10-16 09:13:11 +00:00
|
|
|
else
|
|
|
|
j = cip->width * cip->height;
|
|
|
|
|
2013-10-24 03:08:58 +00:00
|
|
|
if (!MALLOC(p, ubyte, j))
|
2010-10-16 09:13:11 +00:00
|
|
|
{
|
2011-06-01 07:59:51 +00:00
|
|
|
PHYSFS_close(f);
|
2010-10-16 09:13:11 +00:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
bmp = &GameBitmaps[x];
|
|
|
|
|
|
|
|
if (BitmapOriginal[x].bm_flags & 0x80) // already customized?
|
2014-11-30 22:09:20 +00:00
|
|
|
gr_free_bitmap_data(*bmp);
|
2010-10-16 09:13:11 +00:00
|
|
|
else
|
|
|
|
{
|
2006-03-20 16:43:15 +00:00
|
|
|
// save original bitmap info
|
|
|
|
BitmapOriginal[x] = *bmp;
|
|
|
|
BitmapOriginal[x].bm_flags |= 0x80;
|
2010-10-16 09:13:11 +00:00
|
|
|
if (GameBitmapOffset[x]) // from pig?
|
|
|
|
{
|
|
|
|
BitmapOriginal[x].bm_flags |= BM_FLAG_PAGED_OUT;
|
2006-03-20 16:43:15 +00:00
|
|
|
BitmapOriginal[x].bm_data = (ubyte *)(size_t)GameBitmapOffset[x];
|
2010-10-16 09:13:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
GameBitmapOffset[x] = 0; // not in pig
|
2014-07-04 03:44:25 +00:00
|
|
|
*bmp = {};
|
2010-10-16 09:13:11 +00:00
|
|
|
gr_init_bitmap (bmp, 0, 0, 0, cip->width, cip->height, cip->width, p);
|
|
|
|
gr_set_bitmap_flags(bmp, cip->flags & 255);
|
|
|
|
bmp->avg_color = cip->flags >> 8;
|
|
|
|
|
|
|
|
if ( cip->flags & BM_FLAG_RLE )
|
|
|
|
{
|
|
|
|
int *ip = (int *)p;
|
|
|
|
*ip = j;
|
|
|
|
p += 4;
|
|
|
|
j -= 4;
|
|
|
|
}
|
|
|
|
|
2011-06-01 07:59:51 +00:00
|
|
|
if (PHYSFS_read(f, p, 1, j) < 1)
|
2010-10-16 09:13:11 +00:00
|
|
|
{
|
2011-06-01 07:59:51 +00:00
|
|
|
PHYSFS_close(f);
|
2010-10-16 09:13:11 +00:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
else if ((cip->repl_idx + 1) < 0)
|
|
|
|
{
|
2011-06-01 07:59:51 +00:00
|
|
|
PHYSFSX_fseek( f, cip->offset, SEEK_SET );
|
2010-10-16 09:13:11 +00:00
|
|
|
snd = &GameSounds[x & 0x7fffffff];
|
|
|
|
|
2013-10-24 03:08:58 +00:00
|
|
|
j = cip->width;
|
|
|
|
if (!MALLOC(p, ubyte, j))
|
2010-10-16 09:13:11 +00:00
|
|
|
{
|
2011-06-01 07:59:51 +00:00
|
|
|
PHYSFS_close(f);
|
2010-10-16 09:13:11 +00:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (SoundOriginal[x & 0x7fffffff].length & 0x80000000) // already customized?
|
|
|
|
d_free(snd->data);
|
|
|
|
else
|
|
|
|
{
|
2006-03-20 16:43:15 +00:00
|
|
|
#ifdef ALLEGRO
|
2010-10-16 09:13:11 +00:00
|
|
|
SoundOriginal[x & 0x7fffffff].length = snd->len | 0x80000000;
|
2006-03-20 16:43:15 +00:00
|
|
|
#else
|
2010-10-16 09:13:11 +00:00
|
|
|
SoundOriginal[x & 0x7fffffff].length = snd->length | 0x80000000;
|
2006-03-20 16:43:15 +00:00
|
|
|
#endif
|
2010-10-16 09:13:11 +00:00
|
|
|
SoundOriginal[x & 0x7fffffff].data = snd->data;
|
|
|
|
}
|
2006-03-20 16:43:15 +00:00
|
|
|
|
|
|
|
#ifdef ALLEGRO
|
2010-10-16 09:13:11 +00:00
|
|
|
snd->loop_end = snd->len = j;
|
2006-03-20 16:43:15 +00:00
|
|
|
#else
|
2010-10-16 09:13:11 +00:00
|
|
|
snd->length = j;
|
2006-03-20 16:43:15 +00:00
|
|
|
#endif
|
2010-10-16 09:13:11 +00:00
|
|
|
snd->data = p;
|
|
|
|
|
2011-06-01 07:59:51 +00:00
|
|
|
if (PHYSFS_read(f, p, j, 1) < 1)
|
2010-10-16 09:13:11 +00:00
|
|
|
{
|
2011-06-01 07:59:51 +00:00
|
|
|
PHYSFS_close(f);
|
2010-10-16 09:13:11 +00:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
cip++;
|
2006-03-20 16:43:15 +00:00
|
|
|
}
|
2010-10-16 09:13:11 +00:00
|
|
|
rc = 0;
|
|
|
|
|
2011-06-01 07:59:51 +00:00
|
|
|
PHYSFS_close(f);
|
2010-10-16 09:13:11 +00:00
|
|
|
|
|
|
|
return rc;
|
2006-03-20 16:43:15 +00:00
|
|
|
}
|
|
|
|
|
2013-03-10 02:45:12 +00:00
|
|
|
static int read_d2_robot_info(PHYSFS_file *fp, robot_info *ri)
|
2006-03-20 16:43:15 +00:00
|
|
|
{
|
|
|
|
int j, k;
|
|
|
|
|
2011-06-01 07:59:51 +00:00
|
|
|
ri->model_num = PHYSFSX_readInt(fp);
|
2010-10-16 09:13:11 +00:00
|
|
|
|
2008-01-13 00:58:49 +00:00
|
|
|
for (j = 0; j < MAX_GUNS; j++)
|
2014-10-26 22:08:58 +00:00
|
|
|
PHYSFSX_readVector(fp, ri->gun_points[j]);
|
2006-03-20 16:43:15 +00:00
|
|
|
for (j = 0; j < MAX_GUNS; j++)
|
2011-06-01 07:59:51 +00:00
|
|
|
ri->gun_submodels[j] = PHYSFSX_readByte(fp);
|
|
|
|
ri->exp1_vclip_num = PHYSFSX_readShort(fp);
|
|
|
|
ri->exp1_sound_num = PHYSFSX_readShort(fp);
|
|
|
|
ri->exp2_vclip_num = PHYSFSX_readShort(fp);
|
|
|
|
ri->exp2_sound_num = PHYSFSX_readShort(fp);
|
|
|
|
ri->weapon_type = PHYSFSX_readByte(fp);
|
2006-03-20 16:43:15 +00:00
|
|
|
if (ri->weapon_type >= N_weapon_types)
|
|
|
|
ri->weapon_type = 0;
|
2011-06-01 07:59:51 +00:00
|
|
|
/*ri->weapon_type2 =*/ PHYSFSX_readByte(fp);
|
|
|
|
ri->n_guns = PHYSFSX_readByte(fp);
|
|
|
|
ri->contains_id = PHYSFSX_readByte(fp);
|
|
|
|
ri->contains_count = PHYSFSX_readByte(fp);
|
|
|
|
ri->contains_prob = PHYSFSX_readByte(fp);
|
|
|
|
ri->contains_type = PHYSFSX_readByte(fp);
|
|
|
|
/*ri->kamikaze =*/ PHYSFSX_readByte(fp);
|
|
|
|
ri->score_value = PHYSFSX_readShort(fp);
|
|
|
|
/*ri->badass =*/ PHYSFSX_readByte(fp);
|
|
|
|
/*ri->energy_drain =*/ PHYSFSX_readByte(fp);
|
|
|
|
ri->lighting = PHYSFSX_readFix(fp);
|
|
|
|
ri->strength = PHYSFSX_readFix(fp);
|
|
|
|
ri->mass = PHYSFSX_readFix(fp);
|
|
|
|
ri->drag = PHYSFSX_readFix(fp);
|
2006-03-20 16:43:15 +00:00
|
|
|
for (j = 0; j < NDL; j++)
|
2011-06-01 07:59:51 +00:00
|
|
|
ri->field_of_view[j] = PHYSFSX_readFix(fp);
|
2006-03-20 16:43:15 +00:00
|
|
|
for (j = 0; j < NDL; j++)
|
2011-06-01 07:59:51 +00:00
|
|
|
ri->firing_wait[j] = PHYSFSX_readFix(fp);
|
2006-03-20 16:43:15 +00:00
|
|
|
for (j = 0; j < NDL; j++)
|
2011-06-01 07:59:51 +00:00
|
|
|
/*ri->firing_wait2[j] =*/ PHYSFSX_readFix(fp);
|
2006-03-20 16:43:15 +00:00
|
|
|
for (j = 0; j < NDL; j++)
|
2011-06-01 07:59:51 +00:00
|
|
|
ri->turn_time[j] = PHYSFSX_readFix(fp);
|
2006-03-20 16:43:15 +00:00
|
|
|
#if 0 // not used in d1, removed in d2
|
|
|
|
for (j = 0; j < NDL; j++)
|
2011-06-01 07:59:51 +00:00
|
|
|
ri->fire_power[j] = PHYSFSX_readFix(fp);
|
2006-03-20 16:43:15 +00:00
|
|
|
for (j = 0; j < NDL; j++)
|
2011-06-01 07:59:51 +00:00
|
|
|
ri->shield[j] = PHYSFSX_readFix(fp);
|
2006-03-20 16:43:15 +00:00
|
|
|
#endif
|
|
|
|
for (j = 0; j < NDL; j++)
|
2011-06-01 07:59:51 +00:00
|
|
|
ri->max_speed[j] = PHYSFSX_readFix(fp);
|
2006-03-20 16:43:15 +00:00
|
|
|
for (j = 0; j < NDL; j++)
|
2011-06-01 07:59:51 +00:00
|
|
|
ri->circle_distance[j] = PHYSFSX_readFix(fp);
|
2006-03-20 16:43:15 +00:00
|
|
|
for (j = 0; j < NDL; j++)
|
2011-06-01 07:59:51 +00:00
|
|
|
ri->rapidfire_count[j] = PHYSFSX_readByte(fp);
|
2006-03-20 16:43:15 +00:00
|
|
|
for (j = 0; j < NDL; j++)
|
2011-06-01 07:59:51 +00:00
|
|
|
ri->evade_speed[j] = PHYSFSX_readByte(fp);
|
|
|
|
ri->cloak_type = PHYSFSX_readByte(fp);
|
|
|
|
ri->attack_type = PHYSFSX_readByte(fp);
|
|
|
|
ri->see_sound = PHYSFSX_readByte(fp);
|
|
|
|
ri->attack_sound = PHYSFSX_readByte(fp);
|
|
|
|
ri->claw_sound = PHYSFSX_readByte(fp);
|
|
|
|
/*ri->taunt_sound =*/ PHYSFSX_readByte(fp);
|
|
|
|
ri->boss_flag = PHYSFSX_readByte(fp);
|
|
|
|
/*ri->companion =*/ PHYSFSX_readByte(fp);
|
|
|
|
/*ri->smart_blobs =*/ PHYSFSX_readByte(fp);
|
|
|
|
/*ri->energy_blobs =*/ PHYSFSX_readByte(fp);
|
|
|
|
/*ri->thief =*/ PHYSFSX_readByte(fp);
|
|
|
|
/*ri->pursuit =*/ PHYSFSX_readByte(fp);
|
|
|
|
/*ri->lightcast =*/ PHYSFSX_readByte(fp);
|
|
|
|
/*ri->death_roll =*/ PHYSFSX_readByte(fp);
|
|
|
|
/*ri->flags =*/ PHYSFSX_readByte(fp);
|
|
|
|
/*ri->pad[0] =*/ PHYSFSX_readByte(fp);
|
|
|
|
/*ri->pad[1] =*/ PHYSFSX_readByte(fp);
|
|
|
|
/*ri->pad[2] =*/ PHYSFSX_readByte(fp);
|
|
|
|
/*ri->deathroll_sound =*/ PHYSFSX_readByte(fp);
|
|
|
|
/*ri->glow =*/ PHYSFSX_readByte(fp);
|
|
|
|
/*ri->behavior =*/ PHYSFSX_readByte(fp);
|
|
|
|
/*ri->aim =*/ PHYSFSX_readByte(fp);
|
2006-03-20 16:43:15 +00:00
|
|
|
|
2010-10-16 09:13:11 +00:00
|
|
|
for (j = 0; j < MAX_GUNS + 1; j++)
|
|
|
|
{
|
|
|
|
for (k = 0; k < N_ANIM_STATES; k++)
|
|
|
|
{
|
2011-06-01 07:59:51 +00:00
|
|
|
ri->anim_states[j][k].n_joints = PHYSFSX_readShort(fp);
|
|
|
|
ri->anim_states[j][k].offset = PHYSFSX_readShort(fp);
|
2006-03-20 16:43:15 +00:00
|
|
|
}
|
|
|
|
}
|
2011-06-01 07:59:51 +00:00
|
|
|
ri->always_0xabcd = PHYSFSX_readInt(fp);
|
2010-10-16 09:13:11 +00:00
|
|
|
|
2006-03-20 16:43:15 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2014-07-23 02:27:22 +00:00
|
|
|
static void load_hxm(const d_fname &hxmname)
|
2010-10-16 09:13:11 +00:00
|
|
|
{
|
|
|
|
unsigned int repl_num;
|
|
|
|
int i;
|
2011-06-01 07:59:51 +00:00
|
|
|
PHYSFS_file *f;
|
2010-10-16 09:13:11 +00:00
|
|
|
int n_items;
|
|
|
|
|
2013-09-02 23:21:13 +00:00
|
|
|
if (!(f = PHYSFSX_openReadBuffered(hxmname)))
|
2010-10-16 09:13:11 +00:00
|
|
|
return; // hxm file doesn't exist
|
|
|
|
|
2011-06-01 07:59:51 +00:00
|
|
|
if (PHYSFSX_readInt(f) != 0x21584d48) /* HMX! */
|
2010-10-16 09:13:11 +00:00
|
|
|
{
|
2011-06-01 07:59:51 +00:00
|
|
|
PHYSFS_close(f); // invalid hxm file
|
2010-10-16 09:13:11 +00:00
|
|
|
return;
|
2006-03-20 16:43:15 +00:00
|
|
|
}
|
2010-10-16 09:13:11 +00:00
|
|
|
|
2011-06-01 07:59:51 +00:00
|
|
|
if (PHYSFSX_readInt(f) != 1)
|
2010-10-16 09:13:11 +00:00
|
|
|
{
|
2011-06-01 07:59:51 +00:00
|
|
|
PHYSFS_close(f); // unknown version
|
2010-10-16 09:13:11 +00:00
|
|
|
return;
|
2006-03-20 16:43:15 +00:00
|
|
|
}
|
2010-10-16 09:13:11 +00:00
|
|
|
|
|
|
|
// read robot info
|
2011-06-01 07:59:51 +00:00
|
|
|
if ((n_items = PHYSFSX_readInt(f)) != 0)
|
2010-10-16 09:13:11 +00:00
|
|
|
{
|
|
|
|
for (i = 0; i < n_items; i++)
|
|
|
|
{
|
2011-06-01 07:59:51 +00:00
|
|
|
repl_num = PHYSFSX_readInt(f);
|
2010-10-16 09:13:11 +00:00
|
|
|
|
|
|
|
if (repl_num >= MAX_ROBOT_TYPES)
|
|
|
|
{
|
2011-06-01 07:59:51 +00:00
|
|
|
PHYSFSX_fseek(f, 480, SEEK_CUR); /* sizeof d2_robot_info */
|
2010-10-16 09:13:11 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (!(read_d2_robot_info(f, &Robot_info[repl_num])))
|
|
|
|
{
|
2011-06-01 07:59:51 +00:00
|
|
|
PHYSFS_close(f);
|
2010-10-16 09:13:11 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2006-03-20 16:43:15 +00:00
|
|
|
}
|
2010-10-16 09:13:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// read joint positions
|
2011-06-01 07:59:51 +00:00
|
|
|
if ((n_items = PHYSFSX_readInt(f)) != 0)
|
2010-10-16 09:13:11 +00:00
|
|
|
{
|
|
|
|
for (i = 0; i < n_items; i++)
|
|
|
|
{
|
2011-06-01 07:59:51 +00:00
|
|
|
repl_num = PHYSFSX_readInt(f);
|
2010-10-16 09:13:11 +00:00
|
|
|
|
|
|
|
if (repl_num >= MAX_ROBOT_JOINTS)
|
2011-06-01 07:59:51 +00:00
|
|
|
PHYSFSX_fseek(f, sizeof(jointpos), SEEK_CUR);
|
2010-10-16 09:13:11 +00:00
|
|
|
else
|
|
|
|
{
|
2011-06-01 07:59:51 +00:00
|
|
|
if (PHYSFS_read(f, &Robot_joints[repl_num], sizeof(jointpos), 1) < 1)
|
2010-10-16 09:13:11 +00:00
|
|
|
{
|
2011-06-01 07:59:51 +00:00
|
|
|
PHYSFS_close(f);
|
2010-10-16 09:13:11 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2006-03-20 16:43:15 +00:00
|
|
|
}
|
|
|
|
}
|
2010-10-16 09:13:11 +00:00
|
|
|
|
|
|
|
// read polygon models
|
2011-06-01 07:59:51 +00:00
|
|
|
if ((n_items = PHYSFSX_readInt(f)) != 0)
|
2010-10-16 09:13:11 +00:00
|
|
|
{
|
|
|
|
for (i = 0; i < n_items; i++)
|
|
|
|
{
|
|
|
|
polymodel *pm;
|
|
|
|
|
2011-06-01 07:59:51 +00:00
|
|
|
repl_num = PHYSFSX_readInt(f);
|
2010-10-16 09:13:11 +00:00
|
|
|
if (repl_num >= MAX_POLYGON_MODELS)
|
|
|
|
{
|
2011-06-01 07:59:51 +00:00
|
|
|
PHYSFSX_readInt(f); // skip n_models
|
|
|
|
PHYSFSX_fseek(f, 734 - 8 + PHYSFSX_readInt(f) + 8, SEEK_CUR);
|
2010-10-16 09:13:11 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pm = &Polygon_models[repl_num];
|
2014-07-25 23:56:59 +00:00
|
|
|
polymodel_read(pm, f);
|
2014-08-16 04:15:16 +00:00
|
|
|
pm->model_data = make_unique<ubyte[]>(pm->model_data_size);
|
2011-06-01 07:59:51 +00:00
|
|
|
if (PHYSFS_read(f, pm->model_data, pm->model_data_size, 1) < 1)
|
2010-10-16 09:13:11 +00:00
|
|
|
{
|
2014-07-24 03:12:57 +00:00
|
|
|
pm->model_data.reset();
|
2011-06-01 07:59:51 +00:00
|
|
|
PHYSFS_close(f);
|
2010-10-16 09:13:11 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-06-01 07:59:51 +00:00
|
|
|
Dying_modelnums[repl_num] = PHYSFSX_readInt(f);
|
|
|
|
Dead_modelnums[repl_num] = PHYSFSX_readInt(f);
|
2010-10-16 09:13:11 +00:00
|
|
|
}
|
|
|
|
}
|
2006-03-20 16:43:15 +00:00
|
|
|
}
|
2010-10-16 09:13:11 +00:00
|
|
|
|
|
|
|
// read object bitmaps
|
2011-06-01 07:59:51 +00:00
|
|
|
if ((n_items = PHYSFSX_readInt(f)) != 0)
|
2010-10-16 09:13:11 +00:00
|
|
|
{
|
|
|
|
for (i = 0; i < n_items; i++)
|
|
|
|
{
|
2011-06-01 07:59:51 +00:00
|
|
|
repl_num = PHYSFSX_readInt(f);
|
2010-10-16 09:13:11 +00:00
|
|
|
if (repl_num >= MAX_OBJ_BITMAPS)
|
2011-06-01 07:59:51 +00:00
|
|
|
PHYSFSX_fseek(f, 2, SEEK_CUR);
|
2010-10-16 09:13:11 +00:00
|
|
|
else
|
2011-06-01 07:59:51 +00:00
|
|
|
ObjBitmaps[repl_num].index = PHYSFSX_readShort(f);
|
2010-10-16 09:13:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-01 07:59:51 +00:00
|
|
|
PHYSFS_close(f);
|
2006-03-20 16:43:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// undo customized items
|
2013-03-10 02:45:12 +00:00
|
|
|
static void custom_remove()
|
2010-10-16 09:13:11 +00:00
|
|
|
{
|
|
|
|
int i;
|
2006-03-20 16:43:15 +00:00
|
|
|
grs_bitmap *bmo = BitmapOriginal;
|
2010-10-16 09:13:11 +00:00
|
|
|
grs_bitmap *bmp = GameBitmaps;
|
2006-03-20 16:43:15 +00:00
|
|
|
|
2010-10-16 09:13:11 +00:00
|
|
|
for (i = 0; i < MAX_BITMAP_FILES; bmo++, bmp++, i++)
|
|
|
|
if (bmo->bm_flags & 0x80)
|
|
|
|
{
|
2014-11-30 22:09:20 +00:00
|
|
|
gr_free_bitmap_data(*bmp);
|
2006-03-20 16:43:15 +00:00
|
|
|
*bmp = *bmo;
|
2010-10-16 09:13:11 +00:00
|
|
|
|
|
|
|
if (bmo->bm_flags & BM_FLAG_PAGED_OUT)
|
|
|
|
{
|
|
|
|
GameBitmapOffset[i] = (int)(size_t)BitmapOriginal[i].bm_data;
|
2006-03-20 16:43:15 +00:00
|
|
|
gr_set_bitmap_flags(bmp, BM_FLAG_PAGED_OUT);
|
|
|
|
gr_set_bitmap_data(bmp, Piggy_bitmap_cache_data);
|
2010-10-16 09:13:11 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2006-03-20 16:43:15 +00:00
|
|
|
gr_set_bitmap_flags(bmp, bmo->bm_flags & 0x7f);
|
2010-10-16 09:13:11 +00:00
|
|
|
}
|
|
|
|
bmo->bm_flags = 0;
|
|
|
|
}
|
|
|
|
for (i = 0; i < MAX_SOUND_FILES; i++)
|
|
|
|
if (SoundOriginal[i].length & 0x80000000)
|
|
|
|
{
|
|
|
|
d_free(GameSounds[i].data);
|
|
|
|
GameSounds[i].data = SoundOriginal[i].data;
|
2006-03-20 16:43:15 +00:00
|
|
|
#ifdef ALLEGRO
|
2010-10-16 09:13:11 +00:00
|
|
|
GameSounds[i].len = SoundOriginal[i].length & 0x7fffffff;
|
2006-03-20 16:43:15 +00:00
|
|
|
#else
|
2010-10-16 09:13:11 +00:00
|
|
|
GameSounds[i].length = SoundOriginal[i].length & 0x7fffffff;
|
2006-03-20 16:43:15 +00:00
|
|
|
#endif
|
2010-10-16 09:13:11 +00:00
|
|
|
SoundOriginal[i].length = 0;
|
|
|
|
}
|
2006-03-20 16:43:15 +00:00
|
|
|
}
|
|
|
|
|
2014-07-23 02:27:22 +00:00
|
|
|
void load_custom_data(const d_fname &level_name)
|
2010-10-16 09:13:11 +00:00
|
|
|
{
|
|
|
|
custom_remove();
|
2014-07-23 02:27:22 +00:00
|
|
|
d_fname custom_file;
|
|
|
|
using std::copy;
|
|
|
|
using std::next;
|
|
|
|
auto bl = begin(level_name);
|
|
|
|
auto bc = begin(custom_file);
|
|
|
|
auto &pg1 = ".pg1";
|
|
|
|
copy(bl, next(bl, custom_file.size() - sizeof(pg1)), bc);
|
|
|
|
auto o = std::find(bc, next(bc, custom_file.size() - sizeof(pg1)), '.');
|
|
|
|
copy(begin(pg1), end(pg1), o);
|
2010-10-16 09:13:11 +00:00
|
|
|
load_pigpog(custom_file);
|
2014-07-23 02:27:22 +00:00
|
|
|
auto &dtx = "dtx";
|
|
|
|
++o;
|
|
|
|
copy(begin(dtx), end(dtx), o);
|
2010-10-16 09:13:11 +00:00
|
|
|
load_pigpog(custom_file);
|
2014-07-23 02:27:22 +00:00
|
|
|
auto &hx1 = "hx1";
|
|
|
|
copy(begin(hx1), end(hx1), o);
|
2010-10-16 09:13:11 +00:00
|
|
|
load_hxm(custom_file);
|
2006-03-20 16:43:15 +00:00
|
|
|
}
|
|
|
|
|
2010-10-16 09:13:11 +00:00
|
|
|
void custom_close()
|
|
|
|
{
|
|
|
|
custom_remove();
|
2006-03-20 16:43:15 +00:00
|
|
|
}
|