Initial commit
This commit is contained in:
2
engines/vcruise/POTFILES
Normal file
2
engines/vcruise/POTFILES
Normal file
@@ -0,0 +1,2 @@
|
||||
engines/vcruise/metaengine.cpp
|
||||
engines/vcruise/vcruise.cpp
|
||||
103
engines/vcruise/ad2044_items.cpp
Normal file
103
engines/vcruise/ad2044_items.cpp
Normal file
@@ -0,0 +1,103 @@
|
||||
/* 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 "vcruise/ad2044_items.h"
|
||||
|
||||
namespace VCruise {
|
||||
|
||||
const AD2044ItemInfo g_ad2044ItemInfos[kNumAD2044Items] = {
|
||||
{0, 0, false, 0}, // 0
|
||||
{0, 0, false, 0}, // 1
|
||||
{0, 0, false, 0}, // 2
|
||||
{0, 0, false, 0}, // 3
|
||||
{0, 0, false, 0}, // 4
|
||||
{0, 0, false, 0}, // 5
|
||||
{0, 0, false, 0}, // 6
|
||||
{0, 0, false, 0}, // 7
|
||||
{0, 0, false, 0}, // 8
|
||||
{0, 0, false, 0}, // 9
|
||||
{0, 0, false, 0}, // 10
|
||||
{0, 0, false, 0}, // 11
|
||||
{0, 0, false, 0}, // 12
|
||||
{0, 0, false, 0}, // 13
|
||||
{0, 0, false, 0}, // 14
|
||||
{0, 0, false, 0}, // 15
|
||||
{0, 0, false, 0}, // 16
|
||||
{0, 0, false, 0}, // 17
|
||||
{0x3D70D2EC, 0x98382A38, true, 0x128}, // 18 spoon
|
||||
{0, 0, false, 0}, // 19
|
||||
{0, 0, false, 0}, // 20
|
||||
{0, 0, false, 0}, // 21
|
||||
{0, 0, false, 0}, // 22
|
||||
{0, 0, false, 0}, // 23
|
||||
{0, 0, true, 0x134}, // 24 cigarettes (filled)
|
||||
{0, 0, false, 0}, // 25
|
||||
{0, 0, false, 0}, // 26
|
||||
{0, 0, true, 0x137}, // 27 matches
|
||||
{0, 0, false, 0}, // 28
|
||||
{0, 0, false, 0}, // 29
|
||||
{0, 0, false, 0}, // 30
|
||||
{0, 0, false, 0}, // 31
|
||||
{0, 0, false, 0}, // 32
|
||||
{0, 0, false, 0}, // 33
|
||||
{0, 0, false, 0}, // 34
|
||||
{0, 0, false, 0}, // 35
|
||||
{0, 0, false, 0}, // 36
|
||||
{0, 0, false, 0}, // 37
|
||||
{0, 0, false, 0}, // 38
|
||||
{0, 0, false, 0}, // 39
|
||||
{0, 0, false, 0}, // 40
|
||||
{0, 0, false, 0}, // 41
|
||||
{0, 0, false, 0}, // 42
|
||||
{0, 0, false, 0}, // 43
|
||||
{0, 0, false, 0}, // 44
|
||||
{0, 0, false, 0}, // 45
|
||||
{0, 0, false, 0}, // 46
|
||||
{0, 0, false, 0}, // 47
|
||||
{0, 0, false, 0}, // 48
|
||||
{0, 0, false, 0}, // 49
|
||||
{0, 0, false, 0}, // 50
|
||||
{0, 0, false, 0}, // 51
|
||||
{0, 0, false, 0}, // 52
|
||||
{0, 0, false, 0}, // 53
|
||||
{0x83d54448, 0x839911EF, 0, 0}, // 54 goaler (sic)
|
||||
{0, 0, false, 0}, // 55
|
||||
{0, 0, false, 0}, // 56
|
||||
{0, 0, false, 0}, // 57
|
||||
{0, 0, false, 0}, // 58
|
||||
{0, 0, false, 0}, // 59
|
||||
{0, 0, false, 0x170}, // 60 mirror
|
||||
{0, 0, false, 0}, // 61
|
||||
{0, 0, false, 0}, // 62
|
||||
{0, 0, false, 0}, // 63
|
||||
{0, 0, false, 0}, // 64
|
||||
{0, 0, false, 0}, // 65
|
||||
{0, 0, false, 0}, // 66
|
||||
{0, 0, false, 0}, // 67
|
||||
{0, 0, true, 0x178}, // 68 cigarette
|
||||
{0, 0, true, 0x179}, // 69 cigarette (lit)
|
||||
{0, 0, false, 0}, // 70
|
||||
{0, 0, false, 0}, // 71
|
||||
{0, 0, false, 0}, // 72
|
||||
{0, 0, true, 0x183}, // 73 cigarettes (1 missing)
|
||||
};
|
||||
|
||||
} // End of namespace VCruise
|
||||
43
engines/vcruise/ad2044_items.h
Normal file
43
engines/vcruise/ad2044_items.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/* 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 VCRUISE_AD2044_ITEMS_H
|
||||
#define VCRUISE_AD2044_ITEMS_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
|
||||
namespace VCruise {
|
||||
|
||||
struct AD2044ItemInfo {
|
||||
uint32 enNameCRC;
|
||||
uint32 plNameCRC;
|
||||
bool canBeExamined;
|
||||
uint16 scriptItemID;
|
||||
};
|
||||
|
||||
static const uint kNumAD2044Items = 74;
|
||||
|
||||
extern const AD2044ItemInfo g_ad2044ItemInfos[kNumAD2044Items];
|
||||
|
||||
} // End of namespace VCruise
|
||||
|
||||
|
||||
#endif
|
||||
61
engines/vcruise/ad2044_ui.cpp
Normal file
61
engines/vcruise/ad2044_ui.cpp
Normal file
@@ -0,0 +1,61 @@
|
||||
/* 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 "vcruise/ad2044_ui.h"
|
||||
|
||||
namespace VCruise {
|
||||
|
||||
namespace AD2044Interface {
|
||||
|
||||
Common::Rect getRectForUI(AD2044InterfaceRectID rectID) {
|
||||
switch (rectID) {
|
||||
case AD2044InterfaceRectID::ActiveItemRender:
|
||||
return Common::Rect(512, 150, 588, 217);
|
||||
case AD2044InterfaceRectID::ExamineButton:
|
||||
return Common::Rect(495, 248, 595, 318);
|
||||
case AD2044InterfaceRectID::InventoryRender0:
|
||||
return Common::Rect(24, 394, 100, 461);
|
||||
case AD2044InterfaceRectID::InventoryRender1:
|
||||
return Common::Rect(119, 395, 195, 462);
|
||||
case AD2044InterfaceRectID::InventoryRender2:
|
||||
return Common::Rect(209, 393, 285, 460);
|
||||
case AD2044InterfaceRectID::InventoryRender3:
|
||||
return Common::Rect(302, 393, 378, 460);
|
||||
case AD2044InterfaceRectID::InventoryRender4:
|
||||
return Common::Rect(393, 394, 469, 461);
|
||||
case AD2044InterfaceRectID::InventoryRender5:
|
||||
return Common::Rect(481, 393, 557, 460);
|
||||
default:
|
||||
return Common::Rect();
|
||||
}
|
||||
}
|
||||
|
||||
Common::Rect getFirstInvSlotRect() {
|
||||
return Common::Rect(21, 392, 96, 460);
|
||||
}
|
||||
|
||||
uint getInvSlotSpacing() {
|
||||
return 92;
|
||||
}
|
||||
|
||||
} // End of namespace AD2044Interface
|
||||
|
||||
} // End of namespace VCruise
|
||||
53
engines/vcruise/ad2044_ui.h
Normal file
53
engines/vcruise/ad2044_ui.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/* 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 VCRUISE_AD2044_UI_H
|
||||
#define VCRUISE_AD2044_UI_H
|
||||
|
||||
#include "common/rect.h"
|
||||
|
||||
namespace VCruise {
|
||||
|
||||
enum class AD2044InterfaceRectID {
|
||||
ActiveItemRender,
|
||||
ExamineButton,
|
||||
|
||||
InventoryRender0,
|
||||
InventoryRender1,
|
||||
InventoryRender2,
|
||||
InventoryRender3,
|
||||
InventoryRender4,
|
||||
InventoryRender5,
|
||||
|
||||
};
|
||||
|
||||
namespace AD2044Interface {
|
||||
|
||||
Common::Rect getRectForUI(AD2044InterfaceRectID rectID);
|
||||
Common::Rect getFirstInvSlotRect();
|
||||
uint getInvSlotSpacing();
|
||||
|
||||
|
||||
} // End of namespace AD2044Interface
|
||||
|
||||
} // End of namespace VCruise
|
||||
|
||||
#endif
|
||||
95
engines/vcruise/audio_player.cpp
Normal file
95
engines/vcruise/audio_player.cpp
Normal file
@@ -0,0 +1,95 @@
|
||||
/* 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 "vcruise/audio_player.h"
|
||||
|
||||
namespace VCruise {
|
||||
|
||||
AudioPlayer::AudioPlayer(Audio::Mixer *mixer, const Common::SharedPtr<Audio::AudioStream> &baseStream, Audio::Mixer::SoundType soundType)
|
||||
: _exhausted(false), _isPlaying(false), _mixer(mixer), _baseStream(baseStream), _soundType(soundType) {
|
||||
}
|
||||
|
||||
AudioPlayer::~AudioPlayer() {
|
||||
stop();
|
||||
}
|
||||
|
||||
int AudioPlayer::readBuffer(int16 *buffer, const int numSamplesTimesChannelCount) {
|
||||
Common::StackLock lock(_mutex);
|
||||
|
||||
int samplesRead = 0;
|
||||
if (_exhausted)
|
||||
return 0;
|
||||
|
||||
samplesRead = _baseStream->readBuffer(buffer, numSamplesTimesChannelCount);
|
||||
|
||||
if (samplesRead != numSamplesTimesChannelCount)
|
||||
_exhausted = true;
|
||||
|
||||
return samplesRead;
|
||||
}
|
||||
|
||||
bool AudioPlayer::isStereo() const {
|
||||
return _baseStream->isStereo();
|
||||
}
|
||||
|
||||
int AudioPlayer::getRate() const {
|
||||
return _baseStream->getRate();
|
||||
}
|
||||
|
||||
bool AudioPlayer::endOfData() const {
|
||||
return _exhausted;
|
||||
}
|
||||
|
||||
void AudioPlayer::play(byte volume, int8 balance) {
|
||||
if (!_isPlaying) {
|
||||
_isPlaying = true;
|
||||
_exhausted = false;
|
||||
_mixer->playStream(_soundType, &_handle, this, -1, volume, balance, DisposeAfterUse::NO);
|
||||
}
|
||||
}
|
||||
|
||||
void AudioPlayer::setVolume(byte volume) {
|
||||
_mixer->setChannelVolume(_handle, volume);
|
||||
}
|
||||
|
||||
void AudioPlayer::setBalance(int8 balance) {
|
||||
_mixer->setChannelBalance(_handle, balance);
|
||||
}
|
||||
|
||||
void AudioPlayer::setVolumeAndBalance(byte volume, int8 balance) {
|
||||
if (_isPlaying) {
|
||||
Common::StackLock lock(_mixer->mutex());
|
||||
|
||||
_mixer->setChannelVolume(_handle, volume);
|
||||
_mixer->setChannelBalance(_handle, balance);
|
||||
}
|
||||
}
|
||||
|
||||
void AudioPlayer::stop() {
|
||||
if (_isPlaying) {
|
||||
_mixer->stopHandle(_handle);
|
||||
_isPlaying = false;
|
||||
}
|
||||
|
||||
_exhausted = true;
|
||||
}
|
||||
|
||||
} // End of namespace VCruise
|
||||
67
engines/vcruise/audio_player.h
Normal file
67
engines/vcruise/audio_player.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/* 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 VCRUISE_AUDIO_PLAYER_H
|
||||
#define VCRUISE_AUDIO_PLAYER_H
|
||||
|
||||
#include "common/mutex.h"
|
||||
|
||||
#include "audio/audiostream.h"
|
||||
#include "audio/mixer.h"
|
||||
|
||||
namespace VCruise {
|
||||
|
||||
struct AudioMetadata;
|
||||
class CachedAudio;
|
||||
|
||||
class AudioPlayer : public Audio::AudioStream {
|
||||
public:
|
||||
AudioPlayer(Audio::Mixer *mixer, const Common::SharedPtr<Audio::AudioStream> &baseStream, Audio::Mixer::SoundType soundType);
|
||||
~AudioPlayer();
|
||||
|
||||
int readBuffer(int16 *buffer, const int numSamples) override;
|
||||
bool isStereo() const override;
|
||||
int getRate() const override;
|
||||
bool endOfData() const override;
|
||||
|
||||
void play(byte volume, int8 balance);
|
||||
void stop();
|
||||
|
||||
void setVolume(byte volume);
|
||||
void setBalance(int8 balance);
|
||||
void setVolumeAndBalance(byte volume, int8 balance);
|
||||
|
||||
private:
|
||||
Common::Mutex _mutex;
|
||||
|
||||
Audio::SoundHandle _handle;
|
||||
//bool _isLooping;
|
||||
bool _isPlaying;
|
||||
bool _exhausted;
|
||||
Audio::Mixer *_mixer;
|
||||
Common::SharedPtr<Audio::AudioStream> _baseStream;
|
||||
|
||||
Audio::Mixer::SoundType _soundType;
|
||||
};
|
||||
|
||||
} // End of namespace VCruise
|
||||
|
||||
#endif
|
||||
715
engines/vcruise/circuitpuzzle.cpp
Normal file
715
engines/vcruise/circuitpuzzle.cpp
Normal file
@@ -0,0 +1,715 @@
|
||||
/* 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 "common/algorithm.h"
|
||||
|
||||
#include "vcruise/circuitpuzzle.h"
|
||||
|
||||
namespace VCruise {
|
||||
|
||||
namespace CircuitPuzzleTables {
|
||||
|
||||
// These are hard-coded into the Schizm executable (they're 32-bit in it), figured these out by hand
|
||||
// from tracing screen captures and feeding through a boundary finder script.
|
||||
|
||||
static const int16 g_barriersHorizontal1[100] = {
|
||||
166, 6, 191, 62,
|
||||
244, 7, 267, 62,
|
||||
320, 7, 341, 62,
|
||||
394, 8, 416, 63,
|
||||
469, 8, 492, 62,
|
||||
164, 80, 191, 134,
|
||||
244, 80, 265, 130,
|
||||
320, 80, 336, 131,
|
||||
394, 80, 415, 130,
|
||||
468, 80, 492, 130,
|
||||
163, 152, 191, 199,
|
||||
245, 152, 263, 199,
|
||||
320, 152, 340, 199,
|
||||
395, 152, 415, 199,
|
||||
469, 152, 493, 199,
|
||||
166, 221, 187, 270,
|
||||
245, 221, 266, 270,
|
||||
320, 220, 341, 271,
|
||||
394, 221, 414, 271,
|
||||
469, 221, 492, 271,
|
||||
166, 290, 187, 343,
|
||||
244, 290, 263, 343,
|
||||
320, 290, 341, 343,
|
||||
395, 289, 415, 343,
|
||||
469, 291, 494, 346,
|
||||
};
|
||||
|
||||
static const int16 g_barriersVertical1[64] = {
|
||||
187, 64, 240, 84,
|
||||
266, 63, 316, 84,
|
||||
340, 64, 392, 83,
|
||||
416, 64, 470, 84,
|
||||
186, 135, 240, 151,
|
||||
266, 135, 315, 152,
|
||||
341, 134, 393, 151,
|
||||
416, 135, 479, 152,
|
||||
187, 204, 239, 221,
|
||||
266, 203, 314, 221,
|
||||
341, 204, 391, 220,
|
||||
416, 204, 470, 220,
|
||||
187, 273, 239, 293,
|
||||
266, 271, 314, 292,
|
||||
342, 271, 391, 292,
|
||||
416, 272, 471, 292,
|
||||
};
|
||||
|
||||
static const int16 g_barriersHorizontal2[100] = {
|
||||
160, 8, 185, 62,
|
||||
239, 7, 260, 63,
|
||||
309, 8, 332, 63,
|
||||
388, 8, 407, 63,
|
||||
455, 8, 485, 63,
|
||||
162, 79, 184, 130,
|
||||
241, 80, 260, 131,
|
||||
313, 80, 332, 131,
|
||||
387, 82, 408, 131,
|
||||
460, 82, 484, 131,
|
||||
162, 153, 184, 200,
|
||||
238, 153, 258, 200,
|
||||
312, 153, 333, 201,
|
||||
386, 153, 408, 201,
|
||||
459, 153, 485, 200,
|
||||
161, 220, 183, 270,
|
||||
237, 220, 259, 270,
|
||||
313, 221, 332, 270,
|
||||
384, 220, 408, 269,
|
||||
459, 219, 485, 267,
|
||||
161, 289, 183, 343,
|
||||
238, 288, 259, 350,
|
||||
312, 289, 332, 341,
|
||||
383, 291, 408, 342,
|
||||
460, 290, 484, 341,
|
||||
};
|
||||
|
||||
static const int16 g_barriersVertical2[64] = {
|
||||
186, 63, 239, 84,
|
||||
263, 64, 313, 84,
|
||||
337, 64, 389, 84,
|
||||
411, 64, 464, 85,
|
||||
184, 135, 238, 151,
|
||||
259, 136, 311, 151,
|
||||
336, 135, 388, 152,
|
||||
410, 136, 465, 152,
|
||||
184, 203, 238, 220,
|
||||
263, 204, 311, 220,
|
||||
338, 203, 388, 219,
|
||||
408, 203, 464, 219,
|
||||
185, 272, 237, 291,
|
||||
260, 272, 313, 291,
|
||||
337, 271, 388, 290,
|
||||
411, 271, 463, 289,
|
||||
};
|
||||
|
||||
static const int16 g_linksHorizontal1[100] = {
|
||||
136, 24, 206, 38,
|
||||
216, 24, 284, 38,
|
||||
294, 24, 363, 38,
|
||||
374, 24, 442, 38,
|
||||
452, 24, 520, 38,
|
||||
136, 97, 205, 110,
|
||||
215, 97, 284, 110,
|
||||
294, 98, 363, 110,
|
||||
373, 98, 442, 110,
|
||||
451, 98, 520, 110,
|
||||
137, 170, 206, 182,
|
||||
216, 170, 284, 182,
|
||||
294, 170, 363, 182,
|
||||
373, 170, 442, 182,
|
||||
452, 170, 520, 182,
|
||||
137, 242, 204, 255,
|
||||
216, 242, 284, 255,
|
||||
295, 242, 363, 254,
|
||||
374, 242, 441, 254,
|
||||
452, 242, 520, 254,
|
||||
137, 315, 204, 328,
|
||||
216, 315, 284, 328,
|
||||
295, 315, 362, 327,
|
||||
374, 315, 441, 327,
|
||||
452, 315, 520, 327,
|
||||
};
|
||||
|
||||
static const int16 g_linksVertical1[64] = {
|
||||
205, 36, 217, 98,
|
||||
284, 36, 295, 99,
|
||||
362, 36, 374, 99,
|
||||
441, 37, 452, 99,
|
||||
205, 109, 217, 171,
|
||||
284, 109, 295, 171,
|
||||
363, 109, 374, 171,
|
||||
441, 109, 452, 170,
|
||||
205, 181, 217, 244,
|
||||
284, 181, 295, 243,
|
||||
362, 181, 374, 243,
|
||||
441, 181, 452, 243,
|
||||
205, 254, 217, 316,
|
||||
284, 254, 295, 316,
|
||||
362, 254, 374, 316,
|
||||
441, 254, 453, 316,
|
||||
};
|
||||
|
||||
static const int16 g_linksHorizontal2[100] = {
|
||||
135, 26, 206, 39,
|
||||
214, 27, 284, 39,
|
||||
292, 27, 362, 40,
|
||||
370, 28, 439, 41,
|
||||
447, 29, 515, 40,
|
||||
135, 98, 206, 111,
|
||||
214, 99, 284, 111,
|
||||
292, 99, 362, 111,
|
||||
370, 99, 439, 112,
|
||||
447, 100, 515, 112,
|
||||
135, 170, 206, 182,
|
||||
214, 170, 284, 182,
|
||||
293, 170, 362, 182,
|
||||
370, 170, 438, 182,
|
||||
447, 170, 514, 182,
|
||||
135, 241, 206, 255,
|
||||
214, 241, 285, 254,
|
||||
293, 241, 362, 254,
|
||||
370, 241, 438, 253,
|
||||
447, 241, 515, 253,
|
||||
135, 314, 206, 327,
|
||||
214, 314, 284, 326,
|
||||
292, 313, 362, 325,
|
||||
370, 313, 438, 325,
|
||||
447, 312, 515, 324,
|
||||
};
|
||||
|
||||
static const int16 g_linksVertical2[64] = {
|
||||
204, 37, 216, 100,
|
||||
283, 38, 294, 100,
|
||||
360, 39, 372, 100,
|
||||
437, 39, 449, 102,
|
||||
204, 109, 216, 171,
|
||||
283, 110, 294, 171,
|
||||
360, 110, 371, 171,
|
||||
437, 111, 448, 171,
|
||||
204, 181, 216, 242,
|
||||
283, 181, 294, 242,
|
||||
360, 181, 371, 242,
|
||||
436, 181, 448, 242,
|
||||
204, 253, 216, 315,
|
||||
283, 252, 294, 315,
|
||||
360, 252, 372, 314,
|
||||
436, 251, 448, 314,
|
||||
};
|
||||
|
||||
} // End of namespace CircuitPuzzleTables
|
||||
|
||||
struct CircuitPuzzleAIEvaluator {
|
||||
CircuitPuzzleAIEvaluator();
|
||||
|
||||
static const uint kMaxMovesToReach = CircuitPuzzle::kBoardWidth * CircuitPuzzle::kBoardHeight * 2;
|
||||
|
||||
uint stepsToReach[CircuitPuzzle::kBoardWidth][CircuitPuzzle::kBoardHeight];
|
||||
};
|
||||
|
||||
class CircuitPuzzleVisitedSet {
|
||||
public:
|
||||
CircuitPuzzleVisitedSet();
|
||||
|
||||
void set(const Common::Point &coord);
|
||||
bool get(const Common::Point &coord) const;
|
||||
void clear();
|
||||
|
||||
private:
|
||||
uint32 _bits;
|
||||
};
|
||||
|
||||
CircuitPuzzleVisitedSet::CircuitPuzzleVisitedSet() : _bits(0) {
|
||||
}
|
||||
|
||||
void CircuitPuzzleVisitedSet::set(const Common::Point &coord) {
|
||||
int bit = coord.y * static_cast<int>(CircuitPuzzle::kBoardWidth) + coord.x;
|
||||
_bits |= (1u << bit);
|
||||
}
|
||||
|
||||
bool CircuitPuzzleVisitedSet::get(const Common::Point &coord) const {
|
||||
int bit = coord.y * static_cast<int>(CircuitPuzzle::kBoardWidth) + coord.x;
|
||||
return (_bits & (1u << bit)) != 0;
|
||||
}
|
||||
|
||||
void CircuitPuzzleVisitedSet::clear() {
|
||||
_bits = 0;
|
||||
}
|
||||
|
||||
CircuitPuzzleAIEvaluator::CircuitPuzzleAIEvaluator() {
|
||||
for (uint x = 0; x < CircuitPuzzle::kBoardWidth; x++)
|
||||
for (uint y = 0; y < CircuitPuzzle::kBoardHeight; y++)
|
||||
stepsToReach[x][y] = kMaxMovesToReach;
|
||||
}
|
||||
|
||||
CircuitPuzzle::Action::Action() : _direction(kCellDirectionDown) {
|
||||
}
|
||||
|
||||
CircuitPuzzle::CircuitPuzzle(int layout) : _havePreviousAction(false) {
|
||||
_startPoint = Common::Point(0, 0);
|
||||
_goalPoint = Common::Point(kBoardWidth - 1, 0);
|
||||
|
||||
const int16 *linksHoriz = nullptr;
|
||||
const int16 *linksVert = nullptr;
|
||||
const int16 *barriersHoriz = nullptr;
|
||||
const int16 *barriersVert = nullptr;
|
||||
|
||||
if (layout == 1) {
|
||||
linksHoriz = CircuitPuzzleTables::g_linksHorizontal1;
|
||||
linksVert = CircuitPuzzleTables::g_linksVertical1;
|
||||
barriersHoriz = CircuitPuzzleTables::g_barriersHorizontal1;
|
||||
barriersVert = CircuitPuzzleTables::g_barriersVertical1;
|
||||
} else if (layout == 2) {
|
||||
linksHoriz = CircuitPuzzleTables::g_linksHorizontal2;
|
||||
linksVert = CircuitPuzzleTables::g_linksVertical2;
|
||||
barriersHoriz = CircuitPuzzleTables::g_barriersHorizontal2;
|
||||
barriersVert = CircuitPuzzleTables::g_barriersVertical2;
|
||||
} else
|
||||
error("Unknown circuit screen layout");
|
||||
|
||||
// Pre-connect the side rails
|
||||
for (uint i = 0; i < (kBoardHeight - 1u); i++) {
|
||||
*getConnectionState(Common::Point(0, i), KDirectionDown) = kLinkStateConnected;
|
||||
*getConnectionState(Common::Point(kBoardWidth - 1, i), KDirectionDown) = kLinkStateConnected;
|
||||
}
|
||||
|
||||
// Block edge points
|
||||
for (uint i = 0; i < kBoardWidth; i++)
|
||||
_cells[i][kBoardHeight - 1]._downLink = kLinkStateBlocked;
|
||||
for (uint i = 0; i < kBoardHeight; i++)
|
||||
_cells[kBoardWidth - 1][i]._rightLink = kLinkStateBlocked;
|
||||
|
||||
// Barriers are traced from pixel matches, but links are traced from the highlight boxes.
|
||||
// Since the highlight boxes are (1,1) larger than the clipping box of the animation, and because
|
||||
// the coordinates are inclusive, we need to add (1,1) to barrier sizes, but not link sizes, since the
|
||||
// inclusive (+1,+1) cancels out from the oversize (-1,-1) adjustment.
|
||||
|
||||
// Resolve horizontal links and barriers
|
||||
for (uint y = 0; y < kBoardHeight; y++) {
|
||||
for (uint x = 0; x < (kBoardWidth - 1u); x++) {
|
||||
uint rectDataOffset = (x + y * (kBoardWidth - 1u)) * 4u;
|
||||
|
||||
CellRectSpec &rectSpec = _cellRectSpecs[x][y];
|
||||
rectSpec._rightBarrierRect = Common::Rect(barriersHoriz[rectDataOffset + 0], barriersHoriz[rectDataOffset + 1], barriersHoriz[rectDataOffset + 2] + 1, barriersHoriz[rectDataOffset + 3] + 1);
|
||||
rectSpec._rightLinkRect = Common::Rect(linksHoriz[rectDataOffset + 0], linksHoriz[rectDataOffset + 1], linksHoriz[rectDataOffset + 2], linksHoriz[rectDataOffset + 3]);
|
||||
}
|
||||
}
|
||||
|
||||
// Resolve vertical links and barriers. Skip the first and last column.
|
||||
for (uint y = 0; y < (kBoardHeight - 1u); y++) {
|
||||
for (uint x = 1; x < (kBoardWidth - 1u); x++) {
|
||||
uint rectDataOffset = ((x - 1) + y * (kBoardWidth - 2u)) * 4u;
|
||||
|
||||
CellRectSpec &rectSpec = _cellRectSpecs[x][y];
|
||||
rectSpec._downBarrierRect = Common::Rect(barriersVert[rectDataOffset + 0], barriersVert[rectDataOffset + 1], barriersVert[rectDataOffset + 2] + 1, barriersVert[rectDataOffset + 3] + 1);
|
||||
rectSpec._downLinkRect = Common::Rect(linksVert[rectDataOffset + 0], linksVert[rectDataOffset + 1], linksVert[rectDataOffset + 2], linksVert[rectDataOffset + 3]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CircuitPuzzle::executeAIAction(Common::RandomSource &randomSource, Common::Point &outCoord, CellDirection &outBlockDirection) {
|
||||
// Don't know exactly what algorithm Schizm uses, we use something that approximates the original
|
||||
// pretty well most of the time:
|
||||
// - Identify all connection paths that are tied for the fewest number of new connections required to win.
|
||||
// - Enumerate all open connections on those paths.
|
||||
// - If the previous move blocked a horizontal connection (i.e. with a vertical barrier), prioritize
|
||||
// connections on the same X coordinate as that block.
|
||||
// - Block a random connection from the candidates.
|
||||
//
|
||||
// There seem to be times that Schizm doesn't do this. In particular, Schizm will (rarely) fail to block
|
||||
// a connection even if it's the only connection that will immediately win the puzzle for the player.
|
||||
//
|
||||
// It also doesn't prioritize making moves that will immediately win for the AI.
|
||||
CircuitPuzzleAIEvaluator evaluator;
|
||||
|
||||
computeStepsToReach(evaluator);
|
||||
|
||||
uint stepsToReachGoal = evaluator.stepsToReach[_goalPoint.x][_goalPoint.y];
|
||||
|
||||
if (stepsToReachGoal == 0 || stepsToReachGoal == CircuitPuzzleAIEvaluator::kMaxMovesToReach)
|
||||
return false;
|
||||
|
||||
const uint kMaxLinks = kBoardWidth * kBoardHeight * 2;
|
||||
|
||||
Action potentialBlocks[kMaxLinks];
|
||||
uint numPotentialBlocks = 0;
|
||||
|
||||
Common::Point pointsList1[kMaxLinks];
|
||||
Common::Point pointsList2[kMaxLinks];
|
||||
|
||||
Common::Point *pointsToFloodFill = pointsList1;
|
||||
Common::Point *pointsToProspect = pointsList2;
|
||||
|
||||
uint numPointsToFloodFill = 1;
|
||||
uint numPointsToProspect = 0;
|
||||
|
||||
pointsToFloodFill[0] = _goalPoint;
|
||||
|
||||
CircuitPuzzleVisitedSet visitedSet;
|
||||
|
||||
uint prospectLevel = stepsToReachGoal;
|
||||
|
||||
while (prospectLevel > 0) {
|
||||
floodFillLinks(pointsToFloodFill, numPointsToFloodFill, visitedSet);
|
||||
|
||||
for (uint i = 0; i < numPointsToFloodFill; i++) {
|
||||
const Common::Point &pt = pointsToFloodFill[i];
|
||||
|
||||
for (uint dir = 0; dir < kDirectionCount; dir++) {
|
||||
const LinkState *linkState = getConnectionState(pt, static_cast<Direction>(dir));
|
||||
if (linkState && (*linkState) == kLinkStateOpen) {
|
||||
Common::Point connectedPoint = getConnectedPoint(pt, static_cast<Direction>(dir));
|
||||
|
||||
if (!visitedSet.get(connectedPoint)) {
|
||||
visitedSet.set(connectedPoint);
|
||||
|
||||
if (evaluator.stepsToReach[connectedPoint.x][connectedPoint.y] + 1u == prospectLevel) {
|
||||
// This point is on the shortest path
|
||||
Action action;
|
||||
|
||||
switch (dir) {
|
||||
case kDirectionUp:
|
||||
action._point = connectedPoint;
|
||||
action._direction = kCellDirectionDown;
|
||||
break;
|
||||
case KDirectionDown:
|
||||
action._point = pt;
|
||||
action._direction = kCellDirectionDown;
|
||||
break;
|
||||
case kDirectionLeft:
|
||||
action._point = connectedPoint;
|
||||
action._direction = kCellDirectionRight;
|
||||
break;
|
||||
case kDirectionRight:
|
||||
action._point = pt;
|
||||
action._direction = kCellDirectionRight;
|
||||
break;
|
||||
default:
|
||||
error("Internal error: Bad direction");
|
||||
return false;
|
||||
}
|
||||
|
||||
potentialBlocks[numPotentialBlocks] = action;
|
||||
numPotentialBlocks++;
|
||||
|
||||
pointsToProspect[numPointsToProspect] = connectedPoint;
|
||||
numPointsToProspect++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Common::Point *tempList = pointsToFloodFill;
|
||||
pointsToFloodFill = pointsToProspect;
|
||||
pointsToProspect = tempList;
|
||||
|
||||
numPointsToFloodFill = numPointsToProspect;
|
||||
numPointsToProspect = 0;
|
||||
|
||||
prospectLevel--;
|
||||
}
|
||||
|
||||
if (numPotentialBlocks == 0)
|
||||
return false;
|
||||
|
||||
// All potential blocks are now on the shortest path.
|
||||
// Try to mimic some of the AI behavior of Schizm to form wall advances.
|
||||
// The highest-priority move is one that runs parallel to the previous move.
|
||||
uint selectedBlock = 0;
|
||||
if (numPotentialBlocks > 1) {
|
||||
uint blockQualities[kMaxLinks];
|
||||
for (uint i = 0; i < numPotentialBlocks; i++)
|
||||
blockQualities[i] = 0;
|
||||
|
||||
uint highestQuality = 0;
|
||||
if (_havePreviousAction) {
|
||||
for (uint i = 0; i < numPotentialBlocks; i++) {
|
||||
uint quality = 0;
|
||||
|
||||
const Action &pblock = potentialBlocks[i];
|
||||
|
||||
// We don't want to favor horizontal walls because otherwise that triggers are degenerate behavior where the player can run a wall
|
||||
// directly across and the AI will keeps inserting horizontal walls parallel to the player action.
|
||||
bool isWallBlock = false;
|
||||
if (_previousAction._direction == kCellDirectionRight && pblock._direction == kCellDirectionRight && _previousAction._point.x == pblock._point.x)
|
||||
isWallBlock = true;
|
||||
#if 0
|
||||
else if (_previousAction._direction == kCellDirectionDown && pblock._direction == kCellDirectionDown && _previousAction._point.y == pblock._point.y)
|
||||
isWallBlock = true;
|
||||
#endif
|
||||
|
||||
// If this forms a vertical wall, it's quality 2
|
||||
if (isWallBlock)
|
||||
quality = 2;
|
||||
else {
|
||||
// If this forms a corner, it's quality 1 (disabled, this seems less accurate)
|
||||
#if 0
|
||||
if (_previousAction._direction != pblock._direction) {
|
||||
Common::Point prevAdjacent = _previousAction._point;
|
||||
if (_previousAction._direction == kCellDirectionRight)
|
||||
prevAdjacent.x++;
|
||||
else if (_previousAction._direction == kCellDirectionDown)
|
||||
prevAdjacent.y++;
|
||||
|
||||
Common::Point pblockAdjacent = pblock._point;
|
||||
if (pblock._direction == kCellDirectionRight)
|
||||
pblockAdjacent.x++;
|
||||
else if (pblock._direction == kCellDirectionDown)
|
||||
pblockAdjacent.y++;
|
||||
|
||||
if (prevAdjacent == pblock._point || prevAdjacent == pblockAdjacent || _previousAction._point == pblock._point || _previousAction._point == pblockAdjacent)
|
||||
quality = 1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
blockQualities[i] = quality;
|
||||
if (quality > highestQuality)
|
||||
highestQuality = quality;
|
||||
}
|
||||
}
|
||||
|
||||
uint blocksInHighestQuality[kMaxLinks];
|
||||
uint numBlocksInHighestQuality = 0;
|
||||
|
||||
for (uint i = 0; i < numPotentialBlocks; i++) {
|
||||
if (blockQualities[i] == highestQuality) {
|
||||
blocksInHighestQuality[numBlocksInHighestQuality] = i;
|
||||
numBlocksInHighestQuality++;
|
||||
}
|
||||
}
|
||||
|
||||
if (numBlocksInHighestQuality == 1)
|
||||
selectedBlock = blocksInHighestQuality[0];
|
||||
else {
|
||||
assert(numBlocksInHighestQuality > 1);
|
||||
selectedBlock = blocksInHighestQuality[randomSource.getRandomNumber(numBlocksInHighestQuality - 1)];
|
||||
}
|
||||
}
|
||||
|
||||
const Action &pblock = potentialBlocks[selectedBlock];
|
||||
|
||||
outCoord = pblock._point;
|
||||
outBlockDirection = pblock._direction;
|
||||
|
||||
if (pblock._direction == kCellDirectionDown)
|
||||
_cells[pblock._point.x][pblock._point.y]._downLink = kLinkStateBlocked;
|
||||
if (pblock._direction == kCellDirectionRight)
|
||||
_cells[pblock._point.x][pblock._point.y]._rightLink = kLinkStateBlocked;
|
||||
|
||||
_havePreviousAction = true;
|
||||
_previousAction = pblock;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CircuitPuzzle::addLink(const Common::Point &coord, CellDirection direction) {
|
||||
validateCoord(coord);
|
||||
|
||||
CellState &cell = _cells[coord.x][coord.y];
|
||||
|
||||
LinkState *linkState = nullptr;
|
||||
if (direction == kCellDirectionDown)
|
||||
linkState = &cell._downLink;
|
||||
else if (direction == kCellDirectionRight)
|
||||
linkState = &cell._rightLink;
|
||||
|
||||
if (linkState == nullptr || (*linkState) != kLinkStateOpen)
|
||||
error("Internal error: Circuit link state was invalid");
|
||||
|
||||
*linkState = kLinkStateConnected;
|
||||
}
|
||||
|
||||
CircuitPuzzle::Conclusion CircuitPuzzle::checkConclusion() const {
|
||||
CircuitPuzzleAIEvaluator evaluator;
|
||||
|
||||
computeStepsToReach(evaluator);
|
||||
|
||||
uint stepsToReachGoal = evaluator.stepsToReach[_goalPoint.x][_goalPoint.y];
|
||||
|
||||
if (stepsToReachGoal == 0)
|
||||
return kConclusionPlayerWon;
|
||||
|
||||
if (stepsToReachGoal == CircuitPuzzleAIEvaluator::kMaxMovesToReach)
|
||||
return kConclusionPlayerLost;
|
||||
|
||||
return kConclusionNone;
|
||||
}
|
||||
|
||||
const CircuitPuzzle::CellRectSpec *CircuitPuzzle::getCellRectSpec(const Common::Point &coord) const {
|
||||
validateCoord(coord);
|
||||
|
||||
return &_cellRectSpecs[coord.x][coord.y];
|
||||
}
|
||||
|
||||
bool CircuitPuzzle::isCellDownLinkOpen(const Common::Point &coord) const {
|
||||
validateCoord(coord);
|
||||
|
||||
return _cells[coord.x][coord.y]._downLink == kLinkStateOpen;
|
||||
}
|
||||
|
||||
bool CircuitPuzzle::isCellRightLinkOpen(const Common::Point &coord) const {
|
||||
validateCoord(coord);
|
||||
|
||||
return _cells[coord.x][coord.y]._rightLink == kLinkStateOpen;
|
||||
}
|
||||
|
||||
CircuitPuzzle::CellState::CellState() : _downLink(kLinkStateOpen), _rightLink(kLinkStateOpen) {
|
||||
}
|
||||
|
||||
Common::Point CircuitPuzzle::getConnectedPoint(const Common::Point &coord, Direction direction) {
|
||||
switch (direction) {
|
||||
case kDirectionUp:
|
||||
return Common::Point(coord.x, coord.y - 1);
|
||||
case KDirectionDown:
|
||||
return Common::Point(coord.x, coord.y + 1);
|
||||
case kDirectionLeft:
|
||||
return Common::Point(coord.x - 1, coord.y);
|
||||
case kDirectionRight:
|
||||
return Common::Point(coord.x + 1, coord.y);
|
||||
default:
|
||||
return coord;
|
||||
};
|
||||
}
|
||||
|
||||
CircuitPuzzle::LinkState *CircuitPuzzle::getConnectionState(const Common::Point &coord, Direction direction) {
|
||||
if (!isPositionValid(coord))
|
||||
return nullptr;
|
||||
|
||||
switch (direction) {
|
||||
case kDirectionUp:
|
||||
if (coord.y == 0)
|
||||
return nullptr;
|
||||
return &_cells[coord.x][coord.y - 1]._downLink;
|
||||
case KDirectionDown:
|
||||
if (coord.y == static_cast<int>(kBoardHeight - 1))
|
||||
return nullptr;
|
||||
|
||||
return &_cells[coord.x][coord.y]._downLink;
|
||||
case kDirectionLeft:
|
||||
if (coord.x <= 0)
|
||||
return nullptr;
|
||||
return &_cells[coord.x - 1][coord.y]._rightLink;
|
||||
case kDirectionRight:
|
||||
if (coord.x == static_cast<int>(kBoardWidth - 1))
|
||||
return nullptr;
|
||||
|
||||
return &_cells[coord.x][coord.y]._rightLink;
|
||||
default:
|
||||
return nullptr;
|
||||
};
|
||||
}
|
||||
|
||||
const CircuitPuzzle::LinkState *CircuitPuzzle::getConnectionState(const Common::Point &coord, Direction direction) const {
|
||||
return const_cast<CircuitPuzzle *>(this)->getConnectionState(coord, direction);
|
||||
}
|
||||
|
||||
bool CircuitPuzzle::isPositionValid(const Common::Point &coord) {
|
||||
if (coord.x < 0 || coord.y < 0 || coord.x >= static_cast<int>(kBoardWidth) || coord.y >= static_cast<int>(kBoardHeight))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CircuitPuzzle::computeStepsToReach(CircuitPuzzleAIEvaluator &evaluator) const {
|
||||
const uint kMaxLinks = kBoardWidth * kBoardHeight * 2;
|
||||
|
||||
Common::Point pointsList1[kMaxLinks];
|
||||
Common::Point pointsList2[kMaxLinks];
|
||||
|
||||
Common::Point *pointsToFloodFill = pointsList1;
|
||||
Common::Point *pointsToProspect = pointsList2;
|
||||
|
||||
uint numPointsToFloodFill = 1;
|
||||
uint numPointsToProspect = 0;
|
||||
|
||||
uint floodFillValue = 0;
|
||||
pointsToFloodFill[0] = _startPoint;
|
||||
|
||||
for (uint x = 0; x < kBoardWidth; x++)
|
||||
for (uint y = 0; y < kBoardHeight; y++)
|
||||
evaluator.stepsToReach[x][y] = CircuitPuzzleAIEvaluator::kMaxMovesToReach;
|
||||
|
||||
CircuitPuzzleVisitedSet visitedSet;
|
||||
while (numPointsToFloodFill > 0) {
|
||||
floodFillLinks(pointsToFloodFill, numPointsToFloodFill, visitedSet);
|
||||
|
||||
for (uint i = 0; i < numPointsToFloodFill; i++) {
|
||||
const Common::Point &pt = pointsToFloodFill[i];
|
||||
|
||||
evaluator.stepsToReach[pt.x][pt.y] = floodFillValue;
|
||||
|
||||
for (uint dir = 0; dir < kDirectionCount; dir++) {
|
||||
const LinkState *linkState = getConnectionState(pt, static_cast<Direction>(dir));
|
||||
if (linkState && (*linkState) == kLinkStateOpen) {
|
||||
Common::Point connectedPoint = getConnectedPoint(pt, static_cast<Direction>(dir));
|
||||
|
||||
if (!visitedSet.get(connectedPoint)) {
|
||||
visitedSet.set(connectedPoint);
|
||||
|
||||
pointsToProspect[numPointsToProspect] = connectedPoint;
|
||||
numPointsToProspect++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Common::Point *tempList = pointsToFloodFill;
|
||||
pointsToFloodFill = pointsToProspect;
|
||||
pointsToProspect = tempList;
|
||||
|
||||
numPointsToFloodFill = numPointsToProspect;
|
||||
numPointsToProspect = 0;
|
||||
|
||||
floodFillValue++;
|
||||
}
|
||||
}
|
||||
|
||||
void CircuitPuzzle::floodFillLinks(Common::Point *pointsList, uint &listSize, CircuitPuzzleVisitedSet &visitedSet) const {
|
||||
for (uint i = 0; i < listSize; i++) {
|
||||
const Common::Point &pt = pointsList[i];
|
||||
|
||||
visitedSet.set(pt);
|
||||
for (uint dir = 0; dir < kDirectionCount; dir++) {
|
||||
const LinkState *linkState = getConnectionState(pt, static_cast<Direction>(dir));
|
||||
if (linkState && (*linkState) == kLinkStateConnected) {
|
||||
Common::Point connectedPoint = getConnectedPoint(pt, static_cast<Direction>(dir));
|
||||
|
||||
if (!visitedSet.get(connectedPoint)) {
|
||||
pointsList[listSize] = connectedPoint;
|
||||
listSize++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CircuitPuzzle::validateCoord(const Common::Point &coord) {
|
||||
assert(coord.x >= 0 && coord.y >= 0 && coord.x < static_cast<int>(kBoardWidth) && coord.y < static_cast<int>(kBoardHeight));
|
||||
}
|
||||
|
||||
|
||||
} // End of namespace VCruise
|
||||
127
engines/vcruise/circuitpuzzle.h
Normal file
127
engines/vcruise/circuitpuzzle.h
Normal file
@@ -0,0 +1,127 @@
|
||||
/* 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 VCRUISE_CIRCUITPUZZLE_H
|
||||
#define VCRUISE_CIRCUITPUZZLE_H
|
||||
|
||||
#include "common/array.h"
|
||||
#include "common/random.h"
|
||||
#include "common/rect.h"
|
||||
|
||||
namespace Common {
|
||||
|
||||
class RandomSource;
|
||||
|
||||
} // End of namespace Common
|
||||
|
||||
namespace VCruise {
|
||||
|
||||
struct CircuitPuzzleAIEvaluator;
|
||||
class CircuitPuzzleVisitedSet;
|
||||
|
||||
class CircuitPuzzle {
|
||||
public:
|
||||
explicit CircuitPuzzle(int layout);
|
||||
|
||||
static const uint kBoardWidth = 6;
|
||||
static const uint kBoardHeight = 5;
|
||||
|
||||
enum CellDirection {
|
||||
kCellDirectionRight,
|
||||
kCellDirectionDown,
|
||||
};
|
||||
|
||||
enum Conclusion {
|
||||
kConclusionNone,
|
||||
kConclusionPlayerWon,
|
||||
kConclusionPlayerLost,
|
||||
};
|
||||
|
||||
struct CellRectSpec {
|
||||
Common::Rect _rightLinkRect;
|
||||
Common::Rect _downLinkRect;
|
||||
Common::Rect _rightBarrierRect;
|
||||
Common::Rect _downBarrierRect;
|
||||
};
|
||||
|
||||
// Returns true if the AI can act, if it can then the actions are produced
|
||||
bool executeAIAction(Common::RandomSource &randomSource, Common::Point &outCoord, CellDirection &outBlockDirection);
|
||||
|
||||
void addLink(const Common::Point &coord, CellDirection direction);
|
||||
|
||||
Conclusion checkConclusion() const;
|
||||
|
||||
const CellRectSpec *getCellRectSpec(const Common::Point &coord) const;
|
||||
bool isCellDownLinkOpen(const Common::Point &coord) const;
|
||||
bool isCellRightLinkOpen(const Common::Point &coord) const;
|
||||
|
||||
private:
|
||||
enum LinkState {
|
||||
kLinkStateOpen,
|
||||
kLinkStateConnected,
|
||||
kLinkStateBlocked,
|
||||
};
|
||||
|
||||
enum Direction {
|
||||
kDirectionUp,
|
||||
KDirectionDown,
|
||||
kDirectionLeft,
|
||||
kDirectionRight,
|
||||
|
||||
kDirectionCount,
|
||||
};
|
||||
|
||||
struct CellState {
|
||||
CellState();
|
||||
|
||||
LinkState _downLink;
|
||||
LinkState _rightLink;
|
||||
};
|
||||
|
||||
struct Action {
|
||||
Action();
|
||||
|
||||
Common::Point _point;
|
||||
CellDirection _direction;
|
||||
};
|
||||
|
||||
static Common::Point getConnectedPoint(const Common::Point &coord, Direction direction);
|
||||
LinkState *getConnectionState(const Common::Point &coord, Direction direction);
|
||||
const LinkState *getConnectionState(const Common::Point &coord, Direction direction) const;
|
||||
static bool isPositionValid(const Common::Point &coord);
|
||||
|
||||
void computeStepsToReach(CircuitPuzzleAIEvaluator &evaluator) const;
|
||||
void floodFillLinks(Common::Point *pointsList, uint &listSize, CircuitPuzzleVisitedSet &visitedSet) const;
|
||||
|
||||
static void validateCoord(const Common::Point &coord);
|
||||
|
||||
CellState _cells[kBoardWidth][kBoardHeight];
|
||||
CellRectSpec _cellRectSpecs[kBoardWidth][kBoardHeight];
|
||||
Common::Point _startPoint;
|
||||
Common::Point _goalPoint;
|
||||
|
||||
bool _havePreviousAction;
|
||||
Action _previousAction;
|
||||
};
|
||||
|
||||
} // End of namespace VCruise
|
||||
|
||||
#endif
|
||||
3
engines/vcruise/configure.engine
Normal file
3
engines/vcruise/configure.engine
Normal 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 vcruise "V-Cruise" yes "" "" "16bit highres" "midi"
|
||||
3
engines/vcruise/credits.pl
Normal file
3
engines/vcruise/credits.pl
Normal file
@@ -0,0 +1,3 @@
|
||||
begin_section("V-Cruise");
|
||||
add_person("Eric Lasota", "OneEightHundred", "");
|
||||
end_section();
|
||||
123
engines/vcruise/detection.cpp
Normal file
123
engines/vcruise/detection.cpp
Normal file
@@ -0,0 +1,123 @@
|
||||
/* 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/config-manager.h"
|
||||
#include "common/language.h"
|
||||
|
||||
#include "engines/advancedDetector.h"
|
||||
|
||||
#include "vcruise/detection.h"
|
||||
|
||||
static const PlainGameDescriptor g_vcruiseGames[] = {
|
||||
{"ad2044", "A.D. 2044"},
|
||||
{"reah", "Reah: Face the Unknown"},
|
||||
{"schizm", "Schizm: Mysterious Journey"},
|
||||
{nullptr, nullptr}
|
||||
};
|
||||
|
||||
static const char *const g_vcruiseDirectoryGlobs[] = {
|
||||
"Sfx",
|
||||
"Log",
|
||||
"Waves-12",
|
||||
"Waves-22",
|
||||
"WAVE-01",
|
||||
nullptr
|
||||
};
|
||||
|
||||
#include "vcruise/detection_tables.h"
|
||||
|
||||
class VCruiseMetaEngineDetection : public AdvancedMetaEngineDetection<VCruise::VCruiseGameDescription> {
|
||||
public:
|
||||
VCruiseMetaEngineDetection() : AdvancedMetaEngineDetection(VCruise::gameDescriptions, g_vcruiseGames) {
|
||||
_guiOptions = GUIO5(GAMEOPTION_FAST_ANIMATIONS, GAMEOPTION_INCREASE_DRAG_DISTANCE, GAMEOPTION_LAUNCH_DEBUG, GAMEOPTION_SKIP_MENU, GAMEOPTION_PRELOAD_SOUNDS);
|
||||
_maxScanDepth = 3;
|
||||
_directoryGlobs = g_vcruiseDirectoryGlobs;
|
||||
_flags = kADFlagCanPlayUnknownVariants;
|
||||
}
|
||||
|
||||
const char *getName() const override {
|
||||
return "vcruise";
|
||||
}
|
||||
|
||||
const char *getEngineName() const override {
|
||||
return "V-Cruise";
|
||||
}
|
||||
|
||||
const char *getOriginalCopyright() const override {
|
||||
return "V-Cruise (C) LK Avalon";
|
||||
}
|
||||
|
||||
DetectedGame toDetectedGame(const ADDetectedGame &adGame, ADDetectedGameExtraInfo *extraInfo) const override {
|
||||
DetectedGame game = AdvancedMetaEngineDetection::toDetectedGame(adGame, extraInfo);
|
||||
|
||||
VCruise::VCruiseGameID gameID = reinterpret_cast<const VCruise::VCruiseGameDescription *>(adGame.desc)->gameID;
|
||||
|
||||
if ((adGame.desc->flags & VCruise::VCRUISE_GF_FORCE_LANGUAGE) == 0) {
|
||||
if (gameID == VCruise::GID_AD2044) {
|
||||
game.appendGUIOptions(Common::getGameGUIOptionsDescriptionLanguage(Common::EN_ANY));
|
||||
game.appendGUIOptions(Common::getGameGUIOptionsDescriptionLanguage(Common::PL_POL));
|
||||
} else if (gameID == VCruise::GID_REAH) {
|
||||
game.appendGUIOptions(Common::getGameGUIOptionsDescriptionLanguage(Common::EN_ANY));
|
||||
game.appendGUIOptions(Common::getGameGUIOptionsDescriptionLanguage(Common::NL_NLD));
|
||||
game.appendGUIOptions(Common::getGameGUIOptionsDescriptionLanguage(Common::FR_FRA));
|
||||
game.appendGUIOptions(Common::getGameGUIOptionsDescriptionLanguage(Common::IT_ITA));
|
||||
game.appendGUIOptions(Common::getGameGUIOptionsDescriptionLanguage(Common::DE_DEU));
|
||||
game.appendGUIOptions(Common::getGameGUIOptionsDescriptionLanguage(Common::PL_POL));
|
||||
game.appendGUIOptions(Common::getGameGUIOptionsDescriptionLanguage(Common::ES_ESP));
|
||||
} else if (gameID == VCruise::GID_SCHIZM) {
|
||||
game.appendGUIOptions(Common::getGameGUIOptionsDescriptionLanguage(Common::EN_USA));
|
||||
game.appendGUIOptions(Common::getGameGUIOptionsDescriptionLanguage(Common::EN_GRB));
|
||||
game.appendGUIOptions(Common::getGameGUIOptionsDescriptionLanguage(Common::NL_NLD));
|
||||
game.appendGUIOptions(Common::getGameGUIOptionsDescriptionLanguage(Common::FR_FRA));
|
||||
game.appendGUIOptions(Common::getGameGUIOptionsDescriptionLanguage(Common::IT_ITA));
|
||||
game.appendGUIOptions(Common::getGameGUIOptionsDescriptionLanguage(Common::DE_DEU));
|
||||
game.appendGUIOptions(Common::getGameGUIOptionsDescriptionLanguage(Common::PL_POL));
|
||||
game.appendGUIOptions(Common::getGameGUIOptionsDescriptionLanguage(Common::ES_ESP));
|
||||
game.appendGUIOptions(Common::getGameGUIOptionsDescriptionLanguage(Common::EL_GRC));
|
||||
game.appendGUIOptions(Common::getGameGUIOptionsDescriptionLanguage(Common::RU_RUS));
|
||||
|
||||
if (adGame.desc->flags & VCruise::VCRUISE_GF_BUL_LANGUAGE)
|
||||
game.appendGUIOptions(Common::getGameGUIOptionsDescriptionLanguage(Common::BG_BUL));
|
||||
|
||||
if (adGame.desc->flags & VCruise::VCRUISE_GF_TWN_LANGUAGE)
|
||||
game.appendGUIOptions(Common::getGameGUIOptionsDescriptionLanguage(Common::ZH_TWN));
|
||||
|
||||
if (adGame.desc->flags & VCruise::VCRUISE_GF_JPN_LANGUAGE)
|
||||
game.appendGUIOptions(Common::getGameGUIOptionsDescriptionLanguage(Common::JA_JPN));
|
||||
|
||||
if (adGame.desc->flags & VCruise::VCRUISE_GF_HUN_LANGUAGE)
|
||||
game.appendGUIOptions(Common::getGameGUIOptionsDescriptionLanguage(Common::HU_HUN));
|
||||
|
||||
if (adGame.desc->flags & VCruise::VCRUISE_GF_CHN_LANGUAGE)
|
||||
game.appendGUIOptions(Common::getGameGUIOptionsDescriptionLanguage(Common::ZH_CHN));
|
||||
|
||||
if (adGame.desc->flags & VCruise::VCRUISE_GF_CZE_LANGUAGE)
|
||||
game.appendGUIOptions(Common::getGameGUIOptionsDescriptionLanguage(Common::CS_CZE));
|
||||
}
|
||||
}
|
||||
|
||||
return game;
|
||||
}
|
||||
};
|
||||
|
||||
REGISTER_PLUGIN_STATIC(VCRUISE_DETECTION, PLUGIN_TYPE_ENGINE_DETECTION, VCruiseMetaEngineDetection);
|
||||
83
engines/vcruise/detection.h
Normal file
83
engines/vcruise/detection.h
Normal file
@@ -0,0 +1,83 @@
|
||||
/* 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 VCRUISE_DETECTION_H
|
||||
#define VCRUISE_DETECTION_H
|
||||
|
||||
#include "engines/advancedDetector.h"
|
||||
|
||||
namespace VCruise {
|
||||
|
||||
enum VCruiseGameID {
|
||||
GID_UNKNOWN = 0,
|
||||
|
||||
GID_REAH = 1,
|
||||
GID_SCHIZM = 2,
|
||||
GID_AD2044 = 3,
|
||||
};
|
||||
|
||||
enum VCruiseGameFlag {
|
||||
VCRUISE_GF_WANT_MP3 = (1 << 0),
|
||||
VCRUISE_GF_WANT_OGG_VORBIS = (1 << 1),
|
||||
VCRUISE_GF_NEED_JPEG = (1 << 2),
|
||||
VCRUISE_GF_GENTEE_PACKAGE = (1 << 3),
|
||||
VCRUISE_GF_USE_SETUP_EXE = (1 << 4),
|
||||
|
||||
VCRUISE_GF_BUL_LANGUAGE = (1 << 6),
|
||||
VCRUISE_GF_TWN_LANGUAGE = (1 << 7),
|
||||
VCRUISE_GF_JPN_LANGUAGE = (1 << 8),
|
||||
VCRUISE_GF_HUN_LANGUAGE = (1 << 9),
|
||||
VCRUISE_GF_CHN_LANGUAGE = (1 << 10),
|
||||
VCRUISE_GF_CZE_LANGUAGE = (1 << 11),
|
||||
|
||||
VCRUISE_GF_FORCE_LANGUAGE = (1 << 12),
|
||||
|
||||
VCRUISE_GF_WANT_MIDI = (1 << 13),
|
||||
|
||||
VCRUISE_GF_STEAM_LANGUAGES = VCRUISE_GF_BUL_LANGUAGE | VCRUISE_GF_TWN_LANGUAGE | VCRUISE_GF_JPN_LANGUAGE
|
||||
| VCRUISE_GF_HUN_LANGUAGE | VCRUISE_GF_CHN_LANGUAGE | VCRUISE_GF_CZE_LANGUAGE,
|
||||
};
|
||||
|
||||
struct VCruiseGameDescription {
|
||||
AD_GAME_DESCRIPTION_HELPERS(desc);
|
||||
|
||||
ADGameDescription desc;
|
||||
|
||||
VCruiseGameID gameID;
|
||||
|
||||
// Specifying the language in the ADGameDescription causes AD to fail to detect the game as a match,
|
||||
// so we have to specify it as UNK_LANG and specify the default language here.
|
||||
Common::Language defaultLanguage;
|
||||
};
|
||||
|
||||
|
||||
#define GAMEOPTION_LAUNCH_DEBUG GUIO_GAMEOPTIONS1
|
||||
#define GAMEOPTION_FAST_ANIMATIONS GUIO_GAMEOPTIONS2
|
||||
#define GAMEOPTION_SKIP_MENU GUIO_GAMEOPTIONS3
|
||||
#define GAMEOPTION_INCREASE_DRAG_DISTANCE GUIO_GAMEOPTIONS4
|
||||
#define GAMEOPTION_USE_4BIT_GRAPHICS GUIO_GAMEOPTIONS5
|
||||
#define GAMEOPTION_PRELOAD_SOUNDS GUIO_GAMEOPTIONS6
|
||||
#define GAMEOPTION_FAST_VIDEO_DECODER GUIO_GAMEOPTIONS7
|
||||
|
||||
|
||||
} // End of namespace VCruise
|
||||
|
||||
#endif // VCRUISE_DETECTION_H
|
||||
539
engines/vcruise/detection_tables.h
Normal file
539
engines/vcruise/detection_tables.h
Normal file
@@ -0,0 +1,539 @@
|
||||
/* 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 VCRUISE_DETECTION_TABLES_H
|
||||
#define VCRUISE_DETECTION_TABLES_H
|
||||
|
||||
#include "engines/advancedDetector.h"
|
||||
|
||||
#include "vcruise/detection.h"
|
||||
|
||||
namespace VCruise {
|
||||
|
||||
static const VCruiseGameDescription gameDescriptions[] = {
|
||||
{ // A.D. 2044, GOG English digital version
|
||||
{
|
||||
"ad2044",
|
||||
"English Digital",
|
||||
AD_ENTRY2s("ad2044.exe", "0ab1e3f8b3a17a5b18bb5ee356face25", 327168,
|
||||
"00010001.wav", "d385bb2f1b10ea8c13bbb2948794c9f6", 74950),
|
||||
Common::UNK_LANG,
|
||||
Common::kPlatformWindows,
|
||||
VCRUISE_GF_WANT_MP3 | ADGF_UNSTABLE,
|
||||
GUIO0()
|
||||
},
|
||||
GID_AD2044,
|
||||
Common::EN_ANY,
|
||||
},
|
||||
{ // Reah: Face the Unknown, English DVD version
|
||||
{
|
||||
"reah",
|
||||
"English DVD",
|
||||
AD_ENTRY2s("Reah.exe", "69aa9832338db3f40f616386e54857e8", 304128,
|
||||
"0170_b.wav", "5b705300b4fee3ceb821a1b55884a722", 129248),
|
||||
Common::UNK_LANG,
|
||||
Common::kPlatformWindows,
|
||||
VCRUISE_GF_WANT_MP3,
|
||||
GUIO0()
|
||||
},
|
||||
GID_REAH,
|
||||
Common::EN_ANY,
|
||||
},
|
||||
{ // Reah: Face the Unknown, English digital (GOG) version
|
||||
{
|
||||
"reah",
|
||||
"English Digital",
|
||||
AD_ENTRY2s("Reah.exe", "60ec19c53f1323cc7f0314f98d396283", 304128,
|
||||
"0170_b.wav", "5b705300b4fee3ceb821a1b55884a722", 129248),
|
||||
Common::UNK_LANG,
|
||||
Common::kPlatformWindows,
|
||||
VCRUISE_GF_WANT_MP3,
|
||||
GUIO0()
|
||||
},
|
||||
GID_REAH,
|
||||
Common::EN_ANY,
|
||||
},
|
||||
{ // Reah: Face the Unknown, English 6 CD Version
|
||||
{
|
||||
"reah",
|
||||
"English CD",
|
||||
AD_ENTRY2s("Reah.exe", "77bc7f7819cdd443f52b193529138c87", 305664,
|
||||
"0170_b.wav", "5b705300b4fee3ceb821a1b55884a722", 129248),
|
||||
Common::UNK_LANG,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO0()
|
||||
},
|
||||
GID_REAH,
|
||||
Common::EN_ANY,
|
||||
},
|
||||
{ // Reah: Face the Unknown, English 6 CD Version (Project Two Interactive variation)
|
||||
{
|
||||
"reah",
|
||||
"English CD",
|
||||
AD_ENTRY2s("Reah.exe", "77bc7f7819cdd443f52b193529138c87", 305664,
|
||||
"0170_b.wav", "36c0bf57ab5a748ef6699a159195b3ae", 124356),
|
||||
Common::UNK_LANG,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO0()
|
||||
},
|
||||
GID_REAH,
|
||||
Common::EN_ANY,
|
||||
},
|
||||
{ // Reah: Face the Unknown, German 6 CD Version
|
||||
{
|
||||
"reah",
|
||||
"German CD",
|
||||
AD_ENTRY2s("Reah.exe", "be29f9f9fc9a454488f9d2fb68e26326", 305664,
|
||||
"0170_b.wav", "5f84af02d1193ce9c47fe0dc821f0613", 121220),
|
||||
Common::UNK_LANG,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO0()
|
||||
},
|
||||
GID_REAH,
|
||||
Common::DE_DEU,
|
||||
},
|
||||
{ // Reah: Face the Unknown, Russian 6 CD Version
|
||||
{
|
||||
"reah",
|
||||
"Russian CD",
|
||||
AD_ENTRY3s("Reah.exe", "c44224a888035c14e876cbc45519faca", 305664,
|
||||
"0170_b.wav", "4632023ed0bab3fc800abfa5ef65ceaf", 119850,
|
||||
"Speech01.txt", "734478c94944eab9c954c612c70efb9a", 72694),
|
||||
Common::RU_RUS,
|
||||
Common::kPlatformWindows,
|
||||
VCRUISE_GF_FORCE_LANGUAGE,
|
||||
GUIO0()
|
||||
},
|
||||
GID_REAH,
|
||||
Common::RU_RUS,
|
||||
},
|
||||
{ // Reah: Face the Unknown, English digital (GOG) version + German VO community patch
|
||||
{
|
||||
"reah",
|
||||
"English Digital + German Community Patch",
|
||||
AD_ENTRY2s("Reah.exe", "60ec19c53f1323cc7f0314f98d396283", 304128,
|
||||
"0170_b.wav", "5f84af02d1193ce9c47fe0dc821f0613", 121220),
|
||||
Common::UNK_LANG,
|
||||
Common::kPlatformWindows,
|
||||
VCRUISE_GF_WANT_MP3,
|
||||
GUIO0()
|
||||
},
|
||||
GID_REAH,
|
||||
Common::EN_ANY,
|
||||
},
|
||||
{ // Reah: Face the Unknown, English digital (GOG) version + Russian VO/subtitles community patch
|
||||
{
|
||||
"reah",
|
||||
"English Digital + Russian Community Patch",
|
||||
AD_ENTRY3s("Reah.exe", "60ec19c53f1323cc7f0314f98d396283", 304128,
|
||||
"0170_b.wav", "4632023ed0bab3fc800abfa5ef65ceaf", 119850,
|
||||
"Speech01.txt", "a4eaace1299de1d70805532fc0643a77", 72689),
|
||||
Common::RU_RUS,
|
||||
Common::kPlatformWindows,
|
||||
VCRUISE_GF_WANT_MP3 | VCRUISE_GF_FORCE_LANGUAGE,
|
||||
GUIO0()
|
||||
},
|
||||
GID_REAH,
|
||||
Common::RU_RUS,
|
||||
},
|
||||
{ // Reah: Face the Unknown, Polish demo
|
||||
{
|
||||
"reah",
|
||||
"Polish Demo",
|
||||
AD_ENTRY1s("Reah.exe", "4667d7e3d886f01ec28040a9022b1b56", 281600),
|
||||
Common::UNK_LANG,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO0()
|
||||
},
|
||||
GID_REAH,
|
||||
Common::PL_POL,
|
||||
},
|
||||
|
||||
{ // Schizm: Mysterious Journey, English CD Version
|
||||
{
|
||||
"schizm",
|
||||
"English CD",
|
||||
AD_ENTRY2s("Schizm.exe", "24bb1831a53b3969d9d1a9302740de4a", 368640,
|
||||
"0001_a.wav", "374d93abc3422840623acc618ecb2b1e", 1553784),
|
||||
Common::UNK_LANG,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_CD | VCRUISE_GF_WANT_OGG_VORBIS | VCRUISE_GF_NEED_JPEG,
|
||||
GUIO1(GAMEOPTION_FAST_VIDEO_DECODER)
|
||||
},
|
||||
GID_SCHIZM,
|
||||
Common::EN_GRB,
|
||||
},
|
||||
{ // Schizm: Mysterious Journey, German DVD Version (installed)
|
||||
{
|
||||
"schizm",
|
||||
"German DVD",
|
||||
AD_ENTRY2s("Schizm.exe", "3d63307697c72f3fd6cafb378f61ca2b", 364544,
|
||||
"0001_a.wav", "f2b7eccfb1e9af0282b541c5eac66cc7", 1613240),
|
||||
Common::UNK_LANG,
|
||||
Common::kPlatformWindows,
|
||||
VCRUISE_GF_WANT_OGG_VORBIS | VCRUISE_GF_NEED_JPEG,
|
||||
GUIO1(GAMEOPTION_FAST_VIDEO_DECODER)
|
||||
},
|
||||
GID_SCHIZM,
|
||||
Common::DE_DEU,
|
||||
},
|
||||
|
||||
|
||||
{ // Schizm: Mysterious Journey, English DVD Version (NL release)
|
||||
{
|
||||
"schizm",
|
||||
"English DVD",
|
||||
AD_ENTRY1s("disk1.pak", "41bd7514a7d783c555f3783c9417bf9e", 272405273),
|
||||
Common::UNK_LANG,
|
||||
Common::kPlatformWindows,
|
||||
VCRUISE_GF_WANT_OGG_VORBIS | VCRUISE_GF_NEED_JPEG | VCRUISE_GF_GENTEE_PACKAGE,
|
||||
GUIO1(GAMEOPTION_FAST_VIDEO_DECODER)
|
||||
},
|
||||
GID_SCHIZM,
|
||||
Common::EN_GRB,
|
||||
},
|
||||
{ // Schizm: Mysterious Journey, English DVD Version, 11-language
|
||||
{
|
||||
"schizm",
|
||||
"English DVD",
|
||||
AD_ENTRY2s("setup.pak", "eaaed2f6655342b4c320bdeb6f5ccfb9", 272655597,
|
||||
"setup.exe", "62f2ed1b1a6a4ed3e3298c7d6852a495", 63234),
|
||||
Common::UNK_LANG,
|
||||
Common::kPlatformWindows,
|
||||
VCRUISE_GF_WANT_OGG_VORBIS | VCRUISE_GF_NEED_JPEG | VCRUISE_GF_GENTEE_PACKAGE | VCRUISE_GF_BUL_LANGUAGE,
|
||||
GUIO1(GAMEOPTION_FAST_VIDEO_DECODER)
|
||||
},
|
||||
GID_SCHIZM,
|
||||
Common::EN_GRB,
|
||||
},
|
||||
{ // Schizm: Mysterious Journey, Japanese DVD Version, 12-language
|
||||
{
|
||||
"schizm",
|
||||
"Japanese DVD",
|
||||
AD_ENTRY2s("setup.pak", "eaaed2f6655342b4c320bdeb6f5ccfb9", 272655597,
|
||||
"setup.exe", "62f2ed1b1a6a4ed3e3298c7d6852a495", 66646),
|
||||
Common::UNK_LANG,
|
||||
Common::kPlatformWindows,
|
||||
VCRUISE_GF_WANT_OGG_VORBIS | VCRUISE_GF_NEED_JPEG | VCRUISE_GF_GENTEE_PACKAGE | VCRUISE_GF_USE_SETUP_EXE
|
||||
| VCRUISE_GF_BUL_LANGUAGE | VCRUISE_GF_JPN_LANGUAGE,
|
||||
GUIO1(GAMEOPTION_FAST_VIDEO_DECODER)
|
||||
},
|
||||
GID_SCHIZM,
|
||||
Common::JA_JPN,
|
||||
},
|
||||
{ // Schizm: Mysterious Journey, English DVD Version, unknown variant
|
||||
{
|
||||
"schizm",
|
||||
"English DVD",
|
||||
AD_ENTRY1s("setup.pak", "964e386b187752d53b69f9c55c4f6e6b", 274948185),
|
||||
Common::UNK_LANG,
|
||||
Common::kPlatformWindows,
|
||||
VCRUISE_GF_WANT_OGG_VORBIS | VCRUISE_GF_NEED_JPEG | VCRUISE_GF_GENTEE_PACKAGE,
|
||||
GUIO1(GAMEOPTION_FAST_VIDEO_DECODER)
|
||||
},
|
||||
GID_SCHIZM,
|
||||
Common::EN_GRB,
|
||||
},
|
||||
{ // Schizm: Mysterious Journey, Polish DVD Version
|
||||
{
|
||||
"schizm",
|
||||
"Polish DVD",
|
||||
AD_ENTRY1s("disk1.pak", "a3453878ad86d012b483a82e04276667", 272507257),
|
||||
Common::UNK_LANG,
|
||||
Common::kPlatformWindows,
|
||||
VCRUISE_GF_WANT_OGG_VORBIS | VCRUISE_GF_NEED_JPEG | VCRUISE_GF_GENTEE_PACKAGE,
|
||||
GUIO1(GAMEOPTION_FAST_VIDEO_DECODER)
|
||||
},
|
||||
GID_SCHIZM,
|
||||
Common::PL_POL,
|
||||
},
|
||||
{ // Schizm: Mysterious Journey, German DVD Version (Project 3 Interactive variation)
|
||||
{
|
||||
"schizm",
|
||||
"German DVD",
|
||||
AD_ENTRY1s("disk1.pak", "dcb27eb3d8a0029c551df5f779af36fc", 274285596),
|
||||
Common::UNK_LANG,
|
||||
Common::kPlatformWindows,
|
||||
VCRUISE_GF_WANT_OGG_VORBIS | VCRUISE_GF_NEED_JPEG | VCRUISE_GF_GENTEE_PACKAGE,
|
||||
GUIO1(GAMEOPTION_FAST_VIDEO_DECODER)
|
||||
},
|
||||
GID_SCHIZM,
|
||||
Common::DE_DEU,
|
||||
},
|
||||
{ // Schizm: Mysterious Journey, German DVD Version (Project 3 Interactive + Brightstar Interactive variation)
|
||||
{
|
||||
"schizm",
|
||||
"German DVD",
|
||||
AD_ENTRY1s("disk1.pak", "2f964852baf18f90e884d6873b1bad23", 272798001),
|
||||
Common::UNK_LANG,
|
||||
Common::kPlatformWindows,
|
||||
VCRUISE_GF_WANT_OGG_VORBIS | VCRUISE_GF_NEED_JPEG | VCRUISE_GF_GENTEE_PACKAGE,
|
||||
GUIO1(GAMEOPTION_FAST_VIDEO_DECODER)
|
||||
},
|
||||
GID_SCHIZM,
|
||||
Common::DE_DEU,
|
||||
},
|
||||
|
||||
{ // Schizm: Mysterious Journey, English digital 10-language (GOG) version
|
||||
{
|
||||
"schizm",
|
||||
"English Digital",
|
||||
AD_ENTRY2s("Schizm.exe", "296edd26d951c3bdc4d303c4c88b27cd", 364544,
|
||||
"0001_a.wav", "374d93abc3422840623acc618ecb2b1e", 1553784),
|
||||
Common::UNK_LANG,
|
||||
Common::kPlatformWindows,
|
||||
VCRUISE_GF_WANT_OGG_VORBIS | VCRUISE_GF_NEED_JPEG,
|
||||
GUIO1(GAMEOPTION_FAST_VIDEO_DECODER)
|
||||
},
|
||||
GID_SCHIZM,
|
||||
Common::EN_GRB,
|
||||
},
|
||||
{ // Schizm: Mysterious Journey, German digital 10-language (GOG) version
|
||||
{
|
||||
"schizm",
|
||||
"German Digital",
|
||||
AD_ENTRY2s("Schizm.exe", "296edd26d951c3bdc4d303c4c88b27cd", 364544,
|
||||
"0001_a.wav", "f2b7eccfb1e9af0282b541c5eac66cc7", 1613240),
|
||||
Common::UNK_LANG,
|
||||
Common::kPlatformWindows,
|
||||
VCRUISE_GF_WANT_OGG_VORBIS | VCRUISE_GF_NEED_JPEG,
|
||||
GUIO1(GAMEOPTION_FAST_VIDEO_DECODER)
|
||||
},
|
||||
GID_SCHIZM,
|
||||
Common::DE_DEU,
|
||||
},
|
||||
{ // Schizm: Mysterious Journey, German digital 10-language (GOG) version
|
||||
{
|
||||
"schizm",
|
||||
"Spanish Digital",
|
||||
AD_ENTRY2s("Schizm.exe", "296edd26d951c3bdc4d303c4c88b27cd", 364544,
|
||||
"0001_a.wav", "7a398f17e847a46de629a09fa6178b00", 1409560),
|
||||
Common::UNK_LANG,
|
||||
Common::kPlatformWindows,
|
||||
VCRUISE_GF_WANT_OGG_VORBIS | VCRUISE_GF_NEED_JPEG,
|
||||
GUIO1(GAMEOPTION_FAST_VIDEO_DECODER)
|
||||
},
|
||||
GID_SCHIZM,
|
||||
Common::ES_ESP,
|
||||
},
|
||||
{ // Schizm: Mysterious Journey, French digital 10-language (GOG) version
|
||||
{
|
||||
"schizm",
|
||||
"French Digital",
|
||||
AD_ENTRY2s("Schizm.exe", "296edd26d951c3bdc4d303c4c88b27cd", 364544,
|
||||
"0001_a.wav", "cd46a5df85a879bf293871b5911abcc3", 1305470),
|
||||
Common::UNK_LANG,
|
||||
Common::kPlatformWindows,
|
||||
VCRUISE_GF_WANT_OGG_VORBIS | VCRUISE_GF_NEED_JPEG,
|
||||
GUIO1(GAMEOPTION_FAST_VIDEO_DECODER)
|
||||
},
|
||||
GID_SCHIZM,
|
||||
Common::FR_FRA,
|
||||
},
|
||||
{ // Schizm: Mysterious Journey, Hungarian digital 10-language (GOG) version
|
||||
{
|
||||
"schizm",
|
||||
"Hungarian Digital",
|
||||
AD_ENTRY2s("Schizm.exe", "296edd26d951c3bdc4d303c4c88b27cd", 364544,
|
||||
"0001_a.wav", "9838f59fce21ba3a1eecc3d84c5be8b1", 1502674),
|
||||
Common::UNK_LANG,
|
||||
Common::kPlatformWindows,
|
||||
VCRUISE_GF_WANT_OGG_VORBIS | VCRUISE_GF_NEED_JPEG,
|
||||
GUIO1(GAMEOPTION_FAST_VIDEO_DECODER)
|
||||
},
|
||||
GID_SCHIZM,
|
||||
Common::HU_HUN,
|
||||
},
|
||||
{ // Schizm: Mysterious Journey, Italian digital 10-language (GOG) version
|
||||
{
|
||||
"schizm",
|
||||
"Italian Digital",
|
||||
AD_ENTRY2s("Schizm.exe", "296edd26d951c3bdc4d303c4c88b27cd", 364544,
|
||||
"0001_a.wav", "6d8e4b97710b858525d9965ef1e627ab", 1280506),
|
||||
Common::UNK_LANG,
|
||||
Common::kPlatformWindows,
|
||||
VCRUISE_GF_WANT_OGG_VORBIS | VCRUISE_GF_NEED_JPEG,
|
||||
GUIO1(GAMEOPTION_FAST_VIDEO_DECODER)
|
||||
},
|
||||
GID_SCHIZM,
|
||||
Common::IT_ITA,
|
||||
},
|
||||
{ // Schizm: Mysterious Journey, Polish digital 10-language (GOG) version
|
||||
{
|
||||
"schizm",
|
||||
"Polish Digital",
|
||||
AD_ENTRY2s("Schizm.exe", "296edd26d951c3bdc4d303c4c88b27cd", 364544,
|
||||
"0001_a.wav", "4fc0053f66657e416b69419106d238a5", 1592106),
|
||||
Common::UNK_LANG,
|
||||
Common::kPlatformWindows,
|
||||
VCRUISE_GF_WANT_OGG_VORBIS | VCRUISE_GF_NEED_JPEG,
|
||||
GUIO1(GAMEOPTION_FAST_VIDEO_DECODER)
|
||||
},
|
||||
GID_SCHIZM,
|
||||
Common::PL_POL,
|
||||
},
|
||||
{ // Schizm: Mysterious Journey, Russian digital 10-language (GOG) version
|
||||
{
|
||||
"schizm",
|
||||
"Russian Digital",
|
||||
AD_ENTRY2s("Schizm.exe", "296edd26d951c3bdc4d303c4c88b27cd", 364544,
|
||||
"0001_a.wav", "ba8fc041a92f1afceee35bdbb84eb2cd", 1427794),
|
||||
Common::UNK_LANG,
|
||||
Common::kPlatformWindows,
|
||||
VCRUISE_GF_WANT_OGG_VORBIS | VCRUISE_GF_NEED_JPEG,
|
||||
GUIO1(GAMEOPTION_FAST_VIDEO_DECODER)
|
||||
},
|
||||
GID_SCHIZM,
|
||||
Common::RU_RUS,
|
||||
},
|
||||
|
||||
// Steam (16-language) versions
|
||||
{ // Schizm: Mysterious Journey, English digital 16-language (Steam) version
|
||||
{
|
||||
"schizm",
|
||||
"English Digital",
|
||||
AD_ENTRY3s("Schizm.exe", "8b77c96b51f0c1d676d7a9ff29f06250", 381240,
|
||||
"0001_a.wav", "374d93abc3422840623acc618ecb2b1e", 1553784,
|
||||
"Speech10.txt", "88fdaab90be33bca88db423e1acda8c3", 63697),
|
||||
Common::UNK_LANG,
|
||||
Common::kPlatformWindows,
|
||||
VCRUISE_GF_WANT_OGG_VORBIS | VCRUISE_GF_NEED_JPEG | VCRUISE_GF_STEAM_LANGUAGES,
|
||||
GUIO1(GAMEOPTION_FAST_VIDEO_DECODER)
|
||||
},
|
||||
GID_SCHIZM,
|
||||
Common::EN_GRB,
|
||||
},
|
||||
{ // Schizm: Mysterious Journey, German digital 16-language (Steam) version
|
||||
{
|
||||
"schizm",
|
||||
"German Digital",
|
||||
AD_ENTRY3s("Schizm.exe", "8b77c96b51f0c1d676d7a9ff29f06250", 381240,
|
||||
"0001_a.wav", "f2b7eccfb1e9af0282b541c5eac66cc7", 1613240,
|
||||
"Speech10.txt", "88fdaab90be33bca88db423e1acda8c3", 63697),
|
||||
Common::UNK_LANG,
|
||||
Common::kPlatformWindows,
|
||||
VCRUISE_GF_WANT_OGG_VORBIS | VCRUISE_GF_NEED_JPEG | VCRUISE_GF_STEAM_LANGUAGES,
|
||||
GUIO1(GAMEOPTION_FAST_VIDEO_DECODER)
|
||||
},
|
||||
GID_SCHIZM,
|
||||
Common::DE_DEU,
|
||||
},
|
||||
{ // Schizm: Mysterious Journey, Spanish digital 16-language (Steam) version
|
||||
{
|
||||
"schizm",
|
||||
"Spanish Digital",
|
||||
AD_ENTRY3s("Schizm.exe", "8b77c96b51f0c1d676d7a9ff29f06250", 381240,
|
||||
"0001_a.wav", "7a398f17e847a46de629a09fa6178b00", 1409560,
|
||||
"Speech10.txt", "88fdaab90be33bca88db423e1acda8c3", 63697),
|
||||
Common::UNK_LANG,
|
||||
Common::kPlatformWindows,
|
||||
VCRUISE_GF_WANT_OGG_VORBIS | VCRUISE_GF_NEED_JPEG | VCRUISE_GF_STEAM_LANGUAGES,
|
||||
GUIO1(GAMEOPTION_FAST_VIDEO_DECODER)
|
||||
},
|
||||
GID_SCHIZM,
|
||||
Common::ES_ESP,
|
||||
},
|
||||
{ // Schizm: Mysterious Journey, French digital 16-language (Steam) version
|
||||
{
|
||||
"schizm",
|
||||
"French Digital",
|
||||
AD_ENTRY3s("Schizm.exe", "8b77c96b51f0c1d676d7a9ff29f06250", 381240,
|
||||
"0001_a.wav", "cd46a5df85a879bf293871b5911abcc3", 1305470,
|
||||
"Speech10.txt", "88fdaab90be33bca88db423e1acda8c3", 63697),
|
||||
Common::UNK_LANG,
|
||||
Common::kPlatformWindows,
|
||||
VCRUISE_GF_WANT_OGG_VORBIS | VCRUISE_GF_NEED_JPEG | VCRUISE_GF_STEAM_LANGUAGES,
|
||||
GUIO1(GAMEOPTION_FAST_VIDEO_DECODER)
|
||||
},
|
||||
GID_SCHIZM,
|
||||
Common::FR_FRA,
|
||||
},
|
||||
{ // Schizm: Mysterious Journey, Hungarian digital 16-language (Steam) version
|
||||
{
|
||||
"schizm",
|
||||
"Hungarian Digital",
|
||||
AD_ENTRY3s("Schizm.exe", "8b77c96b51f0c1d676d7a9ff29f06250", 381240,
|
||||
"0001_a.wav", "9838f59fce21ba3a1eecc3d84c5be8b1", 1502674,
|
||||
"Speech10.txt", "88fdaab90be33bca88db423e1acda8c3", 63697),
|
||||
Common::UNK_LANG,
|
||||
Common::kPlatformWindows,
|
||||
VCRUISE_GF_WANT_OGG_VORBIS | VCRUISE_GF_NEED_JPEG | VCRUISE_GF_STEAM_LANGUAGES,
|
||||
GUIO1(GAMEOPTION_FAST_VIDEO_DECODER)
|
||||
},
|
||||
GID_SCHIZM,
|
||||
Common::HU_HUN,
|
||||
},
|
||||
{ // Schizm: Mysterious Journey, Italian digital 16-language (Steam) version
|
||||
{
|
||||
"schizm",
|
||||
"Italian Digital",
|
||||
AD_ENTRY3s("Schizm.exe", "8b77c96b51f0c1d676d7a9ff29f06250", 381240,
|
||||
"0001_a.wav", "6d8e4b97710b858525d9965ef1e627ab", 1280506,
|
||||
"Speech10.txt", "88fdaab90be33bca88db423e1acda8c3", 63697),
|
||||
Common::UNK_LANG,
|
||||
Common::kPlatformWindows,
|
||||
VCRUISE_GF_WANT_OGG_VORBIS | VCRUISE_GF_NEED_JPEG | VCRUISE_GF_STEAM_LANGUAGES,
|
||||
GUIO1(GAMEOPTION_FAST_VIDEO_DECODER)
|
||||
},
|
||||
GID_SCHIZM,
|
||||
Common::IT_ITA,
|
||||
},
|
||||
{ // Schizm: Mysterious Journey, Polish digital 16-language (Steam) version
|
||||
{
|
||||
"schizm",
|
||||
"Polish Digital",
|
||||
AD_ENTRY3s("Schizm.exe", "8b77c96b51f0c1d676d7a9ff29f06250", 381240,
|
||||
"0001_a.wav", "4fc0053f66657e416b69419106d238a5", 1592106,
|
||||
"Speech10.txt", "88fdaab90be33bca88db423e1acda8c3", 63697),
|
||||
Common::UNK_LANG,
|
||||
Common::kPlatformWindows,
|
||||
VCRUISE_GF_WANT_OGG_VORBIS | VCRUISE_GF_NEED_JPEG | VCRUISE_GF_STEAM_LANGUAGES,
|
||||
GUIO1(GAMEOPTION_FAST_VIDEO_DECODER)
|
||||
},
|
||||
GID_SCHIZM,
|
||||
Common::PL_POL,
|
||||
},
|
||||
{ // Schizm: Mysterious Journey, Russian digital 16-language (Steam) version
|
||||
{
|
||||
"schizm",
|
||||
"Russian Digital",
|
||||
AD_ENTRY3s("Schizm.exe", "8b77c96b51f0c1d676d7a9ff29f06250", 381240,
|
||||
"0001_a.wav", "ba8fc041a92f1afceee35bdbb84eb2cd", 1427794,
|
||||
"Speech10.txt", "88fdaab90be33bca88db423e1acda8c3", 63697),
|
||||
Common::UNK_LANG,
|
||||
Common::kPlatformWindows,
|
||||
VCRUISE_GF_WANT_OGG_VORBIS | VCRUISE_GF_NEED_JPEG | VCRUISE_GF_STEAM_LANGUAGES,
|
||||
GUIO1(GAMEOPTION_FAST_VIDEO_DECODER)
|
||||
},
|
||||
GID_SCHIZM,
|
||||
Common::RU_RUS,
|
||||
},
|
||||
|
||||
{ AD_TABLE_END_MARKER, GID_UNKNOWN, Common::UNK_LANG }
|
||||
};
|
||||
|
||||
} // End of namespace VCruise
|
||||
|
||||
#endif
|
||||
1197
engines/vcruise/menu.cpp
Normal file
1197
engines/vcruise/menu.cpp
Normal file
File diff suppressed because it is too large
Load Diff
95
engines/vcruise/menu.h
Normal file
95
engines/vcruise/menu.h
Normal file
@@ -0,0 +1,95 @@
|
||||
/* 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 VCRUISE_MENU_H
|
||||
#define VCRUISE_MENU_H
|
||||
|
||||
#include "common/array.h"
|
||||
#include "common/ptr.h"
|
||||
|
||||
namespace Graphics {
|
||||
|
||||
class Font;
|
||||
struct Surface;
|
||||
class ManagedSurface;
|
||||
|
||||
} // End of namespace Graphics
|
||||
|
||||
namespace Common {
|
||||
|
||||
struct Rect;
|
||||
|
||||
} // End of namespace Common
|
||||
|
||||
namespace VCruise {
|
||||
|
||||
struct OSEvent;
|
||||
class MenuPage;
|
||||
class Runtime;
|
||||
|
||||
class MenuInterface {
|
||||
public:
|
||||
virtual ~MenuInterface();
|
||||
|
||||
virtual void commitRect(const Common::Rect &rect) const = 0;
|
||||
virtual bool popOSEvent(OSEvent &evt) const = 0;
|
||||
virtual Graphics::ManagedSurface *getUIGraphic(uint index) const = 0;
|
||||
virtual Graphics::ManagedSurface *getMenuSurface() const = 0;
|
||||
virtual bool hasDefaultSave() const = 0;
|
||||
virtual bool hasAnySave() const = 0;
|
||||
virtual bool isInGame() const = 0;
|
||||
virtual Common::Point getMouseCoordinate() const = 0;
|
||||
virtual void restartGame() const = 0;
|
||||
virtual void goToCredits() const = 0;
|
||||
virtual void changeMenu(MenuPage *newPage) const = 0;
|
||||
virtual void quitGame() const = 0;
|
||||
virtual void quitToMenu() const = 0;
|
||||
virtual bool canSave() const = 0;
|
||||
virtual bool reloadFromCheckpoint() const = 0;
|
||||
virtual void setMusicMute(bool muted) const = 0;
|
||||
|
||||
virtual void drawLabel(Graphics::ManagedSurface *surface, const Common::String &labelID, const Common::Rect &contentRect) const = 0;
|
||||
};
|
||||
|
||||
class MenuPage {
|
||||
public:
|
||||
MenuPage();
|
||||
virtual ~MenuPage();
|
||||
|
||||
void init(const MenuInterface *menuInterface);
|
||||
|
||||
virtual void start();
|
||||
virtual bool run();
|
||||
virtual void onSettingsChanged();
|
||||
|
||||
protected:
|
||||
const MenuInterface *_menuInterface;
|
||||
};
|
||||
|
||||
MenuPage *createMenuMain(bool isSchizm);
|
||||
MenuPage *createMenuHelp(bool isSchizm);
|
||||
MenuPage *createMenuSound(bool isSchizm);
|
||||
MenuPage *createMenuQuit(bool isSchizm);
|
||||
MenuPage *createMenuPause(bool isSchizm);
|
||||
|
||||
} // End of namespace VCruise
|
||||
|
||||
#endif
|
||||
246
engines/vcruise/metaengine.cpp
Normal file
246
engines/vcruise/metaengine.cpp
Normal file
@@ -0,0 +1,246 @@
|
||||
/* 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 "common/translation.h"
|
||||
|
||||
#include "backends/keymapper/action.h"
|
||||
#include "backends/keymapper/keymapper.h"
|
||||
#include "backends/keymapper/standard-actions.h"
|
||||
|
||||
#include "engines/advancedDetector.h"
|
||||
#include "vcruise/vcruise.h"
|
||||
|
||||
namespace Graphics {
|
||||
|
||||
struct Surface;
|
||||
|
||||
} // End of namespace Graphics
|
||||
|
||||
namespace VCruise {
|
||||
|
||||
static const ADExtraGuiOptionsMap optionsList[] = {
|
||||
{
|
||||
GAMEOPTION_INCREASE_DRAG_DISTANCE,
|
||||
{
|
||||
_s("Improved click sensitivity"),
|
||||
_s("Allows the mouse to be moved a short distance without cancelling click interactions. If this is off, any mouse movement while the mouse button is held cancels a click interaction."),
|
||||
"vcruise_increase_drag_distance",
|
||||
true,
|
||||
0,
|
||||
0
|
||||
}
|
||||
},
|
||||
{
|
||||
GAMEOPTION_FAST_ANIMATIONS,
|
||||
{
|
||||
_s("Faster animations"),
|
||||
_s("Speeds up animations."),
|
||||
"vcruise_fast_animations",
|
||||
false,
|
||||
0,
|
||||
0
|
||||
}
|
||||
},
|
||||
{
|
||||
GAMEOPTION_LAUNCH_DEBUG,
|
||||
{
|
||||
_s("Start with debugger"),
|
||||
_s("Starts with the debugger dashboard active."),
|
||||
"vcruise_debug",
|
||||
false,
|
||||
0,
|
||||
0
|
||||
}
|
||||
},
|
||||
{
|
||||
GAMEOPTION_SKIP_MENU,
|
||||
{
|
||||
_s("Skip main menu"),
|
||||
_s("Starts a new game upon launching instead of going to the main menu."),
|
||||
"vcruise_skip_menu",
|
||||
false,
|
||||
0,
|
||||
0
|
||||
}
|
||||
},
|
||||
{
|
||||
GAMEOPTION_USE_4BIT_GRAPHICS,
|
||||
{
|
||||
_s("Use 16-color graphics"),
|
||||
_s("Uses 16-color graphics."),
|
||||
"vcruise_use_4bit",
|
||||
false,
|
||||
0,
|
||||
0
|
||||
}
|
||||
},
|
||||
{
|
||||
GAMEOPTION_PRELOAD_SOUNDS,
|
||||
{
|
||||
_s("Preload sounds"),
|
||||
_s("Preload sounds. May improve performance on slow hard drives."),
|
||||
"vcruise_preload_sounds",
|
||||
false,
|
||||
0,
|
||||
0
|
||||
}
|
||||
},
|
||||
{
|
||||
GAMEOPTION_FAST_VIDEO_DECODER,
|
||||
{
|
||||
_s("Faster video decoder (lower quality)"),
|
||||
_s("Reduce video decoding CPU usage at the cost of quality."),
|
||||
"vcruise_fast_video_decoder",
|
||||
false,
|
||||
0,
|
||||
0
|
||||
}
|
||||
},
|
||||
AD_EXTRA_GUI_OPTIONS_TERMINATOR
|
||||
};
|
||||
|
||||
} // End of namespace VCruise
|
||||
|
||||
class VCruiseMetaEngine : public AdvancedMetaEngine<VCruise::VCruiseGameDescription> {
|
||||
public:
|
||||
const char *getName() const override {
|
||||
return "vcruise";
|
||||
}
|
||||
|
||||
const ADExtraGuiOptionsMap *getAdvancedExtraGuiOptions() const override {
|
||||
return VCruise::optionsList;
|
||||
}
|
||||
|
||||
bool hasFeature(MetaEngineFeature f) const override;
|
||||
Common::Error createInstance(OSystem *syst, Engine **engine, const VCruise::VCruiseGameDescription *desc) const override;
|
||||
|
||||
Common::Array<Common::Keymap *> initKeymaps(const char *target) const override;
|
||||
};
|
||||
|
||||
bool VCruiseMetaEngine::hasFeature(MetaEngineFeature f) const {
|
||||
switch (f) {
|
||||
case kSupportsLoadingDuringStartup:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return checkExtendedSaves(f);
|
||||
}
|
||||
|
||||
Common::Error VCruiseMetaEngine::createInstance(OSystem *syst, Engine **engine, const VCruise::VCruiseGameDescription *desc) const {
|
||||
*engine = new VCruise::VCruiseEngine(syst, reinterpret_cast<const VCruise::VCruiseGameDescription *>(desc));
|
||||
return Common::kNoError;
|
||||
}
|
||||
|
||||
Common::Array<Common::Keymap *> VCruiseMetaEngine::initKeymaps(const char *target) const {
|
||||
Common::Keymap *keymap = new Common::Keymap(Common::Keymap::kKeymapTypeGame, "vcruise", "V-Cruise");
|
||||
Common::Action *act;
|
||||
|
||||
act = new Common::Action(Common::kStandardActionLeftClick, _("Left click"));
|
||||
act->setLeftClickEvent();
|
||||
act->addDefaultInputMapping("MOUSE_LEFT");
|
||||
act->addDefaultInputMapping("JOY_A");
|
||||
keymap->addAction(act);
|
||||
|
||||
act = new Common::Action("VCRUISE_ESCAPE", _("Escape"));
|
||||
act->setCustomEngineActionEvent(VCruise::kKeymappedEventEscape);
|
||||
act->addDefaultInputMapping("ESCAPE");
|
||||
act->addDefaultInputMapping("JOY_Y");
|
||||
keymap->addAction(act);
|
||||
|
||||
act = new Common::Action("VCRUISE_HELP", _("Display help screen"));
|
||||
act->setCustomEngineActionEvent(VCruise::kKeymappedEventHelp);
|
||||
act->addDefaultInputMapping("F1");
|
||||
keymap->addAction(act);
|
||||
|
||||
act = new Common::Action("VCRUISE_SAVE_GAME", _("Save game"));
|
||||
act->setCustomEngineActionEvent(VCruise::kKeymappedEventSaveGame);
|
||||
act->addDefaultInputMapping("F2");
|
||||
keymap->addAction(act);
|
||||
|
||||
act = new Common::Action("VCRUISE_LOAD_GAME", _("Load game"));
|
||||
act->setCustomEngineActionEvent(VCruise::kKeymappedEventLoadGame);
|
||||
act->addDefaultInputMapping("F3");
|
||||
keymap->addAction(act);
|
||||
|
||||
act = new Common::Action("VCRUISE_SOUND_SETTINGS", _("Open sound settings"));
|
||||
act->setCustomEngineActionEvent(VCruise::kKeymappedEventSoundSettings);
|
||||
act->addDefaultInputMapping("F4");
|
||||
keymap->addAction(act);
|
||||
|
||||
act = new Common::Action("VCRUISE_QUIT", _("Quit game"));
|
||||
act->setCustomEngineActionEvent(VCruise::kKeymappedEventQuit);
|
||||
act->addDefaultInputMapping("F10");
|
||||
keymap->addAction(act);
|
||||
|
||||
act = new Common::Action("VCRUISE_PAUSE", _("Pause game"));
|
||||
act->setCustomEngineActionEvent(VCruise::kKeymappedEventPause);
|
||||
act->addDefaultInputMapping("SPACE");
|
||||
keymap->addAction(act);
|
||||
|
||||
|
||||
act = new Common::Action("VCRUISE_MUSIC_TOGGLE", _("Toggle music"));
|
||||
act->setCustomEngineActionEvent(VCruise::kKeymappedEventMusicToggle);
|
||||
act->addDefaultInputMapping("F5");
|
||||
keymap->addAction(act);
|
||||
|
||||
act = new Common::Action("VCRUISE_SOUND_TOGGLE", _("Toggle sound effects"));
|
||||
act->setCustomEngineActionEvent(VCruise::kKeymappedEventSoundToggle);
|
||||
act->addDefaultInputMapping("F6");
|
||||
keymap->addAction(act);
|
||||
|
||||
act = new Common::Action("VCRUISE_MUSIC_VOLUME_DOWN", _("Music volume down"));
|
||||
act->setCustomEngineActionEvent(VCruise::kKeymappedEventMusicVolumeDown);
|
||||
act->addDefaultInputMapping("F7");
|
||||
keymap->addAction(act);
|
||||
|
||||
act = new Common::Action("VCRUISE_MUSIC_VOLUME_UP", _("Music volume up"));
|
||||
act->setCustomEngineActionEvent(VCruise::kKeymappedEventMusicVolumeUp);
|
||||
act->addDefaultInputMapping("F8");
|
||||
keymap->addAction(act);
|
||||
|
||||
act = new Common::Action("VCRUISE_SOUND_EFFECTS_VOLUME_DOWN", _("Sound effect volume down"));
|
||||
act->setCustomEngineActionEvent(VCruise::kKeymappedEventSoundVolumeUp);
|
||||
act->addDefaultInputMapping("F11");
|
||||
keymap->addAction(act);
|
||||
|
||||
act = new Common::Action("VCRUISE_SOUND_EFFECTS_VOLUME_UP", _("Sound effect volume up"));
|
||||
act->setCustomEngineActionEvent(VCruise::kKeymappedEventSoundVolumeDown);
|
||||
act->addDefaultInputMapping("F12");
|
||||
keymap->addAction(act);
|
||||
|
||||
act = new Common::Action("VCRUISE_SKIP_ANIMATION", _("Skip current animation"));
|
||||
act->setCustomEngineActionEvent(VCruise::kKeymappedEventSkipAnimation);
|
||||
keymap->addAction(act);
|
||||
|
||||
act = new Common::Action("VCRUISE_PUT_ITEM", _("Cycle item in scene (debug cheat)"));
|
||||
act->setCustomEngineActionEvent(VCruise::kKeymappedEventPutItem);
|
||||
keymap->addAction(act);
|
||||
|
||||
return Common::Keymap::arrayOf(keymap);
|
||||
}
|
||||
|
||||
#if PLUGIN_ENABLED_DYNAMIC(VCRUISE)
|
||||
REGISTER_PLUGIN_DYNAMIC(VCRUISE, PLUGIN_TYPE_ENGINE, VCruiseMetaEngine);
|
||||
#else
|
||||
REGISTER_PLUGIN_STATIC(VCRUISE, PLUGIN_TYPE_ENGINE, VCruiseMetaEngine);
|
||||
#endif
|
||||
79
engines/vcruise/midi_player.cpp
Normal file
79
engines/vcruise/midi_player.cpp
Normal file
@@ -0,0 +1,79 @@
|
||||
/* 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/mididrv.h"
|
||||
#include "audio/midiparser_smf.h"
|
||||
|
||||
#include "vcruise/midi_player.h"
|
||||
|
||||
namespace VCruise {
|
||||
|
||||
MidiPlayer::MidiPlayer(MidiDriver *midiDrv, Common::Array<byte> &&musicData, int volume)
|
||||
: _midiDrv(midiDrv), _data(Common::move(musicData)) {
|
||||
_parser.reset(MidiParser::createParser_SMF());
|
||||
|
||||
if (_data.size() > 0u && _parser->loadMusic(&_data[0], _data.size())) {
|
||||
_parser->setTrack(0);
|
||||
_parser->setMidiDriver(_midiDrv);
|
||||
_parser->startPlaying();
|
||||
_parser->property(MidiParser::mpAutoLoop, 1);
|
||||
_parser->setTimerRate(_midiDrv->getBaseTempo());
|
||||
|
||||
setVolume(volume);
|
||||
} else
|
||||
_parser.reset();
|
||||
}
|
||||
|
||||
MidiPlayer::~MidiPlayer() {
|
||||
if (_parser)
|
||||
_parser->stopPlaying();
|
||||
}
|
||||
|
||||
void MidiPlayer::setVolume(int volume) {
|
||||
if (!_parser)
|
||||
return;
|
||||
|
||||
if (volume > 100)
|
||||
volume = 100;
|
||||
else if (volume < 0)
|
||||
volume = 0;
|
||||
|
||||
volume = 51;
|
||||
|
||||
//uint32 effectiveValue = static_cast<uint32>(floor(sqrt(sqrt(volume)) * 5180.76));
|
||||
uint32 effectiveValue = static_cast<uint32>(volume * 0x3fff / 100);
|
||||
|
||||
if (effectiveValue > 0x3fffu)
|
||||
effectiveValue = 0x3fffu;
|
||||
|
||||
byte masterVolMessage[6] = {
|
||||
0x7f, 0x00, 0x04, 0x01, static_cast<byte>(effectiveValue & 0x7f), static_cast<byte>((effectiveValue >> 7) & 0x7f)
|
||||
};
|
||||
|
||||
_midiDrv->sysEx(masterVolMessage, 6);
|
||||
}
|
||||
|
||||
void MidiPlayer::onMidiTimer() {
|
||||
if (_parser)
|
||||
_parser->onTimer();
|
||||
}
|
||||
|
||||
} // End of namespace VCruise
|
||||
56
engines/vcruise/midi_player.h
Normal file
56
engines/vcruise/midi_player.h
Normal file
@@ -0,0 +1,56 @@
|
||||
/* 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 VCRUISE_MIDI_PLAYER_H
|
||||
#define VCRUISE_MIDI_PLAYER_H
|
||||
|
||||
#include "common/array.h"
|
||||
#include "common/mutex.h"
|
||||
#include "common/ptr.h"
|
||||
|
||||
class MidiDriver;
|
||||
class MidiParser;
|
||||
|
||||
namespace Common {
|
||||
|
||||
class SeekableReadStream;
|
||||
|
||||
} // End of namespace Common
|
||||
|
||||
namespace VCruise {
|
||||
|
||||
class MidiPlayer {
|
||||
public:
|
||||
MidiPlayer(MidiDriver *midiDrv, Common::Array<byte> &&musicData, int volume);
|
||||
~MidiPlayer();
|
||||
|
||||
void setVolume(int volume);
|
||||
void onMidiTimer();
|
||||
|
||||
private:
|
||||
MidiDriver *_midiDrv;
|
||||
Common::SharedPtr<MidiParser> _parser;
|
||||
Common::Array<byte> _data;
|
||||
};
|
||||
|
||||
} // End of namespace VCruise
|
||||
|
||||
#endif
|
||||
28
engines/vcruise/module.mk
Normal file
28
engines/vcruise/module.mk
Normal file
@@ -0,0 +1,28 @@
|
||||
MODULE := engines/vcruise
|
||||
|
||||
MODULE_OBJS = \
|
||||
ad2044_items.o \
|
||||
ad2044_ui.o \
|
||||
audio_player.o \
|
||||
circuitpuzzle.o \
|
||||
midi_player.o \
|
||||
metaengine.o \
|
||||
menu.o \
|
||||
runtime.o \
|
||||
runtime_scriptexec.o \
|
||||
sampleloop.o \
|
||||
script.o \
|
||||
textparser.o \
|
||||
vcruise.o
|
||||
|
||||
|
||||
# This module can be built as a plugin
|
||||
ifeq ($(ENABLE_VCRUISE), DYNAMIC_PLUGIN)
|
||||
PLUGIN := 1
|
||||
endif
|
||||
|
||||
# Include common rules
|
||||
include $(srcdir)/rules.mk
|
||||
|
||||
# Detection objects
|
||||
DETECT_OBJS += $(MODULE)/detection.o
|
||||
7391
engines/vcruise/runtime.cpp
Normal file
7391
engines/vcruise/runtime.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1555
engines/vcruise/runtime.h
Normal file
1555
engines/vcruise/runtime.h
Normal file
File diff suppressed because it is too large
Load Diff
2614
engines/vcruise/runtime_scriptexec.cpp
Normal file
2614
engines/vcruise/runtime_scriptexec.cpp
Normal file
File diff suppressed because it is too large
Load Diff
362
engines/vcruise/sampleloop.cpp
Normal file
362
engines/vcruise/sampleloop.cpp
Normal file
@@ -0,0 +1,362 @@
|
||||
/* 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 "common/stream.h"
|
||||
|
||||
#include "vcruise/sampleloop.h"
|
||||
|
||||
namespace VCruise {
|
||||
|
||||
SampleLoop::SampleLoop() : identifier(0), type(0), start(0), end(0), fraction(0), playCount(0) {
|
||||
}
|
||||
|
||||
bool SampleLoop::read(Common::ReadStream &stream, uint &availableBytes) {
|
||||
if (availableBytes < 24)
|
||||
return false;
|
||||
|
||||
byte bytes[24];
|
||||
|
||||
uint32 bytesRead = stream.read(bytes, 24);
|
||||
availableBytes -= bytesRead;
|
||||
if (bytesRead != 24)
|
||||
return false;
|
||||
|
||||
this->identifier = READ_LE_UINT32(bytes + 0);
|
||||
this->type = READ_LE_UINT32(bytes + 4);
|
||||
this->start = READ_LE_UINT32(bytes + 8);
|
||||
this->end = READ_LE_UINT32(bytes + 12);
|
||||
this->fraction = READ_LE_UINT32(bytes + 16);
|
||||
this->playCount = READ_LE_UINT32(bytes + 20);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
SampleChunk::SampleChunk() : manufacturer(0), product(0), samplePeriod(0), midiUnityNote(0), midiPitchFraction(0), smpteFormat(0), smpteOffset(0) {
|
||||
}
|
||||
|
||||
bool SampleChunk::read(Common::ReadStream &stream, uint &availableBytes) {
|
||||
if (availableBytes < 36)
|
||||
return false;
|
||||
|
||||
byte bytes[36];
|
||||
|
||||
uint32 bytesRead = stream.read(bytes, 36);
|
||||
availableBytes -= bytesRead;
|
||||
if (bytesRead != 36)
|
||||
return false;
|
||||
|
||||
this->manufacturer = READ_LE_UINT32(bytes + 0);
|
||||
this->product = READ_LE_UINT32(bytes + 4);
|
||||
this->samplePeriod = READ_LE_UINT32(bytes + 8);
|
||||
this->midiUnityNote = READ_LE_UINT32(bytes + 12);
|
||||
this->midiPitchFraction = READ_LE_UINT32(bytes + 16);
|
||||
this->smpteFormat = READ_LE_UINT32(bytes + 20);
|
||||
this->smpteOffset = READ_LE_UINT32(bytes + 24);
|
||||
|
||||
uint32 numSampleLoops = READ_LE_UINT32(bytes + 28);
|
||||
uint32 sizeOfSamplerData = READ_LE_UINT32(bytes + 32);
|
||||
|
||||
loops.resize(numSampleLoops);
|
||||
samplerData.resize(sizeOfSamplerData);
|
||||
|
||||
for (uint32 i = 0; i < numSampleLoops; i++)
|
||||
if (!loops[i].read(stream, availableBytes))
|
||||
return false;
|
||||
|
||||
if (sizeOfSamplerData > 0) {
|
||||
if (availableBytes < sizeOfSamplerData)
|
||||
return false;
|
||||
|
||||
bytesRead = stream.read(&samplerData[0], sizeOfSamplerData);
|
||||
availableBytes -= bytesRead;
|
||||
if (bytesRead != sizeOfSamplerData)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Common::SharedPtr<SoundLoopInfo> SoundLoopInfo::readFromWaveFile(Common::SeekableReadStream &stream) {
|
||||
if (!stream.seek(0))
|
||||
return nullptr;
|
||||
|
||||
int64 waveSize64 = stream.size();
|
||||
|
||||
if (waveSize64 > static_cast<int64>(0xffffffffu))
|
||||
return nullptr;
|
||||
|
||||
uint availableBytes = waveSize64;
|
||||
|
||||
if (availableBytes < 8)
|
||||
return nullptr;
|
||||
|
||||
byte riffHeader[8];
|
||||
if (stream.read(riffHeader, 8) != 8)
|
||||
return nullptr;
|
||||
|
||||
availableBytes -= 8;
|
||||
|
||||
if (READ_LE_UINT32(riffHeader + 0) != 0x46464952)
|
||||
return nullptr;
|
||||
|
||||
uint riffDataSize = READ_LE_UINT32(riffHeader + 4);
|
||||
|
||||
if (riffDataSize > availableBytes)
|
||||
return nullptr;
|
||||
|
||||
availableBytes = riffDataSize;
|
||||
|
||||
if (availableBytes < 4)
|
||||
return nullptr;
|
||||
|
||||
byte waveHeader[4];
|
||||
if (stream.read(waveHeader, 4) != 4)
|
||||
return nullptr;
|
||||
|
||||
availableBytes -= 4;
|
||||
|
||||
if (READ_LE_UINT32(waveHeader + 0) != 0x45564157)
|
||||
return nullptr;
|
||||
|
||||
while (availableBytes > 0) {
|
||||
if (availableBytes < 8)
|
||||
return nullptr;
|
||||
|
||||
byte chunkHeader[8];
|
||||
if (stream.read(chunkHeader, 8) != 8)
|
||||
return nullptr;
|
||||
|
||||
availableBytes -= 8;
|
||||
|
||||
uint32 chunkType = READ_LE_UINT32(chunkHeader + 0);
|
||||
uint32 chunkSize = READ_LE_UINT32(chunkHeader + 4);
|
||||
|
||||
if (chunkSize > availableBytes)
|
||||
return nullptr;
|
||||
|
||||
if (chunkType == 0x6c706d73) {
|
||||
Common::SharedPtr<SoundLoopInfo> sndLoop(new SoundLoopInfo());
|
||||
|
||||
uint chunkAvailableBytes = chunkSize;
|
||||
if (!sndLoop->_sampleChunk.read(stream, chunkAvailableBytes))
|
||||
return nullptr;
|
||||
|
||||
if (sndLoop->_sampleChunk.loops.size() == 0)
|
||||
return nullptr;
|
||||
|
||||
return sndLoop;
|
||||
}
|
||||
|
||||
if (!stream.seek(chunkSize, SEEK_CUR))
|
||||
return nullptr;
|
||||
|
||||
availableBytes -= chunkSize;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SampleLoopAudioStream::LoopRange::LoopRange() : _startSampleInclusive(0), _endSampleExclusive(0), _playCount(0) {
|
||||
}
|
||||
|
||||
SampleLoopAudioStream::SampleLoopAudioStream(Audio::SeekableAudioStream *baseStream, const SoundLoopInfo *loopInfo)
|
||||
: _baseStream(baseStream), _terminated(false), _ignoreLoops(false), _currentSampleOffset(0), _currentLoop(-1), _currentLoopIteration(0), _streamFrames(0), _streamSamples(0) {
|
||||
|
||||
_streamFrames = baseStream->getLength().convertToFramerate(baseStream->getRate()).totalNumberOfFrames();
|
||||
_streamSamples = _streamFrames;
|
||||
|
||||
if (_baseStream->isStereo())
|
||||
_streamSamples *= 2;
|
||||
|
||||
if (loopInfo) {
|
||||
_loopRanges.resize(loopInfo->_sampleChunk.loops.size());
|
||||
for (uint i = 0; i < _loopRanges.size(); i++) {
|
||||
const SampleLoop &inLoop = loopInfo->_sampleChunk.loops[i];
|
||||
LoopRange &outLoop = _loopRanges[i];
|
||||
|
||||
outLoop._startSampleInclusive = inLoop.start;
|
||||
outLoop._endSampleExclusive = inLoop.end;
|
||||
outLoop._playCount = inLoop.playCount;
|
||||
}
|
||||
} else {
|
||||
_loopRanges.resize(1);
|
||||
_loopRanges[0]._startSampleInclusive = 0;
|
||||
_loopRanges[0]._endSampleExclusive = _streamFrames;
|
||||
}
|
||||
|
||||
for (LoopRange &range : _loopRanges) {
|
||||
range._restartTimestamp = Audio::Timestamp(0, range._startSampleInclusive, baseStream->getRate());
|
||||
|
||||
if (range._startSampleInclusive > static_cast<uint>(_streamFrames))
|
||||
range._startSampleInclusive = _streamFrames;
|
||||
if (range._endSampleExclusive > static_cast<uint>(_streamFrames))
|
||||
range._endSampleExclusive = _streamFrames;
|
||||
if (range._endSampleExclusive < range._startSampleInclusive)
|
||||
range._endSampleExclusive = range._startSampleInclusive;
|
||||
|
||||
if (_baseStream->isStereo()) {
|
||||
range._startSampleInclusive *= 2;
|
||||
range._endSampleExclusive *= 2;
|
||||
}
|
||||
}
|
||||
|
||||
for (uint i = 0; i < _loopRanges.size(); ) {
|
||||
const LoopRange &thisRange = _loopRanges[i];
|
||||
|
||||
bool isValid = true;
|
||||
if (thisRange._endSampleExclusive == thisRange._startSampleInclusive)
|
||||
isValid = false;
|
||||
|
||||
if (i > 0) {
|
||||
const LoopRange &prevRange = _loopRanges[i - 1];
|
||||
if (thisRange._startSampleInclusive < prevRange._endSampleExclusive)
|
||||
isValid = false;
|
||||
}
|
||||
|
||||
if (isValid)
|
||||
i++;
|
||||
else
|
||||
_loopRanges.remove_at(i);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
SampleLoopAudioStream::~SampleLoopAudioStream() {
|
||||
}
|
||||
|
||||
void SampleLoopAudioStream::stopLooping() {
|
||||
_mutex.lock();
|
||||
_ignoreLoops = true;
|
||||
_mutex.unlock();
|
||||
}
|
||||
|
||||
int SampleLoopAudioStream::readBuffer(int16 *buffer, int numSamples) {
|
||||
bool ignoreLoops = false;
|
||||
|
||||
_mutex.lock();
|
||||
ignoreLoops = _ignoreLoops;
|
||||
_mutex.unlock();
|
||||
|
||||
int totalSamplesRead = 0;
|
||||
|
||||
for (;;) {
|
||||
if (_terminated || numSamples == 0)
|
||||
return totalSamplesRead;
|
||||
|
||||
int consecutiveSamplesAvailable = 0;
|
||||
bool terminateIfReadCompletes = false;
|
||||
|
||||
if (ignoreLoops) {
|
||||
consecutiveSamplesAvailable = _streamSamples - _currentSampleOffset;
|
||||
terminateIfReadCompletes = true;
|
||||
} else if (_currentLoop < 0) {
|
||||
// Not currently in a loop
|
||||
int samplesUntilLoop = -1;
|
||||
uint scanLoopIndex = 0;
|
||||
for (const LoopRange &loopRange : _loopRanges) {
|
||||
if (static_cast<int>(loopRange._startSampleInclusive) >= _currentSampleOffset) {
|
||||
samplesUntilLoop = loopRange._startSampleInclusive - _currentSampleOffset;
|
||||
break;
|
||||
} else
|
||||
scanLoopIndex++;
|
||||
}
|
||||
|
||||
if (samplesUntilLoop < 0) {
|
||||
// Past the end of the last loop
|
||||
consecutiveSamplesAvailable = _streamSamples - _currentSampleOffset;
|
||||
terminateIfReadCompletes = true;
|
||||
} else if (samplesUntilLoop == 0) {
|
||||
// At the start of a loop
|
||||
_currentLoop = scanLoopIndex;
|
||||
_currentLoopIteration = 0;
|
||||
continue;
|
||||
} else {
|
||||
// Before a loop
|
||||
consecutiveSamplesAvailable = samplesUntilLoop;
|
||||
}
|
||||
} else {
|
||||
// In a loop
|
||||
const LoopRange &loopRange = _loopRanges[_currentLoop];
|
||||
|
||||
int samplesAvailable = loopRange._endSampleExclusive - static_cast<int>(_currentSampleOffset);
|
||||
if (samplesAvailable == 0) {
|
||||
// At the end of the loop
|
||||
if (loopRange._playCount > 0) {
|
||||
if (_currentLoopIteration == loopRange._playCount) {
|
||||
// Exit loop
|
||||
_currentLoop = -1;
|
||||
continue;
|
||||
} else
|
||||
_currentLoopIteration++;
|
||||
}
|
||||
|
||||
if (!_baseStream->seek(loopRange._restartTimestamp)) {
|
||||
_terminated = true;
|
||||
return totalSamplesRead;
|
||||
}
|
||||
|
||||
_currentSampleOffset = loopRange._startSampleInclusive;
|
||||
continue;
|
||||
} else {
|
||||
// Inside of a loop
|
||||
consecutiveSamplesAvailable = samplesAvailable;
|
||||
}
|
||||
}
|
||||
|
||||
if (consecutiveSamplesAvailable == 0)
|
||||
_terminated = true;
|
||||
else {
|
||||
int samplesDesired = numSamples;
|
||||
if (samplesDesired > consecutiveSamplesAvailable)
|
||||
samplesDesired = consecutiveSamplesAvailable;
|
||||
|
||||
int samplesRead = _baseStream->readBuffer(buffer, samplesDesired);
|
||||
|
||||
if (samplesRead > 0)
|
||||
totalSamplesRead += samplesRead;
|
||||
|
||||
if (samplesRead != samplesDesired)
|
||||
_terminated = true;
|
||||
else {
|
||||
_currentSampleOffset += samplesRead;
|
||||
buffer += samplesRead;
|
||||
numSamples -= samplesRead;
|
||||
|
||||
if (samplesRead == consecutiveSamplesAvailable && terminateIfReadCompletes)
|
||||
_terminated = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool SampleLoopAudioStream::isStereo() const {
|
||||
return _baseStream->isStereo();
|
||||
}
|
||||
|
||||
int SampleLoopAudioStream::getRate() const {
|
||||
return _baseStream->getRate();
|
||||
}
|
||||
|
||||
bool SampleLoopAudioStream::endOfData() const {
|
||||
return _terminated;
|
||||
}
|
||||
|
||||
} // namespace VCruise
|
||||
117
engines/vcruise/sampleloop.h
Normal file
117
engines/vcruise/sampleloop.h
Normal file
@@ -0,0 +1,117 @@
|
||||
/* 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 VCRUISE_SAMPLELOOP_H
|
||||
#define VCRUISE_SAMPLELOOP_H
|
||||
|
||||
#include "common/ptr.h"
|
||||
#include "common/mutex.h"
|
||||
|
||||
#include "audio/audiostream.h"
|
||||
|
||||
namespace Common {
|
||||
|
||||
class ReadStream;
|
||||
|
||||
} // End of namespace Common
|
||||
|
||||
namespace VCruise {
|
||||
|
||||
struct SampleLoop {
|
||||
SampleLoop();
|
||||
|
||||
bool read(Common::ReadStream &stream, uint &availableBytes);
|
||||
|
||||
uint32 identifier;
|
||||
uint32 type;
|
||||
uint32 start;
|
||||
uint32 end;
|
||||
uint32 fraction;
|
||||
uint32 playCount;
|
||||
};
|
||||
|
||||
struct SampleChunk {
|
||||
SampleChunk();
|
||||
|
||||
bool read(Common::ReadStream &stream, uint &availableBytes);
|
||||
|
||||
uint32 manufacturer;
|
||||
uint32 product;
|
||||
uint32 samplePeriod;
|
||||
uint32 midiUnityNote;
|
||||
uint32 midiPitchFraction;
|
||||
uint32 smpteFormat;
|
||||
uint32 smpteOffset;
|
||||
|
||||
// uint32 numSampleLoops;
|
||||
// uint32 sizeOfSamplerData;
|
||||
|
||||
Common::Array<SampleLoop> loops;
|
||||
Common::Array<byte> samplerData;
|
||||
};
|
||||
|
||||
struct SoundLoopInfo {
|
||||
SampleChunk _sampleChunk;
|
||||
|
||||
static Common::SharedPtr<SoundLoopInfo> readFromWaveFile(Common::SeekableReadStream &stream);
|
||||
};
|
||||
|
||||
class SampleLoopAudioStream : public Audio::AudioStream {
|
||||
public:
|
||||
SampleLoopAudioStream(Audio::SeekableAudioStream *baseStream, const SoundLoopInfo *loopInfo);
|
||||
virtual ~SampleLoopAudioStream();
|
||||
|
||||
void stopLooping();
|
||||
|
||||
int readBuffer(int16 *buffer, const int numSamples) override;
|
||||
bool isStereo() const override;
|
||||
int getRate() const override;
|
||||
bool endOfData() const override;
|
||||
|
||||
private:
|
||||
struct LoopRange {
|
||||
LoopRange();
|
||||
|
||||
Audio::Timestamp _restartTimestamp;
|
||||
|
||||
uint _startSampleInclusive;
|
||||
uint _endSampleExclusive;
|
||||
uint _playCount;
|
||||
};
|
||||
|
||||
Common::Mutex _mutex;
|
||||
|
||||
int _currentSampleOffset;
|
||||
int _currentLoop;
|
||||
uint _currentLoopIteration;
|
||||
int _streamFrames;
|
||||
int _streamSamples;
|
||||
bool _terminated;
|
||||
bool _ignoreLoops;
|
||||
|
||||
Common::Array<LoopRange> _loopRanges;
|
||||
|
||||
Audio::SeekableAudioStream *_baseStream;
|
||||
};
|
||||
|
||||
} // End of namespace VCruise
|
||||
|
||||
#endif
|
||||
1715
engines/vcruise/script.cpp
Normal file
1715
engines/vcruise/script.cpp
Normal file
File diff suppressed because it is too large
Load Diff
323
engines/vcruise/script.h
Normal file
323
engines/vcruise/script.h
Normal file
@@ -0,0 +1,323 @@
|
||||
/* 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 VCRUISE_SCRIPT_H
|
||||
#define VCRUISE_SCRIPT_H
|
||||
|
||||
#include "common/array.h"
|
||||
#include "common/hashmap.h"
|
||||
#include "common/path.h"
|
||||
#include "common/ptr.h"
|
||||
#include "common/types.h"
|
||||
|
||||
namespace Common {
|
||||
|
||||
class ReadStream;
|
||||
|
||||
} // End of namespace Common
|
||||
|
||||
namespace VCruise {
|
||||
|
||||
struct ScreenScriptSet;
|
||||
struct RoomScriptSet;
|
||||
struct ScriptSet;
|
||||
struct ITextPreprocessor;
|
||||
|
||||
namespace ScriptOps {
|
||||
|
||||
enum ScriptOp {
|
||||
kInvalid,
|
||||
|
||||
kNumber,
|
||||
|
||||
kRotate,
|
||||
kAngle,
|
||||
kAngleGGet,
|
||||
kSpeed,
|
||||
kSAnimL,
|
||||
kChangeL,
|
||||
kAnimR,
|
||||
kAnimF,
|
||||
kAnimN,
|
||||
kAnimG,
|
||||
kAnimS,
|
||||
kAnim,
|
||||
kStatic,
|
||||
kVarLoad,
|
||||
kVarStore,
|
||||
kVarAddAndStore,
|
||||
kVarGlobalLoad,
|
||||
kVarGlobalStore,
|
||||
kItemCheck,
|
||||
kItemHaveSpace,
|
||||
kItemRemove,
|
||||
kItemHighlightSet,
|
||||
kItemAdd,
|
||||
kItemClear,
|
||||
kSetCursor,
|
||||
kSetRoom,
|
||||
kLMB,
|
||||
kLMB1,
|
||||
kSoundS1,
|
||||
kSoundS2,
|
||||
kSoundS3,
|
||||
kSoundL1,
|
||||
kSoundL2,
|
||||
kSoundL3,
|
||||
k3DSoundS2,
|
||||
k3DSoundL2,
|
||||
k3DSoundL3,
|
||||
kStopAL,
|
||||
kRange,
|
||||
kAddXSound,
|
||||
kClrXSound,
|
||||
kStopSndLA,
|
||||
kStopSndLO,
|
||||
kMusic,
|
||||
kMusicVolRamp,
|
||||
kParm0,
|
||||
kParm1,
|
||||
kParm2,
|
||||
kParm3,
|
||||
kParmG,
|
||||
kSParmX,
|
||||
kSAnimX,
|
||||
kVolumeDn2,
|
||||
kVolumeDn3,
|
||||
kVolumeDn4,
|
||||
kVolumeUp3,
|
||||
kRandom,
|
||||
kDrop,
|
||||
kDup,
|
||||
kSwap,
|
||||
kSay1,
|
||||
kSay2,
|
||||
kSay3,
|
||||
kSay3Get,
|
||||
kSetTimer,
|
||||
kGetTimer,
|
||||
kDelay,
|
||||
kLoSet,
|
||||
kLoGet,
|
||||
kHiSet,
|
||||
kHiGet,
|
||||
|
||||
kNot,
|
||||
kAnd,
|
||||
kOr,
|
||||
kSub,
|
||||
kAdd,
|
||||
kNegate,
|
||||
kCmpEq,
|
||||
kCmpLt,
|
||||
kCmpGt,
|
||||
|
||||
kBitLoad,
|
||||
kBitSet0,
|
||||
kBitSet1,
|
||||
|
||||
kDisc1,
|
||||
kDisc2,
|
||||
kDisc3,
|
||||
|
||||
kGoto,
|
||||
|
||||
kEscOn,
|
||||
kEscOff,
|
||||
kEscGet,
|
||||
kBackStart,
|
||||
kSaveAs,
|
||||
kSave0,
|
||||
kExit,
|
||||
kAllowSaves,
|
||||
|
||||
kAnimName,
|
||||
kValueName,
|
||||
kVarName,
|
||||
kSoundName,
|
||||
kCursorName,
|
||||
kDubbing,
|
||||
|
||||
kCheckValue, // Check if stack top is equal to arg. If it is, pop the argument, otherwise leave it on the stack and skip the next instruction.
|
||||
kJump, // Offset instruction index by arg.
|
||||
|
||||
// Schizm ops
|
||||
kCallFunction,
|
||||
kMusicStop,
|
||||
kMusicPlayScore,
|
||||
kScoreAlways,
|
||||
kScoreNormal,
|
||||
kSndPlay,
|
||||
kSndPlayEx,
|
||||
kSndPlay3D,
|
||||
kSndPlaying,
|
||||
kSndWait,
|
||||
kSndHalt,
|
||||
kSndToBack,
|
||||
kSndStop,
|
||||
kSndStopAll,
|
||||
kSndAddRandom,
|
||||
kSndClearRandom,
|
||||
kVolumeAdd,
|
||||
kVolumeChange,
|
||||
kAnimVolume,
|
||||
kAnimChange,
|
||||
kScreenName,
|
||||
kExtractByte,
|
||||
kInsertByte,
|
||||
kString,
|
||||
kCmpNE,
|
||||
kCmpLE,
|
||||
kCmpGE,
|
||||
kReturn,
|
||||
kSpeech,
|
||||
kSpeechEx,
|
||||
kSpeechTest,
|
||||
kSay,
|
||||
kRandomInclusive,
|
||||
kHeroOut,
|
||||
kHeroGetPos,
|
||||
kHeroSetPos,
|
||||
kHeroGet,
|
||||
kGarbage,
|
||||
kGetRoom,
|
||||
kBitAnd,
|
||||
kBitOr,
|
||||
kAngleGet,
|
||||
kIsCDVersion,
|
||||
kIsDVDVersion,
|
||||
kDisc,
|
||||
kHidePanel,
|
||||
kRotateUpdate,
|
||||
kMul,
|
||||
kDiv,
|
||||
kMod,
|
||||
kGetDigit,
|
||||
kPuzzleInit,
|
||||
kPuzzleCanPress,
|
||||
kPuzzleDoMove1,
|
||||
kPuzzleDoMove2,
|
||||
kPuzzleDone,
|
||||
kPuzzleWhoWon,
|
||||
kFn,
|
||||
kItemHighlightSetTrue,
|
||||
|
||||
// AD2044 ops
|
||||
kAnimT,
|
||||
kAnimForward,
|
||||
kAnimReverse,
|
||||
kAnimKForward,
|
||||
kNoUpdate,
|
||||
kNoClear,
|
||||
kSay1_AD2044,
|
||||
kSay2_AD2044,
|
||||
kSay1Rnd,
|
||||
kM,
|
||||
kEM,
|
||||
kSE,
|
||||
kSDot,
|
||||
kE,
|
||||
kDot,
|
||||
kSound,
|
||||
kISound,
|
||||
kUSound,
|
||||
kSay2K,
|
||||
kSay3K,
|
||||
kRGet,
|
||||
kRSet,
|
||||
kEndRSet,
|
||||
kStop,
|
||||
|
||||
kNumOps,
|
||||
};
|
||||
|
||||
} // End of namespace ScriptOps
|
||||
|
||||
struct Instruction {
|
||||
Instruction();
|
||||
explicit Instruction(ScriptOps::ScriptOp paramOp);
|
||||
Instruction(ScriptOps::ScriptOp paramOp, int32 paramArg);
|
||||
|
||||
ScriptOps::ScriptOp op;
|
||||
int32 arg;
|
||||
};
|
||||
|
||||
struct Script {
|
||||
Common::Array<Instruction> instrs;
|
||||
};
|
||||
|
||||
typedef Common::HashMap<uint, Common::SharedPtr<Script> > ScriptMap_t;
|
||||
typedef Common::HashMap<uint, Common::SharedPtr<ScreenScriptSet> > ScreenScriptSetMap_t;
|
||||
typedef Common::HashMap<uint, Common::SharedPtr<RoomScriptSet> > RoomScriptSetMap_t;
|
||||
typedef Common::HashMap<Common::String, uint> ScreenNameMap_t;
|
||||
|
||||
struct ScreenScriptSet {
|
||||
Common::SharedPtr<Script> entryScript;
|
||||
ScriptMap_t interactionScripts;
|
||||
};
|
||||
|
||||
struct RoomScriptSet {
|
||||
ScreenScriptSetMap_t screenScripts;
|
||||
ScreenNameMap_t screenNames;
|
||||
};
|
||||
|
||||
struct ScriptSet {
|
||||
ScriptSet();
|
||||
|
||||
RoomScriptSetMap_t roomScripts;
|
||||
|
||||
Common::Array<Common::SharedPtr<Script> > functions;
|
||||
Common::Array<Common::String> functionNames;
|
||||
Common::Array<Common::String> strings;
|
||||
};
|
||||
|
||||
struct FunctionDef {
|
||||
Common::String fnName;
|
||||
Common::SharedPtr<Script> func;
|
||||
};
|
||||
|
||||
// Global state is required for Schizm because its preprocessor defines exist across files.
|
||||
// For example, volPortWaves is set in Room01 but used in Room03 and Room20
|
||||
struct IScriptCompilerGlobalState {
|
||||
virtual ~IScriptCompilerGlobalState();
|
||||
|
||||
virtual void define(const Common::String &key, uint roomNumber, int32 value) = 0;
|
||||
virtual bool getDefine(const Common::String &str, uint &outRoomNumber, int32 &outValue) const = 0;
|
||||
|
||||
virtual uint getFunctionIndex(const Common::String &fnName) = 0;
|
||||
virtual void setFunction(uint fnIndex, const Common::SharedPtr<Script> &fn) = 0;
|
||||
|
||||
virtual uint getNumFunctions() const = 0;
|
||||
virtual void dumpFunctionNames(Common::Array<Common::String> &fnNames) const = 0;
|
||||
virtual Common::SharedPtr<Script> getFunction(uint fnIndex) const = 0;
|
||||
};
|
||||
|
||||
Common::SharedPtr<IScriptCompilerGlobalState> createScriptCompilerGlobalState();
|
||||
Common::SharedPtr<ScriptSet> compileReahLogicFile(Common::ReadStream &stream, uint streamSize, const Common::Path &blamePath);
|
||||
Common::SharedPtr<ScriptSet> compileAD2044LogicFile(Common::ReadStream &stream, uint streamSize, const Common::Path &blamePath);
|
||||
|
||||
void compileSchizmLogicFile(ScriptSet &scriptSet, uint loadAsRoom, uint fileRoom, Common::ReadStream &stream, uint streamSize, const Common::Path &blamePath, IScriptCompilerGlobalState *gs);
|
||||
bool checkSchizmLogicForDuplicatedRoom(Common::ReadStream &stream, uint streamSize);
|
||||
void optimizeScriptSet(ScriptSet &scriptSet);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
306
engines/vcruise/textparser.cpp
Normal file
306
engines/vcruise/textparser.cpp
Normal file
@@ -0,0 +1,306 @@
|
||||
/* 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 "common/path.h"
|
||||
#include "common/stream.h"
|
||||
#include "common/textconsole.h"
|
||||
|
||||
#include "vcruise/textparser.h"
|
||||
|
||||
namespace VCruise {
|
||||
|
||||
TextParserState::TextParserState() : _lineNum(1), _col(1), _prevWasCR(false), _isParsingComment(false) {
|
||||
}
|
||||
|
||||
|
||||
TextParser::TextParser(Common::ReadStream *stream) : _stream(stream), _returnedBufferPos(kReturnedBufferSize) {
|
||||
memset(_returnedBuffer, 0, kReturnedBufferSize);
|
||||
}
|
||||
|
||||
bool TextParser::readOneChar(char &outC, TextParserState &outState) {
|
||||
if (_returnedBufferPos == kReturnedBufferSize) {
|
||||
if (_stream->eos())
|
||||
return false;
|
||||
}
|
||||
|
||||
char c = 0;
|
||||
|
||||
if (_returnedBufferPos != kReturnedBufferSize) {
|
||||
c = _returnedBuffer[_returnedBufferPos++];
|
||||
} else {
|
||||
if (!_stream->read(&c, 1))
|
||||
return false;
|
||||
}
|
||||
|
||||
TextParserState prevState = _state;
|
||||
|
||||
if (c == '\r') {
|
||||
_state._lineNum++;
|
||||
_state._col = 1;
|
||||
_state._isParsingComment = false;
|
||||
_state._prevWasCR = true;
|
||||
} else if (c == '\n') {
|
||||
if (!_state._prevWasCR) {
|
||||
_state._lineNum++;
|
||||
_state._col = 1;
|
||||
}
|
||||
_state._prevWasCR = false;
|
||||
} else {
|
||||
_state._col++;
|
||||
_state._prevWasCR = false;
|
||||
|
||||
if (c == ';')
|
||||
_state._isParsingComment = true;
|
||||
}
|
||||
|
||||
|
||||
outC = c;
|
||||
outState = prevState;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TextParser::skipWhitespaceAndComments(char &outC, TextParserState &outState) {
|
||||
char c = 0;
|
||||
TextParserState firstCharState;
|
||||
|
||||
while (readOneChar(c, firstCharState)) {
|
||||
if (isWhitespace(c))
|
||||
continue;
|
||||
|
||||
if (_state._isParsingComment)
|
||||
continue;
|
||||
|
||||
outC = c;
|
||||
outState = firstCharState;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TextParser::isDelimiter(char c) {
|
||||
if (c == ',' || c == '=' || c == '[' || c == ']')
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TextParser::isCompoundDelimiter(char c1, char c2) {
|
||||
if (c2 == '=' && (c1 == '=' || c1 == '<' || c1 == '>' || c1 == '!'))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TextParser::isWhitespace(char c) {
|
||||
return (c == ' ') || ((c & 0xe0) == 0);
|
||||
}
|
||||
|
||||
void TextParser::requeue(const char *chars, uint numChars, const TextParserState &state) {
|
||||
_state = state;
|
||||
assert(_returnedBufferPos >= numChars);
|
||||
_returnedBufferPos -= numChars;
|
||||
memcpy(_returnedBuffer + _returnedBufferPos, chars, numChars);
|
||||
}
|
||||
|
||||
void TextParser::requeue(const Common::String &str, const TextParserState &state) {
|
||||
requeue(str.c_str(), str.size(), state);
|
||||
}
|
||||
|
||||
void TextParser::expectToken(Common::String &outToken, const Common::Path &blamePath) {
|
||||
TextParserState state;
|
||||
expectTokenInternal(outToken, blamePath, state);
|
||||
}
|
||||
|
||||
void TextParser::expectShort(int16 &outInt, const Common::Path &blamePath) {
|
||||
int i;
|
||||
expectInt(i, blamePath);
|
||||
outInt = static_cast<int16>(i);
|
||||
}
|
||||
|
||||
void TextParser::expectInt(int &outInt, const Common::Path &blamePath) {
|
||||
Common::String token;
|
||||
TextParserState state;
|
||||
expectTokenInternal(token, blamePath, state);
|
||||
|
||||
if (!sscanf(token.c_str(), "%i", &outInt))
|
||||
error("Parsing error in '%s' at line %i col %i: Integer was malformed", blamePath.toString(Common::Path::kNativeSeparator).c_str(), static_cast<int>(state._lineNum), static_cast<int>(state._col));
|
||||
}
|
||||
|
||||
void TextParser::expectUInt(uint &outUInt, const Common::Path &blamePath) {
|
||||
Common::String token;
|
||||
TextParserState state;
|
||||
expectTokenInternal(token, blamePath, state);
|
||||
|
||||
if (!sscanf(token.c_str(), "%u", &outUInt))
|
||||
error("Parsing error in '%s' at line %i col %i: Unsigned integer was malformed", blamePath.toString(Common::Path::kNativeSeparator).c_str(), static_cast<int>(state._lineNum), static_cast<int>(state._col));
|
||||
}
|
||||
|
||||
void TextParser::expectLine(Common::String &outToken, const Common::Path &blamePath, bool continueToNextLine) {
|
||||
outToken.clear();
|
||||
|
||||
char c = 0;
|
||||
TextParserState state;
|
||||
|
||||
bool isSkippingWhitespace = true;
|
||||
uint nonWhitespaceLength = 0;
|
||||
|
||||
while (readOneChar(c, state)) {
|
||||
if (c == '\r' || c == '\n' || _state._isParsingComment) {
|
||||
requeue(&c, 1, state);
|
||||
if (continueToNextLine)
|
||||
skipToEOL();
|
||||
break;
|
||||
}
|
||||
|
||||
bool cIsWhitespace = isWhitespace(c);
|
||||
if (isSkippingWhitespace) {
|
||||
if (cIsWhitespace)
|
||||
continue;
|
||||
isSkippingWhitespace = false;
|
||||
}
|
||||
|
||||
outToken += c;
|
||||
if (!cIsWhitespace)
|
||||
nonWhitespaceLength = outToken.size();
|
||||
}
|
||||
|
||||
if (nonWhitespaceLength != outToken.size())
|
||||
outToken = outToken.substr(0, nonWhitespaceLength);
|
||||
}
|
||||
|
||||
void TextParser::expect(const char *str, const Common::Path &blamePath) {
|
||||
Common::String token;
|
||||
TextParserState state;
|
||||
expectTokenInternal(token, blamePath, state);
|
||||
|
||||
if (token != str)
|
||||
error("Parsing error in '%s' at line %i col %i: Expected token '%s' but found '%s'", blamePath.toString(Common::Path::kNativeSeparator).c_str(), static_cast<int>(state._lineNum), static_cast<int>(state._col), str, token.c_str());
|
||||
}
|
||||
|
||||
void TextParser::skipToEOL() {
|
||||
char c = 0;
|
||||
TextParserState state;
|
||||
|
||||
while (readOneChar(c, state)) {
|
||||
if (c == '\n')
|
||||
return;
|
||||
|
||||
if (c == '\r') {
|
||||
if (readOneChar(c, state)) {
|
||||
if (c != '\n')
|
||||
requeue(&c, 1, state);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool TextParser::checkEOL() {
|
||||
char c = 0;
|
||||
TextParserState state;
|
||||
|
||||
for (;;) {
|
||||
if (!readOneChar(c, state))
|
||||
return true;
|
||||
|
||||
if (_state._isParsingComment || c == '\n' || c == '\r') {
|
||||
// EOL or comment
|
||||
requeue(&c, 1, state);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!isWhitespace(c)) {
|
||||
// Non-whitespace
|
||||
requeue(&c, 1, state);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TextParser::expectTokenInternal(Common::String &outToken, const Common::Path &blamePath, TextParserState &outState) {
|
||||
if (!parseToken(outToken, outState))
|
||||
error("Parsing error in '%s' unexpected end of file", blamePath.toString(Common::Path::kNativeSeparator).c_str());
|
||||
}
|
||||
|
||||
bool TextParser::parseToken(Common::String &outString, TextParserState &outState) {
|
||||
outString.clear();
|
||||
|
||||
char c = 0;
|
||||
TextParserState state;
|
||||
|
||||
if (!skipWhitespaceAndComments(c, state))
|
||||
return false;
|
||||
|
||||
outState = state;
|
||||
|
||||
outString += c;
|
||||
|
||||
if (c == '\"') {
|
||||
while (readOneChar(c, state)) {
|
||||
if (c == '\n' || c == '\r') {
|
||||
requeue(&c, 1, state);
|
||||
return true;
|
||||
}
|
||||
|
||||
outString += c;
|
||||
if (c == '\"')
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (isDelimiter(c)) {
|
||||
char firstC = c;
|
||||
if (readOneChar(c, state)) {
|
||||
if (isCompoundDelimiter(firstC, c))
|
||||
outString += c;
|
||||
else
|
||||
requeue(&c, 1, state);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
while (readOneChar(c, state)) {
|
||||
if (isWhitespace(c) || _state._isParsingComment) {
|
||||
requeue(&c, 1, state);
|
||||
break;
|
||||
}
|
||||
|
||||
if (outString.size() == 1 && isCompoundDelimiter(outString[0], c)) {
|
||||
outString += c;
|
||||
break;
|
||||
}
|
||||
|
||||
if (isDelimiter(c)) {
|
||||
requeue(&c, 1, state);
|
||||
break;
|
||||
}
|
||||
|
||||
outString += c;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // End of namespace VCruise
|
||||
90
engines/vcruise/textparser.h
Normal file
90
engines/vcruise/textparser.h
Normal file
@@ -0,0 +1,90 @@
|
||||
/* 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 VCRUISE_TEXTPARSER_H
|
||||
#define VCRUISE_TEXTPARSER_H
|
||||
|
||||
#include "common/hashmap.h"
|
||||
#include "common/hash-str.h"
|
||||
#include "common/str.h"
|
||||
#include "common/memstream.h"
|
||||
|
||||
namespace Common {
|
||||
|
||||
class Path;
|
||||
class ReadStream;
|
||||
|
||||
} // End of namespace Common
|
||||
|
||||
namespace VCruise {
|
||||
|
||||
struct TextParserState {
|
||||
TextParserState();
|
||||
|
||||
uint _lineNum;
|
||||
uint _col;
|
||||
bool _prevWasCR;
|
||||
bool _isParsingComment;
|
||||
};
|
||||
|
||||
class TextParser {
|
||||
public:
|
||||
explicit TextParser(Common::ReadStream *stream);
|
||||
|
||||
bool parseToken(Common::String &outString, TextParserState &outState);
|
||||
|
||||
bool readOneChar(char &outC, TextParserState &outState);
|
||||
bool skipWhitespaceAndComments(char &outC, TextParserState &outState);
|
||||
|
||||
void requeue(const char *chars, uint numChars, const TextParserState &state);
|
||||
void requeue(const Common::String &str, const TextParserState &state);
|
||||
|
||||
void expectToken(Common::String &outToken, const Common::Path &blamePath);
|
||||
void expectShort(int16 &outInt, const Common::Path &blamePath);
|
||||
void expectInt(int &outInt, const Common::Path &blamePath);
|
||||
void expectUInt(uint &outUInt, const Common::Path &blamePath);
|
||||
void expectLine(Common::String &outToken, const Common::Path &blamePath, bool continueToNextLine);
|
||||
|
||||
void expect(const char *str, const Common::Path &blamePath);
|
||||
|
||||
void skipToEOL();
|
||||
bool checkEOL();
|
||||
|
||||
private:
|
||||
void expectTokenInternal(Common::String &outToken, const Common::Path &blamePath, TextParserState &outState);
|
||||
|
||||
static bool isDelimiter(char c);
|
||||
static bool isCompoundDelimiter(char c1, char c2);
|
||||
static bool isWhitespace(char c);
|
||||
|
||||
TextParserState _state;
|
||||
|
||||
Common::ReadStream *_stream;
|
||||
|
||||
static const uint kReturnedBufferSize = 8;
|
||||
|
||||
char _returnedBuffer[kReturnedBufferSize];
|
||||
uint _returnedBufferPos;
|
||||
};
|
||||
|
||||
} // End of namespace VCruise
|
||||
|
||||
#endif
|
||||
497
engines/vcruise/vcruise.cpp
Normal file
497
engines/vcruise/vcruise.cpp
Normal file
@@ -0,0 +1,497 @@
|
||||
/* 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 "engines/util.h"
|
||||
|
||||
#include "common/compression/gentee_installer.h"
|
||||
|
||||
#include "common/config-manager.h"
|
||||
#include "common/events.h"
|
||||
#include "common/file.h"
|
||||
#include "common/stream.h"
|
||||
#include "common/savefile.h"
|
||||
#include "common/system.h"
|
||||
#include "common/algorithm.h"
|
||||
#include "common/translation.h"
|
||||
|
||||
#include "audio/mididrv.h"
|
||||
#include "audio/mixer.h"
|
||||
|
||||
#include "gui/message.h"
|
||||
|
||||
#include "vcruise/runtime.h"
|
||||
#include "vcruise/vcruise.h"
|
||||
|
||||
namespace VCruise {
|
||||
|
||||
VCruiseEngine::VCruiseEngine(OSystem *syst, const VCruiseGameDescription *gameDesc) : Engine(syst), _gameDescription(gameDesc) {
|
||||
const Common::FSNode gameDataDir(ConfMan.getPath("path"));
|
||||
}
|
||||
|
||||
VCruiseEngine::~VCruiseEngine() {
|
||||
}
|
||||
|
||||
void VCruiseEngine::handleEvents() {
|
||||
Common::Event evt;
|
||||
Common::EventManager *eventMan = _system->getEventManager();
|
||||
|
||||
while (eventMan->pollEvent(evt)) {
|
||||
switch (evt.type) {
|
||||
case Common::EVENT_LBUTTONDOWN:
|
||||
_runtime->onLButtonDown(evt.mouse.x, evt.mouse.y);
|
||||
break;
|
||||
case Common::EVENT_LBUTTONUP:
|
||||
_runtime->onLButtonUp(evt.mouse.x, evt.mouse.y);
|
||||
break;
|
||||
case Common::EVENT_MOUSEMOVE:
|
||||
_runtime->onMouseMove(evt.mouse.x, evt.mouse.y);
|
||||
break;
|
||||
case Common::EVENT_CUSTOM_ENGINE_ACTION_START:
|
||||
_runtime->onKeymappedEvent(static_cast<VCruise::KeymappedEvent>(evt.customType));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VCruiseEngine::staticHandleMidiTimer(void *refCon) {
|
||||
static_cast<VCruiseEngine *>(refCon)->handleMidiTimer();
|
||||
}
|
||||
|
||||
void VCruiseEngine::handleMidiTimer() {
|
||||
_runtime->onMidiTimer();
|
||||
}
|
||||
|
||||
Common::Error VCruiseEngine::run() {
|
||||
#if !defined(USE_JPEG)
|
||||
if (_gameDescription->desc.flags & VCRUISE_GF_NEED_JPEG) {
|
||||
return Common::Error(Common::kUnknownError, _s("This game requires JPEG support, which was not compiled in."));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(USE_OGG) || !defined(USE_VORBIS)
|
||||
if (_gameDescription->desc.flags & VCRUISE_GF_WANT_OGG_VORBIS) {
|
||||
GUI::MessageDialog dialog(
|
||||
_("Music for this game requires Ogg Vorbis support, which was not compiled in.\n"
|
||||
"The game will still play, but will not have any music."));
|
||||
dialog.runModal();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(USE_MAD)
|
||||
if (_gameDescription->desc.flags & VCRUISE_GF_WANT_MP3) {
|
||||
GUI::MessageDialog dialog(
|
||||
_("Music for this game requires MP3 support, which was not compiled in.\n"
|
||||
"The game will still play, but will not have any music."));
|
||||
dialog.runModal();
|
||||
}
|
||||
#endif
|
||||
|
||||
Common::ScopedPtr<MidiDriver> midiDrv;
|
||||
if (_gameDescription->gameID == GID_AD2044) {
|
||||
MidiDriver::DeviceHandle midiDevHdl = MidiDriver::detectDevice(MDT_MIDI | MDT_ADLIB | MDT_PREFER_GM);
|
||||
if (midiDevHdl) {
|
||||
midiDrv.reset(MidiDriver::createMidi(midiDevHdl));
|
||||
|
||||
if (midiDrv->open() != 0)
|
||||
midiDrv.reset();
|
||||
}
|
||||
}
|
||||
|
||||
if (_gameDescription->desc.flags & VCRUISE_GF_GENTEE_PACKAGE) {
|
||||
Common::File *f = new Common::File();
|
||||
|
||||
if (!f->open(_gameDescription->desc.filesDescriptions[0].fileName))
|
||||
error("Couldn't open installer package '%s'", _gameDescription->desc.filesDescriptions[0].fileName);
|
||||
|
||||
Common::Archive *installerPackageArchive = Common::createGenteeInstallerArchive(f, "#setuppath#/", false, true);
|
||||
if (!installerPackageArchive)
|
||||
error("Couldn't load installer package '%s'", _gameDescription->desc.filesDescriptions[0].fileName);
|
||||
|
||||
SearchMan.add("VCruiseInstallerPackage", installerPackageArchive);
|
||||
}
|
||||
|
||||
if (_gameDescription->desc.flags & VCRUISE_GF_USE_SETUP_EXE) {
|
||||
Common::File *f = new Common::File();
|
||||
|
||||
if (!f->open(_gameDescription->desc.filesDescriptions[1].fileName))
|
||||
error("Couldn't open installer package '%s'", _gameDescription->desc.filesDescriptions[1].fileName);
|
||||
|
||||
Common::Archive *setupPackageArchive = Common::createGenteeInstallerArchive(f, "#setuppath#/", true, true);
|
||||
if (!setupPackageArchive)
|
||||
error("Couldn't load installer package '%s'", _gameDescription->desc.filesDescriptions[1].fileName);
|
||||
|
||||
SearchMan.add("VCruiseSetupPackage", setupPackageArchive);
|
||||
}
|
||||
|
||||
syncSoundSettings();
|
||||
|
||||
// Figure out screen layout
|
||||
Common::Point size;
|
||||
|
||||
if (_gameDescription->gameID == GID_AD2044) {
|
||||
size = Common::Point(640, 480);
|
||||
|
||||
Common::Point traySize = Common::Point(640, 97);
|
||||
Common::Point menuBarSize = Common::Point(188, 102);
|
||||
Common::Point videoTL = Common::Point(20, 21);
|
||||
|
||||
Common::Point videoSize = Common::Point(432, 307);
|
||||
|
||||
_menuBarRect = Common::Rect(size.x - menuBarSize.x, 0, size.x, menuBarSize.y);
|
||||
_videoRect = Common::Rect(videoTL, videoTL + videoSize);
|
||||
_trayRect = Common::Rect(0, size.y - traySize.y, size.x, size.y);
|
||||
_subtitleRect = Common::Rect(_videoRect.left, _videoRect.bottom, _videoRect.right, _trayRect.top);
|
||||
} else {
|
||||
Common::Point videoSize;
|
||||
Common::Point traySize;
|
||||
Common::Point menuBarSize;
|
||||
|
||||
if (_gameDescription->gameID == GID_REAH) {
|
||||
videoSize = Common::Point(608, 348);
|
||||
menuBarSize = Common::Point(640, 44);
|
||||
traySize = Common::Point(640, 88);
|
||||
} else if (_gameDescription->gameID == GID_SCHIZM) {
|
||||
videoSize = Common::Point(640, 360);
|
||||
menuBarSize = Common::Point(640, 32);
|
||||
traySize = Common::Point(640, 88);
|
||||
} else {
|
||||
error("Unknown game");
|
||||
}
|
||||
|
||||
size.x = videoSize.x;
|
||||
if (menuBarSize.x > size.x)
|
||||
size.x = menuBarSize.x;
|
||||
if (traySize.x > size.x)
|
||||
size.x = traySize.x;
|
||||
|
||||
size.y = videoSize.y + menuBarSize.y + traySize.y;
|
||||
|
||||
Common::Point menuTL = Common::Point((size.x - menuBarSize.x) / 2, 0);
|
||||
Common::Point videoTL = Common::Point((size.x - videoSize.x) / 2, menuTL.y + menuBarSize.y);
|
||||
Common::Point trayTL = Common::Point((size.x - traySize.x) / 2, videoTL.y + videoSize.y);
|
||||
|
||||
_menuBarRect = Common::Rect(menuTL.x, menuTL.y, menuTL.x + menuBarSize.x, menuTL.y + menuBarSize.y);
|
||||
_videoRect = Common::Rect(videoTL.x, videoTL.y, videoTL.x + videoSize.x, videoTL.y + videoSize.y);
|
||||
_trayRect = Common::Rect(trayTL.x, trayTL.y, trayTL.x + traySize.x, trayTL.y + traySize.y);
|
||||
}
|
||||
|
||||
// TODO: Optionally support CLUT8 for AD 2044
|
||||
initGraphics(size.x, size.y, nullptr);
|
||||
if (_system->getScreenFormat().isCLUT8())
|
||||
return Common::kUnsupportedColorMode;
|
||||
|
||||
_system->fillScreen(0);
|
||||
|
||||
_runtime.reset(new Runtime(_system, _mixer, midiDrv.get(), _rootFSNode, _gameDescription->gameID, _gameDescription->defaultLanguage));
|
||||
_runtime->initSections(_videoRect, _menuBarRect, _trayRect, _subtitleRect, Common::Rect(640, 480), _system->getScreenFormat());
|
||||
|
||||
if (midiDrv)
|
||||
midiDrv->setTimerCallback(this, VCruiseEngine::staticHandleMidiTimer);
|
||||
|
||||
const char *exeName = _gameDescription->desc.filesDescriptions[0].fileName;
|
||||
|
||||
if (_gameDescription->desc.flags & VCRUISE_GF_GENTEE_PACKAGE)
|
||||
exeName = "Schizm.exe";
|
||||
|
||||
_runtime->loadCursors(exeName);
|
||||
|
||||
if (ConfMan.getBool("vcruise_debug")) {
|
||||
_runtime->setDebugMode(true);
|
||||
}
|
||||
|
||||
if (ConfMan.getBool("vcruise_fast_animations")) {
|
||||
_runtime->setFastAnimationMode(true);
|
||||
}
|
||||
|
||||
if (ConfMan.getBool("vcruise_preload_sounds")) {
|
||||
_runtime->setPreloadSounds(true);
|
||||
}
|
||||
|
||||
if (ConfMan.getBool("vcruise_use_4bit")) {
|
||||
_runtime->setLowQualityGraphicsMode(true);
|
||||
}
|
||||
|
||||
if (ConfMan.hasKey("save_slot")) {
|
||||
int saveSlot = ConfMan.getInt("save_slot");
|
||||
if (saveSlot >= 0) {
|
||||
(void)_runtime->bootGame(false);
|
||||
|
||||
Common::Error err = loadGameState(saveSlot);
|
||||
if (err.getCode() != Common::kNoError)
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
// Run the game
|
||||
while (!shouldQuit()) {
|
||||
handleEvents();
|
||||
|
||||
if (!_runtime->runFrame())
|
||||
break;
|
||||
|
||||
_runtime->drawFrame();
|
||||
_system->delayMillis(5);
|
||||
}
|
||||
|
||||
|
||||
if (midiDrv)
|
||||
midiDrv->setTimerCallback(nullptr, nullptr);
|
||||
|
||||
_runtime.reset();
|
||||
|
||||
if (midiDrv)
|
||||
midiDrv->close();
|
||||
|
||||
if (_gameDescription->desc.flags & VCRUISE_GF_GENTEE_PACKAGE)
|
||||
SearchMan.remove("VCruiseInstallerPackage");
|
||||
|
||||
// Flush any settings changes made in-game
|
||||
ConfMan.flushToDisk();
|
||||
|
||||
return Common::kNoError;
|
||||
}
|
||||
|
||||
void VCruiseEngine::pauseEngineIntern(bool pause) {
|
||||
Engine::pauseEngineIntern(pause);
|
||||
}
|
||||
|
||||
bool VCruiseEngine::hasFeature(EngineFeature f) const {
|
||||
switch (f) {
|
||||
case kSupportsReturnToLauncher:
|
||||
case kSupportsSavingDuringRuntime:
|
||||
case kSupportsLoadingDuringRuntime:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
void VCruiseEngine::syncSoundSettings() {
|
||||
// Sync the engine with the config manager
|
||||
int soundVolumeMusic = ConfMan.getInt("music_volume");
|
||||
int soundVolumeSFX = ConfMan.getInt("sfx_volume");
|
||||
int soundVolumeSpeech = ConfMan.getInt("speech_volume");
|
||||
|
||||
bool mute = false;
|
||||
if (ConfMan.hasKey("mute"))
|
||||
mute = ConfMan.getBool("mute");
|
||||
|
||||
// We need to handle the speech mute separately here. This is because the
|
||||
// engine code should be able to rely on all speech sounds muted when the
|
||||
// user specified subtitles only mode, which results in "speech_mute" to
|
||||
// be set to "true". The global mute setting has precedence over the
|
||||
// speech mute setting though.
|
||||
bool speechMute = mute;
|
||||
if (!speechMute)
|
||||
speechMute = ConfMan.getBool("speech_mute");
|
||||
|
||||
bool muteSound = ConfMan.getBool("vcruise_mute_sound");
|
||||
if (ConfMan.hasKey("vcruise_mute_sound"))
|
||||
muteSound = ConfMan.getBool("vcruise_mute_sound");
|
||||
|
||||
// We don't mute music here because Schizm has a special behavior that bypasses music mute when using one
|
||||
// of the ships to transition zones.
|
||||
_mixer->muteSoundType(Audio::Mixer::kPlainSoundType, mute || muteSound);
|
||||
_mixer->muteSoundType(Audio::Mixer::kMusicSoundType, mute);
|
||||
_mixer->muteSoundType(Audio::Mixer::kSFXSoundType, mute || muteSound);
|
||||
_mixer->muteSoundType(Audio::Mixer::kSpeechSoundType, speechMute || muteSound);
|
||||
|
||||
_mixer->setVolumeForSoundType(Audio::Mixer::kPlainSoundType, Audio::Mixer::kMaxMixerVolume);
|
||||
_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, soundVolumeMusic);
|
||||
_mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, soundVolumeSFX);
|
||||
_mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, soundVolumeSpeech);
|
||||
}
|
||||
|
||||
Common::Error VCruiseEngine::saveGameStream(Common::WriteStream *stream, bool isAutosave) {
|
||||
_runtime->saveGame(stream);
|
||||
|
||||
if (stream->err())
|
||||
return Common::Error(Common::kWritingFailed);
|
||||
|
||||
return Common::Error(Common::kNoError);
|
||||
}
|
||||
|
||||
Common::Error VCruiseEngine::loadGameStream(Common::SeekableReadStream *stream) {
|
||||
LoadGameOutcome loadGameOutcome = _runtime->loadGame(stream);
|
||||
|
||||
switch (loadGameOutcome) {
|
||||
case kLoadGameOutcomeSucceeded:
|
||||
return Common::Error(Common::kNoError);
|
||||
case kLoadGameOutcomeSaveDataCorrupted: {
|
||||
GUI::MessageDialog dialog(_("Failed to load save, the save data appears to be damaged."));
|
||||
dialog.runModal();
|
||||
}
|
||||
return Common::Error(Common::kReadingFailed);
|
||||
case kLoadGameOutcomeMissingVersion: {
|
||||
GUI::MessageDialog dialog(_("Failed to read version information from save file."));
|
||||
dialog.runModal();
|
||||
}
|
||||
return Common::Error(Common::kReadingFailed);
|
||||
case kLoadGameOutcomeInvalidVersion: {
|
||||
GUI::MessageDialog dialog(_("Failed to load save, the save file doesn't contain valid version information."));
|
||||
dialog.runModal();
|
||||
}
|
||||
return Common::Error(Common::kReadingFailed);
|
||||
case kLoadGameOutcomeSaveIsTooNew: {
|
||||
GUI::MessageDialog dialog(_("Saved game was created with a newer version of ScummVM. Unable to load."));
|
||||
dialog.runModal();
|
||||
}
|
||||
return Common::Error(Common::kReadingFailed);
|
||||
case kLoadGameOutcomeSaveIsTooOld: {
|
||||
GUI::MessageDialog dialog(_("Saved game was created with an earlier, incompatible version of ScummVM. Unable to load."));
|
||||
dialog.runModal();
|
||||
}
|
||||
return Common::Error(Common::kReadingFailed);
|
||||
default: {
|
||||
GUI::MessageDialog dialog(_("An unknown error occurred while attempting to load the saved game."));
|
||||
dialog.runModal();
|
||||
}
|
||||
return Common::Error(Common::kReadingFailed);
|
||||
};
|
||||
|
||||
return Common::Error(Common::kNoError);
|
||||
}
|
||||
|
||||
bool VCruiseEngine::canSaveAutosaveCurrently() {
|
||||
return _runtime->canSave(false);
|
||||
}
|
||||
|
||||
bool VCruiseEngine::canSaveGameStateCurrently(Common::U32String *msg) {
|
||||
return _runtime->canSave(false);
|
||||
}
|
||||
|
||||
bool VCruiseEngine::canLoadGameStateCurrently(Common::U32String *msg) {
|
||||
return _runtime->canLoad();
|
||||
}
|
||||
|
||||
void VCruiseEngine::initializePath(const Common::FSNode &gamePath) {
|
||||
Engine::initializePath(gamePath);
|
||||
|
||||
const char *gameSubPath = nullptr;
|
||||
|
||||
if (_gameDescription->desc.flags & VCRUISE_GF_GENTEE_PACKAGE) {
|
||||
if (_gameDescription->gameID == GID_SCHIZM)
|
||||
gameSubPath = "Schizm";
|
||||
}
|
||||
|
||||
if (gameSubPath) {
|
||||
const int kNumCasePasses = 3;
|
||||
|
||||
for (int casePass = 0; casePass < kNumCasePasses; casePass++) {
|
||||
Common::String subPathStr(gameSubPath);
|
||||
|
||||
if (casePass == 1)
|
||||
subPathStr.toUppercase();
|
||||
else if (casePass == 2)
|
||||
subPathStr.toLowercase();
|
||||
|
||||
Common::FSNode gameSubDir = gamePath.getChild(subPathStr);
|
||||
if (gameSubDir.isDirectory()) {
|
||||
SearchMan.addDirectory("VCruiseGameDir", gameSubDir, 0, 3);
|
||||
break;
|
||||
}
|
||||
|
||||
if (casePass != kNumCasePasses - 1)
|
||||
warning("Expected to find subpath '%s' in the game directory but couldn't find it", gameSubPath);
|
||||
}
|
||||
}
|
||||
|
||||
_rootFSNode = gamePath;
|
||||
}
|
||||
|
||||
bool VCruiseEngine::hasDefaultSave() {
|
||||
return hasAnySave();
|
||||
}
|
||||
|
||||
bool VCruiseEngine::hasAnySave() {
|
||||
Common::StringArray saveFiles = getSaveFileManager()->listSavefiles(_targetName + ".*");
|
||||
return saveFiles.size() > 0;
|
||||
}
|
||||
|
||||
Common::Error VCruiseEngine::loadMostRecentSave() {
|
||||
Common::SaveFileManager *sfm = getSaveFileManager();
|
||||
|
||||
Common::StringArray saveFiles = sfm->listSavefiles(_targetName + ".*");
|
||||
|
||||
uint64 highestDateTime = 0;
|
||||
uint32 highestPlayTime = 0;
|
||||
Common::String highestSaveFileName;
|
||||
|
||||
for (const Common::String &saveFileName : saveFiles) {
|
||||
Common::InSaveFile *saveFile = sfm->openForLoading(saveFileName);
|
||||
|
||||
if (!saveFile) {
|
||||
warning("Couldn't load save file '%s' to determine recency", saveFileName.c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
ExtendedSavegameHeader header;
|
||||
bool loadedHeader = getMetaEngine()->readSavegameHeader(saveFile, &header, true);
|
||||
if (!loadedHeader) {
|
||||
warning("Couldn't parse header from '%s'", saveFileName.c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
uint8 day = 0;
|
||||
uint8 month = 0;
|
||||
uint16 year = 0;
|
||||
|
||||
uint8 hour = 0;
|
||||
uint8 minute = 0;
|
||||
|
||||
MetaEngine::decodeSavegameDate(&header, year, month, day);
|
||||
MetaEngine::decodeSavegameTime(&header, hour, minute);
|
||||
|
||||
uint64 dateTime = static_cast<uint64>(year) << 32;
|
||||
dateTime |= static_cast<uint64>(month) << 24;
|
||||
dateTime |= static_cast<uint64>(day) << 16;
|
||||
dateTime |= static_cast<uint64>(hour) << 8;
|
||||
dateTime |= minute;
|
||||
|
||||
uint32 playTime = header.playtime;
|
||||
|
||||
if (dateTime > highestDateTime || (dateTime == highestDateTime && playTime > highestPlayTime)) {
|
||||
highestSaveFileName = saveFileName;
|
||||
highestDateTime = dateTime;
|
||||
highestPlayTime = playTime;
|
||||
}
|
||||
}
|
||||
|
||||
if (highestSaveFileName.empty()) {
|
||||
warning("Couldn't find any valid saves to load");
|
||||
return Common::Error(Common::kReadingFailed);
|
||||
}
|
||||
|
||||
Common::String slotStr = highestSaveFileName.substr(_targetName.size() + 1);
|
||||
|
||||
int slot = 0;
|
||||
if (sscanf(slotStr.c_str(), "%i", &slot) != 1) {
|
||||
warning("Couldn't parse save slot ID from %s", highestSaveFileName.c_str());
|
||||
return Common::Error(Common::kReadingFailed);
|
||||
}
|
||||
|
||||
return loadGameState(slot);
|
||||
}
|
||||
|
||||
|
||||
} // End of namespace VCruise
|
||||
90
engines/vcruise/vcruise.h
Normal file
90
engines/vcruise/vcruise.h
Normal file
@@ -0,0 +1,90 @@
|
||||
/* 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 VCRUISE_H
|
||||
#define VCRUISE_H
|
||||
|
||||
#include "engines/engine.h"
|
||||
#include "common/rect.h"
|
||||
|
||||
#include "vcruise/runtime.h"
|
||||
#include "vcruise/detection.h"
|
||||
|
||||
/**
|
||||
* This is the namespace of the V-Cruise engine.
|
||||
*
|
||||
* Status of this engine: ???
|
||||
*
|
||||
* Games using this engine:
|
||||
* - Reah: Face the Unknown
|
||||
* - Schizm: Mysterious Journey
|
||||
*/
|
||||
namespace VCruise {
|
||||
|
||||
class VCruiseEngine : public ::Engine {
|
||||
protected:
|
||||
// Engine APIs
|
||||
Common::Error run() override;
|
||||
|
||||
public:
|
||||
VCruiseEngine(OSystem *syst, const VCruiseGameDescription *gameDesc);
|
||||
~VCruiseEngine() override;
|
||||
|
||||
bool hasFeature(EngineFeature f) const override;
|
||||
void syncSoundSettings() override;
|
||||
|
||||
const VCruiseGameDescription *_gameDescription;
|
||||
|
||||
Common::Error saveGameStream(Common::WriteStream *stream, bool isAutosave) override;
|
||||
Common::Error loadGameStream(Common::SeekableReadStream *stream) override;
|
||||
|
||||
bool canSaveAutosaveCurrently() override;
|
||||
bool canSaveGameStateCurrently(Common::U32String *msg = nullptr) override;
|
||||
bool canLoadGameStateCurrently(Common::U32String *msg = nullptr) override;
|
||||
|
||||
void initializePath(const Common::FSNode &gamePath) override;
|
||||
|
||||
bool hasDefaultSave();
|
||||
bool hasAnySave();
|
||||
|
||||
Common::Error loadMostRecentSave();
|
||||
|
||||
protected:
|
||||
void pauseEngineIntern(bool pause) override;
|
||||
|
||||
private:
|
||||
void handleEvents();
|
||||
static void staticHandleMidiTimer(void *refCon);
|
||||
void handleMidiTimer();
|
||||
|
||||
Common::Rect _videoRect;
|
||||
Common::Rect _menuBarRect;
|
||||
Common::Rect _trayRect;
|
||||
Common::Rect _subtitleRect;
|
||||
|
||||
Common::FSNode _rootFSNode;
|
||||
|
||||
Common::SharedPtr<Runtime> _runtime;
|
||||
};
|
||||
|
||||
} // End of namespace VCruise
|
||||
|
||||
#endif /* VCRUISE_H */
|
||||
Reference in New Issue
Block a user