From 67869d2c10234479949bd74abc42931a019264e6 Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Fri, 27 Jul 2007 19:02:19 +0000 Subject: - Moved disk code for Nippon Safes in new file disk_ns.cpp, adding _ns suffix to classes and member functions. - Added function stubs into new file disk_br.cpp for Big Red Adventure [IT STILL CRASHES!]. - Modified engine to create the proper Disk manager object. svn-id: r28246 --- engines/parallaction/disk.cpp | 1441 -------------------------------- engines/parallaction/disk.h | 118 ++- engines/parallaction/disk_br.cpp | 134 +++ engines/parallaction/disk_ns.cpp | 1443 +++++++++++++++++++++++++++++++++ engines/parallaction/font.cpp | 4 +- engines/parallaction/module.mk | 3 +- engines/parallaction/parallaction.cpp | 27 +- engines/parallaction/walk.cpp | 2 +- 8 files changed, 1674 insertions(+), 1498 deletions(-) delete mode 100644 engines/parallaction/disk.cpp create mode 100644 engines/parallaction/disk_br.cpp create mode 100644 engines/parallaction/disk_ns.cpp (limited to 'engines/parallaction') diff --git a/engines/parallaction/disk.cpp b/engines/parallaction/disk.cpp deleted file mode 100644 index c972827dc6..0000000000 --- a/engines/parallaction/disk.cpp +++ /dev/null @@ -1,1441 +0,0 @@ -/* 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 2 - * 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, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -#include "common/stdafx.h" - -#include "graphics/iff.h" -#include "graphics/surface.h" - -#include "parallaction/parallaction.h" - - -namespace Audio { - AudioStream *make8SVXStream(Common::ReadStream &input); -} - -namespace Parallaction { - - -// HACK: Several archives ('de', 'en', 'fr' and 'disk0') in the multi-lingual -// Amiga version of Nippon Safes, and one archive ('fr') in the Amiga Demo of -// Nippon Safes used different internal offsets than all the other archives. -// -// When an archive is opened in the Amiga demo, its size is checked against -// SIZEOF_SMALL_ARCHIVE to detect when the smaller archive is used. -// -// When an archive is opened in Amiga multi-lingual version, the header is -// checked again NDOS to detect when a smaller archive is used. -// -#define SIZEOF_SMALL_ARCHIVE 12778 - -#define ARCHIVE_FILENAMES_OFS 0x16 - -#define NORMAL_ARCHIVE_FILES_NUM 384 -#define SMALL_ARCHIVE_FILES_NUM 180 - -#define NORMAL_ARCHIVE_SIZES_OFS 0x3016 -#define SMALL_ARCHIVE_SIZES_OFS 0x1696 - -#define NORMAL_ARCHIVE_DATA_OFS 0x4000 -#define SMALL_ARCHIVE_DATA_OFS 0x1966 - -Archive::Archive() { - resetArchivedFile(); -} - -void Archive::open(const char *file) { - debugC(1, kDebugDisk, "Archive::open(%s)", file); - - if (_archive.isOpen()) - close(); - - char path[PATH_LEN]; - - strcpy(path, file); - if (!_archive.open(path)) - error("archive '%s' not found", path); - - _archiveName = file; - - bool isSmallArchive = false; - if (_vm->getPlatform() == Common::kPlatformAmiga) { - if (_vm->getFeatures() & GF_DEMO) { - isSmallArchive = _archive.size() == SIZEOF_SMALL_ARCHIVE; - } else if (_vm->getFeatures() & GF_LANG_MULT) { - isSmallArchive = (_archive.readUint32BE() != MKID_BE('NDOS')); - } - } - - _numFiles = (isSmallArchive) ? SMALL_ARCHIVE_FILES_NUM : NORMAL_ARCHIVE_FILES_NUM; - - _archive.seek(ARCHIVE_FILENAMES_OFS); - _archive.read(_archiveDir, _numFiles*32); - - _archive.seek((isSmallArchive) ? SMALL_ARCHIVE_SIZES_OFS : NORMAL_ARCHIVE_SIZES_OFS); - - uint32 dataOffset = (isSmallArchive) ? SMALL_ARCHIVE_DATA_OFS : NORMAL_ARCHIVE_DATA_OFS; - for (uint16 i = 0; i < _numFiles; i++) { - _archiveOffsets[i] = dataOffset; - _archiveLenghts[i] = _archive.readUint32BE(); - dataOffset += _archiveLenghts[i]; - } - - return; -} - - -void Archive::close() { - if (!_archive.isOpen()) return; - - resetArchivedFile(); - - _archive.close(); - _archiveName.clear(); -} - -Common::String Archive::name() const { - return _archiveName; -} - -bool Archive::openArchivedFile(const char *filename) { - debugC(3, kDebugDisk, "Archive::openArchivedFile(%s)", filename); - - resetArchivedFile(); - - debugC(3, kDebugDisk, "Archive::openArchivedFile(%s)", filename); - - if (!_archive.isOpen()) - error("Archive::openArchivedFile: the archive is not open"); - - uint16 i = 0; - for ( ; i < _numFiles; i++) { - if (!scumm_stricmp(_archiveDir[i], filename)) break; - } - if (i == _numFiles) return false; - - debugC(9, kDebugDisk, "Archive::openArchivedFile: '%s' found in slot %i", filename, i); - - _file = true; - - _fileOffset = _archiveOffsets[i]; - _fileCursor = _archiveOffsets[i]; - _fileEndOffset = _archiveOffsets[i] + _archiveLenghts[i]; - - _archive.seek(_fileOffset); - - return true; -} - -void Archive::resetArchivedFile() { - _file = false; - _fileCursor = 0; - _fileOffset = 0; - _fileEndOffset = 0; -} - -void Archive::closeArchivedFile() { - resetArchivedFile(); -} - - -uint32 Archive::size() const { - return (_file == true ? _fileEndOffset - _fileOffset : 0); -} - -uint32 Archive::pos() const { - return (_file == true ? _fileCursor - _fileOffset : 0 ); -} - -bool Archive::eos() const { - return (_file == true ? _fileCursor == _fileEndOffset : true ); -} - -void Archive::seek(int32 offs, int whence) { - assert(_file == true && _fileCursor <= _fileEndOffset); - - switch (whence) { - case SEEK_CUR: - _fileCursor += offs; - break; - case SEEK_SET: - _fileCursor = _fileOffset + offs; - break; - case SEEK_END: - _fileCursor = _fileEndOffset - offs; - break; - } - assert(_fileCursor <= _fileEndOffset && _fileCursor >= _fileOffset); - - _archive.seek(_fileCursor, SEEK_SET); -} - -uint32 Archive::read(void *dataPtr, uint32 dataSize) { -// printf("read(%i, %i)\n", file->_cursor, file->_endOffset); - if (_file == false) - error("Archive::read: no archived file is currently open"); - - if (_fileCursor >= _fileEndOffset) - error("can't read beyond end of archived file"); - - if (_fileEndOffset - _fileCursor < dataSize) - dataSize = _fileEndOffset - _fileCursor; - - int32 readBytes = _archive.read(dataPtr, dataSize); - _fileCursor += readBytes; - - return readBytes; -} - - - - - -/* - This stream class is just a wrapper around Archive, so - deallocation is not a problem. In fact, this class doesn't - delete its input (Archive) stream. -*/ -class DummyArchiveStream : public Common::SeekableReadStream { - - Archive *_input; - -public: - DummyArchiveStream(Archive &input) : _input(&input) { - - } - - ~DummyArchiveStream() { - // this class exists to provide this empty destructor - } - - bool eos() const { - return _input->eos(); - } - - uint32 read(void* data, uint32 dataSize) { - return _input->read(data, dataSize); - } - - uint32 pos() const { - return _input->pos(); - } - - uint32 size() const { - return _input->size(); - } - - void seek(int32 offset, int whence) { - _input->seek(offset, whence); - } - -}; - - - -Disk::Disk(Parallaction *vm) : _vm(vm) { - -} - -Disk::~Disk() { - -} - -void Disk::errorFileNotFound(const char *s) { - error("File '%s' not found", s); -} - - -Common::String Disk::selectArchive(const Common::String& name) { - Common::String oldName = _resArchive.name(); - _resArchive.open(name.c_str()); - return oldName; -} - -void Disk::setLanguage(uint16 language) { - debugC(1, kDebugDisk, "setLanguage(%i)", language); - - switch (language) { - case 0: - strcpy(_languageDir, "it/"); - break; - - case 1: - strcpy(_languageDir, "fr/"); - break; - - case 2: - strcpy(_languageDir, "en/"); - break; - - case 3: - strcpy(_languageDir, "ge/"); - break; - - default: - error("unknown language"); - - } - - _languageDir[2] = '\0'; - _locArchive.open(_languageDir); - _languageDir[2] = '/'; - - return; -} - -#pragma mark - - - - -DosDisk::DosDisk(Parallaction* vm) : Disk(vm) { - -} - -DosDisk::~DosDisk() { -} - - -// -// loads a cnv from an external file -// -Cnv* DosDisk::loadExternalCnv(const char *filename) { -// printf("Gfx::loadExternalCnv(%s)...", filename); - - char path[PATH_LEN]; - - sprintf(path, "%s.cnv", filename); - - Common::File stream; - - if (!stream.open(path)) - errorFileNotFound(path); - - uint16 numFrames = stream.readByte(); - uint16 width = stream.readByte(); - uint16 height = stream.readByte(); - - uint32 decsize = numFrames * width * height; - byte *data = (byte*)malloc(decsize); - stream.read(data, decsize); - - return new Cnv(numFrames, width, height, data); -} - -StaticCnv *DosDisk::loadExternalStaticCnv(const char *filename) { - - char path[PATH_LEN]; - - sprintf(path, "%s.cnv", filename); - - Common::File stream; - - if (!stream.open(path)) - errorFileNotFound(path); - - StaticCnv *cnv = new StaticCnv; - - stream.skip(1); - cnv->_width = stream.readByte(); - cnv->_height = stream.readByte(); - - uint16 size = cnv->_width*cnv->_height; - - cnv->_data0 = (byte*)malloc(size); - stream.read(cnv->_data0, size); - - return cnv; -} - -Cnv* DosDisk::loadCnv(const char *filename) { -// printf("Gfx::loadCnv(%s)\n", filename); - - char path[PATH_LEN]; - - strcpy(path, filename); - if (!_resArchive.openArchivedFile(path)) { - sprintf(path, "%s.pp", filename); - if (!_resArchive.openArchivedFile(path)) - errorFileNotFound(path); - } - - uint16 numFrames = _resArchive.readByte(); - uint16 width = _resArchive.readByte(); - uint16 height = _resArchive.readByte(); - - uint32 decsize = numFrames * width * height; - byte *data = (byte*)malloc(decsize); - - Graphics::PackBitsReadStream decoder(_resArchive); - decoder.read(data, decsize); - - return new Cnv(numFrames, width, height, data); -} - -Cnv* DosDisk::loadTalk(const char *name) { - - const char *ext = strstr(name, ".talk"); - if (ext != NULL) { - // npc talk - return loadCnv(name); - - } - - // character talk - char v20[PATH_LEN]; - char *v24 = const_cast(name); - if (IS_MINI_CHARACTER(v24)) { - v24+=4; - } - - if (_engineFlags & kEngineTransformedDonna) { - sprintf(v20, "%stta", v24); - } else { - sprintf(v20, "%stal", v24); - } - - return loadExternalCnv(v20); -} - -Script* DosDisk::loadLocation(const char *name) { - - char archivefile[PATH_LEN]; - - if (IS_MINI_CHARACTER(_vm->_characterName)) { - sprintf(archivefile, "%s%s", _vm->_characterName+4, _languageDir); - } else { - if (IS_DUMMY_CHARACTER(_vm->_characterName)) { - strcpy(archivefile, _languageDir); - } else { - sprintf(archivefile, "%s%s", _vm->_characterName, _languageDir); - } - } - - strcat(archivefile, name); - strcat(archivefile, ".loc"); - - debugC(3, kDebugDisk, "DosDisk::loadLocation(%s): trying '%s'", name, archivefile); - - if (!_locArchive.openArchivedFile(archivefile)) { - sprintf(archivefile, "%s%s.loc", _languageDir, name); - debugC(3, kDebugDisk, "DosDisk::loadLocation(%s): trying '%s'", name, archivefile); - - if (!_locArchive.openArchivedFile(archivefile)) - errorFileNotFound(name); - } - - return new Script(new DummyArchiveStream(_locArchive), true); -} - -Script* DosDisk::loadScript(const char* name) { - - char vC8[PATH_LEN]; - - sprintf(vC8, "%s.script", name); - - if (!_resArchive.openArchivedFile(vC8)) - errorFileNotFound(vC8); - - return new Script(new DummyArchiveStream(_resArchive), true); -} - -StaticCnv* DosDisk::loadHead(const char* name) { - - char path[PATH_LEN]; - - if (IS_MINI_CHARACTER(name)) { - name += 4; - } - - sprintf(path, "%shead", name); - path[8] = '\0'; - - return loadExternalStaticCnv(path); -} - - -StaticCnv* DosDisk::loadPointer() { - return loadExternalStaticCnv("pointer"); -} - - -Font* DosDisk::loadFont(const char* name) { - char path[PATH_LEN]; - sprintf(path, "%scnv", name); - return createFont(name, loadExternalCnv(path)); -} - - -Cnv* DosDisk::loadObjects(const char *name) { - - if (IS_MINI_CHARACTER(name)) { - name += 4; - } - - char path[PATH_LEN]; - sprintf(path, "%sobj", name); - return loadExternalCnv(path); -} - - -StaticCnv* DosDisk::loadStatic(const char* name) { - - char path[PATH_LEN]; - - strcpy(path, name); - if (!_resArchive.openArchivedFile(path)) { - sprintf(path, "%s.pp", name); - if (!_resArchive.openArchivedFile(path)) - errorFileNotFound(path); - } - - StaticCnv* cnv = new StaticCnv; - - _resArchive.skip(1); - cnv->_width = _resArchive.readByte(); - cnv->_height = _resArchive.readByte(); - - uint16 size = cnv->_width*cnv->_height; - cnv->_data0 = (byte*)malloc(size); - - Graphics::PackBitsReadStream decoder(_resArchive); - decoder.read(cnv->_data0, size); - - return cnv; -} - -Cnv* DosDisk::loadFrames(const char* name) { - return loadCnv(name); -} - -// -// slides (background images) are stored compressed by scanline in a rle fashion -// -// the uncompressed data must then be unpacked to get: -// * color data [bits 0-5] -// * mask data [bits 6-7] (z buffer) -// * path data [bit 8] (walkable areas) -// -void DosDisk::unpackBackground(Common::ReadStream *stream, byte *screen, byte *mask, byte *path) { - - byte b; - uint32 i = 0; - - while (!stream->eos()) { - b = stream->readByte(); - - path[i/8] |= ((b & 0x80) >> 7) << (i & 7); - mask[i/4] |= ((b & 0x60) >> 5) << ((i & 3) << 1); - screen[i] = b & 0x1F; - i++; - } - - return; -} - - -void DosDisk::parseDepths(Common::SeekableReadStream &stream) { - _vm->_gfx->_bgLayers[0] = stream.readByte(); - _vm->_gfx->_bgLayers[1] = stream.readByte(); - _vm->_gfx->_bgLayers[2] = stream.readByte(); - _vm->_gfx->_bgLayers[3] = stream.readByte(); -} - - -void DosDisk::parseBackground(Common::SeekableReadStream &stream) { - - stream.read(_vm->_gfx->_palette, BASE_PALETTE_SIZE); - _vm->_gfx->setPalette(_vm->_gfx->_palette); - - parseDepths(stream); - - for (uint32 _si = 0; _si < 6; _si++) { - _vm->_gfx->_palettefx[_si]._timer = stream.readUint16BE(); - _vm->_gfx->_palettefx[_si]._step = stream.readUint16BE(); - _vm->_gfx->_palettefx[_si]._flags = stream.readUint16BE(); - _vm->_gfx->_palettefx[_si]._first = stream.readByte(); - _vm->_gfx->_palettefx[_si]._last = stream.readByte(); - } - -} - -void DosDisk::loadBackground(const char *filename) { - - if (!_resArchive.openArchivedFile(filename)) - errorFileNotFound(filename); - - parseBackground(_resArchive); - - byte *bg = (byte*)calloc(1, _vm->_screenSize); - byte *mask = (byte*)calloc(1, _vm->_screenMaskSize); - byte *path = (byte*)calloc(1, _vm->_screenPathSize); - - - Graphics::PackBitsReadStream stream(_resArchive); - unpackBackground(&stream, bg, mask, path); - - _vm->_gfx->setBackground(bg); - _vm->_gfx->setMask(mask); - _vm->setPath(path); - - free(bg); - free(mask); - free(path); - - return; -} - -// -// read background path and mask from a file -// -// mask and path are normally combined (via OR) into the background picture itself -// read the comment on the top of this file for more -// -void DosDisk::loadMaskAndPath(const char *name) { - char path[PATH_LEN]; - sprintf(path, "%s.msk", name); - - if (!_resArchive.openArchivedFile(path)) - errorFileNotFound(name); - - byte *maskBuf = (byte*)calloc(1, _vm->_screenMaskSize); - byte *pathBuf = (byte*)calloc(1, _vm->_screenPathSize); - - parseDepths(_resArchive); - - _resArchive.read(pathBuf, _vm->_screenPathSize); - _resArchive.read(maskBuf, _vm->_screenMaskSize); - - _vm->_gfx->setMask(maskBuf); - _vm->setPath(pathBuf); - - return; -} - -void DosDisk::loadSlide(const char *filename) { - char path[PATH_LEN]; - sprintf(path, "%s.slide", filename); - loadBackground(path); -} - -void DosDisk::loadScenery(const char *name, const char *mask) { - char path[PATH_LEN]; - sprintf(path, "%s.dyn", name); - loadBackground(path); - - if (mask != NULL) { - // load external masks and paths only for certain locations - loadMaskAndPath(mask); - } - -} - -Table* DosDisk::loadTable(const char* name) { - char path[PATH_LEN]; - sprintf(path, "%s.tab", name); - - Common::File stream; - if (!stream.open(path)) - errorFileNotFound(path); - - Table *t = new Table(100); - - fillBuffers(stream); - while (scumm_stricmp(_tokens[0], "ENDTABLE")) { - t->addData(_tokens[0]); - fillBuffers(stream); - } - - stream.close(); - - return t; -} - -Common::ReadStream* DosDisk::loadMusic(const char* name) { - char path[PATH_LEN]; - sprintf(path, "%s.mid", name); - - Common::File *stream = new Common::File; - if (!stream->open(path)) - errorFileNotFound(path); - - return stream; -} - - -Common::ReadStream* DosDisk::loadSound(const char* name) { - return NULL; -} - - - - - - -#pragma mark - - - -/* the decoder presented here is taken from pplib by Stuart Caie. The - * following statement comes from the original source. - * - * pplib 1.0: a simple PowerPacker decompression and decryption library - * placed in the Public Domain on 2003-09-18 by Stuart Caie. - */ - -#define PP_READ_BITS(nbits, var) do { \ - bit_cnt = (nbits); (var) = 0; \ - while (bits_left < bit_cnt) { \ - if (buf < src) return 0; \ - bit_buffer |= *--buf << bits_left; \ - bits_left += 8; \ - } \ - bits_left -= bit_cnt; \ - while (bit_cnt--) { \ - (var) = ((var) << 1) | (bit_buffer & 1); \ - bit_buffer >>= 1; \ - } \ -} while (0) - -#define PP_BYTE_OUT(byte) do { \ - if (out <= dest) return 0; \ - *--out = (byte); written++; \ -} while (0) - - -class PowerPackerStream : public Common::SeekableReadStream { - - SeekableReadStream *_stream; - bool _dispose; - -private: - int ppDecrunchBuffer(byte *src, byte *dest, uint32 src_len, uint32 dest_len) { - - byte *buf, *out, *dest_end, *off_lens, bits_left = 0, bit_cnt; - uint32 bit_buffer = 0, x, todo, offbits, offset, written = 0; - - if (src == NULL || dest == NULL) return 0; - - /* set up input and output pointers */ - off_lens = src; src = &src[4]; - buf = &src[src_len]; - - out = dest_end = &dest[dest_len]; - - /* skip the first few bits */ - PP_READ_BITS(src[src_len + 3], x); - - /* while there are input bits left */ - while (written < dest_len) { - PP_READ_BITS(1, x); - if (x == 0) { - /* bit==0: literal, then match. bit==1: just match */ - todo = 1; do { PP_READ_BITS(2, x); todo += x; } while (x == 3); - while (todo--) { PP_READ_BITS(8, x); PP_BYTE_OUT(x); } - - /* should we end decoding on a literal, break out of the main loop */ - if (written == dest_len) break; - } - - /* match: read 2 bits for initial offset bitlength / match length */ - PP_READ_BITS(2, x); - offbits = off_lens[x]; - todo = x+2; - if (x == 3) { - PP_READ_BITS(1, x); - if (x == 0) offbits = 7; - PP_READ_BITS(offbits, offset); - do { PP_READ_BITS(3, x); todo += x; } while (x == 7); - } - else { - PP_READ_BITS(offbits, offset); - } - if (&out[offset] >= dest_end) return 0; /* match_overflow */ - while (todo--) { x = out[offset]; PP_BYTE_OUT(x); } - } - - /* all output bytes written without error */ - return 1; - } - - uint16 getCrunchType(uint32 signature) { - - byte eff; - - switch (signature) { - case 0x50503230: /* PP20 */ - eff = 4; - break; - case 0x50504C53: /* PPLS */ - error("PPLS crunched files are not supported"); - eff = 8; - break; - case 0x50583230: /* PX20 */ - error("PX20 crunched files are not supported"); - eff = 6; - break; - default: - eff = 0; - - } - - return eff; - } - -public: - PowerPackerStream(Common::SeekableReadStream &stream) { - - _dispose = false; - - uint32 signature = stream.readUint32BE(); - if (getCrunchType(signature) == 0) { - stream.seek(0, SEEK_SET); - _stream = &stream; - return; - } - - stream.seek(4, SEEK_END); - uint32 decrlen = stream.readUint32BE() >> 8; - byte *dest = (byte*)malloc(decrlen); - - uint32 crlen = stream.size() - 4; - byte *src = (byte*)malloc(crlen); - stream.seek(4, SEEK_SET); - stream.read(src, crlen); - - ppDecrunchBuffer(src, dest, crlen-8, decrlen); - - free(src); - _stream = new Common::MemoryReadStream(dest, decrlen, true); - _dispose = true; - } - - ~PowerPackerStream() { - if (_dispose) delete _stream; - } - - uint32 size() const { - return _stream->size(); - } - - uint32 pos() const { - return _stream->pos(); - } - - bool eos() const { - return _stream->eos(); - } - - void seek(int32 offs, int whence = SEEK_SET) { - _stream->seek(offs, whence); - } - - uint32 read(void *dataPtr, uint32 dataSize) { - return _stream->read(dataPtr, dataSize); - } -}; - - - - - -AmigaDisk::AmigaDisk(Parallaction *vm) : Disk(vm) { - -} - - -AmigaDisk::~AmigaDisk() { - -} - -#define NUM_PLANES 5 - -/* - unpackFrame transforms images from 5-bitplanes format to - 8-bit color-index mode -*/ -void AmigaDisk::unpackFrame(byte *dst, byte *src, uint16 planeSize) { - - byte s0, s1, s2, s3, s4, mask, t0, t1, t2, t3, t4; - - for (uint32 j = 0; j < planeSize; j++) { - s0 = src[j]; - s1 = src[j+planeSize]; - s2 = src[j+planeSize*2]; - s3 = src[j+planeSize*3]; - s4 = src[j+planeSize*4]; - - for (uint32 k = 0; k < 8; k++) { - mask = 1 << (7 - k); - t0 = (s0 & mask ? 1 << 0 : 0); - t1 = (s1 & mask ? 1 << 1 : 0); - t2 = (s2 & mask ? 1 << 2 : 0); - t3 = (s3 & mask ? 1 << 3 : 0); - t4 = (s4 & mask ? 1 << 4 : 0); - *dst++ = t0 | t1 | t2 | t3 | t4; - } - - } - -} - -/* - patchFrame applies DLTA data (dlta) to specified buffer (dst) -*/ -void AmigaDisk::patchFrame(byte *dst, byte *dlta, uint16 bytesPerPlane, uint16 height) { - - uint32 *dataIndex = (uint32*)dlta; - uint32 *ofslenIndex = (uint32*)dlta + 8; - - uint16 *base = (uint16*)dlta; - uint16 wordsPerLine = bytesPerPlane >> 1; - - for (uint j = 0; j < NUM_PLANES; j++) { - uint16 *dst16 = (uint16*)(dst + j * bytesPerPlane * height); - - uint16 *data = base + READ_BE_UINT32(dataIndex); - dataIndex++; - uint16 *ofslen = base + READ_BE_UINT32(ofslenIndex); - ofslenIndex++; - - while (*ofslen != 0xFFFF) { - - uint16 ofs = READ_BE_UINT16(ofslen); - ofslen++; - uint16 size = READ_BE_UINT16(ofslen); - ofslen++; - - while (size > 0) { - dst16[ofs] ^= *data++; - ofs += wordsPerLine; - size--; - } - - } - - } - -} - -// FIXME: no mask is loaded -void AmigaDisk::unpackBitmap(byte *dst, byte *src, uint16 numFrames, uint16 bytesPerPlane, uint16 height) { - - byte *baseFrame = src; - byte *tempBuffer = 0; - - uint16 planeSize = bytesPerPlane * height; - - for (uint32 i = 0; i < numFrames; i++) { - if (READ_BE_UINT32(src) == MKID_BE('DLTA')) { - - uint size = READ_BE_UINT32(src + 4); - - if (tempBuffer == 0) - tempBuffer = (byte*)malloc(planeSize * NUM_PLANES); - - memcpy(tempBuffer, baseFrame, planeSize * NUM_PLANES); - - patchFrame(tempBuffer, src + 8, bytesPerPlane, height); - unpackFrame(dst, tempBuffer, planeSize); - - src += (size + 8); - dst += planeSize * 8; - } else { - unpackFrame(dst, src, planeSize); - src += planeSize * NUM_PLANES; - dst += planeSize * 8; - } - } - - if (tempBuffer) - free(tempBuffer); - -} - -StaticCnv* AmigaDisk::makeStaticCnv(Common::SeekableReadStream &stream) { - - stream.skip(1); - uint16 width = stream.readByte(); - uint16 height = stream.readByte(); - - assert((width & 7) == 0); - - byte bytesPerPlane = width / 8; - - uint32 rawsize = bytesPerPlane * NUM_PLANES * height; - byte *buf = (byte*)malloc(rawsize); - stream.read(buf, rawsize); - - uint32 decsize = width * height; - byte *data = (byte*)calloc(decsize, 1); - - unpackBitmap(data, buf, 1, bytesPerPlane, height); - - free(buf); - - StaticCnv *cnv = new StaticCnv(); - cnv->_width = width; - cnv->_height = height; - cnv->_data0 = data; - cnv->_data1 = NULL; - - return cnv; -} - -Cnv* AmigaDisk::makeCnv(Common::SeekableReadStream &stream) { - - uint16 numFrames = stream.readByte(); - uint16 width = stream.readByte(); - uint16 height = stream.readByte(); - - assert((width & 7) == 0); - - byte bytesPerPlane = width / 8; - - uint32 rawsize = numFrames * bytesPerPlane * NUM_PLANES * height; - byte *buf = (byte*)malloc(rawsize); - stream.read(buf, rawsize); - - uint32 decsize = numFrames * width * height; - byte *data = (byte*)calloc(decsize, 1); - - unpackBitmap(data, buf, numFrames, bytesPerPlane, height); - - free(buf); - - return new Cnv(numFrames, width, height, data); -} -#undef NUM_PLANES - -Script* AmigaDisk::loadLocation(const char *name) { - debugC(1, kDebugDisk, "AmigaDisk()::loadLocation '%s'", name); - - char path[PATH_LEN]; - if (IS_MINI_CHARACTER(_vm->_characterName)) { - sprintf(path, "%s%s%s.loc.pp", _vm->_characterName+4, _languageDir, name); - } else - sprintf(path, "%s%s%s.loc.pp", _vm->_characterName, _languageDir, name); - - if (!_locArchive.openArchivedFile(path)) { - sprintf(path, "%s%s.loc.pp", _languageDir, name); - if (!_locArchive.openArchivedFile(path)) { - errorFileNotFound(name); - } - } - - debugC(3, kDebugDisk, "location file found: %s", path); - - return new Script(new PowerPackerStream(_locArchive), true); -} - -Script* AmigaDisk::loadScript(const char* name) { - debugC(1, kDebugDisk, "AmigaDisk::loadScript '%s'", name); - - char vC8[PATH_LEN]; - - sprintf(vC8, "%s.script", name); - - if (!_resArchive.openArchivedFile(vC8)) - errorFileNotFound(vC8); - - return new Script(new DummyArchiveStream(_resArchive), true); -} - -StaticCnv* AmigaDisk::loadPointer() { - debugC(1, kDebugDisk, "AmigaDisk::loadPointer"); - - Common::File stream; - if (!stream.open("pointer")) - errorFileNotFound("pointer"); - - return makeStaticCnv(stream); -} - -StaticCnv* AmigaDisk::loadStatic(const char* name) { - debugC(1, kDebugDisk, "AmigaDisk::loadStatic '%s'", name); - - Common::SeekableReadStream *s = openArchivedFile(name, true); - StaticCnv *cnv = makeStaticCnv(*s); - - delete s; - - return cnv; -} - -Common::SeekableReadStream *AmigaDisk::openArchivedFile(const char* name, bool errorOnFileNotFound) { - debugC(3, kDebugDisk, "AmigaDisk::openArchivedFile(%s)", name); - - if (_resArchive.openArchivedFile(name)) { - return new DummyArchiveStream(_resArchive); - } - - char path[PATH_LEN]; - - sprintf(path, "%s.pp", name); - if (_resArchive.openArchivedFile(path)) { - return new PowerPackerStream(_resArchive); - } - - sprintf(path, "%s.dd", name); - if (_resArchive.openArchivedFile(path)) { - return new PowerPackerStream(_resArchive); - } - - if (errorOnFileNotFound) - errorFileNotFound(name); - - return NULL; -} - -/* - FIXME: mask values are not computed correctly for level 1 and 2 - - NOTE: this routine is only able to build masks for Nippon Safes, since mask widths are hardcoded - into the main loop. -*/ -void buildMask(byte* buf) { - - byte mask1[16] = { 0, 0x80, 0x20, 0xA0, 8, 0x88, 0x28, 0xA8, 2, 0x82, 0x22, 0xA2, 0xA, 0x8A, 0x2A, 0xAA }; - byte mask0[16] = { 0, 0x40, 0x10, 0x50, 4, 0x44, 0x14, 0x54, 1, 0x41, 0x11, 0x51, 0x5, 0x45, 0x15, 0x55 }; - - byte plane0[40]; - byte plane1[40]; - - for (int32 i = 0; i < _vm->_screenHeight; i++) { - - memcpy(plane0, buf, 40); - memcpy(plane1, buf+40, 40); - - for (uint32 j = 0; j < 40; j++) { - *buf++ = mask0[(plane0[j] & 0xF0) >> 4] | mask1[(plane1[j] & 0xF0) >> 4]; - *buf++ = mask0[plane0[j] & 0xF] | mask1[plane1[j] & 0xF]; - } - - } -} - -class BackgroundDecoder : public Graphics::ILBMDecoder { - - PaletteFxRange *_range; - uint32 _i; - -protected: - void readCRNG(Common::IFFChunk &chunk) { - _range[_i]._timer = chunk.readUint16BE(); - _range[_i]._step = chunk.readUint16BE(); - _range[_i]._flags = chunk.readUint16BE(); - _range[_i]._first = chunk.readByte(); - _range[_i]._last = chunk.readByte(); - - _i++; - } - -public: - BackgroundDecoder(Common::ReadStream &input, Graphics::Surface &surface, byte *&colors, PaletteFxRange *range) : - Graphics::ILBMDecoder(input, surface, colors), _range(range), _i(0) { - } - - void decode() { - Common::IFFChunk *chunk; - while ((chunk = nextChunk()) != 0) { - switch (chunk->id) { - case ID_BMHD: - readBMHD(*chunk); - break; - - case ID_CMAP: - readCMAP(*chunk); - break; - - case ID_BODY: - readBODY(*chunk); - break; - - case ID_CRNG: - readCRNG(*chunk); - break; - } - } - } - - uint32 getNumRanges() { - return _i; - } -}; - - -void AmigaDisk::loadBackground(const char *name) { - - Common::SeekableReadStream *s = openArchivedFile(name, true); - - Graphics::Surface surf; - byte *pal; - BackgroundDecoder decoder(*s, surf, pal, _vm->_gfx->_palettefx); - decoder.decode(); - - for (uint32 i = 0; i < BASE_PALETTE_COLORS * 3; i++) - _vm->_gfx->_palette[i] = pal[i] >> 2; - free(pal); - _vm->_gfx->setPalette(_vm->_gfx->_palette); - _vm->_gfx->setBackground(static_cast(surf.pixels)); - surf.free(); - delete s; - - return; - -} - -void AmigaDisk::loadMask(const char *name) { - - char path[PATH_LEN]; - sprintf(path, "%s.mask", name); - - Common::SeekableReadStream *s = openArchivedFile(path, false); - if (s == NULL) - return; // no errors if missing mask files: not every location has one - - s->seek(0x30, SEEK_SET); - - byte r, g, b; - for (uint i = 0; i < 4; i++) { - r = s->readByte(); - g = s->readByte(); - b = s->readByte(); - - _vm->_gfx->_bgLayers[i] = (((r << 4) & 0xF00) | (g & 0xF0) | (b >> 4)) & 0xFF; - -// printf("rgb = (%x, %x, %x) -> %x\n", r, g, b, _vm->_gfx->_bgLayers[i]); - } - - - s->seek(0x126, SEEK_SET); // HACK: skipping IFF/ILBM header should be done by analysis, not magic - Graphics::PackBitsReadStream stream(*s); - - byte *buf = (byte*)malloc(_vm->_screenMaskSize); - stream.read(buf, _vm->_screenMaskSize); - buildMask(buf); - _vm->_gfx->setMask(buf); - free(buf); - delete s; - - return; -} - -void AmigaDisk::loadPath(const char *name) { - - char path[PATH_LEN]; - sprintf(path, "%s.path", name); - - Common::SeekableReadStream *s = openArchivedFile(path, false); - if (s == NULL) - return; // no errors if missing path files: not every location has one - - - s->seek(0x120, SEEK_SET); // HACK: skipping IFF/ILBM header should be done by analysis, not magic - - Graphics::PackBitsReadStream stream(*s); - byte *buf = (byte*)malloc(_vm->_screenPathSize); - stream.read(buf, _vm->_screenPathSize); - _vm->setPath(buf); - free(buf); - delete s; - - return; -} - -void AmigaDisk::loadScenery(const char* background, const char* mask) { - debugC(1, kDebugDisk, "AmigaDisk::loadScenery '%s', '%s'", background, mask); - - char path[PATH_LEN]; - sprintf(path, "%s.bkgnd", background); - - loadBackground(path); - loadMask(background); - loadPath(background); - - return; -} - -void AmigaDisk::loadSlide(const char *name) { - debugC(1, kDebugDisk, "AmigaDisk::loadSlide '%s'", name); - - char path[PATH_LEN]; - sprintf(path, "slides/%s", name); - Common::SeekableReadStream *s = openArchivedFile(path, false); - if (s) - loadBackground(path); - else - loadBackground(name); - - return; -} - -Cnv* AmigaDisk::loadFrames(const char* name) { - debugC(1, kDebugDisk, "AmigaDisk::loadFrames '%s'", name); - - Common::SeekableReadStream *s; - - char path[PATH_LEN]; - sprintf(path, "anims/%s", name); - - s = openArchivedFile(path, false); - if (!s) - s = openArchivedFile(name, true); - - Cnv *cnv = makeCnv(*s); - delete s; - - return cnv; -} - -StaticCnv* AmigaDisk::loadHead(const char* name) { - debugC(1, kDebugDisk, "AmigaDisk::loadHead '%s'", name); - - char path[PATH_LEN]; - sprintf(path, "%s.head", name); - - Common::SeekableReadStream *s = openArchivedFile(path, true); - StaticCnv *cnv = makeStaticCnv(*s); - - delete s; - - return cnv; -} - - -Cnv* AmigaDisk::loadObjects(const char *name) { - debugC(1, kDebugDisk, "AmigaDisk::loadObjects"); - - char path[PATH_LEN]; - if (_vm->getFeatures() & GF_DEMO) - sprintf(path, "%s.objs", name); - else - sprintf(path, "objs/%s.objs", name); - - Common::SeekableReadStream *s = openArchivedFile(path, true); - - Cnv *cnv = makeCnv(*s); - delete s; - - return cnv; -} - - -Cnv* AmigaDisk::loadTalk(const char *name) { - debugC(1, kDebugDisk, "AmigaDisk::loadTalk '%s'", name); - - Common::SeekableReadStream *s; - - char path[PATH_LEN]; - if (_vm->getFeatures() & GF_DEMO) - sprintf(path, "%s.talk", name); - else - sprintf(path, "talk/%s.talk", name); - - s = openArchivedFile(path, false); - if (s == NULL) { - s = openArchivedFile(name, true); - } - - Cnv *cnv = makeCnv(*s); - delete s; - - return cnv; -} - -Table* AmigaDisk::loadTable(const char* name) { - debugC(1, kDebugDisk, "AmigaDisk::loadTable '%s'", name); - - char path[PATH_LEN]; - sprintf(path, "%s.table", name); - - bool dispose = false; - - Common::SeekableReadStream *stream; - - if (!scumm_stricmp(name, "global")) { - Common::File *s = new Common::File; - if (!s->open(path)) - errorFileNotFound(path); - - dispose = true; - stream = s; - } else { - if (!(_vm->getFeatures() & GF_DEMO)) - sprintf(path, "objs/%s.table", name); - if (!_resArchive.openArchivedFile(path)) - errorFileNotFound(path); - - stream = &_resArchive; - } - - Table *t = new Table(100); - - fillBuffers(*stream); - while (scumm_stricmp(_tokens[0], "ENDTABLE")) { - t->addData(_tokens[0]); - fillBuffers(*stream); - } - - if (dispose) - delete stream; - - return t; -} - -Font* AmigaDisk::loadFont(const char* name) { - debugC(1, kDebugDisk, "AmigaFullDisk::loadFont '%s'", name); - - char path[PATH_LEN]; - sprintf(path, "%sfont", name); - - if (_vm->getFeatures() & GF_LANG_IT) { - // Italian version has separate font files - Common::File stream; - if (!stream.open(path)) - errorFileNotFound(path); - - return createFont(name, stream); - } else { - if (!_resArchive.openArchivedFile(path)) - errorFileNotFound(path); - - return createFont(name, _resArchive); - } -} - - -Common::ReadStream* AmigaDisk::loadMusic(const char* name) { - return openArchivedFile(name); -} - -Common::ReadStream* AmigaDisk::loadSound(const char* name) { - char path[PATH_LEN]; - sprintf(path, "%s.snd", name); - - openArchivedFile(path); - - return new DummyArchiveStream(_resArchive); -} - -} // namespace Parallaction diff --git a/engines/parallaction/disk.h b/engines/parallaction/disk.h index 14ea4f0e16..d910201f27 100644 --- a/engines/parallaction/disk.h +++ b/engines/parallaction/disk.h @@ -29,19 +29,8 @@ #include "parallaction/defs.h" #include "common/file.h" -namespace Audio { - class AudioStream; -} - namespace Parallaction { -//------------------------------------------------------ -// ARCHIVE MANAGEMENT -//------------------------------------------------------ - - -#define MAX_ARCHIVE_ENTRIES 384 - class Table; class Parallaction; class Gfx; @@ -51,22 +40,49 @@ class Font; struct Cnv; struct StaticCnv; + +class Disk { + +public: + Disk() { } + virtual ~Disk() { } + + virtual Common::String selectArchive(const Common::String &name) = 0; + virtual void setLanguage(uint16 language) = 0; + + virtual Script* loadLocation(const char *name) = 0; + virtual Script* loadScript(const char* name) = 0; + virtual Cnv* loadTalk(const char *name) = 0; + virtual Cnv* loadObjects(const char *name) = 0; + virtual StaticCnv* loadPointer() = 0; + virtual StaticCnv* loadHead(const char* name) = 0; + virtual Font* loadFont(const char* name) = 0; + virtual StaticCnv* loadStatic(const char* name) = 0; + virtual Cnv* loadFrames(const char* name) = 0; + virtual void loadSlide(const char *filename) = 0; + virtual void loadScenery(const char* background, const char* mask) = 0; + virtual Table* loadTable(const char* name) = 0; + virtual Common::ReadStream* loadMusic(const char* name) = 0; + virtual Common::ReadStream* loadSound(const char* name) = 0; +}; + + + + +#define MAX_ARCHIVE_ENTRIES 384 + class Archive : public Common::SeekableReadStream { protected: - bool _file; uint32 _fileOffset; uint32 _fileCursor; uint32 _fileEndOffset; - Common::String _archiveName; char _archiveDir[MAX_ARCHIVE_ENTRIES][32]; uint32 _archiveLenghts[MAX_ARCHIVE_ENTRIES]; uint32 _archiveOffsets[MAX_ARCHIVE_ENTRIES]; - Common::File _archive; - uint32 _numFiles; protected: @@ -77,21 +93,17 @@ public: void open(const char* file); void close(); - Common::String name() const; - bool openArchivedFile(const char *name); void closeArchivedFile(); - uint32 size() const; uint32 pos() const; bool eos() const; void seek(int32 offs, int whence = SEEK_SET); - uint32 read(void *dataPtr, uint32 dataSize); }; -class Disk { +class Disk_ns : public Disk { protected: Archive _resArchive; @@ -103,29 +115,14 @@ protected: void errorFileNotFound(const char *s); public: - Disk(Parallaction *vm); - virtual ~Disk(); + Disk_ns(Parallaction *vm); + virtual ~Disk_ns(); Common::String selectArchive(const Common::String &name); void setLanguage(uint16 language); - - virtual Script* loadLocation(const char *name) = 0; - virtual Script* loadScript(const char* name) = 0; - virtual Cnv* loadTalk(const char *name) = 0; - virtual Cnv* loadObjects(const char *name) = 0; - virtual StaticCnv* loadPointer() = 0; - virtual StaticCnv* loadHead(const char* name) = 0; - virtual Font* loadFont(const char* name) = 0; - virtual StaticCnv* loadStatic(const char* name) = 0; - virtual Cnv* loadFrames(const char* name) = 0; - virtual void loadSlide(const char *filename) = 0; - virtual void loadScenery(const char* background, const char* mask) = 0; - virtual Table* loadTable(const char* name) = 0; - virtual Common::ReadStream* loadMusic(const char* name) = 0; - virtual Common::ReadStream* loadSound(const char* name) = 0; }; -class DosDisk : public Disk { +class DosDisk_ns : public Disk_ns { private: void unpackBackground(Common::ReadStream *stream, byte *screen, byte *mask, byte *path); @@ -142,8 +139,8 @@ protected: Gfx *_gfx; public: - DosDisk(Parallaction *vm); - virtual ~DosDisk(); + DosDisk_ns(Parallaction *vm); + virtual ~DosDisk_ns(); Script* loadLocation(const char *name); Script* loadScript(const char* name); @@ -161,7 +158,7 @@ public: Common::ReadStream* loadSound(const char* name); }; -class AmigaDisk : public Disk { +class AmigaDisk_ns : public Disk_ns { protected: Cnv* makeCnv(Common::SeekableReadStream &stream); @@ -176,9 +173,43 @@ protected: void loadBackground(const char *name); public: - AmigaDisk(Parallaction *vm); - virtual ~AmigaDisk(); + AmigaDisk_ns(Parallaction *vm); + virtual ~AmigaDisk_ns(); + + Script* loadLocation(const char *name); + Script* loadScript(const char* name); + Cnv* loadTalk(const char *name); + Cnv* loadObjects(const char *name); + StaticCnv* loadPointer(); + StaticCnv* loadHead(const char* name); + Font* loadFont(const char* name); + StaticCnv* loadStatic(const char* name); + Cnv* loadFrames(const char* name); + void loadSlide(const char *filename); + void loadScenery(const char* background, const char* mask); + Table* loadTable(const char* name); + Common::ReadStream* loadMusic(const char* name); + Common::ReadStream* loadSound(const char* name); +}; + + +// for the moment DosDisk_br subclasses Disk. When Amiga support will +// be taken into consideration, it might be useful to add another level +// like we did for Nippon Safes. +class DosDisk_br : public Disk { + +protected: + Parallaction *_vm; + +protected: + void errorFileNotFound(const char *s); + +public: + DosDisk_br(Parallaction *vm); + virtual ~DosDisk_br(); + Common::String selectArchive(const Common::String &name); + void setLanguage(uint16 language); Script* loadLocation(const char *name); Script* loadScript(const char* name); Cnv* loadTalk(const char *name); @@ -195,6 +226,7 @@ public: Common::ReadStream* loadSound(const char* name); }; + } // namespace Parallaction diff --git a/engines/parallaction/disk_br.cpp b/engines/parallaction/disk_br.cpp new file mode 100644 index 0000000000..07d9954f23 --- /dev/null +++ b/engines/parallaction/disk_br.cpp @@ -0,0 +1,134 @@ +/* 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 2 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "common/stdafx.h" +#include "parallaction/parallaction.h" + + +namespace Parallaction { + + +void DosDisk_br::errorFileNotFound(const char *s) { + error("File '%s' not found", s); +} + +Common::String DosDisk_br::selectArchive(const Common::String& name) { + debugC(5, kDebugDisk, "DosDisk_br::selectArchive"); + return ""; +} + +void DosDisk_br::setLanguage(uint16 language) { + debugC(5, kDebugDisk, "DosDisk_br::setLanguage"); + + return; +} + +DosDisk_br::DosDisk_br(Parallaction* vm) : _vm(vm) { + +} + +DosDisk_br::~DosDisk_br() { +} + +Cnv* DosDisk_br::loadTalk(const char *name) { + debugC(5, kDebugDisk, "DosDisk_br::loadTalk"); + + return 0; +} + +Script* DosDisk_br::loadLocation(const char *name) { + debugC(5, kDebugDisk, "DosDisk_br::loadLocation"); + return 0; +} + +Script* DosDisk_br::loadScript(const char* name) { + debugC(5, kDebugDisk, "DosDisk_br::loadScript"); + return 0; +} + +// there are no Head resources in Big Red Adventure +StaticCnv* DosDisk_br::loadHead(const char* name) { + debugC(5, kDebugDisk, "DosDisk_br::loadHead"); + return 0; +} + + +StaticCnv* DosDisk_br::loadPointer() { + debugC(5, kDebugDisk, "DosDisk_br::loadPointer"); + return 0; +} + + +Font* DosDisk_br::loadFont(const char* name) { + debugC(5, kDebugDisk, "DosDisk_br::loadFont"); + return 0; +} + + +Cnv* DosDisk_br::loadObjects(const char *name) { + debugC(5, kDebugDisk, "DosDisk_br::loadObjects"); + return 0; +} + + +StaticCnv* DosDisk_br::loadStatic(const char* name) { + debugC(5, kDebugDisk, "DosDisk_br::loadStatic"); + return 0; +} + +Cnv* DosDisk_br::loadFrames(const char* name) { + debugC(5, kDebugDisk, "DosDisk_br::loadFrames"); + return 0; +} + +// there are no Slide resources in Big Red Adventure +void DosDisk_br::loadSlide(const char *filename) { + debugC(5, kDebugDisk, "DosDisk_br::loadSlide"); + return; +} + +void DosDisk_br::loadScenery(const char *name, const char *mask) { + debugC(5, kDebugDisk, "DosDisk_br::loadScenery"); + return; +} + +Table* DosDisk_br::loadTable(const char* name) { + debugC(5, kDebugDisk, "DosDisk_br::loadTable"); + return 0; +} + +Common::ReadStream* DosDisk_br::loadMusic(const char* name) { + debugC(5, kDebugDisk, "DosDisk_br::loadMusic"); + return 0; +} + + +Common::ReadStream* DosDisk_br::loadSound(const char* name) { + debugC(5, kDebugDisk, "DosDisk_br::loadSound"); + return 0; +} + + +} // namespace Parallaction diff --git a/engines/parallaction/disk_ns.cpp b/engines/parallaction/disk_ns.cpp new file mode 100644 index 0000000000..bf9b0277cb --- /dev/null +++ b/engines/parallaction/disk_ns.cpp @@ -0,0 +1,1443 @@ +/* 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 2 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "common/stdafx.h" + +#include "graphics/iff.h" +#include "graphics/surface.h" + +#include "parallaction/parallaction.h" + + +namespace Audio { + class AudioStream; + + AudioStream *make8SVXStream(Common::ReadStream &input); +} + +namespace Parallaction { + + +// HACK: Several archives ('de', 'en', 'fr' and 'disk0') in the multi-lingual +// Amiga version of Nippon Safes, and one archive ('fr') in the Amiga Demo of +// Nippon Safes used different internal offsets than all the other archives. +// +// When an archive is opened in the Amiga demo, its size is checked against +// SIZEOF_SMALL_ARCHIVE to detect when the smaller archive is used. +// +// When an archive is opened in Amiga multi-lingual version, the header is +// checked again NDOS to detect when a smaller archive is used. +// +#define SIZEOF_SMALL_ARCHIVE 12778 + +#define ARCHIVE_FILENAMES_OFS 0x16 + +#define NORMAL_ARCHIVE_FILES_NUM 384 +#define SMALL_ARCHIVE_FILES_NUM 180 + +#define NORMAL_ARCHIVE_SIZES_OFS 0x3016 +#define SMALL_ARCHIVE_SIZES_OFS 0x1696 + +#define NORMAL_ARCHIVE_DATA_OFS 0x4000 +#define SMALL_ARCHIVE_DATA_OFS 0x1966 + +Archive::Archive() { + resetArchivedFile(); +} + +void Archive::open(const char *file) { + debugC(1, kDebugDisk, "Archive::open(%s)", file); + + if (_archive.isOpen()) + close(); + + char path[PATH_LEN]; + + strcpy(path, file); + if (!_archive.open(path)) + error("archive '%s' not found", path); + + _archiveName = file; + + bool isSmallArchive = false; + if (_vm->getPlatform() == Common::kPlatformAmiga) { + if (_vm->getFeatures() & GF_DEMO) { + isSmallArchive = _archive.size() == SIZEOF_SMALL_ARCHIVE; + } else if (_vm->getFeatures() & GF_LANG_MULT) { + isSmallArchive = (_archive.readUint32BE() != MKID_BE('NDOS')); + } + } + + _numFiles = (isSmallArchive) ? SMALL_ARCHIVE_FILES_NUM : NORMAL_ARCHIVE_FILES_NUM; + + _archive.seek(ARCHIVE_FILENAMES_OFS); + _archive.read(_archiveDir, _numFiles*32); + + _archive.seek((isSmallArchive) ? SMALL_ARCHIVE_SIZES_OFS : NORMAL_ARCHIVE_SIZES_OFS); + + uint32 dataOffset = (isSmallArchive) ? SMALL_ARCHIVE_DATA_OFS : NORMAL_ARCHIVE_DATA_OFS; + for (uint16 i = 0; i < _numFiles; i++) { + _archiveOffsets[i] = dataOffset; + _archiveLenghts[i] = _archive.readUint32BE(); + dataOffset += _archiveLenghts[i]; + } + + return; +} + + +void Archive::close() { + if (!_archive.isOpen()) return; + + resetArchivedFile(); + + _archive.close(); + _archiveName.clear(); +} + +Common::String Archive::name() const { + return _archiveName; +} + +bool Archive::openArchivedFile(const char *filename) { + debugC(3, kDebugDisk, "Archive::openArchivedFile(%s)", filename); + + resetArchivedFile(); + + debugC(3, kDebugDisk, "Archive::openArchivedFile(%s)", filename); + + if (!_archive.isOpen()) + error("Archive::openArchivedFile: the archive is not open"); + + uint16 i = 0; + for ( ; i < _numFiles; i++) { + if (!scumm_stricmp(_archiveDir[i], filename)) break; + } + if (i == _numFiles) return false; + + debugC(9, kDebugDisk, "Archive::openArchivedFile: '%s' found in slot %i", filename, i); + + _file = true; + + _fileOffset = _archiveOffsets[i]; + _fileCursor = _archiveOffsets[i]; + _fileEndOffset = _archiveOffsets[i] + _archiveLenghts[i]; + + _archive.seek(_fileOffset); + + return true; +} + +void Archive::resetArchivedFile() { + _file = false; + _fileCursor = 0; + _fileOffset = 0; + _fileEndOffset = 0; +} + +void Archive::closeArchivedFile() { + resetArchivedFile(); +} + + +uint32 Archive::size() const { + return (_file == true ? _fileEndOffset - _fileOffset : 0); +} + +uint32 Archive::pos() const { + return (_file == true ? _fileCursor - _fileOffset : 0 ); +} + +bool Archive::eos() const { + return (_file == true ? _fileCursor == _fileEndOffset : true ); +} + +void Archive::seek(int32 offs, int whence) { + assert(_file == true && _fileCursor <= _fileEndOffset); + + switch (whence) { + case SEEK_CUR: + _fileCursor += offs; + break; + case SEEK_SET: + _fileCursor = _fileOffset + offs; + break; + case SEEK_END: + _fileCursor = _fileEndOffset - offs; + break; + } + assert(_fileCursor <= _fileEndOffset && _fileCursor >= _fileOffset); + + _archive.seek(_fileCursor, SEEK_SET); +} + +uint32 Archive::read(void *dataPtr, uint32 dataSize) { +// printf("read(%i, %i)\n", file->_cursor, file->_endOffset); + if (_file == false) + error("Archive::read: no archived file is currently open"); + + if (_fileCursor >= _fileEndOffset) + error("can't read beyond end of archived file"); + + if (_fileEndOffset - _fileCursor < dataSize) + dataSize = _fileEndOffset - _fileCursor; + + int32 readBytes = _archive.read(dataPtr, dataSize); + _fileCursor += readBytes; + + return readBytes; +} + + + + + +/* + This stream class is just a wrapper around Archive, so + deallocation is not a problem. In fact, this class doesn't + delete its input (Archive) stream. +*/ +class DummyArchiveStream : public Common::SeekableReadStream { + + Archive *_input; + +public: + DummyArchiveStream(Archive &input) : _input(&input) { + + } + + ~DummyArchiveStream() { + // this class exists to provide this empty destructor + } + + bool eos() const { + return _input->eos(); + } + + uint32 read(void* data, uint32 dataSize) { + return _input->read(data, dataSize); + } + + uint32 pos() const { + return _input->pos(); + } + + uint32 size() const { + return _input->size(); + } + + void seek(int32 offset, int whence) { + _input->seek(offset, whence); + } + +}; + + + +void Disk_ns::errorFileNotFound(const char *s) { + error("File '%s' not found", s); +} + +Disk_ns::Disk_ns(Parallaction *vm) : _vm(vm) { + +} + +Disk_ns::~Disk_ns() { + +} + + +Common::String Disk_ns::selectArchive(const Common::String& name) { + Common::String oldName = _resArchive.name(); + _resArchive.open(name.c_str()); + return oldName; +} + +void Disk_ns::setLanguage(uint16 language) { + debugC(1, kDebugDisk, "setLanguage(%i)", language); + + switch (language) { + case 0: + strcpy(_languageDir, "it/"); + break; + + case 1: + strcpy(_languageDir, "fr/"); + break; + + case 2: + strcpy(_languageDir, "en/"); + break; + + case 3: + strcpy(_languageDir, "ge/"); + break; + + default: + error("unknown language"); + + } + + _languageDir[2] = '\0'; + _locArchive.open(_languageDir); + _languageDir[2] = '/'; + + return; +} + +#pragma mark - + + + +DosDisk_ns::DosDisk_ns(Parallaction* vm) : Disk_ns(vm) { + +} + +DosDisk_ns::~DosDisk_ns() { +} + + +// +// loads a cnv from an external file +// +Cnv* DosDisk_ns::loadExternalCnv(const char *filename) { +// printf("Gfx::loadExternalCnv(%s)...", filename); + + char path[PATH_LEN]; + + sprintf(path, "%s.cnv", filename); + + Common::File stream; + + if (!stream.open(path)) + errorFileNotFound(path); + + uint16 numFrames = stream.readByte(); + uint16 width = stream.readByte(); + uint16 height = stream.readByte(); + + uint32 decsize = numFrames * width * height; + byte *data = (byte*)malloc(decsize); + stream.read(data, decsize); + + return new Cnv(numFrames, width, height, data); +} + +StaticCnv *DosDisk_ns::loadExternalStaticCnv(const char *filename) { + + char path[PATH_LEN]; + + sprintf(path, "%s.cnv", filename); + + Common::File stream; + + if (!stream.open(path)) + errorFileNotFound(path); + + StaticCnv *cnv = new StaticCnv; + + stream.skip(1); + cnv->_width = stream.readByte(); + cnv->_height = stream.readByte(); + + uint16 size = cnv->_width*cnv->_height; + + cnv->_data0 = (byte*)malloc(size); + stream.read(cnv->_data0, size); + + return cnv; +} + +Cnv* DosDisk_ns::loadCnv(const char *filename) { +// printf("Gfx::loadCnv(%s)\n", filename); + + char path[PATH_LEN]; + + strcpy(path, filename); + if (!_resArchive.openArchivedFile(path)) { + sprintf(path, "%s.pp", filename); + if (!_resArchive.openArchivedFile(path)) + errorFileNotFound(path); + } + + uint16 numFrames = _resArchive.readByte(); + uint16 width = _resArchive.readByte(); + uint16 height = _resArchive.readByte(); + + uint32 decsize = numFrames * width * height; + byte *data = (byte*)malloc(decsize); + + Graphics::PackBitsReadStream decoder(_resArchive); + decoder.read(data, decsize); + + return new Cnv(numFrames, width, height, data); +} + +Cnv* DosDisk_ns::loadTalk(const char *name) { + + const char *ext = strstr(name, ".talk"); + if (ext != NULL) { + // npc talk + return loadCnv(name); + + } + + // character talk + char v20[PATH_LEN]; + char *v24 = const_cast(name); + if (IS_MINI_CHARACTER(v24)) { + v24+=4; + } + + if (_engineFlags & kEngineTransformedDonna) { + sprintf(v20, "%stta", v24); + } else { + sprintf(v20, "%stal", v24); + } + + return loadExternalCnv(v20); +} + +Script* DosDisk_ns::loadLocation(const char *name) { + + char archivefile[PATH_LEN]; + + if (IS_MINI_CHARACTER(_vm->_characterName)) { + sprintf(archivefile, "%s%s", _vm->_characterName+4, _languageDir); + } else { + if (IS_DUMMY_CHARACTER(_vm->_characterName)) { + strcpy(archivefile, _languageDir); + } else { + sprintf(archivefile, "%s%s", _vm->_characterName, _languageDir); + } + } + + strcat(archivefile, name); + strcat(archivefile, ".loc"); + + debugC(3, kDebugDisk, "DosDisk_ns::loadLocation(%s): trying '%s'", name, archivefile); + + if (!_locArchive.openArchivedFile(archivefile)) { + sprintf(archivefile, "%s%s.loc", _languageDir, name); + debugC(3, kDebugDisk, "DosDisk_ns::loadLocation(%s): trying '%s'", name, archivefile); + + if (!_locArchive.openArchivedFile(archivefile)) + errorFileNotFound(name); + } + + return new Script(new DummyArchiveStream(_locArchive), true); +} + +Script* DosDisk_ns::loadScript(const char* name) { + + char vC8[PATH_LEN]; + + sprintf(vC8, "%s.script", name); + + if (!_resArchive.openArchivedFile(vC8)) + errorFileNotFound(vC8); + + return new Script(new DummyArchiveStream(_resArchive), true); +} + +StaticCnv* DosDisk_ns::loadHead(const char* name) { + + char path[PATH_LEN]; + + if (IS_MINI_CHARACTER(name)) { + name += 4; + } + + sprintf(path, "%shead", name); + path[8] = '\0'; + + return loadExternalStaticCnv(path); +} + + +StaticCnv* DosDisk_ns::loadPointer() { + return loadExternalStaticCnv("pointer"); +} + + +Font* DosDisk_ns::loadFont(const char* name) { + char path[PATH_LEN]; + sprintf(path, "%scnv", name); + return createFont(name, loadExternalCnv(path)); +} + + +Cnv* DosDisk_ns::loadObjects(const char *name) { + + if (IS_MINI_CHARACTER(name)) { + name += 4; + } + + char path[PATH_LEN]; + sprintf(path, "%sobj", name); + return loadExternalCnv(path); +} + + +StaticCnv* DosDisk_ns::loadStatic(const char* name) { + + char path[PATH_LEN]; + + strcpy(path, name); + if (!_resArchive.openArchivedFile(path)) { + sprintf(path, "%s.pp", name); + if (!_resArchive.openArchivedFile(path)) + errorFileNotFound(path); + } + + StaticCnv* cnv = new StaticCnv; + + _resArchive.skip(1); + cnv->_width = _resArchive.readByte(); + cnv->_height = _resArchive.readByte(); + + uint16 size = cnv->_width*cnv->_height; + cnv->_data0 = (byte*)malloc(size); + + Graphics::PackBitsReadStream decoder(_resArchive); + decoder.read(cnv->_data0, size); + + return cnv; +} + +Cnv* DosDisk_ns::loadFrames(const char* name) { + return loadCnv(name); +} + +// +// slides (background images) are stored compressed by scanline in a rle fashion +// +// the uncompressed data must then be unpacked to get: +// * color data [bits 0-5] +// * mask data [bits 6-7] (z buffer) +// * path data [bit 8] (walkable areas) +// +void DosDisk_ns::unpackBackground(Common::ReadStream *stream, byte *screen, byte *mask, byte *path) { + + byte b; + uint32 i = 0; + + while (!stream->eos()) { + b = stream->readByte(); + + path[i/8] |= ((b & 0x80) >> 7) << (i & 7); + mask[i/4] |= ((b & 0x60) >> 5) << ((i & 3) << 1); + screen[i] = b & 0x1F; + i++; + } + + return; +} + + +void DosDisk_ns::parseDepths(Common::SeekableReadStream &stream) { + _vm->_gfx->_bgLayers[0] = stream.readByte(); + _vm->_gfx->_bgLayers[1] = stream.readByte(); + _vm->_gfx->_bgLayers[2] = stream.readByte(); + _vm->_gfx->_bgLayers[3] = stream.readByte(); +} + + +void DosDisk_ns::parseBackground(Common::SeekableReadStream &stream) { + + stream.read(_vm->_gfx->_palette, BASE_PALETTE_SIZE); + _vm->_gfx->setPalette(_vm->_gfx->_palette); + + parseDepths(stream); + + for (uint32 _si = 0; _si < 6; _si++) { + _vm->_gfx->_palettefx[_si]._timer = stream.readUint16BE(); + _vm->_gfx->_palettefx[_si]._step = stream.readUint16BE(); + _vm->_gfx->_palettefx[_si]._flags = stream.readUint16BE(); + _vm->_gfx->_palettefx[_si]._first = stream.readByte(); + _vm->_gfx->_palettefx[_si]._last = stream.readByte(); + } + +} + +void DosDisk_ns::loadBackground(const char *filename) { + + if (!_resArchive.openArchivedFile(filename)) + errorFileNotFound(filename); + + parseBackground(_resArchive); + + byte *bg = (byte*)calloc(1, _vm->_screenSize); + byte *mask = (byte*)calloc(1, _vm->_screenMaskSize); + byte *path = (byte*)calloc(1, _vm->_screenPathSize); + + + Graphics::PackBitsReadStream stream(_resArchive); + unpackBackground(&stream, bg, mask, path); + + _vm->_gfx->setBackground(bg); + _vm->_gfx->setMask(mask); + _vm->setPath(path); + + free(bg); + free(mask); + free(path); + + return; +} + +// +// read background path and mask from a file +// +// mask and path are normally combined (via OR) into the background picture itself +// read the comment on the top of this file for more +// +void DosDisk_ns::loadMaskAndPath(const char *name) { + char path[PATH_LEN]; + sprintf(path, "%s.msk", name); + + if (!_resArchive.openArchivedFile(path)) + errorFileNotFound(name); + + byte *maskBuf = (byte*)calloc(1, _vm->_screenMaskSize); + byte *pathBuf = (byte*)calloc(1, _vm->_screenPathSize); + + parseDepths(_resArchive); + + _resArchive.read(pathBuf, _vm->_screenPathSize); + _resArchive.read(maskBuf, _vm->_screenMaskSize); + + _vm->_gfx->setMask(maskBuf); + _vm->setPath(pathBuf); + + return; +} + +void DosDisk_ns::loadSlide(const char *filename) { + char path[PATH_LEN]; + sprintf(path, "%s.slide", filename); + loadBackground(path); +} + +void DosDisk_ns::loadScenery(const char *name, const char *mask) { + char path[PATH_LEN]; + sprintf(path, "%s.dyn", name); + loadBackground(path); + + if (mask != NULL) { + // load external masks and paths only for certain locations + loadMaskAndPath(mask); + } + +} + +Table* DosDisk_ns::loadTable(const char* name) { + char path[PATH_LEN]; + sprintf(path, "%s.tab", name); + + Common::File stream; + if (!stream.open(path)) + errorFileNotFound(path); + + Table *t = new Table(100); + + fillBuffers(stream); + while (scumm_stricmp(_tokens[0], "ENDTABLE")) { + t->addData(_tokens[0]); + fillBuffers(stream); + } + + stream.close(); + + return t; +} + +Common::ReadStream* DosDisk_ns::loadMusic(const char* name) { + char path[PATH_LEN]; + sprintf(path, "%s.mid", name); + + Common::File *stream = new Common::File; + if (!stream->open(path)) + errorFileNotFound(path); + + return stream; +} + + +Common::ReadStream* DosDisk_ns::loadSound(const char* name) { + return NULL; +} + + + + + + +#pragma mark - + + +/* the decoder presented here is taken from pplib by Stuart Caie. The + * following statement comes from the original source. + * + * pplib 1.0: a simple PowerPacker decompression and decryption library + * placed in the Public Domain on 2003-09-18 by Stuart Caie. + */ + +#define PP_READ_BITS(nbits, var) do { \ + bit_cnt = (nbits); (var) = 0; \ + while (bits_left < bit_cnt) { \ + if (buf < src) return 0; \ + bit_buffer |= *--buf << bits_left; \ + bits_left += 8; \ + } \ + bits_left -= bit_cnt; \ + while (bit_cnt--) { \ + (var) = ((var) << 1) | (bit_buffer & 1); \ + bit_buffer >>= 1; \ + } \ +} while (0) + +#define PP_BYTE_OUT(byte) do { \ + if (out <= dest) return 0; \ + *--out = (byte); written++; \ +} while (0) + + +class PowerPackerStream : public Common::SeekableReadStream { + + SeekableReadStream *_stream; + bool _dispose; + +private: + int ppDecrunchBuffer(byte *src, byte *dest, uint32 src_len, uint32 dest_len) { + + byte *buf, *out, *dest_end, *off_lens, bits_left = 0, bit_cnt; + uint32 bit_buffer = 0, x, todo, offbits, offset, written = 0; + + if (src == NULL || dest == NULL) return 0; + + /* set up input and output pointers */ + off_lens = src; src = &src[4]; + buf = &src[src_len]; + + out = dest_end = &dest[dest_len]; + + /* skip the first few bits */ + PP_READ_BITS(src[src_len + 3], x); + + /* while there are input bits left */ + while (written < dest_len) { + PP_READ_BITS(1, x); + if (x == 0) { + /* bit==0: literal, then match. bit==1: just match */ + todo = 1; do { PP_READ_BITS(2, x); todo += x; } while (x == 3); + while (todo--) { PP_READ_BITS(8, x); PP_BYTE_OUT(x); } + + /* should we end decoding on a literal, break out of the main loop */ + if (written == dest_len) break; + } + + /* match: read 2 bits for initial offset bitlength / match length */ + PP_READ_BITS(2, x); + offbits = off_lens[x]; + todo = x+2; + if (x == 3) { + PP_READ_BITS(1, x); + if (x == 0) offbits = 7; + PP_READ_BITS(offbits, offset); + do { PP_READ_BITS(3, x); todo += x; } while (x == 7); + } + else { + PP_READ_BITS(offbits, offset); + } + if (&out[offset] >= dest_end) return 0; /* match_overflow */ + while (todo--) { x = out[offset]; PP_BYTE_OUT(x); } + } + + /* all output bytes written without error */ + return 1; + } + + uint16 getCrunchType(uint32 signature) { + + byte eff; + + switch (signature) { + case 0x50503230: /* PP20 */ + eff = 4; + break; + case 0x50504C53: /* PPLS */ + error("PPLS crunched files are not supported"); + eff = 8; + break; + case 0x50583230: /* PX20 */ + error("PX20 crunched files are not supported"); + eff = 6; + break; + default: + eff = 0; + + } + + return eff; + } + +public: + PowerPackerStream(Common::SeekableReadStream &stream) { + + _dispose = false; + + uint32 signature = stream.readUint32BE(); + if (getCrunchType(signature) == 0) { + stream.seek(0, SEEK_SET); + _stream = &stream; + return; + } + + stream.seek(4, SEEK_END); + uint32 decrlen = stream.readUint32BE() >> 8; + byte *dest = (byte*)malloc(decrlen); + + uint32 crlen = stream.size() - 4; + byte *src = (byte*)malloc(crlen); + stream.seek(4, SEEK_SET); + stream.read(src, crlen); + + ppDecrunchBuffer(src, dest, crlen-8, decrlen); + + free(src); + _stream = new Common::MemoryReadStream(dest, decrlen, true); + _dispose = true; + } + + ~PowerPackerStream() { + if (_dispose) delete _stream; + } + + uint32 size() const { + return _stream->size(); + } + + uint32 pos() const { + return _stream->pos(); + } + + bool eos() const { + return _stream->eos(); + } + + void seek(int32 offs, int whence = SEEK_SET) { + _stream->seek(offs, whence); + } + + uint32 read(void *dataPtr, uint32 dataSize) { + return _stream->read(dataPtr, dataSize); + } +}; + + + + + +AmigaDisk_ns::AmigaDisk_ns(Parallaction *vm) : Disk_ns(vm) { + +} + + +AmigaDisk_ns::~AmigaDisk_ns() { + +} + +#define NUM_PLANES 5 + +/* + unpackFrame transforms images from 5-bitplanes format to + 8-bit color-index mode +*/ +void AmigaDisk_ns::unpackFrame(byte *dst, byte *src, uint16 planeSize) { + + byte s0, s1, s2, s3, s4, mask, t0, t1, t2, t3, t4; + + for (uint32 j = 0; j < planeSize; j++) { + s0 = src[j]; + s1 = src[j+planeSize]; + s2 = src[j+planeSize*2]; + s3 = src[j+planeSize*3]; + s4 = src[j+planeSize*4]; + + for (uint32 k = 0; k < 8; k++) { + mask = 1 << (7 - k); + t0 = (s0 & mask ? 1 << 0 : 0); + t1 = (s1 & mask ? 1 << 1 : 0); + t2 = (s2 & mask ? 1 << 2 : 0); + t3 = (s3 & mask ? 1 << 3 : 0); + t4 = (s4 & mask ? 1 << 4 : 0); + *dst++ = t0 | t1 | t2 | t3 | t4; + } + + } + +} + +/* + patchFrame applies DLTA data (dlta) to specified buffer (dst) +*/ +void AmigaDisk_ns::patchFrame(byte *dst, byte *dlta, uint16 bytesPerPlane, uint16 height) { + + uint32 *dataIndex = (uint32*)dlta; + uint32 *ofslenIndex = (uint32*)dlta + 8; + + uint16 *base = (uint16*)dlta; + uint16 wordsPerLine = bytesPerPlane >> 1; + + for (uint j = 0; j < NUM_PLANES; j++) { + uint16 *dst16 = (uint16*)(dst + j * bytesPerPlane * height); + + uint16 *data = base + READ_BE_UINT32(dataIndex); + dataIndex++; + uint16 *ofslen = base + READ_BE_UINT32(ofslenIndex); + ofslenIndex++; + + while (*ofslen != 0xFFFF) { + + uint16 ofs = READ_BE_UINT16(ofslen); + ofslen++; + uint16 size = READ_BE_UINT16(ofslen); + ofslen++; + + while (size > 0) { + dst16[ofs] ^= *data++; + ofs += wordsPerLine; + size--; + } + + } + + } + +} + +// FIXME: no mask is loaded +void AmigaDisk_ns::unpackBitmap(byte *dst, byte *src, uint16 numFrames, uint16 bytesPerPlane, uint16 height) { + + byte *baseFrame = src; + byte *tempBuffer = 0; + + uint16 planeSize = bytesPerPlane * height; + + for (uint32 i = 0; i < numFrames; i++) { + if (READ_BE_UINT32(src) == MKID_BE('DLTA')) { + + uint size = READ_BE_UINT32(src + 4); + + if (tempBuffer == 0) + tempBuffer = (byte*)malloc(planeSize * NUM_PLANES); + + memcpy(tempBuffer, baseFrame, planeSize * NUM_PLANES); + + patchFrame(tempBuffer, src + 8, bytesPerPlane, height); + unpackFrame(dst, tempBuffer, planeSize); + + src += (size + 8); + dst += planeSize * 8; + } else { + unpackFrame(dst, src, planeSize); + src += planeSize * NUM_PLANES; + dst += planeSize * 8; + } + } + + if (tempBuffer) + free(tempBuffer); + +} + +StaticCnv* AmigaDisk_ns::makeStaticCnv(Common::SeekableReadStream &stream) { + + stream.skip(1); + uint16 width = stream.readByte(); + uint16 height = stream.readByte(); + + assert((width & 7) == 0); + + byte bytesPerPlane = width / 8; + + uint32 rawsize = bytesPerPlane * NUM_PLANES * height; + byte *buf = (byte*)malloc(rawsize); + stream.read(buf, rawsize); + + uint32 decsize = width * height; + byte *data = (byte*)calloc(decsize, 1); + + unpackBitmap(data, buf, 1, bytesPerPlane, height); + + free(buf); + + StaticCnv *cnv = new StaticCnv(); + cnv->_width = width; + cnv->_height = height; + cnv->_data0 = data; + cnv->_data1 = NULL; + + return cnv; +} + +Cnv* AmigaDisk_ns::makeCnv(Common::SeekableReadStream &stream) { + + uint16 numFrames = stream.readByte(); + uint16 width = stream.readByte(); + uint16 height = stream.readByte(); + + assert((width & 7) == 0); + + byte bytesPerPlane = width / 8; + + uint32 rawsize = numFrames * bytesPerPlane * NUM_PLANES * height; + byte *buf = (byte*)malloc(rawsize); + stream.read(buf, rawsize); + + uint32 decsize = numFrames * width * height; + byte *data = (byte*)calloc(decsize, 1); + + unpackBitmap(data, buf, numFrames, bytesPerPlane, height); + + free(buf); + + return new Cnv(numFrames, width, height, data); +} +#undef NUM_PLANES + +Script* AmigaDisk_ns::loadLocation(const char *name) { + debugC(1, kDebugDisk, "AmigaDisk_ns()::loadLocation '%s'", name); + + char path[PATH_LEN]; + if (IS_MINI_CHARACTER(_vm->_characterName)) { + sprintf(path, "%s%s%s.loc.pp", _vm->_characterName+4, _languageDir, name); + } else + sprintf(path, "%s%s%s.loc.pp", _vm->_characterName, _languageDir, name); + + if (!_locArchive.openArchivedFile(path)) { + sprintf(path, "%s%s.loc.pp", _languageDir, name); + if (!_locArchive.openArchivedFile(path)) { + errorFileNotFound(name); + } + } + + debugC(3, kDebugDisk, "location file found: %s", path); + + return new Script(new PowerPackerStream(_locArchive), true); +} + +Script* AmigaDisk_ns::loadScript(const char* name) { + debugC(1, kDebugDisk, "AmigaDisk_ns::loadScript '%s'", name); + + char vC8[PATH_LEN]; + + sprintf(vC8, "%s.script", name); + + if (!_resArchive.openArchivedFile(vC8)) + errorFileNotFound(vC8); + + return new Script(new DummyArchiveStream(_resArchive), true); +} + +StaticCnv* AmigaDisk_ns::loadPointer() { + debugC(1, kDebugDisk, "AmigaDisk_ns::loadPointer"); + + Common::File stream; + if (!stream.open("pointer")) + errorFileNotFound("pointer"); + + return makeStaticCnv(stream); +} + +StaticCnv* AmigaDisk_ns::loadStatic(const char* name) { + debugC(1, kDebugDisk, "AmigaDisk_ns::loadStatic '%s'", name); + + Common::SeekableReadStream *s = openArchivedFile(name, true); + StaticCnv *cnv = makeStaticCnv(*s); + + delete s; + + return cnv; +} + +Common::SeekableReadStream *AmigaDisk_ns::openArchivedFile(const char* name, bool errorOnFileNotFound) { + debugC(3, kDebugDisk, "AmigaDisk_ns::openArchivedFile(%s)", name); + + if (_resArchive.openArchivedFile(name)) { + return new DummyArchiveStream(_resArchive); + } + + char path[PATH_LEN]; + + sprintf(path, "%s.pp", name); + if (_resArchive.openArchivedFile(path)) { + return new PowerPackerStream(_resArchive); + } + + sprintf(path, "%s.dd", name); + if (_resArchive.openArchivedFile(path)) { + return new PowerPackerStream(_resArchive); + } + + if (errorOnFileNotFound) + errorFileNotFound(name); + + return NULL; +} + +/* + FIXME: mask values are not computed correctly for level 1 and 2 + + NOTE: this routine is only able to build masks for Nippon Safes, since mask widths are hardcoded + into the main loop. +*/ +void buildMask(byte* buf) { + + byte mask1[16] = { 0, 0x80, 0x20, 0xA0, 8, 0x88, 0x28, 0xA8, 2, 0x82, 0x22, 0xA2, 0xA, 0x8A, 0x2A, 0xAA }; + byte mask0[16] = { 0, 0x40, 0x10, 0x50, 4, 0x44, 0x14, 0x54, 1, 0x41, 0x11, 0x51, 0x5, 0x45, 0x15, 0x55 }; + + byte plane0[40]; + byte plane1[40]; + + for (int32 i = 0; i < _vm->_screenHeight; i++) { + + memcpy(plane0, buf, 40); + memcpy(plane1, buf+40, 40); + + for (uint32 j = 0; j < 40; j++) { + *buf++ = mask0[(plane0[j] & 0xF0) >> 4] | mask1[(plane1[j] & 0xF0) >> 4]; + *buf++ = mask0[plane0[j] & 0xF] | mask1[plane1[j] & 0xF]; + } + + } +} + +class BackgroundDecoder : public Graphics::ILBMDecoder { + + PaletteFxRange *_range; + uint32 _i; + +protected: + void readCRNG(Common::IFFChunk &chunk) { + _range[_i]._timer = chunk.readUint16BE(); + _range[_i]._step = chunk.readUint16BE(); + _range[_i]._flags = chunk.readUint16BE(); + _range[_i]._first = chunk.readByte(); + _range[_i]._last = chunk.readByte(); + + _i++; + } + +public: + BackgroundDecoder(Common::ReadStream &input, Graphics::Surface &surface, byte *&colors, PaletteFxRange *range) : + Graphics::ILBMDecoder(input, surface, colors), _range(range), _i(0) { + } + + void decode() { + Common::IFFChunk *chunk; + while ((chunk = nextChunk()) != 0) { + switch (chunk->id) { + case ID_BMHD: + readBMHD(*chunk); + break; + + case ID_CMAP: + readCMAP(*chunk); + break; + + case ID_BODY: + readBODY(*chunk); + break; + + case ID_CRNG: + readCRNG(*chunk); + break; + } + } + } + + uint32 getNumRanges() { + return _i; + } +}; + + +void AmigaDisk_ns::loadBackground(const char *name) { + + Common::SeekableReadStream *s = openArchivedFile(name, true); + + Graphics::Surface surf; + byte *pal; + BackgroundDecoder decoder(*s, surf, pal, _vm->_gfx->_palettefx); + decoder.decode(); + + for (uint32 i = 0; i < BASE_PALETTE_COLORS * 3; i++) + _vm->_gfx->_palette[i] = pal[i] >> 2; + free(pal); + _vm->_gfx->setPalette(_vm->_gfx->_palette); + _vm->_gfx->setBackground(static_cast(surf.pixels)); + surf.free(); + delete s; + + return; + +} + +void AmigaDisk_ns::loadMask(const char *name) { + + char path[PATH_LEN]; + sprintf(path, "%s.mask", name); + + Common::SeekableReadStream *s = openArchivedFile(path, false); + if (s == NULL) + return; // no errors if missing mask files: not every location has one + + s->seek(0x30, SEEK_SET); + + byte r, g, b; + for (uint i = 0; i < 4; i++) { + r = s->readByte(); + g = s->readByte(); + b = s->readByte(); + + _vm->_gfx->_bgLayers[i] = (((r << 4) & 0xF00) | (g & 0xF0) | (b >> 4)) & 0xFF; + +// printf("rgb = (%x, %x, %x) -> %x\n", r, g, b, _vm->_gfx->_bgLayers[i]); + } + + + s->seek(0x126, SEEK_SET); // HACK: skipping IFF/ILBM header should be done by analysis, not magic + Graphics::PackBitsReadStream stream(*s); + + byte *buf = (byte*)malloc(_vm->_screenMaskSize); + stream.read(buf, _vm->_screenMaskSize); + buildMask(buf); + _vm->_gfx->setMask(buf); + free(buf); + delete s; + + return; +} + +void AmigaDisk_ns::loadPath(const char *name) { + + char path[PATH_LEN]; + sprintf(path, "%s.path", name); + + Common::SeekableReadStream *s = openArchivedFile(path, false); + if (s == NULL) + return; // no errors if missing path files: not every location has one + + + s->seek(0x120, SEEK_SET); // HACK: skipping IFF/ILBM header should be done by analysis, not magic + + Graphics::PackBitsReadStream stream(*s); + byte *buf = (byte*)malloc(_vm->_screenPathSize); + stream.read(buf, _vm->_screenPathSize); + _vm->setPath(buf); + free(buf); + delete s; + + return; +} + +void AmigaDisk_ns::loadScenery(const char* background, const char* mask) { + debugC(1, kDebugDisk, "AmigaDisk_ns::loadScenery '%s', '%s'", background, mask); + + char path[PATH_LEN]; + sprintf(path, "%s.bkgnd", background); + + loadBackground(path); + loadMask(background); + loadPath(background); + + return; +} + +void AmigaDisk_ns::loadSlide(const char *name) { + debugC(1, kDebugDisk, "AmigaDisk_ns::loadSlide '%s'", name); + + char path[PATH_LEN]; + sprintf(path, "slides/%s", name); + Common::SeekableReadStream *s = openArchivedFile(path, false); + if (s) + loadBackground(path); + else + loadBackground(name); + + return; +} + +Cnv* AmigaDisk_ns::loadFrames(const char* name) { + debugC(1, kDebugDisk, "AmigaDisk_ns::loadFrames '%s'", name); + + Common::SeekableReadStream *s; + + char path[PATH_LEN]; + sprintf(path, "anims/%s", name); + + s = openArchivedFile(path, false); + if (!s) + s = openArchivedFile(name, true); + + Cnv *cnv = makeCnv(*s); + delete s; + + return cnv; +} + +StaticCnv* AmigaDisk_ns::loadHead(const char* name) { + debugC(1, kDebugDisk, "AmigaDisk_ns::loadHead '%s'", name); + + char path[PATH_LEN]; + sprintf(path, "%s.head", name); + + Common::SeekableReadStream *s = openArchivedFile(path, true); + StaticCnv *cnv = makeStaticCnv(*s); + + delete s; + + return cnv; +} + + +Cnv* AmigaDisk_ns::loadObjects(const char *name) { + debugC(1, kDebugDisk, "AmigaDisk_ns::loadObjects"); + + char path[PATH_LEN]; + if (_vm->getFeatures() & GF_DEMO) + sprintf(path, "%s.objs", name); + else + sprintf(path, "objs/%s.objs", name); + + Common::SeekableReadStream *s = openArchivedFile(path, true); + + Cnv *cnv = makeCnv(*s); + delete s; + + return cnv; +} + + +Cnv* AmigaDisk_ns::loadTalk(const char *name) { + debugC(1, kDebugDisk, "AmigaDisk_ns::loadTalk '%s'", name); + + Common::SeekableReadStream *s; + + char path[PATH_LEN]; + if (_vm->getFeatures() & GF_DEMO) + sprintf(path, "%s.talk", name); + else + sprintf(path, "talk/%s.talk", name); + + s = openArchivedFile(path, false); + if (s == NULL) { + s = openArchivedFile(name, true); + } + + Cnv *cnv = makeCnv(*s); + delete s; + + return cnv; +} + +Table* AmigaDisk_ns::loadTable(const char* name) { + debugC(1, kDebugDisk, "AmigaDisk_ns::loadTable '%s'", name); + + char path[PATH_LEN]; + sprintf(path, "%s.table", name); + + bool dispose = false; + + Common::SeekableReadStream *stream; + + if (!scumm_stricmp(name, "global")) { + Common::File *s = new Common::File; + if (!s->open(path)) + errorFileNotFound(path); + + dispose = true; + stream = s; + } else { + if (!(_vm->getFeatures() & GF_DEMO)) + sprintf(path, "objs/%s.table", name); + if (!_resArchive.openArchivedFile(path)) + errorFileNotFound(path); + + stream = &_resArchive; + } + + Table *t = new Table(100); + + fillBuffers(*stream); + while (scumm_stricmp(_tokens[0], "ENDTABLE")) { + t->addData(_tokens[0]); + fillBuffers(*stream); + } + + if (dispose) + delete stream; + + return t; +} + +Font* AmigaDisk_ns::loadFont(const char* name) { + debugC(1, kDebugDisk, "AmigaFullDisk::loadFont '%s'", name); + + char path[PATH_LEN]; + sprintf(path, "%sfont", name); + + if (_vm->getFeatures() & GF_LANG_IT) { + // Italian version has separate font files + Common::File stream; + if (!stream.open(path)) + errorFileNotFound(path); + + return createFont(name, stream); + } else { + if (!_resArchive.openArchivedFile(path)) + errorFileNotFound(path); + + return createFont(name, _resArchive); + } +} + + +Common::ReadStream* AmigaDisk_ns::loadMusic(const char* name) { + return openArchivedFile(name); +} + +Common::ReadStream* AmigaDisk_ns::loadSound(const char* name) { + char path[PATH_LEN]; + sprintf(path, "%s.snd", name); + + openArchivedFile(path); + + return new DummyArchiveStream(_resArchive); +} + +} // namespace Parallaction diff --git a/engines/parallaction/font.cpp b/engines/parallaction/font.cpp index 3bc7835888..ee624b083c 100644 --- a/engines/parallaction/font.cpp +++ b/engines/parallaction/font.cpp @@ -408,7 +408,7 @@ void AmigaFont::drawString(byte *buffer, uint32 pitch, const char *s) { } -Font *DosDisk::createFont(const char *name, Cnv* cnv) { +Font *DosDisk_ns::createFont(const char *name, Cnv* cnv) { Font *f = 0; if (!scumm_stricmp(name, "comic")) @@ -425,7 +425,7 @@ Font *DosDisk::createFont(const char *name, Cnv* cnv) { return f; } -Font *AmigaDisk::createFont(const char *name, Common::SeekableReadStream &stream) { +Font *AmigaDisk_ns::createFont(const char *name, Common::SeekableReadStream &stream) { // TODO: implement AmigaLabelFont for labels return new AmigaFont(stream); } diff --git a/engines/parallaction/module.mk b/engines/parallaction/module.mk index 97741673a3..a94f197cee 100644 --- a/engines/parallaction/module.mk +++ b/engines/parallaction/module.mk @@ -7,7 +7,8 @@ MODULE_OBJS := \ debug.o \ detection.o \ dialogue.o \ - disk.o \ + disk_br.o \ + disk_ns.o \ font.o \ graphics.o \ intro.o \ diff --git a/engines/parallaction/parallaction.cpp b/engines/parallaction/parallaction.cpp index ca6ed73aa4..70f1de9f4a 100644 --- a/engines/parallaction/parallaction.cpp +++ b/engines/parallaction/parallaction.cpp @@ -191,17 +191,24 @@ int Parallaction::init() { _screenMaskSize = _screenMaskWidth * _screenHeight; _screenPathSize = _screenPathWidth * _screenHeight; - - - if (getPlatform() == Common::kPlatformPC) { - _disk = new DosDisk(this); - } else { - if (getFeatures() & GF_DEMO) { - strcpy(_location._name, "fognedemo"); + if (getGameType() == GType_Nippon) { + if (getPlatform() == Common::kPlatformPC) { + _disk = new DosDisk_ns(this); + } else { + if (getFeatures() & GF_DEMO) { + strcpy(_location._name, "fognedemo"); + } + _disk = new AmigaDisk_ns(this); + _disk->selectArchive((_vm->getFeatures() & GF_DEMO) ? "disk0" : "disk1"); } - _disk = new AmigaDisk(this); - _disk->selectArchive((_vm->getFeatures() & GF_DEMO) ? "disk0" : "disk1"); - } + } else + if (getGameType() == GType_BRA) { + if (getPlatform() == Common::kPlatformPC) { + _disk = new DosDisk_br(this); + } else + error("unsupported platform for Big Red Adventure"); + } else + error("unknown game type"); _engineFlags = 0; diff --git a/engines/parallaction/walk.cpp b/engines/parallaction/walk.cpp index 5d2d005e9f..fd2fa8d186 100644 --- a/engines/parallaction/walk.cpp +++ b/engines/parallaction/walk.cpp @@ -41,7 +41,7 @@ static uint16 walkData2 = 0; // next walk frame uint16 queryPath(uint16 x, uint16 y) { // NOTE: a better solution would have us mirror each byte in the mask in the loading routine - // AmigaDisk::loadPath() instead of doing it here. + // AmigaDisk_ns::loadPath() instead of doing it here. byte _al = _buffer[y*40 + x/8]; byte _dl = (_vm->getPlatform() == Common::kPlatformPC) ? (x & 7) : (7 - (x & 7)); -- cgit v1.2.3