mirror of
https://github.com/scummvm/scummvm.git
synced 2025-04-02 10:52:32 -04:00
302 lines
6.8 KiB
C++
302 lines
6.8 KiB
C++
/* ScummVM - Graphic Adventure Engine
|
|
*
|
|
* ScummVM is the legal property of its developers, whose names
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
|
* file distributed with this source distribution.
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
#include "common/file.h"
|
|
|
|
#include "chamber/chamber.h"
|
|
#include "chamber/common.h"
|
|
#include "chamber/resdata.h"
|
|
#include "chamber/decompr.h"
|
|
|
|
namespace Chamber {
|
|
|
|
extern void askDisk2(void);
|
|
extern int16 loadSplash(const char *filename);
|
|
|
|
/*
|
|
Get bank entry
|
|
TODO: port SeekToString to this routine
|
|
*/
|
|
byte *seekToEntry(byte *bank, uint16 num, byte **end) {
|
|
byte len;
|
|
byte *p = bank;
|
|
|
|
while (num--) {
|
|
len = *p;
|
|
p += len;
|
|
}
|
|
len = *p;
|
|
*end = p + len;
|
|
return p + 1;
|
|
}
|
|
|
|
byte *seekToEntryW(byte *bank, uint16 num, byte **end) {
|
|
uint16 len;
|
|
byte *p = bank;
|
|
|
|
while (num--) {
|
|
len = p[0] | (p[1] << 8);
|
|
p += len;
|
|
}
|
|
len = p[0] | (p[1] << 8);
|
|
*end = p + len;
|
|
return p + 2;
|
|
}
|
|
|
|
uint16 loadFile(const char *filename, byte *buffer) {
|
|
Common::File in;
|
|
|
|
in.open(filename);
|
|
|
|
if (!in.isOpen())
|
|
return 0;
|
|
|
|
return in.read(buffer, 0xFFFF0);
|
|
}
|
|
|
|
uint16 saveFile(char *filename, byte *buffer, uint16 size) {
|
|
warning("STUB: SaveFile(%s, buffer, %d)", filename, size);
|
|
return 0;
|
|
#if 0
|
|
int16 f;
|
|
int16 wlen;
|
|
f = open(filename, O_RDONLY | O_BINARY);
|
|
if (f == -1)
|
|
return 0;
|
|
wlen = write(f, buffer, size);
|
|
close(f);
|
|
if (wlen == -1)
|
|
return 0;
|
|
return (uint16)wlen;
|
|
#endif
|
|
}
|
|
|
|
int16 loadFilesList(ResEntry_t *entries) {
|
|
int16 i;
|
|
for (i = 0; entries[i].name[0] != '$'; i++) {
|
|
if (!loadFile(entries[i].name, (byte *)entries[i].buffer))
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
|
|
byte *arpla_data = NULL;
|
|
byte *aleat_data = NULL;
|
|
byte *icone_data = NULL;
|
|
byte *souco_data = NULL;
|
|
byte *carpc_data = NULL;
|
|
byte *souri_data = NULL;
|
|
byte *templ_data = NULL;
|
|
byte *mursm_data = NULL;
|
|
byte *gauss_data = NULL;
|
|
byte *lutin_data = NULL;
|
|
byte *anima_data = NULL;
|
|
byte *anico_data = NULL;
|
|
byte *zones_data = NULL;
|
|
|
|
ResEntry_tp res_static[] = {
|
|
{"ARPLA.BIN", &arpla_data},
|
|
{"ALEAT.BIN", &aleat_data},
|
|
{"ICONE.BIN", &icone_data},
|
|
{"SOUCO.BIN", &souco_data},
|
|
{"CARPC.BIN", &carpc_data},
|
|
{"SOURI.BIN", &souri_data},
|
|
{"TEMPL.BIN", &templ_data},
|
|
{"MURSM.BIN", &mursm_data},
|
|
{"GAUSS.BIN", &gauss_data},
|
|
{"LUTIN.BIN", &lutin_data},
|
|
{"ANIMA.BIN", &anima_data},
|
|
{"ANICO.BIN", &anico_data},
|
|
{"ZONES.BIN", &zones_data},
|
|
{"$", NULL}
|
|
};
|
|
|
|
/*
|
|
Load resident data files. Original game has all these data files embedded in the executable.
|
|
NB! Static data includes the font file, don't use any text print routines before it's loaded.
|
|
*/
|
|
int16 loadStaticData() {
|
|
Common::File pxi;
|
|
|
|
if (g_vm->getLanguage() == Common::EN_USA)
|
|
pxi.open("kult1.pxi");
|
|
else
|
|
pxi.open("ere.pxi");
|
|
|
|
uint numMods = pxi.readUint16BE();
|
|
uint modBase = 2 + numMods * 4;
|
|
|
|
uint32 *modOffs = new uint32[numMods];
|
|
|
|
for (uint i = 0; i < numMods; i++)
|
|
modOffs[i] = modBase + pxi.readUint32BE();
|
|
|
|
// So far, take only resource 0. Additional selection is required
|
|
uint32 modOfs = modOffs[0];
|
|
pxi.seek(modOfs);
|
|
|
|
uint32 modPsize = pxi.readUint32BE();
|
|
uint32 modUsize = pxi.readUint32BE();
|
|
|
|
byte *modData = new byte[modPsize];
|
|
|
|
pxi.read(modData, modPsize);
|
|
|
|
warning("Module %d : at 0x%6X, psize = %6d, usize = %6d", 0, modOfs, modPsize, modUsize);
|
|
|
|
byte *rawData = new byte[modUsize];
|
|
g_vm->_pxiData = rawData;
|
|
|
|
uint32 rawSize = decompress(modData, rawData);
|
|
warning("decoded to %d bytes", rawSize);
|
|
|
|
delete[] modData;
|
|
|
|
if (rawData[0] != 'M' || rawData[1] != 'Z')
|
|
error("Module decompressed, but is not an EXE file");
|
|
|
|
uint16 hdrparas = READ_LE_UINT16(rawData + 8);
|
|
uint32 off = hdrparas * 16;
|
|
|
|
warning("hdrparas: 0x%x, off: 0x%x", hdrparas, off);
|
|
|
|
const char *firstRes = "ARPLA.";
|
|
int32 resOffs = -1;
|
|
|
|
for (uint i = off; i < rawSize; i++)
|
|
if (!strncmp((char *)rawData + i, firstRes, strlen(firstRes))) {
|
|
resOffs = i;
|
|
break;
|
|
}
|
|
|
|
if (resOffs == -1)
|
|
error("No internal resources table found");
|
|
|
|
warning("Found resources table at 0x%X", resOffs - off);
|
|
|
|
while (rawData[resOffs] != '$') {
|
|
Common::String resName((char *)rawData + resOffs);
|
|
|
|
resOffs += MAX(resName.size() + 1, 10U); // work around malformed resource entry in the US release
|
|
|
|
uint16 reso = READ_LE_UINT16(rawData + resOffs);
|
|
resOffs += 2;
|
|
uint16 ress = READ_LE_UINT16(rawData + resOffs);
|
|
resOffs += 2;
|
|
|
|
warning("%s : %X", resName.c_str(), ress * 16 + reso);
|
|
|
|
int i;
|
|
for (i = 0; res_static[i].name[0] != '$'; i++) { // Yeah, linear search
|
|
if (!strcmp(res_static[i].name, resName.c_str())) {
|
|
*res_static[i].buffer = rawData + off + ress * 16 + reso;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (res_static[i].name[0] == '$')
|
|
warning("loadStaticData(): Extra resource %s", resName.c_str());
|
|
}
|
|
|
|
// And now check that everything was loaded
|
|
bool missing = false;
|
|
for (int i = 0; res_static[i].name[0] != '$'; i++) {
|
|
if (*res_static[i].buffer == NULL) {
|
|
warning("loadStaticData(): Resource %s is not present", res_static[i].name);
|
|
missing = true;
|
|
}
|
|
}
|
|
|
|
delete[] modOffs;
|
|
|
|
return !missing;
|
|
}
|
|
|
|
ResEntry_t res_texts[] = {
|
|
{"VEPCI.BIN", vepci_data},
|
|
{"MOTSI.BIN", motsi_data},
|
|
{"$", NULL}
|
|
};
|
|
|
|
/*
|
|
Load strings data (commands/names)
|
|
*/
|
|
int16 loadVepciData() {
|
|
return loadFilesList(res_texts);
|
|
}
|
|
|
|
int16 loadFond(void) {
|
|
return loadSplash("FOND.BIN");
|
|
}
|
|
|
|
ResEntry_t res_sprites[] = {
|
|
{"PUZZL.BIN", puzzl_data},
|
|
{"SPRIT.BIN", sprit_data},
|
|
{"$", NULL}
|
|
};
|
|
|
|
int16 loadSpritesData(void) {
|
|
return loadFilesList(res_sprites);
|
|
}
|
|
|
|
ResEntry_t res_person[] = {
|
|
{"PERS1.BIN", pers1_data},
|
|
{"PERS2.BIN", pers2_data},
|
|
{"$", NULL}
|
|
};
|
|
|
|
int16 loadPersData(void) {
|
|
/*Originally it tries to load pers1 + pers2 as a single contiguos resource, if have enough memory*/
|
|
/*If memory is low, necessary file is loaded on demand, according to requested bank resource index*/
|
|
/*Here we load both parts to their own memory buffers then select one in LoadPersSprit()*/
|
|
return loadFilesList(res_person);
|
|
}
|
|
|
|
ResEntry_t res_desci[] = {
|
|
{"DESCI.BIN", desci_data},
|
|
{"$", NULL}
|
|
};
|
|
|
|
/*
|
|
Load strings data (obj. descriptions)
|
|
*/
|
|
int16 loadDesciData(void) {
|
|
while (!loadFilesList(res_desci))
|
|
askDisk2();
|
|
return 1;
|
|
}
|
|
|
|
ResEntry_t res_diali[] = {
|
|
{"DIALI.BIN", diali_data},
|
|
{"$", NULL}
|
|
};
|
|
|
|
/*
|
|
Load strings data (dialogs)
|
|
*/
|
|
int16 loadDialiData(void) {
|
|
while (!loadFilesList(res_diali))
|
|
askDisk2();
|
|
return 1;
|
|
}
|
|
|
|
} // End of namespace Chamber
|