diff options
Diffstat (limited to 'engines/cryo/resource.cpp')
-rw-r--r-- | engines/cryo/resource.cpp | 555 |
1 files changed, 555 insertions, 0 deletions
diff --git a/engines/cryo/resource.cpp b/engines/cryo/resource.cpp new file mode 100644 index 0000000000..7698de0906 --- /dev/null +++ b/engines/cryo/resource.cpp @@ -0,0 +1,555 @@ +/* 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. + * + */ + +#include "cryo/defs.h" +#include "cryo/cryo.h" +#include "cryo/platdefs.h" +#include "cryo/cryolib.h" +#include "cryo/eden.h" +#include "cryo/sound.h" + +namespace Cryo { + +#define CRYO_DAT_VER 1 // 32-bit integer + +// Original name: prechargephrases +void EdenGame::preloadDialogs(int16 vid) { + perso_t *perso = &_persons[PER_MORKUS]; + if (vid == 170) + perso = &_persons[PER_UNKN_156]; + _globals->_characterPtr = perso; + _globals->_dialogType = DialogType::dtInspect; + int num = (perso->_id << 3) | _globals->_dialogType; + Dialog *dial = (Dialog *)getElem(_gameDialogs, num); + dialoscansvmas(dial); +} + +////// datfile.c +void EdenGame::verifh(byte *ptr) { + byte sum = 0; + byte *head = ptr; + + for (int8 i = 0; i < 6; i++) + sum += *head++; + + if (sum != 0xAB) + return; + + debug("* Begin unpacking resource"); + head -= 6; + uint16 h0 = READ_LE_UINT16(head); + // 3 = 2 bytes for the uint16 and 1 byte for an unused char + head += 3; + uint16 h3 = READ_LE_UINT16(head); + head += 2; + byte *data = h0 + head + 26; + h3 -= 6; + head += h3; + for (; h3; h3--) + *data-- = *head--; + head = data + 1; + data = ptr; + expandHSQ(head, data); +} + +void EdenGame::openbigfile() { + _bigfile.open("EDEN.DAT"); + + char buf[16]; + int count = _bigfile.readUint16LE(); + _bigfileHeader = new PakHeaderNode(count); + for (int j = 0; j < count; j++) { + for (int k = 0; k < 16; k++) + buf[k] = _bigfile.readByte(); + _bigfileHeader->_files[j]._name = Common::String(buf); + _bigfileHeader->_files[j]._size = _bigfile.readUint32LE(); + _bigfileHeader->_files[j]._offs = _bigfile.readUint32LE(); + _bigfileHeader->_files[j]._flag = _bigfile.readByte(); + } + + _vm->_video->resetInternals(); + _vm->_video->setFile(&_bigfile); +} + +void EdenGame::closebigfile() { + _bigfile.close(); +} + +int EdenGame::loadmusicfile(int16 num) { + PakHeaderItem *file = &_bigfileHeader->_files[num + 435]; + int32 size = file->_size; + int32 offs = file->_offs; + _bigfile.seek(offs, SEEK_SET); + uint32 numread = size; + if (numread > kMaxMusicSize) + error("Music file %s is too big", file->_name.c_str()); + _bigfile.read(_musicBuf, numread); + return size; +} + +void EdenGame::loadRawFile(uint16 num, byte *buffer) { + if (_vm->getPlatform() == Common::kPlatformDOS) { + if ((_vm->isDemo() && num > 2204) || num > 2472) + error("Trying to read invalid game resource"); + } + + assert(num < _bigfileHeader->_count); + PakHeaderItem *file = &_bigfileHeader->_files[num]; + int32 size = file->_size; + int32 offs = file->_offs; + + _bigfile.seek(offs, SEEK_SET); + _bigfile.read(buffer, size); +} + +void EdenGame::loadIconFile(uint16 num, Icon *buffer) { + if (_vm->getPlatform() == Common::kPlatformDOS) { + if ((_vm->isDemo() && num > 2204) || num > 2472) + error("Trying to read invalid game resource"); + } + + assert(num < _bigfileHeader->_count); + PakHeaderItem *file = &_bigfileHeader->_files[num]; + int32 size = file->_size; + int32 offs = file->_offs; + debug("* Loading icon - Resource %d (%s) at 0x%X, %d bytes", num, file->_name.c_str(), offs, size); + _bigfile.seek(offs, SEEK_SET); + + int count = size / 18; // sizeof(Icon) + for (int i = 0; i < count; i++) { + if (_vm->getPlatform() == Common::kPlatformMacintosh) { + buffer[i].sx = _bigfile.readSint16BE(); + buffer[i].sy = _bigfile.readSint16BE(); + buffer[i].ex = _bigfile.readSint16BE(); + buffer[i].ey = _bigfile.readSint16BE(); + buffer[i]._cursorId = _bigfile.readUint16BE();; + buffer[i]._actionId = _bigfile.readUint32BE();; + buffer[i]._objectId = _bigfile.readUint32BE();; + } + else { + buffer[i].sx = _bigfile.readSint16LE(); + buffer[i].sy = _bigfile.readSint16LE(); + buffer[i].ex = _bigfile.readSint16LE(); + buffer[i].ey = _bigfile.readSint16LE(); + buffer[i]._cursorId = _bigfile.readUint16LE();; + buffer[i]._actionId = _bigfile.readUint32LE();; + buffer[i]._objectId = _bigfile.readUint32LE();; + } + } +} + +void EdenGame::loadRoomFile(uint16 num, Room *buffer) { + if (_vm->getPlatform() == Common::kPlatformDOS) { + if ((_vm->isDemo() && num > 2204) || num > 2472) + error("Trying to read invalid game resource"); + } + + assert(num < _bigfileHeader->_count); + PakHeaderItem *file = &_bigfileHeader->_files[num]; + int32 size = file->_size; + int32 offs = file->_offs; + debug("* Loading room - Resource %d (%s) at 0x%X, %d bytes", num, file->_name.c_str(), offs, size); + _bigfile.seek(offs, SEEK_SET); + + int count = size / 14; // sizeof(Room) + for (int i = 0; i < count; i++) { + buffer[i]._id = _bigfile.readByte(); + for (int j = 0; j < 4; j++) + buffer[i]._exits[j] = _bigfile.readByte(); + buffer[i]._flags = _bigfile.readByte(); + if (_vm->getPlatform() == Common::kPlatformMacintosh) { + buffer[i]._bank = _bigfile.readUint16BE(); + buffer[i]._party = _bigfile.readUint16BE(); + } + else { + buffer[i]._bank = _bigfile.readUint16LE(); + buffer[i]._party = _bigfile.readUint16LE(); + } + buffer[i]._level = _bigfile.readByte(); + buffer[i]._video = _bigfile.readByte(); + buffer[i]._location = _bigfile.readByte(); + buffer[i]._backgroundBankNum = _bigfile.readByte(); + } +} + +// Original name: shnmfl +void EdenGame::loadHnm(uint16 num) { + unsigned int resNum = num - 1 + 485; + assert(resNum < _bigfileHeader->_count); + PakHeaderItem *file = &_bigfileHeader->_files[resNum]; + int size = file->_size; + int offs = file->_offs; + debug("* Loading movie %d (%s) at 0x%X, %d bytes", num, file->_name.c_str(), (uint)offs, size); + _vm->_video->_file->seek(offs, SEEK_SET); +} + +// Original name: ssndfl +int EdenGame::loadSound(uint16 num) { + unsigned int resNum = num - 1 + ((_vm->getPlatform() == Common::kPlatformDOS && _vm->isDemo()) ? 656 : 661); + assert(resNum < _bigfileHeader->_count); + PakHeaderItem *file = &_bigfileHeader->_files[resNum]; + int32 size = file->_size; + int32 offs = file->_offs; + debug("* Loading sound %d (%s) at 0x%X, %d bytes", num, file->_name.c_str(), (uint)offs, size); + if (_soundAllocated) { + free(_voiceSamplesBuffer); + _voiceSamplesBuffer = nullptr; + _soundAllocated = false; //TODO: bug??? no alloc + } + else { + _voiceSamplesBuffer = (byte *)malloc(size); + _soundAllocated = true; + } + + _bigfile.seek(offs, SEEK_SET); + //For PC loaded data is a VOC file, on Mac version this is a raw samples + if (_vm->getPlatform() == Common::kPlatformMacintosh) + _bigfile.read(_voiceSamplesBuffer, size); + else { + // VOC files also include extra information for lipsync + // 1. Standard VOC header + _bigfile.read(_voiceSamplesBuffer, 0x1A); + + // 2. Lipsync? + unsigned char chunkType = _bigfile.readByte(); + + uint32 val = 0; + _bigfile.read(&val, 3); + unsigned int chunkLen = LE32(val); + + if (chunkType == 5) { + _bigfile.read(_gameLipsync + 7260, chunkLen); + chunkType = _bigfile.readByte(); + _bigfile.read(&val, 3); + chunkLen = LE32(val); + } + + // 3. Normal sound data + if (chunkType == 1) { + _bigfile.readUint16LE(); + size = chunkLen - 2; + _bigfile.read(_voiceSamplesBuffer, size); + } + } + + return size; +} + +void EdenGame::convertMacToPC() { + // Convert all mac (big-endian) resources to native format + // Array of longs + int *p = (int *)_gameLipsync; + for (int i = 0; i < 7240 / 4; i++) + p[i] = BE32(p[i]); +} + +void EdenGame::loadpermfiles() { + Common::File f; + const int kNumIcons = 136; + const int kNumRooms = 424; + const int kNumFollowers = 15; + const int kNumLabyrinthPath = 70; + const int kNumDinoSpeedForCitaLevel = 16; + const int kNumTabletView = 12; + const int kNumPersoRoomBankTable = 84; + const int kNumGotos = 130; + const int kNumObjects = 42; + const int kNumObjectLocations = 45; + const int kNumPersons = 58; + const int kNumCitadel = 7; + const int kNumCharacterRects = 19; + const int kNumCharacters = 20; + const int kNumAreas = 12; + // tab_2CEF0 + // tab_2CF70 + const int kNumActionCursors = 299; + + const int expectedDataSize = + kNumIcons * 18 + // sizeof(Icon) + kNumRooms * 14 + // sizeof(Room) + kNumFollowers * 16 + // sizeof(Follower) + kNumLabyrinthPath + + kNumDinoSpeedForCitaLevel + + kNumTabletView + + kNumPersoRoomBankTable + + kNumGotos * 5 + // sizeof(Goto) + kNumObjects * 12 + // sizeof(object_t) + kNumObjectLocations * 2 + + kNumPersons * 18 + // sizeof(perso_t) + kNumCitadel * 34 + // sizeof(Citadel) + kNumCharacterRects * 8 + + kNumCharacters * 5 + + kNumAreas * 10 + // (sizeof(Area) - 4) + 64 * 2 + + 64 * 2 + + kNumActionCursors + + 12 + + 3 * 6 * 2 * 3 * 2; + + if (f.open("cryo.dat")) { + const int dataSize = f.size() - 8 - 4; // CRYODATA + version + char headerId[9]; + + f.read(headerId, 8); + headerId[8] = '\0'; + if (strcmp(headerId, "CRYODATA")) + error("Invalid cryo.dat aux data file"); + + if (f.readUint32LE() != CRYO_DAT_VER) + error("Incorrect data version for cryo.dat"); + + if (dataSize != expectedDataSize) + error("Mismatching data in cryo.dat aux data file (got %d, expected %d)", dataSize, expectedDataSize); + } + else + error("Can not load cryo.dat"); + + switch (_vm->getPlatform()) { + case Common::kPlatformDOS: + // Since PC version stores hotspots and rooms info in the executable, load them from premade resource file + for (int i = 0; i < kNumIcons; i++) { + _gameIcons[i].sx = f.readSint16LE(); + _gameIcons[i].sy = f.readSint16LE(); + _gameIcons[i].ex = f.readSint16LE(); + _gameIcons[i].ey = f.readSint16LE(); + _gameIcons[i]._cursorId = f.readUint16LE(); + _gameIcons[i]._actionId = f.readUint32LE(); + _gameIcons[i]._objectId = f.readUint32LE(); + } + + for (int i = 0; i < kNumRooms; i++) { + _gameRooms[i]._id = f.readByte(); + for (int j = 0; j < 4; j++) + _gameRooms[i]._exits[j] = f.readByte(); + _gameRooms[i]._flags = f.readByte(); + _gameRooms[i]._bank = f.readUint16LE(); + _gameRooms[i]._party = f.readUint16LE(); + _gameRooms[i]._level = f.readByte(); + _gameRooms[i]._video = f.readByte(); + _gameRooms[i]._location = f.readByte(); + _gameRooms[i]._backgroundBankNum = f.readByte(); + } + break; + case Common::kPlatformMacintosh: + loadIconFile(2498, _gameIcons); + loadRoomFile(2497, _gameRooms); + loadRawFile(2486, _gameLipsync); + convertMacToPC(); + + // Skip the icons and rooms of the DOS version + f.skip(kNumIcons * 14 + kNumRooms * 11); + break; + default: + error("Unsupported platform"); + } + + // Read the common static data + + for (int i = 0; i < kNumFollowers; i++) { + _followerList[i]._id = f.readSByte(); + _followerList[i]._spriteNum = f.readSByte(); + _followerList[i].sx = f.readSint16LE(); + _followerList[i].sy = f.readSint16LE(); + _followerList[i].ex = f.readSint16LE(); + _followerList[i].ey = f.readSint16LE(); + _followerList[i]._spriteBank = f.readSint16LE(); + _followerList[i].ff_C = f.readSint16LE(); + _followerList[i].ff_E = f.readSint16LE(); + } + + f.read(_labyrinthPath, kNumLabyrinthPath); + f.read(_dinoSpeedForCitadelLevel, kNumDinoSpeedForCitaLevel); + f.read(_tabletView, kNumTabletView); + f.read(_personRoomBankTable, kNumPersoRoomBankTable); + f.read(_gotos, kNumGotos * 5); // sizeof(Goto) + + for (int i = 0; i < kNumObjects; i++) { + _objects[i]._id = f.readByte(); + _objects[i]._flags = f.readByte(); + _objects[i]._locations = f.readUint32LE(); + _objects[i]._itemMask = f.readUint16LE(); + _objects[i]._powerMask = f.readUint16LE(); + _objects[i]._count = f.readSint16LE(); + } + + for (int i = 0; i < kNumObjectLocations; i++) { + _objectLocations[i] = f.readUint16LE(); + } + + for (int i = 0; i < kNumPersons; i++) { + _persons[i]._roomNum = f.readUint16LE(); + _persons[i]._actionId = f.readUint16LE(); + _persons[i]._partyMask = f.readUint16LE(); + _persons[i]._id = f.readByte(); + _persons[i]._flags = f.readByte(); + _persons[i]._roomBankId = f.readByte(); + _persons[i]._spriteBank = f.readByte(); + _persons[i]._items = f.readUint16LE(); + _persons[i]._powers = f.readUint16LE(); + _persons[i]._targetLoc = f.readByte(); + _persons[i]._lastLoc = f.readByte(); + _persons[i]._speed = f.readByte(); + _persons[i]._steps = f.readByte(); + } + + for (int i = 0; i < kNumCitadel; i++) { + _citadelList[i]._id = f.readSint16LE(); + for (int j = 0; j < 8; j++) + _citadelList[i]._bank[j] = f.readSint16LE(); + for (int j = 0; j < 8; j++) + _citadelList[i]._video[j] = f.readSint16LE(); + } + + for (int i = 0; i < kNumCharacterRects; i++) { + _characterRects[i].left = f.readSint16LE(); + _characterRects[i].top = f.readSint16LE(); + _characterRects[i].right = f.readSint16LE(); + _characterRects[i].bottom = f.readSint16LE(); + } + + f.read(_characterArray, kNumCharacters * 5); + + for (int i = 0; i < kNumAreas; i++) { + _areasTable[i]._num = f.readByte(); + _areasTable[i]._type = f.readByte(); + _areasTable[i]._flags = f.readUint16LE(); + _areasTable[i]._firstRoomIdx = f.readUint16LE(); + _areasTable[i]._citadelLevel = f.readByte(); + _areasTable[i]._placeNum = f.readByte(); + _areasTable[i]._citadelRoomPtr = nullptr; + _areasTable[i]._visitCount = f.readSint16LE(); + } + + for (int i = 0; i < 64; i++) { + tab_2CEF0[i] = f.readSint16LE(); + } + + for (int i = 0; i < 64; i++) { + tab_2CF70[i] = f.readSint16LE(); + } + + f.read(_actionCursors, kNumActionCursors); + f.read(_mapMode, 12); + f.read(_cubeTextureCoords, 3 * 6 * 2 * 3 * 2); + + f.close(); + + loadRawFile(0, _mainBankBuf); + loadRawFile(402, _gameFont); + loadRawFile(404, _gameDialogs); + loadRawFile(403, _gameConditions); +} + +bool EdenGame::ReadDataSyncVOC(unsigned int num) { + unsigned int resNum = num - 1 + ((_vm->getPlatform() == Common::kPlatformDOS && _vm->isDemo()) ? 656 : 661); + unsigned char vocHeader[0x1A]; + int filePos = 0; + loadpartoffile(resNum, vocHeader, filePos, sizeof(vocHeader)); + filePos += sizeof(vocHeader); + unsigned char chunkType = 0; + loadpartoffile(resNum, &chunkType, sizeof(vocHeader), 1); + filePos++; + if (chunkType == 5) { + uint32 chunkLen = 0; + loadpartoffile(resNum, &chunkLen, filePos, 3); + filePos += 3; + chunkLen = LE32(chunkLen); + loadpartoffile(resNum, _gameLipsync + 7260, filePos, chunkLen); + return true; + } + return false; +} + +bool EdenGame::ReadDataSync(uint16 num) { + if (_vm->getPlatform() == Common::kPlatformMacintosh) { + long pos = READ_LE_UINT32(_gameLipsync + num * 4); + if (pos != -1) { + long len = 1024; + loadpartoffile(1936, _gameLipsync + 7260, pos, len); + return true; + } + } + else + return ReadDataSyncVOC(num + 1); //TODO: remove -1 in caller + return false; +} + +void EdenGame::loadpartoffile(uint16 num, void *buffer, int32 pos, int32 len) { + assert(num < _bigfileHeader->_count); + PakHeaderItem *file = &_bigfileHeader->_files[num]; + int32 offs = READ_LE_UINT32(&file->_offs); + debug("* Loading partial resource %d (%s) at 0x%X(+0x%X), %d bytes", num, file->_name.c_str(), offs, pos, len); + _bigfile.seek(offs + pos, SEEK_SET); + _bigfile.read(buffer, len); +} + +void EdenGame::expandHSQ(byte *input, byte *output) { + byte *src = input; + byte *dst = output; + byte *ptr; + uint16 bit; // bit + uint16 queue = 0; // queue + uint16 len = 0; + int16 ofs; +#define GetBit \ +bit = queue & 1; \ +queue >>= 1; \ +if (!queue) { \ + queue = (src[1] << 8) | src[0]; src += 2; \ + bit = queue & 1; \ + queue = (queue >> 1) | 0x8000; \ + } + + for (;;) { + GetBit; + if (bit) + *dst++ = *src++; + else { + len = 0; + GetBit; + if (!bit) { + GetBit; + len = (len << 1) | bit; + GetBit; + len = (len << 1) | bit; + ofs = 0xFF00 | *src++; //TODO: -256 + } + else { + ofs = (src[1] << 8) | src[0]; + src += 2; + len = ofs & 7; + ofs = (ofs >> 3) | 0xE000; + if (!len) { + len = *src++; + if (!len) + break; + } + } + ptr = dst + ofs; + len += 2; + while (len--) + *dst++ = *ptr++; + } + } +} + +} // namespace Cryo |