Initial commit

This commit is contained in:
2026-02-02 04:50:13 +01:00
commit 5b11698731
22592 changed files with 7677434 additions and 0 deletions

1
engines/voyeur/POTFILES Normal file
View File

@@ -0,0 +1 @@
engines/voyeur/metaengine.cpp

View File

@@ -0,0 +1,510 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "voyeur/animation.h"
#include "voyeur/staticres.h"
#include "voyeur/voyeur.h"
#include "common/endian.h"
#include "common/memstream.h"
#include "common/system.h"
#include "audio/decoders/raw.h"
#include "graphics/surface.h"
#include "backends/keymapper/keymapper.h"
namespace Voyeur {
// Number of audio frames to keep audio track topped up when playing back video
#define SOUND_FRAMES_READAHEAD 3
RL2Decoder::RL2Decoder() {
_paletteStart = 0;
_fileStream = nullptr;
_soundFrameNumber = -1;
_audioTrack = nullptr;
_videoTrack = nullptr;
}
RL2Decoder::~RL2Decoder() {
close();
}
bool RL2Decoder::loadVideo(int videoId) {
Common::Path filename(Common::String::format("%s.rl2",
::Voyeur::SZ_FILENAMES[videoId * 2]));
return loadRL2File(filename, false);
}
bool RL2Decoder::loadRL2File(const Common::Path &file, bool palFlag) {
bool result = VideoDecoder::loadFile(file);
_paletteStart = palFlag ? 0 : 128;
return result;
}
bool RL2Decoder::loadStream(Common::SeekableReadStream *stream) {
close();
// Load basic file information
_fileStream = stream;
_header.load(stream);
_paletteStart = 0;
// 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
_audioTrack = nullptr;
if (_header._soundRate) {
_audioTrack = new RL2AudioTrack(_header, stream, getSoundType());
addTrack(_audioTrack);
}
// Create a video track
_videoTrack = new RL2VideoTrack(_header, _audioTrack, stream);
addTrack(_videoTrack);
// Load the offset/sizes of the video's audio data
_soundFrames.reserve(_header._numFrames);
for (int frameNumber = 0; frameNumber < _header._numFrames; ++frameNumber) {
int offset = _header._frameOffsets[frameNumber];
int size = _header._frameSoundSizes[frameNumber];
_soundFrames.push_back(SoundFrame(offset, size));
}
return true;
}
const Common::List<Common::Rect> *RL2Decoder::getDirtyRects() const {
if (_videoTrack)
return _videoTrack->getDirtyRects();
return nullptr;
}
void RL2Decoder::clearDirtyRects() {
if (_videoTrack)
_videoTrack->clearDirtyRects();
}
void RL2Decoder::copyDirtyRectsToBuffer(uint8 *dst, uint pitch) {
if (_videoTrack)
_videoTrack->copyDirtyRectsToBuffer(dst, pitch);
}
void RL2Decoder::readNextPacket() {
int frameNumber = getCurFrame();
RL2AudioTrack *audioTrack = getRL2AudioTrack();
// Handle queueing sound data
if (_soundFrameNumber == -1)
_soundFrameNumber = (frameNumber == -1) ? 0 : frameNumber;
while (audioTrack->numQueuedStreams() < SOUND_FRAMES_READAHEAD &&
(_soundFrameNumber < (int)_soundFrames.size())) {
_fileStream->seek(_soundFrames[_soundFrameNumber]._offset);
audioTrack->queueSound(_fileStream, _soundFrames[_soundFrameNumber]._size);
++_soundFrameNumber;
}
}
bool RL2Decoder::seekIntern(const Audio::Timestamp &where) {
_soundFrameNumber = -1;
return VideoDecoder::seekIntern(where);
}
void RL2Decoder::close() {
VideoDecoder::close();
delete _fileStream;
_fileStream = nullptr;
_soundFrameNumber = -1;
}
/*------------------------------------------------------------------------*/
RL2Decoder::SoundFrame::SoundFrame(int offset, int size) {
_offset = offset;
_size = size;
}
/*------------------------------------------------------------------------*/
RL2Decoder::RL2FileHeader::RL2FileHeader() {
_frameOffsets = nullptr;
_frameSoundSizes = nullptr;
_channels = 0;
_colorCount = 0;
_numFrames = 0;
_rate = 0;
_soundRate = 0;
_videoBase = 0;
_backSize = 0;
_signature = MKTAG('N', 'O', 'N', 'E');
_form = 0;
_dataSize = 0;
_method = 0;
_defSoundSize = 0;
}
RL2Decoder::RL2FileHeader::~RL2FileHeader() {
delete[] _frameOffsets;
delete[] _frameSoundSizes;
}
void RL2Decoder::RL2FileHeader::load(Common::SeekableReadStream *stream) {
stream->seek(0);
_form = stream->readUint32LE();
_backSize = stream->readUint32LE();
_signature = stream->readUint32BE();
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
delete[] _frameOffsets;
_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
delete[] _frameSoundSizes;
_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');
}
Common::Rational RL2Decoder::RL2FileHeader::getFrameRate() const {
return (_soundRate > 0) ? Common::Rational(_rate, _defSoundSize) :
Common::Rational(11025, 1103);
}
/*------------------------------------------------------------------------*/
RL2Decoder::RL2VideoTrack::RL2VideoTrack(const RL2FileHeader &header, RL2AudioTrack *audioTrack,
Common::SeekableReadStream *stream): _header(header), _fileStream(stream) {
_frameOffsets = nullptr;
// Set up surfaces
_surface = new Graphics::Surface();
_surface->create(320, 200, Graphics::PixelFormat::createFormatCLUT8());
_backSurface = nullptr;
_hasBackFrame = header._backSize != 0;
if (_hasBackFrame)
initBackSurface();
_videoBase = header._videoBase;
_dirtyPalette = header._colorCount > 0;
_curFrame = -1;
_initialFrame = true;
}
RL2Decoder::RL2VideoTrack::~RL2VideoTrack() {
// Free surfaces
_surface->free();
delete _surface;
if (_backSurface) {
_backSurface->free();
delete _backSurface;
}
}
void RL2Decoder::RL2VideoTrack::initBackSurface() {
_backSurface = new Graphics::Surface();
_backSurface->create(320, 200, Graphics::PixelFormat::createFormatCLUT8());
}
bool RL2Decoder::RL2VideoTrack::seek(const Audio::Timestamp &time) {
int frame = getFrameAtTime(time);
if (frame < 0 || frame >= _header._numFrames)
return false;
_curFrame = frame;
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 (_initialFrame && _hasBackFrame) {
// Read in the initial background frame
_fileStream->seek(0x324);
rl2DecodeFrameWithoutTransparency(0);
Common::copy((byte *)_surface->getPixels(), (byte *)_surface->getPixels() + (320 * 200),
(byte *)_backSurface->getPixels());
_dirtyRects.push_back(Common::Rect(0, 0, _surface->w, _surface->h));
_initialFrame = false;
}
// Move to the next frame data
_fileStream->seek(_header._frameOffsets[++_curFrame]);
// If there's any sound data, pass it to the audio track
_fileStream->seek(_header._frameSoundSizes[_curFrame], SEEK_CUR);
// Decode the graphic data using the appropriate method depending on whether the animation
// has a background or just raw frames without any background transparency
if (_backSurface) {
rl2DecodeFrameWithTransparency(_videoBase);
} else {
rl2DecodeFrameWithoutTransparency(_videoBase);
}
return _surface;
}
void RL2Decoder::RL2VideoTrack::copyDirtyRectsToBuffer(uint8 *dst, uint pitch) {
for (const auto &r : _dirtyRects) {
for (int y = r.top; y < r.bottom; ++y) {
const int x = r.left;
memcpy(dst + y * pitch + x, (byte *)_surface->getPixels() + y * getWidth() + x, r.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::rl2DecodeFrameWithoutTransparency(int screenOffset) {
if (screenOffset == -1)
screenOffset = _videoBase;
int frameSize = _surface->w * _surface->h - screenOffset;
byte *destP = (byte *)_surface->getPixels();
// Main frame decode loop
byte nextByte;
for (;;) {
nextByte = _fileStream->readByte();
if (nextByte < 0x80) {
// Simple byte to copy to output
assert(frameSize > 0);
*destP++ = nextByte;
--frameSize;
} else if (nextByte > 0x80) {
// Lower 7 bits a run length for the following byte
int runLength = _fileStream->readByte();
runLength = MIN(runLength, frameSize);
Common::fill(destP, destP + runLength, nextByte & 0x7f);
destP += runLength;
frameSize -= runLength;
} else {
// Follow byte run length for zeroes. If zero, indicates end of image
int runLength = _fileStream->readByte();
if (runLength == 0)
break;
runLength = MIN(runLength, frameSize);
Common::fill(destP, destP + runLength, 0);
destP += runLength;
frameSize -= runLength;
}
}
// If there's any remaining screen area, zero it out
byte *endP = (byte *)_surface->getPixels() + _surface->w * _surface->h;
if (destP != endP)
Common::fill(destP, endP, 0);
}
void RL2Decoder::RL2VideoTrack::rl2DecodeFrameWithTransparency(int screenOffset) {
int frameSize = _surface->w * _surface->h - screenOffset;
byte *refP = (byte *)_backSurface->getPixels();
byte *destP = (byte *)_surface->getPixels();
// If there's a screen offset, copy unchanged initial pixels from reference surface
if (screenOffset > 0)
Common::copy(refP, refP + screenOffset, destP);
// Main decode loop
while (frameSize > 0) {
byte nextByte = _fileStream->readByte();
if (nextByte == 0) {
// Move one single byte from reference surface
assert(frameSize > 0);
destP[screenOffset] = refP[screenOffset];
++screenOffset;
--frameSize;
} else if (nextByte < 0x80) {
// Single 7-bit pixel to output (128-255)
assert(frameSize > 0);
destP[screenOffset] = nextByte | 0x80;
++screenOffset;
--frameSize;
} else if (nextByte == 0x80) {
int runLength = _fileStream->readByte();
if (runLength == 0)
return;
// Run length of transparency (i.e. pixels to copy from reference frame)
runLength = MIN(runLength, frameSize);
Common::copy(refP + screenOffset, refP + screenOffset + runLength, destP + screenOffset);
screenOffset += runLength;
frameSize -= runLength;
} else {
// Run length of a single pixel value
int runLength = _fileStream->readByte();
runLength = MIN(runLength, frameSize);
Common::fill(destP + screenOffset, destP + screenOffset + runLength, nextByte);
screenOffset += runLength;
frameSize -= runLength;
}
}
// If there's a remaining section of the screen not covered, copy it from reference surface
if (screenOffset < (_surface->w * _surface->h))
Common::copy(refP + screenOffset, refP + (_surface->w * _surface->h), destP + screenOffset);
}
Graphics::Surface *RL2Decoder::RL2VideoTrack::getBackSurface() {
if (!_backSurface)
initBackSurface();
return _backSurface;
}
/*------------------------------------------------------------------------*/
RL2Decoder::RL2AudioTrack::RL2AudioTrack(const RL2FileHeader &header, Common::SeekableReadStream *stream, Audio::Mixer::SoundType soundType) :
AudioTrack(soundType),
_header(header) {
// Create audio straem for the audio track
_audStream = Audio::makeQueuingAudioStream(_header._rate, _header._channels == 2);
}
RL2Decoder::RL2AudioTrack::~RL2AudioTrack() {
delete _audStream;
}
void RL2Decoder::RL2AudioTrack::queueSound(Common::SeekableReadStream *stream, int size) {
// 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);
}
Audio::AudioStream *RL2Decoder::RL2AudioTrack::getAudioStream() const {
return _audStream;
}
void RL2Decoder::play(VoyeurEngine *vm, int resourceOffset,
byte *frames, byte *imgPos) {
vm->flipPageAndWait();
int paletteStart = getPaletteStart();
int paletteCount = getPaletteCount();
PictureResource videoFrame(getRL2VideoTrack()->getBackSurface());
int picCtr = 0;
Common::Keymapper *keymapper = g_system->getEventManager()->getKeymapper();
keymapper->getKeymap("voyeur-default")->setEnabled(false);
keymapper->getKeymap("cutscene")->setEnabled(true);
while (!vm->shouldQuit() && !endOfVideo() && !vm->_eventsManager->_mouseClicked) {
if (hasDirtyPalette()) {
const byte *palette = getPalette();
vm->_screen->setPalette128(palette, paletteStart, paletteCount);
}
if (needsUpdate()) {
if (frames) {
// If reached a point where a new background is needed, load it
// and copy over to the video decoder
if (getCurFrame() >= READ_LE_UINT16(frames + picCtr * 4)) {
PictureResource *newPic = vm->_bVoy->boltEntry(0x302 + picCtr)._picResource;
Common::Point pt(READ_LE_UINT16(imgPos + 4 * picCtr) - 32,
READ_LE_UINT16(imgPos + 4 * picCtr + 2) - 20);
vm->_screen->sDrawPic(newPic, &videoFrame, pt);
++picCtr;
}
}
// Decode the next frame and display
const Graphics::Surface *frame = decodeNextFrame();
vm->_screen->blitFrom(*frame);
}
vm->_eventsManager->getMouseInfo();
g_system->delayMillis(10);
}
keymapper->getKeymap("cutscene")->setEnabled(false);
keymapper->getKeymap("voyeur-default")->setEnabled(true);
}
} // End of namespace Voyeur

194
engines/voyeur/animation.h Normal file
View File

@@ -0,0 +1,194 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef VOYEUR_ANIMATION_H
#define VOYEUR_ANIMATION_H
#include "video/video_decoder.h"
#include "audio/audiostream.h"
#include "audio/mixer.h"
#include "common/array.h"
#include "common/list.h"
#include "common/rect.h"
#include "common/stream.h"
#include "voyeur/files.h"
namespace Audio {
class Timestamp;
}
namespace Voyeur {
class VoyeurEngine;
/**
* Decoder for RL2 videos.
*
* Video decoder used in engines:
* - voyeur
*/
class RL2Decoder : public Video::VideoDecoder {
private:
class RL2FileHeader {
public:
RL2FileHeader();
~RL2FileHeader();
int _channels;
int _colorCount;
int _numFrames;
int _rate;
int _soundRate;
int _videoBase;
int *_frameSoundSizes;
uint32 _backSize;
uint32 _signature;
uint32 *_frameOffsets;
byte _palette[768];
void load(Common::SeekableReadStream *stream);
Common::Rational getFrameRate() const;
bool isValid() const;
private:
uint32 _form; // Unused variable
uint32 _dataSize; // Unused variable
int _method; // Unused variable
int _defSoundSize;
};
class SoundFrame {
public:
int _offset;
int _size;
SoundFrame(int offset, int size);
};
class RL2AudioTrack : public AudioTrack {
private:
const RL2FileHeader &_header;
Audio::QueuingAudioStream *_audStream;
protected:
Audio::AudioStream *getAudioStream() const override;
public:
RL2AudioTrack(const RL2FileHeader &header, Common::SeekableReadStream *stream,
Audio::Mixer::SoundType soundType);
~RL2AudioTrack() override;
int numQueuedStreams() const { return _audStream->numQueuedStreams(); }
bool isSeekable() const override { return true; }
bool seek(const Audio::Timestamp &time) override { return true; }
void queueSound(Common::SeekableReadStream *stream, int size);
};
class RL2VideoTrack : public FixedRateVideoTrack {
public:
RL2VideoTrack(const RL2FileHeader &header, RL2AudioTrack *audioTrack,
Common::SeekableReadStream *stream);
~RL2VideoTrack() override;
uint16 getWidth() const override;
uint16 getHeight() const override;
Graphics::Surface *getSurface() { return _surface; }
Graphics::Surface *getBackSurface();
Graphics::PixelFormat getPixelFormat() const override;
int getCurFrame() const override { return _curFrame; }
int getFrameCount() const override { return _header._numFrames; }
const Graphics::Surface *decodeNextFrame() override;
const byte *getPalette() const override { _dirtyPalette = false; return _header._palette; }
int getPaletteCount() const { return _header._colorCount; }
bool hasDirtyPalette() const override { return _dirtyPalette; }
const Common::List<Common::Rect> *getDirtyRects() const { return &_dirtyRects; }
void clearDirtyRects() { _dirtyRects.clear(); }
void copyDirtyRectsToBuffer(uint8 *dst, uint pitch);
Common::Rational getFrameRate() const override { return _header.getFrameRate(); }
bool isSeekable() const override { return true; }
bool seek(const Audio::Timestamp &time) override;
private:
Common::SeekableReadStream *_fileStream;
const RL2FileHeader &_header;
Graphics::Surface *_surface;
Graphics::Surface *_backSurface;
bool _hasBackFrame;
mutable bool _dirtyPalette;
bool _initialFrame;
int _curFrame;
uint32 _videoBase;
uint32 *_frameOffsets;
Common::List<Common::Rect> _dirtyRects;
void copyFrame(uint8 *data);
void rl2DecodeFrameWithTransparency(int screenOffset);
void rl2DecodeFrameWithoutTransparency(int screenOffset = -1);
void initBackSurface();
};
private:
RL2AudioTrack *_audioTrack;
RL2VideoTrack *_videoTrack;
Common::SeekableReadStream *_fileStream;
RL2FileHeader _header;
int _paletteStart;
Common::Array<SoundFrame> _soundFrames;
int _soundFrameNumber;
const Common::List<Common::Rect> *getDirtyRects() const;
void clearDirtyRects();
void copyDirtyRectsToBuffer(uint8 *dst, uint pitch);
int getPaletteStart() const { return _paletteStart; }
const RL2FileHeader &getHeader() { return _header; }
void readNextPacket() override;
bool seekIntern(const Audio::Timestamp &time) override;
public:
RL2Decoder();
~RL2Decoder() override;
void close() override;
bool loadStream(Common::SeekableReadStream *stream) override;
bool loadRL2File(const Common::Path &file, bool palFlag);
bool loadVideo(int videoId);
int getPaletteCount() const { return _header._colorCount; }
/**
* Play back a given Voyeur RL2 video
* @param vm Engine reference
* @param resourceOffset Starting resource to use for frame pictures
* @param frames Optional frame numbers resource for when to apply image data
* @param imgPos Position to draw image data
*/
void play(VoyeurEngine *vm, int resourceOffset = 0, byte *frames = nullptr, byte *imgPos = nullptr);
RL2VideoTrack *getRL2VideoTrack() { return _videoTrack; }
RL2AudioTrack *getRL2AudioTrack() { return _audioTrack; }
};
} // End of namespace Voyeur
#endif /* VOYEUR_ANIMATION_H */

View File

@@ -0,0 +1,3 @@
# This file is included from the main "configure" script
# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps] [components]
add_engine voyeur "Voyeur" yes

View File

@@ -0,0 +1,4 @@
begin_section("Voyeur");
add_person("Arnaud Boutonn&eacute;", "Strangerke", "");
add_person("Paul Gilbert", "dreammaster", "");
end_section();

370
engines/voyeur/data.cpp Normal file
View File

@@ -0,0 +1,370 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "voyeur/data.h"
#include "voyeur/voyeur.h"
namespace Voyeur {
void VoyeurEvent::synchronize(Common::Serializer &s) {
s.syncAsByte(_hour);
s.syncAsByte(_minute);
s.syncAsByte(_isAM);
s.syncAsByte(_type);
s.syncAsSint16LE(_audioVideoId);
s.syncAsSint16LE(_computerOn);
s.syncAsSint16LE(_computerOff);
s.syncAsSint16LE(_dead);
}
/*------------------------------------------------------------------------*/
SVoy::SVoy(VoyeurEngine *vm):_vm(vm) {
// Initialize all the data fields
_abortInterface = false;
_isAM = false;
Common::fill(&_phoneCallsReceived[0], &_phoneCallsReceived[5], false);
Common::fill(&_roomHotspotsEnabled[0], &_roomHotspotsEnabled[32], false);
_victimMurdered = false;
_audioVisualStartTime = 0;
_audioVisualDuration = 0;
_boltGroupId2 = 0;
_computerTextId = -1;
_computerTimeMin = _computerTimeMax = 0;
_eventCount = 0;
_fadingStep1 = 0;
_fadingStep2 = 0;
_fadingType = 0;
_incriminatedVictimNumber = 0;
_musicStartTime = 0;
_playStampMode = 0;
_switchBGNum = 0;
_transitionId = 0;
_videoEventId = 0;
_vocSecondsOffset = 0;
_RTANum = 0;
_RTVLimit = 0;
_RTVNum = 0;
_viewBounds = nullptr;
Common::fill(&_evPicPtrs[0], &_evPicPtrs[6], (PictureResource *)nullptr);
Common::fill(&_evCmPtrs[0], &_evCmPtrs[6], (CMapResource *)nullptr);
_policeEvent = 0;
_eventFlags = EVTFLAG_TIME_DISABLED;
_fadingAmount1 = _fadingAmount2 = 127;
_murderThreshold = 9999;
_aptLoadMode = -1;
_eventFlags |= EVTFLAG_100;
_totalPhoneCalls = 0;
for (int i = 0; i < 6; i++)
_evPicPtrs[i] = nullptr;
for (int i = 0; i < 1000; i++) {
_events[i]._hour = 0;
_events[i]._minute = 0;
_events[i]._isAM = true;
_events[i]._type = EVTYPE_NONE;
_events[i]._audioVideoId = -1;
_events[i]._computerOn = 0;
_events[i]._computerOff = 0;
_events[i]._dead = 0;
}
for (int i = 0; i < 6; i++)
_evCmPtrs[i] = nullptr;
}
void SVoy::addEvent(int hour, int minute, VoyeurEventType type, int audioVideoId,
int on, int off, int dead) {
VoyeurEvent &e = _events[_eventCount++];
e._type = type;
e._hour = hour;
e._minute = minute;
e._isAM = hour < 12;
e._audioVideoId = audioVideoId;
e._computerOn = on;
e._computerOff = off;
e._dead = dead;
}
void SVoy::synchronize(Common::Serializer &s) {
s.syncAsByte(_isAM);
s.syncAsSint16LE(_RTANum);
s.syncAsSint16LE(_RTVNum);
s.syncAsSint16LE(_switchBGNum);
_videoHotspotTimes.synchronize(s);
_audioHotspotTimes.synchronize(s);
_evidenceHotspotTimes.synchronize(s);
int count = s.getVersion() == 1 ? 20 : 32;
for (int idx = 0; idx < count; ++idx) {
s.syncAsByte(_roomHotspotsEnabled[idx]);
}
s.syncAsSint16LE(_audioVisualStartTime);
s.syncAsSint16LE(_audioVisualDuration);
s.syncAsSint16LE(_vocSecondsOffset);
s.syncAsSint16LE(_abortInterface);
s.syncAsSint16LE(_playStampMode);
s.syncAsSint16LE(_aptLoadMode);
s.syncAsSint16LE(_transitionId);
s.syncAsSint16LE(_RTVLimit);
s.syncAsSint16LE(_eventFlags);
s.syncAsSint16LE(_boltGroupId2);
s.syncAsSint16LE(_musicStartTime);
s.syncAsSint16LE(_totalPhoneCalls);
s.syncAsSint16LE(_computerTextId);
s.syncAsSint16LE(_computerTimeMin);
s.syncAsSint16LE(_computerTimeMax);
s.syncAsSint16LE(_victimMurdered);
s.syncAsSint16LE(_murderThreshold);
// Events
s.syncAsUint16LE(_eventCount);
for (int idx = 0; idx < _eventCount; ++idx)
_events[idx].synchronize(s);
s.syncAsSint16LE(_fadingAmount1);
s.syncAsSint16LE(_fadingAmount2);
s.syncAsSint16LE(_fadingStep1);
s.syncAsSint16LE(_fadingStep2);
s.syncAsSint16LE(_fadingType);
s.skip(sizeof(int16), 0, 2);
s.syncAsSint16LE(_incriminatedVictimNumber);
s.syncAsSint16LE(_videoEventId);
if (s.isLoading()) {
// Reset apartment loading mode to initial game value
_aptLoadMode = 140;
_viewBounds = nullptr;
}
}
void SVoy::addVideoEventStart() {
VoyeurEvent &e = _events[_eventCount];
e._hour = _vm->_gameHour;
e._minute = _vm->_gameMinute;
e._isAM = _isAM;
e._type = EVTYPE_VIDEO;
e._audioVideoId = _vm->_audioVideoId;
e._computerOn = _vocSecondsOffset;
e._dead = _vm->_eventsManager->_videoDead;
}
void SVoy::addVideoEventEnd() {
VoyeurEvent &e = _events[_eventCount];
e._computerOff = _RTVNum - _audioVisualStartTime - _vocSecondsOffset;
if (_eventCount < (TOTAL_EVENTS - 1))
++_eventCount;
}
void SVoy::addAudioEventStart() {
VoyeurEvent &e = _events[_eventCount];
e._hour = _vm->_gameHour;
e._minute = _vm->_gameMinute;
e._isAM = _isAM;
e._type = EVTYPE_AUDIO;
e._audioVideoId = _vm->_audioVideoId;
e._computerOn = _vocSecondsOffset;
e._dead = _vm->_eventsManager->_videoDead;
}
void SVoy::addAudioEventEnd() {
VoyeurEvent &e = _events[_eventCount];
e._computerOff = _RTVNum - _audioVisualStartTime - _vocSecondsOffset;
if (_eventCount < (TOTAL_EVENTS - 1))
++_eventCount;
}
void SVoy::addEvidEventStart(int v) {
VoyeurEvent &e = _events[_eventCount];
e._hour = _vm->_gameHour;
e._minute = _vm->_gameMinute;
e._isAM = _isAM;
e._type = EVTYPE_EVID;
e._audioVideoId = _vm->_playStampGroupId;
e._computerOn = _boltGroupId2;
e._computerOff = v;
}
void SVoy::addEvidEventEnd(int totalPages) {
VoyeurEvent &e = _events[_eventCount];
e._dead = totalPages;
if (_eventCount < (TOTAL_EVENTS - 1))
++_eventCount;
}
void SVoy::addComputerEventStart() {
VoyeurEvent &e = _events[_eventCount];
e._hour = _vm->_gameHour;
e._minute = _vm->_gameMinute;
e._isAM = _isAM;
e._type = EVTYPE_COMPUTER;
e._audioVideoId = _vm->_playStampGroupId;
e._computerOn = _computerTextId;
}
void SVoy::addComputerEventEnd(int v) {
VoyeurEvent &e = _events[_eventCount];
e._computerOff = v;
if (_eventCount < (TOTAL_EVENTS - 1))
++_eventCount;
}
void SVoy::reviewAnEvidEvent(int eventIndex) {
VoyeurEvent &e = _events[eventIndex];
_vm->_playStampGroupId = e._audioVideoId;
_boltGroupId2 = e._computerOn;
int frameOff = e._computerOff;
if (_vm->_bVoy->getBoltGroup(_vm->_playStampGroupId)) {
_vm->_screen->_backColors = _vm->_bVoy->boltEntry(_vm->_playStampGroupId + 1)._cMapResource;
_vm->_screen->_backgroundPage = _vm->_bVoy->boltEntry(_vm->_playStampGroupId)._picResource;
_vm->_screen->_vPort->setupViewPort(_vm->_screen->_backgroundPage);
_vm->_screen->_backColors->startFade();
_vm->doEvidDisplay(frameOff, e._dead);
_vm->_bVoy->freeBoltGroup(_vm->_playStampGroupId);
_vm->_playStampGroupId = -1;
if (_boltGroupId2 != -1) {
_vm->_bVoy->freeBoltGroup(_boltGroupId2);
_boltGroupId2 = -1;
}
}
}
void SVoy::reviewComputerEvent(int eventIndex) {
VoyeurEvent &e = _events[eventIndex];
_vm->_playStampGroupId = e._audioVideoId;
_computerTextId = e._computerOn;
if (_vm->_bVoy->getBoltGroup(_vm->_playStampGroupId)) {
_vm->_screen->_backColors = _vm->_bVoy->boltEntry(_vm->_playStampGroupId + 1)._cMapResource;
_vm->_screen->_backgroundPage = _vm->_bVoy->boltEntry(_vm->_playStampGroupId)._picResource;
_vm->_screen->_vPort->setupViewPort(_vm->_screen->_backgroundPage);
_vm->_screen->_backColors->startFade();
_vm->flipPageAndWaitForFade();
_vm->getComputerBrush();
_vm->flipPageAndWait();
_vm->doComputerText(e._computerOff);
_vm->_bVoy->freeBoltGroup(0x4900);
_vm->_bVoy->freeBoltGroup(_vm->_playStampGroupId);
_vm->_playStampGroupId = -1;
}
}
bool SVoy::checkForKey() {
StateResource *state = _vm->_controlPtr->_state;
state->_victimEvidenceIndex = 0;
if (_vm->_voy->_victimMurdered)
return false;
for (int eventIdx = 0; eventIdx < _eventCount; ++eventIdx) {
VoyeurEvent &e = _events[eventIdx];
switch (e._type) {
case EVTYPE_VIDEO:
switch (state->_victimIndex) {
case 1:
if (e._audioVideoId == 33 && e._computerOn < 2 && e._computerOff >= 38)
state->_victimEvidenceIndex = 1;
break;
case 2:
if (e._audioVideoId == 47 && e._computerOn < 2 && e._computerOff >= 9)
state->_victimEvidenceIndex = 2;
break;
case 3:
if (e._audioVideoId == 46 && e._computerOn < 2 && e._computerOff > 2)
state->_victimEvidenceIndex = 3;
break;
case 4:
if (e._audioVideoId == 40 && e._computerOn < 2 && e._computerOff > 6)
state->_victimEvidenceIndex = 4;
break;
default:
break;
}
break;
case EVTYPE_AUDIO:
switch (state->_victimIndex) {
case 1:
if (e._audioVideoId == 8 && e._computerOn < 2 && e._computerOff > 26)
state->_victimEvidenceIndex = 1;
break;
case 3:
if (e._audioVideoId == 20 && e._computerOn < 2 && e._computerOff > 28)
state->_victimEvidenceIndex = 3;
if (e._audioVideoId == 35 && e._computerOn < 2 && e._computerOff > 18)
state->_victimEvidenceIndex = 3;
break;
default:
break;
}
break;
case EVTYPE_EVID:
switch (state->_victimIndex) {
case 4:
if (e._audioVideoId == 0x2400 && e._computerOn == 0x4f00 && e._computerOff == 17)
state->_victimEvidenceIndex = 4;
default:
break;
}
break;
case EVTYPE_COMPUTER:
switch (state->_victimIndex) {
case 2:
if (e._computerOn == 13 && e._computerOff > 76)
state->_victimEvidenceIndex = 2;
break;
default:
break;
}
break;
default:
break;
}
if (state->_victimEvidenceIndex == state->_victimIndex)
return true;
}
return false;
}
} // End of namespace Voyeur

230
engines/voyeur/data.h Normal file
View File

@@ -0,0 +1,230 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef VOYEUR_DATA_H
#define VOYEUR_DATA_H
#include "common/scummsys.h"
#include "common/serializer.h"
#include "voyeur/files.h"
namespace Voyeur {
#define TOTAL_EVENTS 1000
enum VoyeurEventType {
EVTYPE_NONE = 0,
EVTYPE_VIDEO = 1,
EVTYPE_AUDIO = 2,
EVTYPE_EVID = 3,
EVTYPE_COMPUTER = 4
};
enum EventFlag { EVTFLAG_TIME_DISABLED = 1, EVTFLAG_2 = 2, EVTFLAG_8 = 8, EVTFLAG_RECORDING = 0x10,
EVTFLAG_40 = 0x40, EVTFLAG_VICTIM_PRESET = 0x80, EVTFLAG_100 = 0x100 };
struct VoyeurEvent {
int _hour;
int _minute;
bool _isAM;
VoyeurEventType _type;
int _audioVideoId;
int _computerOn;
int _computerOff;
int _dead;
void synchronize(Common::Serializer &s);
};
class VoyeurEngne;
/**
* Encapsulates a list of the time expired ranges that hotspots in the mansion
* view are enabled for in a given time period.
*/
template<int SLOTS>
class HotspotTimes {
public:
int _min[SLOTS][20]; // Min time expired
int _max[SLOTS][20]; // Max time expired
HotspotTimes() {
reset();
}
/**
* Resets the data to an initial state
*/
void reset() {
for (int hotspotIdx = 0; hotspotIdx < 20; ++hotspotIdx) {
for (int slotIdx = 0; slotIdx < SLOTS; ++slotIdx) {
_min[slotIdx][hotspotIdx] = 9999;
_max[slotIdx][hotspotIdx] = 0;
}
}
}
/**
* Synchronise the data
*/
void synchronize(Common::Serializer &s) {
for (int slotIndex = 0; slotIndex < SLOTS; ++slotIndex) {
for (int hotspotIndex = 0; hotspotIndex < 20; ++hotspotIndex) {
s.syncAsSint16LE(_min[slotIndex][hotspotIndex]);
s.syncAsSint16LE(_max[slotIndex][hotspotIndex]);
}
}
}
/**
* Returns true if the given value is in the range specified by the
* min and max at the given hotspot and slot indexes
*/
bool isInRange(int slotIndex, int hotspotIndex, int v) const {
return _min[slotIndex][hotspotIndex] <= v &&
v < _max[slotIndex][hotspotIndex];
}
};
class SVoy {
private:
VoyeurEngine *_vm;
public:
bool _abortInterface;
bool _isAM;
bool _phoneCallsReceived[5];
bool _roomHotspotsEnabled[32];
bool _victimMurdered;
int _aptLoadMode;
int _audioVisualStartTime;
int _audioVisualDuration;
int _boltGroupId2;
int _computerTextId;
int _computerTimeMin;
int _computerTimeMax;
int _eventCount;
int _eventFlags;
int _fadingAmount1;
int _fadingAmount2;
int _fadingStep1;
int _fadingStep2;
int _fadingType;
int _incriminatedVictimNumber;
int _murderThreshold;
int _musicStartTime;
int _playStampMode;
int _switchBGNum;
int _totalPhoneCalls;
int _transitionId;
int _videoEventId;
int _vocSecondsOffset;
int _RTANum;
int _RTVLimit;
int _RTVNum;
HotspotTimes<3> _audioHotspotTimes;
HotspotTimes<3> _evidenceHotspotTimes;
HotspotTimes<8> _videoHotspotTimes;
Common::Rect _computerScreenRect;
RectResource *_viewBounds;
PictureResource *_evPicPtrs[6];
CMapResource *_evCmPtrs[6];
VoyeurEvent _events[TOTAL_EVENTS];
SVoy(VoyeurEngine *vm);
/**
* Synchronize the data
*/
void synchronize(Common::Serializer &s);
/**
* Add an event to the list of game events that have occurred
*/
void addEvent(int hour, int minute, VoyeurEventType type, int audioVideoId,
int on, int off, int dead);
/**
* Adds the start of a video event happening
*/
void addVideoEventStart();
/**
* Adds the finish of a video event happening
*/
void addVideoEventEnd();
/**
* Adds the start of an audio event happening
*/
void addAudioEventStart();
/**
* Adsd the finish of an audio event happening
*/
void addAudioEventEnd();
/**
* Adds the start of an evidence event happening
*/
void addEvidEventStart(int v);
/**
* Adds the finish of an evidence event happening
*/
void addEvidEventEnd(int totalPages);
/**
* Adds the start of a computer event happening
*/
void addComputerEventStart();
/**
* Adds the finish of a computer event happening
*/
void addComputerEventEnd(int v);
/**
* Review a previously recorded evidence event
*/
void reviewAnEvidEvent(int eventIndex);
/**
* Review a previously recorded computer event
*/
void reviewComputerEvent(int eventIndex);
/**
* Checks for key information in determining what kind of murder
* should take place
*/
bool checkForKey();
private:
int _policeEvent;
};
} // End of namespace Voyeur
#endif /* VOYEUR_DATA_H */

173
engines/voyeur/debugger.cpp Normal file
View File

@@ -0,0 +1,173 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "voyeur/debugger.h"
#include "voyeur/screen.h"
#include "voyeur/voyeur.h"
#include "voyeur/staticres.h"
namespace Voyeur {
Debugger::Debugger(VoyeurEngine *vm) : GUI::Debugger(), _vm(vm) {
// Register methods
registerCmd("continue", WRAP_METHOD(Debugger, cmdExit));
registerCmd("time", WRAP_METHOD(Debugger, Cmd_Time));
registerCmd("hotspots", WRAP_METHOD(Debugger, Cmd_Hotspots));
registerCmd("mouse", WRAP_METHOD(Debugger, Cmd_Mouse));
// Set fields
_isTimeActive = true;
_showMousePosition = false;
}
static const int TIME_STATES[] = {
0, 31, 0, 43, 59, 0, 67, 75, 85, 93, 0, 0, 111, 121, 0, 0
};
bool Debugger::Cmd_Time(int argc, const char **argv) {
if (argc < 2) {
// Get the current day and time of day
Common::String dtString = _vm->getDayName();
Common::String timeString = _vm->getTimeOfDay();
if (!timeString.empty())
dtString += " " + timeString;
debugPrintf("Time period = %d, date/time is: %s, time is %s\n",
_vm->_voy->_transitionId, dtString.c_str(), _isTimeActive ? "on" : "off");
debugPrintf("Format: %s [on | off | 1..17 | val <amount>]\n\n", argv[0]);
} else {
if (!strcmp(argv[1], "on")) {
_isTimeActive = true;
debugPrintf("Time is now on\n\n");
} else if (!strcmp(argv[1], "off")) {
_isTimeActive = false;
debugPrintf("Time is now off\n\n");
} else if (!strcmp(argv[1], "val")) {
if (argc < 3) {
debugPrintf("Time expired is currently %d.\n", _vm->_voy->_RTVNum);
} else {
_vm->_voy->_RTVNum = atoi(argv[2]);
debugPrintf("Time expired is now %d.\n", _vm->_voy->_RTVNum);
}
} else {
int timeId = atoi(argv[1]);
if (timeId >= 1 && timeId < 17) {
int stateId = TIME_STATES[timeId - 1];
if (!stateId) {
debugPrintf("Given time period is not used in-game\n");
} else {
debugPrintf("Changing to time period: %d\n", timeId);
if (_vm->_mainThread->goToState(-1, stateId))
_vm->_mainThread->parsePlayCommands();
return false;
}
} else {
debugPrintf("Unknown parameter\n\n");
}
}
}
return true;
}
bool Debugger::Cmd_Hotspots(int argc, const char **argv) {
if (_vm->_voy->_computerTextId >= 0) {
debugPrintf("Hotspot Computer Screen %d - %d,%d->%d,%d\n",
_vm->_voy->_computerTextId,
_vm->_voy->_computerScreenRect.left,
_vm->_voy->_computerScreenRect.top,
_vm->_voy->_computerScreenRect.right,
_vm->_voy->_computerScreenRect.bottom);
}
#if 0
// Room hotspots
BoltEntry &boltEntry = _vm->_bVoy->boltEntry(_vm->_playStampGroupId + 4);
if (boltEntry._rectResource) {
Common::Array<RectEntry> &hotspots = boltEntry._rectResource->_entries;
for (uint hotspotIdx = 0; hotspotIdx < hotspots.size(); ++hotspotIdx) {
Common::String pos = Common::String::format("(%d,%d->%d,%d)",
hotspots[hotspotIdx].left, hotspots[hotspotIdx].top,
hotspots[hotspotIdx].right, hotspots[hotspotIdx].bottom);
int arrIndex = hotspots[hotspotIdx]._arrIndex;
if (_vm->_voy->_roomHotspotsEnabled[arrIndex - 1]) {
debugPrintf("Hotspot Room %d - %s - Enabled\n", arrIndex, pos);
} else {
debugPrintf("Hotspot Room - %s - Disabled\n", pos);
}
}
}
#endif
// Outside view hotspots
BoltEntry &boltEntry = _vm->_bVoy->boltEntry(_vm->_playStampGroupId + 1);
if (boltEntry._rectResource) {
Common::Array<RectEntry> &hotspots = boltEntry._rectResource->_entries;
for (uint hotspotIdx = 0; hotspotIdx < hotspots.size(); ++hotspotIdx) {
Common::String pos = Common::String::format("(%d,%d->%d,%d)",
hotspots[hotspotIdx].left, hotspots[hotspotIdx].top,
hotspots[hotspotIdx].right, hotspots[hotspotIdx].bottom);
for (int arrIndex = 0; arrIndex < 3; ++arrIndex) {
if (_vm->_voy->_audioHotspotTimes._min[arrIndex][hotspotIdx] != 9999) {
debugPrintf("Hotspot %d %s Audio slot %d, time: %d to %d\n",
hotspotIdx, pos.c_str(), arrIndex,
_vm->_voy->_audioHotspotTimes._min[arrIndex][hotspotIdx],
_vm->_voy->_audioHotspotTimes._max[arrIndex][hotspotIdx]);
}
if (_vm->_voy->_evidenceHotspotTimes._min[arrIndex][hotspotIdx] != 9999) {
debugPrintf("Hotspot %d %s Evidence slot %d, time: %d to %d\n",
hotspotIdx, pos.c_str(), arrIndex,
_vm->_voy->_evidenceHotspotTimes._min[arrIndex][hotspotIdx],
_vm->_voy->_evidenceHotspotTimes._max[arrIndex][hotspotIdx]);
}
}
for (int arrIndex = 0; arrIndex < 8; ++arrIndex) {
if (_vm->_voy->_videoHotspotTimes._min[arrIndex][hotspotIdx] != 9999) {
debugPrintf("Hotspot %d %s Video slot %d, time: %d to %d\n",
hotspotIdx, pos.c_str(), arrIndex,
_vm->_voy->_videoHotspotTimes._min[arrIndex][hotspotIdx],
_vm->_voy->_videoHotspotTimes._max[arrIndex][hotspotIdx]);
}
}
}
}
debugPrintf("\nEnd of list\n");
return true;
}
bool Debugger::Cmd_Mouse(int argc, const char **argv) {
if (argc < 2) {
debugPrintf("mouse [ on | off ]\n");
} else {
_showMousePosition = !strcmp(argv[1], "on");
debugPrintf("Mouse position is now %s\n", _showMousePosition ? "on" : "off");
}
return true;
}
} // End of namespace Voyeur

69
engines/voyeur/debugger.h Normal file
View File

@@ -0,0 +1,69 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#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:
/**
* Specifies whether time should pass, and the video camera's batteries go down
* @default true
*/
bool _isTimeActive;
/*
* Specifies whether to show the current mouse position on the screen
*/
bool _showMousePosition;
protected:
/**
* Turn time on or off, set the current time period, or the camera delay
* within the current time period.
*/
bool Cmd_Time(int argc, const char **argv);
/**
* List the active hotspots during the current time period
*/
bool Cmd_Hotspots(int argc, const char **argv);
/**
* Toggle showing the mouse on the screen
*/
bool Cmd_Mouse(int argc, const char **argv);
public:
Debugger(VoyeurEngine *vm);
~Debugger() override {}
};
} // End of namespace Voyeur
#endif

View File

@@ -0,0 +1,65 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "base/plugins.h"
#include "common/str-array.h"
#include "common/memstream.h"
#include "engines/advancedDetector.h"
#include "voyeur/detection.h"
#include "voyeur/voyeur.h"
static const PlainGameDescriptor voyeurGames[] = {
{"voyeur", "Voyeur"},
{0, 0}
};
static const DebugChannelDef debugFlagList[] = {
{Voyeur::kDebugScripts, "scripts", "Game scripts"},
DEBUG_CHANNEL_END
};
#include "voyeur/detection_tables.h"
class VoyeurMetaEngineDetection : public AdvancedMetaEngineDetection<Voyeur::VoyeurGameDescription> {
public:
VoyeurMetaEngineDetection() : AdvancedMetaEngineDetection(Voyeur::gameDescriptions, voyeurGames) {
_maxScanDepth = 3;
}
const char *getName() const override {
return "voyeur";
}
const char *getEngineName() const override {
return "Voyeur";
}
const char *getOriginalCopyright() const override {
return "Voyeur (C) Philips P.O.V. Entertainment Group";
}
const DebugChannelDef *getDebugChannels() const override {
return debugFlagList;
}
};
REGISTER_PLUGIN_STATIC(VOYEUR_DETECTION, PLUGIN_TYPE_ENGINE_DETECTION, VoyeurMetaEngineDetection);

View File

@@ -0,0 +1,37 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef VOYEUR_DETECTION_H
#define VOYEUR_DETECTION_H
namespace Voyeur {
struct VoyeurGameDescription {
AD_GAME_DESCRIPTION_HELPERS(desc);
ADGameDescription desc;
};
#define GAMEOPTION_COPY_PROTECTION GUIO_GAMEOPTIONS1
} // End of namespace Voyeur
#endif // VOYEUR_DETECTION_H

View File

@@ -0,0 +1,64 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace Voyeur {
static const VoyeurGameDescription gameDescriptions[] = {
{
// Voyeur DOS English
{
"voyeur",
nullptr,
AD_ENTRY1s("bvoy.blt", "12e9e10654171501cf8be3a7aa7198e1", 13036269),
Common::EN_ANY,
Common::kPlatformDOS,
ADGF_NO_FLAGS,
GUIO2(GUIO_NOMIDI, GAMEOPTION_COPY_PROTECTION)
}
},
{
// Voyeur DOS English
{
"voyeur",
"Demo",
AD_ENTRY1s("bvoy.blt", "abd10f241b845ebc2a76d27a43770709", 13015827),
Common::EN_ANY,
Common::kPlatformDOS,
ADGF_DEMO,
GUIO2(GUIO_NOMIDI, GAMEOPTION_COPY_PROTECTION)
}
},
{// Voyeur German Fan Translation - By Bakhtosh
{
"voyeur",
"German Fan Made Version",
AD_ENTRY1s("bvoy.blt", "af281a228ddcf7daa18a3c8b591bace9", 15134654),
Common::DE_DEU,
Common::kPlatformDOS,
ADGF_NO_FLAGS,
GUIO2(GUIO_NOMIDI, GAMEOPTION_COPY_PROTECTION)}
},
{AD_TABLE_END_MARKER}};
} // End of namespace Voyeur

598
engines/voyeur/events.cpp Normal file
View File

@@ -0,0 +1,598 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "voyeur/events.h"
#include "voyeur/voyeur.h"
#include "voyeur/staticres.h"
#include "common/events.h"
#include "graphics/cursorman.h"
#include "graphics/font.h"
#include "graphics/fontman.h"
#include "graphics/paletteman.h"
namespace Voyeur {
IntNode::IntNode() {
_intFunc = nullptr;
_curTime = 0;
_timeReset = 0;
_flags = 0;
}
IntNode::IntNode(uint16 curTime, uint16 timeReset, uint16 flags) {
_intFunc = nullptr;
_curTime = curTime;
_timeReset = timeReset;
_flags = flags;
}
/*------------------------------------------------------------------------*/
IntData::IntData() {
_flipWait = false;
_hasPalette = false;
_flashTimer = 0;
_flashStep = 0;
_skipFading = false;
_palStartIndex = 0;
_palEndIndex = 0;
_palette = nullptr;
}
/*------------------------------------------------------------------------*/
EventsManager::EventsManager(VoyeurEngine *vm) : _intPtr(_gameData),
_fadeIntNode(0, 0, 3), _cycleIntNode(0, 0, 3), _vm(vm) {
_cycleStatus = 0;
_fadeStatus = 0;
_priorFrameTime = g_system->getMillis();
_gameCounter = 0;
_counterFlag = false;
_recordBlinkCounter = 0;
_cursorBlinked = false;
Common::fill(&_cycleTime[0], &_cycleTime[4], 0);
Common::fill(&_cycleNext[0], &_cycleNext[4], (byte *)nullptr);
_cyclePtr = nullptr;
_leftClick = _rightClick = false;
_mouseClicked = _newMouseClicked = false;
_newLeftClick = _newRightClick = false;
_videoDead = 0;
_fadeFirstCol = _fadeLastCol = 0;
_fadeCount = 1;
for (int i = 0; i < 4; i++)
_cycleNext[i] = nullptr;
}
void EventsManager::startMainClockInt() {
_mainIntNode._intFunc = &EventsManager::mainVoyeurIntFunc;
_mainIntNode._flags = 0;
_mainIntNode._curTime = 0;
_mainIntNode._timeReset = 60;
}
void EventsManager::mainVoyeurIntFunc() {
if (!(_vm->_voy->_eventFlags & EVTFLAG_TIME_DISABLED)) {
++_vm->_voy->_switchBGNum;
if (_vm->_debugger->_isTimeActive) {
// Increase camera discharge
++_vm->_voy->_RTVNum;
// If the murder threshold has been set, and is passed, then flag the victim
// as murdered, which prevents sending the tape from succeeding
if (_vm->_voy->_RTVNum >= _vm->_voy->_murderThreshold)
_vm->_voy->_victimMurdered = true;
}
}
}
void EventsManager::sWaitFlip() {
Common::Array<ViewPortResource *> &viewPorts = _vm->_screen->_viewPortListPtr->_entries;
for (uint idx = 0; idx < viewPorts.size(); ++idx) {
ViewPortResource &viewPort = *viewPorts[idx];
if (_vm->_screen->_saveBack && (viewPort._flags & DISPFLAG_40)) {
Common::Rect *clipPtr = _vm->_screen->_clipPtr;
_vm->_screen->_clipPtr = &viewPort._clipRect;
if (viewPort._restoreFn)
(_vm->_screen->*viewPort._restoreFn)(&viewPort);
_vm->_screen->_clipPtr = clipPtr;
viewPort._rectListCount[viewPort._pageIndex] = 0;
viewPort._rectListPtr[viewPort._pageIndex]->clear();
viewPort._flags &= ~DISPFLAG_40;
}
}
while (_gameData._flipWait && !_vm->shouldQuit()) {
pollEvents();
g_system->delayMillis(10);
}
}
void EventsManager::checkForNextFrameCounter() {
// Check for next game frame
uint32 milli = g_system->getMillis();
if ((milli - _priorFrameTime) >= GAME_FRAME_TIME) {
_counterFlag = !_counterFlag;
if (_counterFlag)
++_gameCounter;
_priorFrameTime = milli;
// Run the timer-based updates
voyeurTimer();
if ((_gameCounter % GAME_FRAME_RATE) == 0)
mainVoyeurIntFunc();
// If mouse position display is on, display the position
if (_vm->_debugger->_showMousePosition)
showMousePosition();
// Display the frame
_vm->_screen->update();
}
}
void EventsManager::showMousePosition() {
const Graphics::Font &font(*FontMan.getFontByUsage(Graphics::FontManager::kConsoleFont));
Common::String mousePos = Common::String::format("(%d,%d)", _mousePos.x, _mousePos.y);
if (_vm->_voyeurArea == AREA_INTERFACE) {
Common::Point pt = _mousePos + _vm->_mansionViewPos - Common::Point(40, 27);
if (pt.x < 0) pt.x = 0;
if (pt.y < 0) pt.y = 0;
mousePos += Common::String::format(" - (%d,%d)", pt.x, pt.y);
}
_vm->_screen->fillRect(Common::Rect(0, 0, 110, font.getFontHeight()), 0);
font.drawString(_vm->_screen, mousePos, 0, 0, 110, 63);
}
void EventsManager::voyeurTimer() {
_gameData._flashTimer += _gameData._flashStep;
if (_gameData._flipWait) {
_gameData._flipWait = false;
_gameData._skipFading = false;
}
videoTimer();
// Iterate through the list of registered nodes
for (auto &node : _intNodes) {
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 * 3, _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::delayClick(int cycles) {
uint32 totalMilli = cycles * 1000 / GAME_FRAME_RATE;
uint32 delayEnd = g_system->getMillis() + totalMilli;
do {
g_system->delayMillis(10);
getMouseInfo();
} while (!_vm->shouldQuit() && g_system->getMillis() < delayEnd
&& !_vm->_eventsManager->_mouseClicked);
}
void EventsManager::pollEvents() {
checkForNextFrameCounter();
Common::Event event;
while (g_system->getEventManager()->pollEvent(event) && !_vm->shouldQuit()) {
// Handle keypress
switch (event.type) {
case Common::EVENT_QUIT:
case Common::EVENT_RETURN_TO_LAUNCHER:
case Common::EVENT_KEYUP:
return;
case Common::EVENT_KEYDOWN:
return;
case Common::EVENT_LBUTTONDOWN:
_newLeftClick = true;
_newMouseClicked = true;
return;
case Common::EVENT_RBUTTONDOWN:
_newRightClick = true;
_newMouseClicked = true;
return;
case Common::EVENT_LBUTTONUP:
case Common::EVENT_RBUTTONUP:
_newMouseClicked = false;
_newLeftClick = false;
_newRightClick = false;
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->_screen->_VGAColors[_fadeFirstCol * 3];
int mapIndex = 0;
for (int idx = _fadeFirstCol; idx <= _fadeLastCol; ++idx, vgaP += 3) {
ViewPortPalEntry &palEntry = _vm->_screen->_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._skipFading = true;
_fadeIntNode._flags &= ~1;
} else {
byte *vgaP = &_vm->_screen->_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 (_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._skipFading)
return;
if (--_fadeCount == 0) {
_fadeIntNode._flags |= 1;
_fadeStatus &= ~1;
return;
}
for (int i = _fadeFirstCol; i <= _fadeLastCol; ++i) {
ViewPortPalEntry &palEntry = _vm->_screen->_viewPortListPtr->_palette[i];
byte *vgaP = &_vm->_screen->_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;
}
void EventsManager::vDoCycleInt() {
for (int idx = 3; idx >= 0; --idx) {
if (_cyclePtr->_type[idx] && --_cycleTime[idx] <= 0) {
byte *pSrc = _cycleNext[idx];
byte *pPal = _vm->_screen->_VGAColors;
if (_cyclePtr->_type[idx] != 1) {
// New palette data being specified - loop to set entries
do {
int palIndex = READ_LE_UINT16(pSrc);
pPal[palIndex * 3] = pSrc[3];
pPal[palIndex * 3 + 1] = pSrc[4];
pPal[palIndex * 3 + 2] = pSrc[5];
pSrc += 6;
if ((int16)READ_LE_UINT16(pSrc) >= 0) {
// Resetting back to start of cycle data
pSrc = _cycleNext[idx];
break;
}
} while (*(pSrc + 2) == 0);
_cycleNext[idx] = pSrc;
_cycleTime[idx] = pSrc[2];
} else {
// Palette rotation to be done
_cycleTime[idx] = pSrc[4];
if (pSrc[5] == 1) {
// Move palette entry to end of range
int start = READ_LE_UINT16(pSrc);
int end = READ_LE_UINT16(&pSrc[2]);
assert(start < 0x100 && end < 0x100);
// Store the RGB of the first entry to be moved
byte r = pPal[start * 3];
byte g = pPal[start * 3 + 1];
byte b = pPal[start * 3 + 2];
Common::copy(&pPal[start * 3 + 3], &pPal[end * 3 + 3], &pPal[start * 3]);
// Place the original saved entry at the end of the range
pPal[end * 3] = r;
pPal[end * 3 + 1] = g;
pPal[end * 3 + 2] = b;
if (_fadeStatus & 1) {
//dx = start, di = end
warning("TODO: Adjustment of ViewPortListResource");
}
} else {
// Move palette entry to start of range
int start = READ_LE_UINT16(pSrc);
int end = READ_LE_UINT16(&pSrc[2]);
assert(start < 0x100 && end < 0x100);
// Store the RGB of the entry to be moved
byte r = pPal[end * 3];
byte g = pPal[end * 3 + 1];
byte b = pPal[end * 3 + 2];
// Move the remainder of the range forwards one entry
Common::copy_backward(&pPal[start * 3], &pPal[end * 3], &pPal[end * 3 + 3]);
// Place the original saved entry at the end of the range
pPal[start * 3] = r;
pPal[start * 3 + 1] = g;
pPal[start * 3 + 2] = b;
if (_fadeStatus & 1) {
//dx = start, di = end
warning("TODO: Adjustment of ViewPortListResource");
}
}
}
_intPtr._hasPalette = true;
}
}
}
void EventsManager::fadeIntFunc() {
switch (_vm->_voy->_fadingType) {
case 1:
if (_vm->_voy->_fadingAmount1 < 63)
_vm->_voy->_fadingAmount1 += _vm->_voy->_fadingStep1;
if (_vm->_voy->_fadingAmount2 < 63)
_vm->_voy->_fadingAmount2 += _vm->_voy->_fadingStep2;
if (_vm->_voy->_fadingAmount1 > 63)
_vm->_voy->_fadingAmount1 = 63;
if (_vm->_voy->_fadingAmount2 > 63)
_vm->_voy->_fadingAmount2 = 63;
if ((_vm->_voy->_fadingAmount1 == 63) && (_vm->_voy->_fadingAmount2 == 63))
_vm->_voy->_fadingType = 0;
break;
case 2:
if (_vm->_voy->_fadingAmount1 > 0)
_vm->_voy->_fadingAmount1 -= _vm->_voy->_fadingStep1;
if (_vm->_voy->_fadingAmount2 > 0)
_vm->_voy->_fadingAmount2 -= _vm->_voy->_fadingStep2;
if (_vm->_voy->_fadingAmount1 < 0)
_vm->_voy->_fadingAmount1 = 0;
if (_vm->_voy->_fadingAmount2 < 0)
_vm->_voy->_fadingAmount2 = 0;
if ((_vm->_voy->_fadingAmount1 == 0) && (_vm->_voy->_fadingAmount2 == 0))
_vm->_voy->_fadingType = 0;
break;
default:
break;
}
}
void EventsManager::deleteIntNode(IntNode *node) {
_intNodes.remove(node);
}
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->_screen->sDrawPic(pic, &cursor, Common::Point());
}
void EventsManager::setCursor(byte *cursorData, int width, int height, int keyColor) {
CursorMan.replaceCursor(cursorData, width, height, width / 2, height / 2, keyColor);
}
void EventsManager::setCursorColor(int idx, int mode) {
switch (mode) {
case 0:
_vm->_screen->setColor(idx, 90, 90, 232);
break;
case 1:
_vm->_screen->setColor(idx, 232, 90, 90);
break;
case 2:
_vm->_screen->setColor(idx, 90, 232, 90);
break;
case 3:
_vm->_screen->setColor(idx, 90, 232, 232);
break;
default:
break;
}
}
void EventsManager::showCursor() {
CursorMan.showMouse(true);
}
void EventsManager::hideCursor() {
CursorMan.showMouse(false);
}
void EventsManager::getMouseInfo() {
pollEvents();
if (_vm->_voy->_eventFlags & EVTFLAG_RECORDING) {
if ((_gameCounter - _recordBlinkCounter) > 8) {
_recordBlinkCounter = _gameCounter;
if (_cursorBlinked) {
_cursorBlinked = false;
_vm->_screen->setOneColor(128, 220, 20, 20);
_vm->_screen->setColor(128, 220, 20, 20);
} else {
_cursorBlinked = true;
_vm->_screen->setOneColor(128, 220, 220, 220);
_vm->_screen->setColor(128, 220, 220, 220);
}
}
}
_mouseClicked = _newMouseClicked;
_leftClick = _newLeftClick;
_rightClick = _newRightClick;
_newMouseClicked = false;
_newLeftClick = false;
_newRightClick = false;
}
void EventsManager::startCursorBlink() {
if (_vm->_voy->_eventFlags & EVTFLAG_RECORDING) {
_vm->_screen->setOneColor(128, 55, 5, 5);
_vm->_screen->setColor(128, 220, 20, 20);
_intPtr._hasPalette = true;
_vm->_screen->drawDot();
//copySection();
}
}
void EventsManager::incrementTime(int amt) {
for (int i = 0; i < amt; ++i)
mainVoyeurIntFunc();
}
void EventsManager::stopEvidDim() {
deleteIntNode(&_evIntNode);
}
Common::String EventsManager::getEvidString(int eventIndex) {
assert(eventIndex <= _vm->_voy->_eventCount);
VoyeurEvent &e = _vm->_voy->_events[eventIndex];
if (_vm->getLanguage() == Common::DE_DEU)
return Common::String::format("%03d %.2d:%.2d %s %s", eventIndex + 1,
e._isAM ? e._hour : e._hour + 12, e._minute, e._isAM ? AM_DE : PM_DE, EVENT_TYPE_STRINGS_DE[e._type - 1]);
return Common::String::format("%03d %.2d:%.2d %s %s", eventIndex + 1,
e._hour, e._minute, e._isAM ? AM_EN : PM_EN, EVENT_TYPE_STRINGS_EN[e._type - 1]);
}
} // End of namespace Voyeur

144
engines/voyeur/events.h Normal file
View File

@@ -0,0 +1,144 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef VOYEUR_EVENTS_H
#define VOYEUR_EVENTS_H
#include "common/scummsys.h"
#include "common/list.h"
#include "graphics/surface.h"
#include "voyeur/files.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;
IntNode();
IntNode(uint16 curTime, uint16 timeReset, uint16 flags);
};
class IntData {
public:
bool _flipWait;
int _flashTimer;
int _flashStep;
bool _hasPalette;
bool _skipFading;
int _palStartIndex;
int _palEndIndex;
byte *_palette;
IntData();
};
class EventsManager {
private:
VoyeurEngine *_vm;
bool _counterFlag;
bool _cursorBlinked;
uint32 _gameCounter;
uint32 _priorFrameTime;
uint32 _recordBlinkCounter; // Original field was called _joe :)
Common::List<IntNode *> _intNodes;
Common::Point _mousePos;
void mainVoyeurIntFunc();
void checkForNextFrameCounter();
void voyeurTimer();
void videoTimer();
void vDoFadeInt();
void vDoCycleInt();
void fadeIntFunc();
void addIntNode(IntNode *node);
void deleteIntNode(IntNode *node);
/**
* Debugger support method to show the mouse position
*/
void showMousePosition();
public:
IntData _gameData;
IntData &_intPtr;
IntNode _fadeIntNode;
IntNode _fade2IntNode;
IntNode _cycleIntNode;
IntNode _evIntNode;
IntNode _mainIntNode;
int _cycleStatus;
int _fadeFirstCol, _fadeLastCol;
int _fadeCount;
int _fadeStatus;
bool _leftClick, _rightClick;
bool _mouseClicked, _newMouseClicked;
bool _newLeftClick, _newRightClick;
int _videoDead;
int _cycleTime[4];
byte *_cycleNext[4];
VInitCycleResource *_cyclePtr;
EventsManager(VoyeurEngine *vm);
void setMousePos(const Common::Point &p) { _mousePos = p; }
void startMainClockInt();
void sWaitFlip();
void vInitColor();
void delay(int cycles);
void delayClick(int cycles);
void pollEvents();
void startFade(CMapResource *cMap);
void addFadeInt();
void setCursor(PictureResource *pic);
void setCursor(byte *cursorData, int width, int height, int keyColor);
void setCursorColor(int idx, int mode);
void showCursor();
void hideCursor();
Common::Point getMousePos() { return _mousePos; }
uint32 getGameCounter() const { return _gameCounter; }
void getMouseInfo();
void startCursorBlink();
void incrementTime(int amt);
void stopEvidDim();
Common::String getEvidString(int eventIndex);
};
} // End of namespace Voyeur
#endif /* VOYEUR_EVENTS_H */

1634
engines/voyeur/files.cpp Normal file

File diff suppressed because it is too large Load Diff

618
engines/voyeur/files.h Normal file
View File

@@ -0,0 +1,618 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#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/screen.h"
namespace Voyeur {
class VoyeurEngine;
class BoltFile;
class BoltGroup;
class BoltEntry;
class RectResource;
class PictureResource;
class ViewPortResource;
class ViewPortListResource;
class FontResource;
class CMapResource;
class VInitCycleResource;
class PtrResource;
class ControlResource;
class StateResource;
class ThreadResource;
#define DECOMPRESS_SIZE 0x7000
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;
int _bufferEnd;
int _bufferBegin;
int _bytesLeft;
int _bufSize;
byte *_bufStart;
byte *_bufPos;
byte _decompressBuf[DECOMPRESS_SIZE];
int _historyIndex;
byte _historyBuffer[0x200];
int _runLength;
bool _decompState;
int _runType;
int _runValue;
int _runOffset;
Common::File *_curFd;
Common::Array<ResolveEntry> _resolves;
byte *_boltPageFrame;
public:
BoltFilesState(VoyeurEngine *vm);
byte *decompress(byte *buf, int size, int mode);
void nextBlock();
};
class BoltFile {
private:
Common::Array<BoltGroup> _groups;
protected:
BoltFilesState &_state;
virtual void initResource(int resType) = 0;
void initDefault();
private:
void resolveAll();
byte *getBoltMember(uint32 id);
public:
Common::File _file;
BoltFile(const char *filename, BoltFilesState &state);
virtual ~BoltFile();
BoltGroup *getBoltGroup(uint16 id);
void freeBoltGroup(uint16 id);
void freeBoltMember(uint32 id);
byte *memberAddr(uint32 id);
byte *memberAddrOffset(uint32 id);
void resolveIt(uint32 id, byte **p);
void resolveFunction(uint32 id, ScreenMethodPtr *fn);
BoltEntry &boltEntry(uint16 id);
BoltEntry &getBoltEntryFromLong(uint32 id);
PictureResource *getPictureResource(uint32 id);
CMapResource *getCMapResource(uint32 id);
};
class BVoyBoltFile: public BoltFile {
private:
// initType method table
void sInitRect();
void sInitPic();
void vInitCMap();
void vInitCycl();
void initViewPort();
void initViewPortList();
void initFontInfo();
void initFont();
void initSoundMap();
protected:
void initResource(int resType) override;
public:
BVoyBoltFile(BoltFilesState &state);
};
class StampBoltFile: public BoltFile {
private:
void initThread();
void initState();
void initPtr();
void initControl();
protected:
void initResource(int resType) override;
public:
StampBoltFile(BoltFilesState &state);
};
class BoltGroup {
private:
Common::SeekableReadStream *_file;
public:
bool _loaded;
bool _processed;
int _count;
int _fileOffset;
Common::Array<BoltEntry> _entries;
public:
BoltGroup(Common::SeekableReadStream *f);
virtual ~BoltGroup();
void load(uint16 groupId);
void unload();
};
class BoltEntry {
private:
Common::SeekableReadStream *_file;
public:
uint16 _id;
byte _mode;
byte _initMethod;
int _fileOffset;
int _size;
byte *_data;
// bvoy.blt resource types
RectResource *_rectResource;
PictureResource *_picResource;
ViewPortResource *_viewPortResource;
ViewPortListResource *_viewPortListResource;
FontResource *_fontResource;
FontInfoResource *_fontInfoResource;
CMapResource *_cMapResource;
VInitCycleResource *_vInitCycleResource;
// stampblt.blt resource types
PtrResource *_ptrResource;
ControlResource *_controlResource;
StateResource *_stateResource;
ThreadResource *_threadResource;
public:
BoltEntry(Common::SeekableReadStream *f, uint16 id);
virtual ~BoltEntry();
void load();
bool hasResource() const;
};
class FilesManager {
public:
BoltFilesState *_boltFilesState;
BoltFile *_curLibPtr;
public:
FilesManager(VoyeurEngine *vm);
~FilesManager();
bool openBoltLib(const char *filename, BoltFile *&boltFile);
byte *fload(const char *filename, int *size);
};
class RectEntry: public Common::Rect {
public:
int _arrIndex;
int _count;
RectEntry(int x1, int y1, int x2, int y2, int arrIndex, int count);
};
class RectResource: public Common::Rect {
public:
Common::Array<RectEntry> _entries;
public:
RectResource(const byte *src, int size, bool isExtendedRects);
RectResource(int xp, int yp, int width, int height);
virtual ~RectResource() {}
};
/* bvoy.blt resource types */
enum PictureFlag {
PICFLAG_2 = 2, PICFLAG_PIC_OFFSET = 8, PICFLAG_CLEAR_SCREEN = 0x10,
PICFLAG_20 = 0x20, PICFLAG_HFLIP = 0x40, PICFLAG_VFLIP = 0x80, PICFLAG_100 = 0x100,
PICFLAG_CLEAR_SCREEN00 = 0x1000
};
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,
DISPFLAG_NONE = 0};
class DisplayResource {
protected:
VoyeurEngine *_vm;
public:
uint32 _flags;
public:
DisplayResource();
DisplayResource(VoyeurEngine *vm);
/**
* Fill a box of the given size at the current _drawPtr location
*/
void sFillBox(int width, int height);
/**
* Draw text at the current pen position
*/
int drawText(const Common::String &msg);
/**
* Return the width of a given text in the current font
*/
int textWidth(const Common::String &msg);
/**
* Clip the given rectangle by the currently viewable area
*/
bool clipRect(Common::Rect &rect);
};
class PictureResource: public DisplayResource {
private:
/**
* Flip the image data horizontally
*/
void flipHorizontal(const byte *data);
/**
* Flip the image data vertically
*/
void flipVertical(const byte *data);
public:
byte _select;
byte _pick;
byte _onOff;
Common::Rect _bounds;
uint32 _maskData;
uint _planeSize;
byte _keyColor;
/**
* Image data for the picture
*/
byte *_imgData;
/**
* Flag to indicate whether to free the image data
*/
DisposeAfterUse::Flag _freeImgData;
public:
PictureResource(BoltFilesState &state, const byte *src);
PictureResource(int flags, int select, int pick, int onOff,
const Common::Rect &bounds, int maskData, byte *imgData, int planeSize);
PictureResource(Graphics::Surface *surface);
PictureResource();
virtual ~PictureResource();
};
typedef void (ViewPortResource::*ViewPortMethodPtr)();
class ViewPortResource: public DisplayResource {
private:
BoltFilesState &_state;
private:
void setupViewPort(PictureResource *page, Common::Rect *clippingRect, ViewPortSetupPtr setupFn,
ViewPortAddPtr addFn, ViewPortRestorePtr restoreFn);
public:
ViewPortResource *_parent;
ViewPortSetupPtr _setupFn;
int _pageCount;
ViewPortAddPtr _addFn;
int _pageIndex;
ViewPortRestorePtr _restoreFn;
int _lastPage;
ScreenMethodPtr _fn1;
Common::Rect _bounds;
PictureResource *_currentPic;
PictureResource *_activePage;
PictureResource *_pages[2];
// 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 favor
// of the arrays' .size() method
Common::Array<Common::Rect> *_rectListPtr[3];
int _rectListCount[3];
Common::Rect _clipRect;
Common::Rect _fontRect;
public:
ViewPortResource(BoltFilesState &state, const byte *src);
virtual ~ViewPortResource();
void setupViewPort();
void setupViewPort(PictureResource *pic, Common::Rect *clippingRect = nullptr);
void addSaveRect(int pageIndex, const Common::Rect &r);
void fillPic(byte onOff);
void drawIfaceTime();
void drawPicPerm(PictureResource *pic, const Common::Point &pt);
};
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 _fontDepth;
int _padding;
int _fontHeight;
int _topPadding;
int *_charWidth;
byte *_charOffsets;
byte *_charImages;
FontResource(BoltFilesState &state, byte *src);
virtual ~FontResource();
};
enum FontJustify { ALIGN_LEFT = 0, ALIGN_CENTER = 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 VInitCycleResource {
private:
BoltFilesState &_state;
public:
int _type[4];
byte *_ptr[4];
public:
VInitCycleResource(BoltFilesState &state, const byte *src);
virtual ~VInitCycleResource() {}
void vStartCycle();
void vStopCycle();
};
/* stampblt.blt resources */
class PtrResource {
public:
Common::Array<BoltEntry *> _entries;
PtrResource(BoltFilesState &state, const byte *src);
virtual ~PtrResource() {}
};
class ControlResource {
public:
int _memberIds[8];
byte *_entries[8];
int _stateId;
StateResource *_state;
ControlResource(BoltFilesState &state, const byte *src);
virtual ~ControlResource() {}
};
/**
* Stores data about the intended victim
*/
class StateResource {
public:
int _vals[4];
int &_victimIndex;
int &_victimEvidenceIndex;
int &_victimMurderIndex;
StateResource(BoltFilesState &state, const byte *src);
virtual ~StateResource() {}
/**
* Synchronizes the game data
*/
void synchronize(Common::Serializer &s);
};
class ThreadResource {
public:
static int _useCount[8];
static void initUseCount();
static void unloadAllStacks(VoyeurEngine *vm);
static void init();
private:
VoyeurEngine *_vm;
Common::Point _aptPos;
private:
bool getStateInfo();
byte *getDataOffset();
void getButtonsText();
void getButtonsFlags();
void performOpenCard();
const byte *getRecordOffset(const byte *p);
const byte *getNextRecord(const byte *p);
const byte *getSTAMPCard(int cardId);
int getStateFromID(uint32 id);
uint32 getSID(int sid);
void cardAction(const byte *p);
void doSTAMPCardAction();
bool goToStateID(int stackId, int id);
const byte *cardPerform(const byte *card);
bool cardPerform2(const byte *p, int cardCmdId);
void savePrevious();
void setButtonFlag(int idx, byte bits);
void clearButtonFlag(int idx, byte bits);
/**
* Frees the apartment screen data
*/
void freeTheApt();
/**
* Does any necessary animation at the start or end of showing the apartment.
*/
void doAptAnim(int mode);
/**
* Updates the mansion scroll position if ncessary, and returns true if it
* has been changed.
*/
bool checkMansionScroll();
public:
int _stateId;
int _stackId;
int _savedStateId;
int _savedStackId;
int _newStateId;
int _newStackId;
int _stateFlags;
int _stateCount;
int _parseCount;
uint32 _nextStateId;
byte *_threadInfoPtr;
byte _buttonFlags[64];
byte _buttonIds[64];
byte *_ctlPtr;
byte *_playCommandsPtr;
/**
* Loads the specified stack
*/
bool loadAStack(int stackId);
/**
* Unloads the specified stack
*/
void unloadAStack(int stackId);
/**
* Initializes data for the thread based on the current state
*/
bool doState();
public:
ThreadResource(BoltFilesState &state, const byte *src);
virtual ~ThreadResource() {}
/**
* Initialize the thread
*/
void initThreadStruct(int idx, int id);
/**
* Go to a new state and/or stack
*/
bool goToState(int stackId, int stateId);
bool chooseSTAMPButton(int buttonId);
/**
* Parses the script commands from the currently active stack
*/
void parsePlayCommands();
/**
* Do the camera view looking at the mansion
*/
int doInterface();
/**
* Do the display of a room that has one or more evidence hotspots
* available for display
*/
void doRoom();
/**
* Shows the apartment screen
*/
int doApt();
/**
* Loads data needed for displaying the initial apartment screen
*/
void loadTheApt();
/**
* Synchronizes the game data
*/
void synchronize(Common::Serializer &s);
};
} // End of namespace Voyeur
#endif /* VOYEUR_FILES_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,262 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "voyeur/voyeur.h"
#include "engines/advancedDetector.h"
#include "common/savefile.h"
#include "common/system.h"
#include "common/translation.h"
#include "backends/keymapper/action.h"
#include "backends/keymapper/keymapper.h"
#include "backends/keymapper/standard-actions.h"
#include "graphics/surface.h"
#include "voyeur/detection.h"
#define MAX_SAVES 99
namespace Voyeur {
static const ADExtraGuiOptionsMap optionsList[] = {
{
GAMEOPTION_COPY_PROTECTION,
{
// I18N: lockout is code to start the game
_s("Enable lockout system"),
_s("Require a lockout code to start the game."),
"copy_protection",
false,
0,
0
},
},
AD_EXTRA_GUI_OPTIONS_TERMINATOR
};
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
class VoyeurMetaEngine : public AdvancedMetaEngine<Voyeur::VoyeurGameDescription> {
public:
const char *getName() const override {
return "voyeur";
}
const ADExtraGuiOptionsMap *getAdvancedExtraGuiOptions() const override {
return Voyeur::optionsList;
}
bool hasFeature(MetaEngineFeature f) const override;
Common::Error createInstance(OSystem *syst, Engine **engine, const Voyeur::VoyeurGameDescription *desc) const override;
SaveStateList listSaves(const char *target) const override;
int getMaximumSaveSlot() const override;
bool removeSaveState(const char *target, int slot) const override;
SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const override;
Common::KeymapArray initKeymaps(const char *target) const override;
};
bool VoyeurMetaEngine::hasFeature(MetaEngineFeature f) const {
return
(f == kSupportsListSaves) ||
(f == kSupportsLoadingDuringStartup) ||
(f == kSupportsDeleteSave) ||
(f == kSavesSupportMetaInfo) ||
(f == kSavesSupportThumbnail) ||
(f == kSimpleSavesNames);
}
bool Voyeur::VoyeurEngine::hasFeature(EngineFeature f) const {
return
(f == kSupportsReturnToLauncher) ||
(f == kSupportsLoadingDuringRuntime) ||
(f == kSupportsSavingDuringRuntime);
}
Common::Error VoyeurMetaEngine::createInstance(OSystem *syst, Engine **engine, const Voyeur::VoyeurGameDescription *desc) const {
*engine = new Voyeur::VoyeurEngine(syst,desc);
return Common::kNoError;
}
SaveStateList VoyeurMetaEngine::listSaves(const char *target) const {
Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
Common::String saveDesc;
Common::String pattern = Common::String::format("%s.0##", target);
Common::StringArray filenames = saveFileMan->listSavefiles(pattern);
SaveStateList saveList;
Voyeur::VoyeurSavegameHeader header;
for (const auto &filename : filenames) {
const char *ext = strrchr(filename.c_str(), '.');
int slot = ext ? atoi(ext + 1) : -1;
if (slot >= 0 && slot <= MAX_SAVES) {
Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(filename);
if (in) {
if (header.read(in)) {
saveList.push_back(SaveStateDescriptor(this, slot, header._saveName));
}
delete in;
}
}
}
// Sort saves based on slot number.
Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
return saveList;
}
int VoyeurMetaEngine::getMaximumSaveSlot() const {
return MAX_SAVES;
}
bool VoyeurMetaEngine::removeSaveState(const char *target, int slot) const {
Common::String filename = Common::String::format("%s.%03d", target, slot);
return 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) {
Voyeur::VoyeurSavegameHeader header;
header.read(f, false);
delete f;
// Create the return descriptor
SaveStateDescriptor desc(this, slot, header._saveName);
desc.setThumbnail(header._thumbnail);
desc.setSaveDate(header._saveYear, header._saveMonth, header._saveDay);
desc.setSaveTime(header._saveHour, header._saveMinutes);
desc.setPlayTime(header._totalFrames * GAME_FRAME_TIME);
return desc;
}
return SaveStateDescriptor();
}
Common::KeymapArray VoyeurMetaEngine::initKeymaps(const char *target) const {
using namespace Common;
using namespace Voyeur;
Keymap *engineKeymap = new Keymap(Keymap::kKeymapTypeGame, "voyeur-default", _("Default keymappings"));
Keymap *cutsceneKeymap = new Keymap(Keymap::kKeymapTypeGame, "cutscene", _("Cutscene keymappings"));
Keymap *roomKeymap = new Keymap(Keymap::kKeymapTypeGame, "room", _("Room keymappings"));
Keymap *cameraKeymap = new Keymap(Keymap::kKeymapTypeGame, "camera", _("Camera keymappings"));
Keymap *introKeymap = new Keymap(Keymap::kKeymapTypeGame, "intro", _("Intro keymappings"));
Common::Action *act;
act = new Common::Action(kStandardActionLeftClick, _("Interact"));
act->setLeftClickEvent();
act->addDefaultInputMapping("MOUSE_LEFT");
act->addDefaultInputMapping("JOY_A");
engineKeymap->addAction(act);
act = new Common::Action(kStandardActionRightClick, _("Exit"));
act->setRightClickEvent();
act->addDefaultInputMapping("MOUSE_RIGHT");
act->addDefaultInputMapping("JOY_B");
engineKeymap->addAction(act);
act = new Common::Action(kStandardActionRightClick, _("Skip scene"));
act->setLeftClickEvent();
act->addDefaultInputMapping("MOUSE_LEFT");
act->addDefaultInputMapping("MOUSE_RIGHT");
act->addDefaultInputMapping("JOY_A");
cutsceneKeymap->addAction(act);
act = new Common::Action(kStandardActionLeftClick, _("View evidence"));
act->setLeftClickEvent();
act->addDefaultInputMapping("MOUSE_LEFT");
act->addDefaultInputMapping("JOY_A");
roomKeymap->addAction(act);
act = new Common::Action(kStandardActionRightClick, _("Exit / Put away evidence"));
act->setRightClickEvent();
act->addDefaultInputMapping("MOUSE_RIGHT");
act->addDefaultInputMapping("JOY_B");
roomKeymap->addAction(act);
act = new Common::Action(kStandardActionLeftClick, _("Enter room"));
act->setLeftClickEvent();
act->addDefaultInputMapping("MOUSE_LEFT");
act->addDefaultInputMapping("JOY_A");
cameraKeymap->addAction(act);
act = new Common::Action(kStandardActionRightClick, _("Exit"));
act->setRightClickEvent();
act->addDefaultInputMapping("MOUSE_RIGHT");
act->addDefaultInputMapping("JOY_B");
cameraKeymap->addAction(act);
act = new Common::Action("SKIP", _("Skip intro"));
act->setCustomEngineActionEvent(kActionSkip);
act->addDefaultInputMapping("MOUSE_LEFT");
act->addDefaultInputMapping("ESCAPE");
act->addDefaultInputMapping("SPACE");
act->addDefaultInputMapping("JOY_A");
introKeymap->addAction(act);
KeymapArray keymaps(5);
keymaps[0] = engineKeymap;
keymaps[1] = cutsceneKeymap;
keymaps[2] = roomKeymap;
keymaps[3] = cameraKeymap;
keymaps[4] = introKeymap;
cutsceneKeymap->setEnabled(false);
roomKeymap->setEnabled(false);
cameraKeymap->setEnabled(false);
introKeymap->setEnabled(false);
return keymaps;
}
#if PLUGIN_ENABLED_DYNAMIC(VOYEUR)
REGISTER_PLUGIN_DYNAMIC(VOYEUR, PLUGIN_TYPE_ENGINE, VoyeurMetaEngine);
#else
REGISTER_PLUGIN_STATIC(VOYEUR, PLUGIN_TYPE_ENGINE, VoyeurMetaEngine);
#endif

26
engines/voyeur/module.mk Normal file
View File

@@ -0,0 +1,26 @@
MODULE := engines/voyeur
MODULE_OBJS := \
animation.o \
data.o \
debugger.o \
events.o \
files.o \
files_threads.o \
metaengine.o \
screen.o \
sound.o \
staticres.o \
voyeur.o \
voyeur_game.o
# This module can be built as a plugin
ifeq ($(ENABLE_VOYEUR), DYNAMIC_PLUGIN)
PLUGIN := 1
endif
# Include common rules
include $(srcdir)/rules.mk
# Detection objects
DETECT_OBJS += $(MODULE)/detection.o

1076
engines/voyeur/screen.cpp Normal file

File diff suppressed because it is too large Load Diff

115
engines/voyeur/screen.h Normal file
View File

@@ -0,0 +1,115 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef VOYEUR_GRAPHICS_H
#define VOYEUR_GRAPHICS_H
#include "common/scummsys.h"
#include "common/array.h"
#include "common/rect.h"
#include "common/serializer.h"
#include "graphics/screen.h"
namespace Voyeur {
#define SCREEN_WIDTH 320
#define SCREEN_HEIGHT 200
class VoyeurEngine;
class Screen;
class DisplayResource;
class PictureResource;
class ViewPortResource;
class ViewPortListResource;
class FontResource;
class FontInfoResource;
class CMapResource;
class DrawInfo {
public:
int _penColor;
Common::Point _pos;
public:
DrawInfo(int penColor, const Common::Point &pos);
};
typedef void (Screen::*ScreenMethodPtr)();
typedef void (Screen::*ViewPortSetupPtr)(ViewPortResource *);
typedef void (Screen::*ViewPortAddPtr)(ViewPortResource *, int idx, const Common::Rect &bounds);
typedef void (Screen::*ViewPortRestorePtr)(ViewPortResource *);
class Screen: public Graphics::Screen {
public:
byte _VGAColors[Graphics::PALETTE_SIZE];
PictureResource *_backgroundPage;
int _SVGAMode;
ViewPortListResource *_viewPortListPtr;
ViewPortResource *_vPort;
bool _saveBack;
Common::Rect *_clipPtr;
uint _planeSelect;
CMapResource *_backColors;
FontInfoResource *_fontPtr;
PictureResource *_fontChar;
DrawInfo *_drawPtr;
DrawInfo _defaultDrawInfo;
private:
VoyeurEngine *_vm;
void restoreBack(Common::Array<Common::Rect> &rectList, int rectListCount,
PictureResource *srcPic, PictureResource *destPic);
public:
Screen(VoyeurEngine *vm);
~Screen() override;
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 sDrawPic(DisplayResource *srcDisplay, DisplayResource *destDisplay, const Common::Point &initialOffset);
void fillPic(DisplayResource *display, byte onOff);
void sDisplayPic(PictureResource *pic);
void drawANumber(DisplayResource *display, int num, const Common::Point &pt);
void flipPage();
void setPalette(const byte *palette, int start, int count);
void setPalette128(const byte *palette, int start, int count);
void resetPalette();
void setColor(int idx, byte r, byte g, byte b);
void setOneColor(int idx, byte r, byte g, byte b);
void setColors(int start, int count, const byte *pal);
void screenReset();
void fadeDownICF1(int steps);
void fadeUpICF1(int steps = 0);
void fadeDownICF(int steps);
void drawDot();
/**
* Synchronizes the game data
*/
void synchronize(Common::Serializer &s);
};
} // End of namespace Voyeur
#endif /* VOYEUR_GRAPHICS_H */

87
engines/voyeur/sound.cpp Normal file
View File

@@ -0,0 +1,87 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "audio/audiostream.h"
#include "audio/decoders/raw.h"
#include "audio/decoders/voc.h"
#include "common/file.h"
#include "common/memstream.h"
#include "voyeur/sound.h"
#include "voyeur/staticres.h"
namespace Voyeur {
SoundManager::SoundManager(Audio::Mixer *mixer) {
_mixer = mixer;
_vocOffset = 0;
}
void SoundManager::playVOCMap(byte *voc, int vocSize) {
Common::MemoryReadStream *dataStream = new Common::MemoryReadStream(voc, vocSize, DisposeAfterUse::NO);
Audio::AudioStream *audioStream = Audio::makeVOCStream(dataStream, Audio::FLAG_UNSIGNED, DisposeAfterUse::YES);
_mixer->playStream(Audio::Mixer::kSFXSoundType, &_soundHandle, audioStream);
}
void SoundManager::abortVOCMap() {
_mixer->stopHandle(_soundHandle);
}
void SoundManager::stopVOCPlay() {
_mixer->stopHandle(_soundHandle);
_vocOffset = 0;
}
void SoundManager::setVOCOffset(int offset) {
_vocOffset = offset;
}
Common::Path SoundManager::getVOCFileName(int idx) {
assert(idx >= 0);
return Common::Path(Common::String::format("%s.voc", SZ_FILENAMES[idx]));
}
void SoundManager::startVOCPlay(const Common::Path &filename) {
Common::File f;
if (!f.open(filename))
error("Could not find voc file - %s", filename.toString().c_str());
Audio::SeekableAudioStream *audioStream = Audio::makeVOCStream(f.readStream(f.size()),
Audio::FLAG_UNSIGNED, DisposeAfterUse::YES);
_mixer->playStream(Audio::Mixer::kSFXSoundType, &_soundHandle, audioStream);
audioStream->seek(Audio::Timestamp(_vocOffset * 1000, 11025));
}
void SoundManager::startVOCPlay(int soundId) {
startVOCPlay(getVOCFileName(soundId));
}
int SoundManager::getVOCStatus() {
return _mixer->isSoundHandleActive(_soundHandle);
}
uint32 SoundManager::getVOCFrame() {
Audio::Timestamp timestamp = _mixer->getElapsedTime(_soundHandle);
return timestamp.secs();
}
} // End of namespace Voyeur

52
engines/voyeur/sound.h Normal file
View File

@@ -0,0 +1,52 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef VOYEUR_SOUND_H
#define VOYEUR_SOUND_H
#include "common/scummsys.h"
#include "common/path.h"
#include "audio/mixer.h"
namespace Voyeur {
class SoundManager {
private:
Audio::Mixer *_mixer;
Audio::SoundHandle _soundHandle;
int _vocOffset;
public:
SoundManager(Audio::Mixer *mixer);
void playVOCMap(byte *voc, int vocSize);
void stopVOCPlay();
void abortVOCMap();
void setVOCOffset(int offset);
Common::Path getVOCFileName(int idx);
void startVOCPlay(const Common::Path &filename);
void startVOCPlay(int soundId);
int getVOCStatus();
uint32 getVOCFrame();
};
} // End of namespace Voyeur
#endif /* VOYEUR_SOUND_H */

View File

@@ -0,0 +1,165 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "voyeur/staticres.h"
namespace Voyeur {
const int COMPUTER_DEFAULTS[] = {
18, 1, 0, 1, 33, 0, 998, -1, 18, 2, 0, 1, 41, 0,
998, -1, 18, 3, 0, 1, 47, 0, 998, -1, 18, 4, 0,
1, 53, 0, 998, -1, 18, 5, 0, 1, 46, 0, 998, -1,
18, 6, 0, 1, 50, 0, 998, -1, 18, 7, 0, 1, 40, 0,
998, -1, 18, 8, 0, 1, 43, 0, 998, -1, 19, 1, 0,
2, 28, 0, 998, -1
};
const int RESOLVE_TABLE[] = {
0x2A00, 0x4A00, 0x1000, 0x4B00, 0x2C00, 0x4F00, 0x1400, 0x5000,
0x1700, 0x5100, 0x1800, 0x5200, 0x3300, 0x5400, 0x3700, 0x5500,
0x1A00, 0x1C00, 0x1E00, 0x1F00, 0x2100, 0x2200, 0x2400, 0x2700,
0x2B00, 0x1100, 0x4C00, 0x1200, 0x4D00, 0x1300, 0x4E00, 0x2E00,
0x1900, 0x3200, 0x3400, 0x3800, 0x2800, 0x3E00, 0x4100, 0x2900,
0x4400, 0x4600, 0x5300, 0x3900, 0x7600, 0x7200, 0x7300, 0x7400,
0x7500
};
const int LEVEL_H[] = {
4, 7, 7, 8, 9, 10, 2, 2, 4, 8, 8, 9, 9, 10, 10, 11, 11
};
const int LEVEL_M[] = {
0, 0, 30, 0, 30, 0, 0, 0, 30, 0, 30, 0, 45, 0, 30, 0, 30
};
const int BLIND_TABLE[] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 0, 9, 10, 11, 1, 11, 5, 12,
13, 16, 15, 16, 17, 18, 5, 6, 18, 17, 13, 13, 14, 14,
5, 12, 6, 6, 13, 14, 13
};
const int COMPUTER_SCREEN_TABLE[] = {
269, 128, 307, 163,
269, 128, 307, 163,
68, 79, 98, 102,
68, 79, 98, 102,
68, 79, 98, 102,
68, 79, 98, 102,
248, 138, 291, 163,
83, 132, 143, 156,
248, 138, 291, 163,
83, 132, 143, 156,
83, 132, 143, 156,
248, 138, 291, 163,
68, 79, 98, 102,
68, 79, 98, 102
};
const char *const SZ_FILENAMES[] = {
"A2110100", nullptr, "A2300100", nullptr, "B1220100", nullptr, "C1220100", nullptr,
"C1290100", nullptr, "D1220100", nullptr, "D1270100", nullptr, "E1210100", nullptr,
"E1260100", nullptr, "E1280100", nullptr, "E1325100", nullptr, "F1200100", nullptr,
"G1250100", nullptr, "G1260100", nullptr, "H1200100", nullptr, "H1230100", nullptr,
"H1310100", nullptr, "I1300100", nullptr, "J1220100", nullptr, "J1230100", nullptr,
"J1320100", nullptr, "K1260100", nullptr, "K1280100", nullptr, "K1325100", nullptr,
"L1210100", nullptr, "L1280100", nullptr, "L1290100", nullptr, "L1300100", nullptr,
"L1310100", nullptr, "M1260100", nullptr, "M1310100", nullptr, "N1210100", nullptr,
"N1225100", nullptr, "N1275510", nullptr, "N1280510", nullptr, "N1325100", nullptr,
"O1230100", nullptr, "O1260100", nullptr, "O1260520", nullptr, "O1280100", nullptr,
"O1325540", nullptr, "P1276710", nullptr, "P1280540", nullptr, "P1280740", nullptr,
"P1290510", nullptr, "P1325100", nullptr, "P1325300", nullptr, "P1325520", nullptr,
"Q1230100", nullptr, "Q1240530", nullptr, "Q1240730", nullptr, "Q1260100", nullptr,
"Q1260520", nullptr, "Q1260720", nullptr, "Q1325100", nullptr, "R1280540", nullptr,
"Z1110510", nullptr, "Z1110520", nullptr, "Z1110530", nullptr, "Z1110540", nullptr,
"Z1110545", nullptr, "Z2320100", nullptr, "Z2905300", nullptr, "Z3110100", nullptr,
"Z3115510", nullptr, "Z3115520", nullptr, "Z3115530", nullptr, "Z3115540", nullptr,
"Z4915100", nullptr, "Z4915200", nullptr, "Z4915300",
nullptr, nullptr, nullptr, nullptr, nullptr,
"MMARG", "MZACK", "MREED", "MJESSI", "MCHLOE", "MCAMERA", "MENDCRED",
"NEWCALL2", "PHONE1", "PHONE2", "PHONE3", "PHONE6", "PHONE8",
"B1300100", "C1250100", "C1320100", "D1320100", "E1210200", "E1260200",
"E1280200", "E1310100", "G1230100", "G1300100", "I1210100", "I1270100",
"I1280100", "J1250100", "J1280100", "K1260200", "K1270100", "K1325200",
"L1240100", "M1200100", "M1230100", "M1290100", "N1250100", "N1260100",
"N1280100", "O1250510", "O1290510", "O1320510", "O1320710", "P1240100",
"P1240530", "P1260100", "P1270100", "P1280100", "P1280530", "P1320530",
"Q1240100", "E1325100"
};
const char *const SATURDAY_EN = "Saturday";
const char *const SUNDAY_EN = "Sunday";
const char *const MONDAY_EN = "Monday Morning";
const char *const AM_EN = "am";
const char *const PM_EN = "pm";
const char *const START_OF_MESSAGE_EN = "*** Start of Message ***";
const char *const END_OF_MESSAGE_EN = "*** End of Message ***";
const char *const EVENT_TYPE_STRINGS_EN[4] = { "Video", "Audio", "Evidence", "Computer" };
const char *const SATURDAY_AFTERNOON_EN = "Saturday Afternoon";
const char *const PLAYER_APARTMENT_EN = "Player's Apartment";
const char *const SATURDAY_DE = "Samstag";
const char *const SUNDAY_DE = "Sonntag";
const char *const MONDAY_DE = "Montag Morgen";
const char *const AM_DE = " Uhr";
const char *const PM_DE = " Uhr";
const char *const START_OF_MESSAGE_DE = " *** TEXTANFANG *** ";
const char *const END_OF_MESSAGE_DE = " *** TEXTENDE *** ";
const char *const EVENT_TYPE_STRINGS_DE[4] = {"Video", "Audio", "Beweis", "Computer"};
const char *const SATURDAY_AFTERNOON_DE = "Samstag Nachmittag";
const char *const PLAYER_APARTMENT_DE = "Wohnung des Spielers";
int DOT_LINE_START[9] = {
0xE880, 0xE9C0, 0xEB00, 0xEC40, 0xED80, 0xEEC0, 0xF000, 0xF140, 0xF280
};
int DOT_LINE_OFFSET[9] = {
144, 143, 142, 141, 141, 141, 142, 143, 144
};
int DOT_LINE_LENGTH[9] = {
5, 7, 9, 11, 11, 11, 9, 7, 5
};
const char *const PIRACY_MESSAGE_EN[] = {
"It is illegal to make",
"unauthorized copies of",
"this software. Duplication",
"of this software for any",
"reason including sale,",
"loan, rental, or gift is a",
"crime. Penalties include",
"fines of up to $50,000",
"and jail terms up to",
"5 years."
};
const char *const PIRACY_MESSAGE_DE[] = {
"VOYEUR",
"A POV Entert. Group Production",
"Copyright 1993, 1994",
"Philips Interactive Media",
"Alle Urheberrechte und",
"Leistungsschutzrechte",
"vorbehalten. Kein Verleih.",
"Keine unerlaubte Vervielfaeltigung,",
"Vermietung, Auffuehrung",
"oder Sendung."
};
} // End of namespace Voyeur

View File

@@ -0,0 +1,74 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef VOYEUR_STATICRES_H
#define VOYEUR_STATICRES_H
#include "common/scummsys.h"
namespace Voyeur {
extern const int COMPUTER_DEFAULTS[];
extern const int RESOLVE_TABLE[];
extern const int LEVEL_H[];
extern const int LEVEL_M[];
extern const int BLIND_TABLE[];
extern const int COMPUTER_SCREEN_TABLE[];
extern const char *const SZ_FILENAMES[];
extern const char *const SATURDAY_EN;
extern const char *const SUNDAY_EN;
extern const char *const MONDAY_EN;
extern const char *const AM_EN;
extern const char *const PM_EN;
extern const char *const START_OF_MESSAGE_EN;
extern const char *const END_OF_MESSAGE_EN;
extern const char *const EVENT_TYPE_STRINGS_EN[4];
extern const char *const SATURDAY_AFTERNOON_EN;
extern const char *const PLAYER_APARTMENT_EN;
extern const char *const SATURDAY_DE;
extern const char *const SUNDAY_DE;
extern const char *const MONDAY_DE;
extern const char *const AM_DE;
extern const char *const PM_DE;
extern const char *const START_OF_MESSAGE_DE;
extern const char *const END_OF_MESSAGE_DE;
extern const char *const EVENT_TYPE_STRINGS_DE[4];
extern const char *const SATURDAY_AFTERNOON_DE;
extern const char *const PLAYER_APARTMENT_DE;
extern int DOT_LINE_START[9];
extern int DOT_LINE_OFFSET[9];
extern int DOT_LINE_LENGTH[9];
extern const char *const PIRACY_MESSAGE_EN[];
extern const char *const PIRACY_MESSAGE_DE[];
} // End of namespace Voyeur
#endif

1014
engines/voyeur/voyeur.cpp Normal file

File diff suppressed because it is too large Load Diff

326
engines/voyeur/voyeur.h Normal file
View File

@@ -0,0 +1,326 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef VOYEUR_VOYEUR_H
#define VOYEUR_VOYEUR_H
#include "voyeur/debugger.h"
#include "voyeur/data.h"
#include "voyeur/events.h"
#include "voyeur/files.h"
#include "voyeur/screen.h"
#include "voyeur/sound.h"
#include "common/scummsys.h"
#include "common/system.h"
#include "common/error.h"
#include "common/random.h"
#include "common/savefile.h"
#include "common/serializer.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: Complete
*
* Games using this engine:
* - Voyeur (Dos)
*/
namespace Voyeur {
#define DEBUG_BASIC 1
#define DEBUG_INTERMEDIATE 2
#define DEBUG_DETAILED 3
// Constants used for doInterface display of the mansion
#define MANSION_MAX_X 784
#define MANSION_MAX_Y 150
#define MANSION_VIEW_X 40
#define MANSION_VIEW_Y 27
#define MANSION_VIEW_WIDTH 240
#define MANSION_VIEW_HEIGHT 148
#define MANSION_SCROLL_AREA_X 20
#define MANSION_SCROLL_AREA_Y 20
#define MANSION_SCROLL_INC_X 4
#define MANSION_SCROLL_INC_Y 4
enum VoyeurDebugChannels {
kDebugScripts = 1,
};
enum VoyeurArea { AREA_NONE, AREA_APARTMENT, AREA_INTERFACE, AREA_ROOM, AREA_EVIDENCE };
struct VoyeurGameDescription;
enum VOYEURAction {
kActionNone,
kActionSkip,
};
class VoyeurEngine : public Engine {
private:
const VoyeurGameDescription *_gameDescription;
Common::RandomSource _randomSource;
FontInfoResource _defaultFontInfo;
void ESP_Init();
void globalInitBolt();
void initBolt();
void vInitInterrupts();
void initInput();
bool doHeadTitle();
void showConversionScreen();
bool doLock();
void showTitleScreen();
void doOpening();
void playStamp();
void initStamp();
void closeStamp();
void showLogo8Intro();
/**
* Shows the game ending title animation
*/
void doTailTitle();
/**
* Shows the game ending credits
*/
void doClosingCredits();
/**
* Shows the final anti-piracy message before exiting the game
*/
void doPiracy();
/**
* Review previous tape recordings on the TV
*/
void reviewTape();
/**
* Shows the TV gossip animation
*/
void doGossip();
/**
* Shows the animation of the VCR tape during the 'Call the Police' sequence
*/
void doTapePlaying();
/**
* Does a check as to whether a murder has been witnessed
*/
bool checkForMurder();
/**
* Does a check for whether incriminating evidence has been revealed
*/
bool checkForIncriminate();
/**
* Plays a video event previously witnessed
*/
void playAVideoEvent(int eventIndex);
/**
* Shows the user a screen to select one of four characters to send the
* video tape to
*/
int getChooseButton();
/**
* Synchronizes the game data
*/
void synchronize(Common::Serializer &s);
/**
* Resets the mansion view position
*/
void centerMansionView();
protected:
// Engine APIs
Common::Error run() override;
bool hasFeature(EngineFeature f) const override;
public:
BoltFile *_bVoy;
Debugger *_debugger;
EventsManager *_eventsManager;
FilesManager *_filesManager;
Screen *_screen;
SoundManager *_soundManager;
SVoy *_voy;
BoltFile *_stampLibPtr;
BoltGroup *_controlGroupPtr;
ControlResource *_controlPtr;
byte *_stampData;
BoltGroup *_stackGroupPtr;
int _glGoState;
int _glGoStack;
int _stampFlags;
int _playStampGroupId;
int _currentVocId;
int _audioVideoId;
const int *_resolvePtr;
int _iForceDeath;
int _checkTransitionId;
int _gameHour;
int _gameMinute;
int _flashTimeVal;
bool _flashTimeFlag;
int _timeBarVal;
int _checkPhoneVal;
Common::Point _mansionViewPos;
ThreadResource *_mainThread;
VoyeurArea _voyeurArea;
int _loadGameSlot;
public:
VoyeurEngine(OSystem *syst, const VoyeurGameDescription *gameDesc);
~VoyeurEngine() override;
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);
bool canLoadGameStateCurrently(Common::U32String *msg = nullptr) override;
bool canSaveGameStateCurrently(Common::U32String *msg = nullptr) override;
Common::Error loadGameState(int slot) override;
Common::Error saveGameState(int slot, const Common::String &desc, bool isAutosave = false) override;
void loadGame(int slot);
void playRL2Video(const Common::Path &filename);
void doTransitionCard(const Common::String &time, const Common::String &location);
/**
* Play a given video
*/
void playAVideo(int videoId);
/**
* Play a given video for a given amount of time. This is particularly used
* for later tape playback, where it will only play back as much of the video
* as the user originally watched (since they can break out of watching a video).
*/
void playAVideoDuration(int videoId, int duration);
/**
* Play an audio sequence
*/
void playAudio(int audioId);
void makeViewFinder();
void makeViewFinderP();
void initIFace();
void checkTransition();
int doComputerText(int maxLen);
void getComputerBrush();
/**
* Displays the time/charge remaining on the video camera screen
*/
void doTimeBar();
/**
* If necessary, flashes the time remaining bar on the video camera screen
*/
void flashTimeBar();
/**
* Handle scrolling of the mansion view in the camera sights
*/
void doScroll(const Common::Point &pt);
/**
* Check for phone call
*/
void checkPhoneCall();
/**
* Display evidence sequence from within a room
* Suspension of disbelief needed to believe that recording from a distance,
* you could still flip through the often pages of evidence for a single hotspot.
*/
void doEvidDisplay(int evidId, int eventId);
/**
* Flips the active page and waits until it's drawn
*/
void flipPageAndWait();
/**
* Flips the active page and waits until it's drawn and faded in
*/
void flipPageAndWaitForFade();
/**
* Returns the string for the current in-game day of the week
*/
Common::String getDayName();
/**
* Returns the string for the current in-game time of day
*/
Common::String getTimeOfDay();
/**
* Show the ending sequence of the arrest
*/
void showEndingNews();
};
#define VOYEUR_SAVEGAME_VERSION 3
/**
* Header for Voyeur savegame files
*/
struct VoyeurSavegameHeader {
uint8 _version;
Common::String _saveName;
Graphics::Surface *_thumbnail;
int _saveYear, _saveMonth, _saveDay;
int _saveHour, _saveMinutes;
int _totalFrames;
/**
* Read in the header from the specified file
*/
bool read(Common::InSaveFile *f, bool skipThumbnail = true);
/**
* Write out header information to the specified file
*/
void write(Common::OutSaveFile *f, VoyeurEngine *vm, const Common::String &saveName);
};
} // End of namespace Voyeur
#endif /* VOYEUR_VOYEUR_H */

File diff suppressed because it is too large Load Diff