/* 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 "common/fs.h" #include "common/config-manager.h" #include "prince/prince.h" #include "prince/graphics.h" #include "prince/debugger.h" #include "prince/script.h" #include "prince/hero.h" #include "prince/resource.h" #include "prince/archive.h" namespace Prince { Common::SeekableReadStream *Resource::getDecompressedStream(Common::SeekableReadStream *stream) { if (!(((PrinceEngine *)g_engine)->getFeatures() & GF_EXTRACTED)) return stream; byte header[4]; stream->read(header, 4); stream->seek(0); if (READ_BE_UINT32(header) == MKTAG('M', 'A', 'S', 'M')) { byte *buffer = (byte *)malloc(stream->size()); stream->read(buffer, stream->size()); Decompressor dec; uint32 decompLen = READ_BE_UINT32(buffer + 14); byte *decompData = (byte *)malloc(decompLen); dec.decompress(buffer + 18, decompData, decompLen); free(buffer); debug(8, "Resource::getDecompressedStream: decompressed %d to %d bytes", stream->size(), decompLen); return new Common::MemoryReadStream(decompData, decompLen, DisposeAfterUse::YES); } else { return stream; } } bool AnimListItem::loadFromStream(Common::SeekableReadStream &stream) { int32 pos = stream.pos(); uint16 type = stream.readUint16LE(); if (type == 0xFFFF) { return false; } _type = type; _fileNumber = stream.readUint16LE(); _startPhase = stream.readUint16LE(); _endPhase = stream.readUint16LE(); _loopPhase = stream.readUint16LE(); _x = stream.readSint16LE(); _y = stream.readSint16LE(); _loopType = stream.readUint16LE(); _nextAnim = stream.readUint16LE(); _flags = stream.readUint16LE(); debug(7, "AnimListItem type %d, fileNumber %d, x %d, y %d, flags %d", _type, _fileNumber, _x, _y, _flags); debug(7, "startPhase %d, endPhase %d, loopPhase %d", _startPhase, _endPhase, _loopPhase); // 32 byte aligment stream.seek(pos + 32); return true; } bool PrinceEngine::loadLocation(uint16 locationNr) { blackPalette(); _flicPlayer.close(); memset(_textSlots, 0, sizeof(_textSlots)); freeAllSamples(); debugEngine("PrinceEngine::loadLocation %d", locationNr); const Common::FSNode gameDataDir(ConfMan.get("path")); SearchMan.remove(Common::String::format("%02d", _locationNr)); _locationNr = locationNr; _debugger->_locationNr = locationNr; _flags->setFlagValue(Flags::CURRROOM, _locationNr); _interpreter->stopBg(); changeCursor(0); const Common::String locationNrStr = Common::String::format("%02d", _locationNr); debugEngine("loadLocation %s", locationNrStr.c_str()); if (!(getFeatures() & GF_EXTRACTED)) { PtcArchive *locationArchive = new PtcArchive(); if (!locationArchive->open(locationNrStr + "/databank.ptc")) error("Can't open location %s", locationNrStr.c_str()); SearchMan.add(locationNrStr, locationArchive); } else { SearchMan.addSubDirectoryMatching(gameDataDir, locationNrStr); } loadMusic(_locationNr); // load location background, replace old one Resource::loadResource(_roomBmp, "room", true); if (_roomBmp->getSurface()) { _sceneWidth = _roomBmp->getSurface()->w; } loadZoom(_zoomBitmap, kZoomBitmapLen, "zoom"); loadShadow(_shadowBitmap, kShadowBitmapSize, "shadow", "shadow2"); loadTrans(_transTable, "trans"); loadPath("path"); for (uint32 i = 0; i < _pscrList.size(); i++) { delete _pscrList[i]; } _pscrList.clear(); Resource::loadResource(_pscrList, "pscr.lst", false); loadMobPriority("mobpri"); _mobList.clear(); if (getGameType() == kPrinceDataDE) { const Common::String mobLstName = Common::String::format("mob%02d.lst", _locationNr); debug(3, "moblist name: %s", mobLstName.c_str()); Resource::loadResource(_mobList, mobLstName.c_str(), false); } else if (getGameType() == kPrinceDataPL) { Resource::loadResource(_mobList, "mob.lst", false); } if (getFeatures() & GF_TRANSLATED) { // update Mob texts for translated version setMobTranslationTexts(); } _animList.clear(); Resource::loadResource(_animList, "anim.lst", false); for (uint32 i = 0; i < _objList.size(); i++) { delete _objList[i]; } _objList.clear(); Resource::loadResource(_objList, "obj.lst", false); _room->loadRoom(_script->getRoomOffset(_locationNr)); for (uint i = 0; i < _maskList.size(); i++) { free(_maskList[i]._data); } _maskList.clear(); _script->loadAllMasks(_maskList, _room->_nak); _picWindowX = 0; _lightX = _script->getLightX(_locationNr); _lightY = _script->getLightY(_locationNr); setShadowScale(_script->getShadowScale(_locationNr)); for (uint i = 0; i < _mobList.size(); i++) { _mobList[i]._visible = _script->getMobVisible(_room->_mobs, i); } _script->installObjects(_room->_obj); freeAllNormAnims(); clearBackAnimList(); _script->installBackAnims(_backAnimList, _room->_backAnim); _graph->makeShadowTable(70, _graph->_shadowTable70); _graph->makeShadowTable(50, _graph->_shadowTable50); _mainHero->freeOldMove(); _secondHero->freeOldMove(); _mainHero->scrollHero(); return true; } bool PrinceEngine::loadAnim(uint16 animNr, bool loop) { Common::String streamName = Common::String::format("AN%02d", animNr); Common::SeekableReadStream *flicStream = SearchMan.createReadStreamForMember(streamName); if (!flicStream) { error("Can't open %s", streamName.c_str()); return false; } flicStream = Resource::getDecompressedStream(flicStream); if (!_flicPlayer.loadStream(flicStream)) { error("Can't load flic stream %s", streamName.c_str()); } debugEngine("%s loaded", streamName.c_str()); _flicLooped = loop; _flicPlayer.start(); playNextFLCFrame(); return true; } bool PrinceEngine::loadZoom(byte *zoomBitmap, uint32 dataSize, const char *resourceName) { Common::SeekableReadStream *stream = SearchMan.createReadStreamForMember(resourceName); if (!stream) { delete stream; return false; } stream = Resource::getDecompressedStream(stream); if (stream->read(zoomBitmap, dataSize) != dataSize) { free(zoomBitmap); delete stream; return false; } delete stream; return true; } bool PrinceEngine::loadShadow(byte *shadowBitmap, uint32 dataSize, const char *resourceName1, const char *resourceName2) { Common::SeekableReadStream *stream = SearchMan.createReadStreamForMember(resourceName1); if (!stream) { delete stream; return false; } stream = Resource::getDecompressedStream(stream); if (stream->read(shadowBitmap, dataSize) != dataSize) { free(shadowBitmap); delete stream; return false; } Common::SeekableReadStream *stream2 = SearchMan.createReadStreamForMember(resourceName2); if (!stream2) { delete stream; delete stream2; return false; } stream2 = Resource::getDecompressedStream(stream2); byte *shadowBitmap2 = shadowBitmap + dataSize; if (stream2->read(shadowBitmap2, dataSize) != dataSize) { free(shadowBitmap); delete stream; delete stream2; return false; } delete stream; delete stream2; return true; } bool PrinceEngine::loadTrans(byte *transTable, const char *resourceName) { Common::SeekableReadStream *stream = SearchMan.createReadStreamForMember(resourceName); if (!stream) { delete stream; for (int i = 0; i < 256; i++) { for (int j = 0; j < 256; j++) { transTable[i * 256 + j] = j; } } return true; } stream = Resource::getDecompressedStream(stream); if (stream->read(transTable, kTransTableSize) != kTransTableSize) { delete stream; return false; } delete stream; return true; } bool PrinceEngine::loadPath(const char *resourceName) { Common::SeekableReadStream *stream = SearchMan.createReadStreamForMember(resourceName); if (!stream) { delete stream; return false; } stream = Resource::getDecompressedStream(stream); if (stream->read(_roomPathBitmap, kPathBitmapLen) != kPathBitmapLen) { delete stream; return false; } delete stream; return true; } bool PrinceEngine::loadAllInv() { for (int i = 0; i < kMaxInv; i++) { InvItem tempInvItem; const Common::String invStreamName = Common::String::format("INV%02d", i); Common::SeekableReadStream *invStream = SearchMan.createReadStreamForMember(invStreamName); if (!invStream) { delete invStream; return true; } invStream = Resource::getDecompressedStream(invStream); tempInvItem._x = invStream->readUint16LE(); tempInvItem._y = invStream->readUint16LE(); int width = invStream->readUint16LE(); int height = invStream->readUint16LE(); tempInvItem._surface = new Graphics::Surface(); tempInvItem._surface->create(width, height, Graphics::PixelFormat::createFormatCLUT8()); for (int h = 0; h < tempInvItem._surface->h; h++) { invStream->read(tempInvItem._surface->getBasePtr(0, h), tempInvItem._surface->w); } _allInvList.push_back(tempInvItem); delete invStream; } return true; } bool PrinceEngine::loadMobPriority(const char *resourceName) { Common::SeekableReadStream *stream = SearchMan.createReadStreamForMember(resourceName); if (!stream) { delete stream; return false; } stream = Resource::getDecompressedStream(stream); _mobPriorityList.clear(); uint mobId; while (1) { mobId = stream->readUint32LE(); if (mobId == 0xFFFFFFFF) { break; } _mobPriorityList.push_back(mobId); } delete stream; return true; } } // End of namespace Prince