diff --git a/engines/zvision/actions.cpp b/engines/zvision/actions.cpp index 5d1dc9a60812..7b9050f47ad6 100644 --- a/engines/zvision/actions.cpp +++ b/engines/zvision/actions.cpp @@ -312,27 +312,11 @@ ActionMusic::~ActionMusic() { bool ActionMusic::execute() { if (_engine->getScriptManager()->getSideFX(_slotkey)) return true; - Common::File *file = new Common::File(); - if (!file->exists(_fileName) && _fileName.size() >= 12) { - _fileName.setChar('r', 9); - _fileName.setChar('a', 10); - _fileName.setChar('w', 11); - if (!file->exists(_fileName)) { - _fileName.setChar('i', 9); - _fileName.setChar('f', 10); - _fileName.setChar('p', 11); - if (!file->exists(_fileName)) { - _fileName.setChar('s', 9); - _fileName.setChar('r', 10); - _fileName.setChar('c', 11); - if (!file->exists(_fileName)) - return true; - } - } - } - if (file->exists(_fileName)) - _engine->getScriptManager()->addSideFX(new MusicNode(_engine, _slotkey, _fileName, _loop, _volume)); - delete file; + + if (!_engine->getSearchManager()->hasFile(_fileName)) + return true; + + _engine->getScriptManager()->addSideFX(new MusicNode(_engine, _slotkey, _fileName, _loop, _volume)); return true; } @@ -585,16 +569,21 @@ ActionStreamVideo::ActionStreamVideo(ZVision *engine, int32 slotkey, const Commo bool ActionStreamVideo::execute() { ZorkAVIDecoder decoder; - if (!decoder.loadFile(_fileName)) { - return true; - } + Common::File *_file = _engine->getSearchManager()->openFile(_fileName); + + if (_file) { + if (!decoder.loadStream(_file)) { + return true; + } + + Common::Rect destRect; + if ((_flags & DIFFERENT_DIMENSIONS) == DIFFERENT_DIMENSIONS) { + destRect = Common::Rect(_x1, _y1, _x2, _y2); + } - Common::Rect destRect; - if ((_flags & DIFFERENT_DIMENSIONS) == DIFFERENT_DIMENSIONS) { - destRect = Common::Rect(_x1, _y1, _x2, _y2); + _engine->playVideo(decoder, destRect, _skippable); } - _engine->playVideo(decoder, destRect, _skippable); return true; } diff --git a/engines/zvision/animation_node.cpp b/engines/zvision/animation_node.cpp index 11275b5c7da0..89d0f5e45156 100644 --- a/engines/zvision/animation_node.cpp +++ b/engines/zvision/animation_node.cpp @@ -41,7 +41,7 @@ AnimationNode::AnimationNode(ZVision *engine, uint32 controlKey, const Common::S _animation(NULL) { if (fileName.hasSuffix(".rlf") || fileName.hasSuffix(".avi")) { - _animation = new MetaAnimation(fileName); + _animation = new MetaAnimation(fileName, engine); _frmDelay = _animation->frameTime(); } else { warning("Unrecognized animation file type: %s", fileName.c_str()); diff --git a/engines/zvision/cursor.cpp b/engines/zvision/cursor.cpp index 5386c8ead6b2..e2e3d7ee72bf 100644 --- a/engines/zvision/cursor.cpp +++ b/engines/zvision/cursor.cpp @@ -66,6 +66,35 @@ ZorkCursor::ZorkCursor(const Common::String &fileName) _surface.convertToInPlace(Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0)); } +ZorkCursor::ZorkCursor(ZVision *engine, const Common::String &fileName) + : _width(0), + _height(0), + _hotspotX(0), + _hotspotY(0) { + Common::File file; + if (!engine->getSearchManager()->openFile(file, fileName)) + return; + + uint32 magic = file.readUint32BE(); + if (magic != MKTAG('Z', 'C', 'R', '1')) { + warning("%s is not a Zork Cursor file", fileName.c_str()); + return; + } + + _hotspotX = file.readUint16LE(); + _hotspotY = file.readUint16LE(); + _width = file.readUint16LE(); + _height = file.readUint16LE(); + + uint dataSize = _width * _height * sizeof(uint16); + _surface.create(_width, _height, Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0)); + uint32 bytesRead = file.read(_surface.getPixels(), dataSize); + assert(bytesRead == dataSize); + + // Convert to RGB 565 + _surface.convertToInPlace(Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0)); +} + ZorkCursor::ZorkCursor(const ZorkCursor &other) { _width = other._width; _height = other._height; diff --git a/engines/zvision/cursor.h b/engines/zvision/cursor.h index 8f119c89825f..2304bf4c82f9 100644 --- a/engines/zvision/cursor.h +++ b/engines/zvision/cursor.h @@ -24,6 +24,7 @@ #define ZVISION_CURSOR_H #include "graphics/surface.h" +#include "zvision/zvision.h" namespace Common { @@ -40,6 +41,7 @@ class ZorkCursor { public: ZorkCursor(); ZorkCursor(const Common::String &fileName); + ZorkCursor(ZVision *engine, const Common::String &fileName); ZorkCursor(const ZorkCursor &other); ~ZorkCursor(); diff --git a/engines/zvision/cursor_manager.cpp b/engines/zvision/cursor_manager.cpp index aaf3bb8ee44c..c66fa650a8d1 100644 --- a/engines/zvision/cursor_manager.cpp +++ b/engines/zvision/cursor_manager.cpp @@ -57,15 +57,15 @@ CursorManager::CursorManager(ZVision *engine, const Graphics::PixelFormat *pixel if (_engine->getGameId() == GID_NEMESIS) { Common::String name; name = Common::String::format("%sa.zcr", _zNemCursorFileNames[i]); - _cursors[i][0] = ZorkCursor(name); // Up cursor + _cursors[i][0] = ZorkCursor(_engine, name); // Up cursor name = Common::String::format("%sb.zcr", _zNemCursorFileNames[i]); - _cursors[i][1] = ZorkCursor(name); // Down cursor + _cursors[i][1] = ZorkCursor(_engine, name); // Down cursor } else if (_engine->getGameId() == GID_GRANDINQUISITOR) { - _cursors[i][0] = ZorkCursor(_zgiCursorFileNames[i]); // Up cursor + _cursors[i][0] = ZorkCursor(_engine, _zgiCursorFileNames[i]); // Up cursor char buffer[25]; strcpy(buffer, _zgiCursorFileNames[i]); buffer[3] += 2; - _cursors[i][1] = ZorkCursor(buffer); // Down cursor + _cursors[i][1] = ZorkCursor(_engine, buffer); // Down cursor } } } @@ -76,22 +76,22 @@ void CursorManager::setItemID(int id) { Common::String file; if (_engine->getGameId() == GID_NEMESIS) { file = Common::String::format("%2.2d%s%c.zcr", id, "idle", 'a'); - _cursors[NUM_CURSORS][0] = ZorkCursor(file); + _cursors[NUM_CURSORS][0] = ZorkCursor(_engine, file); file = Common::String::format("%2.2d%s%c.zcr", id, "idle", 'b'); - _cursors[NUM_CURSORS][1] = ZorkCursor(file); + _cursors[NUM_CURSORS][1] = ZorkCursor(_engine, file); file = Common::String::format("%2.2d%s%c.zcr", id, "act", 'a'); - _cursors[NUM_CURSORS + 1][0] = ZorkCursor(file); + _cursors[NUM_CURSORS + 1][0] = ZorkCursor(_engine, file); file = Common::String::format("%2.2d%s%c.zcr", id, "act", 'b'); - _cursors[NUM_CURSORS + 1][0] = ZorkCursor(file); + _cursors[NUM_CURSORS + 1][0] = ZorkCursor(_engine, file); } else if (_engine->getGameId() == GID_GRANDINQUISITOR) { file = Common::String::format("g0b%cc%2.2x1.zcr", 'a' , id); - _cursors[NUM_CURSORS][0] = ZorkCursor(file); + _cursors[NUM_CURSORS][0] = ZorkCursor(_engine, file); file = Common::String::format("g0b%cc%2.2x1.zcr", 'c' , id); - _cursors[NUM_CURSORS][1] = ZorkCursor(file); + _cursors[NUM_CURSORS][1] = ZorkCursor(_engine, file); file = Common::String::format("g0b%cc%2.2x1.zcr", 'b' , id); - _cursors[NUM_CURSORS + 1][0] = ZorkCursor(file); + _cursors[NUM_CURSORS + 1][0] = ZorkCursor(_engine, file); file = Common::String::format("g0b%cc%2.2x1.zcr", 'd' , id); - _cursors[NUM_CURSORS + 1][1] = ZorkCursor(file); + _cursors[NUM_CURSORS + 1][1] = ZorkCursor(_engine, file); } else return; } diff --git a/engines/zvision/lever_control.cpp b/engines/zvision/lever_control.cpp index e96c873033db..33aa2be592b3 100644 --- a/engines/zvision/lever_control.cpp +++ b/engines/zvision/lever_control.cpp @@ -86,7 +86,7 @@ LeverControl::~LeverControl() { void LeverControl::parseLevFile(const Common::String &fileName) { Common::File file; - if (!file.open(fileName)) { + if (!_engine->getSearchManager()->openFile(file, fileName)) { warning("LEV file %s could could be opened", fileName.c_str()); return; } @@ -103,7 +103,7 @@ void LeverControl::parseLevFile(const Common::String &fileName) { Common::String animationFileName(fileNameBuffer); if (animationFileName.hasSuffix(".avi") || animationFileName.hasSuffix(".rlf")) - _animation = new MetaAnimation(animationFileName); + _animation = new MetaAnimation(animationFileName, _engine); } else if (line.matchString("*skipcolor*", true)) { // Not used diff --git a/engines/zvision/meta_animation.cpp b/engines/zvision/meta_animation.cpp index 430b1436cb1d..33ae92a523fc 100644 --- a/engines/zvision/meta_animation.cpp +++ b/engines/zvision/meta_animation.cpp @@ -37,17 +37,19 @@ namespace ZVision { -MetaAnimation::MetaAnimation(const Common::String &fileName) +MetaAnimation::MetaAnimation(const Common::String &fileName, ZVision *engine) : _fileType(RLF), _cur_frame(NULL) { if (fileName.hasSuffix(".rlf")) { _fileType = RLF; - _animation.rlf = new RlfAnimation(fileName, false); + Common::File *_file = engine->getSearchManager()->openFile(fileName); + _animation.rlf = new RlfAnimation(_file, false); _frmDelay = _animation.rlf->frameTime(); } else if (fileName.hasSuffix(".avi")) { _fileType = AVI; + Common::File *_file = engine->getSearchManager()->openFile(fileName); _animation.avi = new ZorkAVIDecoder(); - _animation.avi->loadFile(fileName); + _animation.avi->loadStream(_file); _frmDelay = 1000.0 / _animation.avi->getDuration().framerate(); } else { warning("Unrecognized animation file type: %s", fileName.c_str()); diff --git a/engines/zvision/meta_animation.h b/engines/zvision/meta_animation.h index fea7a6a6c1f1..e25995589125 100644 --- a/engines/zvision/meta_animation.h +++ b/engines/zvision/meta_animation.h @@ -24,6 +24,7 @@ #define ZVISION_METAANIM_NODE_H #include "zvision/sidefx.h" +#include "zvision/zvision.h" #include "common/rect.h" #include "common/list.h" @@ -47,7 +48,7 @@ class RlfAnimation; class MetaAnimation { public: - MetaAnimation(const Common::String &fileName); + MetaAnimation(const Common::String &fileName, ZVision *engine); ~MetaAnimation(); struct playnode { diff --git a/engines/zvision/module.mk b/engines/zvision/module.mk index 62a12936637c..b8dca9e63ad7 100644 --- a/engines/zvision/module.mk +++ b/engines/zvision/module.mk @@ -35,7 +35,8 @@ MODULE_OBJS := \ inventory_manager.o \ slot_control.o \ menu.o \ - meta_animation.o + meta_animation.o \ + search_manager.o MODULE_DIRS += \ engines/zvision diff --git a/engines/zvision/music_node.cpp b/engines/zvision/music_node.cpp index 30271480c189..d47a796382fe 100644 --- a/engines/zvision/music_node.cpp +++ b/engines/zvision/music_node.cpp @@ -51,7 +51,7 @@ MusicNode::MusicNode(ZVision *engine, uint32 key, Common::String &filename, bool if (filename.contains(".wav")) { Common::File *file = new Common::File(); - if (file->open(filename)) { + if (_engine->getSearchManager()->openFile(*file, filename)) { audioStream = Audio::makeWAVStream(file, DisposeAfterUse::YES); } } else { diff --git a/engines/zvision/render_manager.cpp b/engines/zvision/render_manager.cpp index f5d6847cf363..6cfc0509c74d 100644 --- a/engines/zvision/render_manager.cpp +++ b/engines/zvision/render_manager.cpp @@ -22,6 +22,7 @@ #include "common/scummsys.h" +#include "zvision/zvision.h" #include "zvision/render_manager.h" #include "zvision/lzss_read_stream.h" @@ -37,8 +38,9 @@ namespace ZVision { -RenderManager::RenderManager(OSystem *system, uint32 windowWidth, uint32 windowHeight, const Common::Rect workingWindow, const Graphics::PixelFormat pixelFormat) - : _system(system), +RenderManager::RenderManager(ZVision *engine, uint32 windowWidth, uint32 windowHeight, const Common::Rect workingWindow, const Graphics::PixelFormat pixelFormat) + : _engine(engine), + _system(engine->_system), _wrkWidth(workingWindow.width()), _wrkHeight(workingWindow.height()), _screenCenterX(_wrkWidth / 2), @@ -113,7 +115,7 @@ void RenderManager::renderImageToBackground(const Common::String &fileName, int1 void RenderManager::readImageToSurface(const Common::String &fileName, Graphics::Surface &destination) { Common::File file; - if (!file.open(fileName)) { + if (!_engine->getSearchManager()->openFile(file, fileName)) { warning("Could not open file %s", fileName.c_str()); return; } @@ -207,7 +209,7 @@ void RenderManager::readImageToSurface(const Common::String &fileName, Graphics: void RenderManager::readImageToSurface(const Common::String &fileName, Graphics::Surface &destination, bool transposed) { Common::File file; - if (!file.open(fileName)) { + if (!_engine->getSearchManager()->openFile(file, fileName)) { warning("Could not open file %s", fileName.c_str()); return; } diff --git a/engines/zvision/render_manager.h b/engines/zvision/render_manager.h index 901385b453ea..3c03331d0f6b 100644 --- a/engines/zvision/render_manager.h +++ b/engines/zvision/render_manager.h @@ -47,7 +47,7 @@ namespace ZVision { class RenderManager { public: - RenderManager(OSystem *system, uint32 windowWidth, uint32 windowHeight, const Common::Rect workingWindow, const Graphics::PixelFormat pixelFormat); + RenderManager(ZVision *engine, uint32 windowWidth, uint32 windowHeight, const Common::Rect workingWindow, const Graphics::PixelFormat pixelFormat); ~RenderManager(); private: @@ -70,6 +70,7 @@ class RenderManager { typedef Common::HashMap subMap; private: + ZVision *_engine; OSystem *_system; const Graphics::PixelFormat _pixelFormat; diff --git a/engines/zvision/rlf_animation.cpp b/engines/zvision/rlf_animation.cpp index dab32aed174d..f23f569d9835 100644 --- a/engines/zvision/rlf_animation.cpp +++ b/engines/zvision/rlf_animation.cpp @@ -37,6 +37,7 @@ namespace ZVision { RlfAnimation::RlfAnimation(const Common::String &fileName, bool stream) : _stream(stream), + _readStream(NULL), _lastFrameRead(0), _frameCount(0), _width(0), @@ -45,11 +46,15 @@ RlfAnimation::RlfAnimation(const Common::String &fileName, bool stream) _frames(0), _currentFrame(0), _frameBufferByteSize(0) { - if (!_file.open(fileName)) { + + Common::File *_file = new Common::File; + if (!_file->open(fileName)) { warning("RLF animation file %s could not be opened", fileName.c_str()); return; } + _readStream = _file; + if (!readHeader()) { warning("%s is not a RLF animation file. Wrong magic number", fileName.c_str()); return; @@ -68,59 +73,90 @@ RlfAnimation::RlfAnimation(const Common::String &fileName, bool stream) } } +RlfAnimation::RlfAnimation(Common::SeekableReadStream *rstream, bool stream) + : _stream(stream), + _readStream(rstream), + _lastFrameRead(0), + _frameCount(0), + _width(0), + _height(0), + _frameTime(0), + _frames(0), + _currentFrame(0), + _frameBufferByteSize(0) { + + if (!readHeader()) { + warning("Stream is not a RLF animation. Wrong magic number"); + return; + } + + _currentFrameBuffer.create(_width, _height, Graphics::createPixelFormat<565>()); + _frameBufferByteSize = _width * _height * sizeof(uint16); + + if (!stream) { + _frames = new Frame[_frameCount]; + + // Read in each frame + for (uint i = 0; i < _frameCount; ++i) { + _frames[i] = readNextFrame(); + } + } +} + RlfAnimation::~RlfAnimation() { for (uint i = 0; i < _frameCount; ++i) { delete[] _frames[i].encodedData; } delete[] _frames; + delete _readStream; _currentFrameBuffer.free(); } bool RlfAnimation::readHeader() { - if (_file.readUint32BE() != MKTAG('F', 'E', 'L', 'R')) { + if (_readStream->readUint32BE() != MKTAG('F', 'E', 'L', 'R')) { return false; } // Read the header - _file.readUint32LE(); // Size1 - _file.readUint32LE(); // Unknown1 - _file.readUint32LE(); // Unknown2 - _frameCount = _file.readUint32LE(); // Frame count + _readStream->readUint32LE(); // Size1 + _readStream->readUint32LE(); // Unknown1 + _readStream->readUint32LE(); // Unknown2 + _frameCount = _readStream->readUint32LE(); // Frame count // Since we don't need any of the data, we can just seek right to the // entries we need rather than read in all the individual entries. - _file.seek(136, SEEK_CUR); + _readStream->seek(136, SEEK_CUR); //// Read CIN header - //_file.readUint32BE(); // Magic number FNIC - //_file.readUint32LE(); // Size2 - //_file.readUint32LE(); // Unknown3 - //_file.readUint32LE(); // Unknown4 - //_file.readUint32LE(); // Unknown5 - //_file.seek(0x18, SEEK_CUR); // VRLE - //_file.readUint32LE(); // LRVD - //_file.readUint32LE(); // Unknown6 - //_file.seek(0x18, SEEK_CUR); // HRLE - //_file.readUint32LE(); // ELHD - //_file.readUint32LE(); // Unknown7 - //_file.seek(0x18, SEEK_CUR); // HKEY - //_file.readUint32LE(); // ELRH + //_readStream->readUint32BE(); // Magic number FNIC + //_readStream->readUint32LE(); // Size2 + //_readStream->readUint32LE(); // Unknown3 + //_readStream->readUint32LE(); // Unknown4 + //_readStream->readUint32LE(); // Unknown5 + //_readStream->seek(0x18, SEEK_CUR); // VRLE + //_readStream->readUint32LE(); // LRVD + //_readStream->readUint32LE(); // Unknown6 + //_readStream->seek(0x18, SEEK_CUR); // HRLE + //_readStream->readUint32LE(); // ELHD + //_readStream->readUint32LE(); // Unknown7 + //_readStream->seek(0x18, SEEK_CUR); // HKEY + //_readStream->readUint32LE(); // ELRH //// Read MIN info header - //_file.readUint32BE(); // Magic number FNIM - //_file.readUint32LE(); // Size3 - //_file.readUint32LE(); // OEDV - //_file.readUint32LE(); // Unknown8 - //_file.readUint32LE(); // Unknown9 - //_file.readUint32LE(); // Unknown10 - _width = _file.readUint32LE(); // Width - _height = _file.readUint32LE(); // Height + //_readStream->readUint32BE(); // Magic number FNIM + //_readStream->readUint32LE(); // Size3 + //_readStream->readUint32LE(); // OEDV + //_readStream->readUint32LE(); // Unknown8 + //_readStream->readUint32LE(); // Unknown9 + //_readStream->readUint32LE(); // Unknown10 + _width = _readStream->readUint32LE(); // Width + _height = _readStream->readUint32LE(); // Height // Read time header - _file.readUint32BE(); // Magic number EMIT - _file.readUint32LE(); // Size4 - _file.readUint32LE(); // Unknown11 - _frameTime = _file.readUint32LE() / 10; // Frame time in microseconds + _readStream->readUint32BE(); // Magic number EMIT + _readStream->readUint32LE(); // Size4 + _readStream->readUint32LE(); // Unknown11 + _frameTime = _readStream->readUint32LE() / 10; // Frame time in microseconds return true; } @@ -128,17 +164,17 @@ bool RlfAnimation::readHeader() { RlfAnimation::Frame RlfAnimation::readNextFrame() { RlfAnimation::Frame frame; - _file.readUint32BE(); // Magic number MARF - uint32 size = _file.readUint32LE(); // Size - _file.readUint32LE(); // Unknown1 - _file.readUint32LE(); // Unknown2 - uint32 type = _file.readUint32BE(); // Either ELHD or ELRH - uint32 headerSize = _file.readUint32LE(); // Offset from the beginning of this frame to the frame data. Should always be 28 - _file.readUint32LE(); // Unknown3 + _readStream->readUint32BE(); // Magic number MARF + uint32 size = _readStream->readUint32LE(); // Size + _readStream->readUint32LE(); // Unknown1 + _readStream->readUint32LE(); // Unknown2 + uint32 type = _readStream->readUint32BE(); // Either ELHD or ELRH + uint32 headerSize = _readStream->readUint32LE(); // Offset from the beginning of this frame to the frame data. Should always be 28 + _readStream->readUint32LE(); // Unknown3 frame.encodedSize = size - headerSize; frame.encodedData = new int8[frame.encodedSize]; - _file.read(frame.encodedData, frame.encodedSize); + _readStream->read(frame.encodedData, frame.encodedSize); if (type == MKTAG('E', 'L', 'H', 'D')) { frame.type = Masked; diff --git a/engines/zvision/rlf_animation.h b/engines/zvision/rlf_animation.h index 35916de6cb47..3764465786eb 100644 --- a/engines/zvision/rlf_animation.h +++ b/engines/zvision/rlf_animation.h @@ -37,6 +37,7 @@ namespace ZVision { class RlfAnimation { public: RlfAnimation(const Common::String &fileName, bool stream = true); + RlfAnimation(Common::SeekableReadStream *rstream, bool stream); ~RlfAnimation(); private: @@ -52,7 +53,7 @@ class RlfAnimation { }; private: - Common::File _file; + Common::SeekableReadStream *_readStream; bool _stream; uint _lastFrameRead; diff --git a/engines/zvision/scr_file_handling.cpp b/engines/zvision/scr_file_handling.cpp index 833db11ad1fa..db4e8fa9b152 100644 --- a/engines/zvision/scr_file_handling.cpp +++ b/engines/zvision/scr_file_handling.cpp @@ -22,6 +22,7 @@ #include "common/scummsys.h" +#include "zvision/zvision.h" #include "zvision/script_manager.h" #include "zvision/utility.h" @@ -40,7 +41,7 @@ namespace ZVision { void ScriptManager::parseScrFile(const Common::String &fileName, script_scope &scope) { Common::File file; - if (!file.open(fileName)) { + if (!_engine->getSearchManager()->openFile(file, fileName)) { warning("Script file not found: %s", fileName.c_str()); return; } diff --git a/engines/zvision/search_manager.cpp b/engines/zvision/search_manager.cpp new file mode 100644 index 000000000000..5c94ff0a26f9 --- /dev/null +++ b/engines/zvision/search_manager.cpp @@ -0,0 +1,274 @@ +/* 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/debug.h" + +#include "zvision/search_manager.h" +#include "zvision/zfs_archive.h" +#include "common/fs.h" +#include "common/stream.h" + + +namespace ZVision { + +sManager::sManager(const Common::String &root_path, int depth) { + _root = root_path; + if (_root[_root.size() - 1] == '\\' || _root[_root.size() - 1] == '/') + _root.deleteLastChar(); + + Common::FSNode fs_node(_root); + + list_dir_recursive(dir_list, fs_node, depth); + + for (Common::List::iterator it = dir_list.begin(); it != dir_list.end();) + if (it->size() == _root.size()) + it = dir_list.erase(it); + else if (it->size() > _root.size()) { + *it = Common::String(it->c_str() + _root.size() + 1); + it++; + } else + it++; +} + +sManager::~sManager() { + Common::List::iterator it = archList.begin(); + while (it != archList.end()) { + delete *it; + it++; + } + + archList.clear(); +} + +void sManager::addPatch(const Common::String &src, const Common::String &dst) { + Common::String lw_name = dst; + lw_name.toLowercase(); + + sManager::MatchList::iterator it = files.find(lw_name); + + if (it != files.end()) { + lw_name = src; + lw_name.toLowercase(); + files[lw_name] = it->_value; + } +} + +void sManager::addFile(const Common::String &name, Common::Archive *arch) { + bool addArch = true; + Common::List::iterator it = archList.begin(); + while (it != archList.end()) { + if (*it == arch) { + addArch = false; + break; + } + it++; + } + if (addArch) + archList.push_back(arch); + + Common::String lw_name = name; + lw_name.toLowercase(); + + sManager::Node nod; + nod.name = lw_name; + nod.arch = arch; + + sManager::MatchList::iterator fit = files.find(lw_name); + + if (fit == files.end()) { + files[lw_name] = nod; + } else { + Common::SeekableReadStream *stream = fit->_value.arch->createReadStreamForMember(fit->_value.name); + if (stream) { + if (stream->size() < 10) + fit->_value.arch = arch; + delete stream; + } else { + files[lw_name] = nod; + } + } +} + +Common::File *sManager::openFile(const Common::String &name) { + Common::String lw_name = name; + lw_name.toLowercase(); + + sManager::MatchList::iterator fit = files.find(lw_name); + + if (fit != files.end()) { + Common::File *tmp = new Common::File(); + tmp->open(fit->_value.name, *fit->_value.arch); + return tmp; + } + return NULL; +} + +bool sManager::openFile(Common::File &file, const Common::String &name) { + Common::String lw_name = name; + lw_name.toLowercase(); + + sManager::MatchList::iterator fit = files.find(lw_name); + + if (fit != files.end()) + return file.open(fit->_value.name, *fit->_value.arch); + return false; +} + +bool sManager::hasFile(const Common::String &name) { + Common::String lw_name = name; + lw_name.toLowercase(); + + sManager::MatchList::iterator fit = files.find(lw_name); + + if (fit != files.end()) + return true; + return false; +} + +void sManager::loadZix(const Common::String &name) { + Common::File file; + file.open(name); + + Common::String line; + + while (!file.eos()) { + line = file.readLine(); + if (line.matchString("----------*", true)) + break; + } + + if (file.eos()) + return; + + Common::Array archives; + + while (!file.eos()) { + line = file.readLine(); + line.trim(); + if (line.matchString("----------*", true)) + break; + else if (line.matchString("DIR:*", true)) { + Common::String path(line.c_str() + 5); + Common::Archive *arc; + char n_path[128]; + strcpy(n_path, path.c_str()); + for (uint i = 0; i < path.size(); i++) + if (n_path[i] == '\\') + n_path[i] = '/'; + + path = Common::String(n_path); + if (path.size() && path[0] == '.') + path.deleteChar(0); + if (path.size() && path[0] == '/') + path.deleteChar(0); + + if (path.matchString("*.zfs", true)) + arc = new ZfsArchive(path); + else { + if (path.size()) { + if (path[path.size() - 1] == '\\' || path[path.size() - 1] == '/') + path.deleteLastChar(); + if (path.size()) + for (Common::List::iterator it = dir_list.begin(); it != dir_list.end(); ++it) + if (path.equalsIgnoreCase(*it)) { + path = *it; + break; + } + } + + path = Common::String::format("%s/%s", _root.c_str(), path.c_str()); + + arc = new Common::FSDirectory(path); + } + archives.push_back(arc); + } + } + + if (file.eos()) + return; + + while (!file.eos()) { + line = file.readLine(); + line.trim(); + uint dr = 0; + char buf[32]; + if (sscanf(line.c_str(), "%u %s", &dr, buf) == 2) { + if (dr < archives.size() && dr > 0) { + addFile(Common::String(buf), archives[dr - 1]); + } + } + } +} + +void sManager::addDir(const Common::String &name) { + Common::String path; + for (Common::List::iterator it = dir_list.begin(); it != dir_list.end(); ++it) + if (name.equalsIgnoreCase(*it)) { + path = *it; + break; + } + + if (path.size() == 0) + return; + + path = Common::String::format("%s/%s", _root.c_str(), path.c_str()); + + Common::FSDirectory *dir = new Common::FSDirectory(path); + + Common::ArchiveMemberList list; + dir->listMatchingMembers(list, "*.zfs"); + + + for (Common::ArchiveMemberList::iterator iter = list.begin(); iter != list.end(); ++iter) { + Common::String flname = (*iter)->getName(); + + ZfsArchive *zfs = new ZfsArchive(Common::String::format("%s/%s", name.c_str(), flname.c_str())); + + Common::ArchiveMemberList zfslist; + zfs->listMembers(zfslist); + + for (Common::ArchiveMemberList::iterator ziter = zfslist.begin(); ziter != zfslist.end(); ++ziter) { + Common::String z_name = (*ziter)->getName(); + addFile(z_name, zfs); + } + } + + list.clear(); + dir->listMembers(list); + + for (Common::ArchiveMemberList::iterator iter = list.begin(); iter != list.end(); ++iter) { + Common::String flname = (*iter)->getName(); + addFile(flname, dir); + } +} + +void sManager::list_dir_recursive(Common::List &_list, const Common::FSNode &fs_node, int depth) { + Common::FSList fs_list; + fs_node.getChildren(fs_list); + + _list.push_back(fs_node.getPath()); + + if (depth > 1) + for (Common::FSList::const_iterator it = fs_list.begin(); it != fs_list.end(); ++it) + list_dir_recursive(_list, *it, depth - 1); +} + +} // End of namespace ZVision diff --git a/engines/zvision/search_manager.h b/engines/zvision/search_manager.h new file mode 100644 index 000000000000..c768cb8b009f --- /dev/null +++ b/engines/zvision/search_manager.h @@ -0,0 +1,51 @@ +#ifndef SEARCH_MANAGER_H_INCLUDED +#define SEARCH_MANAGER_H_INCLUDED + +#include "common/str.h" +#include "common/hash-str.h" +#include "common/hashmap.h" +#include "common/archive.h" +#include "common/file.h" +#include "common/list.h" + +namespace ZVision { + +class sManager { +public: + sManager(const Common::String &root_path, int depth); + ~sManager(); + + void addFile(const Common::String &name, Common::Archive *arch); + void addDir(const Common::String &name); + void addPatch(const Common::String &src, const Common::String &dst); + + Common::File *openFile(const Common::String &name); + bool openFile(Common::File &file, const Common::String &name); + bool hasFile(const Common::String &name); + + void loadZix(const Common::String &name); + +private: + + void list_dir_recursive(Common::List &dir_list, const Common::FSNode &fs_node, int depth); + + struct Node { + Common::String name; + Common::Archive *arch; + }; + + Common::List dir_list; + + typedef Common::HashMap MatchList; + + Common::List archList; + MatchList files; + + Common::String _root; + +private: +}; + +} + +#endif // SEARCH_MANAGER_H_INCLUDED diff --git a/engines/zvision/zork_raw.cpp b/engines/zvision/zork_raw.cpp index e7cc71a70b23..a4d091f3c0cb 100644 --- a/engines/zvision/zork_raw.cpp +++ b/engines/zvision/zork_raw.cpp @@ -254,7 +254,7 @@ Audio::RewindableAudioStream *makeRawZorkStream(const byte *buffer, uint32 size, Audio::RewindableAudioStream *makeRawZorkStream(const Common::String &filePath, ZVision *engine) { Common::File *file = new Common::File(); - assert(file->open(filePath)); + assert(engine->getSearchManager()->openFile(*file, filePath)); Common::String fileName = getFileName(filePath); fileName.toLowercase(); diff --git a/engines/zvision/zvision.cpp b/engines/zvision/zvision.cpp index f21498c3157a..bf945f859add 100644 --- a/engines/zvision/zvision.cpp +++ b/engines/zvision/zvision.cpp @@ -33,8 +33,10 @@ #include "zvision/zfs_archive.h" #include "zvision/detection.h" #include "zvision/menu.h" +#include "zvision/search_manager.h" #include "common/config-manager.h" +#include "common/str.h" #include "common/debug.h" #include "common/debug-channels.h" #include "common/textconsole.h" @@ -88,6 +90,29 @@ ZVision::~ZVision() { void ZVision::initialize() { const Common::FSNode gameDataDir(ConfMan.get("path")); + + _searchManager = new sManager(ConfMan.get("path"), 6); + + _searchManager->addDir("addon"); + + if (_gameDescription->gameId == GID_GRANDINQUISITOR) { + _searchManager->loadZix("INQUIS.ZIX"); + _searchManager->addPatch("C000H01Q.RAW", "C000H01Q.SRC"); + _searchManager->addPatch("CM00H01Q.RAW", "CM00H01Q.SRC"); + _searchManager->addPatch("DM00H01Q.RAW", "DM00H01Q.SRC"); + _searchManager->addPatch("E000H01Q.RAW", "E000H01Q.SRC"); + _searchManager->addPatch("EM00H50Q.RAW", "EM00H50Q.SRC"); + _searchManager->addPatch("GJNPH65P.RAW", "GJNPH65P.SRC"); + _searchManager->addPatch("GJNPH72P.RAW", "GJNPH72P.SRC"); + _searchManager->addPatch("H000H01Q.RAW", "H000H01Q.SRC"); + _searchManager->addPatch("M000H01Q.RAW", "M000H01Q.SRC"); + _searchManager->addPatch("P000H01Q.RAW", "P000H01Q.SRC"); + _searchManager->addPatch("Q000H01Q.RAW", "Q000H01Q.SRC"); + _searchManager->addPatch("SW00H01Q.RAW", "SW00H01Q.SRC"); + _searchManager->addPatch("T000H01Q.RAW", "T000H01Q.SRC"); + _searchManager->addPatch("U000H01Q.RAW", "U000H01Q.SRC"); + } else if (_gameDescription->gameId == GID_NEMESIS) + _searchManager->loadZix("NEMESIS.ZIX"); // TODO: There are 10 file clashes when we flatten the directories. // From a quick look, the files are exactly the same, so it shouldn't matter. // But I'm noting it here just in-case it does become a problem. @@ -123,7 +148,7 @@ void ZVision::initialize() { // Create managers _scriptManager = new ScriptManager(this); - _renderManager = new RenderManager(_system, WINDOW_WIDTH, WINDOW_HEIGHT, _workingWindow, _pixelFormat); + _renderManager = new RenderManager(this, WINDOW_WIDTH, WINDOW_HEIGHT, _workingWindow, _pixelFormat); _saveManager = new SaveManager(this); _stringManager = new StringManager(this); _cursorManager = new CursorManager(this, &_pixelFormat); diff --git a/engines/zvision/zvision.h b/engines/zvision/zvision.h index 26d7644eb0dd..c9e14e8651b0 100644 --- a/engines/zvision/zvision.h +++ b/engines/zvision/zvision.h @@ -26,6 +26,7 @@ #include "zvision/detection.h" #include "zvision/clock.h" +#include "zvision/search_manager.h" #include "common/random.h" #include "common/events.h" @@ -99,6 +100,7 @@ class ZVision : public Engine { SaveManager *_saveManager; StringManager *_stringManager; menuHandler *_menu; + sManager *_searchManager; // Clock Clock _clock; @@ -135,6 +137,9 @@ class ZVision : public Engine { StringManager *getStringManager() const { return _stringManager; } + sManager *getSearchManager() const { + return _searchManager; + } Common::RandomSource *getRandomSource() const { return _rnd; }