/* ScummVM - Graphic Adventure Engine * * ScummVM is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include "common/config-manager.h" #include "efh/efh.h" namespace Efh { int32 EfhEngine::readFileToBuffer(const Common::Path &filename, uint8 *destBuffer) { debugC(1, kDebugUtils, "readFileToBuffer %s", filename.toString().c_str()); Common::File f; if (!f.open(filename)) error("Unable to find file %s", filename.toString().c_str()); int size = f.size(); return f.read(destBuffer, size); } void EfhEngine::readAnimInfo() { debugC(6, kDebugEngine, "readAnimInfo"); Common::Path fileName("animinfo"); Common::File f; if (!f.open(fileName)) error("Unable to find file %s", fileName.toString().c_str()); for (int i = 0; i < 100; ++i) { for (int id = 0; id < 15; ++id) { Common::String txtBuffer = "->"; for (int frameId = 0; frameId < 4; ++frameId) { _animInfo[i]._frameList[id]._subFileId[frameId] = f.readByte(); txtBuffer += Common::String::format(" %d", _animInfo[i]._frameList[id]._subFileId[frameId]); } debugC(6, kDebugEngine, "%s", txtBuffer.c_str()); } Common::String debugStr = ""; for (int id = 0; id < 10; ++id) { _animInfo[i]._posY[id] = f.readByte(); debugStr += Common::String::format("%d ", _animInfo[i]._posY[id]); } debugC(6, kDebugEngine, "%s", debugStr.c_str()); debugStr = ""; for (int id = 0; id < 10; ++id) { _animInfo[i]._posX[id] = f.readUint16LE(); debugStr += Common::String::format("%d ", _animInfo[i]._posX[id]); } debugC(6, kDebugEngine, "%s", debugStr.c_str()); debugC(6, kDebugEngine, "---------"); } } void EfhEngine::findMapFile(int16 mapId) { debugC(7, kDebugEngine, "findMapFile %d", mapId); if (!_introDoneFl) return; Common::Path fileName(Common::String::format("map.%d", mapId)); Common::File f; // The original was checking for the file and eventually asking to change floppies if (!f.open(fileName)) error("File not found: %s", fileName.toString().c_str()); f.close(); } void EfhEngine::rImageFile(const Common::Path &filename, uint8 *targetBuffer, uint8 **subFilesArray, uint8 *packedBuffer) { debugC(1, kDebugUtils, "rImageFile %s", filename.toString().c_str()); readFileToBuffer(filename, packedBuffer); uint32 size = uncompressBuffer(packedBuffer, targetBuffer); if (ConfMan.getBool("dump_scripts")) { // dump a decompressed image file Common::DumpFile dump; dump.open(filename.append(".dump")); dump.write(targetBuffer, size); dump.flush(); dump.close(); // End of dump } // TODO: Refactoring: once uncompressed, the container contains for each image its width, its height, and raw data (4 Bpp) // => Write a class to handle that more properly uint8 *ptr = targetBuffer; uint16 counter = 0; while (READ_LE_INT16(ptr) != 0 && !shouldQuitGame()) { subFilesArray[counter] = ptr; ++counter; int16 imageWidth = READ_LE_INT16(ptr); ptr += 2; int16 imageHeight = READ_LE_INT16(ptr); ptr += 2; ptr += (imageWidth * imageHeight); } } void EfhEngine::readImpFile(int16 id, bool techMapFl) { debugC(6, kDebugEngine, "readImpFile %d %s", id, techMapFl ? "True" : "False"); Common::Path fileName(Common::String::format("imp.%d", id)); if (techMapFl) readFileToBuffer(fileName, _imp1); else readFileToBuffer(fileName, _imp2); decryptImpFile(techMapFl); } void EfhEngine::readItems() { debugC(7, kDebugEngine, "readItems"); Common::Path fileName("items"); Common::File f; if (!f.open(fileName)) error("Unable to find file %s", fileName.toString().c_str()); for (int i = 0; i < 300; ++i) { for (uint idx = 0; idx < 15; ++idx) _items[i]._name[idx] = f.readByte(); _items[i]._damage = f.readByte(); _items[i]._defense = f.readByte(); _items[i]._attacks = f.readByte(); _items[i]._uses = f.readByte(); _items[i]._agilityModifier = f.readByte(); _items[i]._range = f.readByte(); _items[i]._attackType = f.readByte(); _items[i]._specialEffect = f.readByte(); _items[i]._defenseType = f.readByte(); _items[i]._exclusiveType = f.readByte(); _items[i]._field19_mapPosX_or_maxDeltaPoints = f.readByte(); _items[i]._mapPosY = f.readByte(); debugC(7, kDebugEngine, "%s\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x", _items[i]._name, _items[i]._damage, _items[i]._defense, _items[i]._attacks, _items[i]._uses, _items[i]._agilityModifier, _items[i]._range, _items[i]._attackType, _items[i]._specialEffect, _items[i]._defenseType, _items[i]._exclusiveType, _items[i]._field19_mapPosX_or_maxDeltaPoints, _items[i]._mapPosY); } } void EfhEngine::loadNewPortrait() { debugC(7, kDebugEngine, "loadNewPortrait"); static int16 const unkConstRelatedToAnimImageSetId[19] = {0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2}; _unkRelatedToAnimImageSetId = unkConstRelatedToAnimImageSetId[_techId]; if (_currentAnimImageSetId == 200 + _unkRelatedToAnimImageSetId) return; findMapFile(_techId); _currentAnimImageSetId = 200 + _unkRelatedToAnimImageSetId; int imageSetId = _unkRelatedToAnimImageSetId + 13; loadImageSet(imageSetId, _portraitBuf, _portraitSubFilesArray, _decompBuf); } void EfhEngine::loadAnimImageSet() { debugC(3, kDebugEngine, "loadAnimImageSet"); if (_currentAnimImageSetId == _animImageSetId || _animImageSetId == 0xFF) return; findMapFile(_techId); _unkAnimRelatedIndex = 0; _currentAnimImageSetId = _animImageSetId; int16 animSetId = _animImageSetId + 17; loadImageSet(animSetId, _portraitBuf, _portraitSubFilesArray, _decompBuf); } void EfhEngine::loadHistory() { debugC(2, kDebugEngine, "loadHistory"); Common::Path fileName("history"); readFileToBuffer(fileName, _history); } void EfhEngine::loadTechMapImp(int16 fileId) { debugC(3, kDebugEngine, "loadTechMapImp %d", fileId); if (fileId == 0xFF) return; _techId = fileId; findMapFile(_techId); // The original was loading the specific tech.%d and map.%d files. // This is gone in our implementation as we pre-load all the files to save them inside the savegames // This is not present in the original. // The purpose is to properly load the misc map data in arrays in order to use them without being a pain afterwards loadMapArrays(_techId); loadImageSetToTileBank(0, _mapBitmapRefArr[_techId]._setId1); loadImageSetToTileBank(1, _mapBitmapRefArr[_techId]._setId2); initMapMonsters(); readImpFile(_techId, true); displayAnimFrames(0xFE, false); } void EfhEngine::loadPlacesFile(uint16 fullPlaceId, bool forceReloadFl) { debugC(2, kDebugEngine, "loadPlacesFile %d %s", fullPlaceId, forceReloadFl ? "True" : "False"); if (fullPlaceId == 0xFF) return; findMapFile(_techId); _fullPlaceId = fullPlaceId; uint16 minPlace = _lastMainPlaceId * 20; uint16 maxPlace = minPlace + 19; if (_fullPlaceId < minPlace || _fullPlaceId > maxPlace || forceReloadFl) { _lastMainPlaceId = _fullPlaceId / 20; Common::Path fileName(Common::String::format("places.%d", _lastMainPlaceId)); readFileToBuffer(fileName, _decompBuf); uncompressBuffer(_decompBuf, _places); } copyCurrentPlaceToBuffer(_fullPlaceId % 20); } void EfhEngine::readTileFact() { debugC(7, kDebugEngine, "readTileFact"); Common::Path fileName("tilefact"); Common::File f; if (!f.open(fileName)) error("Unable to find file %s", fileName.toString().c_str()); for (int i = 0; i < 432; ++i) { _tileFact[i]._status = f.readByte(); _tileFact[i]._tileId = f.readByte(); } } void EfhEngine::loadNPCS() { debugC(7, kDebugEngine, "loadNPCS"); Common::Path fileName("npcs"); Common::File f; if (!f.open(fileName)) error("Unable to find file %s", fileName.toString().c_str()); for (int i = 0; i < 99; ++i) { for (int idx = 0; idx < 11; ++idx) _npcBuf[i]._name[idx] = f.readByte(); _npcBuf[i].fieldB_textId = f.readByte(); _npcBuf[i].field_C = f.readByte(); _npcBuf[i].field_D = f.readByte(); _npcBuf[i].fieldE_textId = f.readByte(); _npcBuf[i].field_F = f.readByte(); _npcBuf[i].field_10 = f.readByte(); _npcBuf[i].field11_NpcId = f.readByte(); _npcBuf[i].field12_textId = f.readUint16LE(); _npcBuf[i].field14_textId = f.readUint16LE(); _npcBuf[i]._xp = f.readUint32LE(); for (int idx = 0; idx < 15; ++idx) { _npcBuf[i]._activeScore[idx] = f.readByte(); } for (int idx = 0; idx < 11; ++idx) { _npcBuf[i]._passiveScore[idx] = f.readByte(); } for (int idx = 0; idx < 11; ++idx) { _npcBuf[i]._infoScore[idx] = f.readByte(); } _npcBuf[i].field_3F = f.readByte(); _npcBuf[i].field_40 = f.readByte(); for (int idx = 0; idx < 10; ++idx) { _npcBuf[i]._inventory[idx]._ref = f.readSint16LE(); _npcBuf[i]._inventory[idx]._stat1 = f.readByte(); _npcBuf[i]._inventory[idx]._curHitPoints = f.readByte(); } _npcBuf[i]._possessivePronounSHL6 = f.readByte(); _npcBuf[i]._speed = f.readByte(); _npcBuf[i].field_6B = f.readByte(); _npcBuf[i].field_6C = f.readByte(); _npcBuf[i].field_6D = f.readByte(); _npcBuf[i]._defaultDefenseItemId = f.readByte(); _npcBuf[i].field_6F = f.readByte(); _npcBuf[i].field_70 = f.readByte(); _npcBuf[i].field_71 = f.readByte(); _npcBuf[i].field_72 = f.readByte(); _npcBuf[i].field_73 = f.readByte(); _npcBuf[i]._hitPoints = f.readSint16LE(); _npcBuf[i]._maxHP = f.readSint16LE(); _npcBuf[i].field_78 = f.readByte(); _npcBuf[i].field_79 = f.readUint16LE(); _npcBuf[i].field_7B = f.readUint16LE(); _npcBuf[i].field_7D = f.readByte(); _npcBuf[i].field_7E = f.readByte(); _npcBuf[i].field_7F = f.readByte(); _npcBuf[i].field_80 = f.readByte(); _npcBuf[i].field_81 = f.readByte(); _npcBuf[i].field_82 = f.readByte(); _npcBuf[i].field_83 = f.readByte(); _npcBuf[i].field_84 = f.readByte(); _npcBuf[i].field_85 = f.readByte(); } } /** * Pre-Loads MAP and TECH files. * This is required in order to implement a clean savegame feature */ void EfhEngine::preLoadMaps() { Common::DumpFile dump; if (ConfMan.getBool("dump_scripts")) dump.open("efhMaps.dump"); for (int idx = 0; idx < 19; ++idx) { Common::Path fileName(Common::String::format("tech.%d", idx)); readFileToBuffer(fileName, _decompBuf); uncompressBuffer(_decompBuf, _techDataArr[idx]); fileName = Common::Path(Common::String::format("map.%d", idx)); readFileToBuffer(fileName, _decompBuf); uncompressBuffer(_decompBuf, _mapArr[idx]); _mapBitmapRefArr[idx]._setId1 = _mapArr[idx][0]; _mapBitmapRefArr[idx]._setId2 = _mapArr[idx][1]; uint8 *mapSpecialTilePtr = &_mapArr[idx][2]; for (int i = 0; i < 100; ++i) { _mapSpecialTiles[idx][i]._placeId = mapSpecialTilePtr[9 * i]; _mapSpecialTiles[idx][i]._posX = mapSpecialTilePtr[9 * i + 1]; _mapSpecialTiles[idx][i]._posY = mapSpecialTilePtr[9 * i + 2]; _mapSpecialTiles[idx][i]._triggerType = mapSpecialTilePtr[9 * i + 3]; _mapSpecialTiles[idx][i]._triggerValue = mapSpecialTilePtr[9 * i + 4]; _mapSpecialTiles[idx][i]._field5_textId = READ_LE_UINT16(&mapSpecialTilePtr[9 * i + 5]); _mapSpecialTiles[idx][i]._field7_textId = READ_LE_UINT16(&mapSpecialTilePtr[9 * i + 7]); if (ConfMan.getBool("dump_scripts") && _mapSpecialTiles[idx][i]._placeId != 0xFF) { // dump a decoded version of the maps Common::String buffer = Common::String::format("[%d][%d] _ placeId: 0x%02X _pos: %d, %d _triggerType: 0x%02X (%d), triggerId: %d, _field5/7: %d %d\n" , idx, i, _mapSpecialTiles[idx][i]._placeId, _mapSpecialTiles[idx][i]._posX, _mapSpecialTiles[idx][i]._posX, _mapSpecialTiles[idx][i]._triggerType , _mapSpecialTiles[idx][i]._triggerType, _mapSpecialTiles[idx][i]._triggerValue, _mapSpecialTiles[idx][i]._field5_textId, _mapSpecialTiles[idx][i]._field7_textId); dump.write(buffer.c_str(), buffer.size()); } } uint8 *mapMonstersPtr = &_mapArr[idx][902]; for (int i = 0; i < 64; ++i) { _mapMonsters[idx][i]._possessivePronounSHL6 = mapMonstersPtr[29 * i]; _mapMonsters[idx][i]._npcId = mapMonstersPtr[29 * i + 1]; _mapMonsters[idx][i]._fullPlaceId = mapMonstersPtr[29 * i + 2]; _mapMonsters[idx][i]._posX = mapMonstersPtr[29 * i + 3]; _mapMonsters[idx][i]._posY = mapMonstersPtr[29 * i + 4]; _mapMonsters[idx][i]._weaponItemId = mapMonstersPtr[29 * i + 5]; _mapMonsters[idx][i]._maxDamageAbsorption = mapMonstersPtr[29 * i + 6]; _mapMonsters[idx][i]._monsterRef = mapMonstersPtr[29 * i + 7]; _mapMonsters[idx][i]._additionalInfo = mapMonstersPtr[29 * i + 8]; _mapMonsters[idx][i]._talkTextId = mapMonstersPtr[29 * i + 9]; _mapMonsters[idx][i]._groupSize = mapMonstersPtr[29 * i + 10]; for (int j = 0; j < 9; ++j) _mapMonsters[idx][i]._hitPoints[j] = READ_LE_INT16(&mapMonstersPtr[29 * i + 11 + j * 2]); } uint8 *mapPtr = &_mapArr[idx][2758]; for (int i = 0; i < 64; ++i) { for (int j = 0; j < 64; ++j) _mapGameMaps[idx][i][j] = *mapPtr++; } } if (ConfMan.getBool("dump_scripts")) { dump.flush(); dump.close(); } } } // End of namespace Efh