diff options
-rw-r--r-- | engines/voyeur/animation.cpp | 351 | ||||
-rw-r--r-- | engines/voyeur/animation.h | 150 | ||||
-rw-r--r-- | engines/voyeur/configure.engine | 3 | ||||
-rw-r--r-- | engines/voyeur/debugger.cpp | 34 | ||||
-rw-r--r-- | engines/voyeur/debugger.h | 45 | ||||
-rw-r--r-- | engines/voyeur/detection.cpp | 170 | ||||
-rw-r--r-- | engines/voyeur/detection_tables.h | 45 | ||||
-rw-r--r-- | engines/voyeur/events.cpp | 379 | ||||
-rw-r--r-- | engines/voyeur/events.h | 110 | ||||
-rw-r--r-- | engines/voyeur/files.cpp | 1215 | ||||
-rw-r--r-- | engines/voyeur/files.h | 368 | ||||
-rw-r--r-- | engines/voyeur/game.cpp | 101 | ||||
-rw-r--r-- | engines/voyeur/game.h | 142 | ||||
-rw-r--r-- | engines/voyeur/graphics.cpp | 648 | ||||
-rw-r--r-- | engines/voyeur/graphics.h | 118 | ||||
-rw-r--r-- | engines/voyeur/module.mk | 21 | ||||
-rw-r--r-- | engines/voyeur/sound.cpp | 47 | ||||
-rw-r--r-- | engines/voyeur/sound.h | 47 | ||||
-rw-r--r-- | engines/voyeur/utils.cpp | 55 | ||||
-rw-r--r-- | engines/voyeur/utils.h | 59 | ||||
-rw-r--r-- | engines/voyeur/voyeur.cpp | 538 | ||||
-rw-r--r-- | engines/voyeur/voyeur.h | 119 |
22 files changed, 4765 insertions, 0 deletions
diff --git a/engines/voyeur/animation.cpp b/engines/voyeur/animation.cpp new file mode 100644 index 0000000000..cbd7b0af18 --- /dev/null +++ b/engines/voyeur/animation.cpp @@ -0,0 +1,351 @@ +/* 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 "voyeur/animation.h" +#include "common/memstream.h" +#include "common/system.h" +#include "audio/decoders/raw.h" +#include "graphics/surface.h" + +namespace Video { + +RL2Decoder::RL2Decoder(Audio::Mixer::SoundType soundType) : _soundType(soundType) { +} + +RL2Decoder::~RL2Decoder() { + close(); +} + +bool RL2Decoder::loadStream(Common::SeekableReadStream *stream) { + close(); + + // Load basic file information + _header.load(stream); + + // Check RL2 magic number + if (!_header.isValid()) { + warning("RL2Decoder::loadStream(): attempted to load non-RL2 data (0x%08X)", _header._signature); + return false; + } + + // Add an audio track if sound is present + RL2AudioTrack *audioTrack = NULL; + if (_header._soundRate) { + audioTrack = new RL2AudioTrack(_header, _soundType); + addTrack(audioTrack); + } + + // Create a video track + addTrack(new RL2VideoTrack(_header, audioTrack, stream)); + + return true; +} + +const Common::List<Common::Rect> *RL2Decoder::getDirtyRects() const { + const Track *track = getTrack(0); + + if (track) + return ((const RL2VideoTrack *)track)->getDirtyRects(); + + return 0; +} + +void RL2Decoder::clearDirtyRects() { + Track *track = getTrack(0); + + if (track) + ((RL2VideoTrack *)track)->clearDirtyRects(); +} + +void RL2Decoder::copyDirtyRectsToBuffer(uint8 *dst, uint pitch) { + Track *track = getTrack(0); + + if (track) + ((RL2VideoTrack *)track)->copyDirtyRectsToBuffer(dst, pitch); +} + +/*------------------------------------------------------------------------*/ + +RL2Decoder::RL2FileHeader::RL2FileHeader() { + _frameOffsets = NULL; + _frameSoundSizes = NULL; +} + +RL2Decoder::RL2FileHeader::~RL2FileHeader() { + delete[] _frameOffsets; + _frameSoundSizes; +} + +void RL2Decoder::RL2FileHeader::load(Common::SeekableReadStream *stream) { + stream->seek(0); + + _form = stream->readUint32LE(); + _backSize = stream->readUint32LE(); + _signature = stream->readUint32LE(); + + if (!isValid()) + return; + + _dataSize = stream->readUint32LE(); + _numFrames = stream->readUint32LE(); + _method = stream->readUint16LE(); + _soundRate = stream->readUint16LE(); + _rate = stream->readUint16LE(); + _channels = stream->readUint16LE(); + _defSoundSize = stream->readUint16LE(); + _videoBase = stream->readUint16LE(); + _colorCount = stream->readUint32LE(); + assert(_colorCount <= 256); + + stream->read(_palette, 768); + + // Skip over background frame, if any, and the list of overall frame sizes (which we don't use) + stream->skip(_backSize + 4 * _numFrames); + + // Load frame offsets + _frameOffsets = new uint32[_numFrames]; + for (int i = 0; i < _numFrames; ++i) + _frameOffsets[i] = stream->readUint32LE(); + + // Load the size of the sound portion of each frame + _frameSoundSizes = new int[_numFrames]; + for (int i = 0; i < _numFrames; ++i) + _frameSoundSizes[i] = stream->readUint32LE() & 0xffff; +} + +bool RL2Decoder::RL2FileHeader::isValid() const { + return _signature == MKTAG('R','L','V','2') || _signature != MKTAG('R','L','V','3'); +} + +/*------------------------------------------------------------------------*/ + +RL2Decoder::RL2VideoTrack::RL2VideoTrack(const RL2FileHeader &header, RL2AudioTrack *audioTrack, + Common::SeekableReadStream *stream): + _header(header), _audioTrack(audioTrack), _fileStream(stream) { + + // Calculate the frame rate + int fps = (header._soundRate > 0) ? header._rate / header._defSoundSize : 11025 / 1103; + _frameDelay = 1000 / fps; + + _surface = new Graphics::Surface(); + _surface->create(320, 200, Graphics::PixelFormat::createFormatCLUT8()); + if (header._backSize == 0) { + _backSurface = NULL; + } else { + _backSurface = new Graphics::Surface(); + _backSurface->create(320, 200, Graphics::PixelFormat::createFormatCLUT8()); + + stream->seek(0x324); + rl2DecodeFrameWithoutBackground(0); + } + + _videoBase = header._videoBase; + _dirtyPalette = true; + + _curFrame = 0; + _nextFrameStartTime = 0; +} + +RL2Decoder::RL2VideoTrack::~RL2VideoTrack() { + delete _fileStream; + + _surface->free(); + delete _surface; + if (_backSurface) { + _backSurface->free(); + delete _backSurface; + } +} + +bool RL2Decoder::RL2VideoTrack::endOfTrack() const { + return getCurFrame() >= getFrameCount(); +} + +bool RL2Decoder::RL2VideoTrack::rewind() { + _curFrame = 0; + _nextFrameStartTime = 0; + + return true; +} + +uint16 RL2Decoder::RL2VideoTrack::getWidth() const { + return _surface->w; +} + +uint16 RL2Decoder::RL2VideoTrack::getHeight() const { + return _surface->h; +} + +Graphics::PixelFormat RL2Decoder::RL2VideoTrack::getPixelFormat() const { + return _surface->format; +} + +const Graphics::Surface *RL2Decoder::RL2VideoTrack::decodeNextFrame() { + if (_curFrame == 0 && _backSurface) { + // Read in the background frame + _fileStream->seek(0x324); + rl2DecodeFrameWithoutBackground(0); + _dirtyRects.push_back(Common::Rect(0, 0, _surface->w, _surface->h)); + } + + // Move to the next frame data + _fileStream->seek(_header._frameOffsets[_curFrame]); + + // If there's any sound data, pass it to the audio track + if (_header._frameSoundSizes[_curFrame] > 0 && _audioTrack) + _audioTrack->queueSound(_fileStream, _header._frameSoundSizes[_curFrame]); + + // Decode the graphic data + if (_backSurface) + rl2DecodeFrameWithBackground(); + else + rl2DecodeFrameWithoutBackground(); + + _curFrame++; + _nextFrameStartTime += _frameDelay; + + return _surface; +} + +void RL2Decoder::RL2VideoTrack::copyDirtyRectsToBuffer(uint8 *dst, uint pitch) { + for (Common::List<Common::Rect>::const_iterator it = _dirtyRects.begin(); it != _dirtyRects.end(); ++it) { + for (int y = (*it).top; y < (*it).bottom; ++y) { + const int x = (*it).left; + memcpy(dst + y * pitch + x, (byte *)_surface->getPixels() + y * getWidth() + x, (*it).right - x); + } + } + + clearDirtyRects(); +} + +void RL2Decoder::RL2VideoTrack::copyFrame(uint8 *data) { + memcpy((byte *)_surface->getPixels(), data, getWidth() * getHeight()); + + // Redraw + _dirtyRects.clear(); + _dirtyRects.push_back(Common::Rect(0, 0, getWidth(), getHeight())); +} + +void RL2Decoder::RL2VideoTrack::rl2DecodeFrameWithoutBackground(int screenOffset) { + if (screenOffset == -1) + screenOffset = _videoBase; + byte *destP = (byte *)_surface->getPixels() + screenOffset; + int frameSize = _surface->w * _surface->h - screenOffset; + + while (frameSize > 0) { + byte nextByte = _fileStream->readByte(); + + if (nextByte < 0x80) { + *destP++ = nextByte; + --frameSize; + } else if (nextByte == 0x80) { + int runLength = _fileStream->readByte(); + if (runLength == 0) + return; + + runLength = MIN(runLength, frameSize); + Common::fill(destP, destP + runLength, 0); + destP += runLength; + frameSize -= runLength; + } else { + int runLength = _fileStream->readByte(); + + runLength = MIN(runLength, frameSize); + Common::fill(destP, destP + runLength, nextByte & 0x7f); + destP += runLength; + frameSize -= runLength; + } + } +} + +void RL2Decoder::RL2VideoTrack::rl2DecodeFrameWithBackground() { + int screenOffset = _videoBase; + int frameSize = _surface->w * _surface->h - _videoBase; + byte *src = (byte *)_backSurface->getPixels(); + byte *dest = (byte *)_surface->getPixels(); + + while (frameSize > 0) { + byte nextByte = _fileStream->readByte(); + + if (nextByte == 0) { + dest[screenOffset] = src[screenOffset]; + ++screenOffset; + --frameSize; + } else if (nextByte < 0x80) { + dest[screenOffset] = nextByte | 0x80; + ++screenOffset; + --frameSize; + } else if (nextByte == 0x80) { + byte runLength = _fileStream->readByte(); + if (runLength == 0) + return; + + assert(runLength <= frameSize); + Common::copy(src + screenOffset, src + screenOffset + runLength, dest); + screenOffset += runLength; + frameSize -= runLength; + } else { + byte runLength = _fileStream->readByte(); + + assert(runLength <= frameSize); + Common::fill(dest + screenOffset, dest + screenOffset + runLength, nextByte & 0x7f); + screenOffset += runLength; + frameSize -= runLength; + } + } +} + +/*------------------------------------------------------------------------*/ + +RL2Decoder::RL2AudioTrack::RL2AudioTrack(const RL2FileHeader &header, Audio::Mixer::SoundType soundType): + _header(header), _soundType(soundType) { + _audStream = createAudioStream(); +} + +RL2Decoder::RL2AudioTrack::~RL2AudioTrack() { + delete _audStream; +} + +void RL2Decoder::RL2AudioTrack::queueSound(Common::SeekableReadStream *stream, int size) { + if (_audStream) { + // Queue the sound data + byte *data = (byte *)malloc(size); + stream->read(data, size); + Common::MemoryReadStream *memoryStream = new Common::MemoryReadStream(data, size, + DisposeAfterUse::YES); + + _audStream->queueAudioStream(Audio::makeRawStream(memoryStream, _header._rate, + Audio::FLAG_UNSIGNED, DisposeAfterUse::YES), DisposeAfterUse::YES); + } else { + delete stream; + } +} + +Audio::AudioStream *RL2Decoder::RL2AudioTrack::getAudioStream() const { + return _audStream; +} + +Audio::QueuingAudioStream *RL2Decoder::RL2AudioTrack::createAudioStream() { + return Audio::makeQueuingAudioStream(_header._rate, _header._channels == 2); +} + +} // End of namespace Video diff --git a/engines/voyeur/animation.h b/engines/voyeur/animation.h new file mode 100644 index 0000000000..c5991f49f0 --- /dev/null +++ b/engines/voyeur/animation.h @@ -0,0 +1,150 @@ +/* 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. + * + */ + +#ifndef VOYEUR_ANIMATION_H +#define VOYEUR_ANIMATION_H + +#include "video/video_decoder.h" +#include "audio/audiostream.h" +#include "audio/mixer.h" +#include "common/list.h" +#include "common/rect.h" +#include "common/stream.h" + +namespace Video { + +/** + * Decoder for RL2 videos. + * + * Video decoder used in engines: + * - voyeur + */ +class RL2Decoder : public VideoDecoder { + + class RL2FileHeader { + public: + uint32 _form; + uint32 _backSize; + uint32 _signature; + uint32 _dataSize; + int _numFrames; + int _method; + int _soundRate; + int _rate; + int _channels; + int _defSoundSize; + int _videoBase; + int _colorCount; + byte _palette[768]; + + uint32 *_frameOffsets; + int *_frameSoundSizes; + public: + RL2FileHeader(); + ~RL2FileHeader(); + void load(Common::SeekableReadStream *stream); + bool isValid() const; + }; + +private: + Audio::Mixer::SoundType _soundType; + RL2FileHeader _header; +public: + RL2Decoder(Audio::Mixer::SoundType soundType = Audio::Mixer::kPlainSoundType); + virtual ~RL2Decoder(); + + bool loadStream(Common::SeekableReadStream *stream); + + const Common::List<Common::Rect> *getDirtyRects() const; + void clearDirtyRects(); + void copyDirtyRectsToBuffer(uint8 *dst, uint pitch); + +private: + class RL2AudioTrack : public AudioTrack { + public: + RL2AudioTrack(const RL2FileHeader &header, Audio::Mixer::SoundType soundType); + ~RL2AudioTrack(); + + void queueSound(Common::SeekableReadStream *stream, int size); + Audio::Mixer::SoundType getSoundType() const { return _soundType; } + + protected: + Audio::AudioStream *getAudioStream() const; + + private: + Audio::Mixer::SoundType _soundType; + const RL2FileHeader &_header; + + Audio::QueuingAudioStream *_audStream; + Audio::QueuingAudioStream *createAudioStream(); + }; + + class RL2VideoTrack : public VideoTrack { + public: + RL2VideoTrack(const RL2FileHeader &header, RL2AudioTrack *audioTrack, + Common::SeekableReadStream *stream); + ~RL2VideoTrack(); + + bool endOfTrack() const; + bool isRewindable() const { return true; } + bool rewind(); + + uint16 getWidth() const; + uint16 getHeight() const; + Graphics::PixelFormat getPixelFormat() const; + int getCurFrame() const { return _curFrame; } + int getFrameCount() const { return _header._numFrames; } + uint32 getNextFrameStartTime() const { return _nextFrameStartTime; } + const Graphics::Surface *decodeNextFrame(); + const byte *getPalette() const { _dirtyPalette = false; return _header._palette; } + bool hasDirtyPalette() const { return _dirtyPalette; } + + const Common::List<Common::Rect> *getDirtyRects() const { return &_dirtyRects; } + void clearDirtyRects() { _dirtyRects.clear(); } + void copyDirtyRectsToBuffer(uint8 *dst, uint pitch); + + private: + Common::SeekableReadStream *_fileStream; + const RL2FileHeader &_header; + RL2AudioTrack *_audioTrack; + Graphics::Surface *_surface; + Graphics::Surface *_backSurface; + + mutable bool _dirtyPalette; + + int _curFrame; + uint32 _videoBase; + uint32 *_frameOffsets; + uint32 _frameDelay; + uint32 _nextFrameStartTime; + + Common::List<Common::Rect> _dirtyRects; + + void copyFrame(uint8 *data); + void rl2DecodeFrameWithBackground(); + void rl2DecodeFrameWithoutBackground(int screenOffset = -1); + }; +}; + +} // End of namespace Video + +#endif /* VOYEUR_ANIMATION_H */ diff --git a/engines/voyeur/configure.engine b/engines/voyeur/configure.engine new file mode 100644 index 0000000000..647e20267f --- /dev/null +++ b/engines/voyeur/configure.engine @@ -0,0 +1,3 @@ +# This file is included from the main "configure" script +# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps] +add_engine voyeur "Voyeur" yes diff --git a/engines/voyeur/debugger.cpp b/engines/voyeur/debugger.cpp new file mode 100644 index 0000000000..8407ead22f --- /dev/null +++ b/engines/voyeur/debugger.cpp @@ -0,0 +1,34 @@ +/* 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 "voyeur/debugger.h" + +#include "voyeur/graphics.h" +#include "voyeur/voyeur.h" + +namespace Voyeur { + +Debugger::Debugger() : GUI::Debugger() { + DCmd_Register("continue", WRAP_METHOD(Debugger, Cmd_Exit)); +} + +} // End of namespace Voyeur diff --git a/engines/voyeur/debugger.h b/engines/voyeur/debugger.h new file mode 100644 index 0000000000..302008716b --- /dev/null +++ b/engines/voyeur/debugger.h @@ -0,0 +1,45 @@ +/* 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. + * + */ + +#ifndef VOYEUR_DEBUGGER_H +#define VOYEUR_DEBUGGER_H + +#include "common/scummsys.h" +#include "gui/debugger.h" + +namespace Voyeur { + +class VoyeurEngine; + +class Debugger : public GUI::Debugger { +private: + VoyeurEngine *_vm; + +public: + Debugger(); + virtual ~Debugger() {} + void setVm(VoyeurEngine *vm) { _vm = vm; } +}; + +} // End of namespace Voyeur + +#endif diff --git a/engines/voyeur/detection.cpp b/engines/voyeur/detection.cpp new file mode 100644 index 0000000000..e9a5b8d982 --- /dev/null +++ b/engines/voyeur/detection.cpp @@ -0,0 +1,170 @@ +/* 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 "voyeur/voyeur.h" + +#include "base/plugins.h" +#include "common/savefile.h" +#include "common/str-array.h" +#include "common/memstream.h" +#include "engines/advancedDetector.h" +#include "common/system.h" +#include "graphics/colormasks.h" +#include "graphics/surface.h" + +#define MAX_SAVES 99 + +namespace Voyeur { + +struct VoyeurGameDescription { + ADGameDescription desc; +}; + +uint32 VoyeurEngine::getFeatures() const { + return _gameDescription->desc.flags; +} + +Common::Language VoyeurEngine::getLanguage() const { + return _gameDescription->desc.language; +} + +Common::Platform VoyeurEngine::getPlatform() const { + return _gameDescription->desc.platform; +} + +bool VoyeurEngine::getIsDemo() const { + return _gameDescription->desc.flags & ADGF_DEMO; +} + +} // End of namespace Voyeur + +static const PlainGameDescriptor voyeurGames[] = { + {"voyeur", "Voyeur"}, + {0, 0} +}; + +#include "voyeur/detection_tables.h" + +class VoyeurMetaEngine : public AdvancedMetaEngine { +public: + VoyeurMetaEngine() : AdvancedMetaEngine(Voyeur::gameDescriptions, sizeof(Voyeur::VoyeurGameDescription), voyeurGames) { + _maxScanDepth = 3; + } + + virtual const char *getName() const { + return "Voyeur Engine"; + } + + virtual const char *getOriginalCopyright() const { + return "Voyeur (c)"; + } + + virtual bool hasFeature(MetaEngineFeature f) const; + virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const; + virtual SaveStateList listSaves(const char *target) const; + virtual int getMaximumSaveSlot() const; + virtual void removeSaveState(const char *target, int slot) const; + SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const; +}; + +bool VoyeurMetaEngine::hasFeature(MetaEngineFeature f) const { + return + (f == kSupportsListSaves) || + (f == kSupportsLoadingDuringStartup) || + (f == kSupportsDeleteSave) || + (f == kSavesSupportMetaInfo) || + (f == kSavesSupportThumbnail); +} + +bool Voyeur::VoyeurEngine::hasFeature(EngineFeature f) const { + return + (f == kSupportsRTL) || + (f == kSupportsLoadingDuringRuntime) || + (f == kSupportsSavingDuringRuntime); +} + +bool VoyeurMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const { + const Voyeur::VoyeurGameDescription *gd = (const Voyeur::VoyeurGameDescription *)desc; + if (gd) { + *engine = new Voyeur::VoyeurEngine(syst, gd); + } + return gd != 0; +} + +SaveStateList VoyeurMetaEngine::listSaves(const char *target) const { + Common::SaveFileManager *saveFileMan = g_system->getSavefileManager(); + Common::StringArray filenames; + Common::String saveDesc; + Common::String pattern = Common::String::format("%s.0??", target); + + filenames = saveFileMan->listSavefiles(pattern); + sort(filenames.begin(), filenames.end()); // Sort to get the files in numerical order + + SaveStateList saveList; + for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) { + const char *ext = strrchr(file->c_str(), '.'); + int slot = ext ? atoi(ext + 1) : -1; + + if (slot >= 0 && slot < MAX_SAVES) { + Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(*file); + + if (in) { + delete in; + } + } + } + + return saveList; +} + +int VoyeurMetaEngine::getMaximumSaveSlot() const { + return MAX_SAVES; +} + +void VoyeurMetaEngine::removeSaveState(const char *target, int slot) const { + Common::String filename = Common::String::format("%s.%03d", target, slot); + g_system->getSavefileManager()->removeSavefile(filename); +} + +SaveStateDescriptor VoyeurMetaEngine::querySaveMetaInfos(const char *target, int slot) const { + Common::String filename = Common::String::format("%s.%03d", target, slot); + Common::InSaveFile *f = g_system->getSavefileManager()->openForLoading(filename); + + if (f) { + delete f; + + // Create the return descriptor + SaveStateDescriptor desc(slot, ""); + + return desc; + } + + return SaveStateDescriptor(); +} + + +#if PLUGIN_ENABLED_DYNAMIC(VOYEUR) +REGISTER_PLUGIN_DYNAMIC(VOYEUR, PLUGIN_TYPE_ENGINE, VoyeurMetaEngine); +#else +REGISTER_PLUGIN_STATIC(VOYEUR, PLUGIN_TYPE_ENGINE, VoyeurMetaEngine); +#endif diff --git a/engines/voyeur/detection_tables.h b/engines/voyeur/detection_tables.h new file mode 100644 index 0000000000..789eb4c22b --- /dev/null +++ b/engines/voyeur/detection_tables.h @@ -0,0 +1,45 @@ +/* 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. + * + */ + +namespace Voyeur { + +static const VoyeurGameDescription gameDescriptions[] = { + { + // Voyeur DOS English + { + "voyeur", + 0, + { + {"a1100100.rl2", 0, "b44630677618d034970ca0a13c1c1237", 336361}, + AD_LISTEND + }, + Common::EN_ANY, + Common::kPlatformDOS, + ADGF_NO_FLAGS, + GUIO1(GUIO_NONE) + }, + }, + + { AD_TABLE_END_MARKER } +}; + +} // End of namespace Voyeur diff --git a/engines/voyeur/events.cpp b/engines/voyeur/events.cpp new file mode 100644 index 0000000000..56b7afd377 --- /dev/null +++ b/engines/voyeur/events.cpp @@ -0,0 +1,379 @@ +/* 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 "voyeur/events.h" +#include "voyeur/voyeur.h" +#include "graphics/cursorman.h" +#include "graphics/palette.h" + +namespace Voyeur { + +IntNode::IntNode() { + _intFunc = NULL; + _curTime = 0; + _timeReset = 0; + _flags = 0; +} + +IntNode::IntNode(uint16 curTime, uint16 timeReset, uint16 flags) { + _intFunc = NULL; + _curTime = curTime; + _timeReset = timeReset; + _flags = flags; +} + +/*------------------------------------------------------------------------*/ + +EventsManager::EventsManager(): _intPtr(_gameData), + _fadeIntNode(0, 0, 3), _cycleIntNode(0, 0, 3) { + _cycleStatus = 0; + _mouseButton = 0; + _fadeStatus = 0; + _priorFrameTime = g_system->getMillis(); + Common::fill(&_keyState[0], &_keyState[256], false); +} + +void EventsManager::resetMouse() { + // No implementation +} + +void EventsManager::startMainClockInt() { + _mainIntNode._intFunc = &EventsManager::mainVoyeurIntFunc; + _mainIntNode._flags = 0; + _mainIntNode._curTime = 0; + _mainIntNode._timeReset = _vm->_graphicsManager._palFlag ? 50 : 60; +} + +void EventsManager::mainVoyeurIntFunc() { + // TODO +} + +void EventsManager::vStopCycle() { + _cycleIntNode._flags = 1; + _cycleStatus &= 2; +} + +void EventsManager::sWaitFlip() { + while (_gameData._flipWait && !_vm->shouldQuit()) { + pollEvents(); + g_system->delayMillis(10); + } + + Common::Array<ViewPortResource *> &viewPorts = _vm->_graphicsManager._viewPortListPtr->_entries; + for (uint idx = 0; idx < viewPorts.size(); ++idx) { + ViewPortResource &viewPort = *viewPorts[idx]; + + if (_vm->_graphicsManager._saveBack && (viewPort._flags & DISPFLAG_40)) { + Common::Rect *clipPtr = _vm->_graphicsManager._clipPtr; + _vm->_graphicsManager._clipPtr = &viewPort._clipRect; + + if (viewPort._restoreFn) + (_vm->_graphicsManager.*viewPort._restoreFn)(&viewPort); + + _vm->_graphicsManager._clipPtr = clipPtr; + viewPort._rectListCount[viewPort._pageIndex] = 0; + viewPort._rectListPtr[viewPort._pageIndex]->clear(); + viewPort._flags &= ~DISPFLAG_40; + } + } +} + +void EventsManager::checkForNextFrameCounter() { + // Check for next game frame + uint32 milli = g_system->getMillis(); + if ((milli - _priorFrameTime) >= GAME_FRAME_TIME) { + ++_gameCounter; + _priorFrameTime = milli; + + // Run the timer-based updates + voyeurTimer(); + + // Display the frame + g_system->copyRectToScreen((byte *)_vm->_graphicsManager._screenSurface.getPixels(), + SCREEN_WIDTH, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); + g_system->updateScreen(); + + // Signal the ScummVM debugger + _vm->_debugger.onFrame(); + } +} + +void EventsManager::voyeurTimer() { + _gameData.field22 += _gameData.field24; + _gameData.field1A += _gameData.field1E; + // _gameData.field1C += _gameData._timerFn; *** WHY INC field by a function pointer?! + + _gameData.field16 = 0; + _gameData.field3D = 1; + + if (--_gameData.field26 <= 0) { + if (_gameData._flipWait) { + _gameData.field38 = 1; + _gameData._flipWait = false; + _gameData.field3B = 0; + } + + _gameData.field26 >>= 8; + } + + videoTimer(); + + // Iterate through the list of registered nodes + Common::List<IntNode *>::iterator i; + for (i = _intNodes.begin(); i != _intNodes.end(); ++i) { + IntNode &node = **i; + + if (node._flags & 1) + continue; + if (!(node._flags & 2)) { + if (--node._curTime != 0) + continue; + + node._curTime = node._timeReset; + } + + (this->*node._intFunc)(); + } +} + +void EventsManager::videoTimer() { + if (_gameData._hasPalette) { + _gameData._hasPalette = false; + + g_system->getPaletteManager()->setPalette(_gameData._palette, + _gameData._palStartIndex, + _gameData._palEndIndex - _gameData._palStartIndex + 1); + } +} + +void EventsManager::delay(int cycles) { + uint32 totalMilli = cycles * 1000 / GAME_FRAME_RATE; + uint32 delayEnd = g_system->getMillis() + totalMilli; + + while (!_vm->shouldQuit() && g_system->getMillis() < delayEnd) { + g_system->delayMillis(10); + + pollEvents(); + } +} + +void EventsManager::pollEvents() { + checkForNextFrameCounter(); + + Common::Event event; + while (g_system->getEventManager()->pollEvent(event)) { + // Handle keypress + switch (event.type) { + case Common::EVENT_QUIT: + case Common::EVENT_RTL: + return; + + case Common::EVENT_KEYDOWN: + _keyState[(byte)toupper(event.kbd.ascii)] = true; + return; + case Common::EVENT_KEYUP: + _keyState[(byte)toupper(event.kbd.ascii)] = false; + return; + case Common::EVENT_LBUTTONDOWN: + _mouseButton = 1; + _vm->_voy._incriminate = true; + return; + case Common::EVENT_RBUTTONDOWN: + _mouseButton = 2; + return; + case Common::EVENT_LBUTTONUP: + case Common::EVENT_RBUTTONUP: + _vm->_voy._incriminate = false; + _mouseButton = 0; + return; + case Common::EVENT_MOUSEMOVE: + _mousePos = event.mouse; + break; + default: + break; + } + } +} + +void EventsManager::startFade(CMapResource *cMap) { + _fadeIntNode._flags |= 1; + if (_cycleStatus & 1) + _cycleIntNode._flags |= 1; + + _fadeFirstCol = cMap->_start; + _fadeLastCol = cMap->_end; + _fadeCount = cMap->_steps + 1; + + if (cMap->_steps > 0) { + _fadeStatus = cMap->_fadeStatus | 1; + byte *vgaP = &_vm->_graphicsManager._VGAColors[_fadeFirstCol * 3]; + int mapIndex = 0; + + for (int idx = _fadeFirstCol; idx <= _fadeLastCol; ++idx, vgaP += 3) { + ViewPortPalEntry &palEntry = _vm->_graphicsManager._viewPortListPtr->_palette[idx]; + palEntry._rEntry = vgaP[0] << 8; + int rDiff = (cMap->_entries[mapIndex * 3] << 8) - palEntry._rEntry; + palEntry._rChange = rDiff / cMap->_steps; + + palEntry._gEntry = vgaP[1] << 8; + int gDiff = (cMap->_entries[mapIndex * 3 + 1] << 8) - palEntry._gEntry; + palEntry._gChange = gDiff / cMap->_steps; + + palEntry._bEntry = vgaP[2] << 8; + int bDiff = (cMap->_entries[mapIndex * 3 + 2] << 8) - palEntry._bEntry; + palEntry._bChange = bDiff / cMap->_steps; + + palEntry._palIndex = idx; + if (!(cMap->_fadeStatus & 1)) + ++mapIndex; + } + + if (cMap->_fadeStatus & 2) + _intPtr.field3B = 1; + _fadeIntNode._flags &= ~1; + } else { + byte *vgaP = &_vm->_graphicsManager._VGAColors[_fadeFirstCol * 3]; + int mapIndex = 0; + + for (int idx = _fadeFirstCol; idx <= _fadeLastCol; ++idx, vgaP += 3) { + Common::copy(&cMap->_entries[mapIndex], &cMap->_entries[mapIndex + 3], vgaP); + + if (!(cMap->_fadeStatus & 1)) + mapIndex += 3; + } + + if (_intPtr._palStartIndex > _fadeFirstCol) + _intPtr._palStartIndex = _fadeFirstCol; + if (_intPtr._palEndIndex < _fadeLastCol) + _intPtr._palEndIndex = _fadeLastCol; + + _intPtr._hasPalette = true; + if (!(cMap->_fadeStatus & 2)) + _intPtr.field38 = 1; + } + + if (_cycleStatus & 1) + _cycleIntNode._flags &= ~1; +} + +void EventsManager::addIntNode(IntNode *node) { + _intNodes.push_back(node); +} + +void EventsManager::addFadeInt() { + IntNode &node = _fade2IntNode; + node._intFunc = &EventsManager::fadeIntFunc; + node._flags = 0; + node._curTime = 0; + node._timeReset = 1; + + addIntNode(&node); +} + +void EventsManager::vDoFadeInt() { + if (_intPtr.field3B & 1) + return; + if (--_fadeCount == 0) { + _fadeIntNode._flags |= 1; + _fadeStatus &= ~1; + } + + + for (int i = _fadeFirstCol; i <= _fadeLastCol; ++i) { + ViewPortPalEntry &palEntry = _vm->_graphicsManager._viewPortListPtr->_palette[i]; + byte *vgaP = &_vm->_graphicsManager._VGAColors[palEntry._palIndex * 3]; + + palEntry._rEntry += palEntry._rChange; + palEntry._gEntry += palEntry._gChange; + palEntry._bEntry += palEntry._bChange; + + vgaP[0] = palEntry._rEntry >> 8; + vgaP[1] = palEntry._gEntry >> 8; + vgaP[2] = palEntry._bEntry >> 8; + } + + if (_intPtr._palStartIndex > _fadeFirstCol) + _intPtr._palStartIndex = _fadeFirstCol; + if (_intPtr._palEndIndex < _fadeLastCol) + _intPtr._palEndIndex = _fadeLastCol; + + _intPtr._hasPalette = true; + _intPtr.field38 = 1; +} + +void EventsManager::vDoCycleInt() { + // TODO: more +} + + +void EventsManager::fadeIntFunc() { + // TODO: more +} + +void EventsManager::vInitColor() { + _fadeIntNode._intFunc = &EventsManager::vDoFadeInt; + _cycleIntNode._intFunc = &EventsManager::vDoCycleInt; + + addIntNode(&_fadeIntNode); + addIntNode(&_cycleIntNode); +} + +void EventsManager::setCursor(PictureResource *pic) { + PictureResource cursor; + cursor._bounds = pic->_bounds; + cursor._flags = DISPFLAG_CURSOR; + + _vm->_graphicsManager.sDrawPic(pic, &cursor, Common::Point()); +} + +void EventsManager::setCursor(byte *cursorData, int width, int height) { + CursorMan.replaceCursor(cursorData, width, height, 0, 0, 0); +} + +void EventsManager::setCursorColor(int idx, int mode) { + switch (mode) { + case 0: + _vm->_graphicsManager.setColor(idx, 90, 90, 232); + break; + case 1: + _vm->_graphicsManager.setColor(idx, 232, 90, 90); + break; + case 2: + _vm->_graphicsManager.setColor(idx, 90, 232, 90); + break; + case 3: + _vm->_graphicsManager.setColor(idx, 90, 232, 232); + break; + default: + break; + } +} + +void EventsManager::mouseOn() { + CursorMan.showMouse(true); +} + +void EventsManager::mouseOff() { + CursorMan.showMouse(false); +} + +} // End of namespace Voyeur diff --git a/engines/voyeur/events.h b/engines/voyeur/events.h new file mode 100644 index 0000000000..0b78bc2dd8 --- /dev/null +++ b/engines/voyeur/events.h @@ -0,0 +1,110 @@ +/* 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. + * + */ + +#ifndef VOYEUR_EVENTS_H +#define VOYEUR_EVENTS_H + +#include "common/scummsys.h" +#include "common/list.h" +#include "graphics/surface.h" +#include "voyeur/files.h" +#include "voyeur/game.h" + +namespace Voyeur { + +class VoyeurEngine; +class EventsManager; +class CMapResource; + +#define GAME_FRAME_RATE 50 +#define GAME_FRAME_TIME (1000 / GAME_FRAME_RATE) + +typedef void (EventsManager::*EventMethodPtr)(); + +class IntNode { +public: + EventMethodPtr _intFunc; + uint16 _curTime; + uint16 _timeReset; + uint32 _flags; +public: + IntNode(); + IntNode(uint16 curTime, uint16 timeReset, uint16 flags); +}; + +class EventsManager { +private: + VoyeurEngine *_vm; + uint32 _priorFrameTime; + uint32 _gameCounter; + bool _keyState[256]; + int _mouseButton; + Common::List<IntNode *> _intNodes; + Common::Point _mousePos; + + void mainVoyeurIntFunc(); +private: + void checkForNextFrameCounter(); + void voyeurTimer(); + void videoTimer(); + void vDoFadeInt(); + void vDoCycleInt(); + void fadeIntFunc(); +public: + IntData _gameData; + IntData &_intPtr; + IntNode _fadeIntNode; + IntNode _fade2IntNode; + IntNode _cycleIntNode; + IntNode _evintnode; + IntNode _mainIntNode; + int _cycleStatus; + int _fadeFirstCol, _fadeLastCol; + int _fadeCount; + int _fadeStatus; +public: + EventsManager(); + void setVm(VoyeurEngine *vm) { _vm = vm; } + + void resetMouse(); + void startMainClockInt(); + void vStopCycle(); + void sWaitFlip(); + void vInitColor(); + + void delay(int cycles); + void pollEvents(); + void startFade(CMapResource *cMap); + void addIntNode(IntNode *node); + void addFadeInt(); + + void setCursor(PictureResource *pic); + void setCursor(byte *cursorData, int width, int height); + void setCursorColor(int idx, int mode); + void mouseOn(); + void mouseOff(); + Common::Point getMousePos() { return _mousePos; } +}; + +} // End of namespace Voyeur + +#endif /* VOYEUR_EVENTS_H */ diff --git a/engines/voyeur/files.cpp b/engines/voyeur/files.cpp new file mode 100644 index 0000000000..34098e42a1 --- /dev/null +++ b/engines/voyeur/files.cpp @@ -0,0 +1,1215 @@ +/* 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 "voyeur/files.h" +#include "voyeur/graphics.h" +#include "voyeur/voyeur.h" + +namespace Voyeur { + +#define BOLT_GROUP_SIZE 16 + +BoltFilesState::BoltFilesState() { + _curLibPtr = NULL; + _curGroupPtr = NULL; + _curMemberPtr = NULL; + _curMemInfoPtr = NULL; + _fromGroupFlag = 0; + _xorMask = 0; + _encrypt = false; + _curFilePosition = 0; + _bufferEnd = 0; + _bufferBegin = 0; + _bytesLeft = 0; + _bufSize = 0; + _bufStart = NULL; + _bufPos = NULL; + _historyIndex = 0; + _runLength = 0; + _decompState = 0; + _runType = 0; + _runValue = 0; + _runOffset = 0; + Common::fill(&_historyBuffer[0], &_historyBuffer[0x200], 0); + _curFd = NULL; + _boltPageFrame = NULL; +} + +#define NEXT_BYTE if (--_bytesLeft < 0) nextBlock() + +byte *BoltFilesState::decompress(byte *buf, int size, int mode) { + if (!buf) { + buf = new byte[size]; + Common::fill(buf, buf + size, 0); + } + byte *bufP = buf; + + if (mode & 8) { + _decompState = 1; + _runType = 0; + _runLength = size; + } + + while (size > 0) { + if (!_decompState) { + NEXT_BYTE; + byte nextByte = *_bufPos++; + + switch (nextByte & 0xC0) { + case 0: + _runType = 0; + _runLength = 30 - (nextByte & 0x1f) + 1; + break; + case 0x40: + _runType = 1; + _runLength = 35 - (nextByte & 0x1f); + NEXT_BYTE; + _runOffset = *_bufPos++ + ((nextByte & 0x20) << 3); + break; + case 0x80: + _runType = 1; + _runLength = (nextByte & 0x20) ? ((32 - (nextByte & 0x1f)) << 2) + 2 : + (32 - (nextByte & 0x1f)) << 2; + NEXT_BYTE; + _runOffset = *_bufPos++ << 1; + break; + default: + _runType = 2; + + if (nextByte & 0x20) { + _runLength = 0; + } else { + NEXT_BYTE; + _runLength = ((32 - (nextByte & 0x1f)) + (*_bufPos++ << 5)) << 2; + NEXT_BYTE; + _bufPos++; + NEXT_BYTE; + _runValue = *_bufPos++; + } + break; + } + + _runOffset = _historyIndex - _runOffset; + } + + int runOffset = _runOffset & 0x1ff; + int len; + if (_runLength <= size) { + len = _runLength; + _decompState = 0; + } else { + _decompState = 1; + len = size; + _runLength -= size; + if (_runType == 1) + _runOffset += len; + } + + // Reduce the remaining size + size -= len; + + // Handle the run lengths + switch (_runType) { + case 0: + while (len-- > 0) { + NEXT_BYTE; + byte v = *_bufPos++; + _historyBuffer[_historyIndex] = v; + *bufP++ = v; + _historyIndex = (_historyIndex + 1) & 0x1ff; + } + break; + case 1: + while (len-- > 0) { + _historyBuffer[_historyIndex] = _historyBuffer[runOffset]; + *bufP++ = _historyBuffer[runOffset]; + _historyIndex = (_historyIndex + 1) & 0x1ff; + runOffset = (runOffset + 1) & 0x1ff; + } + break; + default: + while (len-- > 0) { + _historyBuffer[_historyIndex] = _runValue; + *bufP++ = _runValue; + _historyIndex = (_historyIndex + 1) & 0x1ff; + } + break; + } + } + + return buf; +} + +#undef NEXT_BYTE + +void BoltFilesState::nextBlock() { + if (_curFilePosition != _bufferEnd) + _curFd->seek(_bufferEnd); + + _bufferBegin = _bufferEnd; + int bytesRead = _curFd->read(_bufStart, _bufSize); + + _bufferEnd = _curFilePosition = _bufferBegin + bytesRead; + _bytesLeft = bytesRead - 1; + _bufPos = _bufStart; +} + +/*------------------------------------------------------------------------*/ + +FilesManager::FilesManager() { + _decompressSize = 0x7000; +} + +bool FilesManager::openBoltLib(const Common::String &filename, BoltFile *&boltFile) { + if (boltFile != NULL) { + _boltFilesState._curLibPtr = boltFile; + return true; + } + + // TODO: Specific library classes for buoy.blt versus stampblt.blt + // Create the bolt file interface object and load the index + boltFile = _boltFilesState._curLibPtr = new BoltFile(_boltFilesState); + return true; +} + +byte *FilesManager::fload(const Common::String &filename, int *size) { + Common::File f; + int filesize; + byte *data = NULL; + + if (f.open(filename)) { + // Read in the file + filesize = f.size(); + data = new byte[filesize]; + f.read(data, filesize); + } else { + filesize = 0; + } + + if (size) + *size = filesize; + return data; +} + +/*------------------------------------------------------------------------*/ + +const BoltMethodPtr BoltFile::_fnInitType[25] = { + &BoltFile::initDefault, &BoltFile::initDefault, &BoltFile::initDefault, &BoltFile::initDefault, + &BoltFile::initDefault, &BoltFile::initDefault, &BoltFile::initDefault, &BoltFile::initDefault, + &BoltFile::sInitPic, &BoltFile::initDefault, &BoltFile::vInitCMap, &BoltFile::vInitCycl, + &BoltFile::initDefault, &BoltFile::initDefault, &BoltFile::initDefault, &BoltFile::initViewPort, + &BoltFile::initViewPortList, &BoltFile::initFont, &BoltFile::initFontInfo, + &BoltFile::initSoundMap, &BoltFile::initDefault, &BoltFile::initDefault, &BoltFile::initDefault, + &BoltFile::initDefault, &BoltFile::initDefault +}; + +BoltFile::BoltFile(BoltFilesState &state): _state(state) { + _state._curFd = &_file; + if (!_file.open("bvoy.blt")) + error("Could not open buoy.blt"); + _state._curFilePosition = 0; + + // Read in the file header + byte header[16]; + _file.read(&header[0], 16); + + if (strncmp((const char *)&header[0], "BOLT", 4) != 0) + error("Tried to load non-bolt file"); + + int totalGroups = header[11] ? header[11] : 0x100; + for (int i = 0; i < totalGroups; ++i) + _groups.push_back(BoltGroup(_state._curFd)); +} + +BoltFile::~BoltFile() { + _state._curFd->close(); +} + +bool BoltFile::getBoltGroup(uint32 id) { + ++_state._fromGroupFlag; + _state._curLibPtr = this; + _state._curGroupPtr = &_groups[(id >> 8) & 0xff]; + + if (!_state._curGroupPtr->_loaded) { + // Load the group index + _state._curGroupPtr->load(); + } + + if (_state._curGroupPtr->_callInitGro) + initGro(); + + if ((id >> 16) != 0) { + id &= 0xff00; + for (int idx = 0; idx < _state._curGroupPtr->_count; ++idx, ++id) { + byte *member = getBoltMember(id); + assert(member); + } + } else if (!_state._curGroupPtr->_processed) { + _state._curGroupPtr->_processed = true; + _state._curGroupPtr->load(); + } + + resolveAll(); + --_state._fromGroupFlag; + return true; +} + +void BoltFile::freeBoltGroup(uint32 id) { + _state._curLibPtr = this; + _state._curGroupPtr = &_groups[(id >> 8) & 0xff]; + + // Unload the group + _state._curGroupPtr->unload(); +} + +BoltEntry &BoltFile::getBoltEntryFromLong(uint32 id) { + BoltGroup &group = _groups[id >> 24]; + assert(group._loaded); + + BoltEntry &entry = group._entries[(id >> 16) & 0xff]; + assert(!entry.hasResource() || (id & 0xffff) == 0); + + return entry; +} + +BoltEntry &BoltFile::boltEntry(uint16 id) { + BoltGroup &group = _groups[id >> 8]; + assert(group._loaded); + + BoltEntry &entry = group._entries[id & 0xff]; + assert(entry.hasResource()); + + return entry; +} + +PictureResource *BoltFile::getPictureResource(uint32 id) { + if ((int32)id == -1) + return NULL; + + if (id & 0xffff) + id <<= 16; + return getBoltEntryFromLong(id)._picResource; +} + +CMapResource *BoltFile::getCMapResource(uint32 id) { + if ((int32)id == -1) + return NULL; + + if (id & 0xffff) + id <<= 16; + return getBoltEntryFromLong(id)._cMapResource; +} + +byte *BoltFile::memberAddr(uint32 id) { + BoltGroup &group = _groups[id >> 8]; + if (!group._loaded) + return NULL; + + // If an entry already has a processed representation, we shouldn't + // still be accessing the raw data + BoltEntry &entry = group._entries[id & 0xff]; + assert(!entry.hasResource()); + + return entry._data; +} + +byte *BoltFile::memberAddrOffset(uint32 id) { + BoltGroup &group = _groups[id >> 24]; + if (!group._loaded) + return NULL; + + // If an entry already has a processed representation, we shouldn't + // still be accessing the raw data + BoltEntry &entry = group._entries[(id >> 16) & 0xff]; + assert(!entry.hasResource()); + + return entry._data + (id & 0xffff); +} + +/** + * Resolves an Id to an offset within a loaded resource + */ +void BoltFile::resolveIt(uint32 id, byte **p) { + if ((int32)id == -1) { + *p = NULL; + } else { + byte *ptr = memberAddrOffset(id); + if (ptr) { + *p = ptr; + } else { + *p = NULL; + assert(_state._resolves.size() < 1000); + _state._resolves.push_back(ResolveEntry(id, p)); + } + } +} + +void BoltFile::resolveFunction(uint32 id, GraphicMethodPtr *fn) { + if ((int32)id == -1) { + *fn = NULL; + } else { + error("Function fnTermGro array not supported"); + } +} + +/** + * Resolve any data references to within resources that weren't + * previously loaded, but are now + */ +void BoltFile::resolveAll() { + for (uint idx = 0; idx < _state._resolves.size(); ++idx) + *_state._resolves[idx]._p = memberAddrOffset(_state._resolves[idx]._id); +} + +byte *BoltFile::getBoltMember(uint32 id) { + _state._curLibPtr = this; + + // Get the group, and load it's entry list if not already loaded + _state._curGroupPtr = &_groups[(id >> 8) & 0xff]; + if (!_state._curGroupPtr->_loaded) + _state._curGroupPtr->load(); + + // Get the entry + _state._curMemberPtr = &_state._curGroupPtr->_entries[id & 0xff]; + if (_state._curMemberPtr->_field1) + initMem(_state._curMemberPtr->_field1); + + // Return the data for the entry if it's already been loaded + if (_state._curMemberPtr->_data) + return _state._curMemberPtr->_data; + + _state._xorMask = _state._curMemberPtr->_xorMask; + _state._encrypt = (_state._curMemberPtr->_mode & 0x10) != 0; + + if (_state._curGroupPtr->_processed) { + // TODO: Figure out weird access type. Uncompressed read perhaps? + //int fileDiff = _state._curGroupPtr->_fileOffset - _state._curMemberPtr->_fileOffset; + + } else { + _state._bufStart = _state._decompressBuf; + _state._bufSize = DECOMPRESS_SIZE; + + if ((_state._curFd != &_file) || (_state._curMemberPtr->_fileOffset < _state._bufferBegin) + || (_state._curMemberPtr->_fileOffset >= _state._bufferEnd)) { + _state._bytesLeft = 0; + _state._bufPos = _state._bufStart; + _state._bufferBegin = -1; + _state._bufferEnd = _state._curMemberPtr->_fileOffset; + } else { + _state._bufPos = _state._curMemberPtr->_fileOffset - _state._bufferBegin + _state._bufStart; + _state._bytesLeft = _state._bufSize - (_state._bufPos - _state._bufStart); + } + } + + _state._decompState = 0; + _state._historyIndex = 0; + + // Initialise the resource + assert(_state._curMemberPtr->_initMethod < 25); + (this->*_fnInitType[_state._curMemberPtr->_initMethod])(); + + return _state._curMemberPtr->_data; +} + +void BoltFile::initDefault() { + _state._curMemberPtr->_data = _state.decompress(0, _state._curMemberPtr->_size, + _state._curMemberPtr->_mode); +} + +void BoltFile::sInitPic() { + // Read in the header data + _state._curMemberPtr->_data = _state.decompress(NULL, 24, _state._curMemberPtr->_mode); + _state._curMemberPtr->_picResource = new PictureResource(_state, + _state._curMemberPtr->_data); +} + +void BoltFile::vInitCMap() { + initDefault(); + _state._curMemberPtr->_cMapResource = new CMapResource( + _state, _state._curMemberPtr->_data); +} + +void BoltFile::vInitCycl() { + initDefault(); + _state._vm->_eventsManager.vStopCycle(); + _state._curMemberPtr->_vInitCyclResource = new VInitCyclResource( + _state, _state._curMemberPtr->_data); +} + +void BoltFile::initViewPort() { + initDefault(); + + ViewPortResource *viewPort; + byte *src = _state._curMemberPtr->_data; + _state._curMemberPtr->_viewPortResource = viewPort = new ViewPortResource(_state, src); + + // This is done post-constructor, since viewports can be self referential, so + // we ned the _viewPortResource field to have been set before resolving the pointer + viewPort->_parent = getBoltEntryFromLong(READ_LE_UINT32(src + 2))._viewPortResource; +} + +void BoltFile::initViewPortList() { + initDefault(); + + ViewPortListResource *res; + _state._curMemberPtr->_viewPortListResource = res = new ViewPortListResource( + _state, _state._curMemberPtr->_data); + + _state._vm->_graphicsManager._viewPortListPtr = res; + _state._vm->_graphicsManager._vPort = &res->_entries[0]; +} + +void BoltFile::initFontInfo() { + initDefault(); + _state._curMemberPtr->_fontInfoResource = new FontInfoResource( + _state, _state._curMemberPtr->_data); +} + +void BoltFile::initFont() { + initDefault(); + _state._curMemberPtr->_fontResource = new FontResource(_state, _state._curMemberPtr->_data); +} + +void BoltFile::initSoundMap() { + initDefault(); +} + +/*------------------------------------------------------------------------*/ + +BoltGroup::BoltGroup(Common::SeekableReadStream *f): _file(f) { + byte buffer[BOLT_GROUP_SIZE]; + + _loaded = false; + + _file->read(&buffer[0], BOLT_GROUP_SIZE); + _processed = buffer[0] != 0; + _callInitGro = buffer[1] != 0; + _termGroIndex = buffer[2]; + _count = buffer[3] ? buffer[3] : 256; // TODO: Added this in. Check it's okay + _fileOffset = READ_LE_UINT32(&buffer[8]); +} + +BoltGroup::~BoltGroup() { +} + +void BoltGroup::load() { + _file->seek(_fileOffset); + + // Read the entries + for (int i = 0; i < _count; ++i) + _entries.push_back(BoltEntry(_file)); + + _loaded = true; +} + +void BoltGroup::unload() { + if (!_loaded) + return; + + _entries.clear(); + _loaded = false; +} + +/*------------------------------------------------------------------------*/ + +BoltEntry::BoltEntry(Common::SeekableReadStream *f): _file(f) { + _data = NULL; + _picResource = NULL; + _viewPortResource = NULL; + _viewPortListResource = NULL; + _fontResource = NULL; + _fontInfoResource = NULL; + _cMapResource = NULL; + _vInitCyclResource = NULL; + + byte buffer[16]; + _file->read(&buffer[0], 16); + _mode = buffer[0]; + _field1 = buffer[1]; + _initMethod = buffer[3]; + _xorMask = buffer[4] & 0xff; // TODO: Is this right?? + _size = READ_LE_UINT32(&buffer[4]); + _fileOffset = READ_LE_UINT32(&buffer[8]); +} + +BoltEntry::~BoltEntry() { + delete[] _data; + delete _picResource; + delete _viewPortResource; + delete _viewPortListResource; + delete _fontResource; + delete _fontInfoResource; + delete _cMapResource; + delete _vInitCyclResource; +} + +void BoltEntry::load() { + // TODO: Currently, all entry loading and decompression is done in BoltFile::memberAddr. + // Ideally, a lot of the code should be moved here +} + +/** + * Returns true if the given bolt entry has an attached resource + */ +bool BoltEntry::hasResource() const { + return _picResource || _viewPortResource || _viewPortListResource + || _fontResource || _fontInfoResource || _cMapResource || _vInitCyclResource; +} + +/*------------------------------------------------------------------------*/ + +PictureResource::PictureResource(BoltFilesState &state, const byte *src) { + _flags = READ_LE_UINT16(src); + _select = src[2]; + _pick = src[3]; + _onOff = src[4]; + _depth = src[5]; + + int xs = READ_LE_UINT16(&src[6]); + int ys = READ_LE_UINT16(&src[8]); + _bounds = Common::Rect(xs, ys, xs + READ_LE_UINT16(&src[10]), + ys + READ_LE_UINT16(&src[12])); + _maskData = READ_LE_UINT32(&src[14]); + _planeSize = READ_LE_UINT16(&src[22]); + + _imgData = NULL; + + int nbytes = _bounds.width() * _bounds.height(); + if (_flags & 0x20) { + error("TODO: sInitPic flags&0x20"); + } else if (_flags & 8) { + int mode = 0; + if (_bounds.width() == 320) { + mode = 147; + state._sImageShift = 2; + state._SVGAReset = false; + } else { + state._SVGAReset = true; + if (_bounds.width() == 640) { + if (_bounds.height() == 400) { + mode = 220; + state._sImageShift = 3; + } else { + mode = 221; + state._sImageShift = 3; + } + } else if (_bounds.width() == 800) { + mode = 222; + state._sImageShift = 3; + } else if (_bounds.width() == 1024) { + mode = 226; + state._sImageShift = 3; + } + } + + if (mode != state._vm->_graphicsManager._SVGAMode) { + state._vm->_graphicsManager._SVGAMode = mode; + state._vm->_graphicsManager.clearPalette(); + } + +// byte *imgData = _imgData; + if (_flags & 0x10) { + // TODO: Figure out what it's doing. Looks like a direct clearing + // of the screen directly + } else { + // TODO: Figure out direct screen loading + } + } else { + if (_flags & 0x1000) { + if (!(_flags & 0x10)) + nbytes = state._curMemberPtr->_size - 24; + + int mask = (nbytes + 0x3FFF) >> 14; + _imgData = NULL; + + if (state._boltPageFrame == 0) + state.EMSGetFrameAddr(&state._boltPageFrame); + if (state._boltPageFrame != 0) { + if (!state.EMSAllocatePages(&_planeSize)) { + _maskData = mask; + + for (int idx = 0; idx < mask; ++idx) + state.EMSMapPageHandle(_planeSize, idx, idx); + + state.decompress(state._boltPageFrame, nbytes, state._curMemberPtr->_mode); + return; + } + } + } + + if (_flags & 0x10) { + _imgData = new byte[nbytes]; + Common::fill(_imgData, _imgData + nbytes, 0); + } else { + _imgData = state.decompress(NULL, nbytes, state._curMemberPtr->_mode); + } + } +} + +PictureResource::PictureResource() { + _flags = 0; + _select = 0; + _pick = 0; + _onOff = 0; + _depth = 0; + _maskData = 0; + _planeSize = 0; + + _imgData = NULL; +} + +PictureResource::PictureResource(int flags, int select, int pick, int onOff, + int depth, const Common::Rect &bounds, int maskData, byte *imgData, + int planeSize) { + _flags = flags; + _select = select; + _pick = pick; + _onOff = onOff; + _depth = depth; + _bounds = bounds; + _maskData = maskData; + _imgData = imgData; + _planeSize = planeSize; +} + +PictureResource::~PictureResource() { + delete[] _imgData; +} + +/*------------------------------------------------------------------------*/ + +ViewPortResource::ViewPortResource(BoltFilesState &state, const byte *src): + _fontChar(0, 0xff, 0xff, 0, 0, Common::Rect(), 0, NULL, 0), _state(state) { + _flags = READ_LE_UINT16(src); + _parent = NULL; + _pageCount = READ_LE_UINT16(src + 6); + _pageIndex = READ_LE_UINT16(src + 8); + _lastPage = READ_LE_UINT16(src + 10); + + int xs = READ_LE_UINT16(src + 12); + int ys = READ_LE_UINT16(src + 14); + _bounds = Common::Rect(xs, ys, xs + READ_LE_UINT16(src + 16), + ys + READ_LE_UINT16(src + 18)); + _field18 = READ_LE_UINT16(src + 0x18); + + _currentPic = state._curLibPtr->getPictureResource(READ_LE_UINT32(src + 0x20)); + _activePage = state._curLibPtr->getPictureResource(READ_LE_UINT32(src + 0x24)); + _pages[0] = state._curLibPtr->getPictureResource(READ_LE_UINT32(src + 0x28)); + _pages[1] = state._curLibPtr->getPictureResource(READ_LE_UINT32(src + 0x2C)); + + state._curLibPtr->resolveIt(READ_LE_UINT32(src + 0x30), &_field30); + + // Get the rect list + for (int listIndex = 0; listIndex < 3; ++listIndex) { + _rectListCount[listIndex] = (int16)READ_LE_UINT16(src + 0x40 + 2 * listIndex); + uint32 id = READ_LE_UINT32(src + 0x34 + listIndex * 4); + + if (id == -1) { + _rectListPtr[listIndex] = NULL; + } else { + _rectListPtr[listIndex] = new Common::Array<Common::Rect>(); + + if (_rectListCount[listIndex] > 0) { + int16 *rectList = (int16 *)state._curLibPtr->memberAddrOffset(id); + for (int i = 0; i < _rectListCount[listIndex]; ++i) { + int xs = FROM_LE_16(rectList[0]); + int ys = FROM_LE_16(rectList[1]); + _rectListPtr[i]->push_back(Common::Rect(xs, ys, xs + FROM_LE_16(rectList[2]), + ys + FROM_LE_16(rectList[3]))); + } + } + } + } + + xs = READ_LE_UINT16(src + 0x46); + ys = READ_LE_UINT16(src + 0x48); + _clipRect = Common::Rect(xs, ys, xs + READ_LE_UINT16(src + 0x4A), + ys + READ_LE_UINT16(src + 0x4C)); + + state._curLibPtr->resolveIt(READ_LE_UINT32(src + 0x7A), &_field7A); + + state._curLibPtr->resolveFunction(READ_LE_UINT32(src + 0x7E), (GraphicMethodPtr *)&_fn1); + state._curLibPtr->resolveFunction(READ_LE_UINT32(src + 0x82), (GraphicMethodPtr *)&_setupFn); + state._curLibPtr->resolveFunction(READ_LE_UINT32(src + 0x86), (GraphicMethodPtr *)&_addFn); + state._curLibPtr->resolveFunction(READ_LE_UINT32(src + 0x8A), (GraphicMethodPtr *)&_restoreFn); + + if (!_restoreFn && _addFn) + _addFn = &GraphicsManager::addRectNoSaveBack; +} + +ViewPortResource::~ViewPortResource() { + for (int i = 0; i < 3; ++i) + delete _rectListPtr[i]; +} + +void ViewPortResource::setupViewPort(PictureResource *page, Common::Rect *clipRect, + ViewPortSetupPtr setupFn, ViewPortAddPtr addFn, ViewPortRestorePtr restoreFn) { + PictureResource *pic = _currentPic; + Common::Rect r = _bounds; + r.translate(pic->_bounds.left, pic->_bounds.top); + int xDiff, yDiff; + + if (page) { + // Clip based on the passed picture resource + xDiff = page->_bounds.left - r.left; + yDiff = page->_bounds.top - r.top; + + if (xDiff > 0) { + int width = r.width(); + r.left = page->_bounds.left; + r.setWidth(xDiff <= width ? width - xDiff : 0); + } + if (yDiff > 0) { + int height = r.height(); + r.top = page->_bounds.top; + r.setHeight(yDiff <= height ? height - yDiff : 0); + } + + xDiff = r.right - page->_bounds.right; + yDiff = r.bottom - page->_bounds.bottom; + + if (xDiff > 0) + r.setWidth(xDiff <= r.width() ? r.width() - xDiff : 0); + if (yDiff > 0) + r.setHeight(yDiff <= r.height() ? r.height() - yDiff : 0); + } + + if (clipRect) { + // Clip based on the passed clip rectangles + xDiff = clipRect->left - r.left; + yDiff = clipRect->top - r.top; + + if (xDiff > 0) { + int width = r.width(); + r.left = clipRect->left; + r.setWidth(xDiff <= width ? width - xDiff : 0); + } + if (yDiff > 0) { + int height = r.height(); + r.top = clipRect->top; + r.setHeight(yDiff <= height ? height - yDiff : 0); + } + + xDiff = r.right - clipRect->right; + yDiff = r.right - clipRect->right; + + if (xDiff > 0) + r.setWidth(xDiff <= r.width() ? r.width() - xDiff : 0); + if (yDiff > 0) + r.setHeight(yDiff <= r.height() ? r.height() - yDiff : 0); + } +// clip = (0x20, 0x14, width: 0x140, height: 0C8h + _activePage = page; + _field18 = 0; + _clipRect = r; + _setupFn = setupFn; + _addFn = addFn; + _restoreFn = restoreFn; + + if (setupFn) + (_state._vm->_graphicsManager.*setupFn)(this); +} + +void ViewPortResource::setupViewPort() { + setupViewPort(_state._vm->_graphicsManager._backgroundPage, NULL, + &GraphicsManager::setupMCGASaveRect, &GraphicsManager::addRectOptSaveRect, + &GraphicsManager::restoreMCGASaveRect); +} + +int ViewPortResource::drawText(const Common::String &msg) { + GraphicsManager &gfxManager = _state._vm->_graphicsManager; + assert(gfxManager._fontPtr); + assert(gfxManager._fontPtr->_curFont); + FontInfoResource &fontInfo = *gfxManager._fontPtr; + FontResource &fontData = *fontInfo._curFont; + int xShadows[9] = { 0, 1, 1, 1, 0, -1, -1, -1, 0 }; + int yShadows[9] = { 0, 1, 0, -1, -1, -1, 0, 1, 1 }; + + Common::Rect *clipPtr = gfxManager._clipPtr; + if (!(fontInfo._picFlags & DISPFLAG_1)) + gfxManager._clipPtr = NULL; + + int minChar = fontData._minChar; + int padding = fontData._padding; + int fontHeight = fontData._fontHeight; + int totalChars = fontData._maxChar - fontData._minChar; + int msgWidth = 0; + int xp = 0, yp = 0; + + Common::Point pos = Common::Point(fontInfo._pos.x, fontInfo._pos.y + fontData._topPadding); + + _fontChar._flags = fontInfo._picFlags | DISPFLAG_2; + _fontChar._select = fontInfo._picSelect; + _fontChar._bounds.setHeight(fontHeight); + + if (gfxManager._drawTextPermFlag || (fontInfo._fontFlags & DISPFLAG_1) || fontInfo._justify || + (gfxManager._saveBack && fontInfo._fontSaveBack && (_flags & DISPFLAG_VIEWPORT))) { + msgWidth = textWidth(msg); + yp = pos.y; + xp = pos.x; + + switch (fontInfo._justify) { + case 1: + xp = pos.x + (fontInfo._justifyWidth / 2) - (msgWidth / 2); + break; + case 2: + xp = pos.x + fontInfo._justifyWidth - msgWidth; + break; + default: + break; + } + + if (!(fontInfo._fontFlags & 3)) { + _fontRect.left = xp; + _fontRect.top = yp; + _fontRect.setWidth(msgWidth); + _fontRect.setHeight(fontHeight); + } else { + _fontRect.left = pos.x; + _fontRect.top = pos.y; + _fontRect.setWidth(fontInfo._justifyWidth); + _fontRect.setHeight(fontInfo._justifyHeight); + } + + pos.x = xp; + pos.y = yp; + + if (fontInfo._fontFlags & 4) { + if (fontInfo._shadow.x <= 0) { + _fontRect.left += fontInfo._shadow.x; + _fontRect.right -= fontInfo._shadow.x * 2; + } else { + _fontRect.right += fontInfo._shadow.x; + } + + if (fontInfo._shadow.y <= 0) { + _fontRect.top += fontInfo._shadow.y; + _fontRect.bottom -= fontInfo._shadow.y * 2; + } else { + _fontRect.bottom += fontInfo._shadow.y; + } + } else if (fontInfo._fontFlags & 8) { + if (fontInfo._shadow.x <= 0) { + _fontRect.left += fontInfo._shadow.x; + _fontRect.right -= fontInfo._shadow.x * 3; + } else { + _fontRect.right += fontInfo._shadow.x * 3; + _fontRect.left -= fontInfo._shadow.x; + } + + if (fontInfo._shadow.y <= 0) { + _fontRect.top += fontInfo._shadow.y; + _fontRect.bottom -= fontInfo._shadow.y * 3; + } else { + _fontRect.bottom += fontInfo._shadow.y * 3; + _fontRect.top -= fontInfo._shadow.y; + } + } + } + + if (gfxManager._saveBack && fontInfo._fontSaveBack && (_flags & DISPFLAG_VIEWPORT)) { + addSaveRect(_pageIndex, _fontRect); + } + + if (fontInfo._fontFlags & DISPFLAG_1) { + gfxManager._drawPtr->_pos = Common::Point(_fontRect.left, _fontRect.top); + gfxManager._drawPtr->_penColor = fontInfo._backColor; + sFillBox(_fontRect.width()); + } + + bool saveBack = gfxManager._saveBack; + gfxManager._saveBack = false; + + int count = 0; + if (fontInfo._fontFlags & DISPFLAG_4) + count = 1; + else if (fontInfo._fontFlags & DISPFLAG_8) + count = 8; + + for (int i = count; i >= 0; --i) { + xp = pos.x; + yp = pos.y; + + switch (xShadows[i]) { + case -1: + xp -= fontInfo._shadow.x; + break; + case 1: + xp += fontInfo._shadow.x; + break; + default: + break; + } + + switch (yShadows[i]) { + case -1: + yp -= fontInfo._shadow.y; + break; + case 1: + yp += fontInfo._shadow.y; + break; + default: + break; + } + + if (i != 0) { + _fontChar._pick = 0; + _fontChar._onOff = fontInfo._shadowColor; + } else if (fontData.field2 == 1 || (fontInfo._fontFlags & 0x10)) { + _fontChar._pick = 0; + _fontChar._onOff = fontInfo._foreColor; + } else { + _fontChar._pick = fontInfo._picPick; + _fontChar._onOff = fontInfo._picOnOff; + _fontChar._depth = fontData.field2; + } + + // Loop to draw each character in turn + msgWidth = -padding; + const char *msgP = msg.c_str(); + char ch; + + while ((ch = *msgP++) != '\0') { + int charValue = (int)ch - minChar; + if (charValue < 0 || charValue >= totalChars || fontData._charWidth[charValue] == 0) + charValue = fontData._maxChar - minChar; + + int charWidth = fontData._charWidth[charValue]; + _fontChar._bounds.setWidth(charWidth); + + uint16 offset = READ_LE_UINT16(fontData._data1 + charValue * 2); + _fontChar._imgData = fontData._data2 + offset * 2; + + gfxManager.sDrawPic(&_fontChar, this, Common::Point(xp, yp)); + + _fontChar._imgData = NULL; + xp += charWidth + padding; + msgWidth += charWidth + padding; + } + } + + msgWidth = MAX(msgWidth, 0); + if (fontInfo._justify == ALIGN_LEFT) + fontInfo._pos.x = xp; + + gfxManager._saveBack = saveBack; + gfxManager._clipPtr = clipPtr; + + return msgWidth; +} + +int ViewPortResource::textWidth(const Common::String &msg) { + if (msg.size() == 0) + return 0; + + const char *msgP = msg.c_str(); + FontResource &fontData = *_state._vm->_graphicsManager._fontPtr->_curFont; + int minChar = fontData._minChar; + int maxChar = fontData._maxChar; + int padding = fontData._padding; + int totalWidth = -padding; + char ch; + + // Loop through the characters + while ((ch = *msgP++) != '\0') { + int charValue = (int)ch; + if (charValue < minChar || charValue > maxChar) + charValue = maxChar; + + if (!fontData._charWidth[charValue - minChar]) + charValue = maxChar; + + totalWidth += fontData._charWidth[charValue - minChar] + padding; + } + + if (totalWidth < 0) + totalWidth = 0; + return totalWidth; +} + +void ViewPortResource::addSaveRect(int pageIndex, const Common::Rect &r) { + // TODO +} + +void ViewPortResource::sFillBox(int width) { + // TODO +} + +void ViewPortResource::fillPic(byte onOff) { + _state._vm->_graphicsManager.fillPic(this, onOff); +} + +/*------------------------------------------------------------------------*/ + +ViewPortListResource::ViewPortListResource(BoltFilesState &state, const byte *src) { + uint count = READ_LE_UINT16(src); + _palIndex = READ_LE_UINT16(src + 2); + + // Load palette map + byte *palData = state._curLibPtr->memberAddr(READ_LE_UINT32(src + 4)); + for (uint i = 0; i < 256; ++i, palData += 16) + _palette.push_back(ViewPortPalEntry(palData)); + + // Load view port pointer list + uint32 *idP = (uint32 *)&src[8]; + for (uint i = 0; i < count; ++i, ++idP) { + uint32 id = READ_LE_UINT32(idP); + BoltEntry &entry = state._curLibPtr->getBoltEntryFromLong(id); + + assert(entry._viewPortResource); + _entries.push_back(entry._viewPortResource); + } +} + +/*------------------------------------------------------------------------*/ + +ViewPortPalEntry::ViewPortPalEntry(const byte *src) { + uint16 *v = (uint16 *)src; + _rEntry = READ_LE_UINT16(v++); + _gEntry = READ_LE_UINT16(v++); + _bEntry = READ_LE_UINT16(v++); + _rChange = READ_LE_UINT16(v++); + _gChange = READ_LE_UINT16(v++); + _bChange = READ_LE_UINT16(v++); + _palIndex = READ_LE_UINT16(v++); +} + + +/*------------------------------------------------------------------------*/ + +FontResource::FontResource(BoltFilesState &state, byte *src) { + _minChar = src[0]; + _maxChar = src[1]; + field2 = src[2]; + _padding = src[3]; + _fontHeight = src[5]; + _topPadding = (int8)src[6]; + + int totalChars = _maxChar - _minChar + 1; + _charWidth = new int[totalChars]; + for (int i = 0; i < totalChars; ++i) + _charWidth[i] = READ_LE_UINT16(src + 8 + 2 * i); + + _data1 = src + 8 + totalChars * 2; + _data2 = _data1 + totalChars * 2; +} + +FontResource::~FontResource() { + delete[] _charWidth; +} + +/*------------------------------------------------------------------------*/ + +FontInfoResource::FontInfoResource(BoltFilesState &state, const byte *src) { + _curFont = NULL; + _picFlags = src[4]; + _picSelect = src[5]; + _picPick = src[6]; + _picOnOff = src[7]; + _fontFlags = src[8]; + _justify = (FontJustify)src[9]; + _fontSaveBack = READ_LE_UINT16(src + 10); + _pos.x = (int16)READ_LE_UINT16(src + 12); + _pos.y = (int16)READ_LE_UINT16(src + 14); + _justifyWidth = READ_LE_UINT16(src + 16); + _justifyHeight = READ_LE_UINT16(src + 18); + _shadow.x = READ_LE_UINT16(src + 20); + _shadow.y = READ_LE_UINT16(src + 22); + _foreColor = READ_LE_UINT16(src + 24); + _backColor = READ_LE_UINT16(src + 26); + _shadowColor = READ_LE_UINT16(src + 28); +} + +FontInfoResource::FontInfoResource() { + _curFont = NULL; + _picFlags = 3; + _picSelect = 0xff; + _picPick = 0xff; + _picOnOff = 0; + _fontFlags = 0; + _justify = ALIGN_LEFT; + _fontSaveBack = 0; + _justifyWidth = 1; + _justifyHeight = 1; + _shadow = Common::Point(1, 1); + _foreColor = 1; + _backColor = 0; + _shadowColor = 0; +} + +FontInfoResource::FontInfoResource(byte picFlags, byte picSelect, byte picPick, byte picOnOff, + byte fontFlags, FontJustify justify, int fontSaveBack, const Common::Point &pos, + int justifyWidth, int justifyHeight, const Common::Point &shadow, int foreColor, + int backColor, int shadowColor) { + _curFont = NULL; + _picFlags = picFlags; + _picSelect = picSelect; + _picPick = picPick; + _picOnOff = picOnOff; + _fontFlags = fontFlags; + _justify = justify; + _fontSaveBack = fontSaveBack; + _pos = pos; + _justifyWidth = justifyWidth; + _justifyHeight = justifyHeight; + _shadow = shadow; + _foreColor = foreColor; + _backColor = backColor; + _shadowColor = shadowColor; +} + +/*------------------------------------------------------------------------*/ + +CMapResource::CMapResource(BoltFilesState &state, const byte *src): _vm(state._vm) { + _steps = src[0]; + _fadeStatus = src[1]; + _start = READ_LE_UINT16(src + 2); + _end = READ_LE_UINT16(src + 4); + + int count = _end - _start + 1; + _entries = new byte[count * 3]; + Common::copy(src + 6, src + 6 + 3 * count, _entries); + + int palIndex = state._vm->_graphicsManager._viewPortListPtr->_palIndex; + if (_end > palIndex) + _end = palIndex; + if (_start > palIndex) + _start = palIndex; +} + +CMapResource::~CMapResource() { + delete[] _entries; +} + +void CMapResource::startFade() { + _vm->_eventsManager.startFade(this); +} + +/*------------------------------------------------------------------------*/ + +VInitCyclResource::VInitCyclResource(BoltFilesState &state, const byte *src) { + for (int i = 0; i < 4; ++i) { + state._curLibPtr->resolveIt(READ_LE_UINT32(src + 8 + i * 4), &_ptr[i]); + } +} + +} // End of namespace Voyeur diff --git a/engines/voyeur/files.h b/engines/voyeur/files.h new file mode 100644 index 0000000000..b66546cd0c --- /dev/null +++ b/engines/voyeur/files.h @@ -0,0 +1,368 @@ +/* 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. + * + */ + +#ifndef VOYEUR_FILES_H +#define VOYEUR_FILES_H + +#include "common/scummsys.h" +#include "common/file.h" +#include "common/rect.h" +#include "common/str.h" +#include "voyeur/graphics.h" + +namespace Voyeur { + +class VoyeurEngine; +class BoltFile; +class BoltGroup; +class BoltEntry; +class PictureResource; +class ViewPortResource; +class ViewPortListResource; +class FontResource; +class CMapResource; +class VInitCyclResource; + +#define DECOMPRESS_SIZE 0x7000 + +typedef void (BoltFile::*BoltMethodPtr)(); + +class ResolveEntry { +public: + uint32 _id; + byte **_p; + + ResolveEntry(uint32 id, byte **p) { _id = id; _p = p; } +}; + +class BoltFilesState { +public: + VoyeurEngine *_vm; + BoltFile *_curLibPtr; + BoltGroup *_curGroupPtr; + BoltEntry *_curMemberPtr; + byte *_curMemInfoPtr; + int _fromGroupFlag; + byte _xorMask; + bool _encrypt; + int _curFilePosition; + int _bufferEnd; + int _bufferBegin; + int _bytesLeft; + int _bufSize; + byte *_bufStart; + byte *_bufPos; + byte _decompressBuf[DECOMPRESS_SIZE]; + int _historyIndex; + byte _historyBuffer[0x200]; + int _runLength; + int _decompState; + int _runType; + int _runValue; + int _runOffset; + Common::File *_curFd; + Common::Array<ResolveEntry> _resolves; + + byte *_boltPageFrame; + int _sImageShift; + bool _SVGAReset; +public: + BoltFilesState(); + + byte *decompress(byte *buf, int size, int mode); + void nextBlock(); + + void EMSGetFrameAddr(byte **pageFrame) {} // TODO: Maybe? + bool EMSAllocatePages(uint *planeSize) { return false; } // TODO: Maybe? + void EMSMapPageHandle(int planeSize, int idx1, int idx2) {} // TODO: Maybe? +}; + +class BoltFile { +private: + static const BoltMethodPtr _fnInitType[25]; +private: + BoltFilesState &_state; + Common::Array<BoltGroup> _groups; + Common::File _file; + + // initType method table + void initDefault(); + void sInitPic(); + void vInitCMap(); + void vInitCycl(); + void initViewPort(); + void initViewPortList(); + void initFontInfo(); + void initFont(); + void initSoundMap(); +private: + void resolveAll(); + byte *getBoltMember(uint32 id); + + void termType() {} // TODO + void initMem(int id) {} // TODO + void termMem() {} // TODO + void initGro() {} // TODO + void termGro() {} // TODO +public: + BoltFile(BoltFilesState &state); + ~BoltFile(); + + bool getBoltGroup(uint32 id); + void freeBoltGroup(uint32 id); + byte *memberAddr(uint32 id); + byte *memberAddrOffset(uint32 id); + void resolveIt(uint32 id, byte **p); + void resolveFunction(uint32 id, GraphicMethodPtr *fn); + + BoltEntry &boltEntry(uint16 id); + BoltEntry &getBoltEntryFromLong(uint32 id); + PictureResource *getPictureResource(uint32 id); + CMapResource *getCMapResource(uint32 id); +}; + +class BoltGroup { +private: + Common::SeekableReadStream *_file; +public: + byte _loaded; + bool _processed; + bool _callInitGro; + int _termGroIndex; + int _count; + int _fileOffset; + Common::Array<BoltEntry> _entries; +public: + BoltGroup(Common::SeekableReadStream *f); + virtual ~BoltGroup(); + + void load(); + void unload(); +}; + + +class BoltEntry { +private: + Common::SeekableReadStream *_file; +public: + byte _mode; + byte _field1; + byte _initMethod; + int _fileOffset; + byte _xorMask; + int _size; + byte *_data; + + PictureResource *_picResource; + ViewPortResource *_viewPortResource; + ViewPortListResource *_viewPortListResource; + FontResource *_fontResource; + FontInfoResource *_fontInfoResource; + CMapResource *_cMapResource; + VInitCyclResource *_vInitCyclResource; +public: + BoltEntry(Common::SeekableReadStream *f); + virtual ~BoltEntry(); + + void load(); + bool hasResource() const; +}; + +class FilesManager { +private: + int _decompressSize; +public: + BoltFilesState _boltFilesState; + BoltFile *_curLibPtr; +public: + FilesManager(); + void setVm(VoyeurEngine *vm) { _boltFilesState._vm = vm; } + + bool openBoltLib(const Common::String &filename, BoltFile *&boltFile); + byte *fload(const Common::String &filename, int *size = NULL); +}; + +enum DisplayFlag { DISPFLAG_1 = 1, DISPFLAG_2 = 2, DISPFLAG_4 = 4, DISPFLAG_8 = 8, + DISPFLAG_10 = 0x10, DISPFLAG_20 = 0x20, DISPFLAG_40 = 0x40, DISPFLAG_80 = 0x80, + DISPFLAG_100 = 0x100, DISPFLAG_200 = 0x200, DISPFLAG_400 = 0x400, + DISPFLAG_800 = 0x800, DISPFLAG_1000 = 0x1000, DISPFLAG_2000 = 0x2000, + DISPFLAG_4000 = 0x4000, DISPFLAG_VIEWPORT = 0x8000, DISPFLAG_CURSOR = 0x10000 }; + +class DisplayResource { +public: + uint32 _flags; +}; + +class PictureResource: public DisplayResource { +public: + byte _select; + byte _pick; + byte _onOff; + byte _depth; + Common::Rect _bounds; + uint32 _maskData; + uint _planeSize; + + byte *_imgData; +public: + PictureResource(BoltFilesState &state, const byte *src); + PictureResource(int flags, int select, int pick, int onOff, int depth, + const Common::Rect &bounds, int maskData, byte *imgData, int planeSize); + PictureResource(); + virtual ~PictureResource(); +}; + +typedef void (ViewPortResource::*ViewPortMethodPtr)(); + +class ViewPortResource: public DisplayResource { +private: + BoltFilesState &_state; +private: + void setupViewPort(PictureResource *page, Common::Rect *clipRect, ViewPortSetupPtr setupFn, + ViewPortAddPtr addFn, ViewPortRestorePtr restoreFn); +public: + ViewPortResource *_parent; + int _pageCount; + int _pageIndex; + int _lastPage; + Common::Rect _bounds; + int _field18; + PictureResource *_currentPic; + PictureResource *_activePage; + PictureResource *_pages[2]; + byte *_field30; + + // Rect lists and counts. Note that _rectListCount values of '-1' seem to have + // special significance, which is why I'm not making them redundant in favour + // of the arrays' .size() method + Common::Array<Common::Rect> *_rectListPtr[3]; + int _rectListCount[3]; + + Common::Rect _clipRect; + byte *_field7A; + GraphicMethodPtr _fn1; + ViewPortSetupPtr _setupFn; + ViewPortAddPtr _addFn; + ViewPortRestorePtr _restoreFn; + PictureResource _fontChar; + Common::Rect _fontRect; +public: + ViewPortResource(BoltFilesState &state, const byte *src); + virtual ~ViewPortResource(); + + void setupViewPort(); + int drawText(const Common::String &msg); + int textWidth(const Common::String &msg); + void addSaveRect(int pageIndex, const Common::Rect &r); + void sFillBox(int width); + void fillPic(byte onOff = 0); +}; + +class ViewPortPalEntry { +public: + uint16 _rEntry, _gEntry, _bEntry; + uint16 _rChange, _gChange, _bChange; + uint16 _palIndex; +public: + ViewPortPalEntry(const byte *src); +}; + +class ViewPortListResource { +public: + Common::Array<ViewPortPalEntry> _palette; + Common::Array<ViewPortResource *> _entries; + int _palIndex; + + ViewPortListResource(BoltFilesState &state, const byte *src); + virtual ~ViewPortListResource() {} +}; + +class FontResource { +public: + int _minChar, _maxChar; + int field2; + int _padding; + int _fontHeight; + int _topPadding; + int *_charWidth; + byte *_data1; + byte *_data2; + + FontResource(BoltFilesState &state, byte *src); + virtual ~FontResource(); +}; + +enum FontJustify { ALIGN_LEFT = 0, ALIGN_CENTRE = 1, ALIGN_RIGHT = 2 }; + +class FontInfoResource { +public: + FontResource *_curFont; + byte _picFlags; + byte _picSelect; + byte _picPick; + byte _picOnOff; + byte _fontFlags; + FontJustify _justify; + int _fontSaveBack; + Common::Point _pos; + int _justifyWidth; + int _justifyHeight; + Common::Point _shadow; + int _foreColor; + int _backColor; + int _shadowColor; +public: + FontInfoResource(BoltFilesState &state, const byte *src); + FontInfoResource(); + FontInfoResource(byte picFlags, byte picSelect, byte picPick, byte picOnOff, byte fontFlags, + FontJustify justify, int fontSaveBack, const Common::Point &pos, int justifyWidth, + int justifyHeight, const Common::Point &shadow, int foreColor, int backColor, + int shadowColor); +}; + +class CMapResource { +private: + VoyeurEngine *_vm; +public: + int _steps; + int _fadeStatus; + int _start; + int _end; + byte *_entries; +public: + CMapResource(BoltFilesState &state, const byte *src); + virtual ~CMapResource(); + + void startFade(); +}; + +class VInitCyclResource { +public: + byte *_ptr[4]; +public: + VInitCyclResource(BoltFilesState &state, const byte *src); + virtual ~VInitCyclResource() {} +}; + +} // End of namespace Voyeur + +#endif /* VOYEUR_FILES_H */ diff --git a/engines/voyeur/game.cpp b/engines/voyeur/game.cpp new file mode 100644 index 0000000000..a653a842ae --- /dev/null +++ b/engines/voyeur/game.cpp @@ -0,0 +1,101 @@ +/* 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 "voyeur/game.h" +#include "voyeur/voyeur.h" + +namespace Voyeur { + +IntData::IntData() { + _field9 = false; + _flipWait = false; + _hasPalette = false; + field16 = 0; + field1A = 0; + field1E = 0; + field22 = 0; + field24 = 0; + field26 = 0; + field2A = 0; + field38 = 0; + field3B = 0; + field3D = 0; + _palStartIndex = 0; + _palEndIndex = 0; + _palette = NULL; +} + +void IntData::audioInit() { + +} + +/*------------------------------------------------------------------------*/ + +Game::Game() { +} + +void Game::doTransitionCard(const Common::String &time, const Common::String &location) { + _vm->_graphicsManager.setColor(128, 16, 16, 16); + _vm->_graphicsManager.setColor(224, 220, 220, 220); + _vm->_eventsManager._intPtr.field38 = true; + _vm->_eventsManager._intPtr._hasPalette = true; + + (*_vm->_graphicsManager._vPort)->setupViewPort(); + (*_vm->_graphicsManager._vPort)->fillPic(128); + _vm->_graphicsManager.flipPage(); + _vm->_eventsManager.sWaitFlip(); + + (*_vm->_graphicsManager._vPort)->_parent->_flags |= DISPFLAG_8; + _vm->_graphicsManager.flipPage(); + _vm->_eventsManager.sWaitFlip(); + (*_vm->_graphicsManager._vPort)->fillPic(128); + + FontInfoResource &fi = *_vm->_graphicsManager._fontPtr; + fi._curFont = _vm->_bVoy->boltEntry(257)._fontResource; + fi._foreColor = 224; + fi._fontSaveBack = 0; + fi._pos = Common::Point(0, 116); + fi._justify = ALIGN_CENTRE; + fi._justifyWidth = 384; + fi._justifyHeight = 120; + + (*_vm->_graphicsManager._vPort)->drawText(time); + + if (!location.empty()) { + fi._pos = Common::Point(0, 138); + fi._justify = ALIGN_CENTRE; + fi._justifyWidth = 384; + fi._justifyHeight = 140; + + (*_vm->_graphicsManager._vPort)->drawText(location); + } + + (*_vm->_graphicsManager._vPort)->_parent->_flags |= DISPFLAG_8; + _vm->_graphicsManager.flipPage(); + _vm->_eventsManager.sWaitFlip(); +} + +void Game::addVideoEventStart() { + +} + +} // End of namespace Voyeur diff --git a/engines/voyeur/game.h b/engines/voyeur/game.h new file mode 100644 index 0000000000..eb7d5f5e59 --- /dev/null +++ b/engines/voyeur/game.h @@ -0,0 +1,142 @@ +/* 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. + * + */ + +#ifndef VOYEUR_GAME_H +#define VOYEUR_GAME_H + +#include "common/scummsys.h" +#include "common/events.h" +#include "common/str.h" + +namespace Voyeur { + +class VoyeurEngine; + +class Event { +public: + int _hours; + int _minutes; + int _seconds; + int _type; + int _data1; + int _data2; + byte *_data; +}; + +class SVoy { +public: + int _delaySecs; + int _RTANum; + int _RTVNum; + int _switchBGNum; + int _group; + int _resolvePtr; + int _seconds; + int _minutes; + int _hours; + int _morning; + int _timeChangeFlag; + int _totalSeconds; + int _gameSeconds; + int _vCursorOn[160]; + int _vCursorOff[160]; + int _aCursorOn[60]; + int _aCursorOff[60]; + int _eCursorOn[60]; + int _eCursorOff[60]; + int _timeStart; + int _duration; + int _vidStart; + int _doApt; + int _function; + int _anim; + int _level; + int _levelDone; + int _flags; + int _evGroup; + byte *_evPicPtrs[6]; + byte *_evCmPtrs[6]; + int _audioTime; + int _phones[5]; + int _numPhonesUsed; + int _evidence[20]; + int _computerNum; + int _computerBut; + int _computerOn; + int _computerOff; + int _dead; + int _deadTime; + int _eventCnt; + Event _eventTable[1000]; + int _curICF0; + int _curICF1; + int _fadeICF0; + int _fadeICF1; + int _fadeFunc; + int _lastInplay; + int _incriminate; + int _policeEvent; +}; + +class IntData { +public: + bool _field9; + bool _flipWait; + int field16; + int field1A; + int field1E; + int field22; + int field24; + int field26; + int field2A; + bool _hasPalette; + int field38; + int field3B; + int field3D; + int _palStartIndex; + int _palEndIndex; + byte *_palette; +public: + IntData(); + + void audioInit(); +}; + +class Game { +private: + VoyeurEngine *_vm; +public: + int _v2A098; + int _v2A0A6; + int _v2A0A4; + int _v2A09A; +public: + Game(); + void setVm(VoyeurEngine *vm) { _vm = vm; } + + void doTransitionCard(const Common::String &time, const Common::String &location); + void addVideoEventStart(); +}; + +} // End of namespace Voyeur + +#endif /* VOYEUR_GAME_H */ diff --git a/engines/voyeur/graphics.cpp b/engines/voyeur/graphics.cpp new file mode 100644 index 0000000000..3a37eb9fb0 --- /dev/null +++ b/engines/voyeur/graphics.cpp @@ -0,0 +1,648 @@ +/* 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 "voyeur/graphics.h" +#include "voyeur/game.h" +#include "voyeur/voyeur.h" +#include "engines/util.h" +#include "graphics/palette.h" +#include "graphics/surface.h" + +namespace Voyeur { + +/*------------------------------------------------------------------------*/ + +DrawInfo::DrawInfo(int penColor, const Common::Point &pos, int flags) { + _penColor = penColor; + _pos = pos; + _flags = flags; +} + +/*------------------------------------------------------------------------*/ + +GraphicsManager::GraphicsManager(): + _defaultDrawInfo(1, Common::Point(), 0), + _drawPtr(&_defaultDrawInfo) { + _SVGAPage = 0; + _SVGAMode = 0; + _SVGAReset = 0; + _screenOffset = 0; + _planeSelect = 0; + _sImageShift = 3; + _palFlag = false; + _MCGAMode = false; + _saveBack = true; + _drawTextPermFlag = false; + _clipPtr = NULL; + _viewPortListPtr = NULL; + _backgroundPage = NULL; + _vPort = NULL; + _fontPtr = NULL; +} + +void GraphicsManager::sInitGraphics() { + initGraphics(SCREEN_WIDTH, SCREEN_HEIGHT, false); + _screenSurface.create(SCREEN_WIDTH, SCREEN_HEIGHT, + Graphics::PixelFormat::createFormatCLUT8()); + + clearPalette(); +} + +GraphicsManager::~GraphicsManager() { + _screenSurface.free(); +} + +void GraphicsManager::setupMCGASaveRect(ViewPortResource *viewPort) { + _MCGAMode = true; + + if (viewPort->_activePage) { + viewPort->_activePage->_flags |= 1; + Common::Rect *clipRect = _clipPtr; + _clipPtr = &viewPort->_clipRect; + + sDrawPic(viewPort->_activePage, viewPort->_currentPic, Common::Point()); + + _clipPtr = clipRect; + } + + viewPort->_rectListCount[1] = -1; +} + +void GraphicsManager::addRectOptSaveRect(ViewPortResource *viewPort, int idx, const Common::Rect &bounds) { + int count1, count2; + int idx1, varE, var24; + + if (viewPort->_rectListCount[idx] == -1) + return; + + // TODO: Lots of code in original, which I suspect may be overlapping rect merging + viewPort->_rectListPtr[idx]->push_back(bounds); + ++viewPort->_rectListCount[idx]; +} + +void GraphicsManager::restoreMCGASaveRect(ViewPortResource *viewPort) { + if (viewPort->_rectListCount[0] != -1) { + for (int i = 0; i < viewPort->_rectListCount[0]; ++i) { + addRectOptSaveRect(viewPort, 1, (*viewPort->_rectListPtr[0])[i]); + } + } else { + viewPort->_rectListCount[1] = -1; + } + + restoreBack(*viewPort->_rectListPtr[1], viewPort->_rectListCount[1], viewPort->_pages[0], + viewPort->_pages[1]); + + int count = viewPort->_rectListCount[0]; + restoreBack(*viewPort->_rectListPtr[0], viewPort->_rectListCount[0], + viewPort->_activePage, viewPort->_currentPic); + + SWAP(viewPort->_rectListPtr[0], viewPort->_rectListPtr[1]); + viewPort->_rectListCount[1] = count; +} + +void GraphicsManager::addRectNoSaveBack(ViewPortResource *viewPort, int idx, const Common::Rect &bounds) { + // TODO: more +} + +void GraphicsManager::sDrawPic(DisplayResource *srcDisplay, DisplayResource *destDisplay, + const Common::Point &initialOffset) { + int var4C = 0; + int width1, width2; + int widthDiff, widthDiff2; + int height1; + int srcOffset; + int screenOffset; + int srcFlags, destFlags; + ViewPortResource *destViewPort = NULL; + Common::Rect newBounds; + Common::Rect backBounds; + int var24; + bool isClipped = false; + int var52; + int var20, var22; + int var26, var2C; + byte pixel; + + byte *srcImgData, *destImgData; + byte *srcP, *destP; + byte byteVal, byteVal2; + + // Get the picture parameters, or deference viewport pointers to get their pictures + PictureResource *srcPic = (PictureResource *)srcDisplay; + PictureResource *destPic = (PictureResource *)destDisplay; + + if (srcDisplay->_flags & DISPFLAG_VIEWPORT) { + // A viewport was passed, not a picture + srcPic = ((ViewPortResource *)srcDisplay)->_currentPic; + } + if (destDisplay->_flags & DISPFLAG_VIEWPORT) { + destViewPort = (ViewPortResource *)destDisplay; + destPic = destViewPort->_currentPic; + } + + Common::Point offset = Common::Point(initialOffset.x + srcPic->_bounds.left - destPic->_bounds.left, + initialOffset.y + srcPic->_bounds.top - destPic->_bounds.top); + width1 = width2 = srcPic->_bounds.width(); + height1 = srcPic->_bounds.height(); + srcOffset = 0; + srcFlags = srcPic->_flags; + destFlags = destPic->_flags; + byte *cursorData = NULL; + + if (srcFlags & 1) { + if (_clipPtr) { + int xs = _clipPtr->left - destPic->_bounds.left; + int ys = _clipPtr->top - destPic->_bounds.top; + newBounds = Common::Rect(xs, ys, xs + _clipPtr->width(), ys + _clipPtr->height()); + } else if (destViewPort) { + int xs = destViewPort->_clipRect.left - destPic->_bounds.left; + int ys = destViewPort->_clipRect.top - destPic->_bounds.top; + newBounds = Common::Rect(xs, ys, xs + destViewPort->_clipRect.width(), + ys + destViewPort->_clipRect.height()); + } else { + newBounds = Common::Rect(0, 0, destPic->_bounds.width(), destPic->_bounds.height()); + } + + var24 = offset.y - newBounds.top; + if (var24 < 0) { + var52 = width2; + srcOffset -= var24 * var52; + height1 += var24; + offset.y = newBounds.top; + + if (height1 <= 0) + return; + + isClipped = true; + } + + var20 = newBounds.bottom - (offset.y + height1); + if (var20 < 0) { + height1 += var20; + if (height1 <= 0) + return; + } + + var22 = offset.x - newBounds.left; + if (var22 < 0) { + srcOffset -= var22; + width2 += var22; + offset.x = newBounds.left; + + if (width2 <= 0) + return; + + isClipped = true; + } + + var26 = newBounds.right - (offset.x + width2); + if (var26 < 0) { + width2 += var26; + if (width2 <= 0) + return; + + isClipped = true; + } + } + + screenOffset = offset.y * destPic->_bounds.width() + offset.x; + widthDiff = width1 - width2; + widthDiff2 = destPic->_bounds.width() - width2; + + if (destViewPort) { + if (!_saveBack || ((srcPic->_flags & DISPFLAG_800) != 0)) { + backBounds.left = destPic->_bounds.left + offset.x; + backBounds.top = destPic->_bounds.top + offset.y; + backBounds.setWidth(width2); + backBounds.setHeight(height1); + addRectOptSaveRect(destViewPort, 1, backBounds); + + } else if (!destViewPort->_addFn) { + if (destViewPort->_rectListCount[destViewPort->_pageIndex] < -1) { + Common::Rect r; + r.left = destPic->_bounds.left + offset.x; + r.top = destPic->_bounds.top + offset.y; + r.setWidth(width2); + r.setHeight(height1); + + (*destViewPort->_rectListPtr[destViewPort->_pageIndex]).push_back(r); + ++destViewPort->_rectListCount[destViewPort->_pageIndex]; + } + } else { + int xs = offset.x + destPic->_bounds.left; + int ys = offset.y + destPic->_bounds.top; + backBounds = Common::Rect(xs, ys, xs + width2, ys + height1); + + (this->*destViewPort->_addFn)(destViewPort, destViewPort->_bounds.top, backBounds); + } + } + + if (srcFlags & DISPFLAG_1000) { + srcImgData = srcPic->_imgData + (var4C << 14) + _screenOffset; + for (uint idx = 0; idx < srcPic->_maskData; ++idx) { + if (var4C < 4) { + EMSMapPageHandle(srcPic->_planeSize, srcPic->_imgData[idx], var4C); + ++var4C; + } + } + } else { + srcImgData = srcPic->_imgData; + } + if (destFlags & DISPFLAG_1000) { + destImgData = destPic->_imgData + (var4C << 14) + _screenOffset; + for (uint idx = 0; idx < srcPic->_maskData; ++idx) { + if (var4C < 4) { + EMSMapPageHandle(destPic->_planeSize, destPic->_imgData[idx], var4C); + ++var4C; + } + } + } else { + destImgData = destPic->_imgData; + } + + _SVGAPage = _SVGAReset; + if (srcPic->_select != 0xff) + return; + + if (destFlags & DISPFLAG_CURSOR) { + cursorData = new byte[width2 * height1]; + Common::fill(cursorData, cursorData + width2 * height1, 0); + destImgData = cursorData; + } + + if (srcPic->_pick == 0xff) { + if (srcFlags & DISPFLAG_8) { + error("TODO: sDrawPic"); + } else { + // loc_258B8 + srcP = srcImgData + srcOffset; + + if (destFlags & DISPFLAG_8) { + // loc_258D8 + destP = destImgData + screenOffset; + + if (srcFlags & DISPFLAG_2) { + // loc_25652 + srcP = srcImgData + srcOffset; + + if (destFlags & DISPFLAG_8) { + // loc_2566F + if (srcFlags & DISPFLAG_2) { + // loc_256FA + srcP = (byte *)_screenSurface.getPixels() + srcOffset; + + for (int yp = 0; yp < height1; ++yp) { + for (int xp = 0; xp < width2; ++width2, ++srcP, ++destP) { + pixel = *srcP; + if (pixel) + *destP = pixel; + } + + srcP += widthDiff; + destP += widthDiff2; + } + } else { + // loc_25706 + for (int yp = 0; yp < height1; ++yp) { + Common::copy(srcP, srcP + width2, destP); + srcP += width2 + widthDiff; + destP += width2 + widthDiff2; + } + } + } else { + // loc_25773 + destP = destImgData + screenOffset; + + if (srcFlags & DISPFLAG_2) { + // loc_25793 + for (int yp = 0; yp < height1; ++yp) { + Common::copy(srcP, srcP + width2, destP); + srcP += width2 + widthDiff; + destP += width2 + widthDiff2; + } + } else { + // loc_25829 + destP = (byte *)_screenSurface.getPixels() + screenOffset; + + for (int yp = 0; yp < height1; ++yp) { + Common::copy(srcP, srcP + width2, destP); + srcP += width2 + widthDiff; + destP += width2 + widthDiff2; + } + } + } + } else { + // loc_25D40 + if (srcFlags & DISPFLAG_100) { + // loc_25D4A + } else { + // loc_2606D + destP = (byte *)_screenSurface.getPixels() + screenOffset; + + for (int yp = 0; yp < height1; ++yp) { + Common::copy(srcP, srcP + width2, destP); + destP += width2 + widthDiff2; + srcP += width2 + widthDiff; + } + } + } + } else { + // loc_2615E + destP = destImgData + screenOffset; + + if (srcFlags & DISPFLAG_2) { + // loc_2617e + if (srcFlags & DISPFLAG_100) { + // loc_26188 + srcP = srcImgData; + if (isClipped) { + // loc_26199 +error("TODO: var22/var24/var2C not initialised before use?"); + if (var22 < 0) { + var22 = -var22; + } else { + var22 = 0; + } + var26 = var22 + width2; + if (var24 < 0) { + var24 = -var24; + } else { + var24 = 0; + } + + width2 = srcPic->_bounds.width(); + height1 = var24 + height1; + byteVal = 0; + + for (int yp = 0; yp < height1; ++yp) { + for (int xp = 0; xp < width2; ++xp) { + if (byteVal2 <= 0) { + byteVal = *srcP++; + if (byteVal & 0x80) { + byteVal &= 0x7f; + byteVal2 = *srcP++; + if (!byteVal2) + byteVal2 = width2; + } + } + + if (yp >= var24 && xp >= var22 && xp < var26) { + if (byteVal > 0) + *destP = byteVal; + ++destP; + } + } + + if (yp >= var24) + destP += widthDiff2; + } + } else { + // loc_262BE + byteVal = 0; + for (int yp = 0; yp < height1; ++yp) { + for (int xp = 0; xp < width2; ++xp) { + byteVal2 = 0; + if (!byteVal2) { + byteVal = *++srcP; + if (byteVal & 0x80) { + byteVal &= 0x7f; + byteVal2 = *srcP++; + + if (!byteVal2) + byteVal2 = width2; + } + } + + if (byteVal > 0) + *destP = byteVal; + + ++destP; + --byteVal2; + } + + destP += widthDiff2; + } + } + } else { + // loc_2637F + // Copy with transparency + for (int yp = 0; yp < height1; ++yp) { + for (int xp = 0; xp < width2; ++xp, ++srcP, ++destP) { + if (*srcP != 0) + *destP = *srcP; + } + + destP += widthDiff2; + srcP += widthDiff; + } + } + } else { + if (srcFlags & 0x100) { + srcP = srcImgData; + + if (isClipped) { + // loc_26424 + + } else { + // loc_26543 + } + } else { + for (int yp = 0; yp < height1; ++yp) { + Common::copy(srcP, srcP + width2, destP); + destP += width2 + widthDiff2; + srcP += width2 + widthDiff; + } + } + } + } + } + } else { + // loc_26666 + if (srcPic->_pick == 0) { + // loc_2727A + byte onOff = srcPic->_onOff; + + if (srcFlags & DISPFLAG_2) { + if (srcFlags & DISPFLAG_8) { + error("sDrawPic: TODO"); + } else { + error("sDrawPic: TODO"); + } + } else { + // loc_27477 + if (destFlags & DISPFLAG_8) { + // loc_27481 + destP = (byte *)_screenSurface.getPixels() + screenOffset; + for (int yp = 0; yp < height1; ++yp) { + Common::fill(srcP, srcP + width2, onOff); + destP += width2 + widthDiff2; + } + } else { + // loc_2753C + destP = destImgData + screenOffset; + + for (int yp = 0; yp < height1; ++yp) { + Common::fill(destP, destP + width2, onOff); + destP += width2 + widthDiff2; + } + } + } + + } else { + // loc_26673 + // TODO + } + } + + if (cursorData) { + _vm->_eventsManager.setCursor(cursorData, width2, height1); + delete[] cursorData; + } +} + +void GraphicsManager::fillPic(DisplayResource *display, byte onOff) { + PictureResource *pic; + if (display->_flags & DISPFLAG_VIEWPORT) { + pic = ((ViewPortResource *)display)->_currentPic; + } else { + pic = (PictureResource *)display; + } + + PictureResource picResource; + picResource._flags = 0; + picResource._select = 0xff; + picResource._pick = 0; + picResource._onOff = onOff; + picResource._bounds = pic->_bounds; + + sDrawPic(&picResource, display, Common::Point()); +} + +/** + * Queues the given picture for display + */ +void GraphicsManager::sDisplayPic(PictureResource *pic) { + if (pic->_flags & DISPFLAG_8) { + _vm->_eventsManager._intPtr.field2A = READ_LE_UINT32(pic->_imgData) >> _sImageShift; + } + + _vm->_eventsManager._intPtr._flipWait = true; +} + +void GraphicsManager::EMSMapPageHandle(int v1, int v2, int v3) { + // TODO +} + +void GraphicsManager::flipPage() { + Common::Array<ViewPortResource *> &viewPorts = _viewPortListPtr->_entries; + bool flipFlag = false; + + for (uint idx = 0; idx < viewPorts.size(); ++idx) { + if (viewPorts[idx]->_flags & DISPFLAG_20) { + if ((viewPorts[idx]->_flags & (DISPFLAG_8 || DISPFLAG_1)) + == (DISPFLAG_8 || DISPFLAG_1)) { + if (_planeSelect == idx) + sDisplayPic(viewPorts[idx]->_currentPic); + flipFlag = true; + } + } + + if (flipFlag) { + ViewPortResource &viewPort = *viewPorts[idx]; + + viewPort._lastPage = viewPort._pageIndex; + ++viewPort._pageIndex; + + if (viewPort._pageIndex >= viewPort._pageCount) + viewPort._pageIndex = 0; + + assert(viewPort._pageIndex < 2); + viewPort._currentPic = viewPort._pages[viewPort._pageIndex]; + viewPort._flags = (viewPort._flags & ~DISPFLAG_8) | DISPFLAG_40; + } + } +} + +void GraphicsManager::restoreBack(Common::Array<Common::Rect> &rectList, int rectListCount, + PictureResource *srcPic, PictureResource *destPic) { + bool saveBack = _saveBack; + _saveBack = false; + + // WORKAROUND: Since _backgroundPage can point to a resource freed at the end of display methods, + // I'm now explicitly resetting it to null in screenReset(), so at this point it can be null + if (!srcPic) + return; + + if (rectListCount == -1) { + sDrawPic(srcPic, destPic, Common::Point()); + } else { + for (int i = rectListCount - 1; i >= 0; --i) { + _clipPtr = &rectList[i]; + sDrawPic(srcPic, destPic, Common::Point()); + } + } + + _saveBack = saveBack; +} + +void GraphicsManager::clearPalette() { + byte palette[768]; + Common::fill(&palette[0], &palette[768], 0); + g_system->getPaletteManager()->setPalette(&palette[0], 0, 256); +} + +void GraphicsManager::setPalette(const byte *palette, int start, int count) { + g_system->getPaletteManager()->setPalette(palette, start, count); +} + +void GraphicsManager::resetPalette() { + for (int i = 0; i < 256; ++i) + setColor(i, 0, 0, 0); + + _vm->_eventsManager._intPtr.field38 = 1; + _vm->_eventsManager._intPtr._hasPalette = true; +} + +void GraphicsManager::setColor(int idx, byte r, byte g, byte b) { + byte *vgaP = &_VGAColors[idx * 3]; + vgaP[0] = r; + vgaP[1] = g; + vgaP[2] = b; + + _vm->_eventsManager._intPtr._palStartIndex = MIN(_vm->_eventsManager._intPtr._palStartIndex, idx); + _vm->_eventsManager._intPtr._palEndIndex = MAX(_vm->_eventsManager._intPtr._palEndIndex, idx); +} + +void GraphicsManager::screenReset() { + resetPalette(); + + _backgroundPage = NULL; + (*_vPort)->setupViewPort(); + fillPic(*_vPort, 0); + (*_vPort)->_parent->_flags |= DISPFLAG_8; + + // Flip + flipPage(); + _vm->_eventsManager.sWaitFlip(); +} + +} // End of namespace Voyeur diff --git a/engines/voyeur/graphics.h b/engines/voyeur/graphics.h new file mode 100644 index 0000000000..23a29657f1 --- /dev/null +++ b/engines/voyeur/graphics.h @@ -0,0 +1,118 @@ +/* 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. + * + */ + +#ifndef VOYEUR_GRAPHICS_H +#define VOYEUR_GRAPHICS_H + +//#include "voyeur/files.h" +#include "voyeur/game.h" +#include "common/scummsys.h" +#include "common/array.h" +#include "graphics/surface.h" + +namespace Voyeur { + +#define SCREEN_WIDTH 320 +#define SCREEN_HEIGHT 200 +#define PALETTE_COUNT 256 +#define PALETTE_SIZE (256 * 3) + +class VoyeurEngine; +class GraphicsManager; +class DisplayResource; +class PictureResource; +class ViewPortResource; +class ViewPortListResource; +class FontResource; +class FontInfoResource; +class CMapResource; + +class DrawInfo { +public: + int _penColor; + Common::Point _pos; + int _flags; +public: + DrawInfo(int penColor, const Common::Point &pos, int flags); +}; + +typedef void (GraphicsManager::*GraphicMethodPtr)(); +typedef void (GraphicsManager::*ViewPortSetupPtr)(ViewPortResource *); +typedef void (GraphicsManager::*ViewPortAddPtr)(ViewPortResource *, int idx, const Common::Rect &bounds); +typedef void (GraphicsManager::*ViewPortRestorePtr)(ViewPortResource *); + +class GraphicsManager { +public: + VoyeurEngine *_vm; + bool _palFlag; + byte _VGAColors[PALETTE_SIZE]; + Common::Array<byte *> _colorChain; + PictureResource *_backgroundPage; + int _SVGAPage; + int _SVGAMode; + int _SVGAReset; + ViewPortListResource *_viewPortListPtr; + ViewPortResource **_vPort; + bool _MCGAMode; + bool _saveBack; + Common::Rect *_clipPtr; + int _screenOffset; + uint _planeSelect; + int _sImageShift; + Graphics::Surface _screenSurface; + CMapResource *_backColors; + FontInfoResource *_fontPtr; + DrawInfo *_drawPtr; + DrawInfo _defaultDrawInfo; + bool _drawTextPermFlag; +private: + static void fadeIntFunc(); + static void vDoCycleInt(); + + void restoreBack(Common::Array<Common::Rect> &rectList, int rectListCount, + PictureResource *srcPic, PictureResource *destPic); +public: + GraphicsManager(); + ~GraphicsManager(); + void setVm(VoyeurEngine *vm) { _vm = vm; } + void sInitGraphics(); + + void setupMCGASaveRect(ViewPortResource *viewPort); + void addRectOptSaveRect(ViewPortResource *viewPort, int idx, const Common::Rect &bounds); + void restoreMCGASaveRect(ViewPortResource *viewPort); + void addRectNoSaveBack(ViewPortResource *viewPort, int idx, const Common::Rect &bounds); + + void EMSMapPageHandle(int v1, int v2, int v3); + void sDrawPic(DisplayResource *srcDisplay, DisplayResource *destDisplay, const Common::Point &initialOffset); + void fillPic(DisplayResource *display, byte onOff = 0); + void sDisplayPic(PictureResource *pic); + void flipPage(); + void clearPalette(); + void setPalette(const byte *palette, int start, int count); + void resetPalette(); + void setColor(int idx, byte r, byte g, byte b); + void screenReset(); +}; + +} // End of namespace Voyeur + +#endif /* VOYEUR_GRAPHICS_H */ diff --git a/engines/voyeur/module.mk b/engines/voyeur/module.mk new file mode 100644 index 0000000000..645b62ff49 --- /dev/null +++ b/engines/voyeur/module.mk @@ -0,0 +1,21 @@ +MODULE := engines/voyeur + +MODULE_OBJS := \ + animation.o \ + debugger.o \ + detection.o \ + events.o \ + game.o \ + files.o \ + graphics.o \ + sound.o \ + utils.o \ + voyeur.o + +# This module can be built as a plugin +ifeq ($(ENABLE_VOYEUR), DYNAMIC_PLUGIN) +PLUGIN := 1 +endif + +# Include common rules +include $(srcdir)/rules.mk diff --git a/engines/voyeur/sound.cpp b/engines/voyeur/sound.cpp new file mode 100644 index 0000000000..628e6e27a9 --- /dev/null +++ b/engines/voyeur/sound.cpp @@ -0,0 +1,47 @@ +/* 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 "voyeur/sound.h" + +namespace Voyeur { + +SoundManager::SoundManager() { +} + +void SoundManager::playVOCMap(byte *voc, int vocSize) { + // TODO +} + +bool SoundManager::vocMapStatus() { + // TODO + return false; +} + +void SoundManager::continueVocMap() { + // TODO +} + +void SoundManager::abortVOCMap() { + // TODO +} + +} // End of namespace Voyeur diff --git a/engines/voyeur/sound.h b/engines/voyeur/sound.h new file mode 100644 index 0000000000..01d5dc20b9 --- /dev/null +++ b/engines/voyeur/sound.h @@ -0,0 +1,47 @@ +/* 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. + * + */ + +#ifndef VOYEUR_SOUND_H +#define VOYEUR_SOUND_H + +#include "common/scummsys.h" +#include "common/str.h" +#include "voyeur/files.h" + +namespace Voyeur { + +class SoundManager { +private: + VoyeurEngine *_vm; +public: + SoundManager(); + void setVm(VoyeurEngine *vm) { _vm = vm; } + + void playVOCMap(byte *voc, int vocSize); + bool vocMapStatus(); + void continueVocMap(); + void abortVOCMap(); +}; + +} // End of namespace Voyeur + +#endif /* VOYEUR_SOUND_H */ diff --git a/engines/voyeur/utils.cpp b/engines/voyeur/utils.cpp new file mode 100644 index 0000000000..5c861389d9 --- /dev/null +++ b/engines/voyeur/utils.cpp @@ -0,0 +1,55 @@ +/* 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 "voyeur/utils.h" +#include "common/savefile.h" + +namespace Voyeur { + +LockTime::LockTime() { + field0 = field1 = field2 = field3 = 0; +} + +void LockClass::getSysDate() { + +} + +void LockClass::getThePassword() { + field0 = 26; + _password = "3333"; + fieldE = field16; + field12 = field1A; + fieldC = -1; + + // TODO: Original loaded 'VOYEUR.DAT' here to get most recent game's password. + // We'll want to transform this to proper savegames in ScummVM +} + +void LockClass::saveThePassword() { + //TODO +} + +Common::String LockClass::getDateString() { + return Common::String("ScummVM"); +} + +} // End of namespace Voyeur diff --git a/engines/voyeur/utils.h b/engines/voyeur/utils.h new file mode 100644 index 0000000000..b9266781dc --- /dev/null +++ b/engines/voyeur/utils.h @@ -0,0 +1,59 @@ +/* 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. + * + */ + +#ifndef VOYEUR_UTILS_H +#define VOYEUR_UTILS_H + +#include "common/scummsys.h" +#include "common/str.h" + +namespace Voyeur { + +class LockTime { +public: + int field0; + int field1; + int field2; + int field3; + + LockTime(); +}; + +class LockClass { +public: + int field0; + Common::String _password; + int fieldC; + LockTime fieldE; + int field12; + LockTime field16; + int field1A; +public: + void getSysDate(); + void getThePassword(); + void saveThePassword(); + Common::String getDateString(); +}; + +} // End of namespace Voyeur + +#endif /* VOYEUR_UTILS_H */ diff --git a/engines/voyeur/voyeur.cpp b/engines/voyeur/voyeur.cpp new file mode 100644 index 0000000000..871fc41d25 --- /dev/null +++ b/engines/voyeur/voyeur.cpp @@ -0,0 +1,538 @@ +/* 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 "voyeur/voyeur.h" +#include "voyeur/animation.h" +#include "voyeur/graphics.h" +#include "voyeur/utils.h" +#include "common/scummsys.h" +#include "common/config-manager.h" +#include "common/debug-channels.h" + +namespace Voyeur { + +VoyeurEngine *g_vm; + +VoyeurEngine::VoyeurEngine(OSystem *syst, const VoyeurGameDescription *gameDesc) : Engine(syst), + _gameDescription(gameDesc), _randomSource("Voyeur"), + _defaultFontInfo(3, 0xff, 0xff, 0, 0, ALIGN_LEFT, 0, Common::Point(), 1, 1, + Common::Point(1, 1), 1, 0, 0) { + DebugMan.addDebugChannel(kDebugPath, "Path", "Pathfinding debug level"); + _bVoy = NULL; + + initialiseManagers(); +} + +VoyeurEngine::~VoyeurEngine() { + delete _bVoy; +} + +Common::String VoyeurEngine::generateSaveName(int slot) { + return Common::String::format("%s.%03d", _targetName.c_str(), slot); +} + +/** + * Returns true if it is currently okay to restore a game + */ +bool VoyeurEngine::canLoadGameStateCurrently() { + return true; +} + +/** + * Returns true if it is currently okay to save the game + */ +bool VoyeurEngine::canSaveGameStateCurrently() { + return true; +} + +/** + * Load the savegame at the specified slot index + */ +Common::Error VoyeurEngine::loadGameState(int slot) { + return Common::kNoError; +} + +/** + * Save the game to the given slot index, and with the given name + */ +Common::Error VoyeurEngine::saveGameState(int slot, const Common::String &desc) { + //TODO + return Common::kNoError; +} + +Common::Error VoyeurEngine::run() { + ESP_Init(); + globalInitBolt(); + + _eventsManager.resetMouse(); + doHeadTitle(); + + //doHeadTitle(); + + return Common::kNoError; +} + + +int VoyeurEngine::getRandomNumber(int maxNumber) { + return _randomSource.getRandomNumber(maxNumber); +} + +void VoyeurEngine::initialiseManagers() { + _debugger.setVm(this); + _eventsManager.setVm(this); + _filesManager.setVm(this); + _game.setVm(this); + _graphicsManager.setVm(this); + _soundManager.setVm(this); + +} + +void VoyeurEngine::ESP_Init() { +} + +void VoyeurEngine::globalInitBolt() { + initBolt(); + + _filesManager.openBoltLib("bvoy.blt", _bVoy); + _bVoy->getBoltGroup(0x10000); + _bVoy->getBoltGroup(0x10100); + + _graphicsManager._fontPtr = &_defaultFontInfo; + _graphicsManager._fontPtr->_curFont = _bVoy->boltEntry(0x101)._fontResource; + assert(_graphicsManager._fontPtr->_curFont); + + // Setup default flags + Common::fill((byte *)&_voy, (byte *)&_voy + sizeof(SVoy), 0); + _voy._eCursorOff[0x74 / 2] = 1; + _voy._eCursorOff[0x68 / 2] = 0; + _voy._eventTable[998]._data = NULL; // Original set 63h:63h + _voy._evidence[19] = 0; + _voy._evidence[17] = 0; + _voy._evidence[18] = 9999; + + _voy._curICF0 = _graphicsManager._palFlag ? 0xFFFFA5E0 : 0x5F90; + _eventsManager.addFadeInt(); +} + +void VoyeurEngine::initBolt() { + vInitInterrupts(); + _graphicsManager.sInitGraphics(); + _eventsManager.vInitColor(); + initInput(); +} + +void VoyeurEngine::vInitInterrupts() { + _eventsManager._intPtr._palette = &_graphicsManager._VGAColors[0]; +} + +void VoyeurEngine::initInput() { +} + +bool VoyeurEngine::doHeadTitle() { +// char dest[144]; + + _eventsManager.startMainClockInt(); + + // Show starting screen + if (_bVoy->getBoltGroup(0x10500)) + showConversionScreen(); + if (shouldQuit()) + return false; + + if (ConfMan.getBool("copy_protection")) { + bool result = doLock(); + if (!result || shouldQuit()) + return false; + } + + showTitleScreen(); + + // Opening + if (!_voy._incriminate) { + doOpening(); + _game.doTransitionCard("Saturday Afternoon", "Player's Apartment"); + _eventsManager.delay(90); + } else { + _voy._incriminate = false; + } + + if (_voy._eCursorOff[58] & 0x80) { + if (_voy._evidence[19] == 0) { + // TODO + } else { + // TODO + } + } + + _voy._eCursorOff[55] = 140; + return true; +} + +void VoyeurEngine::showConversionScreen() { + _graphicsManager._backgroundPage = _bVoy->boltEntry(0x502)._picResource; + (*_graphicsManager._vPort)->setupViewPort(); + (*_graphicsManager._vPort)->_flags |= DISPFLAG_8; + + _graphicsManager.flipPage(); + _eventsManager.sWaitFlip(); + + // Immediate palette load to show the initial screen + CMapResource *cMap = _bVoy->getCMapResource(0x503); + assert(cMap); + cMap->_steps = 0; + cMap->startFade(); + + // Wait briefly + _eventsManager.delay(150); + if (shouldQuit()) + return; + + // Fade out the screen + cMap = _bVoy->getCMapResource(0x5040000); + cMap->_steps = 30; + cMap->startFade(); + if (shouldQuit()) + return; + + (*_graphicsManager._vPort)->_flags |= DISPFLAG_8; + _graphicsManager.flipPage(); + _eventsManager.sWaitFlip(); + + while (!shouldQuit() && (_eventsManager._fadeStatus & 1)) + _eventsManager.delay(1); + + _graphicsManager.screenReset(); + _bVoy->freeBoltGroup(0x10500); + + +} + +bool VoyeurEngine::doLock() { + bool result = true; + bool flag = false; + int buttonVocSize, wrongVocSize; + byte *buttonVoc = _filesManager.fload("button.voc", &buttonVocSize); + byte *wrongVoc = _filesManager.fload("wrong.voc", &wrongVocSize); + LockClass lock; + PictureResource *cursorPic; + byte *keyData; + int keyCount; + int key; + + if (_bVoy->getBoltGroup(0x10700)) { + lock.getSysDate(); + lock.getThePassword(); + + _voy._eventTable[999]._type = lock.fieldC; + _voy._eventTable[999]._data = _bVoy->memberAddr(0x704); + + Common::String password = lock._password; + cursorPic = _bVoy->getPictureResource(0x702); + assert(cursorPic); + + // Get the mappings of keys on the keypad + keyData = _bVoy->memberAddr(0x705); + keyCount = READ_LE_UINT16(keyData); + + _graphicsManager._backColors = _bVoy->getCMapResource(0x7010000); + _graphicsManager._backgroundPage = _bVoy->getPictureResource(0x700); + (*_graphicsManager._vPort)->setupViewPort(); + + _graphicsManager._backColors->startFade(); + (*_graphicsManager._vPort)->_parent->_flags |= DISPFLAG_8; + _graphicsManager.flipPage(); + _eventsManager.sWaitFlip(); + + while (!shouldQuit() && (_eventsManager._fadeStatus & 1)) + _eventsManager.delay(1); + + _eventsManager.setCursorColor(127, 0); + _graphicsManager.setColor(1, 64, 64, 64); + _graphicsManager.setColor(2, 96, 96, 96); + _graphicsManager.setColor(3, 160, 160, 160); + _graphicsManager.setColor(4, 224, 224, 224); + + // Set up the cursor + _eventsManager.setCursor(cursorPic); + _eventsManager.mouseOn(); + + _eventsManager._intPtr. field38 = 1; + _eventsManager._intPtr._hasPalette = true; + + _graphicsManager._fontPtr->_curFont = _bVoy->boltEntry(0x708)._fontResource; + _graphicsManager._fontPtr->_fontSaveBack = 0; + _graphicsManager._fontPtr->_fontFlags = 0; + + Common::String dateString = lock.getDateString(); + Common::String displayString = Common::String::format("Last Play %s", dateString.c_str()); + + bool firstLoop = true; + bool breakFlag = false; + while (!breakFlag && !shouldQuit()) { + (*_graphicsManager._vPort)->setupViewPort(); + (*_graphicsManager._vPort)->_parent->_flags |= DISPFLAG_8; + _graphicsManager.flipPage(); + _eventsManager.sWaitFlip(); + + // Display the last play time + _graphicsManager._fontPtr->_pos = Common::Point(0, 97); + _graphicsManager._fontPtr->_justify = ALIGN_CENTRE; + _graphicsManager._fontPtr->_justifyWidth = 384; + _graphicsManager._fontPtr->_justifyHeight = 97; + + (*_graphicsManager._vPort)->drawText(displayString); + (*_graphicsManager._vPort)->_parent->_flags |= DISPFLAG_8; + _graphicsManager.flipPage(); + _eventsManager.sWaitFlip(); + + if (firstLoop) { + firstLoop = false; + displayString = ""; + } + + // Loop for getting key presses + do { + do { + // Scan through the list of key rects to check if a keypad key is highlighted + key = -1; + Common::Point mousePos = _eventsManager.getMousePos() + + Common::Point(30, 20); + + for (int keyIndex = 0; keyIndex < keyCount; ++keyIndex) { + int x1 = READ_LE_UINT16(keyData + (((keyIndex << 2) + 1) << 1)); + int x2 = READ_LE_UINT16(keyData + (((keyIndex << 2) + 3) << 1)); + int y1 = READ_LE_UINT16(keyData + (((keyIndex << 2) + 2) << 1)); + int y2 = READ_LE_UINT16(keyData + (((keyIndex << 2) + 4) << 1)); + + if (mousePos.x >= x1 && mousePos.x <= x2 && mousePos.y >= y1 && mousePos.y <= y2) { + key = keyIndex; + } + } + + _eventsManager.setCursorColor(127, (key == -1) ? 0 : 1); + _eventsManager._intPtr.field38 = 1; + _eventsManager._intPtr._hasPalette = true; + + _eventsManager.delay(1); + } while (!shouldQuit() && !_voy._incriminate); + _voy._incriminate = false; + } while (!shouldQuit() && key == -1); + + _soundManager.abortVOCMap(); + _soundManager.playVOCMap(buttonVoc, buttonVocSize); + + while (_soundManager.vocMapStatus()) { + if (shouldQuit()) + break; + + _soundManager.continueVocMap(); + _eventsManager.delay(1); + } + + // Process the key + if (key < 10) { + // Numeric key + if (displayString.size() < 10) { + displayString += '0' + key; + continue; + } + } else if (key == 10) { + // Accept key + if (!flag) { + if ((password.empty() && displayString.empty()) || (password == displayString)) { + breakFlag = true; + result = true; + break; + } + } else { + if (displayString.size() > 0) { + result = true; + breakFlag = true; + break; + } + } + } else if (key == 11) { + // New code + if ((password.empty() && displayString.empty()) || (password != displayString)) { + (*_graphicsManager._vPort)->setupViewPort(); + flag = true; + displayString = ""; + continue; + } + } else if (key == 12) { + // Exit keyword + breakFlag = true; + result = false; + break; + } else { + continue; + } + + _soundManager.playVOCMap(wrongVoc, wrongVocSize); + } + + _graphicsManager.fillPic(*_graphicsManager._vPort); + (*_graphicsManager._vPort)->_parent->_flags |= DISPFLAG_8; + _graphicsManager.flipPage(); + _eventsManager.sWaitFlip(); + _graphicsManager.resetPalette(); + + if (flag && result) + lock._password = displayString; + lock.saveThePassword(); + + _voy._eventTable[999]._data = NULL; + _bVoy->freeBoltGroup(0x10700); + } + + _eventsManager.mouseOff(); + + delete[] buttonVoc; + delete[] wrongVoc; + + return result; +} + +void VoyeurEngine::showTitleScreen() { + if (_bVoy->getBoltGroup(0x10500)) { + _graphicsManager._backgroundPage = _bVoy->getPictureResource(0x500); + + (*_graphicsManager._vPort)->setupViewPort(); + (*_graphicsManager._vPort)->_flags |= DISPFLAG_8; + _graphicsManager.flipPage(); + _eventsManager.sWaitFlip(); + + // Immediate palette load to show the initial screen + CMapResource *cMap = _bVoy->getCMapResource(0x501); + assert(cMap); + cMap->_steps = 60; + cMap->startFade(); + + // Wait briefly + _eventsManager.delay(200); + if (shouldQuit()) + return; + + // Fade out the screen + cMap = _bVoy->getCMapResource(0x504); + cMap->_steps = 30; + cMap->startFade(); + + (*_graphicsManager._vPort)->_flags |= DISPFLAG_8; + _graphicsManager.flipPage(); + _eventsManager.sWaitFlip(); + + while (!shouldQuit() && (_eventsManager._fadeStatus & 1)) + _eventsManager.delay(1); + if (shouldQuit()) + return; + + _graphicsManager.screenReset(); + _eventsManager.delay(200); + + // Voyeur title + playRL2Video("a1100100.rl2"); + _graphicsManager.screenReset(); + + _bVoy->freeBoltGroup(0x10500); + } +} + +void VoyeurEngine::doOpening() { + _graphicsManager.screenReset(); + + if (!_bVoy->getBoltGroup(0x10200)) + return; + + byte *frameTable = _bVoy->memberAddr(0x215); + byte *xyTable = _bVoy->memberAddr(0x216); + byte *whTable = _bVoy->memberAddr(0x217); + int frmaeIndex = 0; + int creditShow = 1; + _game._v2A098 = 1; + _voy._eCursorOff[52] = 0; + _voy._RTVNum = 0; + _voy._eCursorOff[50] = _voy._RTVNum; + _game._v2A0A6 = 4; + _game._v2A0A4 = 0; + _voy._eCursorOff[58] = 16; + _game._v2A09A = -1; + _game.addVideoEventStart(); + _voy._eCursorOff[58] &= ~1; + + for (int i = 0; i < 256; ++i) + _graphicsManager.setColor(i, 8, 8, 8); + + _eventsManager._intPtr.field38 = 1; + _eventsManager._intPtr._hasPalette = true; + (*_graphicsManager._vPort)->setupViewPort(); + (*_graphicsManager._vPort)->_parent->_flags |= DISPFLAG_8; + _graphicsManager.flipPage(); + _eventsManager.sWaitFlip(); + + ::Video::RL2Decoder decoder; + decoder.loadFile("a2300100.rl2"); + decoder.start(); + + while (!shouldQuit() && !decoder.endOfVideo() && !_voy._incriminate) { + if (decoder.hasDirtyPalette()) { + const byte *palette = decoder.getPalette(); + _graphicsManager.setPalette(palette, 0, 256); + } + + if (decoder.needsUpdate()) { + const Graphics::Surface *frame = decoder.decodeNextFrame(); + + Common::copy((byte *)frame->getPixels(), (byte *)frame->getPixels() + 320 * 200, + (byte *)_graphicsManager._screenSurface.getPixels()); + } + + _eventsManager.pollEvents(); + g_system->delayMillis(10); + } + +} + +void VoyeurEngine::playRL2Video(const Common::String &filename) { + ::Video::RL2Decoder decoder; + decoder.loadFile(filename); + decoder.start(); + + while (!shouldQuit() && !decoder.endOfVideo() && !_voy._incriminate) { + if (decoder.hasDirtyPalette()) { + const byte *palette = decoder.getPalette(); + _graphicsManager.setPalette(palette, 0, 256); + } + + if (decoder.needsUpdate()) { + const Graphics::Surface *frame = decoder.decodeNextFrame(); + + Common::copy((byte *)frame->getPixels(), (byte *)frame->getPixels() + 320 * 200, + (byte *)_graphicsManager._screenSurface.getPixels()); + } + + _eventsManager.pollEvents(); + g_system->delayMillis(10); + } +} + +} // End of namespace Voyeur diff --git a/engines/voyeur/voyeur.h b/engines/voyeur/voyeur.h new file mode 100644 index 0000000000..f698aae702 --- /dev/null +++ b/engines/voyeur/voyeur.h @@ -0,0 +1,119 @@ +/* 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. + * + */ + +#ifndef VOYEUR_VOYEUR_H +#define VOYEUR_VOYEUR_H + +#include "voyeur/debugger.h" +#include "voyeur/events.h" +#include "voyeur/files.h" +#include "voyeur/game.h" +#include "voyeur/graphics.h" +#include "voyeur/sound.h" +#include "common/scummsys.h" +#include "common/system.h" +#include "common/error.h" +#include "common/random.h" +#include "common/util.h" +#include "engines/engine.h" +#include "graphics/surface.h" + +/** + * This is the namespace of the Voyeur engine. + * + * Status of this engine: In Development + * + * Games using this engine: + * - Voyeur + */ +namespace Voyeur { + +#define DEBUG_BASIC 1 +#define DEBUG_INTERMEDIATE 2 +#define DEBUG_DETAILED 3 + +#define MAX_RESOLVE 1000 + +enum VoyeurDebugChannels { + kDebugPath = 1 << 0 +}; + +struct VoyeurGameDescription; + + +class VoyeurEngine : public Engine { +private: + const VoyeurGameDescription *_gameDescription; + Common::RandomSource _randomSource; + + Common::Array<int> _resolves; + FontInfoResource _defaultFontInfo; + + void ESP_Init(); + void initialiseManagers(); + void globalInitBolt(); + void initBolt(); + void vInitInterrupts(); + void initInput(); + + bool doHeadTitle(); + void showConversionScreen(); + bool doLock(); + void showTitleScreen(); + void doOpening(); +protected: + // Engine APIs + virtual Common::Error run(); + virtual bool hasFeature(EngineFeature f) const; +public: + BoltFile *_bVoy; + Debugger _debugger; + EventsManager _eventsManager; + FilesManager _filesManager; + Game _game; + GraphicsManager _graphicsManager; + SoundManager _soundManager; + SVoy _voy; +public: + VoyeurEngine(OSystem *syst, const VoyeurGameDescription *gameDesc); + virtual ~VoyeurEngine(); + void GUIError(const Common::String &msg); + + uint32 getFeatures() const; + Common::Language getLanguage() const; + Common::Platform getPlatform() const; + uint16 getVersion() const; + bool getIsDemo() const; + + int getRandomNumber(int maxNumber); + Common::String generateSaveName(int slotNumber); + virtual bool canLoadGameStateCurrently(); + virtual bool canSaveGameStateCurrently(); + virtual Common::Error loadGameState(int slot); + virtual Common::Error saveGameState(int slot, const Common::String &desc); + + void playRL2Video(const Common::String &filename); +}; + +} // End of namespace Voyeur + +#endif /* VOYEUR_VOYEUR_H */ |