Initial commit
This commit is contained in:
1
engines/cryomni3d/POTFILES
Normal file
1
engines/cryomni3d/POTFILES
Normal file
@@ -0,0 +1 @@
|
||||
engines/cryomni3d/metaengine.cpp
|
||||
3
engines/cryomni3d/configure.engine
Normal file
3
engines/cryomni3d/configure.engine
Normal file
@@ -0,0 +1,3 @@
|
||||
# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps] [components]
|
||||
add_engine cryomni3d "Cryo Omni3D games" yes "versailles" "" "highres hnm"
|
||||
add_engine versailles "Versailles 1685" yes
|
||||
3
engines/cryomni3d/credits.pl
Normal file
3
engines/cryomni3d/credits.pl
Normal file
@@ -0,0 +1,3 @@
|
||||
begin_section("Cryomni3D");
|
||||
add_person("Philippe Valembois", "lePhilousophe", "");
|
||||
end_section();
|
||||
472
engines/cryomni3d/cryomni3d.cpp
Normal file
472
engines/cryomni3d/cryomni3d.cpp
Normal file
@@ -0,0 +1,472 @@
|
||||
/* 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/scummsys.h"
|
||||
#include "common/error.h"
|
||||
#include "common/system.h"
|
||||
#include "common/textconsole.h"
|
||||
#include "common/debug-channels.h"
|
||||
|
||||
#include "common/events.h"
|
||||
#include "common/file.h"
|
||||
|
||||
#include "engines/util.h"
|
||||
|
||||
#include "audio/mixer.h"
|
||||
#include "graphics/paletteman.h"
|
||||
|
||||
#include "cryomni3d/cryomni3d.h"
|
||||
#include "cryomni3d/datstream.h"
|
||||
|
||||
#include "cryomni3d/image/hlz.h"
|
||||
#include "cryomni3d/image/hnm.h"
|
||||
#include "video/hnm_decoder.h"
|
||||
|
||||
namespace CryOmni3D {
|
||||
|
||||
CryOmni3DEngine::CryOmni3DEngine(OSystem *syst,
|
||||
const CryOmni3DGameDescription *gamedesc) : Engine(syst), _gameDescription(gamedesc),
|
||||
_canLoadSave(false), _fontManager(), _sprites(), _dragStatus(kDragStatus_NoDrag), _lastMouseButton(0),
|
||||
_autoRepeatNextEvent(uint(-1)), _hnmHasClip(false) {
|
||||
if (!_mixer->isReady()) {
|
||||
error("Sound initialization failed");
|
||||
}
|
||||
|
||||
// Setup mixer
|
||||
syncSoundSettings();
|
||||
|
||||
unlockPalette();
|
||||
}
|
||||
|
||||
CryOmni3DEngine::~CryOmni3DEngine() {
|
||||
}
|
||||
|
||||
Common::Error CryOmni3DEngine::run() {
|
||||
return Common::kNoError;
|
||||
}
|
||||
|
||||
void CryOmni3DEngine::pauseEngineIntern(bool pause) {
|
||||
Engine::pauseEngineIntern(pause);
|
||||
|
||||
/*
|
||||
if (pause) {
|
||||
_video->pauseVideos();
|
||||
} else {
|
||||
_video->resumeVideos();
|
||||
_system->updateScreen();
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
DATSeekableStream *CryOmni3DEngine::getStaticData(uint32 gameId, uint16 version) const {
|
||||
Common::File *datFile = new Common::File();
|
||||
|
||||
if (!datFile->open("cryomni3d.dat")) {
|
||||
delete datFile;
|
||||
error("Failed to open cryomni3d.dat file");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DATSeekableStream *gameStream = DATSeekableStream::getGame(datFile, gameId, version, getLanguage(),
|
||||
getPlatform());
|
||||
if (!gameStream) {
|
||||
delete datFile;
|
||||
error("Failed to find game in cryomni3d.dat file");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return gameStream;
|
||||
}
|
||||
|
||||
void CryOmni3DEngine::playHNM(const Common::Path &filepath, Audio::Mixer::SoundType soundType,
|
||||
HNMCallback beforeDraw, HNMCallback afterDraw) {
|
||||
Graphics::PixelFormat screenFormat = g_system->getScreenFormat();
|
||||
byte *currentPalette = nullptr;
|
||||
if (screenFormat.bytesPerPixel == 1) {
|
||||
currentPalette = new byte[256 * 3];
|
||||
g_system->getPaletteManager()->grabPalette(currentPalette, 0, 256);
|
||||
}
|
||||
|
||||
// Pass the ownership of currentPalette to HNMDecoder
|
||||
Video::VideoDecoder *videoDecoder = new Video::HNMDecoder(screenFormat, false, currentPalette);
|
||||
videoDecoder->setSoundType(soundType);
|
||||
|
||||
if (!videoDecoder->loadFile(filepath)) {
|
||||
warning("Failed to open movie file %s", filepath.toString(Common::Path::kNativeSeparator).c_str());
|
||||
delete videoDecoder;
|
||||
return;
|
||||
}
|
||||
|
||||
videoDecoder->start();
|
||||
|
||||
uint16 width = videoDecoder->getWidth();
|
||||
uint16 height = videoDecoder->getHeight();
|
||||
|
||||
bool skipVideo = false;
|
||||
uint frameNum = 0;
|
||||
while (!shouldAbort() && !videoDecoder->endOfVideo() && !skipVideo) {
|
||||
if (videoDecoder->needsUpdate()) {
|
||||
const Graphics::Surface *frame = videoDecoder->decodeNextFrame();
|
||||
|
||||
if (frame) {
|
||||
if (videoDecoder->hasDirtyPalette()) {
|
||||
const byte *palette = videoDecoder->getPalette();
|
||||
setPalette(palette, 0, 256);
|
||||
}
|
||||
|
||||
if (beforeDraw) {
|
||||
(this->*beforeDraw)(frameNum);
|
||||
}
|
||||
|
||||
if (_hnmHasClip) {
|
||||
Common::Rect rct(width, height);
|
||||
rct.clip(_hnmClipping);
|
||||
g_system->copyRectToScreen(frame->getPixels(), frame->pitch, rct.left, rct.top, rct.width(),
|
||||
rct.height());
|
||||
} else {
|
||||
g_system->copyRectToScreen(frame->getPixels(), frame->pitch, 0, 0, width, height);
|
||||
}
|
||||
|
||||
if (afterDraw) {
|
||||
(this->*afterDraw)(frameNum);
|
||||
}
|
||||
|
||||
frameNum++;
|
||||
}
|
||||
}
|
||||
g_system->updateScreen();
|
||||
g_system->delayMillis(10);
|
||||
|
||||
if (pollEvents() && checkKeysPressed()) {
|
||||
skipVideo = true;
|
||||
}
|
||||
}
|
||||
|
||||
delete videoDecoder;
|
||||
}
|
||||
|
||||
Image::ImageDecoder *CryOmni3DEngine::loadHLZ(const Common::Path &filepath) {
|
||||
Common::File file;
|
||||
|
||||
if (!file.open(filepath)) {
|
||||
warning("Failed to open hlz file %s", filepath.toString(Common::Path::kNativeSeparator).c_str());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Image::ImageDecoder *imageDecoder = new Image::HLZFileDecoder();
|
||||
|
||||
if (!imageDecoder->loadStream(file)) {
|
||||
warning("Failed to load hlz file %s", filepath.toString(Common::Path::kNativeSeparator).c_str());
|
||||
delete imageDecoder;
|
||||
imageDecoder = nullptr;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return imageDecoder;
|
||||
}
|
||||
|
||||
bool CryOmni3DEngine::displayHLZ(const Common::Path &filepath, uint32 timeout) {
|
||||
Image::ImageDecoder *imageDecoder = loadHLZ(filepath);
|
||||
|
||||
if (!imageDecoder) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (imageDecoder->hasPalette()) {
|
||||
setPalette(imageDecoder->getPalette().data(), 0, imageDecoder->getPalette().size());
|
||||
}
|
||||
|
||||
const Graphics::Surface *frame = imageDecoder->getSurface();
|
||||
g_system->copyRectToScreen(frame->getPixels(), frame->pitch, 0, 0, frame->w, frame->h);
|
||||
g_system->updateScreen();
|
||||
|
||||
uint32 end;
|
||||
if (timeout == uint(-1)) {
|
||||
end = uint(-1);
|
||||
} else {
|
||||
end = g_system->getMillis() + timeout;
|
||||
}
|
||||
bool exitImg = false;
|
||||
while (!shouldAbort() && !exitImg && g_system->getMillis() < end) {
|
||||
if (pollEvents()) {
|
||||
if (checkKeysPressed() || getCurrentMouseButton() == 1) {
|
||||
exitImg = true;
|
||||
}
|
||||
}
|
||||
g_system->updateScreen();
|
||||
g_system->delayMillis(10);
|
||||
}
|
||||
|
||||
delete imageDecoder;
|
||||
|
||||
return exitImg || shouldAbort();
|
||||
}
|
||||
|
||||
void CryOmni3DEngine::setCursor(const Graphics::Cursor &cursor) const {
|
||||
CursorMan.replaceCursor(&cursor);
|
||||
}
|
||||
|
||||
void CryOmni3DEngine::setCursor(uint cursorId) const {
|
||||
const Graphics::Cursor &cursor = _sprites.getCursor(cursorId);
|
||||
CursorMan.replaceCursor(&cursor);
|
||||
}
|
||||
|
||||
bool CryOmni3DEngine::pollEvents() {
|
||||
Common::Event event;
|
||||
int buttonMask;
|
||||
bool hasEvents = false;
|
||||
|
||||
// Don't take into transitional clicks for the drag
|
||||
buttonMask = g_system->getEventManager()->getButtonState();
|
||||
uint oldMouseButton;
|
||||
if (buttonMask & 0x1) {
|
||||
oldMouseButton = 1;
|
||||
} else if (buttonMask & 0x2) {
|
||||
oldMouseButton = 2;
|
||||
} else {
|
||||
oldMouseButton = 0;
|
||||
}
|
||||
|
||||
int transitionalMask = 0;
|
||||
while (g_system->getEventManager()->pollEvent(event)) {
|
||||
if (event.type == Common::EVENT_KEYDOWN) {
|
||||
_keysPressed.push(event.kbd);
|
||||
} else if (event.type == Common::EVENT_LBUTTONDOWN) {
|
||||
transitionalMask |= Common::EventManager::LBUTTON;
|
||||
} else if (event.type == Common::EVENT_RBUTTONDOWN) {
|
||||
transitionalMask |= Common::EventManager::RBUTTON;
|
||||
}
|
||||
hasEvents = true;
|
||||
}
|
||||
|
||||
// Merge current button state with any buttons pressed since last poll
|
||||
// That's to avoid missed clicks
|
||||
buttonMask = g_system->getEventManager()->getButtonState() |
|
||||
transitionalMask;
|
||||
if (buttonMask & 0x1) {
|
||||
_lastMouseButton = 1;
|
||||
} else if (buttonMask & 0x2) {
|
||||
_lastMouseButton = 2;
|
||||
} else {
|
||||
_lastMouseButton = 0;
|
||||
}
|
||||
|
||||
_dragStatus = kDragStatus_NoDrag;
|
||||
uint currentMouseButton = getCurrentMouseButton();
|
||||
if (!oldMouseButton && currentMouseButton == 1) {
|
||||
// Starting the drag
|
||||
_dragStatus = kDragStatus_Pressed;
|
||||
_dragStart = getMousePos();
|
||||
} else if (oldMouseButton == 1) {
|
||||
// We were already pressing
|
||||
if (currentMouseButton == 1) {
|
||||
// We are still pressing
|
||||
Common::Point delta = _dragStart - getMousePos();
|
||||
if (ABS(delta.x) > 2 || ABS(delta.y) > 2) {
|
||||
// We moved from the start point
|
||||
_dragStatus = kDragStatus_Dragging;
|
||||
} else if (_autoRepeatNextEvent != uint(-1)) {
|
||||
// Check for auto repeat duration
|
||||
if (_autoRepeatNextEvent < g_system->getMillis()) {
|
||||
_dragStatus = kDragStatus_Pressed;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// We just finished dragging
|
||||
_dragStatus = kDragStatus_Finished;
|
||||
// Cancel auto repeat
|
||||
_autoRepeatNextEvent = uint(-1);
|
||||
}
|
||||
}
|
||||
// Else we weren't dragging and still aren't
|
||||
|
||||
return hasEvents;
|
||||
}
|
||||
|
||||
void CryOmni3DEngine::setAutoRepeatClick(uint millis) {
|
||||
_autoRepeatNextEvent = g_system->getMillis() + millis;
|
||||
}
|
||||
|
||||
void CryOmni3DEngine::waitMouseRelease() {
|
||||
while (getCurrentMouseButton() != 0 && !shouldAbort()) {
|
||||
pollEvents();
|
||||
g_system->updateScreen();
|
||||
g_system->delayMillis(10);
|
||||
}
|
||||
}
|
||||
|
||||
void CryOmni3DEngine::setMousePos(const Common::Point &point) {
|
||||
g_system->warpMouse(point.x, point.y);
|
||||
// Ensure to update mouse position in event manager
|
||||
pollEvents();
|
||||
}
|
||||
|
||||
Common::Point CryOmni3DEngine::getMousePos() {
|
||||
return g_system->getEventManager()->getMousePos();
|
||||
}
|
||||
|
||||
Common::KeyState CryOmni3DEngine::getNextKey() {
|
||||
if (_keysPressed.empty()) {
|
||||
return Common::KeyState();
|
||||
} else {
|
||||
return _keysPressed.pop();
|
||||
}
|
||||
}
|
||||
|
||||
bool CryOmni3DEngine::checkKeysPressed() {
|
||||
Common::KeyCode kc = getNextKey().keycode;
|
||||
if (kc != Common::KEYCODE_INVALID) {
|
||||
clearKeys();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool CryOmni3DEngine::checkKeysPressed(uint numKeys, ...) {
|
||||
bool found = false;
|
||||
Common::KeyCode kc = getNextKey().keycode;
|
||||
while (!found && kc != Common::KEYCODE_INVALID) {
|
||||
va_list va;
|
||||
va_start(va, numKeys);
|
||||
for (uint i = 0; i < numKeys; i++) {
|
||||
// Compiler says that KeyCode is promoted to int, so we need this ugly cast
|
||||
Common::KeyCode match = (Common::KeyCode) va_arg(va, int);
|
||||
if (match == kc) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
va_end(va);
|
||||
kc = getNextKey().keycode;
|
||||
}
|
||||
clearKeys();
|
||||
return found;
|
||||
}
|
||||
|
||||
void CryOmni3DEngine::copySubPalette(byte *dst, const byte *src, uint start, uint num) {
|
||||
assert(start < 256);
|
||||
assert(start + num < 256);
|
||||
memcpy(&dst[3 * start], &src[3 * start], 3 * num * sizeof(*dst));
|
||||
}
|
||||
|
||||
void CryOmni3DEngine::setPalette(const byte *colors, uint start, uint num) {
|
||||
if (start < _lockPaletteStartRW) {
|
||||
colors = colors + 3 * (_lockPaletteStartRW - start);
|
||||
start = _lockPaletteStartRW;
|
||||
}
|
||||
uint end = start + num - 1;
|
||||
if (end > _lockPaletteEndRW) {
|
||||
num = num - (end - _lockPaletteEndRW);
|
||||
end = _lockPaletteEndRW;
|
||||
}
|
||||
g_system->getPaletteManager()->setPalette(colors, start, num);
|
||||
// Don't update screen there: palette will be updated with next updateScreen call
|
||||
}
|
||||
|
||||
void CryOmni3DEngine::fadeOutPalette() {
|
||||
byte palOut[256 * 3];
|
||||
uint16 palWork[256 * 3];
|
||||
uint16 delta[256 * 3];
|
||||
|
||||
g_system->getPaletteManager()->grabPalette(palOut, 0, 256);
|
||||
for (uint i = 0; i < 256 * 3; i++) {
|
||||
palWork[i] = palOut[i] << 8;
|
||||
delta[i] = palWork[i] / 25;
|
||||
}
|
||||
|
||||
for (uint step = 0; step < 25 && !shouldAbort(); step++) {
|
||||
for (uint i = 0; i < 256 * 3; i++) {
|
||||
palWork[i] -= delta[i];
|
||||
palOut[i] = palWork[i] >> 8;
|
||||
}
|
||||
setPalette(palOut, 0, 256);
|
||||
// Wait 50ms between each steps but refresh screen every 10ms
|
||||
for (uint i = 0; i < 5; i++) {
|
||||
pollEvents();
|
||||
g_system->updateScreen();
|
||||
g_system->delayMillis(10);
|
||||
}
|
||||
}
|
||||
setBlackPalette();
|
||||
pollEvents();
|
||||
g_system->updateScreen();
|
||||
clearKeys();
|
||||
}
|
||||
|
||||
void CryOmni3DEngine::fadeInPalette(const byte *palette) {
|
||||
byte palOut[256 * 3];
|
||||
uint16 palWork[256 * 3];
|
||||
uint16 delta[256 * 3];
|
||||
|
||||
memset(palOut, 0, sizeof(palOut));
|
||||
memset(palWork, 0, sizeof(palWork));
|
||||
for (uint i = 0; i < 256 * 3; i++) {
|
||||
delta[i] = (palette[i] << 8) / 25;
|
||||
}
|
||||
|
||||
setBlackPalette();
|
||||
for (uint step = 0; step < 25 && !shouldAbort(); step++) {
|
||||
for (uint i = 0; i < 256 * 3; i++) {
|
||||
palWork[i] += delta[i];
|
||||
palOut[i] = palWork[i] >> 8;
|
||||
}
|
||||
setPalette(palOut, 0, 256);
|
||||
// Wait 50ms between each steps but refresh screen every 10ms
|
||||
for (uint i = 0; i < 5; i++) {
|
||||
pollEvents();
|
||||
g_system->updateScreen();
|
||||
g_system->delayMillis(10);
|
||||
}
|
||||
}
|
||||
setPalette(palette, 0, 256);
|
||||
pollEvents();
|
||||
g_system->updateScreen();
|
||||
clearKeys();
|
||||
}
|
||||
|
||||
void CryOmni3DEngine::setBlackPalette() {
|
||||
byte pal[256 * 3];
|
||||
memset(pal, 0, 256 * 3);
|
||||
g_system->getPaletteManager()->setPalette(pal, 0, 256);
|
||||
g_system->updateScreen();
|
||||
}
|
||||
|
||||
void CryOmni3DEngine::fillSurface(byte color) {
|
||||
g_system->fillScreen(color);
|
||||
g_system->updateScreen();
|
||||
}
|
||||
|
||||
Common::Error CryOmni3DEngine_HNMPlayer::run() {
|
||||
CryOmni3DEngine::run();
|
||||
|
||||
initGraphics(640, 480);
|
||||
|
||||
syncSoundSettings();
|
||||
|
||||
for (int i = 0; _gameDescription->desc.filesDescriptions[i].fileName; i++) {
|
||||
playHNM(_gameDescription->desc.filesDescriptions[i].fileName, Audio::Mixer::kMusicSoundType);
|
||||
}
|
||||
|
||||
return Common::kNoError;
|
||||
}
|
||||
|
||||
} // End of namespace CryOmni3D
|
||||
196
engines/cryomni3d/cryomni3d.h
Normal file
196
engines/cryomni3d/cryomni3d.h
Normal file
@@ -0,0 +1,196 @@
|
||||
/* 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 CRYOMNI3D_CRYOMNI3D_H
|
||||
#define CRYOMNI3D_CRYOMNI3D_H
|
||||
|
||||
#include "audio/mixer.h"
|
||||
|
||||
#include "common/array.h"
|
||||
#include "common/keyboard.h"
|
||||
#include "common/queue.h"
|
||||
#include "common/rect.h"
|
||||
#include "common/scummsys.h"
|
||||
|
||||
#include "engines/engine.h"
|
||||
|
||||
#include "graphics/cursorman.h"
|
||||
|
||||
#include "cryomni3d/font_manager.h"
|
||||
#include "cryomni3d/objects.h"
|
||||
#include "cryomni3d/sprites.h"
|
||||
#include "cryomni3d/detection.h"
|
||||
|
||||
class OSystem;
|
||||
|
||||
namespace Common {
|
||||
struct Point;
|
||||
class SeekableReadStream;
|
||||
}
|
||||
|
||||
namespace Image {
|
||||
class ImageDecoder;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the namespace of the Cryo Omni3D engine.
|
||||
*
|
||||
* Status of this engine: ???
|
||||
*
|
||||
* Games using this engine:
|
||||
* - Versailles
|
||||
* - ...
|
||||
*/
|
||||
namespace CryOmni3D {
|
||||
|
||||
class DATSeekableStream;
|
||||
|
||||
// Engine Debug Flags
|
||||
enum {
|
||||
kDebugFile = 1,
|
||||
kDebugVariable,
|
||||
kDebugSaveLoad,
|
||||
};
|
||||
|
||||
enum DragStatus {
|
||||
kDragStatus_NoDrag = 0,
|
||||
kDragStatus_Pressed,
|
||||
kDragStatus_Finished,
|
||||
kDragStatus_Dragging
|
||||
};
|
||||
|
||||
class CryOmni3DEngine : public ::Engine {
|
||||
protected:
|
||||
Common::Error run() override;
|
||||
|
||||
public:
|
||||
CryOmni3DEngine(OSystem *syst, const CryOmni3DGameDescription *gamedesc);
|
||||
~CryOmni3DEngine() override;
|
||||
|
||||
// Detection related functions
|
||||
const CryOmni3DGameDescription *_gameDescription;
|
||||
const char *getGameId() const;
|
||||
uint32 getFeatures() const;
|
||||
uint16 getVersion() const;
|
||||
Common::Platform getPlatform() const;
|
||||
uint8 getGameType() const;
|
||||
Common::Language getLanguage() const;
|
||||
|
||||
bool hasFeature(EngineFeature f) const override;
|
||||
bool canLoadGameStateCurrently(Common::U32String *msg = nullptr) override { return _canLoadSave; }
|
||||
bool canSaveGameStateCurrently(Common::U32String *msg = nullptr) override { return _canLoadSave; }
|
||||
|
||||
void setCanLoadSave(bool canLoadSave) { _canLoadSave = canLoadSave; }
|
||||
static const uint kSaveDescriptionLen = 20;
|
||||
private:
|
||||
void pauseEngineIntern(bool) override;
|
||||
|
||||
public:
|
||||
Image::ImageDecoder *loadHLZ(const Common::Path &filepath);
|
||||
|
||||
void fillSurface(byte color);
|
||||
/* We use CursorMan because it avoids problems with cursors in GMM */
|
||||
void setCursor(const Graphics::Cursor &cursor) const;
|
||||
void setCursor(uint cursorId) const;
|
||||
bool showMouse(bool visible) { return CursorMan.showMouse(visible); }
|
||||
typedef void (CryOmni3DEngine::*HNMCallback)(uint frameNum);
|
||||
void playHNM(const Common::Path &filepath,
|
||||
Audio::Mixer::SoundType soundType = Audio::Mixer::kPlainSoundType,
|
||||
HNMCallback beforeDraw = nullptr, HNMCallback afterDraw = nullptr);
|
||||
bool displayHLZ(const Common::Path &filepath, uint32 timeout = uint(-1));
|
||||
|
||||
bool pollEvents();
|
||||
Common::Point getMousePos();
|
||||
void setMousePos(const Common::Point &point);
|
||||
uint getCurrentMouseButton() { return _lastMouseButton; }
|
||||
Common::KeyState getNextKey();
|
||||
bool checkKeysPressed();
|
||||
bool checkKeysPressed(uint numKeys, ...);
|
||||
void clearKeys() { _keysPressed.clear(); }
|
||||
void waitMouseRelease();
|
||||
void setAutoRepeatClick(uint millis);
|
||||
DragStatus getDragStatus() { return _dragStatus; }
|
||||
|
||||
virtual bool displayToolbar(const Graphics::Surface *original) = 0;
|
||||
virtual bool hasPlaceDocumentation() = 0;
|
||||
virtual bool displayPlaceDocumentation() = 0;
|
||||
virtual uint displayOptions() = 0;
|
||||
virtual bool shouldAbort() { return g_engine->shouldQuit(); }
|
||||
|
||||
virtual void makeTranslucent(Graphics::Surface &dst, const Graphics::Surface &src) const = 0;
|
||||
virtual void setupPalette(const byte *colors, uint start, uint num) = 0;
|
||||
|
||||
protected:
|
||||
DATSeekableStream *getStaticData(uint32 gameId, uint16 version) const;
|
||||
|
||||
void copySubPalette(byte *dst, const byte *src, uint start, uint num);
|
||||
void setPalette(const byte *colors, uint start, uint num);
|
||||
void lockPalette(uint startRW, uint endRW) { _lockPaletteStartRW = startRW; _lockPaletteEndRW = endRW; }
|
||||
void unlockPalette() { _lockPaletteStartRW = 0; _lockPaletteEndRW = 255; }
|
||||
void fadeOutPalette();
|
||||
void fadeInPalette(const byte *colors);
|
||||
void setBlackPalette();
|
||||
|
||||
void setHNMClipping(const Common::Rect &clip) { _hnmClipping = clip; _hnmHasClip = true; }
|
||||
void unsetHNMClipping() { _hnmHasClip = false; }
|
||||
|
||||
protected:
|
||||
bool _canLoadSave;
|
||||
|
||||
FontManager _fontManager;
|
||||
Sprites _sprites;
|
||||
Objects _objects;
|
||||
Inventory _inventory;
|
||||
|
||||
Common::Queue<Common::KeyState> _keysPressed;
|
||||
|
||||
DragStatus _dragStatus;
|
||||
Common::Point _dragStart;
|
||||
uint _lastMouseButton;
|
||||
uint _autoRepeatNextEvent;
|
||||
|
||||
private:
|
||||
uint _lockPaletteStartRW;
|
||||
uint _lockPaletteEndRW;
|
||||
|
||||
Common::Rect _hnmClipping;
|
||||
bool _hnmHasClip;
|
||||
};
|
||||
|
||||
class CryOmni3DEngine_HNMPlayer : public CryOmni3DEngine {
|
||||
protected:
|
||||
Common::Error run() override;
|
||||
|
||||
public:
|
||||
CryOmni3DEngine_HNMPlayer(OSystem *syst, const CryOmni3DGameDescription *gamedesc) : CryOmni3DEngine(syst, gamedesc) {}
|
||||
~CryOmni3DEngine_HNMPlayer() override {}
|
||||
|
||||
bool displayToolbar(const Graphics::Surface *original) override { return false; }
|
||||
bool hasPlaceDocumentation() override { return false; }
|
||||
bool displayPlaceDocumentation() override { return false; }
|
||||
uint displayOptions() override { return 0; }
|
||||
void makeTranslucent(Graphics::Surface &dst, const Graphics::Surface &src) const override {}
|
||||
void setupPalette(const byte *colors, uint start, uint num) override {}
|
||||
};
|
||||
|
||||
} // End of namespace CryOmni3D
|
||||
|
||||
#endif
|
||||
161
engines/cryomni3d/datstream.cpp
Normal file
161
engines/cryomni3d/datstream.cpp
Normal file
@@ -0,0 +1,161 @@
|
||||
/* 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 "cryomni3d/datstream.h"
|
||||
|
||||
namespace CryOmni3D {
|
||||
|
||||
DATSeekableStream *DATSeekableStream::getGame(Common::SeekableReadStream *stream,
|
||||
uint32 gameId, uint16 version, Common::Language lang, Common::Platform platform) {
|
||||
if (stream == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Go to start of file
|
||||
stream->seek(0, SEEK_SET);
|
||||
|
||||
// ALl of this should match devtools/create_cryomni3d_dat
|
||||
|
||||
// Check header
|
||||
byte header[8];
|
||||
memset(header, 0, sizeof(header));
|
||||
stream->read(header, sizeof(header));
|
||||
if (memcmp(header, "CY3DDATA", sizeof(header))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Check version
|
||||
uint16 fileVersion = stream->readUint16LE();
|
||||
if (fileVersion != kFileVersion) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uint16 langTranslated = translateLanguage(lang);
|
||||
uint32 platformTranslated = translatePlatform(platform);
|
||||
|
||||
uint16 games = stream->readUint16LE();
|
||||
|
||||
// Padding to align to 16 bytes boundary
|
||||
(void)stream->readUint32LE();
|
||||
|
||||
for (uint16 game = 0; game < games; game++) {
|
||||
// Keep tag readable
|
||||
uint32 readGameId = stream->readUint32BE();
|
||||
uint16 readVersion = stream->readUint16LE();
|
||||
// Keep tag readable
|
||||
uint16 readLang = stream->readUint16BE();
|
||||
uint32 readPlatforms = stream->readUint32LE();
|
||||
uint32 offset = stream->readUint32LE();
|
||||
uint32 size = stream->readUint32LE();
|
||||
|
||||
if (gameId != readGameId) {
|
||||
continue;
|
||||
}
|
||||
if (version != readVersion) {
|
||||
continue;
|
||||
}
|
||||
if (langTranslated != readLang) {
|
||||
continue;
|
||||
}
|
||||
if (!(platformTranslated & readPlatforms)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If we are there, we got a match
|
||||
return new DATSeekableStream(stream, offset, offset + size);
|
||||
}
|
||||
|
||||
// No match
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Common::String DATSeekableStream::readString16() {
|
||||
char *buf;
|
||||
uint16 len;
|
||||
|
||||
len = readUint16LE();
|
||||
buf = (char *)malloc(len);
|
||||
read(buf, len);
|
||||
|
||||
Common::String s(buf, len);
|
||||
free(buf);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
void DATSeekableStream::readString16Array16(Common::StringArray &array) {
|
||||
uint16 items;
|
||||
uint16 i;
|
||||
|
||||
items = readUint16LE();
|
||||
|
||||
array.reserve(items);
|
||||
for (i = 0; i < items; i++) {
|
||||
array.push_back(readString16());
|
||||
}
|
||||
}
|
||||
|
||||
uint16 DATSeekableStream::translateLanguage(Common::Language lang) {
|
||||
switch (lang) {
|
||||
case Common::DE_DEU:
|
||||
return MKTAG16('d', 'e');
|
||||
case Common::EN_ANY:
|
||||
return MKTAG16('e', 'n');
|
||||
case Common::ES_ESP:
|
||||
return MKTAG16('e', 's');
|
||||
case Common::FR_FRA:
|
||||
return MKTAG16('f', 'r');
|
||||
case Common::IT_ITA:
|
||||
return MKTAG16('i', 't');
|
||||
case Common::JA_JPN:
|
||||
return MKTAG16('j', 'a');
|
||||
case Common::KO_KOR:
|
||||
return MKTAG16('k', 'o');
|
||||
case Common::PT_BRA:
|
||||
return MKTAG16('b', 'r');
|
||||
case Common::ZH_TWN:
|
||||
return MKTAG16('z', 't');
|
||||
default:
|
||||
// Invalid language
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint32 DATSeekableStream::translatePlatform(Common::Platform platform) {
|
||||
switch (platform) {
|
||||
case Common::kPlatformWindows:
|
||||
return 0x1;
|
||||
case Common::kPlatformDOS:
|
||||
return 0x2;
|
||||
case Common::kPlatformMacintosh:
|
||||
return 0x4;
|
||||
case Common::kPlatformPSX:
|
||||
return 0x8;
|
||||
case Common::kPlatformSegaCD:
|
||||
return 0x10;
|
||||
default:
|
||||
// Invalid platform
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace CryOmni3D
|
||||
57
engines/cryomni3d/datstream.h
Normal file
57
engines/cryomni3d/datstream.h
Normal file
@@ -0,0 +1,57 @@
|
||||
/* 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 CRYOMNI3D_DATSTREAM_H
|
||||
#define CRYOMNI3D_DATSTREAM_H
|
||||
|
||||
#include "common/language.h"
|
||||
#include "common/platform.h"
|
||||
#include "common/str.h"
|
||||
#include "common/str-array.h"
|
||||
#include "common/substream.h"
|
||||
|
||||
namespace CryOmni3D {
|
||||
|
||||
class DATSeekableStream : public Common::SeekableSubReadStream {
|
||||
public:
|
||||
|
||||
/* Parent stream must not be used after this call and will be disposed if fetch succeeded */
|
||||
static DATSeekableStream *getGame(Common::SeekableReadStream *stream,
|
||||
uint32 gameId, uint16 version, Common::Language lang, Common::Platform platform);
|
||||
|
||||
Common::String readString16();
|
||||
void readString16Array16(Common::StringArray &array);
|
||||
|
||||
private:
|
||||
DATSeekableStream(SeekableReadStream *parentStream, uint32 start, uint32 end) :
|
||||
SeekableSubReadStream(parentStream, start, end, DisposeAfterUse::YES) { }
|
||||
|
||||
static uint16 translateLanguage(Common::Language lang);
|
||||
static uint32 translatePlatform(Common::Platform platform);
|
||||
|
||||
/* This is the version of the global file format
|
||||
* Each game has then a version specific for its data */
|
||||
static const uint16 kFileVersion = 1;
|
||||
};
|
||||
|
||||
} // End of namespace CryOmni3D
|
||||
|
||||
#endif
|
||||
84
engines/cryomni3d/detection.cpp
Normal file
84
engines/cryomni3d/detection.cpp
Normal file
@@ -0,0 +1,84 @@
|
||||
/* 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 "engines/advancedDetector.h"
|
||||
|
||||
#include "common/file.h"
|
||||
#include "common/md5.h"
|
||||
|
||||
#include "cryomni3d/detection.h"
|
||||
#include "cryomni3d/cryomni3d.h"
|
||||
|
||||
namespace CryOmni3D {
|
||||
|
||||
static const PlainGameDescriptor cryomni3DGames[] = {
|
||||
{"atlantis", "Atlantis: The Lost Tales"},
|
||||
{"versailles", "Versailles 1685"},
|
||||
{nullptr, nullptr}
|
||||
};
|
||||
|
||||
static const DebugChannelDef debugFlagList[] = {
|
||||
{CryOmni3D::kDebugFile, "File", "Track File Accesses"},
|
||||
{CryOmni3D::kDebugVariable, "Variable", "Track Variable Accesses"},
|
||||
{CryOmni3D::kDebugSaveLoad, "SaveLoad", "Track Save/Load Function"},
|
||||
DEBUG_CHANNEL_END
|
||||
};
|
||||
|
||||
} // End of namespace CryOmni3D
|
||||
|
||||
#include "cryomni3d/detection_tables.h"
|
||||
|
||||
namespace CryOmni3D {
|
||||
|
||||
class CryOmni3DMetaEngineDetection : public AdvancedMetaEngineDetection<CryOmni3DGameDescription> {
|
||||
public:
|
||||
CryOmni3DMetaEngineDetection() : AdvancedMetaEngineDetection(CryOmni3D::gameDescriptions, cryomni3DGames) {
|
||||
_directoryGlobs = directoryGlobs;
|
||||
_maxScanDepth = 5;
|
||||
}
|
||||
|
||||
ADDetectedGame fallbackDetect(const FileMap &allFiles,
|
||||
const Common::FSList &fslist, ADDetectedGameExtraInfo **extra) const override {
|
||||
return detectGameFilebased(allFiles, fileBased);
|
||||
}
|
||||
|
||||
const char *getName() const override {
|
||||
return "cryomni3d";
|
||||
}
|
||||
|
||||
const char *getEngineName() const override {
|
||||
return "Cryo Omni3D";
|
||||
}
|
||||
|
||||
const char *getOriginalCopyright() const override {
|
||||
return "Cryo game Engine (C) 1997-2002 Cryo Interactive";
|
||||
}
|
||||
|
||||
const DebugChannelDef *getDebugChannels() const override {
|
||||
return debugFlagList;
|
||||
}
|
||||
};
|
||||
|
||||
} // End of Namespace CryOmni3D
|
||||
|
||||
REGISTER_PLUGIN_STATIC(CRYOMNI3D_DETECTION, PLUGIN_TYPE_ENGINE_DETECTION, CryOmni3D::CryOmni3DMetaEngineDetection);
|
||||
59
engines/cryomni3d/detection.h
Normal file
59
engines/cryomni3d/detection.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 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 CRYOMNI3D_DETECTION_H
|
||||
#define CRYOMNI3D_DETECTION_H
|
||||
|
||||
#include "engines/advancedDetector.h"
|
||||
|
||||
namespace CryOmni3D {
|
||||
|
||||
enum CryOmni3DGameType {
|
||||
GType_VERSAILLES,
|
||||
GType_HNM_PLAYER
|
||||
};
|
||||
|
||||
enum CryOmni3DGameFeatures {
|
||||
GF_VERSAILLES_FONTS_MASK = (3 << 0), // Fonts flag mask
|
||||
GF_VERSAILLES_FONTS_NUMERIC = (0 << 0), // Fonts are font01.crf, ...
|
||||
GF_VERSAILLES_FONTS_SET_A = (1 << 0), // Fonts are for French Macintosh (development version)
|
||||
GF_VERSAILLES_FONTS_SET_B = (2 << 0), // Standard set (Helvet12 is used for debugging docs)
|
||||
GF_VERSAILLES_FONTS_SET_C = (3 << 0), // Fonts for Italian version (Helvet12 is used for docs texts)
|
||||
|
||||
GF_VERSAILLES_AUDIOPADDING_NO = (0 << 2), // Audio files have underscore padding before extension
|
||||
GF_VERSAILLES_AUDIOPADDING_YES = (1 << 2), // Audio files have underscore padding before extension
|
||||
|
||||
GF_VERSAILLES_LINK_STANDARD = (0 << 3), // Links file is lien_doc.txt
|
||||
GF_VERSAILLES_LINK_LOCALIZED = (1 << 3) // Links file is taken from cryomni3d.dat
|
||||
};
|
||||
|
||||
struct CryOmni3DGameDescription {
|
||||
AD_GAME_DESCRIPTION_HELPERS(desc);
|
||||
|
||||
ADGameDescription desc;
|
||||
|
||||
uint8 gameType;
|
||||
uint32 features;
|
||||
};
|
||||
|
||||
} // End of namespace CryOmni3D
|
||||
|
||||
#endif // CRYOMNI3D_DETECTION_H
|
||||
685
engines/cryomni3d/detection_tables.h
Normal file
685
engines/cryomni3d/detection_tables.h
Normal file
@@ -0,0 +1,685 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace CryOmni3D {
|
||||
|
||||
#define GUI_OPTIONS_VERSAILLES GUIO3(GUIO_NOMIDI, GUIO_NOSFX, GUIO_NOASPECT)
|
||||
#define GUI_OPTIONS_HNM_PLAYER GUIO4(GUIO_NOMIDI, GUIO_NOSFX, GUIO_NOSPEECH, GUIO_NOASPECT)
|
||||
|
||||
// To correctly detect root we need files from various places: CD1, CD2, HDD, on-CD install files
|
||||
// We use files common to all installations except the documentation links and the binary
|
||||
// We only check the file presence to simplify and use program to discriminate the version
|
||||
#define VERSAILLES_ENTRY(f, x, s, lien_doc_ext) { \
|
||||
{ "11D_LEB1.HNM", 0, nullptr, AD_NO_SIZE}, \
|
||||
{ "COFBOUM.HNM", 0, nullptr, AD_NO_SIZE}, \
|
||||
{ "lien_doc." lien_doc_ext, 0, nullptr, AD_NO_SIZE}, \
|
||||
{ f, 0, x, s}, \
|
||||
AD_LISTEND}
|
||||
|
||||
#define VERSAILLES_ENTRY_DEF(f, x, s) VERSAILLES_ENTRY(f, x, s, "txt")
|
||||
|
||||
|
||||
// To add new entries, you should check which fonts are loaded by the binary by looking at strings in it
|
||||
// and you should check if audio files have underscores to pad to 8.3 format
|
||||
// The simplest is to request a "tree /f" or "find ." and check which files are present
|
||||
// From experience, numeric should be used when available
|
||||
static const CryOmni3DGameDescription gameDescriptions[] = {
|
||||
// Versailles 1685
|
||||
// French Windows 95 from hybrid Win95/DOS CD
|
||||
// From lePhilousophe
|
||||
{
|
||||
{
|
||||
"versailles",
|
||||
"",
|
||||
VERSAILLES_ENTRY_DEF("VERSAILL.EXE", "3775004b96f056716ce615b458b1f394", 372736),
|
||||
Common::FR_FRA,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUI_OPTIONS_VERSAILLES
|
||||
},
|
||||
GType_VERSAILLES,
|
||||
GF_VERSAILLES_FONTS_NUMERIC | GF_VERSAILLES_AUDIOPADDING_YES | GF_VERSAILLES_LINK_STANDARD,
|
||||
},
|
||||
|
||||
// Versailles 1685
|
||||
// French Windows 95 compressed from hybrid Win95/DOS CD
|
||||
// From lePhilousophe
|
||||
{
|
||||
{
|
||||
"versailles",
|
||||
"",
|
||||
VERSAILLES_ENTRY_DEF("PROGRAM.Z", "a07b5d86af5f3a8883ba97db2bade87d", 293223),
|
||||
Common::FR_FRA,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUI_OPTIONS_VERSAILLES
|
||||
},
|
||||
GType_VERSAILLES,
|
||||
GF_VERSAILLES_FONTS_NUMERIC | GF_VERSAILLES_AUDIOPADDING_YES | GF_VERSAILLES_LINK_STANDARD,
|
||||
},
|
||||
|
||||
// Versailles 1685
|
||||
// French DOS from hybrid Win95/DOS CD
|
||||
// From lePhilousophe
|
||||
{
|
||||
{
|
||||
"versailles",
|
||||
"",
|
||||
VERSAILLES_ENTRY_DEF("VERSAILL.PGM", "1c992f034f43418a5da2e8ebd0b92620", 630431),
|
||||
Common::FR_FRA,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUI_OPTIONS_VERSAILLES
|
||||
},
|
||||
GType_VERSAILLES,
|
||||
GF_VERSAILLES_FONTS_NUMERIC | GF_VERSAILLES_AUDIOPADDING_YES | GF_VERSAILLES_LINK_STANDARD,
|
||||
},
|
||||
|
||||
// Versailles 1685
|
||||
// French DOS from hybrid Win95/DOS CD
|
||||
// From legloutondunet, ticket #11035
|
||||
{
|
||||
{
|
||||
"versailles",
|
||||
"",
|
||||
VERSAILLES_ENTRY_DEF("VERSAILL.PGM", "1c992f034f43418a5da2e8ebd0b92620", 598767),
|
||||
Common::FR_FRA,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUI_OPTIONS_VERSAILLES
|
||||
},
|
||||
GType_VERSAILLES,
|
||||
GF_VERSAILLES_FONTS_SET_B | GF_VERSAILLES_AUDIOPADDING_YES | GF_VERSAILLES_LINK_STANDARD,
|
||||
},
|
||||
|
||||
// Versailles 1685
|
||||
// French Windows from DVD
|
||||
// From Uka in forum
|
||||
{
|
||||
{
|
||||
"versailles",
|
||||
"",
|
||||
VERSAILLES_ENTRY_DEF("Versaill.exe", "09b4734ce473e4cb78738677ce39f536", 346624),
|
||||
Common::FR_FRA,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUI_OPTIONS_VERSAILLES
|
||||
},
|
||||
GType_VERSAILLES,
|
||||
GF_VERSAILLES_FONTS_NUMERIC | GF_VERSAILLES_AUDIOPADDING_YES | GF_VERSAILLES_LINK_STANDARD,
|
||||
},
|
||||
|
||||
// Versailles 1685
|
||||
// French Windows compressed from DVD
|
||||
// From Uka in forum
|
||||
{
|
||||
{
|
||||
"versailles",
|
||||
"",
|
||||
VERSAILLES_ENTRY_DEF("PROGRAM.Z", "167ac4d6e60856ee84d7369107d858d4", 230056),
|
||||
Common::FR_FRA,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUI_OPTIONS_VERSAILLES
|
||||
},
|
||||
GType_VERSAILLES,
|
||||
GF_VERSAILLES_FONTS_NUMERIC | GF_VERSAILLES_AUDIOPADDING_YES | GF_VERSAILLES_LINK_STANDARD,
|
||||
},
|
||||
|
||||
// Versailles 1685
|
||||
// French Macintosh
|
||||
// From criezy
|
||||
{
|
||||
{
|
||||
"versailles",
|
||||
"",
|
||||
VERSAILLES_ENTRY_DEF("Versailles", "f81935517b1bbb58acf70f25efa5c7f3", 375868),
|
||||
Common::FR_FRA,
|
||||
Common::kPlatformMacintosh,
|
||||
ADGF_NO_FLAGS,
|
||||
GUI_OPTIONS_VERSAILLES
|
||||
},
|
||||
GType_VERSAILLES,
|
||||
GF_VERSAILLES_FONTS_SET_A | GF_VERSAILLES_AUDIOPADDING_YES | GF_VERSAILLES_LINK_STANDARD,
|
||||
},
|
||||
|
||||
// Versailles 1685
|
||||
// English Windows from Mac/Win hybrid CD
|
||||
// From lePhilousophe
|
||||
{
|
||||
{
|
||||
"versailles",
|
||||
"",
|
||||
VERSAILLES_ENTRY_DEF("Versaill.exe", "5c3c10ec821b8d96016041ab649af8c7", 377856),
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUI_OPTIONS_VERSAILLES
|
||||
},
|
||||
GType_VERSAILLES,
|
||||
GF_VERSAILLES_FONTS_NUMERIC | GF_VERSAILLES_AUDIOPADDING_NO | GF_VERSAILLES_LINK_STANDARD,
|
||||
},
|
||||
|
||||
// Versailles 1685
|
||||
// English Macintosh from Mac/Win hybrid CD
|
||||
// From lePhilousophe
|
||||
{
|
||||
{
|
||||
"versailles",
|
||||
"",
|
||||
VERSAILLES_ENTRY_DEF("Versailles", "7fa3cb6a3c18f6b4ba6be85dcd433cff", 366199),
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformMacintosh,
|
||||
ADGF_NO_FLAGS,
|
||||
GUI_OPTIONS_VERSAILLES
|
||||
},
|
||||
GType_VERSAILLES,
|
||||
GF_VERSAILLES_FONTS_NUMERIC | GF_VERSAILLES_AUDIOPADDING_NO | GF_VERSAILLES_LINK_STANDARD,
|
||||
},
|
||||
|
||||
// Versailles 1685
|
||||
// English DOS
|
||||
// From lePhilousophe
|
||||
{
|
||||
{
|
||||
"versailles",
|
||||
"",
|
||||
VERSAILLES_ENTRY_DEF("VERSAILL.PGM", "1c992f034f43418a5da2e8ebd0b92620", 598639),
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUI_OPTIONS_VERSAILLES
|
||||
},
|
||||
GType_VERSAILLES,
|
||||
GF_VERSAILLES_FONTS_SET_B | GF_VERSAILLES_AUDIOPADDING_YES | GF_VERSAILLES_LINK_STANDARD,
|
||||
},
|
||||
|
||||
// Versailles 1685
|
||||
// English Windows 95 compressed from hybrid Win95/DOS CD
|
||||
// From scoria in forum
|
||||
{
|
||||
{
|
||||
"versailles",
|
||||
"",
|
||||
VERSAILLES_ENTRY_DEF("PROGRAM.Z", "f5327cb860a67a24a52b6125ddc5e00b", 256146),
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUI_OPTIONS_VERSAILLES
|
||||
},
|
||||
GType_VERSAILLES,
|
||||
GF_VERSAILLES_FONTS_NUMERIC | GF_VERSAILLES_AUDIOPADDING_NO | GF_VERSAILLES_LINK_STANDARD,
|
||||
},
|
||||
|
||||
// Versailles 1685
|
||||
// English DOS from hybrid Win95/DOS CD
|
||||
// From scoria in forum
|
||||
{
|
||||
{
|
||||
"versailles",
|
||||
"",
|
||||
VERSAILLES_ENTRY_DEF("VERSAILL.PGM", "1c992f034f43418a5da2e8ebd0b92620", 710467),
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUI_OPTIONS_VERSAILLES
|
||||
},
|
||||
GType_VERSAILLES,
|
||||
GF_VERSAILLES_FONTS_NUMERIC | GF_VERSAILLES_AUDIOPADDING_NO | GF_VERSAILLES_LINK_STANDARD,
|
||||
},
|
||||
|
||||
// Versailles 1685
|
||||
// English Windows compressed from DVD
|
||||
// From Uka in forum
|
||||
{
|
||||
{
|
||||
"versailles",
|
||||
"",
|
||||
VERSAILLES_ENTRY_DEF("PROGRAM.Z", "daeeb8bce80fe74fe28ecc22b6a97f83", 237679),
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUI_OPTIONS_VERSAILLES
|
||||
},
|
||||
GType_VERSAILLES,
|
||||
GF_VERSAILLES_FONTS_NUMERIC | GF_VERSAILLES_AUDIOPADDING_YES | GF_VERSAILLES_LINK_STANDARD,
|
||||
},
|
||||
|
||||
// Versailles 1685
|
||||
// Italian DOS
|
||||
// From lePhilousophe
|
||||
{
|
||||
{
|
||||
"versailles",
|
||||
"",
|
||||
VERSAILLES_ENTRY_DEF("VERSAILL.PGM", "1c992f034f43418a5da2e8ebd0b92620", 603023),
|
||||
Common::IT_ITA,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUI_OPTIONS_VERSAILLES
|
||||
},
|
||||
GType_VERSAILLES,
|
||||
GF_VERSAILLES_FONTS_SET_C | GF_VERSAILLES_AUDIOPADDING_YES | GF_VERSAILLES_LINK_STANDARD,
|
||||
},
|
||||
|
||||
// Versailles 1685
|
||||
// Italian Windows compressed from DVD
|
||||
// From Uka in forum
|
||||
{
|
||||
{
|
||||
"versailles",
|
||||
"",
|
||||
VERSAILLES_ENTRY_DEF("PROGRAM.Z", "8b0dcf71a7eb21b8378add8b16857bae", 237878),
|
||||
Common::IT_ITA,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUI_OPTIONS_VERSAILLES
|
||||
},
|
||||
GType_VERSAILLES,
|
||||
GF_VERSAILLES_FONTS_SET_C | GF_VERSAILLES_AUDIOPADDING_YES | GF_VERSAILLES_LINK_STANDARD,
|
||||
},
|
||||
|
||||
// Versailles 1685
|
||||
// German Macintosh
|
||||
// From lePhilousophe
|
||||
{
|
||||
{
|
||||
"versailles",
|
||||
"",
|
||||
VERSAILLES_ENTRY("Versailles", "f1aa0603e7f71404f936e4189b4c5b2b", 348614, "ALM"),
|
||||
Common::DE_DEU,
|
||||
Common::kPlatformMacintosh,
|
||||
ADGF_NO_FLAGS,
|
||||
GUI_OPTIONS_VERSAILLES
|
||||
},
|
||||
GType_VERSAILLES,
|
||||
GF_VERSAILLES_FONTS_SET_B | GF_VERSAILLES_AUDIOPADDING_YES | GF_VERSAILLES_LINK_LOCALIZED,
|
||||
},
|
||||
|
||||
// Versailles 1685
|
||||
// German Windows compressed from DVD
|
||||
// From laenion, ticket #11963
|
||||
{
|
||||
{
|
||||
"versailles",
|
||||
"",
|
||||
VERSAILLES_ENTRY("PROGRAM.Z", "cdd35a623d1ed05d1dc3248735cea868", 236363, "ALM"),
|
||||
Common::DE_DEU,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUI_OPTIONS_VERSAILLES
|
||||
},
|
||||
GType_VERSAILLES,
|
||||
GF_VERSAILLES_FONTS_NUMERIC | GF_VERSAILLES_AUDIOPADDING_YES | GF_VERSAILLES_LINK_LOCALIZED,
|
||||
},
|
||||
|
||||
// Versailles 1685
|
||||
// German Windows compressed from DVD
|
||||
// From Uka in forum
|
||||
{
|
||||
{
|
||||
"versailles",
|
||||
"",
|
||||
VERSAILLES_ENTRY_DEF("PROGRAM.Z", "2e1a40237f8b28cb6ef29cff137fa561", 238041),
|
||||
Common::DE_DEU,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUI_OPTIONS_VERSAILLES
|
||||
},
|
||||
GType_VERSAILLES,
|
||||
GF_VERSAILLES_FONTS_NUMERIC | GF_VERSAILLES_AUDIOPADDING_YES | GF_VERSAILLES_LINK_STANDARD,
|
||||
},
|
||||
|
||||
// Versailles 1685
|
||||
// Spanish Windows 95 from hybrid Win95/DOS CD
|
||||
// From lePhilousophe
|
||||
{
|
||||
{
|
||||
"versailles",
|
||||
"",
|
||||
VERSAILLES_ENTRY_DEF("VERSAILL.EXE", "78d90d656ec3b76f158721d38bc68083", 346112),
|
||||
Common::ES_ESP,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUI_OPTIONS_VERSAILLES
|
||||
},
|
||||
GType_VERSAILLES,
|
||||
GF_VERSAILLES_FONTS_NUMERIC | GF_VERSAILLES_AUDIOPADDING_YES | GF_VERSAILLES_LINK_STANDARD,
|
||||
},
|
||||
|
||||
// Versailles 1685
|
||||
// Spanish Windows 95 compressed from hybrid Win95/DOS CD
|
||||
// From lePhilousophe
|
||||
{
|
||||
{
|
||||
"versailles",
|
||||
"",
|
||||
VERSAILLES_ENTRY_DEF("PROGRAM.Z", "9e7c0c3125124010d45dde9dc62744ef", 237800),
|
||||
Common::ES_ESP,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUI_OPTIONS_VERSAILLES
|
||||
},
|
||||
GType_VERSAILLES,
|
||||
GF_VERSAILLES_FONTS_NUMERIC | GF_VERSAILLES_AUDIOPADDING_YES | GF_VERSAILLES_LINK_STANDARD,
|
||||
},
|
||||
|
||||
// Versailles 1685
|
||||
// Spanish DOS from hybrid Win95/DOS CD
|
||||
// From lePhilousophe
|
||||
{
|
||||
{
|
||||
"versailles",
|
||||
"",
|
||||
VERSAILLES_ENTRY_DEF("VERSAILL.PGM", "1c992f034f43418a5da2e8ebd0b92620", 715887),
|
||||
Common::ES_ESP,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUI_OPTIONS_VERSAILLES
|
||||
},
|
||||
GType_VERSAILLES,
|
||||
GF_VERSAILLES_FONTS_NUMERIC | GF_VERSAILLES_AUDIOPADDING_YES | GF_VERSAILLES_LINK_STANDARD,
|
||||
},
|
||||
|
||||
// Versailles 1685
|
||||
// Brazilian Windows from DVD
|
||||
// From Uka in forum
|
||||
{
|
||||
{
|
||||
"versailles",
|
||||
"",
|
||||
VERSAILLES_ENTRY_DEF("Versaill.exe", "49aa4581b8c652aa88c633b6c5fe84ea", 346112),
|
||||
Common::PT_BRA,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUI_OPTIONS_VERSAILLES
|
||||
},
|
||||
GType_VERSAILLES,
|
||||
GF_VERSAILLES_FONTS_NUMERIC | GF_VERSAILLES_AUDIOPADDING_YES | GF_VERSAILLES_LINK_STANDARD,
|
||||
},
|
||||
|
||||
// Versailles 1685
|
||||
// Brazilian Windows compressed from DVD
|
||||
// From Uka in forum
|
||||
{
|
||||
{
|
||||
"versailles",
|
||||
"",
|
||||
VERSAILLES_ENTRY_DEF("PROGRAM.Z", "013eabf30fdec7bb7302a5312d094c64", 237952),
|
||||
Common::PT_BRA,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUI_OPTIONS_VERSAILLES
|
||||
},
|
||||
GType_VERSAILLES,
|
||||
GF_VERSAILLES_FONTS_NUMERIC | GF_VERSAILLES_AUDIOPADDING_YES | GF_VERSAILLES_LINK_STANDARD,
|
||||
},
|
||||
|
||||
// Versailles 1685
|
||||
// Chinese Windows compressed from DVD
|
||||
// From lePhilousophe
|
||||
{
|
||||
{
|
||||
"versailles",
|
||||
"",
|
||||
VERSAILLES_ENTRY_DEF("PROGRAM.Z", "37f3d691e90e17b78050d6a91f7e0377", 242583),
|
||||
Common::ZH_TWN,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUI_OPTIONS_VERSAILLES
|
||||
},
|
||||
GType_VERSAILLES,
|
||||
/* GF_VERSAILLES_FONTS_ | */ GF_VERSAILLES_AUDIOPADDING_YES,
|
||||
},
|
||||
|
||||
// Versailles 1685
|
||||
// Chinese Windows from DVD
|
||||
// From lePhilousophe
|
||||
{
|
||||
{
|
||||
"versailles",
|
||||
"",
|
||||
VERSAILLES_ENTRY_DEF("VERSAILL.EXE", "5209e7c9b20612467af7e9745758ee72", 352256),
|
||||
Common::ZH_TWN,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUI_OPTIONS_VERSAILLES
|
||||
},
|
||||
GType_VERSAILLES,
|
||||
/* GF_VERSAILLES_FONTS_ | */ GF_VERSAILLES_AUDIOPADDING_YES,
|
||||
},
|
||||
|
||||
// Versailles 1685
|
||||
// Korean Windows compressed from DVD
|
||||
// From lePhilousophe
|
||||
{
|
||||
{
|
||||
"versailles",
|
||||
"",
|
||||
VERSAILLES_ENTRY_DEF("PROGRAM.Z", "ffb7599d042fb71f22ab4d76a2e0147f", 244155),
|
||||
Common::KO_KOR,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUI_OPTIONS_VERSAILLES
|
||||
},
|
||||
GType_VERSAILLES,
|
||||
/* GF_VERSAILLES_FONTS_ | */ GF_VERSAILLES_AUDIOPADDING_YES,
|
||||
},
|
||||
|
||||
// Versailles 1685
|
||||
// Korean Windows from DVD
|
||||
// From lePhilousophe
|
||||
{
|
||||
{
|
||||
"versailles",
|
||||
"",
|
||||
VERSAILLES_ENTRY_DEF("VERSAILL.EXE", "549c588e05df8d42b531ffc9b2796303", 355840),
|
||||
Common::KO_KOR,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUI_OPTIONS_VERSAILLES
|
||||
},
|
||||
GType_VERSAILLES,
|
||||
/* GF_VERSAILLES_FONTS_ | */ GF_VERSAILLES_AUDIOPADDING_YES,
|
||||
},
|
||||
|
||||
// Versailles 1685
|
||||
// Japanese Windows compressed from DVD
|
||||
// From lePhilousophe
|
||||
{
|
||||
{
|
||||
"versailles",
|
||||
"",
|
||||
VERSAILLES_ENTRY_DEF("PROGRAM.Z", "1944d7c30dbb25ab10f684422e196c16", 248700),
|
||||
Common::JA_JPN,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUI_OPTIONS_VERSAILLES
|
||||
},
|
||||
GType_VERSAILLES,
|
||||
/* GF_VERSAILLES_FONTS_ | */ GF_VERSAILLES_AUDIOPADDING_YES,
|
||||
},
|
||||
|
||||
// Versailles 1685
|
||||
// Japanese Windows from DVD
|
||||
// From lePhilousophe
|
||||
{
|
||||
{
|
||||
"versailles",
|
||||
"",
|
||||
VERSAILLES_ENTRY_DEF("VERSAILL.EXE", "b7dadaf14cc5783e235125f9d6f6adea", 358912),
|
||||
Common::JA_JPN,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUI_OPTIONS_VERSAILLES
|
||||
},
|
||||
GType_VERSAILLES,
|
||||
/* GF_VERSAILLES_FONTS_ | */ GF_VERSAILLES_AUDIOPADDING_YES,
|
||||
},
|
||||
|
||||
// Versailles 1685
|
||||
// Chinese Windows 95 from hybrid Win95/DOS CD
|
||||
// From kane159. on Discord
|
||||
{
|
||||
{
|
||||
"versailles",
|
||||
"",
|
||||
VERSAILLES_ENTRY_DEF("VERSAILL.EXE", "6b30654356ac219d2dda7ad8054146e4", 386048),
|
||||
Common::ZH_TWN,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUI_OPTIONS_VERSAILLES
|
||||
},
|
||||
GType_VERSAILLES,
|
||||
/* GF_VERSAILLES_FONTS_ | */ GF_VERSAILLES_AUDIOPADDING_YES | GF_VERSAILLES_LINK_STANDARD,
|
||||
},
|
||||
|
||||
// Versailles 1685
|
||||
// Chinese Windows 95 compressed from hybrid Win95/DOS CD
|
||||
// From kane159. on Discord
|
||||
{
|
||||
{
|
||||
"versailles",
|
||||
"",
|
||||
VERSAILLES_ENTRY_DEF("PROGRAM.Z", "62e0d8a68ce0ec92db5d1699db8679ec", 262633),
|
||||
Common::ZH_TWN,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUI_OPTIONS_VERSAILLES
|
||||
},
|
||||
GType_VERSAILLES,
|
||||
/* GF_VERSAILLES_FONTS_ | */ GF_VERSAILLES_AUDIOPADDING_YES | GF_VERSAILLES_LINK_STANDARD,
|
||||
},
|
||||
|
||||
// Versailles 1685
|
||||
// Chinese DOS from hybrid Win95/DOS CD
|
||||
// From kane159. on Discord
|
||||
{
|
||||
{
|
||||
"versailles",
|
||||
"",
|
||||
VERSAILLES_ENTRY_DEF("VERSAILL.PGM", "1c992f034f43418a5da2e8ebd0b92620", 725487),
|
||||
Common::ZH_TWN,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUI_OPTIONS_VERSAILLES
|
||||
},
|
||||
GType_VERSAILLES,
|
||||
/* GF_VERSAILLES_FONTS_ | */ GF_VERSAILLES_AUDIOPADDING_YES | GF_VERSAILLES_LINK_STANDARD,
|
||||
},
|
||||
|
||||
// Versailles 1685
|
||||
// English DOS Non-interactive Demo (US)
|
||||
{
|
||||
{
|
||||
"versailles",
|
||||
"Demo",
|
||||
AD_ENTRY1s("DEMO_US.HNS", "3a65a984353fec354dd26a62ca2cd3fb", 68462303),
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_DEMO,
|
||||
GUI_OPTIONS_HNM_PLAYER
|
||||
},
|
||||
GType_HNM_PLAYER,
|
||||
0,
|
||||
},
|
||||
|
||||
// Atlantis: The Lost Tales
|
||||
// English DOS Non-interactive Demo
|
||||
{
|
||||
{
|
||||
"atlantis",
|
||||
"Demo",
|
||||
AD_ENTRY1s("ATLANTIS.UBB", "f5b41b857678a61d7f9bd6eb41916ce5", 106611456),
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_DEMO,
|
||||
GUI_OPTIONS_HNM_PLAYER
|
||||
},
|
||||
GType_HNM_PLAYER,
|
||||
0,
|
||||
},
|
||||
|
||||
{ AD_TABLE_END_MARKER, 0, 0 }
|
||||
};
|
||||
|
||||
static const char *const directoryGlobs[] = {
|
||||
/** Versailles 1685 **/
|
||||
/* DATAS_V/ANIMACTI/LEVEL1/11D_LEB1.HNM
|
||||
* DATAS_V/ANIMACTI/LEVEL7/COFBOUM.HNM */
|
||||
"DATAS_V",
|
||||
/* When user doesn't want to overwrite */
|
||||
"DATAS_V1",
|
||||
"DATAS_V2",
|
||||
"ANIMACTI",
|
||||
"LEVEL1",
|
||||
"LEVEL7",
|
||||
/* PC Setup */
|
||||
/* INSTALL/DATA/TEXTES/LIEN_DOC.TXT
|
||||
* INSTALL/WIN/PROGRAM.Z
|
||||
* INSTALL/DOS/VERSAILL.PGM */
|
||||
"INSTALL",
|
||||
"DATA",
|
||||
"WIN",
|
||||
"DOS",
|
||||
/* Mac Setup */
|
||||
/* Versailles Folder/DATAV_HD/TEXTES/LIEN_DOC.TXT
|
||||
* Versailles Folder/Versailles */
|
||||
"Versailles Ordner",
|
||||
"Versailles Folder",
|
||||
"Dossier Versailles",
|
||||
"DATAV_HD",
|
||||
/* lien_doc.* */
|
||||
"TEXTES",
|
||||
|
||||
/** End of list **/
|
||||
nullptr
|
||||
};
|
||||
|
||||
//////////////////////////////
|
||||
//Fallback detection
|
||||
//////////////////////////////
|
||||
|
||||
static const CryOmni3DGameDescription fallbackDescs[] = {
|
||||
{
|
||||
{
|
||||
"versailles",
|
||||
"",
|
||||
AD_ENTRY1(0, 0),
|
||||
Common::UNK_LANG,
|
||||
Common::kPlatformUnknown,
|
||||
ADGF_UNSTABLE,
|
||||
GUIO0()
|
||||
},
|
||||
0,
|
||||
0,
|
||||
},
|
||||
};
|
||||
|
||||
static const ADFileBasedFallback fileBased[] = {
|
||||
{ &fallbackDescs[0].desc, { "11D_LEB1.HNM", "COFBOUM.HNM", "VERSAILL.PGM", 0 } },
|
||||
{ &fallbackDescs[0].desc, { "11D_LEB1.HNM", "COFBOUM.HNM", "PROGRAM.Z", 0 } },
|
||||
{ &fallbackDescs[0].desc, { "11D_LEB1.HNM", "COFBOUM.HNM", "VERSAILL.EXE", 0 } },
|
||||
{ &fallbackDescs[0].desc, { "11D_LEB1.HNM", "COFBOUM.HNM", "Versailles", 0 } },
|
||||
{ 0, { 0 } }
|
||||
};
|
||||
|
||||
} // End of namespace CryOmni3D
|
||||
557
engines/cryomni3d/dialogs_manager.cpp
Normal file
557
engines/cryomni3d/dialogs_manager.cpp
Normal file
@@ -0,0 +1,557 @@
|
||||
/* 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 "cryomni3d/dialogs_manager.h"
|
||||
|
||||
#include "common/debug.h"
|
||||
#include "common/file.h"
|
||||
|
||||
namespace CryOmni3D {
|
||||
|
||||
DialogsManager::~DialogsManager() {
|
||||
delete[] _gtoBuffer;
|
||||
}
|
||||
|
||||
void DialogsManager::loadGTO(const Common::Path >oFilePath) {
|
||||
Common::File gtoFile;
|
||||
if (!gtoFile.open(gtoFilePath)) {
|
||||
error("Can't open GTO file '%s'", gtoFilePath.toString(Common::Path::kNativeSeparator).c_str());
|
||||
}
|
||||
|
||||
_labels.clear();
|
||||
_gtoEnd = nullptr;
|
||||
delete[] _gtoBuffer;
|
||||
_gtoBuffer = nullptr;
|
||||
|
||||
uint gtoSize = gtoFile.size();
|
||||
_gtoBuffer = new char[gtoSize];
|
||||
gtoFile.read(_gtoBuffer, gtoSize);
|
||||
gtoFile.close();
|
||||
|
||||
_gtoEnd = _gtoBuffer + gtoSize;
|
||||
|
||||
populateLabels();
|
||||
}
|
||||
|
||||
void DialogsManager::populateLabels() {
|
||||
/* Get labels count and populate the labels array */
|
||||
uint numLabels;
|
||||
const char *labelsP = strstr(_gtoBuffer, "LABELS=");
|
||||
if (labelsP) {
|
||||
labelsP += sizeof("LABELS=") - 1;
|
||||
for (; *labelsP == ' '; labelsP++) { }
|
||||
numLabels = atoi(labelsP);
|
||||
} else {
|
||||
numLabels = 0;
|
||||
}
|
||||
|
||||
for (const char *labelP = _gtoBuffer; labelP != nullptr; labelP = nextLine(labelP)) {
|
||||
if (*labelP == ':') {
|
||||
/* Line starting with ':', it's a label */
|
||||
_labels.push_back(nextChar(labelP));
|
||||
}
|
||||
}
|
||||
|
||||
if (_labels.size() != numLabels) {
|
||||
error("Bad labels number in GTO");
|
||||
}
|
||||
}
|
||||
|
||||
const char *DialogsManager::findLabel(const char *label, const char **realLabel) const {
|
||||
uint labelLen = 0;
|
||||
/* Truncate input label */
|
||||
for (const char *labelP = label;
|
||||
*labelP != '\0' &&
|
||||
*labelP != ' ' &&
|
||||
*labelP != '.' &&
|
||||
*labelP != '\r'; labelP++, labelLen++) { }
|
||||
|
||||
Common::Array<const char *>::const_iterator labelsIt;
|
||||
for (labelsIt = _labels.begin(); labelsIt != _labels.end(); labelsIt++) {
|
||||
if (!strncmp(*labelsIt, label, labelLen)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (labelsIt == _labels.end()) {
|
||||
error("Label not found");
|
||||
}
|
||||
|
||||
if (realLabel) {
|
||||
*realLabel = *labelsIt;
|
||||
}
|
||||
return nextLine(*labelsIt);
|
||||
}
|
||||
|
||||
Common::String DialogsManager::getLabelSound(const char *label) const {
|
||||
/* Remove starting : if any */
|
||||
if (*label == ':') {
|
||||
label++;
|
||||
}
|
||||
|
||||
const char *labelEnd;
|
||||
for (labelEnd = label; *labelEnd >= '0' && *labelEnd <= 'Z'; labelEnd++) { }
|
||||
|
||||
return Common::String(label, labelEnd);
|
||||
}
|
||||
|
||||
const char *DialogsManager::findSequence(const char *sequence) const {
|
||||
uint sequenceLen = strlen(sequence);
|
||||
|
||||
const char *lineP;
|
||||
for (lineP = _gtoBuffer; lineP != nullptr; lineP = nextLine(lineP)) {
|
||||
if (!strncmp(lineP, sequence, sequenceLen)) {
|
||||
/* Line starting with the sequence name */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!lineP) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* Find next label */
|
||||
for (; lineP != nullptr && *lineP != ':'; lineP = nextLine(lineP)) { }
|
||||
|
||||
/* Return the label name without it's ':' */
|
||||
return nextChar(lineP);
|
||||
}
|
||||
|
||||
Common::String DialogsManager::findVideo(const char *data) const {
|
||||
data = previousMatch(data, ".FLC");
|
||||
if (data == nullptr) {
|
||||
return Common::String();
|
||||
}
|
||||
|
||||
// Video name is without the extension
|
||||
const char *end = data;
|
||||
|
||||
for (; data >= _gtoBuffer && *data != '\r'; data--) { }
|
||||
data++;
|
||||
|
||||
if (data < _gtoBuffer || *data == '.') {
|
||||
return Common::String();
|
||||
}
|
||||
|
||||
return Common::String(data, end);
|
||||
}
|
||||
|
||||
Common::String DialogsManager::getText(const char *text) const {
|
||||
/* Skip '<' */
|
||||
text = nextChar(text);
|
||||
|
||||
if (text == nullptr) {
|
||||
return Common::String();
|
||||
}
|
||||
|
||||
const char *end;
|
||||
for (end = text; end < _gtoEnd && *end != '>'; end++) { }
|
||||
|
||||
if (end == _gtoEnd) {
|
||||
return Common::String();
|
||||
}
|
||||
|
||||
return Common::String(text, end);
|
||||
}
|
||||
|
||||
void DialogsManager::reinitVariables() {
|
||||
for (Common::Array<DialogVariable>::iterator it = _dialogsVariables.begin();
|
||||
it != _dialogsVariables.end(); it++) {
|
||||
it->value = 'N';
|
||||
}
|
||||
}
|
||||
|
||||
const DialogsManager::DialogVariable &DialogsManager::find(const Common::String &name) const {
|
||||
for (Common::Array<DialogVariable>::const_iterator it = _dialogsVariables.begin();
|
||||
it != _dialogsVariables.end(); it++) {
|
||||
if (it->name == name) {
|
||||
return *it;
|
||||
}
|
||||
}
|
||||
error("Can't find dialog variable %s", name.c_str());
|
||||
}
|
||||
|
||||
DialogsManager::DialogVariable &DialogsManager::find(const Common::String &name) {
|
||||
for (Common::Array<DialogVariable>::iterator it = _dialogsVariables.begin();
|
||||
it != _dialogsVariables.end(); it++) {
|
||||
if (it->name == name) {
|
||||
return *it;
|
||||
}
|
||||
}
|
||||
error("Can't find dialog variable %s", name.c_str());
|
||||
}
|
||||
|
||||
const char *DialogsManager::nextLine(const char *currentPtr) const {
|
||||
for (; currentPtr < _gtoEnd && *currentPtr != '\r'; currentPtr++) { }
|
||||
|
||||
/* Go after the \r */
|
||||
return nextChar(currentPtr);
|
||||
}
|
||||
|
||||
const char *DialogsManager::nextChar(const char *currentPtr) const {
|
||||
if (currentPtr == nullptr || currentPtr < _gtoBuffer || currentPtr >= _gtoEnd) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
currentPtr++;
|
||||
|
||||
if (currentPtr >= _gtoEnd) {
|
||||
return nullptr;
|
||||
} else {
|
||||
return currentPtr;
|
||||
}
|
||||
}
|
||||
|
||||
const char *DialogsManager::previousMatch(const char *currentPtr, const char *str) const {
|
||||
if (currentPtr == nullptr || currentPtr >= _gtoEnd || currentPtr < _gtoBuffer) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uint matchLen = strlen(str);
|
||||
for (; currentPtr >= _gtoBuffer; currentPtr--) {
|
||||
if (*currentPtr == str[0]) {
|
||||
if (!strncmp(currentPtr, str, matchLen)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (currentPtr < _gtoBuffer) {
|
||||
return nullptr;
|
||||
} else {
|
||||
return currentPtr;
|
||||
}
|
||||
}
|
||||
|
||||
bool DialogsManager::play(const Common::String &sequence, bool &slowStop) {
|
||||
const char *label = findSequence(sequence.c_str());
|
||||
|
||||
if (!label) {
|
||||
error("Can't find sequence '%s' in GTO", sequence.c_str());
|
||||
}
|
||||
|
||||
Common::String video = sequence;
|
||||
|
||||
const char *text = findLabel(label);
|
||||
|
||||
slowStop = false;
|
||||
bool playerLabel = !strncmp(label, "JOU", 3);
|
||||
bool didSomething = false;
|
||||
bool finished = false;
|
||||
/* Keep the gotoList outside the loop to avoid it being freed at the end of it and
|
||||
* having label possibly pointing on free memory */
|
||||
Common::Array<DialogsManager::Goto> gotoList;
|
||||
while (!finished) {
|
||||
const char *actions;
|
||||
if (playerLabel) {
|
||||
/* If sequence begins with a player label go to action directly */
|
||||
playerLabel = false;
|
||||
actions = text;
|
||||
// Maybe a bug in original game, we should go to next line
|
||||
} else if (!strncmp(text, "<#>", 3)) {
|
||||
/* Text is empty: go to action directly */
|
||||
actions = nextLine(text);
|
||||
} else {
|
||||
/* Real text, play video */
|
||||
video = findVideo(text);
|
||||
Common::String properText = getText(text);
|
||||
Common::String sound = getLabelSound(label);
|
||||
Common::HashMap<Common::String, SubtitlesSettings>::const_iterator settingsIt =
|
||||
_subtitlesSettings.find(video);
|
||||
if (settingsIt == _subtitlesSettings.end()) {
|
||||
settingsIt = _subtitlesSettings.find("default");
|
||||
}
|
||||
if (settingsIt == _subtitlesSettings.end()) {
|
||||
error("No video settings for %s", video.c_str());
|
||||
}
|
||||
playDialog(video, sound, properText, settingsIt->_value);
|
||||
didSomething = true;
|
||||
actions = nextLine(text);
|
||||
}
|
||||
gotoList = executeAfterPlayAndBuildGotoList(actions);
|
||||
Common::StringArray questions;
|
||||
bool endOfConversationFound = false;
|
||||
if (_ignoreNoEndOfConversation) {
|
||||
// Don't check if there is an end, so, there is one
|
||||
endOfConversationFound = true;
|
||||
}
|
||||
for (Common::Array<DialogsManager::Goto>::iterator it = gotoList.begin(); it != gotoList.end();
|
||||
it++) {
|
||||
if (!endOfConversationFound && it->label.hasPrefix("JOU")) {
|
||||
// No need to get the real label here, we just need to know if the question ends up
|
||||
if (!executePlayerQuestion(it->text, true)) {
|
||||
endOfConversationFound = true;
|
||||
}
|
||||
}
|
||||
assert(it->text);
|
||||
const char *questionStart = it->text + 1;
|
||||
const char *questionEnd = questionStart;
|
||||
for (; *questionEnd != '>'; questionEnd++) { }
|
||||
questions.push_back(Common::String(questionStart, questionEnd));
|
||||
}
|
||||
uint eocInserted = uint(-1);
|
||||
if (!endOfConversationFound && questions.size() > 0) {
|
||||
eocInserted = questions.size();
|
||||
questions.push_back(_endOfConversationText);
|
||||
}
|
||||
if (questions.size() == 0) {
|
||||
// There are no choices, just quit with a pause to avoid abrupt ending
|
||||
slowStop = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (gotoList[0].label.hasPrefix("JOU")) {
|
||||
// We must give a subject
|
||||
uint playerChoice = askPlayerQuestions(video, questions);
|
||||
didSomething = true;
|
||||
// -1 when shouldAbort
|
||||
if (playerChoice == uint(-1) || playerChoice == eocInserted) {
|
||||
break;
|
||||
}
|
||||
|
||||
text = executePlayerQuestion(gotoList[playerChoice].text, false, &label);
|
||||
if (!text) {
|
||||
break;
|
||||
}
|
||||
} else if (gotoList[0].label.hasPrefix("MES")) {
|
||||
// Display a simple message
|
||||
const char *messageStart = gotoList[0].text + 1;
|
||||
const char *messageEnd = messageStart;
|
||||
for (; *messageEnd != '>'; messageEnd++) { }
|
||||
displayMessage(Common::String(messageStart, messageEnd));
|
||||
break;
|
||||
} else {
|
||||
// Unattended conversation: two NPC speak
|
||||
label = gotoList[0].label.c_str();
|
||||
text = gotoList[0].text;
|
||||
}
|
||||
}
|
||||
return didSomething;
|
||||
}
|
||||
|
||||
Common::Array<DialogsManager::Goto> DialogsManager::executeAfterPlayAndBuildGotoList(
|
||||
const char *actions) {
|
||||
Common::Array<DialogsManager::Goto> gotos;
|
||||
|
||||
for (; actions && *actions != ':'; actions = nextLine(actions)) {
|
||||
if (!strncmp(actions, "GOTO ", 5)) {
|
||||
buildGotoGoto(actions, gotos);
|
||||
break;
|
||||
} else if (!strncmp(actions, "IF ", 3)) {
|
||||
if (buildGotoIf(actions, gotos)) {
|
||||
break;
|
||||
}
|
||||
} else if (!strncmp(actions, "LET ", 4)) {
|
||||
executeLet(actions);
|
||||
} else if (!strncmp(actions, "SHOW ", 5)) {
|
||||
executeShow(actions);
|
||||
}
|
||||
}
|
||||
return gotos;
|
||||
}
|
||||
|
||||
void DialogsManager::buildGotoGoto(const char *gotoLine, Common::Array<Goto> &gotos) {
|
||||
Common::String label;
|
||||
gotoLine = gotoLine + 5;
|
||||
while (true) {
|
||||
const char *labelEnd = gotoLine;
|
||||
for (labelEnd = gotoLine; *labelEnd >= '0' && *labelEnd <= 'Z'; labelEnd++) { }
|
||||
label = Common::String(gotoLine, labelEnd);
|
||||
|
||||
if (label == "REM") {
|
||||
break;
|
||||
}
|
||||
|
||||
// To build goto list, no need to get back the real label position
|
||||
const char *text = findLabel(label.c_str());
|
||||
gotos.push_back(Goto(label, text));
|
||||
|
||||
if (*labelEnd == '.') {
|
||||
if (!strncmp(labelEnd, ".WAV", 4)) {
|
||||
labelEnd += 4;
|
||||
} else {
|
||||
debug("Problem with GOTO.WAV: '%s'", gotoLine);
|
||||
}
|
||||
}
|
||||
for (; *labelEnd == ' ' || *labelEnd == ','; labelEnd++) { }
|
||||
|
||||
if (*labelEnd == '\r') {
|
||||
break;
|
||||
}
|
||||
|
||||
// Next goto tag
|
||||
gotoLine = labelEnd;
|
||||
}
|
||||
}
|
||||
|
||||
bool DialogsManager::buildGotoIf(const char *ifLine, Common::Array<Goto> &gotos) {
|
||||
ifLine += 3;
|
||||
|
||||
bool finishedConditions = false;
|
||||
while (!finishedConditions) {
|
||||
const char *endVar = ifLine;
|
||||
const char *equalPos;
|
||||
// Find next '='
|
||||
for (; *endVar != '='; endVar++) { }
|
||||
equalPos = endVar;
|
||||
// Strip spaces at the end
|
||||
endVar--;
|
||||
for (; *endVar == ' '; endVar--) { }
|
||||
endVar++;
|
||||
Common::String variable(ifLine, endVar);
|
||||
|
||||
const char *testValue = equalPos + 1;
|
||||
for (; *testValue == ' ' || *testValue == '\t'; testValue++) { }
|
||||
|
||||
byte value = (*this)[variable];
|
||||
|
||||
if (value != *testValue) {
|
||||
// IF is not taken, go to next line
|
||||
return false;
|
||||
}
|
||||
|
||||
ifLine = testValue + 1;
|
||||
for (; *ifLine == ' ' || *ifLine == '\t'; ifLine++) { }
|
||||
|
||||
if (!strncmp(ifLine, "AND IF ", 7)) {
|
||||
ifLine += 7;
|
||||
} else {
|
||||
finishedConditions = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* We are in the (implicit) THEN part of the IF
|
||||
* ifLine points to the instruction */
|
||||
if (!strncmp(ifLine, "GOTO", 4)) {
|
||||
buildGotoGoto(ifLine, gotos);
|
||||
} else if (!strncmp(ifLine, "LET", 3)) {
|
||||
executeLet(ifLine);
|
||||
} else if (!strncmp(ifLine, "SHOW", 4)) {
|
||||
executeShow(ifLine);
|
||||
} else {
|
||||
debug("Invalid IF line: %s", ifLine);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DialogsManager::executeLet(const char *letLine) {
|
||||
letLine = letLine + 4;
|
||||
|
||||
const char *endVar = letLine;
|
||||
const char *equalPos;
|
||||
// Find next '='
|
||||
for (; *endVar != '='; endVar++) { }
|
||||
equalPos = endVar;
|
||||
// Strip spaces at the end
|
||||
endVar--;
|
||||
for (; *endVar == ' '; endVar--) { }
|
||||
endVar++;
|
||||
Common::String variable(letLine, endVar);
|
||||
|
||||
(*this)[variable] = equalPos[1];
|
||||
}
|
||||
|
||||
void DialogsManager::executeShow(const char *showLine) {
|
||||
showLine = showLine + 5;
|
||||
|
||||
const char *endShow = showLine;
|
||||
// Find next ')' and include it
|
||||
for (; *endShow != ')'; endShow++) { }
|
||||
endShow++;
|
||||
|
||||
Common::String show(showLine, endShow);
|
||||
|
||||
executeShow(show);
|
||||
}
|
||||
|
||||
const char *DialogsManager::executePlayerQuestion(const char *text, bool dryRun,
|
||||
const char **realLabel) {
|
||||
// Go after the text
|
||||
const char *actions = nextLine(text);
|
||||
|
||||
while (actions && *actions != ':') {
|
||||
if (!strncmp(actions, "IF ", 3)) {
|
||||
actions = parseIf(actions);
|
||||
} else if (!strncmp(actions, "LET ", 4)) {
|
||||
if (!dryRun) {
|
||||
executeLet(actions);
|
||||
}
|
||||
actions = nextLine(actions);
|
||||
} else if (!strncmp(actions, "GOTO ", 5)) {
|
||||
return findLabel(actions + 5, realLabel);
|
||||
} else {
|
||||
actions = nextLine(actions);
|
||||
}
|
||||
}
|
||||
|
||||
// There were no GOTO, so it's the end of the conversation
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const char *DialogsManager::parseIf(const char *ifLine) {
|
||||
ifLine += 3;
|
||||
|
||||
bool finishedConditions = false;
|
||||
while (!finishedConditions) {
|
||||
const char *endVar = ifLine;
|
||||
const char *equalPos;
|
||||
// Find next '='
|
||||
for (; *endVar != '='; endVar++) { }
|
||||
equalPos = endVar;
|
||||
// Strip spaces at the end
|
||||
endVar--;
|
||||
for (; *endVar == ' '; endVar--) { }
|
||||
endVar++;
|
||||
Common::String variable(ifLine, endVar);
|
||||
|
||||
const char *testValue = equalPos + 1;
|
||||
for (; *testValue == ' ' || *testValue == '\t'; testValue++) { }
|
||||
|
||||
byte value = (*this)[variable];
|
||||
|
||||
if (value != *testValue) {
|
||||
// IF is not taken, go to next line
|
||||
return nextLine(ifLine);
|
||||
}
|
||||
|
||||
ifLine = testValue + 1;
|
||||
for (; *ifLine == ' ' || *ifLine == '\t'; ifLine++) { }
|
||||
|
||||
if (!strncmp(ifLine, "AND IF ", 7)) {
|
||||
ifLine += 7;
|
||||
} else {
|
||||
finishedConditions = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* We are in the (implicit) THEN part of the IF
|
||||
* ifLine points to the instruction */
|
||||
return ifLine;
|
||||
}
|
||||
|
||||
void DialogsManager::registerSubtitlesSettings(const Common::String &videoName,
|
||||
const SubtitlesSettings &settings) {
|
||||
_subtitlesSettings[videoName] = settings;
|
||||
}
|
||||
|
||||
} // End of namespace CryOmni3D
|
||||
133
engines/cryomni3d/dialogs_manager.h
Normal file
133
engines/cryomni3d/dialogs_manager.h
Normal file
@@ -0,0 +1,133 @@
|
||||
/* 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 CRYOMNI3D_DIALOGS_MANAGER_H
|
||||
#define CRYOMNI3D_DIALOGS_MANAGER_H
|
||||
|
||||
#include "common/array.h"
|
||||
#include "common/hash-str.h"
|
||||
#include "common/hashmap.h"
|
||||
#include "common/path.h"
|
||||
#include "common/rect.h"
|
||||
#include "common/str.h"
|
||||
#include "common/str-array.h"
|
||||
|
||||
namespace CryOmni3D {
|
||||
|
||||
class DialogsManager {
|
||||
public:
|
||||
struct SubtitlesSettings {
|
||||
SubtitlesSettings() { }
|
||||
SubtitlesSettings(int16 textLeft, int16 textTop, int16 textRight, int16 textBottom,
|
||||
int16 drawLeft, int16 drawTop, int16 drawRight, int16 drawBottom) :
|
||||
textRect(textLeft, textTop, textRight, textBottom), drawRect(drawLeft, drawTop, drawRight,
|
||||
drawBottom) { }
|
||||
Common::Rect textRect;
|
||||
Common::Rect drawRect;
|
||||
};
|
||||
|
||||
DialogsManager() : _gtoBuffer(nullptr), _gtoEnd(nullptr),
|
||||
_ignoreNoEndOfConversation(false) { }
|
||||
virtual ~DialogsManager();
|
||||
|
||||
void init(uint arraySize, const Common::String &endOfConversationText) { _dialogsVariables.resize(arraySize); _endOfConversationText = endOfConversationText; }
|
||||
void loadGTO(const Common::Path >oFilePath);
|
||||
|
||||
void setupVariable(uint id, const Common::String &variable) { _dialogsVariables[id] = DialogVariable(variable, 'N'); }
|
||||
void reinitVariables();
|
||||
uint size() const { return _dialogsVariables.size(); }
|
||||
byte &operator[](uint idx) { return _dialogsVariables[idx].value; }
|
||||
const byte &operator[](uint idx) const { return _dialogsVariables[idx].value; }
|
||||
byte &operator[](const Common::String &name) { return find(name).value; }
|
||||
const byte &operator[](const Common::String &name) const { return find(name).value; }
|
||||
|
||||
void registerSubtitlesSettings(const Common::String &videoName, const SubtitlesSettings &settings);
|
||||
|
||||
void setIgnoreNoEndOfConversation(bool ignore) { _ignoreNoEndOfConversation = ignore; }
|
||||
bool play(const Common::String &sequence, bool &slowStop);
|
||||
|
||||
protected:
|
||||
virtual void executeShow(const Common::String &show) = 0;
|
||||
virtual void playDialog(const Common::String &video, const Common::String &sound,
|
||||
const Common::String &text, const SubtitlesSettings &settings) = 0;
|
||||
virtual void displayMessage(const Common::String &text) = 0;
|
||||
virtual uint askPlayerQuestions(const Common::String &video,
|
||||
const Common::StringArray &questions) = 0;
|
||||
|
||||
private:
|
||||
struct Goto {
|
||||
Goto() : label(), text(nullptr) {
|
||||
}
|
||||
Goto(const Common::String &label_, const char *text_) : label(label_), text(text_) {
|
||||
}
|
||||
|
||||
Common::String label;
|
||||
const char *text;
|
||||
};
|
||||
|
||||
struct DialogVariable {
|
||||
DialogVariable() : name(), value(0) {
|
||||
}
|
||||
DialogVariable(const Common::String &name_, byte value_) : name(name_), value(value_) {
|
||||
}
|
||||
|
||||
Common::String name;
|
||||
byte value;
|
||||
};
|
||||
|
||||
const DialogVariable &find(const Common::String &name) const;
|
||||
DialogVariable &find(const Common::String &name);
|
||||
Common::Array<DialogVariable> _dialogsVariables;
|
||||
|
||||
void populateLabels();
|
||||
const char *findLabel(const char *label, const char **realLabel = nullptr) const;
|
||||
Common::String getLabelSound(const char *label) const;
|
||||
|
||||
const char *findSequence(const char *sequence) const;
|
||||
Common::String findVideo(const char *data) const;
|
||||
Common::String getText(const char *text) const;
|
||||
|
||||
Common::Array<Goto> executeAfterPlayAndBuildGotoList(const char *actions);
|
||||
void buildGotoGoto(const char *gotoLine, Common::Array<Goto> &gotos);
|
||||
bool buildGotoIf(const char *ifLine, Common::Array<Goto> &gotos);
|
||||
void executeLet(const char *letLine);
|
||||
void executeShow(const char *showLine);
|
||||
|
||||
const char *executePlayerQuestion(const char *text, bool dryRun, const char **realLabel = nullptr);
|
||||
const char *parseIf(const char *ifLine);
|
||||
|
||||
const char *nextLine(const char *currentPtr) const;
|
||||
const char *nextChar(const char *currentPtr) const;
|
||||
const char *previousMatch(const char *currentPtr, const char *str) const;
|
||||
|
||||
char *_gtoBuffer;
|
||||
const char *_gtoEnd;
|
||||
Common::Array<const char *> _labels;
|
||||
|
||||
Common::String _endOfConversationText;
|
||||
bool _ignoreNoEndOfConversation;
|
||||
|
||||
Common::HashMap<Common::String, SubtitlesSettings> _subtitlesSettings;
|
||||
};
|
||||
|
||||
} // End of namespace CryOmni3D
|
||||
|
||||
#endif
|
||||
337
engines/cryomni3d/fixed_image.cpp
Normal file
337
engines/cryomni3d/fixed_image.cpp
Normal file
@@ -0,0 +1,337 @@
|
||||
/* 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 "cryomni3d/fixed_image.h"
|
||||
|
||||
#include "common/file.h"
|
||||
#include "common/system.h"
|
||||
#include "graphics/palette.h"
|
||||
#include "graphics/surface.h"
|
||||
#include "image/image_decoder.h"
|
||||
|
||||
namespace CryOmni3D {
|
||||
|
||||
ZonFixedImage::ZonFixedImage(CryOmni3DEngine &engine,
|
||||
Inventory &inventory,
|
||||
const Sprites &sprites,
|
||||
const FixedImageConfiguration *configuration) :
|
||||
_engine(engine), _inventory(inventory), _sprites(sprites),
|
||||
_configuration(configuration),
|
||||
_callback(nullptr), _imageDecoder(nullptr), _imageSurface(nullptr),
|
||||
_zonesMode(kZonesMode_None), _currentZone(uint(-1)), _exit(false), _zoneLow(false),
|
||||
_zoneHigh(false), _zoneHighLeft(false), _zoneHighRight(false), _zoneLeft(false), _zoneRight(false),
|
||||
_zoneQuestion(false), _zoneListen(false), _zoneSee(false), _zoneUse(false), _zoneSpeak(false),
|
||||
_usedObject(nullptr), _highLeftId(0), _highRightId(0), _refreshCursor(false) {
|
||||
}
|
||||
|
||||
ZonFixedImage::~ZonFixedImage() {
|
||||
delete _imageDecoder;
|
||||
}
|
||||
|
||||
void ZonFixedImage::run(const CallbackFunctor *callback) {
|
||||
_exit = false;
|
||||
_zonesMode = kZonesMode_None;
|
||||
|
||||
_callback = callback;
|
||||
|
||||
_engine.showMouse(true);
|
||||
while (!_exit) {
|
||||
(*_callback)(this);
|
||||
}
|
||||
_engine.waitMouseRelease();
|
||||
_engine.showMouse(false);
|
||||
|
||||
// Deselect object
|
||||
_inventory.setSelectedObject(nullptr);
|
||||
|
||||
delete _callback;
|
||||
_callback = nullptr;
|
||||
|
||||
// Don't use the current _imageSurface, we may not own it anymore
|
||||
_imageSurface = nullptr;
|
||||
}
|
||||
|
||||
// Just pass a const char * for zone because it's for workarounds and constructing a null String at almost each load call is inefficient
|
||||
void ZonFixedImage::load(const Common::Path &image, const char *zone) {
|
||||
_imageSurface = nullptr;
|
||||
delete _imageDecoder;
|
||||
_imageDecoder = nullptr;
|
||||
|
||||
_imageDecoder = _engine.loadHLZ(image);
|
||||
if (!_imageDecoder) {
|
||||
error("Can't display fixed image");
|
||||
}
|
||||
_imageSurface = _imageDecoder->getSurface();
|
||||
|
||||
Common::Path zonePath(zone ? image.getParent().appendComponent(zone) : image);
|
||||
loadZones(zonePath);
|
||||
|
||||
#if 0
|
||||
// This is not correct but to debug zones I think it's OK
|
||||
Graphics::Surface *tmpSurf = (Graphics::Surface *) _imageSurface;
|
||||
for (Common::Array<Zone>::const_iterator it = _zones.begin(); it != _zones.end(); it++) {
|
||||
Common::Rect tmp = it->rect;
|
||||
tmpSurf->frameRect(tmp, 244);
|
||||
}
|
||||
#endif
|
||||
|
||||
_zonesMode = kZonesMode_Standard;
|
||||
_refreshCursor = true;
|
||||
|
||||
display();
|
||||
|
||||
// WORKAROUND: Wait for release after displaying the fixed image to avoid handling events due to mouse being pressed
|
||||
// There is this bug in game
|
||||
// Don't display cursor to prevent displaying an invalid cursor
|
||||
_engine.showMouse(false);
|
||||
g_system->updateScreen();
|
||||
_engine.waitMouseRelease();
|
||||
_engine.showMouse(true);
|
||||
}
|
||||
|
||||
void ZonFixedImage::display() const {
|
||||
_engine.setupPalette(_imageDecoder->getPalette().data(), 0,
|
||||
_imageDecoder->getPalette().size());
|
||||
|
||||
g_system->copyRectToScreen(_imageSurface->getPixels(), _imageSurface->pitch, 0, 0,
|
||||
_imageSurface->w, _imageSurface->h);
|
||||
g_system->updateScreen();
|
||||
}
|
||||
|
||||
void ZonFixedImage::loadZones(const Common::Path &image) {
|
||||
_zones.clear();
|
||||
|
||||
Common::String fname(image.baseName());
|
||||
int lastDotPos = fname.findLastOf('.');
|
||||
assert(lastDotPos > -1);
|
||||
fname.erase(lastDotPos + 1);
|
||||
fname += "zon";
|
||||
|
||||
Common::Path zonPath = image.getParent().appendComponent(fname);
|
||||
|
||||
Common::File zonFile;
|
||||
if (!zonFile.open(zonPath)) {
|
||||
error("Can't open ZON file '%s'", zonPath.toString(Common::Path::kNativeSeparator).c_str());
|
||||
}
|
||||
|
||||
int32 zonesNumber = zonFile.size() / 26;
|
||||
_zones.reserve(zonesNumber);
|
||||
|
||||
_highLeftId = Common::Array<CryOmni3D::ZonFixedImage::Zone>::size_type(-1);
|
||||
_highRightId = Common::Array<CryOmni3D::ZonFixedImage::Zone>::size_type(-1);
|
||||
|
||||
int leftSeen = 0x7fffffff; // MAX_INT
|
||||
int rightSeen = 0;
|
||||
Common::Array<Zone>::size_type index = 0;
|
||||
|
||||
while (zonesNumber > 0) {
|
||||
Zone zone;
|
||||
zone.rect.left = zonFile.readSint16BE();
|
||||
zone.rect.top = zonFile.readSint16BE();
|
||||
zone.rect.right = zonFile.readSint16BE();
|
||||
zone.rect.bottom = zonFile.readSint16BE();
|
||||
zone.spriteId = zonFile.readSint16BE();
|
||||
zone.cursorId = _sprites.revMapSpriteId(zone.spriteId);
|
||||
zone.valid = true;
|
||||
zonFile.skip(16);
|
||||
|
||||
_zones.push_back(zone);
|
||||
|
||||
if (zone.cursorId == _configuration->spriteHigh) {
|
||||
if (leftSeen > zone.rect.right) {
|
||||
// The right side is at the leftest seen
|
||||
leftSeen = zone.rect.right;
|
||||
_highLeftId = index;
|
||||
}
|
||||
if (rightSeen < zone.rect.left) {
|
||||
// The left side is at the rightest seen
|
||||
rightSeen = zone.rect.left;
|
||||
_highRightId = index;
|
||||
}
|
||||
}
|
||||
|
||||
zonesNumber--;
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
Common::Point ZonFixedImage::getZoneCenter(uint zoneId) const {
|
||||
if (zoneId >= _zones.size()) {
|
||||
error("Invalid zoneId %u/%u", zoneId, _zones.size());
|
||||
}
|
||||
const Common::Rect &rect = _zones[zoneId].rect;
|
||||
|
||||
return Common::Point((rect.left + rect.right) / 2, (rect.top + rect.bottom) / 2);
|
||||
}
|
||||
|
||||
void ZonFixedImage::manage() {
|
||||
_currentZone = uint(-1);
|
||||
_zoneLow = false;
|
||||
_zoneHigh = false;
|
||||
_zoneHighLeft = false;
|
||||
_zoneHighRight = false;
|
||||
_zoneLeft = false;
|
||||
_zoneRight = false;
|
||||
_zoneQuestion = false;
|
||||
_zoneListen = false;
|
||||
_zoneSee = false;
|
||||
_zoneUse = false;
|
||||
_zoneSpeak = false;
|
||||
_usedObject = nullptr;
|
||||
_key.reset();
|
||||
|
||||
// As the game lets load/save from main menu displayed by cliking from the toolbar,
|
||||
// it's safe to enable GMM Load/Save there
|
||||
_engine.setCanLoadSave(true);
|
||||
|
||||
// Force poll events even when we must refresh the cursor
|
||||
if (!_engine.pollEvents() && !_refreshCursor) {
|
||||
g_system->updateScreen();
|
||||
g_system->delayMillis(10);
|
||||
_engine.setCanLoadSave(false);
|
||||
return;
|
||||
}
|
||||
_refreshCursor = false;
|
||||
|
||||
// Feed the key for the caller
|
||||
_key = _engine.getNextKey();
|
||||
Common::Point mousePos = _engine.getMousePos();
|
||||
|
||||
if (_key == Common::KEYCODE_ESCAPE) {
|
||||
_exit = true;
|
||||
_engine.setCanLoadSave(false);
|
||||
return;
|
||||
} else if (_engine.shouldAbort()) {
|
||||
_exit = true;
|
||||
_engine.setCanLoadSave(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_key == Common::KEYCODE_SPACE ||
|
||||
_engine.getCurrentMouseButton() == 2 ||
|
||||
mousePos.y > _configuration->toolbarTriggerY) {
|
||||
bool mustRedraw = _engine.displayToolbar(_imageSurface);
|
||||
// We just came back from toolbar: check if an object is selected and go into object mode
|
||||
if (_inventory.selectedObject()) {
|
||||
_zonesMode = kZonesMode_Object;
|
||||
}
|
||||
if (mustRedraw) {
|
||||
display();
|
||||
}
|
||||
// Return without any event to redo the loop and force refresh
|
||||
_refreshCursor = true;
|
||||
_engine.setCanLoadSave(false);
|
||||
return;
|
||||
}
|
||||
|
||||
Common::Array<Zone>::iterator zoneIt;
|
||||
for (zoneIt = _zones.begin(); zoneIt != _zones.end(); zoneIt++) {
|
||||
if (zoneIt->valid && zoneIt->rect.contains(mousePos)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (zoneIt != _zones.end()) {
|
||||
_currentZone = zoneIt - _zones.begin();
|
||||
} else {
|
||||
_currentZone = uint(-1);
|
||||
}
|
||||
|
||||
if (_zonesMode == kZonesMode_Standard) {
|
||||
if (zoneIt != _zones.end()) {
|
||||
_engine.setCursor(zoneIt->cursorId);
|
||||
if (_engine.getCurrentMouseButton() == 1) {
|
||||
handleMouseZones(zoneIt);
|
||||
}
|
||||
} else {
|
||||
_engine.setCursor(_configuration->spriteNothing);
|
||||
}
|
||||
} else if (_zonesMode == kZonesMode_Object) {
|
||||
Object *selectedObj = _inventory.selectedObject();
|
||||
if (!selectedObj) {
|
||||
// Normally useless but we never know
|
||||
_engine.setCursor(_configuration->spriteNothing);
|
||||
} else if (zoneIt != _zones.end()) {
|
||||
_engine.setCursor(selectedObj->idSA());
|
||||
if (_engine.getDragStatus() == kDragStatus_Finished) {
|
||||
// Just clicked, store the event and go back to standard mode
|
||||
_usedObject = selectedObj;
|
||||
_zonesMode = kZonesMode_Standard;
|
||||
// We changed mode: need to refresh
|
||||
_refreshCursor = true;
|
||||
}
|
||||
} else {
|
||||
_engine.setCursor(selectedObj->idSl());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
g_system->updateScreen();
|
||||
g_system->delayMillis(10);
|
||||
|
||||
_engine.setCanLoadSave(false);
|
||||
}
|
||||
|
||||
void ZonFixedImage::handleMouseZones(const Common::Array<Zone>::const_iterator ¤tZone) {
|
||||
if (currentZone->cursorId == _configuration->spriteLow) {
|
||||
_zoneLow = true;
|
||||
} else if (currentZone->cursorId == _configuration->spriteHigh) {
|
||||
Common::Array<Zone>::size_type id = currentZone - _zones.begin();
|
||||
if (id == _highLeftId) {
|
||||
_zoneHighLeft = true;
|
||||
} else if (id == _highRightId) {
|
||||
_zoneHighRight = true;
|
||||
} else {
|
||||
_zoneHigh = true;
|
||||
}
|
||||
} else if (currentZone->cursorId == _configuration->spriteLeft) {
|
||||
_zoneLeft = true;
|
||||
} else if (currentZone->cursorId == _configuration->spriteRight) {
|
||||
_zoneRight = true;
|
||||
} else if (currentZone->cursorId == _configuration->spriteQuestion) {
|
||||
_zoneQuestion = true;
|
||||
} else if (currentZone->cursorId == _configuration->spriteListen) {
|
||||
_zoneListen = true;
|
||||
} else if (currentZone->cursorId == _configuration->spriteSee) {
|
||||
_zoneSee = true;
|
||||
} else if (currentZone->cursorId == _configuration->spriteUse) {
|
||||
_zoneUse = true;
|
||||
} else if (currentZone->cursorId == _configuration->spriteSpeak) {
|
||||
_zoneSpeak = true;
|
||||
} else {
|
||||
error("Invalid cursor ID: %d in ImgFix", currentZone->cursorId);
|
||||
}
|
||||
}
|
||||
|
||||
void ZonFixedImage::updateSurface(const Graphics::Surface *newSurface) {
|
||||
if (newSurface->w != _imageSurface->w ||
|
||||
newSurface->h != _imageSurface->h ||
|
||||
newSurface->format != _imageSurface->format) {
|
||||
error("New surface has invalid attributes");
|
||||
}
|
||||
|
||||
// Be careful the surface must be destroyed after the fixed image has finished with it
|
||||
_imageSurface = newSurface;
|
||||
|
||||
display();
|
||||
}
|
||||
|
||||
} // End of namespace CryOmni3D
|
||||
129
engines/cryomni3d/fixed_image.h
Normal file
129
engines/cryomni3d/fixed_image.h
Normal file
@@ -0,0 +1,129 @@
|
||||
/* 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 CRYOMNI3D_FIXED_IMAGE_H
|
||||
#define CRYOMNI3D_FIXED_IMAGE_H
|
||||
|
||||
#include "common/func.h"
|
||||
|
||||
#include "cryomni3d/cryomni3d.h"
|
||||
#include "cryomni3d/objects.h"
|
||||
|
||||
namespace Graphics {
|
||||
struct Surface;
|
||||
}
|
||||
|
||||
namespace CryOmni3D {
|
||||
|
||||
struct FixedImageConfiguration {
|
||||
uint spriteNothing;
|
||||
uint spriteLow;
|
||||
uint spriteHigh;
|
||||
uint spriteLeft;
|
||||
uint spriteRight;
|
||||
uint spriteQuestion;
|
||||
uint spriteListen;
|
||||
uint spriteSee;
|
||||
uint spriteUse;
|
||||
uint spriteSpeak;
|
||||
|
||||
int16 toolbarTriggerY;
|
||||
};
|
||||
|
||||
class ZonFixedImage {
|
||||
public:
|
||||
typedef Common::Functor1<ZonFixedImage *, void> CallbackFunctor;
|
||||
enum ZonesMode {
|
||||
kZonesMode_None = 0,
|
||||
kZonesMode_Standard,
|
||||
kZonesMode_Object
|
||||
};
|
||||
|
||||
/* These functions are used in main engine code */
|
||||
ZonFixedImage(CryOmni3DEngine &engine, Inventory &inventory, const Sprites &sprites,
|
||||
const FixedImageConfiguration *configuration);
|
||||
~ZonFixedImage();
|
||||
|
||||
void run(const CallbackFunctor *callback);
|
||||
|
||||
/* This function is used to refresh image after various events */
|
||||
void display() const;
|
||||
|
||||
/* These functions and attributes are used in image handler */
|
||||
void load(const Common::Path &image, const char *zone = nullptr);
|
||||
void manage();
|
||||
void updateSurface(const Graphics::Surface *newSurface);
|
||||
const Graphics::Surface *surface() const { return _imageSurface; }
|
||||
void changeCallback(CallbackFunctor *callback) { delete _callback; _callback = callback; }
|
||||
Common::Point getZoneCenter(uint zoneId) const;
|
||||
void disableZone(uint zoneId) { _zones[zoneId].valid = false; }
|
||||
|
||||
ZonesMode _zonesMode;
|
||||
|
||||
/* These attributes are read by the image handler to check what action player did */
|
||||
uint _currentZone;
|
||||
bool _exit;
|
||||
bool _zoneLow;
|
||||
bool _zoneHigh;
|
||||
bool _zoneHighLeft;
|
||||
bool _zoneHighRight;
|
||||
bool _zoneLeft;
|
||||
bool _zoneRight;
|
||||
bool _zoneQuestion;
|
||||
bool _zoneListen;
|
||||
bool _zoneSee;
|
||||
bool _zoneUse;
|
||||
bool _zoneSpeak;
|
||||
Object *_usedObject;
|
||||
Common::KeyState _key;
|
||||
|
||||
protected:
|
||||
const CallbackFunctor *_callback;
|
||||
CryOmni3DEngine &_engine;
|
||||
Inventory &_inventory;
|
||||
const Sprites &_sprites;
|
||||
|
||||
struct Zone {
|
||||
Common::Rect rect;
|
||||
/* ZON file stores the index in the sprite */
|
||||
uint16 spriteId;
|
||||
uint16 cursorId;
|
||||
bool valid;
|
||||
};
|
||||
|
||||
void loadZones(const Common::Path &image);
|
||||
void handleMouseZones(const Common::Array<Zone>::const_iterator ¤tZone);
|
||||
|
||||
Image::ImageDecoder *_imageDecoder;
|
||||
const Graphics::Surface *_imageSurface;
|
||||
|
||||
Common::Array<Zone> _zones;
|
||||
Common::Array<Zone>::size_type _highLeftId;
|
||||
Common::Array<Zone>::size_type _highRightId;
|
||||
|
||||
const FixedImageConfiguration *_configuration;
|
||||
|
||||
bool _refreshCursor;
|
||||
};
|
||||
|
||||
} // End of namespace CryOmni3D
|
||||
|
||||
#endif
|
||||
464
engines/cryomni3d/font_manager.cpp
Normal file
464
engines/cryomni3d/font_manager.cpp
Normal file
@@ -0,0 +1,464 @@
|
||||
/* 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/debug.h"
|
||||
#include "common/file.h"
|
||||
#include "common/hash-ptr.h"
|
||||
#include "common/hash-str.h"
|
||||
#ifdef USE_FREETYPE2
|
||||
#include "graphics/fonts/ttf.h"
|
||||
#endif
|
||||
#include "graphics/managed_surface.h"
|
||||
|
||||
#include "cryomni3d/font_manager.h"
|
||||
#include "cryomni3d/fonts/cryoextfont.h"
|
||||
#include "cryomni3d/fonts/cryofont.h"
|
||||
|
||||
namespace CryOmni3D {
|
||||
|
||||
FontManager::FontManager() : _codepage(Common::kCodePageInvalid), _toUnicode(false),
|
||||
_currentFont(nullptr), _currentFontId(uint(-1)), _transparentBackground(false),
|
||||
_spaceWidth(0), _charSpacing(0), _foreColor(0), _currentSurface(nullptr),
|
||||
_lineHeight(30), _justifyText(false), _blockTextRemaining(nullptr),
|
||||
_useSpaceDelimiter(true), _keepASCIIjoined(true) {
|
||||
}
|
||||
|
||||
FontManager::~FontManager() {
|
||||
Common::HashMap<Graphics::Font *, bool> deletedFonts;
|
||||
for (Common::Array<Graphics::Font *>::iterator it = _fonts.begin(); it != _fonts.end(); it++) {
|
||||
if (deletedFonts.find(*it) != deletedFonts.end()) {
|
||||
// Already deleted
|
||||
continue;
|
||||
}
|
||||
|
||||
deletedFonts[*it] = true;
|
||||
delete *it;
|
||||
}
|
||||
}
|
||||
|
||||
void FontManager::loadFonts(const Common::Array<Common::Path> &fontFiles,
|
||||
Common::CodePage codepage) {
|
||||
assert(codepage != Common::kCodePageInvalid);
|
||||
_codepage = codepage;
|
||||
setupWrapParameters();
|
||||
|
||||
// Cryo fonts are never in Unicode
|
||||
_toUnicode = false;
|
||||
|
||||
_fonts.clear();
|
||||
_fonts.reserve(fontFiles.size());
|
||||
|
||||
Common::HashMap<Common::Path, Graphics::Font *,
|
||||
Common::Path::IgnoreCase_Hash, Common::Path::IgnoreCase_EqualTo> fontsCache;
|
||||
|
||||
for (Common::Array<Common::Path>::const_iterator it = fontFiles.begin(); it != fontFiles.end();
|
||||
it++) {
|
||||
Graphics::Font *fontEntry = nullptr;
|
||||
if (fontsCache.tryGetVal(*it, fontEntry)) {
|
||||
_fonts.push_back(fontEntry);
|
||||
continue;
|
||||
}
|
||||
|
||||
// New font
|
||||
|
||||
// For now only support CP950 in extended cryo font
|
||||
if (_codepage == Common::kWindows950) {
|
||||
CryoExtFont *font = new CryoExtFont();
|
||||
font->load(*it, _codepage);
|
||||
_fonts.push_back(font);
|
||||
fontsCache[*it] = font;
|
||||
} else {
|
||||
CryoFont *font = new CryoFont();
|
||||
font->load(*it);
|
||||
_fonts.push_back(font);
|
||||
fontsCache[*it] = font;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FontManager::loadTTFList(const Common::Path &ttfList, Common::CodePage codepage) {
|
||||
#ifdef USE_FREETYPE2
|
||||
assert(codepage != Common::kCodePageInvalid);
|
||||
_codepage = codepage;
|
||||
setupWrapParameters();
|
||||
|
||||
// Freetype2 is configured to use Unicode
|
||||
_toUnicode = true;
|
||||
|
||||
_fonts.clear();
|
||||
|
||||
Common::File list;
|
||||
|
||||
if (!list.open(ttfList)) {
|
||||
error("can't open file %s", ttfList.toString(Common::Path::kNativeSeparator).c_str());
|
||||
}
|
||||
|
||||
Common::Path ttfParentDir(ttfList.getParent());
|
||||
|
||||
Common::String line = list.readLine();
|
||||
uint32 num = atoi(line.c_str());
|
||||
|
||||
_fonts.reserve(num);
|
||||
|
||||
for (uint i = 0; i < num; i++) {
|
||||
line = list.readLine();
|
||||
if (line.size() == 0) {
|
||||
error("Invalid font list: missing line");
|
||||
}
|
||||
|
||||
uint32 sharpFile = line.find("#");
|
||||
if (sharpFile == Common::String::npos) {
|
||||
error("Invalid font list: missing #");
|
||||
}
|
||||
uint32 sharpFlags = line.find("#", sharpFile + 1);
|
||||
if (sharpFlags == Common::String::npos) {
|
||||
error("Invalid font list: missing #");
|
||||
}
|
||||
|
||||
Common::String fontFace(line.begin(), line.begin() + sharpFile);
|
||||
Common::U32String uniFontFace = fontFace.decode(codepage);
|
||||
Common::String fontFile(line.begin() + sharpFile + 1, line.begin() + sharpFlags);
|
||||
Common::String sizeFlags(line.begin() + sharpFlags + 1, line.end());
|
||||
|
||||
uint32 size = atoi(sizeFlags.c_str());
|
||||
bool bold = sizeFlags.contains('B');
|
||||
bool italic = sizeFlags.contains('I');
|
||||
|
||||
Common::Array<Common::Path> fontFiles;
|
||||
fontFiles.push_back(Common::Path(fontFile));
|
||||
fontFiles.push_back(ttfParentDir.appendComponent(fontFile));
|
||||
|
||||
// Use 96 dpi as it's the default under Windows
|
||||
Graphics::Font *font = Graphics::findTTFace(fontFiles, uniFontFace, bold, italic, -(int)size,
|
||||
96, 96, Graphics::kTTFRenderModeMonochrome);
|
||||
if (!font) {
|
||||
error("Can't find required face (line %u) in %s", i, fontFile.c_str());
|
||||
}
|
||||
_fonts.push_back(font);
|
||||
}
|
||||
#else
|
||||
error("TrueType support not compiled in");
|
||||
#endif
|
||||
}
|
||||
|
||||
Common::U32String FontManager::toU32(const Common::String &str) const {
|
||||
assert(_codepage != Common::kCodePageInvalid);
|
||||
|
||||
if (_toUnicode) {
|
||||
return str.decode(_codepage);
|
||||
}
|
||||
|
||||
// Beware: when not using Unicode, U32String will contain codepoints not corresponding to Unicode
|
||||
switch (_codepage) {
|
||||
case Common::kUtf8:
|
||||
error("UTF-8 not supported");
|
||||
case Common::kWindows932:
|
||||
case Common::kWindows949:
|
||||
case Common::kWindows950: {
|
||||
/* if high-order bit is 1, then character is 2 bytes else it's 1 byte
|
||||
* We don't check validity of the codepoint */
|
||||
Common::U32String ret;
|
||||
for (uint32 i = 0; i < str.size(); i++) {
|
||||
uint32 c = (byte)str[i];
|
||||
if ((c & 0x80) && (i + 1 < str.size())) {
|
||||
c <<= 8;
|
||||
i++;
|
||||
c |= str[i] & 0xff;
|
||||
}
|
||||
ret += c;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
default:
|
||||
// All other codepages are SBCS: one byte is one character
|
||||
// We use kISO8859_1 as it's the identity function [0-255] to [0-255]
|
||||
return str.decode(Common::kISO8859_1);
|
||||
}
|
||||
}
|
||||
|
||||
void FontManager::setCurrentFont(int currentFont) {
|
||||
if (currentFont == -1) {
|
||||
currentFont = 0;
|
||||
}
|
||||
_currentFontId = currentFont;
|
||||
_currentFont = _fonts[currentFont];
|
||||
|
||||
setSpaceWidth(0);
|
||||
}
|
||||
|
||||
void FontManager::setSpaceWidth(uint additionalSpace) {
|
||||
// For now space character is still the same in all encodings: 0x20
|
||||
if (_currentFont) {
|
||||
_spaceWidth = additionalSpace + _currentFont->getCharWidth(' ');
|
||||
} else {
|
||||
_spaceWidth = 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint FontManager::displayStr_(uint x, uint y,
|
||||
const Common::U32String &text) const {
|
||||
uint offset = 0;
|
||||
for (Common::U32String::const_iterator it = text.begin(); it != text.end(); it++) {
|
||||
_currentFont->drawChar(_currentSurface, *it, x + offset, y, _foreColor);
|
||||
offset += _currentFont->getCharWidth(*it) + _charSpacing;
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
uint FontManager::getStrWidth(const Common::U32String &text) const {
|
||||
uint width = 0;
|
||||
for (Common::U32String::const_iterator it = text.begin(); it != text.end(); it++) {
|
||||
uint32 c = *it;
|
||||
if (c == ' ') {
|
||||
width += _spaceWidth;
|
||||
} else {
|
||||
width += _currentFont->getCharWidth(*it) + _charSpacing;
|
||||
}
|
||||
}
|
||||
return width;
|
||||
}
|
||||
|
||||
bool FontManager::displayBlockText(const Common::U32String &text,
|
||||
Common::U32String::const_iterator begin) {
|
||||
bool notEnoughSpace = false;
|
||||
Common::U32String::const_iterator ptr = begin;
|
||||
Common::Array<Common::U32String> words;
|
||||
|
||||
if (begin != text.end()) {
|
||||
_blockTextRemaining = nullptr;
|
||||
while (ptr != text.end() && !notEnoughSpace) {
|
||||
uint finalPos;
|
||||
bool has_cr;
|
||||
calculateWordWrap(text, &ptr, &finalPos, &has_cr, words);
|
||||
uint spacesWidth = (words.size() - 1) * _spaceWidth;
|
||||
uint spaceConsumed = 0;
|
||||
double spaceWidthPerWord;
|
||||
if (words.size() == 1) {
|
||||
spaceWidthPerWord = _spaceWidth;
|
||||
} else {
|
||||
spaceWidthPerWord = (double)spacesWidth / (double)words.size();
|
||||
}
|
||||
Common::Array<Common::U32String>::const_iterator word;
|
||||
uint word_i;
|
||||
for (word = words.begin(), word_i = 0; word != words.end(); word++, word_i++) {
|
||||
_blockPos.x += displayStr_(_blockPos.x, _blockPos.y, *word);
|
||||
if (!_justifyText || has_cr) {
|
||||
_blockPos.x += _spaceWidth;
|
||||
} else {
|
||||
double sp = (word_i + 1) * spaceWidthPerWord - spaceConsumed;
|
||||
_blockPos.x += int16(sp);
|
||||
spaceConsumed += uint(sp);
|
||||
}
|
||||
}
|
||||
if (_blockPos.y + _lineHeight + getFontMaxHeight() >= _blockRect.bottom) {
|
||||
notEnoughSpace = true;
|
||||
_blockTextRemaining = ptr;
|
||||
} else {
|
||||
_blockPos.x = _blockRect.left;
|
||||
_blockPos.y += _lineHeight;
|
||||
}
|
||||
}
|
||||
}
|
||||
return notEnoughSpace;
|
||||
}
|
||||
|
||||
uint FontManager::getLinesCount(const Common::U32String &text, uint width) {
|
||||
if (text.size() == 0) {
|
||||
// One line even if it's empty
|
||||
return 1;
|
||||
}
|
||||
if (text.size() >= 1024) {
|
||||
// Too long text, be lazy
|
||||
return getStrWidth(text) / width + 3;
|
||||
}
|
||||
|
||||
uint lineCount = 0;
|
||||
Common::U32String::const_iterator textP = text.begin();
|
||||
uint len = text.size();
|
||||
|
||||
while (len > 0) {
|
||||
Common::U32String buffer;
|
||||
uint lineWidth = 0;
|
||||
lineCount++;
|
||||
while (lineWidth < width && len > 0 && *textP != '\r') {
|
||||
buffer += *(textP++);
|
||||
len--;
|
||||
lineWidth = getStrWidth(buffer);
|
||||
}
|
||||
|
||||
if (lineWidth >= width) {
|
||||
// We overrun the line, get backwards
|
||||
if (_useSpaceDelimiter) {
|
||||
uint bufferSize = buffer.size();
|
||||
while (buffer.size()) {
|
||||
if (buffer[buffer.size() - 1] == ' ') {
|
||||
break;
|
||||
}
|
||||
buffer.deleteLastChar();
|
||||
textP--;
|
||||
len++;
|
||||
}
|
||||
if (!buffer.size()) {
|
||||
// Word was too long: fail
|
||||
// Split in middle of something
|
||||
textP += bufferSize - 1;
|
||||
len -= bufferSize - 1;
|
||||
}
|
||||
if (*textP == ' ') {
|
||||
textP++;
|
||||
}
|
||||
} else {
|
||||
if (buffer.size()) {
|
||||
buffer.deleteLastChar();
|
||||
textP--;
|
||||
len++;
|
||||
} else {
|
||||
// fail
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
// Continue with next line
|
||||
continue;
|
||||
}
|
||||
|
||||
if (len == 0) {
|
||||
// Job is finished
|
||||
break;
|
||||
}
|
||||
if (*textP == '\r') {
|
||||
// Next line
|
||||
len--;
|
||||
textP++;
|
||||
}
|
||||
}
|
||||
return lineCount;
|
||||
}
|
||||
|
||||
void FontManager::calculateWordWrap(const Common::U32String &text,
|
||||
Common::U32String::const_iterator *position, uint *finalPos, bool *hasCr,
|
||||
Common::Array<Common::U32String> &words) const {
|
||||
*hasCr = false;
|
||||
uint offset = 0;
|
||||
bool wordWrap = false;
|
||||
uint lineWidth = _blockRect.right - _blockRect.left;
|
||||
Common::U32String::const_iterator ptr = *position;
|
||||
|
||||
words.clear();
|
||||
|
||||
if (ptr == text.end() || *ptr == '\r') {
|
||||
ptr++;
|
||||
*hasCr = true;
|
||||
*position = ptr;
|
||||
*finalPos = offset;
|
||||
return;
|
||||
}
|
||||
|
||||
while (!wordWrap) {
|
||||
Common::U32String::const_iterator begin = ptr;
|
||||
for (; ptr != text.end() && *ptr != '\r' && (!_useSpaceDelimiter || *ptr != ' '); ptr++) { }
|
||||
Common::U32String word(begin, ptr);
|
||||
uint width = getStrWidth(word);
|
||||
if (width + offset >= lineWidth) {
|
||||
wordWrap = true;
|
||||
// word is too long: just put pointer back at beginning
|
||||
ptr = begin;
|
||||
} else {
|
||||
words.push_back(word);
|
||||
offset += width + _spaceWidth;
|
||||
for (; ptr != text.end() && *ptr == ' '; ptr++) { }
|
||||
for (; ptr != text.end() && *ptr == '\r'; ptr++) {
|
||||
wordWrap = true;
|
||||
*hasCr = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (words.size() > 0) {
|
||||
offset -= _spaceWidth;
|
||||
} /**/ else {
|
||||
// couldn't get a word (too long): we are at start of line
|
||||
Common::U32String::const_iterator begin = ptr;
|
||||
// Start with one character
|
||||
for (ptr++; ptr != text.end(); ptr++) {
|
||||
Common::U32String word(begin, ptr);
|
||||
uint width = getStrWidth(word);
|
||||
if (width >= lineWidth) {
|
||||
break;
|
||||
}
|
||||
offset = width;
|
||||
}
|
||||
// We overran: go back
|
||||
if (ptr != begin) {
|
||||
ptr--;
|
||||
}
|
||||
if (_keepASCIIjoined) {
|
||||
Common::U32String::const_iterator end = ptr;
|
||||
// Until now ptr was pointing after the last character
|
||||
// As we want to look at it, go back
|
||||
if (ptr != begin) {
|
||||
ptr--;
|
||||
}
|
||||
for (; ptr != begin; ptr--) {
|
||||
// Try to split at space or non-ASCII character
|
||||
if (*ptr >= 0x80) {
|
||||
break;
|
||||
}
|
||||
if (Common::isSpace(*ptr)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ptr == begin) {
|
||||
// Too bad: we have to split in middle of something
|
||||
ptr = end;
|
||||
} else {
|
||||
// Go back just after last character
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
Common::U32String word(begin, ptr);
|
||||
words.push_back(word);
|
||||
} /**/
|
||||
*finalPos = offset;
|
||||
*position = ptr;
|
||||
}
|
||||
|
||||
void FontManager::setupWrapParameters() {
|
||||
switch (_codepage) {
|
||||
case Common::kWindows932:
|
||||
_useSpaceDelimiter = true;
|
||||
_keepASCIIjoined = false;
|
||||
break;
|
||||
case Common::kWindows949:
|
||||
_useSpaceDelimiter = true;
|
||||
_keepASCIIjoined = false;
|
||||
break;
|
||||
case Common::kWindows950:
|
||||
_useSpaceDelimiter = false;
|
||||
_keepASCIIjoined = true;
|
||||
break;
|
||||
default:
|
||||
_useSpaceDelimiter = true;
|
||||
_keepASCIIjoined = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace CryOmni3D
|
||||
120
engines/cryomni3d/font_manager.h
Normal file
120
engines/cryomni3d/font_manager.h
Normal file
@@ -0,0 +1,120 @@
|
||||
/* 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 CRYOMNI3D_FONT_MANAGER_H
|
||||
#define CRYOMNI3D_FONT_MANAGER_H
|
||||
|
||||
#include "common/array.h"
|
||||
#include "common/path.h"
|
||||
#include "common/str.h"
|
||||
#include "common/str-enc.h"
|
||||
#include "common/ustr.h"
|
||||
#include "common/rect.h"
|
||||
|
||||
#include "graphics/font.h"
|
||||
|
||||
namespace Graphics {
|
||||
class ManagedSurface;
|
||||
}
|
||||
|
||||
namespace CryOmni3D {
|
||||
|
||||
class FontManager {
|
||||
public:
|
||||
FontManager();
|
||||
virtual ~FontManager();
|
||||
|
||||
void loadFonts(const Common::Array<Common::Path> &fontFiles, Common::CodePage codepage);
|
||||
void loadTTFList(const Common::Path &listFile, Common::CodePage codepage);
|
||||
void setCurrentFont(int currentFont);
|
||||
uint getCurrentFont() { return _currentFontId; }
|
||||
void setTransparentBackground(bool transparent) { _transparentBackground = transparent; }
|
||||
void setSpaceWidth(uint additionalSpace);
|
||||
void setForeColor(byte color) { _foreColor = color; }
|
||||
void setLineHeight(int h) { _lineHeight = h; }
|
||||
int lineHeight() { return _lineHeight; }
|
||||
void setCharSpacing(uint w) { _charSpacing = w; }
|
||||
void setSurface(Graphics::ManagedSurface *surface) { _currentSurface = surface; }
|
||||
|
||||
int getFontMaxHeight() { return _currentFont->getFontHeight(); }
|
||||
|
||||
void displayInt(uint x, uint y, int value) const {
|
||||
displayStr_(x, y,
|
||||
toU32(Common::String::format("%d", value)));
|
||||
}
|
||||
void displayStr(uint x, uint y, const Common::String &text) const { displayStr_(x, y, toU32(text)); }
|
||||
void displayStr(uint x, uint y, const Common::U32String &text) const { displayStr_(x, y, text); }
|
||||
uint getStrWidth(const Common::String &text) const { return getStrWidth(toU32(text)); }
|
||||
uint getStrWidth(const Common::U32String &text) const;
|
||||
|
||||
uint getLinesCount(const Common::String &text, uint width) { return getLinesCount(toU32(text), width); }
|
||||
|
||||
void setupBlock(const Common::Rect &block, bool justifyText = false) {
|
||||
_blockRect = block;
|
||||
_blockPos.x = block.left;
|
||||
_blockPos.y = block.top;
|
||||
_justifyText = justifyText;
|
||||
}
|
||||
bool displayBlockText(const Common::String &text) {
|
||||
_blockTextStr = toU32(text);
|
||||
return displayBlockText(_blockTextStr, _blockTextStr.begin());
|
||||
}
|
||||
bool displayBlockTextContinue() { return displayBlockText(_blockTextStr, _blockTextRemaining); }
|
||||
Common::Point blockTextLastPos() { return _blockPos; }
|
||||
|
||||
private:
|
||||
Common::U32String toU32(const Common::String &text) const;
|
||||
|
||||
uint displayStr_(uint x, uint y, const Common::U32String &text) const;
|
||||
uint getLinesCount(const Common::U32String &text, uint width);
|
||||
bool displayBlockText(const Common::U32String &text, Common::U32String::const_iterator begin);
|
||||
void calculateWordWrap(const Common::U32String &text, Common::U32String::const_iterator *position,
|
||||
uint *finalPos, bool *has_br, Common::Array<Common::U32String> &words) const;
|
||||
|
||||
Common::CodePage _codepage;
|
||||
bool _toUnicode;
|
||||
Common::Array<Graphics::Font *> _fonts;
|
||||
const Graphics::Font *_currentFont;
|
||||
uint _currentFontId;
|
||||
bool _transparentBackground;
|
||||
uint _spaceWidth;
|
||||
uint _charSpacing;
|
||||
|
||||
byte _foreColor;
|
||||
|
||||
Graphics::ManagedSurface *_currentSurface;
|
||||
|
||||
Common::Rect _blockRect;
|
||||
Common::Point _blockPos;
|
||||
int _lineHeight;
|
||||
bool _justifyText;
|
||||
Common::U32String _blockTextStr;
|
||||
Common::U32String::const_iterator _blockTextRemaining;
|
||||
|
||||
// Specific parameters for non alphabetic languages
|
||||
void setupWrapParameters();
|
||||
bool _useSpaceDelimiter;
|
||||
bool _keepASCIIjoined;
|
||||
};
|
||||
|
||||
} // End of namespace CryOmni3D
|
||||
|
||||
#endif
|
||||
268
engines/cryomni3d/fonts/cryoextfont.cpp
Normal file
268
engines/cryomni3d/fonts/cryoextfont.cpp
Normal file
@@ -0,0 +1,268 @@
|
||||
/* 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/debug.h"
|
||||
#include "common/file.h"
|
||||
#include "graphics/managed_surface.h"
|
||||
|
||||
#include "cryomni3d/fonts/cryoextfont.h"
|
||||
|
||||
namespace CryOmni3D {
|
||||
|
||||
CryoExtFont::~CryoExtFont() {
|
||||
delete _crf;
|
||||
}
|
||||
|
||||
void CryoExtFont::load(const Common::Path &fontFile, Common::CodePage codepage) {
|
||||
// For now only CP950 is supported
|
||||
assert(codepage == Common::kWindows950);
|
||||
|
||||
_codepage = codepage;
|
||||
|
||||
Common::File *crf = new Common::File();
|
||||
|
||||
if (!crf->open(fontFile)) {
|
||||
error("can't open file %s", fontFile.toString(Common::Path::kNativeSeparator).c_str());
|
||||
}
|
||||
|
||||
_crf = crf;
|
||||
|
||||
byte magic[8];
|
||||
|
||||
_crf->read(magic, sizeof(magic));
|
||||
if (memcmp(magic, "CRYOFONT", 8)) {
|
||||
error("Invalid font magic");
|
||||
}
|
||||
|
||||
// 3 unknown uint16
|
||||
(void) _crf->readUint16BE();
|
||||
(void) _crf->readUint16BE();
|
||||
(void) _crf->readUint16BE();
|
||||
|
||||
_height = _crf->readSint16BE();
|
||||
//debug("Max char height %d", _maxHeight);
|
||||
|
||||
_crf->read(_comment, sizeof(_comment));
|
||||
//debug("Comment %s", _comment);
|
||||
|
||||
Common::String offsetsFile = fontFile.baseName();
|
||||
offsetsFile.setChar('I', offsetsFile.size() - 1);
|
||||
loadOffsets(fontFile.getParent().appendComponent(offsetsFile));
|
||||
}
|
||||
|
||||
void CryoExtFont::loadOffsets(const Common::Path &offsetsFile) {
|
||||
Common::File cri;
|
||||
|
||||
if (!cri.open(offsetsFile)) {
|
||||
error("can't open file %s", offsetsFile.toString(Common::Path::kNativeSeparator).c_str());
|
||||
}
|
||||
|
||||
uint32 counts = cri.size() / sizeof(uint32);
|
||||
_offsets.reserve(counts);
|
||||
debug("Loading %u offsets", counts);
|
||||
|
||||
for (; counts > 0; counts--) {
|
||||
uint32 offset = cri.readUint32BE();
|
||||
_offsets.push_back(offset);
|
||||
}
|
||||
}
|
||||
|
||||
void CryoExtFont::assureCached(uint32 chr) const {
|
||||
if (_cache.contains(chr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 glyphId = mapGlyph(chr);
|
||||
|
||||
if (glyphId >= _offsets.size()) {
|
||||
warning("Invalid glyph id: %u", glyphId);
|
||||
glyphId = 0;
|
||||
}
|
||||
|
||||
uint32 offset = _offsets[glyphId];
|
||||
_crf->seek(offset);
|
||||
|
||||
Glyph &glyph = _cache[chr];
|
||||
uint16 h = _crf->readUint16BE();
|
||||
uint16 w = _crf->readUint16BE();
|
||||
uint sz = glyph.setup(w, h);
|
||||
//debug("Char %u/%u sz %ux%u %u", chr, glyphId, w, h, sz);
|
||||
glyph.offX = _crf->readSint16BE();
|
||||
glyph.offY = _crf->readSint16BE();
|
||||
glyph.advance = _crf->readUint16BE();
|
||||
//debug("Char %u/%u offX %d offY %d PW %d", chr, glyphId, glyph.offX, glyph.offY, glyph.advance);
|
||||
|
||||
_crf->read(glyph.bitmap, sz);
|
||||
//debug("Char %u/%u read %d", chr, glyphId, v);
|
||||
|
||||
if ((_cache.size() % 10) == 0) {
|
||||
debug("Glyph cache size is now %u", _cache.size());
|
||||
}
|
||||
}
|
||||
|
||||
Common::Rect CryoExtFont::getBoundingBox(uint32 chr) const {
|
||||
assureCached(chr);
|
||||
|
||||
const Glyph &glyph = _cache[chr];
|
||||
return Common::Rect(glyph.offX, glyph.offY,
|
||||
glyph.offX + glyph.w, glyph.offY + glyph.h);
|
||||
}
|
||||
|
||||
int CryoExtFont::getCharWidth(uint32 chr) const {
|
||||
assureCached(chr);
|
||||
|
||||
const Glyph &glyph = _cache[chr];
|
||||
return glyph.advance;
|
||||
}
|
||||
|
||||
void CryoExtFont::drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32 color) const {
|
||||
assert(dst);
|
||||
assert(dst->format.bytesPerPixel == 1 || dst->format.bytesPerPixel == 2 ||
|
||||
dst->format.bytesPerPixel == 4);
|
||||
|
||||
assureCached(chr);
|
||||
|
||||
const Glyph &glyph = _cache[chr];
|
||||
|
||||
x += glyph.offX;
|
||||
// In european versions of Versailles there was a -2 offset which is not present in Chinese one
|
||||
// Maybe this offset should be checked when adding new games
|
||||
y += glyph.offY + _height;
|
||||
|
||||
if (x > dst->w) {
|
||||
return;
|
||||
}
|
||||
if (y > dst->h) {
|
||||
return;
|
||||
}
|
||||
|
||||
int w = glyph.w;
|
||||
int h = glyph.h;
|
||||
|
||||
const uint8 *srcPos = (const uint8 *)glyph.bitmap;
|
||||
|
||||
const uint16 stride = (glyph.w + 7) / 8;
|
||||
const uint16 originalWidth = glyph.w;
|
||||
|
||||
// Make sure we are not drawing outside the screen bounds
|
||||
if (y < 0) {
|
||||
// y is negative so srcPos will increase and h will decrease
|
||||
srcPos -= y * stride;
|
||||
h += y;
|
||||
y = 0;
|
||||
}
|
||||
|
||||
if (y + h > dst->h) {
|
||||
h = dst->h - y;
|
||||
}
|
||||
|
||||
if (h <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
int jStart = 0;
|
||||
if (x < 0) {
|
||||
// x is negative so jStart will be positive and w will decrease
|
||||
jStart = -x;
|
||||
w += x;
|
||||
x = 0;
|
||||
}
|
||||
|
||||
if (x + w > dst->w) {
|
||||
w = dst->w - x;
|
||||
}
|
||||
|
||||
if (w <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const int jEnd = jStart + w - 1;
|
||||
|
||||
for (uint16 i = 0; i < h; i++) {
|
||||
byte b = 0;
|
||||
for (uint16 j = 0; j < originalWidth; j++) {
|
||||
if ((j % 8) == 0) {
|
||||
b = *(srcPos++);
|
||||
}
|
||||
|
||||
if (j >= jStart && j <= jEnd && b & 0x80) {
|
||||
if (dst->format.bytesPerPixel == 1) {
|
||||
*((byte *)dst->getBasePtr(x + j, y + i)) = color;
|
||||
} else if (dst->format.bytesPerPixel == 2) {
|
||||
*((uint16 *)dst->getBasePtr(x + j, y + i)) = color;
|
||||
} else if (dst->format.bytesPerPixel == 4) {
|
||||
*((uint32 *)dst->getBasePtr(x + j, y + i)) = color;
|
||||
}
|
||||
}
|
||||
|
||||
b <<= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32 CryoExtFont::mapGlyph(uint32 chr) const {
|
||||
switch (_codepage) {
|
||||
case Common::kWindows950:
|
||||
/* Nothing more than 0xffff */
|
||||
if (chr >> 16) {
|
||||
return 0;
|
||||
}
|
||||
/* No glyph for non printable */
|
||||
if (chr < 0x20) {
|
||||
return 0;
|
||||
}
|
||||
/* ASCII characters : like in 8bits case, 0x60 ones */
|
||||
if (chr < 0x80) {
|
||||
return chr - 0x20;
|
||||
}
|
||||
/* Invalid ranges */
|
||||
if (chr < 0x8000) {
|
||||
return 0;
|
||||
}
|
||||
if ((chr & 0xff) < 0x40) {
|
||||
return 0;
|
||||
}
|
||||
/* After the 0x60 ASCII characters
|
||||
* a table of 0xC0 large (starting at 0x40) and
|
||||
* 0x80 long (starting at 0x80) */
|
||||
chr = 0xC0 * ((chr >> 8) - 0x80) + ((chr & 0xff) - 0x40) + 0x60;
|
||||
return chr;
|
||||
default:
|
||||
error("Invalid encoding");
|
||||
}
|
||||
}
|
||||
|
||||
CryoExtFont::Glyph::Glyph() : h(0), w(0), offX(0), offY(0), advance(0), bitmap(nullptr) {
|
||||
}
|
||||
|
||||
CryoExtFont::Glyph::~Glyph() {
|
||||
delete[] bitmap;
|
||||
}
|
||||
|
||||
uint CryoExtFont::Glyph::setup(uint16 width, uint16 height) {
|
||||
w = width;
|
||||
h = height;
|
||||
uint sz = h * ((w + 7) / 8);
|
||||
bitmap = new byte[sz];
|
||||
return sz;
|
||||
}
|
||||
|
||||
} // End of namespace CryOmni3D
|
||||
87
engines/cryomni3d/fonts/cryoextfont.h
Normal file
87
engines/cryomni3d/fonts/cryoextfont.h
Normal file
@@ -0,0 +1,87 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CRYOMNI3D_FONTS_CRYOEXTFONT_H
|
||||
#define CRYOMNI3D_FONTS_CRYOEXTFONT_H
|
||||
|
||||
#include "common/array.h"
|
||||
#include "common/hashmap.h"
|
||||
#include "common/str.h"
|
||||
#include "graphics/font.h"
|
||||
|
||||
namespace Common {
|
||||
class SeekableReadStream;
|
||||
}
|
||||
|
||||
namespace CryOmni3D {
|
||||
|
||||
class CryoExtFont : public Graphics::Font {
|
||||
public:
|
||||
CryoExtFont() : _height(0), _maxAdvance(0), _crf(nullptr), _codepage(Common::kCodePageInvalid) { }
|
||||
virtual ~CryoExtFont();
|
||||
|
||||
void load(const Common::Path &fontFile, Common::CodePage encoding);
|
||||
|
||||
virtual int getFontHeight() const { return _height; }
|
||||
virtual int getMaxCharWidth() const { return _maxAdvance; }
|
||||
|
||||
virtual int getCharWidth(uint32 chr) const;
|
||||
|
||||
virtual Common::Rect getBoundingBox(uint32 chr) const;
|
||||
|
||||
virtual void drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32 color) const;
|
||||
|
||||
private:
|
||||
void loadOffsets(const Common::Path &offsetsFile);
|
||||
void assureCached(uint32 chr) const;
|
||||
uint32 mapGlyph(uint32 chr) const;
|
||||
|
||||
struct Glyph {
|
||||
uint16 h;
|
||||
uint16 w;
|
||||
int16 offX;
|
||||
int16 offY;
|
||||
uint16 advance;
|
||||
|
||||
byte *bitmap;
|
||||
|
||||
Glyph();
|
||||
~Glyph();
|
||||
|
||||
uint setup(uint16 width, uint16 height);
|
||||
};
|
||||
|
||||
uint16 _height;
|
||||
uint16 _maxAdvance;
|
||||
byte _comment[32];
|
||||
|
||||
Common::CodePage _codepage;
|
||||
|
||||
mutable Common::SeekableReadStream *_crf;
|
||||
Common::Array<uint32> _offsets;
|
||||
|
||||
typedef Common::HashMap<uint32, Glyph> GlyphCache;
|
||||
mutable GlyphCache _cache;
|
||||
};
|
||||
|
||||
} // End of namespace CryOmni3D
|
||||
|
||||
#endif
|
||||
185
engines/cryomni3d/fonts/cryofont.cpp
Normal file
185
engines/cryomni3d/fonts/cryofont.cpp
Normal file
@@ -0,0 +1,185 @@
|
||||
/* 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/debug.h"
|
||||
#include "common/file.h"
|
||||
#include "graphics/managed_surface.h"
|
||||
|
||||
#include "cryomni3d/fonts/cryofont.h"
|
||||
|
||||
namespace CryOmni3D {
|
||||
|
||||
void CryoFont::load(const Common::Path &fontFile) {
|
||||
Common::File crf;
|
||||
|
||||
if (!crf.open(fontFile)) {
|
||||
error("can't open file %s", fontFile.toString(Common::Path::kNativeSeparator).c_str());
|
||||
}
|
||||
|
||||
byte magic[8];
|
||||
|
||||
crf.read(magic, sizeof(magic));
|
||||
if (memcmp(magic, "CRYOFONT", 8)) {
|
||||
error("Invalid font magic");
|
||||
}
|
||||
|
||||
// 3 unknown uint16
|
||||
(void) crf.readUint16BE();
|
||||
(void) crf.readUint16BE();
|
||||
(void) crf.readUint16BE();
|
||||
|
||||
_height = crf.readSint16BE();
|
||||
//debug("Max char height %d", _maxHeight);
|
||||
|
||||
crf.read(_comment, sizeof(_comment));
|
||||
//debug("Comment %s", _comment);
|
||||
|
||||
loadAll8bitGlyphs(crf);
|
||||
}
|
||||
|
||||
void CryoFont::loadAll8bitGlyphs(Common::SeekableReadStream &font_fl) {
|
||||
for (uint i = 0; i < k8bitCharactersCount; i++) {
|
||||
// Cache maps a character to a glyph
|
||||
Glyph &glyph = _glyphs[i];
|
||||
uint16 h = font_fl.readUint16BE();
|
||||
uint16 w = font_fl.readUint16BE();
|
||||
uint sz = glyph.setup(w, h);
|
||||
//debug("Char %d sz %dx%d %d", i, w, h, sz);
|
||||
glyph.offX = font_fl.readSint16BE();
|
||||
glyph.offY = font_fl.readSint16BE();
|
||||
glyph.advance = font_fl.readUint16BE();
|
||||
//debug("Char %d offX %d offY %d PW %d", i, glyph.offX, glyph.offY, glyph.advance);
|
||||
|
||||
font_fl.read(glyph.bitmap, sz);
|
||||
//debug("Char %d read %d", i, v);
|
||||
|
||||
if (glyph.advance > _maxAdvance) {
|
||||
_maxAdvance = glyph.advance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Common::Rect CryoFont::getBoundingBox(uint32 chr) const {
|
||||
const Glyph &glyph = _glyphs[mapGlyph(chr)];
|
||||
return Common::Rect(glyph.offX, glyph.offY,
|
||||
glyph.offX + glyph.w, glyph.offY + glyph.h);
|
||||
}
|
||||
|
||||
int CryoFont::getCharWidth(uint32 chr) const {
|
||||
const Glyph &glyph = _glyphs[mapGlyph(chr)];
|
||||
return glyph.advance;
|
||||
}
|
||||
|
||||
void CryoFont::drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32 color) const {
|
||||
assert(dst);
|
||||
assert(dst->format.bytesPerPixel == 1 || dst->format.bytesPerPixel == 2 ||
|
||||
dst->format.bytesPerPixel == 4);
|
||||
|
||||
const Glyph &glyph = _glyphs[mapGlyph(chr)];
|
||||
|
||||
x += glyph.offX;
|
||||
y += glyph.offY + _height - 2;
|
||||
|
||||
if (x > dst->w) {
|
||||
return;
|
||||
}
|
||||
if (y > dst->h) {
|
||||
return;
|
||||
}
|
||||
|
||||
int w = glyph.w;
|
||||
int h = glyph.h;
|
||||
|
||||
const uint8 *srcPos = (const uint8 *)glyph.bitmap;
|
||||
|
||||
// Make sure we are not drawing outside the screen bounds
|
||||
if (x < 0) {
|
||||
// x is negative so srcPos will increase and w will decrease
|
||||
srcPos -= x;
|
||||
w += x;
|
||||
x = 0;
|
||||
}
|
||||
|
||||
if (x + w > dst->w) {
|
||||
w = dst->w - x;
|
||||
}
|
||||
|
||||
if (w <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (y < 0) {
|
||||
// y is negative so srcPos will increase and h will decrease
|
||||
srcPos -= y * glyph.w;
|
||||
h += y;
|
||||
y = 0;
|
||||
}
|
||||
|
||||
if (y + h > dst->h) {
|
||||
h = dst->h - y;
|
||||
}
|
||||
|
||||
if (h <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint16 i = 0; i < h; i++) {
|
||||
for (uint16 j = 0; j < w; j++) {
|
||||
if (srcPos[j]) {
|
||||
if (dst->format.bytesPerPixel == 1) {
|
||||
*((byte *)dst->getBasePtr(x + j, y + i)) = color;
|
||||
} else if (dst->format.bytesPerPixel == 2) {
|
||||
*((uint16 *)dst->getBasePtr(x + j, y + i)) = color;
|
||||
} else if (dst->format.bytesPerPixel == 4) {
|
||||
*((uint32 *)dst->getBasePtr(x + j, y + i)) = color;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Next line
|
||||
srcPos += glyph.w;
|
||||
}
|
||||
}
|
||||
|
||||
uint32 CryoFont::mapGlyph(uint32 chr) const {
|
||||
/* Placeholder for non printable and out of limit characters */
|
||||
if (chr < 0x20 || chr >= 0xff) {
|
||||
chr = '?';
|
||||
}
|
||||
chr -= 0x20;
|
||||
return chr;
|
||||
}
|
||||
|
||||
CryoFont::Glyph::Glyph() : h(0), w(0), offX(0), offY(0), advance(0), bitmap(nullptr) {
|
||||
}
|
||||
|
||||
CryoFont::Glyph::~Glyph() {
|
||||
delete[] bitmap;
|
||||
}
|
||||
|
||||
uint CryoFont::Glyph::setup(uint16 width, uint16 height) {
|
||||
w = width;
|
||||
h = height;
|
||||
uint sz = w * h;
|
||||
bitmap = new byte[sz];
|
||||
return sz;
|
||||
}
|
||||
|
||||
} // End of namespace CryOmni3D
|
||||
81
engines/cryomni3d/fonts/cryofont.h
Normal file
81
engines/cryomni3d/fonts/cryofont.h
Normal file
@@ -0,0 +1,81 @@
|
||||
/* 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 CRYOMNI3D_FONTS_CRYOFONT_H
|
||||
#define CRYOMNI3D_FONTS_CRYOFONT_H
|
||||
|
||||
#include "common/array.h"
|
||||
#include "common/hashmap.h"
|
||||
#include "common/str.h"
|
||||
#include "graphics/font.h"
|
||||
|
||||
namespace Common {
|
||||
class SeekableReadStream;
|
||||
}
|
||||
|
||||
namespace CryOmni3D {
|
||||
|
||||
class CryoFont : public Graphics::Font {
|
||||
public:
|
||||
CryoFont() : _height(0), _maxAdvance(0) { }
|
||||
|
||||
void load(const Common::Path &fontFile);
|
||||
|
||||
virtual int getFontHeight() const { return _height; }
|
||||
virtual int getMaxCharWidth() const { return _maxAdvance; }
|
||||
|
||||
virtual int getCharWidth(uint32 chr) const;
|
||||
|
||||
virtual Common::Rect getBoundingBox(uint32 chr) const;
|
||||
|
||||
virtual void drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32 color) const;
|
||||
|
||||
private:
|
||||
void loadAll8bitGlyphs(Common::SeekableReadStream &font_fl);
|
||||
uint32 mapGlyph(uint32 chr) const;
|
||||
|
||||
struct Glyph {
|
||||
uint16 h;
|
||||
uint16 w;
|
||||
int16 offX;
|
||||
int16 offY;
|
||||
uint16 advance;
|
||||
|
||||
byte *bitmap;
|
||||
|
||||
Glyph();
|
||||
~Glyph();
|
||||
|
||||
uint setup(uint16 width, uint16 height);
|
||||
};
|
||||
|
||||
static const uint k8bitCharactersCount = 223;
|
||||
|
||||
uint16 _height;
|
||||
uint16 _maxAdvance;
|
||||
byte _comment[32];
|
||||
|
||||
Glyph _glyphs[k8bitCharactersCount];
|
||||
};
|
||||
|
||||
} // End of namespace CryOmni3D
|
||||
|
||||
#endif
|
||||
70
engines/cryomni3d/image/hlz.cpp
Normal file
70
engines/cryomni3d/image/hlz.cpp
Normal file
@@ -0,0 +1,70 @@
|
||||
/* 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 "cryomni3d/image/hlz.h"
|
||||
|
||||
#include "common/stream.h"
|
||||
#include "common/substream.h"
|
||||
#include "common/textconsole.h"
|
||||
#include "graphics/pixelformat.h"
|
||||
#include "graphics/surface.h"
|
||||
#include "image/codecs/codec.h"
|
||||
|
||||
#include "image/codecs/hlz.h"
|
||||
|
||||
namespace Image {
|
||||
|
||||
HLZFileDecoder::HLZFileDecoder() : _codec(nullptr), _surface(nullptr), _palette(256) {
|
||||
}
|
||||
|
||||
HLZFileDecoder::~HLZFileDecoder() {
|
||||
destroy();
|
||||
}
|
||||
|
||||
void HLZFileDecoder::destroy() {
|
||||
delete _codec;
|
||||
_codec = nullptr;
|
||||
_surface = nullptr;
|
||||
}
|
||||
|
||||
bool HLZFileDecoder::loadStream(Common::SeekableReadStream &stream) {
|
||||
destroy();
|
||||
|
||||
for (uint16 i = 0; i < 256; i++) {
|
||||
byte r = stream.readByte();
|
||||
byte g = stream.readByte();
|
||||
byte b = stream.readByte();
|
||||
_palette.set(i, r, g, b);
|
||||
}
|
||||
|
||||
uint16 width = stream.readUint16LE();
|
||||
uint16 height = stream.readUint16LE();
|
||||
|
||||
if (width == 0 || height == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_codec = new HLZDecoder(width, height);
|
||||
_surface = _codec->decodeFrame(stream);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // End of namespace Image
|
||||
60
engines/cryomni3d/image/hlz.h
Normal file
60
engines/cryomni3d/image/hlz.h
Normal file
@@ -0,0 +1,60 @@
|
||||
/* 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 CRYOMNI3D_IMAGE_HLZ_H
|
||||
#define CRYOMNI3D_IMAGE_HLZ_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "common/str.h"
|
||||
#include "graphics/palette.h"
|
||||
#include "image/image_decoder.h"
|
||||
|
||||
namespace Common {
|
||||
class SeekableReadStream;
|
||||
}
|
||||
|
||||
namespace Graphics {
|
||||
struct Surface;
|
||||
}
|
||||
|
||||
namespace Image {
|
||||
class HLZDecoder;
|
||||
|
||||
class HLZFileDecoder : public ImageDecoder {
|
||||
public:
|
||||
HLZFileDecoder();
|
||||
~HLZFileDecoder() override;
|
||||
|
||||
// ImageDecoder API
|
||||
void destroy() override;
|
||||
bool loadStream(Common::SeekableReadStream &stream) override;
|
||||
const Graphics::Surface *getSurface() const override { return _surface; }
|
||||
const Graphics::Palette &getPalette() const override { return _palette; }
|
||||
|
||||
private:
|
||||
HLZDecoder *_codec;
|
||||
const Graphics::Surface *_surface;
|
||||
Graphics::Palette _palette;
|
||||
};
|
||||
|
||||
} // End of namespace Image
|
||||
|
||||
#endif
|
||||
116
engines/cryomni3d/image/hnm.cpp
Normal file
116
engines/cryomni3d/image/hnm.cpp
Normal file
@@ -0,0 +1,116 @@
|
||||
/* 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 "cryomni3d/image/hnm.h"
|
||||
|
||||
#include "common/stream.h"
|
||||
#include "common/substream.h"
|
||||
#include "common/textconsole.h"
|
||||
#include "graphics/pixelformat.h"
|
||||
#include "graphics/surface.h"
|
||||
#include "image/codecs/codec.h"
|
||||
|
||||
#include "image/codecs/hnm.h"
|
||||
|
||||
namespace Image {
|
||||
|
||||
HNMFileDecoder::HNMFileDecoder(const Graphics::PixelFormat &format) :
|
||||
_format(format), _surface(nullptr), _codec(nullptr) {
|
||||
}
|
||||
|
||||
HNMFileDecoder::~HNMFileDecoder() {
|
||||
destroy();
|
||||
}
|
||||
|
||||
void HNMFileDecoder::destroy() {
|
||||
delete _codec;
|
||||
_codec = nullptr;
|
||||
_surface = nullptr;
|
||||
}
|
||||
|
||||
bool HNMFileDecoder::loadStream(Common::SeekableReadStream &stream) {
|
||||
destroy();
|
||||
|
||||
uint32 tag = stream.readUint32BE();
|
||||
|
||||
/* Only HNM6 for HNM images */
|
||||
if (tag != MKTAG('H', 'N', 'M', '6')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//uint16 ukn = stream.readUint16BE();
|
||||
//byte audioflags = stream.readByte();
|
||||
//byte bpp = stream.readByte();
|
||||
stream.skip(4);
|
||||
uint16 width = stream.readUint16LE();
|
||||
uint16 height = stream.readUint16LE();
|
||||
//uint32 filesize = stream.readUint32LE();
|
||||
//uint32 numframes = stream.readUint32LE();
|
||||
//uint32 ukn2 = stream.readUint32LE();
|
||||
//uint16 speed = stream.readUint16LE();
|
||||
//uint16 maxbuffer = stream.readUint16LE();
|
||||
//uint32 buffer_size = stream.readUint32LE();
|
||||
//byte unknownStr[16];
|
||||
//byte copyright[16];
|
||||
//stream.read(unknownStr, sizeof(unknownStr));
|
||||
//stream.read(copyright, sizeof(copyright));
|
||||
|
||||
stream.skip(52);
|
||||
|
||||
if (width == 0 || height == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read frame header
|
||||
uint32 frameSize = stream.readUint32LE();
|
||||
if (frameSize < 12) {
|
||||
return false;
|
||||
}
|
||||
frameSize -= 4;
|
||||
|
||||
// Read chunk header
|
||||
uint32 chunkSize = stream.readUint32LE();
|
||||
uint16 chunkTag = stream.readUint16BE();
|
||||
//uint16 chunkUkn = stream.readUint16LE();
|
||||
stream.skip(2);
|
||||
|
||||
if (frameSize < chunkSize ||
|
||||
chunkSize < 8 + 24) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool warp;
|
||||
if (chunkTag == MKTAG16('I', 'W')) {
|
||||
warp = true;
|
||||
} else if (chunkTag == MKTAG16('I', 'X')) {
|
||||
warp = false;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
// buffer_size is not reliable on IW and we already have the real size of the image source
|
||||
_codec = createHNM6Decoder(width, height, _format, chunkSize, false);
|
||||
_codec->setWarpMode(warp);
|
||||
_surface = _codec->decodeFrame(stream);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // End of namespace Image
|
||||
59
engines/cryomni3d/image/hnm.h
Normal file
59
engines/cryomni3d/image/hnm.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 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 CRYOMNI3D_IMAGE_HNM_H
|
||||
#define CRYOMNI3D_IMAGE_HNM_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "common/str.h"
|
||||
#include "graphics/pixelformat.h"
|
||||
#include "image/image_decoder.h"
|
||||
|
||||
namespace Common {
|
||||
class SeekableReadStream;
|
||||
}
|
||||
|
||||
namespace Graphics {
|
||||
struct Surface;
|
||||
}
|
||||
|
||||
namespace Image {
|
||||
class HNM6Decoder;
|
||||
|
||||
class HNMFileDecoder : public ImageDecoder {
|
||||
public:
|
||||
HNMFileDecoder(const Graphics::PixelFormat &format);
|
||||
~HNMFileDecoder() override;
|
||||
|
||||
// ImageDecoder API
|
||||
void destroy() override;
|
||||
bool loadStream(Common::SeekableReadStream &stream) override;
|
||||
const Graphics::Surface *getSurface() const override { return _surface; }
|
||||
|
||||
private:
|
||||
Graphics::PixelFormat _format;
|
||||
HNM6Decoder *_codec;
|
||||
const Graphics::Surface *_surface;
|
||||
};
|
||||
|
||||
} // End of namespace Image
|
||||
|
||||
#endif
|
||||
159
engines/cryomni3d/metaengine.cpp
Normal file
159
engines/cryomni3d/metaengine.cpp
Normal file
@@ -0,0 +1,159 @@
|
||||
/* 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 "engines/advancedDetector.h"
|
||||
#include "common/file.h"
|
||||
#include "common/md5.h"
|
||||
#include "common/savefile.h"
|
||||
#include "common/system.h"
|
||||
#include "common/textconsole.h"
|
||||
#include "common/translation.h"
|
||||
|
||||
#include "cryomni3d/cryomni3d.h"
|
||||
|
||||
#ifdef ENABLE_VERSAILLES
|
||||
#include "cryomni3d/versailles/engine.h"
|
||||
#endif
|
||||
|
||||
#include "cryomni3d/detection.h"
|
||||
|
||||
namespace CryOmni3D {
|
||||
|
||||
const char *CryOmni3DEngine::getGameId() const {
|
||||
return _gameDescription->desc.gameId;
|
||||
}
|
||||
|
||||
uint32 CryOmni3DEngine::getFeatures() const {
|
||||
return _gameDescription->features;
|
||||
}
|
||||
|
||||
Common::Platform CryOmni3DEngine::getPlatform() const {
|
||||
return _gameDescription->desc.platform;
|
||||
}
|
||||
|
||||
uint8 CryOmni3DEngine::getGameType() const {
|
||||
return _gameDescription->gameType;
|
||||
}
|
||||
|
||||
Common::Language CryOmni3DEngine::getLanguage() const {
|
||||
return _gameDescription->desc.language;
|
||||
}
|
||||
|
||||
bool CryOmni3DEngine::hasFeature(EngineFeature f) const {
|
||||
return
|
||||
(f == kSupportsReturnToLauncher)
|
||||
|| (f == kSupportsSubtitleOptions);
|
||||
}
|
||||
|
||||
|
||||
class CryOmni3DMetaEngine : public AdvancedMetaEngine<CryOmni3DGameDescription> {
|
||||
public:
|
||||
const char *getName() const override {
|
||||
return "cryomni3d";
|
||||
}
|
||||
|
||||
bool hasFeature(MetaEngineFeature f) const override;
|
||||
Common::Error createInstance(OSystem *syst, Engine **engine, const CryOmni3DGameDescription *desc) const override;
|
||||
|
||||
SaveStateList listSaves(const char *target) const override;
|
||||
int getMaximumSaveSlot() const override { return 999; }
|
||||
bool removeSaveState(const char *target, int slot) const override;
|
||||
Common::String getSavegameFile(int saveGameIdx, const char *target) const override {
|
||||
if (!target)
|
||||
target = getName();
|
||||
if (saveGameIdx == kSavegameFilePattern)
|
||||
return Common::String::format("%s.####", target);
|
||||
else
|
||||
return Common::String::format("%s.%04d", target, saveGameIdx + 1);
|
||||
}
|
||||
};
|
||||
|
||||
bool CryOmni3DMetaEngine::hasFeature(MetaEngineFeature f) const {
|
||||
return
|
||||
(f == kSupportsListSaves)
|
||||
|| (f == kSupportsLoadingDuringStartup)
|
||||
|| (f == kSupportsDeleteSave);
|
||||
}
|
||||
|
||||
SaveStateList CryOmni3DMetaEngine::listSaves(const char *target) const {
|
||||
// Replicate constant here to shorten lines
|
||||
static const uint kSaveDescriptionLen = CryOmni3DEngine::kSaveDescriptionLen;
|
||||
SaveStateList saveList;
|
||||
|
||||
Common::SaveFileManager *saveMan = g_system->getSavefileManager();
|
||||
|
||||
char saveName[kSaveDescriptionLen + 1];
|
||||
saveName[kSaveDescriptionLen] = '\0';
|
||||
Common::StringArray filenames = saveMan->listSavefiles(getSavegameFilePattern(target));
|
||||
sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..)
|
||||
|
||||
int slotNum;
|
||||
|
||||
for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end();
|
||||
++file) {
|
||||
// Obtain the last 4 digits of the filename, since they correspond to the save slot
|
||||
slotNum = atoi(file->c_str() + file->size() - 4);
|
||||
|
||||
if (slotNum >= 1 && slotNum <= 99) {
|
||||
Common::InSaveFile *in = saveMan->openForLoading(*file);
|
||||
if (in) {
|
||||
if (in->read(saveName, kSaveDescriptionLen) == kSaveDescriptionLen) {
|
||||
saveList.push_back(SaveStateDescriptor(this, slotNum - 1, saveName));
|
||||
}
|
||||
delete in;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return saveList;
|
||||
}
|
||||
|
||||
bool CryOmni3DMetaEngine::removeSaveState(const char *target, int slot) const {
|
||||
return g_system->getSavefileManager()->removeSavefile(getSavegameFile(slot, target));
|
||||
}
|
||||
|
||||
Common::Error CryOmni3DMetaEngine::createInstance(OSystem *syst, Engine **engine,
|
||||
const CryOmni3DGameDescription *gd) const {
|
||||
switch (gd->gameType) {
|
||||
case GType_VERSAILLES:
|
||||
#ifdef ENABLE_VERSAILLES
|
||||
*engine = new Versailles::CryOmni3DEngine_Versailles(syst, gd);
|
||||
return Common::kNoError;
|
||||
#else
|
||||
return Common::Error(Common::kUnsupportedGameidError, _s("Versailles 1685 support is not compiled in"));
|
||||
#endif
|
||||
case GType_HNM_PLAYER:
|
||||
*engine = new CryOmni3DEngine_HNMPlayer(syst, gd);
|
||||
return Common::kNoError;
|
||||
default:
|
||||
return Common::kUnsupportedGameidError;
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace CryOmni3D
|
||||
|
||||
#if PLUGIN_ENABLED_DYNAMIC(CRYOMNI3D)
|
||||
REGISTER_PLUGIN_DYNAMIC(CRYOMNI3D, PLUGIN_TYPE_ENGINE, CryOmni3D::CryOmni3DMetaEngine);
|
||||
#else
|
||||
REGISTER_PLUGIN_STATIC(CRYOMNI3D, PLUGIN_TYPE_ENGINE, CryOmni3D::CryOmni3DMetaEngine);
|
||||
#endif
|
||||
43
engines/cryomni3d/module.mk
Normal file
43
engines/cryomni3d/module.mk
Normal file
@@ -0,0 +1,43 @@
|
||||
MODULE := engines/cryomni3d
|
||||
|
||||
MODULE_OBJS = \
|
||||
fonts/cryoextfont.o \
|
||||
fonts/cryofont.o \
|
||||
image/hlz.o \
|
||||
image/hnm.o \
|
||||
cryomni3d.o \
|
||||
datstream.o \
|
||||
dialogs_manager.o \
|
||||
fixed_image.o \
|
||||
font_manager.o \
|
||||
metaengine.o \
|
||||
mouse_boxes.o \
|
||||
objects.o \
|
||||
omni3d.o \
|
||||
sprites.o \
|
||||
wam_parser.o
|
||||
|
||||
ifdef ENABLE_VERSAILLES
|
||||
MODULE_OBJS += \
|
||||
versailles/data.o \
|
||||
versailles/dialogs_manager.o \
|
||||
versailles/dialogs.o \
|
||||
versailles/documentation.o \
|
||||
versailles/engine.o \
|
||||
versailles/logic.o \
|
||||
versailles/menus.o \
|
||||
versailles/music.o \
|
||||
versailles/saveload.o \
|
||||
versailles/toolbar.o
|
||||
endif
|
||||
|
||||
# This module can be built as a plugin
|
||||
ifeq ($(ENABLE_CRYOMNI3D), DYNAMIC_PLUGIN)
|
||||
PLUGIN := 1
|
||||
endif
|
||||
|
||||
# Include common rules
|
||||
include $(srcdir)/rules.mk
|
||||
|
||||
# Detection objects
|
||||
DETECT_OBJS += $(MODULE)/detection.o
|
||||
94
engines/cryomni3d/mouse_boxes.cpp
Normal file
94
engines/cryomni3d/mouse_boxes.cpp
Normal file
@@ -0,0 +1,94 @@
|
||||
/* 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 "cryomni3d/mouse_boxes.h"
|
||||
|
||||
#include "common/rect.h"
|
||||
|
||||
#include "cryomni3d/font_manager.h"
|
||||
|
||||
namespace CryOmni3D {
|
||||
|
||||
MouseBoxes::MouseBoxes(uint size) {
|
||||
_boxes.resize(size);
|
||||
}
|
||||
|
||||
MouseBoxes::~MouseBoxes() {
|
||||
}
|
||||
|
||||
void MouseBoxes::reset() {
|
||||
uint sz = _boxes.size();
|
||||
_boxes.clear();
|
||||
_boxes.resize(sz);
|
||||
}
|
||||
|
||||
void MouseBoxes::setupBox(int box_id, int left, int top, int right, int bottom,
|
||||
const Common::String *text) {
|
||||
MouseBox &box = _boxes[box_id];
|
||||
box.left = left;
|
||||
box.top = top;
|
||||
box.right = right;
|
||||
box.bottom = bottom;
|
||||
box.isChar = false;
|
||||
box.string = text;
|
||||
}
|
||||
|
||||
void MouseBoxes::setupBox(int box_id, int left, int top, int right, int bottom, const char *text) {
|
||||
MouseBox &box = _boxes[box_id];
|
||||
box.left = left;
|
||||
box.top = top;
|
||||
box.right = right;
|
||||
box.bottom = bottom;
|
||||
box.isChar = true;
|
||||
box.charp = text;
|
||||
}
|
||||
|
||||
Common::Rect MouseBoxes::getBoxRect(int box_id) const {
|
||||
const MouseBox &box = _boxes[box_id];
|
||||
return Common::Rect(box.left, box.top, box.right, box.bottom);
|
||||
}
|
||||
|
||||
Common::Point MouseBoxes::getBoxOrigin(int box_id) const {
|
||||
const MouseBox &box = _boxes[box_id];
|
||||
return Common::Point(box.left, box.top);
|
||||
}
|
||||
|
||||
bool MouseBoxes::hitTest(int box_id, const Common::Point &pt) {
|
||||
const MouseBox &box = _boxes[box_id];
|
||||
|
||||
return (box.left != -1) &&
|
||||
(pt.x > box.left && pt.x < box.right &&
|
||||
pt.y > box.top && pt.y < box.bottom);
|
||||
}
|
||||
|
||||
void MouseBoxes::display(int box_id, const FontManager &font_manager) {
|
||||
const MouseBox &box = _boxes[box_id];
|
||||
|
||||
if (box.string) {
|
||||
if (box.isChar) {
|
||||
font_manager.displayStr(box.left, box.top, box.charp);
|
||||
} else {
|
||||
font_manager.displayStr(box.left, box.top, *box.string);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
72
engines/cryomni3d/mouse_boxes.h
Normal file
72
engines/cryomni3d/mouse_boxes.h
Normal file
@@ -0,0 +1,72 @@
|
||||
/* 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 CRYOMNI3D_MOUSE_BOXES_H
|
||||
#define CRYOMNI3D_MOUSE_BOXES_H
|
||||
|
||||
#include "common/array.h"
|
||||
#include "common/str.h"
|
||||
|
||||
namespace Common {
|
||||
struct Point;
|
||||
struct Rect;
|
||||
}
|
||||
|
||||
namespace CryOmni3D {
|
||||
|
||||
class FontManager;
|
||||
|
||||
class MouseBoxes {
|
||||
public:
|
||||
MouseBoxes(uint size);
|
||||
virtual ~MouseBoxes();
|
||||
|
||||
void reset();
|
||||
void setupBox(int box_id, int left, int top, int right, int bottom,
|
||||
const Common::String *text = nullptr);
|
||||
void setupBox(int box_id, int left, int top, int right, int bottom, const char *text);
|
||||
Common::Rect getBoxRect(int box_id) const;
|
||||
Common::Point getBoxOrigin(int box_id) const;
|
||||
bool hitTest(int box_id, const Common::Point &pt);
|
||||
void display(int box_id, const FontManager &font_manager);
|
||||
|
||||
private:
|
||||
struct MouseBox {
|
||||
MouseBox() : left(-1), top(-1), right(-1), bottom(-1), string(nullptr), isChar(false) {}
|
||||
|
||||
int left;
|
||||
int top;
|
||||
int right;
|
||||
int bottom;
|
||||
// Can be nullptr
|
||||
bool isChar;
|
||||
union {
|
||||
const Common::String *string;
|
||||
const char *charp;
|
||||
};
|
||||
};
|
||||
|
||||
Common::Array<MouseBox> _boxes;
|
||||
};
|
||||
|
||||
} // End of namespace CryOmni3D
|
||||
|
||||
#endif
|
||||
107
engines/cryomni3d/objects.cpp
Normal file
107
engines/cryomni3d/objects.cpp
Normal file
@@ -0,0 +1,107 @@
|
||||
/* 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 "cryomni3d/objects.h"
|
||||
|
||||
namespace CryOmni3D {
|
||||
|
||||
Object *Objects::findObjectByNameID(uint nameID) {
|
||||
for (iterator it = begin(); it != end(); it++) {
|
||||
if (it->valid() && it->idOBJ() == nameID) {
|
||||
return it;
|
||||
}
|
||||
}
|
||||
error("nameID not found %u", nameID);
|
||||
}
|
||||
|
||||
Object *Objects::findObjectByIconID(uint iconID) {
|
||||
for (iterator it = begin(); it != end(); it++) {
|
||||
if (it->valid() && it->idCA() == iconID) {
|
||||
return it;
|
||||
}
|
||||
}
|
||||
error("iconID not found %u", iconID);
|
||||
}
|
||||
|
||||
void Inventory::clear() {
|
||||
for (iterator it = begin(); it != end(); it++) {
|
||||
*it = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void Inventory::add(Object *obj) {
|
||||
for (iterator it = begin(); it != end(); it++) {
|
||||
if (*it == nullptr) {
|
||||
*it = obj;
|
||||
(*_changeCallback)(it - begin());
|
||||
return;
|
||||
}
|
||||
}
|
||||
error("No more room in inventory");
|
||||
}
|
||||
|
||||
void Inventory::remove(uint position) {
|
||||
(*this)[position] = nullptr;
|
||||
(*_changeCallback)(uint(-1));
|
||||
}
|
||||
|
||||
void Inventory::removeByIconID(uint iconID) {
|
||||
for (iterator it = begin(); it != end(); it++) {
|
||||
if ((*it) && (*it)->idCA() == iconID) {
|
||||
deselectObject();
|
||||
remove(it - begin());
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Don't bail out
|
||||
}
|
||||
|
||||
void Inventory::removeByNameID(uint nameID) {
|
||||
for (iterator it = begin(); it != end(); it++) {
|
||||
if ((*it) && (*it)->idOBJ() == nameID) {
|
||||
deselectObject();
|
||||
remove(it - begin());
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Don't bail out
|
||||
}
|
||||
|
||||
bool Inventory::inInventoryByIconID(uint iconID) const {
|
||||
for (const_iterator it = begin(); it != end(); it++) {
|
||||
if ((*it) && (*it)->idCA() == iconID) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Inventory::inInventoryByNameID(uint nameID) const {
|
||||
for (const_iterator it = begin(); it != end(); it++) {
|
||||
if ((*it) && (*it)->idOBJ() == nameID) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // End of namespace CryOmni3D
|
||||
103
engines/cryomni3d/objects.h
Normal file
103
engines/cryomni3d/objects.h
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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CRYOMNI3D_OBJECTS_H
|
||||
#define CRYOMNI3D_OBJECTS_H
|
||||
|
||||
#include "common/array.h"
|
||||
#include "common/func.h"
|
||||
#include "common/str.h"
|
||||
|
||||
#include "cryomni3d/sprites.h"
|
||||
|
||||
namespace CryOmni3D {
|
||||
|
||||
class Object {
|
||||
public:
|
||||
typedef Common::Functor0<void> *ViewCallback;
|
||||
|
||||
Object() : _valid(false), _idCA(uint(-1)), _idCl(uint(-1)), _idSA(uint(-1)), _idSl(uint(-1)),
|
||||
_idOBJ(uint(-1)),
|
||||
_viewCallback(nullptr) {}
|
||||
|
||||
Object(const Sprites &sprites, uint id_CA, uint id_OBJ) : _idCA(id_CA),
|
||||
_idCl(sprites.calculateSpriteId(id_CA, 1)), _idSA(sprites.calculateSpriteId(id_CA, 2)),
|
||||
_idSl(sprites.calculateSpriteId(id_CA, 3)),
|
||||
_valid(true), _idOBJ(id_OBJ), _viewCallback(nullptr) {}
|
||||
|
||||
~Object() { delete _viewCallback; }
|
||||
|
||||
uint valid() const { return _valid; }
|
||||
uint idCA() const { return _idCA; }
|
||||
uint idCl() const { return _idCl; }
|
||||
uint idSA() const { return _idSA; }
|
||||
uint idSl() const { return _idSl; }
|
||||
uint idOBJ() const { return _idOBJ; }
|
||||
ViewCallback viewCallback() const { return _viewCallback; }
|
||||
// Takes ownership of the pointer
|
||||
void setViewCallback(ViewCallback callback) { _viewCallback = callback; }
|
||||
|
||||
void rename(uint newIdOBJ) { _idOBJ = newIdOBJ; }
|
||||
|
||||
private:
|
||||
uint _idOBJ;
|
||||
uint _idCA;
|
||||
uint _idCl;
|
||||
uint _idSA;
|
||||
uint _idSl;
|
||||
bool _valid;
|
||||
ViewCallback _viewCallback;
|
||||
};
|
||||
|
||||
class Objects : public Common::Array<Object> {
|
||||
public:
|
||||
Object *findObjectByNameID(uint nameID);
|
||||
Object *findObjectByIconID(uint iconID);
|
||||
private:
|
||||
};
|
||||
|
||||
class Inventory : public Common::Array<Object *> {
|
||||
public:
|
||||
Inventory() : _selectedObject(nullptr), _changeCallback(nullptr) { }
|
||||
~Inventory() { delete _changeCallback; }
|
||||
void init(uint count, Common::Functor1<uint, void> *changeCallback) { _changeCallback = changeCallback; resize(count); }
|
||||
|
||||
void clear();
|
||||
void add(Object *);
|
||||
void remove(uint position);
|
||||
void removeByNameID(uint nameID);
|
||||
void removeByIconID(uint iconID);
|
||||
bool inInventoryByNameID(uint nameID) const;
|
||||
bool inInventoryByIconID(uint iconID) const;
|
||||
|
||||
Object *selectedObject() const { return _selectedObject; }
|
||||
void setSelectedObject(Object *obj) { _selectedObject = obj; }
|
||||
void deselectObject() { _selectedObject = nullptr; }
|
||||
|
||||
private:
|
||||
Object *_selectedObject;
|
||||
Common::Functor1<uint, void> *_changeCallback;
|
||||
};
|
||||
|
||||
} // End of namespace CryOmni3D
|
||||
|
||||
#endif
|
||||
|
||||
274
engines/cryomni3d/omni3d.cpp
Normal file
274
engines/cryomni3d/omni3d.cpp
Normal file
@@ -0,0 +1,274 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 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 "cryomni3d/omni3d.h"
|
||||
|
||||
#include "common/rect.h"
|
||||
|
||||
namespace CryOmni3D {
|
||||
|
||||
void Omni3DManager::init(double hfov) {
|
||||
_alpha = 0.;
|
||||
_beta = 0.;
|
||||
_xSpeed = 0.;
|
||||
_ySpeed = 0.;
|
||||
|
||||
double oppositeSide = tan(hfov / 2.) / (4. / 3.);
|
||||
double vf = atan2(oppositeSide, 1.);
|
||||
_vfov = (M_PI_2 - vf - (13. / 180.*M_PI)) * 10. / 9.;
|
||||
|
||||
double warpVfov = 155. / 180. * M_PI;
|
||||
double hypV = 768. / 2. / sin(warpVfov / 2.);
|
||||
double oppHTot = tan(hfov / 2.) * 16. / 320.;
|
||||
_helperValue = 2048 * 65536 / (2. * M_PI);
|
||||
|
||||
for (int i = 0; i < 31; i++) {
|
||||
double oppH = (i - 15) * oppHTot;
|
||||
double angle = atan2(oppH, 1.);
|
||||
|
||||
_anglesH[i] = angle;
|
||||
_hypothenusesH[i] = sqrt(oppH * oppH + 1);
|
||||
|
||||
double oppVTot = hypV * _hypothenusesH[i];
|
||||
for (int j = 0; j < 21; j++) {
|
||||
double oppV = (j - 20) * oppHTot;
|
||||
|
||||
_oppositeV[j] = oppV;
|
||||
|
||||
double coord = sqrt(oppV * oppV + _hypothenusesH[i] * _hypothenusesH[i]);
|
||||
coord = oppVTot / coord;
|
||||
coord = coord * 65536;
|
||||
|
||||
_squaresCoords[i][j] = coord;
|
||||
}
|
||||
}
|
||||
|
||||
_surface.create(640, 480, Graphics::PixelFormat::createFormatCLUT8());
|
||||
clearConstraints();
|
||||
}
|
||||
|
||||
Omni3DManager::~Omni3DManager() {
|
||||
_surface.free();
|
||||
}
|
||||
|
||||
void Omni3DManager::updateCoords(int xDelta, int yDelta, bool useOldSpeed) {
|
||||
double xDelta1 = xDelta * 0.00025;
|
||||
double yDelta1 = yDelta * 0.0002;
|
||||
|
||||
if (useOldSpeed) {
|
||||
_xSpeed += xDelta1;
|
||||
_ySpeed += yDelta1;
|
||||
} else {
|
||||
_xSpeed = xDelta1;
|
||||
_ySpeed = yDelta1;
|
||||
}
|
||||
_alpha += _xSpeed;
|
||||
_beta += _ySpeed;
|
||||
|
||||
//debug("alpha = %lf beta = %lf xSpeed = %lf ySpeed = %lf", _alpha, _beta, _xSpeed, _ySpeed);
|
||||
|
||||
_xSpeed *= 0.4;
|
||||
_ySpeed *= 0.6;
|
||||
|
||||
if (useOldSpeed) {
|
||||
if (fabs(_xSpeed) < 0.001) {
|
||||
_xSpeed = 0.;
|
||||
}
|
||||
if (fabs(_ySpeed) < 0.001) {
|
||||
_ySpeed = 0.;
|
||||
}
|
||||
}
|
||||
|
||||
if (_alpha < _alphaMin) {
|
||||
_alpha = _alphaMin;
|
||||
_xSpeed = 0.;
|
||||
} else if (_alpha > _alphaMax) {
|
||||
_alpha = _alphaMax;
|
||||
_xSpeed = 0.;
|
||||
}
|
||||
if (_beta < _betaMin) {
|
||||
_beta = _betaMin;
|
||||
_ySpeed = 0.;
|
||||
} else if (_beta > _betaMax) {
|
||||
_beta = _betaMax;
|
||||
_ySpeed = 0.;
|
||||
}
|
||||
|
||||
if (_alpha >= 2. * M_PI) {
|
||||
_alpha -= 2. * M_PI;
|
||||
} else if (_alpha < 0.) {
|
||||
_alpha += 2. * M_PI;
|
||||
}
|
||||
|
||||
_dirtyCoords = true;
|
||||
|
||||
updateImageCoords();
|
||||
}
|
||||
|
||||
void Omni3DManager::updateImageCoords() {
|
||||
if (!_dirtyCoords) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_alpha >= 2.*M_PI) {
|
||||
_alpha -= 2.*M_PI;
|
||||
} else if (_alpha < 0) {
|
||||
_alpha += 2.*M_PI;
|
||||
}
|
||||
if (_beta > 0.9 * _vfov) {
|
||||
_beta = 0.9 * _vfov;
|
||||
} else if (_beta < -0.9 * _vfov) {
|
||||
_beta = -0.9 * _vfov;
|
||||
}
|
||||
|
||||
double tmp = (2048 * 65536) - 2048 * 65536 / (2. * M_PI) * _alpha;
|
||||
|
||||
uint k = 0;
|
||||
for (uint i = 0; i < 31; i++) {
|
||||
double v11 = _anglesH[i] + _beta;
|
||||
double v26 = sin(v11);
|
||||
double v25 = cos(v11) * _hypothenusesH[i];
|
||||
|
||||
uint offset = 80;
|
||||
uint j;
|
||||
for (j = 0; j < 20; j++) {
|
||||
double v16 = atan2(_oppositeV[j], v25);
|
||||
double v17 = v16 * _helperValue;
|
||||
double v18 = (384 * 65536) - _squaresCoords[i][j] * v26;
|
||||
|
||||
k += 2;
|
||||
_imageCoords[k + 0] = (int)(tmp + v17);
|
||||
_imageCoords[k + offset + 0] = (int)(tmp - v17);
|
||||
_imageCoords[k + 1] = (int) v18;
|
||||
_imageCoords[k + offset + 1] = (int) v18;
|
||||
|
||||
offset -= 4;
|
||||
}
|
||||
|
||||
double v19 = atan2(_oppositeV[j], v25);
|
||||
|
||||
k += 2;
|
||||
_imageCoords[k + 0] = (int)((2048.*65536.) - (_alpha - v19) * _helperValue);
|
||||
_imageCoords[k + 1] = (int)((384.*65536.) - _squaresCoords[i][j] * v26);
|
||||
|
||||
k += 40;
|
||||
}
|
||||
|
||||
_dirtyCoords = false;
|
||||
_dirty = true;
|
||||
}
|
||||
|
||||
const Graphics::Surface *Omni3DManager::getSurface() {
|
||||
if (!_sourceSurface) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (_dirtyCoords) {
|
||||
updateImageCoords();
|
||||
}
|
||||
|
||||
if (_dirty) {
|
||||
uint off = 2;
|
||||
byte *dst = (byte *)_surface.getBasePtr(0, 0);
|
||||
const byte *src = (const byte *)_sourceSurface->getBasePtr(0, 0);
|
||||
|
||||
for (uint i = 0; i < 30; i++) {
|
||||
for (uint j = 0; j < 40; j++) {
|
||||
int x1 = (_imageCoords[off + 2] - _imageCoords[off + 0]) >> 4;
|
||||
int y1 = (_imageCoords[off + 3] - _imageCoords[off + 1]) >> 4;
|
||||
int x1_ = (_imageCoords[off + 82 + 2] - _imageCoords[off + 82 + 0]) >> 4;
|
||||
int y1_ = (_imageCoords[off + 82 + 3] - _imageCoords[off + 82 + 1]) >> 4;
|
||||
|
||||
int dx1 = (x1_ - x1) >> 10;
|
||||
int dy1 = (y1_ - y1) >> 15;
|
||||
|
||||
y1 >>= 5;
|
||||
|
||||
int dx2 = (_imageCoords[off + 82 + 0] - _imageCoords[off + 0]) >> 4;
|
||||
int dy2 = (_imageCoords[off + 82 + 1] - _imageCoords[off + 1]) >> 9;
|
||||
int x2 = (((_imageCoords[off + 0] >> 0) * 2) + dx2) >> 1;
|
||||
int y2 = (((_imageCoords[off + 1] >> 5) * 2) + dy2) >> 1;
|
||||
|
||||
for (uint y = 0; y < 16; y++) {
|
||||
uint px = (x2 * 2 + x1) * 16;
|
||||
uint py = (y2 * 2 + y1) / 2;
|
||||
uint deltaX = x1 * 32;
|
||||
uint deltaY = y1;
|
||||
|
||||
for (uint x = 0; x < 16; x++) {
|
||||
uint srcOff = (py & 0x1ff800) | (px >> 21);
|
||||
dst[x] = src[srcOff];
|
||||
px += deltaX;
|
||||
py += deltaY;
|
||||
}
|
||||
dst += 640;
|
||||
|
||||
x1 += dx1;
|
||||
y1 += dy1;
|
||||
x2 += dx2;
|
||||
y2 += dy2;
|
||||
}
|
||||
dst -= 16 * 640 - 16;
|
||||
off += 2;
|
||||
}
|
||||
dst += 15 * 640;
|
||||
off += 2;
|
||||
}
|
||||
|
||||
_dirty = false;
|
||||
}
|
||||
|
||||
return &_surface;
|
||||
}
|
||||
|
||||
void Omni3DManager::clearConstraints() {
|
||||
_alphaMin = -HUGE_VAL;
|
||||
_alphaMax = HUGE_VAL;
|
||||
_betaMin = -HUGE_VAL;
|
||||
_betaMax = HUGE_VAL;
|
||||
}
|
||||
|
||||
Common::Point Omni3DManager::mapMouseCoords(const Common::Point &mouse) {
|
||||
Common::Point pt;
|
||||
|
||||
if (_dirtyCoords) {
|
||||
updateImageCoords();
|
||||
}
|
||||
|
||||
int smallX = mouse.x & 0xf, squareX = mouse.x >> 4;
|
||||
int smallY = mouse.y & 0xf, squareY = mouse.y >> 4;
|
||||
|
||||
uint off = 82 * squareY + 2 * squareX;
|
||||
|
||||
pt.x = ((_imageCoords[off + 2] +
|
||||
smallY * ((_imageCoords[off + 84] - _imageCoords[off + 2]) >> 4) +
|
||||
(smallX * smallY) * ((_imageCoords[off + 86] - _imageCoords[off + 84]) >> 8) +
|
||||
(smallX * (16 - smallY)) * ((_imageCoords[off + 4] - _imageCoords[off + 2]) >> 8))
|
||||
& 0x07ff0000) >> 16;
|
||||
pt.y = (_imageCoords[off + 3] +
|
||||
smallY * ((_imageCoords[off + 85] - _imageCoords[off + 3]) >> 4) +
|
||||
(smallX * smallY) * ((_imageCoords[off + 87] - _imageCoords[off + 85]) >> 8) +
|
||||
(smallX * (16 - smallY)) * ((_imageCoords[off + 5] - _imageCoords[off + 3]) >> 8)) >> 16;
|
||||
|
||||
return pt;
|
||||
}
|
||||
|
||||
} // End of namespace CryOmni3D
|
||||
84
engines/cryomni3d/omni3d.h
Normal file
84
engines/cryomni3d/omni3d.h
Normal file
@@ -0,0 +1,84 @@
|
||||
/* 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 CRYOMNI3D_OMNI3D_H
|
||||
#define CRYOMNI3D_OMNI3D_H
|
||||
|
||||
#include "graphics/surface.h"
|
||||
|
||||
namespace CryOmni3D {
|
||||
|
||||
class Omni3DManager {
|
||||
public:
|
||||
Omni3DManager() : _vfov(0), _alpha(0), _beta(0), _xSpeed(0), _ySpeed(0), _alphaMin(0), _alphaMax(0),
|
||||
_betaMin(0), _betaMax(0), _helperValue(0), _dirty(true), _dirtyCoords(true),
|
||||
_sourceSurface(nullptr) {}
|
||||
virtual ~Omni3DManager();
|
||||
|
||||
void init(double hfov);
|
||||
|
||||
void setSourceSurface(const Graphics::Surface *surface) { _sourceSurface = surface; _dirty = true; }
|
||||
|
||||
void clearConstraints();
|
||||
void setAlphaConstraints(double alphaMin, double alphaMax) { _alphaMin = alphaMin; _alphaMax = alphaMax; }
|
||||
void setBetaMinConstraint(double betaMin) { _betaMin = betaMin; }
|
||||
void setBetaMaxConstraint(double betaMax) { _betaMax = betaMax; }
|
||||
|
||||
void setAlpha(double alpha) { _alpha = alpha; _dirtyCoords = true; }
|
||||
void setBeta(double beta) { _beta = beta; _dirtyCoords = true; }
|
||||
void updateCoords(int xDelta, int yDelta, bool useOldSpeed);
|
||||
|
||||
double getAlpha() const { return _alpha; }
|
||||
double getBeta() const { return _beta; }
|
||||
|
||||
Common::Point mapMouseCoords(const Common::Point &mouse);
|
||||
|
||||
bool hasSpeed() { return _xSpeed != 0. || _ySpeed != 0.; }
|
||||
bool needsUpdate() { return _dirty || _dirtyCoords; }
|
||||
const Graphics::Surface *getSurface();
|
||||
|
||||
private:
|
||||
void updateImageCoords();
|
||||
|
||||
double _vfov;
|
||||
|
||||
double _alpha, _beta;
|
||||
double _xSpeed, _ySpeed;
|
||||
|
||||
double _alphaMin, _alphaMax;
|
||||
double _betaMin, _betaMax;
|
||||
|
||||
int _imageCoords[2544];
|
||||
double _squaresCoords[31][21];
|
||||
double _hypothenusesH[31];
|
||||
double _anglesH[31];
|
||||
double _oppositeV[21];
|
||||
double _helperValue;
|
||||
|
||||
bool _dirty;
|
||||
bool _dirtyCoords;
|
||||
const Graphics::Surface *_sourceSurface;
|
||||
Graphics::Surface _surface;
|
||||
};
|
||||
|
||||
} // End of namespace CryOmni3D
|
||||
|
||||
#endif
|
||||
229
engines/cryomni3d/sprites.cpp
Normal file
229
engines/cryomni3d/sprites.cpp
Normal file
@@ -0,0 +1,229 @@
|
||||
/* 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/debug.h"
|
||||
#include "common/file.h"
|
||||
#include "graphics/surface.h"
|
||||
|
||||
#include "cryomni3d/sprites.h"
|
||||
|
||||
// #define SPRTIES_DEBUG
|
||||
|
||||
namespace CryOmni3D {
|
||||
|
||||
#define MAP_ID(id) \
|
||||
do { \
|
||||
if (_map) { \
|
||||
id = (*_map)[id]; \
|
||||
} \
|
||||
} while(false)
|
||||
|
||||
Sprites::Sprites() : _map(nullptr) {
|
||||
_surface = new Graphics::Surface();
|
||||
}
|
||||
|
||||
Sprites::~Sprites() {
|
||||
for (Common::Array<CryoCursor *>::iterator it = _cursors.begin(); it != _cursors.end(); it++) {
|
||||
if ((*it)->refCnt > 1) {
|
||||
(*it)->refCnt--;
|
||||
} else {
|
||||
delete *it;
|
||||
}
|
||||
}
|
||||
delete _map;
|
||||
delete _surface;
|
||||
}
|
||||
|
||||
void Sprites::loadSprites(Common::ReadStream &spr_fl) {
|
||||
while (true) {
|
||||
uint32 magic = spr_fl.readUint32BE();
|
||||
if (spr_fl.eos()) {
|
||||
// We are EOS so last read likely failed
|
||||
break;
|
||||
}
|
||||
if (magic != MKTAG('S', 'P', 'R', 'I')) {
|
||||
error("Invalid sprite magic");
|
||||
}
|
||||
|
||||
// 2 unknown uint32
|
||||
(void) spr_fl.readUint32BE();
|
||||
(void) spr_fl.readUint32BE();
|
||||
|
||||
CryoCursor *cursor = new CryoCursor();
|
||||
|
||||
uint16 w = spr_fl.readUint16BE();
|
||||
uint16 h = spr_fl.readUint16BE();
|
||||
uint sz = cursor->setup(w, h);
|
||||
cursor->_offX = spr_fl.readUint32BE();
|
||||
cursor->_offY = spr_fl.readUint32BE();
|
||||
|
||||
spr_fl.read(cursor->_data, sz);
|
||||
_cursors.push_back(cursor);
|
||||
}
|
||||
}
|
||||
|
||||
void Sprites::setupMapTable(const uint *table, uint size) {
|
||||
delete _map;
|
||||
_map = nullptr;
|
||||
// Reset the reverse mapping
|
||||
for (Common::Array<CryoCursor *>::iterator it = _cursors.begin(); it != _cursors.end(); it++) {
|
||||
(*it)->_constantId = uint(-1);
|
||||
}
|
||||
if (table) {
|
||||
_map = new Common::Array<uint>(table, size);
|
||||
|
||||
// Sweep all the mapping and set its reverse values
|
||||
uint i = 0;
|
||||
for (Common::Array<uint>::const_iterator it = _map->begin(); it != _map->end(); it++, i++) {
|
||||
_cursors[*it]->_constantId = i;
|
||||
}
|
||||
|
||||
#ifdef SPRITES_DEBUG
|
||||
// Normally we don't have any unreachable sprties from constants,
|
||||
// as it could be time consuming, this should be fixed in the static map
|
||||
// Count unswept values
|
||||
uint unswept = 0;
|
||||
for (Common::Array<CryoCursor *>::iterator it = _cursors.begin(); it != _cursors.end(); it++) {
|
||||
if ((*it)->_constantId == -1u) {
|
||||
unswept++;
|
||||
}
|
||||
}
|
||||
|
||||
if (unswept) {
|
||||
warning("We got %d unreachable sprites from map table. This should not happen."
|
||||
" Fixing it for now", unswept);
|
||||
// Enlarge the map to hold new indices
|
||||
_map->reserve(_map->size() + unswept);
|
||||
|
||||
// Set new indices to unswept sprites
|
||||
i = 0;
|
||||
for (Common::Array<CryoCursor *>::iterator it = _cursors.begin(); it != _cursors.end(); it++, i++) {
|
||||
if ((*it)->_constantId == -1u) {
|
||||
warning("Fixing sprite the %d sprite", i);
|
||||
(*it)->_constantId = _map->size();
|
||||
_map->push_back(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void Sprites::setSpriteHotspot(uint spriteId, uint x, uint y) {
|
||||
MAP_ID(spriteId);
|
||||
_cursors[spriteId]->_offX = x;
|
||||
_cursors[spriteId]->_offY = y;
|
||||
}
|
||||
|
||||
void Sprites::replaceSprite(uint oldSpriteId, uint newSpriteId) {
|
||||
MAP_ID(oldSpriteId);
|
||||
MAP_ID(newSpriteId);
|
||||
if (_cursors[oldSpriteId]->refCnt > 1) {
|
||||
_cursors[oldSpriteId]->refCnt--;
|
||||
} else {
|
||||
delete _cursors[oldSpriteId];
|
||||
}
|
||||
_cursors[oldSpriteId] = _cursors[newSpriteId];
|
||||
_cursors[oldSpriteId]->refCnt++;
|
||||
}
|
||||
|
||||
void Sprites::replaceSpriteColor(uint spriteId, byte currentColor, byte newColor) {
|
||||
MAP_ID(spriteId);
|
||||
|
||||
byte *data = _cursors[spriteId]->_data;
|
||||
uint size = _cursors[spriteId]->_width * _cursors[spriteId]->_height;
|
||||
for (; size > 0; size--, data++) {
|
||||
if (*data == currentColor) {
|
||||
*data = newColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint Sprites::getSpritesCount() const {
|
||||
if (_map) {
|
||||
return _map->size();
|
||||
} else {
|
||||
return _cursors.size();
|
||||
}
|
||||
}
|
||||
|
||||
uint Sprites::revMapSpriteId(uint id) const {
|
||||
if (_map) {
|
||||
if (id >= _cursors.size()) {
|
||||
error("revMapSpriteId is out of bounds: %d/%d", id, _cursors.size());
|
||||
}
|
||||
id = _cursors[id]->_constantId;
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
uint Sprites::calculateSpriteId(uint baseId, uint offset) const {
|
||||
if (_map) {
|
||||
MAP_ID(baseId);
|
||||
baseId += offset;
|
||||
if (baseId >= _cursors.size()) {
|
||||
error("Calculate sprite is out of bounds: %d/%d", baseId, _cursors.size());
|
||||
}
|
||||
uint spriteId = _cursors[baseId]->_constantId;
|
||||
if (spriteId == uint(-1)) {
|
||||
error("Sprite %d is unreachable", baseId);
|
||||
}
|
||||
return spriteId;
|
||||
} else {
|
||||
return baseId + offset;
|
||||
}
|
||||
}
|
||||
|
||||
const Graphics::Surface &Sprites::getSurface(uint spriteId) const {
|
||||
MAP_ID(spriteId);
|
||||
|
||||
CryoCursor *cursor = _cursors[spriteId];
|
||||
|
||||
_surface->init(cursor->_width, cursor->_height, cursor->_width, cursor->_data,
|
||||
Graphics::PixelFormat::createFormatCLUT8());
|
||||
return *_surface;
|
||||
}
|
||||
|
||||
const Graphics::Cursor &Sprites::getCursor(uint spriteId) const {
|
||||
MAP_ID(spriteId);
|
||||
|
||||
return *_cursors[spriteId];
|
||||
}
|
||||
|
||||
Sprites::CryoCursor::CryoCursor() : _width(0), _height(0), _offX(0), _offY(0), _data(nullptr),
|
||||
refCnt(1), _constantId(uint(-1)) {
|
||||
}
|
||||
|
||||
Sprites::CryoCursor::~CryoCursor() {
|
||||
assert(refCnt == 1);
|
||||
delete[] _data;
|
||||
}
|
||||
|
||||
uint Sprites::CryoCursor::setup(uint16 width, uint16 height) {
|
||||
_width = width;
|
||||
_height = height;
|
||||
uint sz = _width * _height;
|
||||
_data = new byte[sz];
|
||||
return sz;
|
||||
}
|
||||
|
||||
} // End of namespace CryOmni3D
|
||||
103
engines/cryomni3d/sprites.h
Normal file
103
engines/cryomni3d/sprites.h
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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CRYOMNI3D_SPRITES_H
|
||||
#define CRYOMNI3D_SPRITES_H
|
||||
|
||||
#include "common/array.h"
|
||||
#include "common/str.h"
|
||||
|
||||
#include "graphics/cursor.h"
|
||||
|
||||
namespace Common {
|
||||
class ReadStream;
|
||||
}
|
||||
|
||||
namespace Graphics {
|
||||
struct Surface;
|
||||
}
|
||||
|
||||
namespace CryOmni3D {
|
||||
|
||||
class Sprites {
|
||||
public:
|
||||
Sprites();
|
||||
virtual ~Sprites();
|
||||
|
||||
void loadSprites(Common::ReadStream &spr_fl);
|
||||
void setupMapTable(const uint *table, uint size);
|
||||
|
||||
void setSpriteHotspot(uint spriteId, uint x, uint y);
|
||||
|
||||
void replaceSprite(uint oldSpriteId, uint newSpriteId);
|
||||
|
||||
uint getSpritesCount() const;
|
||||
|
||||
void replaceSpriteColor(uint spriteId, byte currentColor, byte newColor);
|
||||
|
||||
const Graphics::Surface &getSurface(uint spriteId) const;
|
||||
const Graphics::Cursor &getCursor(uint spriteId) const;
|
||||
|
||||
uint revMapSpriteId(uint id) const;
|
||||
uint calculateSpriteId(uint baseId, uint offset) const;
|
||||
|
||||
byte getKeyColor(uint spriteId) const { return 0; }
|
||||
|
||||
private:
|
||||
class CryoCursor : public Graphics::Cursor {
|
||||
public:
|
||||
uint16 getWidth() const override { return _width; }
|
||||
uint16 getHeight() const override { return _height; }
|
||||
uint16 getHotspotX() const override { return _offX; }
|
||||
uint16 getHotspotY() const override { return _offY; }
|
||||
byte getKeyColor() const override { return 0; }
|
||||
|
||||
const byte *getSurface() const override { return _data; }
|
||||
|
||||
const byte *getPalette() const override { return nullptr; }
|
||||
byte getPaletteStartIndex() const override { return 0; }
|
||||
uint16 getPaletteCount() const override { return 0; }
|
||||
|
||||
uint setup(uint16 width, uint16 height);
|
||||
|
||||
uint16 _width;
|
||||
uint16 _height;
|
||||
int16 _offX;
|
||||
int16 _offY;
|
||||
uint _constantId;
|
||||
|
||||
byte *_data;
|
||||
|
||||
uint refCnt;
|
||||
|
||||
CryoCursor();
|
||||
~CryoCursor() override;
|
||||
};
|
||||
|
||||
// Pointer to avoid to mutate Sprites when asking for a cursor
|
||||
Graphics::Surface *_surface;
|
||||
Common::Array<CryoCursor *> _cursors;
|
||||
Common::Array<uint> *_map;
|
||||
};
|
||||
|
||||
} // End of namespace CryOmni3D
|
||||
|
||||
#endif
|
||||
948
engines/cryomni3d/versailles/data.cpp
Normal file
948
engines/cryomni3d/versailles/data.cpp
Normal file
@@ -0,0 +1,948 @@
|
||||
/* 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 "cryomni3d/datstream.h"
|
||||
|
||||
#include "cryomni3d/versailles/engine.h"
|
||||
|
||||
namespace CryOmni3D {
|
||||
namespace Versailles {
|
||||
|
||||
const uint CryOmni3DEngine_Versailles::kSpritesMapTable[] = {
|
||||
/* 0 */ 242, 240, 243, 241, 256, 93, 97, 94, 160, 98, 178, 161, 179, 196, 197, 244,
|
||||
/* 16 */ 142, 245, 143, 254, 95, 99, 113, 96, 100, 180, 114, 181, 73, 144, 74, 250,
|
||||
/* 32 */ 202, 145, 170, 251, 203, 130, 206, 171, 49, 131, 207, 115, 116, 222, 75, 85,
|
||||
/* 48 */ 76, 252, 204, 236, 86, 172, 253, 205, 237, 132, 81, 208, 173, 133, 82, 209,
|
||||
/* 64 */ 24, 101, 25, 102, 87, 198, 88, 83, 258, 199, 84, 259, 257, 260, 26, 103,
|
||||
/* 80 */ 28, 44, 27, 104, 29, 45, 200, 105, 201, 106, 162, 163, 32, 30, 46, 126,
|
||||
/* 96 */ 33, 31, 47, 5, 127, 122, 219, 227, 123, 220, 107, 69, 108, 70, 164, 165,
|
||||
/* 112 */ 89, 4, 90, 36, 34, 58, 128, 109, 37, 35, 255, 129, 110, 124, 125, 71,
|
||||
/* 128 */ 40, 72, 41, 91, 92, 59, 228, 38, 7, 60, 111, 229, 39, 149, 121, 138,
|
||||
/* 144 */ 112, 6, 139, 148, 42, 43, 232, 230, 233, 231, 140, 141, 134, 150, 135, 234,
|
||||
/* 160 */ 151, 20, 226, 261, 235, 21, 262, 166, 246, 167, 136, 50, 247, 215, 152, 137,
|
||||
/* 176 */ 51, 216, 153, 22, 117, 48, 23, 225, 118, 223, 182, 168, 248, 183, 169, 54,
|
||||
/* 192 */ 52, 249, 217, 55, 53, 218, 8, 214, 119, 120, 186, 184, 154, 61, 187, 185,
|
||||
/* 208 */ 155, 62, 56, 57, 188, 156, 65, 63, 210, 189, 157, 66, 64, 211, 19, 3,
|
||||
/* 224 */ 80, 221, 1, 263, 78, 67, 174, 212, 68, 175, 213, 190, 191, 238, 0, 239,
|
||||
/* 240 */ 224, 77, 146, 2, 147, 79, 158, 176, 159, 177, 194, 192, 195, 193, /*-1u, -1u*/
|
||||
};
|
||||
const uint CryOmni3DEngine_Versailles::kSpritesMapTableSize = ARRAYSIZE(kSpritesMapTable);
|
||||
|
||||
const LevelInitialState CryOmni3DEngine_Versailles::kLevelInitialStates[] = {
|
||||
{ 1, M_PI, 0. }, // Level 1
|
||||
{ 9, M_PI, 0. }, // Level 2
|
||||
{ 10, M_PI_2, 0. }, // Level 3
|
||||
{ 10, 0., 0. }, // Level 4
|
||||
{ 14, M_PI, 0. }, // Level 5
|
||||
{ 8, 0., 0. }, // Level 6
|
||||
{ 1, M_PI, 0. }, // Level 7
|
||||
{ 4, M_PI, 0. } // Level 8
|
||||
};
|
||||
|
||||
const FakeTransitionActionPlace CryOmni3DEngine_Versailles::kFakeTransitions[] = {
|
||||
{31141, 15},
|
||||
{31142, 16},
|
||||
{31143, 17},
|
||||
{32201, 18},
|
||||
{32202, 19},
|
||||
{32203, 20},
|
||||
{32204, 21},
|
||||
{35330, 36},
|
||||
{34172, 18},
|
||||
{0, 0} // Must be the last one
|
||||
};
|
||||
|
||||
static void readSubtitles(Common::HashMap<Common::String, Common::Array<SubtitleEntry> > &subtitles,
|
||||
DATSeekableStream *data) {
|
||||
uint16 vidsCount = data->readUint16LE();
|
||||
for (uint16 i = 0; i < vidsCount; i++) {
|
||||
Common::String vidName = data->readString16();
|
||||
Common::Array<SubtitleEntry> &entries = subtitles[vidName];
|
||||
|
||||
uint16 linesCount = data->readUint16LE();
|
||||
entries.resize(linesCount);
|
||||
for (uint16 j = 0; j < linesCount; j++) {
|
||||
SubtitleEntry &entry = entries[j];
|
||||
|
||||
entry.frameStart = data->readUint32LE();
|
||||
entry.text = data->readString16();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CryOmni3DEngine_Versailles::loadStaticData() {
|
||||
// This should match data in devtools/create_cryomni3d_dat
|
||||
DATSeekableStream *data = getStaticData(MKTAG('V', 'R', 'S', 'L'), 1);
|
||||
|
||||
// In the dat file we have
|
||||
// file names
|
||||
data->readString16Array16(_localizedFilenames);
|
||||
assert(_localizedFilenames.size() == LocalizedFilenames::kMax);
|
||||
|
||||
// epigraph settings, bomb password
|
||||
_epigraphContent = data->readString16();
|
||||
_epigraphPassword = data->readString16();
|
||||
|
||||
if (getLanguage() == Common::JA_JPN) {
|
||||
_bombAlphabet = data->readString16().decode(Common::kWindows932);
|
||||
_bombPassword = data->readString16().decode(Common::kWindows932);
|
||||
} else {
|
||||
_bombAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ '";
|
||||
_bombPassword = data->readString16();
|
||||
}
|
||||
|
||||
// messages, paintings titles
|
||||
data->readString16Array16(_messages);
|
||||
if ((getLanguage() == Common::JA_JPN) ||
|
||||
(getLanguage() == Common::KO_KOR) ||
|
||||
(getLanguage() == Common::ZH_TWN)) {
|
||||
assert(_messages.size() == 151);
|
||||
} else {
|
||||
assert(_messages.size() == 146);
|
||||
}
|
||||
data->readString16Array16(_paintingsTitles);
|
||||
assert(_paintingsTitles.size() == 48);
|
||||
|
||||
_subtitles.clear();
|
||||
// Only CJK have subtitles, don't change dat format for other languages
|
||||
if ((getLanguage() == Common::JA_JPN) ||
|
||||
(getLanguage() == Common::KO_KOR) ||
|
||||
(getLanguage() == Common::ZH_TWN)) {
|
||||
readSubtitles(_subtitles, data);
|
||||
}
|
||||
|
||||
delete data;
|
||||
}
|
||||
|
||||
struct VideoSubSetting {
|
||||
const char *videoName;
|
||||
int16 textLeft;
|
||||
int16 textTop;
|
||||
int16 textRight;
|
||||
int16 textBottom;
|
||||
int16 drawLeft;
|
||||
int16 drawTop;
|
||||
int16 drawRight;
|
||||
int16 drawBottom;
|
||||
};
|
||||
|
||||
static const VideoSubSetting kVideoSubSettings[] = {
|
||||
{"11D_LEB", 15, 11, 190, 479, 208, 129, 562, 479},
|
||||
{"11E_HUI", 330, 9, 620, 479, 111, 109, 321, 341},
|
||||
{"11E_MAN", 403, 12, 630, 479, 134, 89, 390, 405},
|
||||
{"11E_RAC", 10, 9, 241, 479, 271, 147, 628, 479},
|
||||
{"12E_HUI", 361, 16, 618, 479, 84, 107, 330, 479},
|
||||
{"13F_HUI", 373, 12, 633, 479, 96, 88, 341, 479},
|
||||
{"21B1_HUI", 355, 13, 625, 479, 96, 104, 337, 479},
|
||||
{"21F_BON", 324, 11, 628, 479, 84, 74, 307, 479},
|
||||
{"21F_BON2", 11, 13, 298, 479, 321, 99, 536, 424},
|
||||
{"21G_CON", 12, 13, 255, 479, 273, 156, 539, 479},
|
||||
{"21G_DAU", 358, 11, 631, 479, 82, 151, 346, 479},
|
||||
{"21G_HUI", 309, 17, 626, 479, 77, 85, 304, 479},
|
||||
{"21I_LEB", 343, 10, 628, 479, 38, 125, 330, 479},
|
||||
{"21Z_ALI", 380, 13, 627, 479, 184, 106, 369, 479},
|
||||
{"21Z_BOU", 365, 13, 629, 479, 95, 65, 341, 321},
|
||||
{"21Z_MON", 12, 11, 309, 479, 336, 101, 561, 406},
|
||||
{"21Z_PR", 10, 16, 352, 471, 375, 104, 567, 400},
|
||||
{"22G_DAU", 339, 13, 629, 479, 114, 152, 326, 479},
|
||||
{"23I_LEB", 341, 15, 627, 479, 67, 140, 325, 410},
|
||||
{"24Z_BON", 253, 23, 620, 479, 58, 166, 228, 439},
|
||||
{"31J_SUI", 9, 9, 183, 475, 195, 159, 428, 479},
|
||||
{"31L1_LUL", 367, 16, 628, 477, 136, 164, 359, 472},
|
||||
{"31M_SUI", 19, 16, 212, 479, 231, 193, 395, 479},
|
||||
{"31O_SUIA", 11, 12, 175, 479, 186, 118, 490, 479},
|
||||
{"31O_SUIP", 12, 9, 277, 466, 296, 183, 380, 349},
|
||||
{"31Q_SUI", 334, 15, 626, 479, 158, 169, 313, 308},
|
||||
{"31X_BO", 332, 11, 615, 479, 89, 78, 313, 296},
|
||||
{"31X_BON", 329, 12, 618, 456, 0, 171, 243, 479},
|
||||
{"31X_LOU", 12, 9, 267, 447, 280, 88, 639, 479},
|
||||
{"31X_SEI", 352, 12, 626, 479, 102, 98, 340, 479},
|
||||
{"32J_CRO", 418, 7, 618, 477, 103, 58, 402, 438},
|
||||
{"32M_MR", 13, 11, 175, 477, 184, 113, 476, 447},
|
||||
{"32Q_MON", 375, 17, 623, 479, 248, 161, 341, 259},
|
||||
{"32Q_RAC", 294, 11, 627, 479, 110, 152, 287, 479},
|
||||
{"32Q_RAC2", 374, 13, 625, 479, 0, 101, 366, 479},
|
||||
{"31O_SUIA", 11, 12, 175, 479, 186, 118, 490, 479},
|
||||
{"41C_HUI", 345, 17, 626, 479, 69, 147, 330, 479},
|
||||
{"41X2_CRO", 13, 13, 281, 479, 305, 113, 548, 427},
|
||||
{"42C_BON", 15, 13, 347, 479, 368, 173, 525, 410},
|
||||
{"43B1_MAI", 264, 15, 625, 479, 127, 154, 249, 296},
|
||||
{"43B1_SEI", 17, 14, 369, 479, 390, 142, 639, 479},
|
||||
{"43C_CON", 312, 11, 635, 479, 21, 137, 294, 476},
|
||||
{"43C_DUR", 11, 10, 295, 479, 311, 166, 639, 479},
|
||||
{"44C_BON", 17, 12, 331, 479, 358, 181, 531, 407},
|
||||
{"4_MAI", 325, 14, 630, 479, 35, 48, 308, 363},
|
||||
{"51L_LOU", 11, 11, 616, 161, 154, 165, 400, 479},
|
||||
{"51L_PRI", 26, 19, 601, 153, 130, 167, 311, 479},
|
||||
{"51M_LEB", 41, 29, 615, 188, 49, 200, 432, 479},
|
||||
{"51M_MAN", 23, 19, 618, 179, 211, 195, 449, 479},
|
||||
{"52A4_LAC", 12, 11, 258, 479, 273, 184, 465, 383},
|
||||
{"52L_BOU", 12, 12, 190, 479, 307, 56, 592, 332},
|
||||
{"52L_LOU", 8, 13, 604, 168, 135, 171, 413, 479},
|
||||
{"52L_PRI", 20, 17, 610, 167, 336, 182, 639, 479},
|
||||
{"53N_BON", 351, 13, 629, 479, 62, 119, 343, 418},
|
||||
{"54I_BON", 343, 14, 623, 479, 72, 117, 339, 440},
|
||||
{"61_BON", 10, 7, 311, 479, 336, 101, 581, 479},
|
||||
{"61_DUC", 10, 14, 344, 473, 376, 156, 639, 479},
|
||||
{"61_LEN", 13, 9, 269, 479, 285, 63, 590, 479},
|
||||
{"62_DUC", 18, 21, 317, 479, 388, 154, 614, 479},
|
||||
};
|
||||
|
||||
void CryOmni3DEngine_Versailles::setupDialogVariables() {
|
||||
#define SET_DIAL_VARIABLE(id, var) _dialogsMan.setupVariable(id, var)
|
||||
SET_DIAL_VARIABLE(0, "JOUEUR-PARLE-HUISSIER-PETIT-LEVER");
|
||||
SET_DIAL_VARIABLE(1, "HUBAS-PARLE-LEVER1");
|
||||
SET_DIAL_VARIABLE(2, "HUBAS-PARLE-LEVER2");
|
||||
SET_DIAL_VARIABLE(3, "LEBRUN-DIT-COLBERT");
|
||||
SET_DIAL_VARIABLE(4, "LEBRUN-PARLE-ESQUISSE");
|
||||
SET_DIAL_VARIABLE(5, "JOUEUR-PARLE-HUISSIER-GRAND-LEVER");
|
||||
SET_DIAL_VARIABLE(6, "BONTEMPS-PARLE-MAINTENON");
|
||||
SET_DIAL_VARIABLE(7, "BONTEMPS-PARLE-MAINTENON2");
|
||||
SET_DIAL_VARIABLE(8, "BONTEMPS-DEMANDE-INDICE");
|
||||
SET_DIAL_VARIABLE(9, "BONTEMPS-DIT-ENQUETE");
|
||||
SET_DIAL_VARIABLE(10, "JOUEUR-CONFIE-MESSAGE-HUISSIER");
|
||||
SET_DIAL_VARIABLE(11, "JOUEUR-PARLE-HUIMA1");
|
||||
SET_DIAL_VARIABLE(12, "MONSEIGNEUR-ATTEND-ESQUISSES");
|
||||
SET_DIAL_VARIABLE(13, "MONSEIGNEUR-PREVIENT-BONTEMPS");
|
||||
SET_DIAL_VARIABLE(14, "JOUEUR-MENT-MONSEIGNEUR");
|
||||
SET_DIAL_VARIABLE(15, "JOUEUR-ECOUTE-ALIAS");
|
||||
SET_DIAL_VARIABLE(16, "JOUEUR-PARLE-HUCON");
|
||||
SET_DIAL_VARIABLE(17, "BONTEMPS-ATTEND-OBJET-GALLERIE");
|
||||
SET_DIAL_VARIABLE(18, "SUISSE-APOLLON-PARLE-CLEF");
|
||||
SET_DIAL_VARIABLE(19, "SUISSE-CABINET-DEMANDE-AUTORISATION");
|
||||
SET_DIAL_VARIABLE(20, "SUISSE-VU-AUTORISATION");
|
||||
SET_DIAL_VARIABLE(21, "CROISSY-ACCEPTE-TEXTE");
|
||||
SET_DIAL_VARIABLE(22, "JOUEUR-POSSEDE-CLEF-PETITE-PORTE");
|
||||
SET_DIAL_VARIABLE(23, "SUISSE-REFUSE-CLEF");
|
||||
SET_DIAL_VARIABLE(24, "LULLY-ATTEND-MISSION-JOUEUR");
|
||||
SET_DIAL_VARIABLE(25, "LULLY-DONNE-MISSION1-JOUEUR");
|
||||
SET_DIAL_VARIABLE(26, "LULLY-DONNE-MISSION-JOUEUR");
|
||||
SET_DIAL_VARIABLE(27, "RACINE-REPOND-ETRANGERE");
|
||||
SET_DIAL_VARIABLE(28, "RACINE-REPOND-PEUPLES");
|
||||
SET_DIAL_VARIABLE(29, "LULLY-DONNE-MISSION2-JOUEUR");
|
||||
SET_DIAL_VARIABLE(30, "LULLY-DIT-CHAT-PENDU-JOUEUR");
|
||||
SET_DIAL_VARIABLE(31, "JOUEUR-DIT-PEUPLES-LULLY");
|
||||
SET_DIAL_VARIABLE(32, "LALANDE-PARLE-BONTEMPS-SCENE3");
|
||||
SET_DIAL_VARIABLE(33, "BONTEMPS-DONNE-AUTORISATION-CURIOSITES");
|
||||
SET_DIAL_VARIABLE(34, "BONTEMPS-ATTEND-PAMPHLET");
|
||||
SET_DIAL_VARIABLE(35, "BONTEMPS-VU-PAMPHLET-DECHIFFRE-LULLY");
|
||||
SET_DIAL_VARIABLE(36, "CROISSY-DIT-INEPTIES");
|
||||
SET_DIAL_VARIABLE(37, "CROISSY-ATTEND-PAMPHLET2");
|
||||
SET_DIAL_VARIABLE(38, "CROISSY-ATTEND-MEDAILLE");
|
||||
SET_DIAL_VARIABLE(39, "CROISSY-ATTEND-PAMPHLET2-2");
|
||||
SET_DIAL_VARIABLE(40, "JOUEUR-PARLE-CROISSY1");
|
||||
SET_DIAL_VARIABLE(41, "MONSIEUR-PARLE-LALANDE1");
|
||||
SET_DIAL_VARIABLE(42, "MONSIEUR-ATTEND-FUSAIN");
|
||||
SET_DIAL_VARIABLE(43, "MONSIEUR-DONNE-SOLUTION-MEDAILLES");
|
||||
SET_DIAL_VARIABLE(44, "HUISSIER-DIT-DINER");
|
||||
SET_DIAL_VARIABLE(45, "HUISSIER-DIT-PREVENIR-BONTEMPS");
|
||||
SET_DIAL_VARIABLE(46, "JOUEUR-POSSEDE-PAMPHLET-RELIGION");
|
||||
SET_DIAL_VARIABLE(47, "JOUEUR-PARLE-BONTEMPS-SCENE4");
|
||||
SET_DIAL_VARIABLE(48, "BONTEMPS-VU-PAPIER-CROISSY");
|
||||
SET_DIAL_VARIABLE(49, "BONTEMPS-ATTEND-OBJET-SCENE4");
|
||||
SET_DIAL_VARIABLE(50, "BONTEMPS-VU-PAMPHLET-GOUVERNEMENT");
|
||||
SET_DIAL_VARIABLE(51, "JOUEUR-PARLE-VAUBAN");
|
||||
SET_DIAL_VARIABLE(52, "JOUEUR-PARLE-CODE-LOUVOIS");
|
||||
SET_DIAL_VARIABLE(53, "LALANDE-ECOUTE-LOUVOIS");
|
||||
SET_DIAL_VARIABLE(54, "JOUEUR-PARLE-LACHAIZE");
|
||||
SET_DIAL_VARIABLE(55, "JOUEUR-PARLE-LACHAIZE2");
|
||||
SET_DIAL_VARIABLE(56, "LACHAIZE-ATTEND-TEXTE");
|
||||
SET_DIAL_VARIABLE(57, "LACHAIZE-VU-PAMPHLET-RELIGION");
|
||||
SET_DIAL_VARIABLE(58, "LACHAIZE-DIT-REFORME");
|
||||
SET_DIAL_VARIABLE(59, "LACHAIZE-PARLE-BOUILLON");
|
||||
SET_DIAL_VARIABLE(60, "BOUILLON-DIT-DRAGONNADES");
|
||||
SET_DIAL_VARIABLE(61, "JOUEUR-PARLE-BOUILLON");
|
||||
SET_DIAL_VARIABLE(62, "LACHAIZE-TROUVE-ECROUELLES");
|
||||
SET_DIAL_VARIABLE(63, "LACHAIZE-DIT-DRAGONNADES");
|
||||
SET_DIAL_VARIABLE(64, "LACHAIZE-DEMANDE-TEXTE");
|
||||
SET_DIAL_VARIABLE(65, "LACHAIZE-PARLE-ARCHITECTURE");
|
||||
SET_DIAL_VARIABLE(66, "JOUEUR-DIT-DRAGONNADES");
|
||||
SET_DIAL_VARIABLE(67, "BOUILLON-ATTEND-PAMPHLET");
|
||||
SET_DIAL_VARIABLE(68, "BONTEMPS-PARLE-LUSTRE");
|
||||
SET_DIAL_VARIABLE(69, "BONTEMPS-ATTEND-MEMORANDUM2");
|
||||
SET_DIAL_VARIABLE(70, "BONTEMPS-DIT-PROMENADE");
|
||||
SET_DIAL_VARIABLE(71, "BONTEMPS-ATTEND-MEMORANDUM");
|
||||
SET_DIAL_VARIABLE(72, "LENOTRE-DIT-CALME");
|
||||
SET_DIAL_VARIABLE(73, "MAINE-DIT-APOTHICAIRIE");
|
||||
SET_DIAL_VARIABLE(74, "JOUEUR-PARLE-BONTEMPS-SCENE6");
|
||||
SET_DIAL_VARIABLE(75, "{JOUEUR-ESSAYE-OUVRIR-PORTE-CHAMBRE}");
|
||||
SET_DIAL_VARIABLE(76, "{JOUEUR-TROUVE-TITRE-ET-PAMPHLET}");
|
||||
SET_DIAL_VARIABLE(77, "{JOUEUR-ESSAYE-OUVRIR-PORTE-SALON}");
|
||||
SET_DIAL_VARIABLE(78, "{JOUEUR-MONTRE-PAPIER-ECRIT-ENCRE-SYMPATHIQUE}");
|
||||
SET_DIAL_VARIABLE(79, "{JOUEUR-MONTRE-UN-PAMPHLET}");
|
||||
SET_DIAL_VARIABLE(80, "{JOUEUR-MONTRE-TOUT-AUTRE-OBJET}");
|
||||
SET_DIAL_VARIABLE(81, "{JOUEUR-MONTRE-PAMPHLET-ARTS}");
|
||||
SET_DIAL_VARIABLE(82, "{JOUEUR-A-MONTRE-ESQUISSES-NON-TRIEES-LEBRUN}");
|
||||
SET_DIAL_VARIABLE(83, "{JOUEUR-DONNE-ESQUISSES}");
|
||||
SET_DIAL_VARIABLE(84, "{JOUEUR-SE-DIRIGE-VERS-MONSEIGNEUR-AVEC-ESQUISSES}");
|
||||
SET_DIAL_VARIABLE(85, "{JOUEUR-PRESENTE-FAUX-CROQUIS3}");
|
||||
SET_DIAL_VARIABLE(86, "{JOUEUR-PRESENTE-FAUX-CROQUIS2}");
|
||||
SET_DIAL_VARIABLE(87, "{JOUEUR-PRESENTE-FAUX-CROQUIS}");
|
||||
SET_DIAL_VARIABLE(88, "{LE JOUEUR-PRESENTE-ESQUISSES-TRIEES}");
|
||||
SET_DIAL_VARIABLE(89, "{LE JOUEUR-PRESENTE-AUTRES-ESQUISSES-OU-ESQUISSE-NON-TRIEES}");
|
||||
SET_DIAL_VARIABLE(90, "{JOUEUR-PRESENTE-PAMPHLET-SUR-LEBRUN}");
|
||||
SET_DIAL_VARIABLE(91, "{JOUEUR-PRESENTE-TOUT-AUTRE-PAMPHLET-OU-LETTRE}");
|
||||
SET_DIAL_VARIABLE(92, "{JOUEUR-MONTRE-ESQUISSE-DETRUITE}");
|
||||
SET_DIAL_VARIABLE(93, "{JOUEUR-MONTRE-TITRE-FABLE-APPARU-SUR-ESQUISSE}");
|
||||
SET_DIAL_VARIABLE(94, "{JOUEUR-MONTRE-AUTORISATION-DE-BONTEMPS}");
|
||||
SET_DIAL_VARIABLE(95, "{LE JOUEUR-A-TENTE-OUVRIR-PETITE-PORTE}");
|
||||
SET_DIAL_VARIABLE(96, "{JOUEUR-POSSEDE-CLE}");
|
||||
SET_DIAL_VARIABLE(97, "{JOUEUR-PRESENTE-PAMPHLET-PARTITION}");
|
||||
SET_DIAL_VARIABLE(98, "{JOUEUR-MONTRE-PAMPHLET-DECHIFFRE-PAR-LULLY}");
|
||||
SET_DIAL_VARIABLE(99, "{JOUEUR-MONTRE-MEDAILLES-MONSIEUR}");
|
||||
SET_DIAL_VARIABLE(100, "{JOUEUR-MONTRE-PAMPHLET-ARCHITECTURE}");
|
||||
SET_DIAL_VARIABLE(101, "{JOUEUR-MONTRE-EPIGRAPHE-MEDAILLES}");
|
||||
SET_DIAL_VARIABLE(102, "{JOUEUR-MONTRE-TOUT-AUTRE-CHOSE}");
|
||||
SET_DIAL_VARIABLE(103, "{JOUEUR-POSSEDE-FUSAIN-MEDAILLES}");
|
||||
SET_DIAL_VARIABLE(104, "{JOUEUR-MONTRE-FUSAIN-MEDAILLES}");
|
||||
SET_DIAL_VARIABLE(105, "{JOUEUR-PRESENTE-OBJET-HUISSIER}");
|
||||
SET_DIAL_VARIABLE(106, "{JOUEUR-APPROCHE-MADAME-MAINTENON}");
|
||||
SET_DIAL_VARIABLE(107, "{JOUEUR-DONNE-REPAS}");
|
||||
SET_DIAL_VARIABLE(108, "{JOUEUR-TROUVE-PLANS-VAUBAN}");
|
||||
SET_DIAL_VARIABLE(109, "{JOUEUR-ALLER-BUREAU-LOUVOIS}");
|
||||
SET_DIAL_VARIABLE(110, "{JOUEUR-MONTRE-PAMPHLET-RELIGION}");
|
||||
SET_DIAL_VARIABLE(111, "{JOUEUR-MONTRE-PAMPHLET-GOUVERNEMENT}");
|
||||
SET_DIAL_VARIABLE(112, "{JOUEUR-MONTRE-PAPIER-CROISSY}");
|
||||
SET_DIAL_VARIABLE(113, "{JOUEUR-MONTRE-ECROUELLES}");
|
||||
SET_DIAL_VARIABLE(114, "{LACHAIZE-TIENT-TEXTE}");
|
||||
SET_DIAL_VARIABLE(115, "{JOUEUR-VU-PLANS-SALON-DIANE}");
|
||||
SET_DIAL_VARIABLE(116, "{JOUEUR-VU-MEMORANDUM-DANS-LUSTRE-DU-SALON-DE-LA-GUERRE}");
|
||||
SET_DIAL_VARIABLE(117, "{JOUEUR-VU-MEMORANDUM-DANS-LUSTRE-DU-SALON-APOLLON}");
|
||||
SET_DIAL_VARIABLE(118, "{JOUEUR-MONTRE-MEMORANDUM}");
|
||||
SET_DIAL_VARIABLE(119, "{JOUEUR-POSSEDE-CLEF-3-ET-4}");
|
||||
SET_DIAL_VARIABLE(120, "{JOUEUR-DONNE-SIROP-DE-ROSE}");
|
||||
SET_DIAL_VARIABLE(121, "{JOUEUR-DONNE-AUTRE-MEDICAMENT}");
|
||||
SET_DIAL_VARIABLE(122, "{DUC_MAIN_A_PARLE}");
|
||||
SET_DIAL_VARIABLE(123, "{LEVEL1_FINI}");
|
||||
SET_DIAL_VARIABLE(124, "{LEVEL2_FINI}");
|
||||
SET_DIAL_VARIABLE(125, "{LEVEL3_FINI}");
|
||||
SET_DIAL_VARIABLE(126, "{LEVEL4_FINI}");
|
||||
SET_DIAL_VARIABLE(127, "{LEVEL5_FINI}");
|
||||
SET_DIAL_VARIABLE(128, "{LEVEL6_FINI}");
|
||||
SET_DIAL_VARIABLE(129, "{LEVEL7_FINI}");
|
||||
SET_DIAL_VARIABLE(130, "{JOUEUR_POSSEDE_PAMPHLET_ARCHI}");
|
||||
SET_DIAL_VARIABLE(131, "{FAUSSE_ESQ_OK}");
|
||||
SET_DIAL_VARIABLE(132, "{CURRENT_GAME_TIME1}");
|
||||
SET_DIAL_VARIABLE(133, "{CURRENT_GAME_TIME2}");
|
||||
SET_DIAL_VARIABLE(134, "{CURRENT_GAME_TIME3}");
|
||||
SET_DIAL_VARIABLE(135, "{CURRENT_GAME_TIME4}");
|
||||
SET_DIAL_VARIABLE(136, "{CURRENT_GAME_TIME5}");
|
||||
SET_DIAL_VARIABLE(137, "{JOUEUR_POSSEDE_EPIGRAPHE}");
|
||||
#undef SET_DIAL_VARIABLE
|
||||
for (uint i = 0; i < ARRAYSIZE(kVideoSubSettings); i++) {
|
||||
const VideoSubSetting &vss = kVideoSubSettings[i];
|
||||
_dialogsMan.registerSubtitlesSettings(
|
||||
vss.videoName,
|
||||
DialogsManager::SubtitlesSettings(
|
||||
vss.textLeft, vss.textTop, vss.textRight, vss.textBottom,
|
||||
vss.drawLeft, vss.drawTop, vss.drawRight, vss.drawBottom));
|
||||
}
|
||||
}
|
||||
|
||||
void CryOmni3DEngine_Versailles::initPlacesStates() {
|
||||
_placeStates.resize(100);
|
||||
// Reset all the objects before configuring some
|
||||
for (Common::Array<PlaceState>::iterator it = _placeStates.begin(); it != _placeStates.end();
|
||||
it++) {
|
||||
// Useless because it's only a bunch of simple variables
|
||||
it->~PlaceState();
|
||||
new ((void *)it) PlaceState();
|
||||
}
|
||||
#define SET_PLACE_STATE(id, init, filter, docImage) _placeStates[id] = PlaceState(init, filter, docImage)
|
||||
#define FILTER_EVENT(level, place) &CryOmni3DEngine_Versailles::filterEventLevel ## level ## Place ## place
|
||||
#define INIT_PLACE(level, place) &CryOmni3DEngine_Versailles::initPlaceLevel ## level ## Place ## place
|
||||
if (_currentLevel == 1) {
|
||||
SET_PLACE_STATE(1, nullptr, FILTER_EVENT(1, 1), "VS22");
|
||||
SET_PLACE_STATE(2, nullptr, FILTER_EVENT(1, 2), "VS20");
|
||||
SET_PLACE_STATE(3, INIT_PLACE(1, 3), FILTER_EVENT(1, 3), "VS19");
|
||||
SET_PLACE_STATE(4, nullptr, nullptr, nullptr);
|
||||
SET_PLACE_STATE(5, nullptr, nullptr, nullptr);
|
||||
SET_PLACE_STATE(6, nullptr, nullptr, nullptr);
|
||||
SET_PLACE_STATE(7, nullptr, nullptr, nullptr); // Filter is a leftover
|
||||
// WORKAROUND: Missing VS21
|
||||
SET_PLACE_STATE(8, nullptr, nullptr, "VS21");
|
||||
SET_PLACE_STATE(9, nullptr, nullptr, nullptr);
|
||||
SET_PLACE_STATE(10, nullptr, nullptr, "VS31");
|
||||
SET_PLACE_STATE(11, nullptr, nullptr, "VS31");
|
||||
SET_PLACE_STATE(12, nullptr, nullptr, nullptr);
|
||||
SET_PLACE_STATE(13, nullptr, nullptr, "VS31");
|
||||
SET_PLACE_STATE(14, nullptr, FILTER_EVENT(1, 14), nullptr);
|
||||
} else if (_currentLevel == 2) {
|
||||
SET_PLACE_STATE(1, nullptr, FILTER_EVENT(2, 1), "VS22");
|
||||
SET_PLACE_STATE(2, nullptr, FILTER_EVENT(2, 2), "VS20");
|
||||
SET_PLACE_STATE(3, nullptr, nullptr, "VS19");
|
||||
SET_PLACE_STATE(4, nullptr, nullptr, "VS18");
|
||||
SET_PLACE_STATE(5, nullptr, FILTER_EVENT(2, 5), nullptr);
|
||||
SET_PLACE_STATE(6, nullptr, nullptr, "VS19");
|
||||
SET_PLACE_STATE(7, nullptr, nullptr, nullptr);
|
||||
// WORKAROUND: Missing VS21
|
||||
SET_PLACE_STATE(8, nullptr, nullptr, "VS21");
|
||||
SET_PLACE_STATE(9, INIT_PLACE(2, 9), FILTER_EVENT(2, 9), "VS23");
|
||||
SET_PLACE_STATE(10, nullptr, nullptr, "VS31");
|
||||
SET_PLACE_STATE(11, nullptr, FILTER_EVENT(2, 11), "VS31");
|
||||
SET_PLACE_STATE(12, nullptr, FILTER_EVENT(2, 12), "VS24");
|
||||
SET_PLACE_STATE(13, nullptr, nullptr, "VS31");
|
||||
SET_PLACE_STATE(14, nullptr, FILTER_EVENT(2, 14), nullptr);
|
||||
} else if (_currentLevel == 3) {
|
||||
SET_PLACE_STATE(1, nullptr, nullptr, "VS35");
|
||||
SET_PLACE_STATE(2, nullptr, nullptr, "VS40");
|
||||
SET_PLACE_STATE(3, nullptr, FILTER_EVENT(3, 3), "VS40");
|
||||
SET_PLACE_STATE(4, nullptr, nullptr, "VS36");
|
||||
SET_PLACE_STATE(5, nullptr, nullptr, "VS36");
|
||||
SET_PLACE_STATE(6, nullptr, nullptr, "VS30");
|
||||
SET_PLACE_STATE(7, nullptr, nullptr, "VS30");
|
||||
SET_PLACE_STATE(8, nullptr, nullptr, "VS30");
|
||||
SET_PLACE_STATE(9, nullptr, nullptr, "VS39");
|
||||
SET_PLACE_STATE(10, nullptr, FILTER_EVENT(3, 10), "VS28");
|
||||
SET_PLACE_STATE(11, nullptr, nullptr, "VS28");
|
||||
SET_PLACE_STATE(12, nullptr, nullptr, "VS30");
|
||||
SET_PLACE_STATE(13, nullptr, FILTER_EVENT(3, 13), "VS27");
|
||||
SET_PLACE_STATE(14, nullptr, nullptr, "VS26");
|
||||
SET_PLACE_STATE(15, nullptr, FILTER_EVENT(3, 15), "VS25");
|
||||
SET_PLACE_STATE(16, nullptr, nullptr, "VS24");
|
||||
SET_PLACE_STATE(17, nullptr, FILTER_EVENT(3, 17), "VS25");
|
||||
SET_PLACE_STATE(18, nullptr, FILTER_EVENT(3, 18), nullptr);
|
||||
SET_PLACE_STATE(19, nullptr, FILTER_EVENT(3, 19), "VS26");
|
||||
SET_PLACE_STATE(20, nullptr, FILTER_EVENT(3_5, 20), nullptr);
|
||||
SET_PLACE_STATE(21, nullptr, nullptr, "VS28");
|
||||
SET_PLACE_STATE(22, nullptr, FILTER_EVENT(3, 22), "VS26");
|
||||
SET_PLACE_STATE(23, nullptr, FILTER_EVENT(3, 23), nullptr);
|
||||
SET_PLACE_STATE(24, nullptr, nullptr, "VS30");
|
||||
} else if (_currentLevel == 4) {
|
||||
SET_PLACE_STATE(1, nullptr, nullptr, "VS35");
|
||||
SET_PLACE_STATE(2, nullptr, nullptr, "VS40");
|
||||
SET_PLACE_STATE(3, nullptr, nullptr, "VS40");
|
||||
SET_PLACE_STATE(4, nullptr, nullptr, "VS36");
|
||||
SET_PLACE_STATE(5, nullptr, nullptr, nullptr);
|
||||
SET_PLACE_STATE(6, nullptr, nullptr, nullptr);
|
||||
SET_PLACE_STATE(7, nullptr, nullptr, "VS17");
|
||||
SET_PLACE_STATE(8, nullptr, nullptr, "VS17");
|
||||
SET_PLACE_STATE(9, INIT_PLACE(4, 9), nullptr, nullptr);
|
||||
SET_PLACE_STATE(10, nullptr, FILTER_EVENT(4, 10), "VS18");
|
||||
SET_PLACE_STATE(11, nullptr, nullptr, "VS20");
|
||||
SET_PLACE_STATE(12, nullptr, FILTER_EVENT(4, 12_13_14), "VS31");
|
||||
SET_PLACE_STATE(13, nullptr, FILTER_EVENT(4, 12_13_14), "VS31");
|
||||
SET_PLACE_STATE(14, nullptr, FILTER_EVENT(4, 12_13_14), "VS31");
|
||||
SET_PLACE_STATE(15, nullptr, FILTER_EVENT(4, 15), "VS36");
|
||||
SET_PLACE_STATE(16, nullptr, FILTER_EVENT(4, 16), nullptr);
|
||||
SET_PLACE_STATE(17, nullptr, FILTER_EVENT(4, 17), nullptr);
|
||||
} else if (_currentLevel == 5) {
|
||||
SET_PLACE_STATE(1, nullptr, nullptr, "VS35");
|
||||
SET_PLACE_STATE(2, nullptr, nullptr, "VS35");
|
||||
SET_PLACE_STATE(3, nullptr, nullptr, "VS36");
|
||||
SET_PLACE_STATE(4, nullptr, nullptr, "VS36");
|
||||
SET_PLACE_STATE(5, nullptr, nullptr, "VS36");
|
||||
SET_PLACE_STATE(6, INIT_PLACE(5, 6), nullptr, "VS30");
|
||||
SET_PLACE_STATE(7, nullptr, nullptr, "VS30");
|
||||
SET_PLACE_STATE(8, nullptr, nullptr, "VS30");
|
||||
SET_PLACE_STATE(9, nullptr, FILTER_EVENT(5, 9), "VS39");
|
||||
SET_PLACE_STATE(10, nullptr, nullptr, "VS28");
|
||||
SET_PLACE_STATE(11, nullptr, nullptr, "VS16");
|
||||
SET_PLACE_STATE(12, nullptr, nullptr, "VS30");
|
||||
SET_PLACE_STATE(13, nullptr, nullptr, "VS27");
|
||||
SET_PLACE_STATE(14, nullptr, FILTER_EVENT(5, 14), "VS26");
|
||||
SET_PLACE_STATE(15, nullptr, FILTER_EVENT(5, 15), "VS25");
|
||||
SET_PLACE_STATE(16, nullptr, FILTER_EVENT(5, 16), "VS24");
|
||||
SET_PLACE_STATE(17, nullptr, nullptr, "VS25");
|
||||
SET_PLACE_STATE(18, nullptr, nullptr, nullptr);
|
||||
SET_PLACE_STATE(19, nullptr, nullptr, nullptr);
|
||||
SET_PLACE_STATE(20, nullptr, FILTER_EVENT(3_5, 20), nullptr);
|
||||
SET_PLACE_STATE(21, nullptr, nullptr, "VS28");
|
||||
SET_PLACE_STATE(22, nullptr, nullptr, nullptr);
|
||||
SET_PLACE_STATE(23, nullptr, FILTER_EVENT(5, 23), nullptr);
|
||||
SET_PLACE_STATE(24, nullptr, nullptr, nullptr);
|
||||
SET_PLACE_STATE(25, nullptr, nullptr, nullptr);
|
||||
SET_PLACE_STATE(26, nullptr, nullptr, "VS16");
|
||||
SET_PLACE_STATE(27, nullptr, FILTER_EVENT(5, 27), "VS16");
|
||||
SET_PLACE_STATE(28, nullptr, FILTER_EVENT(5, 28), nullptr);
|
||||
SET_PLACE_STATE(29, nullptr, FILTER_EVENT(5, 29), "VS24");
|
||||
SET_PLACE_STATE(30, nullptr, nullptr, nullptr);
|
||||
SET_PLACE_STATE(31, nullptr, nullptr, nullptr);
|
||||
SET_PLACE_STATE(32, nullptr, nullptr, nullptr);
|
||||
SET_PLACE_STATE(33, nullptr, FILTER_EVENT(5, 33), nullptr);
|
||||
SET_PLACE_STATE(34, nullptr, FILTER_EVENT(5, 34), nullptr);
|
||||
} else if (_currentLevel == 6) {
|
||||
SET_PLACE_STATE(1, nullptr, FILTER_EVENT(6, 1), "VS34");
|
||||
SET_PLACE_STATE(2, nullptr, FILTER_EVENT(6, Orangery), "VS32");
|
||||
SET_PLACE_STATE(3, nullptr, FILTER_EVENT(6, 3), "VS32");
|
||||
SET_PLACE_STATE(4, nullptr, FILTER_EVENT(6, Orangery), "VS32");
|
||||
SET_PLACE_STATE(5, nullptr, FILTER_EVENT(6, Orangery), "VS32");
|
||||
SET_PLACE_STATE(6, nullptr, FILTER_EVENT(6, Orangery), "VS32");
|
||||
SET_PLACE_STATE(7, nullptr, FILTER_EVENT(6, Orangery), "VS32");
|
||||
SET_PLACE_STATE(8, nullptr, FILTER_EVENT(6, Orangery), "VS32");
|
||||
SET_PLACE_STATE(9, nullptr, FILTER_EVENT(6, Orangery), "VS32");
|
||||
SET_PLACE_STATE(10, nullptr, FILTER_EVENT(6, Orangery), "VS32");
|
||||
SET_PLACE_STATE(11, nullptr, FILTER_EVENT(6, Orangery), "VS32");
|
||||
SET_PLACE_STATE(12, nullptr, FILTER_EVENT(6, Orangery), "VS32");
|
||||
SET_PLACE_STATE(13, nullptr, nullptr, "VS33");
|
||||
SET_PLACE_STATE(14, nullptr, nullptr, "VS33"); // Filter is a leftover
|
||||
SET_PLACE_STATE(15, nullptr, nullptr, "VS33");
|
||||
SET_PLACE_STATE(16, nullptr, nullptr, "VS33");
|
||||
SET_PLACE_STATE(17, nullptr, nullptr, "VS33");
|
||||
SET_PLACE_STATE(18, nullptr, nullptr, "VS33");
|
||||
SET_PLACE_STATE(19, nullptr, FILTER_EVENT(6, 19), "VS33");
|
||||
SET_PLACE_STATE(20, nullptr, nullptr, "VS33");
|
||||
SET_PLACE_STATE(21, nullptr, nullptr, "VS33");
|
||||
SET_PLACE_STATE(22, nullptr, nullptr, "VS33");
|
||||
SET_PLACE_STATE(23, nullptr, nullptr, "VS33");
|
||||
SET_PLACE_STATE(24, nullptr, nullptr, "VS33");
|
||||
SET_PLACE_STATE(25, nullptr, nullptr, "VS33");
|
||||
SET_PLACE_STATE(26, nullptr, nullptr, "VS33");
|
||||
SET_PLACE_STATE(27, nullptr, nullptr, "VS33");
|
||||
SET_PLACE_STATE(28, nullptr, nullptr, "VS33");
|
||||
SET_PLACE_STATE(29, nullptr, nullptr, "VS33");
|
||||
SET_PLACE_STATE(30, nullptr, nullptr, "VS33");
|
||||
SET_PLACE_STATE(31, nullptr, nullptr, "VS33");
|
||||
SET_PLACE_STATE(32, nullptr, nullptr, "VS33");
|
||||
SET_PLACE_STATE(33, nullptr, nullptr, "VS33");
|
||||
SET_PLACE_STATE(34, nullptr, nullptr, "VS33");
|
||||
SET_PLACE_STATE(35, nullptr, nullptr, "VS33");
|
||||
SET_PLACE_STATE(36, nullptr, nullptr, "VS33");
|
||||
SET_PLACE_STATE(37, nullptr, nullptr, "VS33");
|
||||
SET_PLACE_STATE(38, nullptr, nullptr, "VS33");
|
||||
SET_PLACE_STATE(39, nullptr, nullptr, "VS33");
|
||||
SET_PLACE_STATE(40, nullptr, nullptr, "VS33");
|
||||
SET_PLACE_STATE(41, nullptr, nullptr, "VS33");
|
||||
SET_PLACE_STATE(42, nullptr, nullptr, "VS33");
|
||||
SET_PLACE_STATE(43, nullptr, nullptr, "VS33");
|
||||
SET_PLACE_STATE(44, nullptr, nullptr, "VS33");
|
||||
} else if (_currentLevel == 7) {
|
||||
SET_PLACE_STATE(1, nullptr, nullptr, nullptr);
|
||||
SET_PLACE_STATE(2, nullptr, FILTER_EVENT(7, 2), nullptr);
|
||||
SET_PLACE_STATE(3, nullptr, nullptr, nullptr);
|
||||
SET_PLACE_STATE(4, nullptr, nullptr, nullptr);
|
||||
SET_PLACE_STATE(5, nullptr, nullptr, nullptr);
|
||||
SET_PLACE_STATE(6, nullptr, nullptr, nullptr);
|
||||
SET_PLACE_STATE(7, nullptr, nullptr, nullptr); // Filter is a leftover
|
||||
SET_PLACE_STATE(8, nullptr, nullptr, nullptr);
|
||||
SET_PLACE_STATE(9, nullptr, FILTER_EVENT(7, 9), nullptr);
|
||||
SET_PLACE_STATE(10, nullptr, FILTER_EVENT(7, 10_11_13), "VS31");
|
||||
SET_PLACE_STATE(11, nullptr, FILTER_EVENT(7, 10_11_13), "VS31");
|
||||
SET_PLACE_STATE(12, nullptr, nullptr, nullptr);
|
||||
SET_PLACE_STATE(13, nullptr, FILTER_EVENT(7, 10_11_13), "VS31");
|
||||
SET_PLACE_STATE(14, nullptr, nullptr, nullptr);
|
||||
SET_PLACE_STATE(15, nullptr, nullptr, nullptr);
|
||||
SET_PLACE_STATE(16, nullptr, nullptr, nullptr);
|
||||
SET_PLACE_STATE(17, nullptr, nullptr, nullptr);
|
||||
SET_PLACE_STATE(18, nullptr, nullptr, nullptr);
|
||||
SET_PLACE_STATE(19, nullptr, nullptr, nullptr);
|
||||
SET_PLACE_STATE(20, nullptr, FILTER_EVENT(7, 20), nullptr);
|
||||
SET_PLACE_STATE(21, nullptr, nullptr, nullptr);
|
||||
SET_PLACE_STATE(22, nullptr, nullptr, nullptr);
|
||||
SET_PLACE_STATE(23, nullptr, nullptr, nullptr);
|
||||
SET_PLACE_STATE(24, nullptr, nullptr, nullptr);
|
||||
SET_PLACE_STATE(25, nullptr, nullptr, nullptr);
|
||||
SET_PLACE_STATE(26, nullptr, nullptr, nullptr);
|
||||
SET_PLACE_STATE(27, nullptr, nullptr, nullptr);
|
||||
SET_PLACE_STATE(28, nullptr, nullptr, nullptr);
|
||||
SET_PLACE_STATE(29, nullptr, nullptr, nullptr);
|
||||
} else if (_currentLevel == 8) {
|
||||
SET_PLACE_STATE(1, nullptr, nullptr, "VS35");
|
||||
SET_PLACE_STATE(2, nullptr, nullptr, "VS40");
|
||||
SET_PLACE_STATE(3, nullptr, nullptr, "VS40");
|
||||
SET_PLACE_STATE(4, nullptr, nullptr, "VS36");
|
||||
SET_PLACE_STATE(5, nullptr, nullptr, nullptr);
|
||||
// WORKAROUND: Missing VS30
|
||||
SET_PLACE_STATE(6, nullptr, nullptr, "VS30");
|
||||
SET_PLACE_STATE(7, nullptr, nullptr, "VS30");
|
||||
SET_PLACE_STATE(8, nullptr, nullptr, "VS30");
|
||||
SET_PLACE_STATE(9, nullptr, nullptr, "VS39");
|
||||
SET_PLACE_STATE(10, nullptr, nullptr, "VS28");
|
||||
SET_PLACE_STATE(11, nullptr, nullptr, "VS16");
|
||||
SET_PLACE_STATE(12, nullptr, nullptr, "VS30");
|
||||
SET_PLACE_STATE(13, nullptr, nullptr, "VS27");
|
||||
SET_PLACE_STATE(14, nullptr, nullptr, "VS26");
|
||||
SET_PLACE_STATE(15, nullptr, nullptr, "VS25");
|
||||
SET_PLACE_STATE(16, nullptr, nullptr, "VS24");
|
||||
SET_PLACE_STATE(17, nullptr, nullptr, nullptr);
|
||||
SET_PLACE_STATE(18, nullptr, nullptr, nullptr);
|
||||
SET_PLACE_STATE(19, nullptr, nullptr, nullptr);
|
||||
SET_PLACE_STATE(20, nullptr, nullptr, nullptr);
|
||||
SET_PLACE_STATE(21, nullptr, nullptr, nullptr);
|
||||
SET_PLACE_STATE(22, nullptr, nullptr, nullptr);
|
||||
SET_PLACE_STATE(23, nullptr, nullptr, nullptr);
|
||||
SET_PLACE_STATE(24, nullptr, nullptr, "VS30");
|
||||
SET_PLACE_STATE(25, nullptr, nullptr, nullptr);
|
||||
SET_PLACE_STATE(26, nullptr, nullptr, nullptr);
|
||||
SET_PLACE_STATE(27, nullptr, nullptr, nullptr);
|
||||
SET_PLACE_STATE(28, nullptr, nullptr, nullptr);
|
||||
SET_PLACE_STATE(29, nullptr, nullptr, nullptr);
|
||||
SET_PLACE_STATE(30, nullptr, nullptr, nullptr);
|
||||
SET_PLACE_STATE(31, nullptr, nullptr, nullptr);
|
||||
SET_PLACE_STATE(32, nullptr, nullptr, nullptr);
|
||||
SET_PLACE_STATE(33, nullptr, nullptr, "VS31");
|
||||
SET_PLACE_STATE(34, nullptr, nullptr, "VS31");
|
||||
SET_PLACE_STATE(35, nullptr, nullptr, "VS31");
|
||||
SET_PLACE_STATE(36, nullptr, nullptr, "VS23");
|
||||
SET_PLACE_STATE(37, nullptr, nullptr, "VS22");
|
||||
SET_PLACE_STATE(38, nullptr, nullptr, "VS20");
|
||||
// WORKAROUND: In original game VS19 is in 49 and should be in 39
|
||||
SET_PLACE_STATE(39, nullptr, nullptr, "VS19");
|
||||
SET_PLACE_STATE(40, nullptr, nullptr, "VS18");
|
||||
SET_PLACE_STATE(41, nullptr, nullptr, nullptr);
|
||||
SET_PLACE_STATE(42, nullptr, nullptr, "VS17");
|
||||
SET_PLACE_STATE(43, nullptr, nullptr, "VS17");
|
||||
SET_PLACE_STATE(44, nullptr, nullptr, nullptr);
|
||||
SET_PLACE_STATE(45, nullptr, nullptr, nullptr);
|
||||
SET_PLACE_STATE(46, nullptr, nullptr, nullptr);
|
||||
SET_PLACE_STATE(47, nullptr, nullptr, nullptr);
|
||||
SET_PLACE_STATE(48, nullptr, nullptr, nullptr);
|
||||
SET_PLACE_STATE(49, nullptr, nullptr, nullptr);
|
||||
}
|
||||
#undef INIT_PLACE
|
||||
#undef FILTER_EVENT
|
||||
#undef SET_PLACE_STATE
|
||||
}
|
||||
|
||||
void CryOmni3DEngine_Versailles::setupLevelActionsMask() {
|
||||
_actionMasks.clear();
|
||||
#define SET_MASK(placeId, placeState, oldActionId, newActionId) _actionMasks[PlaceStateActionKey(placeId, placeState, oldActionId)] = newActionId
|
||||
if (_currentLevel == 1) {
|
||||
SET_MASK(1, 0, 11015, 0);
|
||||
SET_MASK(1, 0, 21015, 0);
|
||||
SET_MASK(1, 1, 21011, 0);
|
||||
SET_MASK(1, 1, 21012, 0);
|
||||
SET_MASK(1, 1, 21013, 0);
|
||||
SET_MASK(1, 1, 21014, 0);
|
||||
// 2, 0 is empty
|
||||
SET_MASK(2, 1, 51201, 0);
|
||||
SET_MASK(2, 1, 21202, 0);
|
||||
SET_MASK(2, 1, 21203, 0);
|
||||
SET_MASK(2, 2, 51201, 0);
|
||||
SET_MASK(2, 2, 21202, 0);
|
||||
SET_MASK(2, 2, 21203, 0);
|
||||
SET_MASK(2, 2, 11201, 1);
|
||||
SET_MASK(2, 2, 21201, 1);
|
||||
// 3, 0 is empty
|
||||
SET_MASK(3, 1, 11301, 0);
|
||||
SET_MASK(3, 1, 21301, 0);
|
||||
// 14, 0 is empty
|
||||
SET_MASK(14, 1, 31141, 0);
|
||||
} else if (_currentLevel == 2) {
|
||||
// 1, 0 is empty
|
||||
SET_MASK(1, 1, 12101, 0);
|
||||
SET_MASK(1, 1, 22101, 0);
|
||||
SET_MASK(11, 0, 12111, 0);
|
||||
SET_MASK(11, 0, 22111, 0);
|
||||
// 11, 1 is empty
|
||||
// 9, 0 is empty
|
||||
SET_MASK(9, 1, 52903, 0);
|
||||
SET_MASK(9, 1, 22903, 0);
|
||||
SET_MASK(9, 1, 52902, 12902);
|
||||
SET_MASK(9, 2, 52903, 0);
|
||||
SET_MASK(9, 2, 22903, 0);
|
||||
SET_MASK(9, 2, 52902, 0);
|
||||
SET_MASK(9, 2, 22902, 0);
|
||||
} else if (_currentLevel == 3) {
|
||||
SET_MASK(13, 0, 13131, 0);
|
||||
SET_MASK(13, 0, 23131, 0);
|
||||
SET_MASK(13, 1, 13131, 0);
|
||||
SET_MASK(13, 1, 23131, 0);
|
||||
SET_MASK(13, 1, 33130, 0);
|
||||
// 13, 2 is empty
|
||||
SET_MASK(13, 3, 33130, 0);
|
||||
// 14, 0 is empty
|
||||
SET_MASK(14, 1, 23220, 0);
|
||||
SET_MASK(15, 0, 13151, 43154);
|
||||
SET_MASK(15, 0, 23151, 0);
|
||||
// 15, 1 is empty
|
||||
SET_MASK(17, 0, 13151, 0);
|
||||
SET_MASK(17, 0, 23151, 0);
|
||||
// 17, 1 is empty
|
||||
// 16, 0 is empty
|
||||
SET_MASK(16, 1, 43160, 0);
|
||||
// 19, 0 is empty
|
||||
SET_MASK(19, 1, 43190, 0);
|
||||
SET_MASK(22, 0, 33220, 0);
|
||||
SET_MASK(22, 1, 13220, 0);
|
||||
SET_MASK(22, 1, 23220, 0);
|
||||
SET_MASK(22, 2, 13220, 0);
|
||||
SET_MASK(22, 2, 23220, 0);
|
||||
SET_MASK(22, 2, 33220, 0);
|
||||
} else if (_currentLevel == 4) {
|
||||
// 16, 0 is empty
|
||||
SET_MASK(16, 1, 14161, 0);
|
||||
SET_MASK(16, 1, 24161, 0);
|
||||
SET_MASK(16, 2, 14161, 0);
|
||||
SET_MASK(16, 2, 24161, 0);
|
||||
// 17, 0 is empty
|
||||
SET_MASK(17, 1, 34171, 0);
|
||||
// 7, 0 is empty
|
||||
SET_MASK(7, 1, 24081, 0);
|
||||
SET_MASK(7, 1, 44071, 0);
|
||||
// 8, 0 is empty
|
||||
SET_MASK(8, 1, 24081, 0);
|
||||
SET_MASK(9, 0, 54091, 0);
|
||||
SET_MASK(9, 0, 14091, 0);
|
||||
SET_MASK(9, 0, 24092, 0);
|
||||
SET_MASK(9, 0, 24091, 0);
|
||||
SET_MASK(9, 1, 14091, 54091);
|
||||
SET_MASK(9, 2, 54091, 24091);
|
||||
SET_MASK(10, 0, 14105, 0);
|
||||
SET_MASK(10, 0, 24105, 0);
|
||||
SET_MASK(10, 0, 24106, 0);
|
||||
SET_MASK(10, 0, 24107, 0);
|
||||
SET_MASK(10, 0, 54106, 0);
|
||||
//SET_MASK(10, 0, 54106, 0);
|
||||
SET_MASK(10, 1, 24106, 0);
|
||||
SET_MASK(10, 1, 24107, 0);
|
||||
SET_MASK(10, 1, 54106, 0);
|
||||
//SET_MASK(10, 1, 54106, 0);
|
||||
SET_MASK(10, 2, 14104, 24104);
|
||||
} else if (_currentLevel == 5) {
|
||||
SET_MASK(27, 0, 15270, 0);
|
||||
SET_MASK(27, 0, 25270, 0);
|
||||
SET_MASK(27, 1, 15270, 0);
|
||||
SET_MASK(27, 1, 25270, 0);
|
||||
SET_MASK(27, 1, 35270, 0);
|
||||
SET_MASK(27, 2, 35270, 0);
|
||||
SET_MASK(9, 0, 15090, 0);
|
||||
SET_MASK(9, 0, 25090, 0);
|
||||
// 9, 1 is empty
|
||||
// 13, 0 is empty
|
||||
SET_MASK(13, 1, 25130, 0);
|
||||
SET_MASK(13, 1, 25131, 0);
|
||||
SET_MASK(13, 1, 55130, 0);
|
||||
SET_MASK(13, 1, 55131, 0);
|
||||
SET_MASK(16, 0, 28, 0);
|
||||
SET_MASK(16, 0, 35162, 0);
|
||||
SET_MASK(16, 1, 28, 0);
|
||||
SET_MASK(16, 1, 35162, 0);
|
||||
SET_MASK(16, 1, 25160, 0);
|
||||
SET_MASK(16, 1, 35161, 0);
|
||||
SET_MASK(16, 2, 28, 0);
|
||||
SET_MASK(16, 2, 35162, 0);
|
||||
SET_MASK(16, 2, 25160, 0);
|
||||
SET_MASK(16, 3, 35162, 28);
|
||||
SET_MASK(16, 3, 25160, 0);
|
||||
SET_MASK(16, 3, 35161, 0);
|
||||
SET_MASK(16, 3, 35160, 0);
|
||||
SET_MASK(16, 4, 35162, 28);
|
||||
SET_MASK(16, 4, 25160, 0);
|
||||
SET_MASK(16, 5, 25160, 0);
|
||||
SET_MASK(16, 5, 35160, 0);
|
||||
SET_MASK(16, 6, 35162, 28);
|
||||
SET_MASK(16, 6, 25160, 0);
|
||||
SET_MASK(16, 6, 35161, 0);
|
||||
SET_MASK(16, 6, 35160, 0);
|
||||
// 29, 0 is empty
|
||||
SET_MASK(29, 1, 35290, 0);
|
||||
SET_MASK(15, 0, 15090, 43154);
|
||||
SET_MASK(15, 0, 25090, 0);
|
||||
// 15, 1 is empty
|
||||
SET_MASK(17, 0, 15090, 0);
|
||||
SET_MASK(17, 0, 25090, 0);
|
||||
// 17, 1 is empty
|
||||
// 33, 0 is empty
|
||||
SET_MASK(33, 1, 35330, 0);
|
||||
} else if (_currentLevel == 6) {
|
||||
// 1, 0 is empty
|
||||
SET_MASK(1, 1, 36010, 0);
|
||||
// 3, 0 is empty
|
||||
SET_MASK(3, 1, 36030, 0);
|
||||
SET_MASK(14, 0, 26140, 0);
|
||||
SET_MASK(14, 0, 16140, 0);
|
||||
// 14, 1 is empty
|
||||
SET_MASK(19, 0, 36190, 0);
|
||||
SET_MASK(19, 1, 16190, 0);
|
||||
SET_MASK(19, 1, 26190, 0);
|
||||
SET_MASK(19, 2, 36190, 0);
|
||||
SET_MASK(19, 2, 16190, 0);
|
||||
SET_MASK(19, 2, 26190, 0);
|
||||
} else if (_currentLevel == 7) {
|
||||
// 9, 0 is empty
|
||||
SET_MASK(9, 1, 37090, 0);
|
||||
} else if (_currentLevel == 8) {
|
||||
// Nothing to mask
|
||||
} else {
|
||||
error("Invalid level");
|
||||
}
|
||||
#undef SET_MASK
|
||||
}
|
||||
|
||||
void CryOmni3DEngine_Versailles::initWhoSpeaksWhere() {
|
||||
_whoSpeaksWhere.clear();
|
||||
#define SET_WHO(placeId, actionId, dialog) _whoSpeaksWhere[PlaceActionKey(placeId, actionId)] = dialog
|
||||
if (_currentLevel == 1) {
|
||||
SET_WHO(1, 11015, "13F_HUI");
|
||||
SET_WHO(1, 12101, "21F_BON");
|
||||
SET_WHO(1, 52903, "21G_DAU");
|
||||
SET_WHO(1, 52902, "21G_DAU");
|
||||
SET_WHO(2, 11201, "11E_HUI");
|
||||
SET_WHO(2, 51201, "11E_RAC");
|
||||
SET_WHO(3, 11301, "11D_LEB");
|
||||
SET_WHO(5, 12501, "21B1_HUI");
|
||||
if (currentGameTime() >= 2) {
|
||||
SET_WHO(2, 11201, "12E_HUI");
|
||||
}
|
||||
} else if (_currentLevel == 2) {
|
||||
SET_WHO(1, 12101, "21F_BON");
|
||||
SET_WHO(9, 52903, "21G_DAU");
|
||||
SET_WHO(9, 52902, "21G_DAU");
|
||||
SET_WHO(9, 12902, "22G_DAU");
|
||||
SET_WHO(9, 11201, "11E_HUI");
|
||||
SET_WHO(9, 12901, "21G_HUI");
|
||||
SET_WHO(5, 12501, "21B1_HUI");
|
||||
SET_WHO(10, 12130, "21Z_ALI");
|
||||
SET_WHO(10, 12130, "21Z_MON");
|
||||
SET_WHO(10, 12111, "24Z_BON");
|
||||
SET_WHO(11, 12130, "21Z_MON");
|
||||
SET_WHO(11, 12111, "24Z_BON");
|
||||
SET_WHO(13, 12130, "21Z_ALI");
|
||||
SET_WHO(13, 12130, "21Z_MON");
|
||||
SET_WHO(13, 12111, "24Z_BON");
|
||||
SET_WHO(12, 12121, "23I_LEB");
|
||||
SET_WHO(10, 52130, "21Z_ALI");
|
||||
SET_WHO(11, 52130, "21Z_ALI");
|
||||
SET_WHO(13, 52130, "21Z_ALI");
|
||||
SET_WHO(10, 52101, "21Z_MON");
|
||||
if (currentGameTime() >= 2) {
|
||||
SET_WHO(9, 52902, "22G_DAU");
|
||||
}
|
||||
} else if (_currentLevel == 3) {
|
||||
SET_WHO(13, 13130, "31M_SUI");
|
||||
SET_WHO(13, 13131, "32M_MR");
|
||||
SET_WHO(10, 13100, "31O_SUIA");
|
||||
SET_WHO(10, 13101, "31O_SUIP");
|
||||
SET_WHO(22, 13220, "31L1_LUL");
|
||||
SET_WHO(6, 13060, "31Q_SUI");
|
||||
SET_WHO(15, 13150, "31J_SUI");
|
||||
SET_WHO(17, 13150, "31J_SUI");
|
||||
SET_WHO(3, 13030, "31X_BON");
|
||||
SET_WHO(24, 53240, "32Q_MON");
|
||||
SET_WHO(24, 13241, "32Q_RAC2");
|
||||
SET_WHO(4, 53041, "31X_SEI");
|
||||
SET_WHO(4, 53040, "31X_LOU");
|
||||
SET_WHO(15, 13151, "32J_CRO");
|
||||
SET_WHO(17, 13151, "32J_CRO");
|
||||
} else if (_currentLevel == 4) {
|
||||
SET_WHO(10, 14104, "41C_HUI");
|
||||
SET_WHO(10, 14105, "42C_BON");
|
||||
SET_WHO(16, 14161, "41X2_CRO");
|
||||
SET_WHO(10, 54106, "43C_CON");
|
||||
SET_WHO(10, 54106, "43C_DUR");
|
||||
SET_WHO(9, 54091, "43B1_SEI");
|
||||
SET_WHO(9, 14091, "43B1_SEI");
|
||||
if (currentGameTime() >= 4) {
|
||||
SET_WHO(9, 54091, "4_MAI");
|
||||
SET_WHO(9, 14091, "4_MAI");
|
||||
}
|
||||
} else if (_currentLevel == 5) {
|
||||
SET_WHO(27, 15270, "52A4_LAC");
|
||||
SET_WHO(9, 15090, "53N_BON");
|
||||
SET_WHO(13, 55130, "51M_MAN");
|
||||
SET_WHO(13, 55131, "51M_MAN");
|
||||
SET_WHO(14, 55140, "52L_LOU");
|
||||
SET_WHO(14, 55140, "52L_PRI");
|
||||
SET_WHO(14, 15142, "52L_BOU");
|
||||
SET_WHO(13, 13130, "53M_SUI");
|
||||
if (currentGameTime() >= 4) {
|
||||
SET_WHO(9, 15090, "54I_BON");
|
||||
}
|
||||
} else if (_currentLevel == 6) {
|
||||
SET_WHO(9, 16090, "61_LEN");
|
||||
SET_WHO(19, 16190, "61_DUC");
|
||||
SET_WHO(14, 16140, "61_BON");
|
||||
if (_gameVariables[GameVariables::kMaineTalked] == 1) {
|
||||
SET_WHO(19, 16190, "62_DUC");
|
||||
}
|
||||
}
|
||||
#undef SET_WHO
|
||||
}
|
||||
|
||||
void CryOmni3DEngine_Versailles::initDocPeopleRecord() {
|
||||
_docPeopleRecord.clear();
|
||||
#define SET_INFO(actionId, record) _docPeopleRecord[actionId] = record
|
||||
SET_INFO(22501, "VC25");
|
||||
SET_INFO(22401, "VC19");
|
||||
SET_INFO(22402, "VC24");
|
||||
SET_INFO(22403, "VC24");
|
||||
SET_INFO(22404, "VC24");
|
||||
SET_INFO(22405, "VC24");
|
||||
SET_INFO(22406, "VC24");
|
||||
SET_INFO(22407, "VC24");
|
||||
SET_INFO(22408, "VC24");
|
||||
SET_INFO(21201, "VC25");
|
||||
SET_INFO(21202, "VS12");
|
||||
SET_INFO(21203, "VA13");
|
||||
SET_INFO(21011, "VC13");
|
||||
SET_INFO(21012, "VC11");
|
||||
SET_INFO(21013, "VC10");
|
||||
SET_INFO(21014, "VC18");
|
||||
SET_INFO(22901, "VC25");
|
||||
SET_INFO(21015, "VC25");
|
||||
SET_INFO(22101, "VC18");
|
||||
SET_INFO(22903, "VC12");
|
||||
SET_INFO(22902, "VC10");
|
||||
SET_INFO(22131, "VC16");
|
||||
SET_INFO(22111, "VC18");
|
||||
SET_INFO(21301, "VA12");
|
||||
SET_INFO(22121, "VA12");
|
||||
SET_INFO(22103, "VC20");
|
||||
SET_INFO(22102, "VC15");
|
||||
SET_INFO(23100, "VC23");
|
||||
SET_INFO(23101, "VC23");
|
||||
SET_INFO(23130, "VC23");
|
||||
SET_INFO(23060, "VC23");
|
||||
SET_INFO(23150, "VC23");
|
||||
SET_INFO(23220, "VA11");
|
||||
SET_INFO(23131, "VC11");
|
||||
SET_INFO(23241, "VA13");
|
||||
SET_INFO(23151, "VR12");
|
||||
SET_INFO(23030, "VC18");
|
||||
SET_INFO(23040, "VR11");
|
||||
SET_INFO(23041, "VR13");
|
||||
SET_INFO(23240, "VC15");
|
||||
SET_INFO(24104, "VC25");
|
||||
SET_INFO(24105, "VC18");
|
||||
SET_INFO(24106, "VC12");
|
||||
SET_INFO(24107, "VC19");
|
||||
SET_INFO(24102, "VC21");
|
||||
SET_INFO(24103, "VC21");
|
||||
SET_INFO(24081, "VC21");
|
||||
SET_INFO(24101, "VC24");
|
||||
SET_INFO(24092, "VC14");
|
||||
SET_INFO(24091, "VR13");
|
||||
SET_INFO(24161, "VR12");
|
||||
SET_INFO(25270, "VC26");
|
||||
SET_INFO(25261, "VC26");
|
||||
//SET_INFO(25260, nullptr); // Don't put empty records
|
||||
SET_INFO(25130, "VA12");
|
||||
SET_INFO(25131, "VS12");
|
||||
SET_INFO(25060, "VC23");
|
||||
SET_INFO(25061, "VC22");
|
||||
SET_INFO(25160, "VC23");
|
||||
SET_INFO(25140, "VR11");
|
||||
SET_INFO(25141, "VC16");
|
||||
SET_INFO(25142, "VC20");
|
||||
SET_INFO(25143, "VC15");
|
||||
SET_INFO(25145, "VC17");
|
||||
SET_INFO(25090, "VC18");
|
||||
SET_INFO(26190, "VC13");
|
||||
SET_INFO(24161, "VR12");
|
||||
SET_INFO(26090, "VS13");
|
||||
SET_INFO(26140, "VC18");
|
||||
SET_INFO(27111, "VC21");
|
||||
#undef SET_INFO
|
||||
}
|
||||
|
||||
} // End of namespace Versailles
|
||||
} // End of namespace CryOmni3D
|
||||
322
engines/cryomni3d/versailles/dialogs.cpp
Normal file
322
engines/cryomni3d/versailles/dialogs.cpp
Normal file
@@ -0,0 +1,322 @@
|
||||
/* 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 "cryomni3d/versailles/engine.h"
|
||||
|
||||
namespace CryOmni3D {
|
||||
namespace Versailles {
|
||||
|
||||
bool CryOmni3DEngine_Versailles::preprocessDialog(const Common::String &sequence) {
|
||||
if (_inventory.inInventoryByNameID(96) && _inventory.inInventoryByNameID(98)) {
|
||||
_dialogsMan["{JOUEUR-TROUVE-TITRE-ET-PAMPHLET}"] = 'Y';
|
||||
}
|
||||
if (_inventory.inInventoryByNameID(126)) {
|
||||
_dialogsMan["{JOUEUR_POSSEDE_EPIGRAPHE}"] = 'Y';
|
||||
}
|
||||
|
||||
if (_currentLevel == 1 && _currentPlaceId == 3) {
|
||||
playInGameAnimVideo("11D_LEB1");
|
||||
}
|
||||
|
||||
_dialogsMan["{JOUEUR-VU-MEMORANDUM-DANS-LUSTRE-DU-SALON-DE-LA-GUERRE}"] = 'N';
|
||||
if (_currentLevel == 5 && _gameVariables[GameVariables::kSeenMemorandum] &&
|
||||
!_inventory.inInventoryByNameID(140)) {
|
||||
_dialogsMan["{JOUEUR-VU-MEMORANDUM-DANS-LUSTRE-DU-SALON-DE-LA-GUERRE}"] = 'Y';
|
||||
}
|
||||
|
||||
if (_currentLevel == 1 && _currentPlaceId == 1 && currentGameTime() == 3 &&
|
||||
sequence.hasPrefix("13F_HUI") && _gameVariables[GameVariables::kWarnedIncomplete] == 0 &&
|
||||
_dialogsMan["{JOUEUR-TROUVE-TITRE-ET-PAMPHLET}"] == 'Y' &&
|
||||
(!_inventory.inInventoryByNameID(96) || !_inventory.inInventoryByNameID(98))) {
|
||||
displayMessageBoxWarp(18);
|
||||
_gameVariables[GameVariables::kWarnedIncomplete] = 1;
|
||||
return 0;
|
||||
}
|
||||
if (_currentLevel == 2 && _currentPlaceId == 11 && currentGameTime() == 4 &&
|
||||
sequence.hasPrefix("24Z_BON") && _gameVariables[GameVariables::kWarnedIncomplete] == 0 &&
|
||||
_dialogsMan["{JOUEUR-MONTRE-TITRE-FABLE-APPARU-SUR-ESQUISSE}"] == 'Y' &&
|
||||
(!_inventory.inInventoryByNameID(101) || !_inventory.inInventoryByNameID(103))) {
|
||||
displayMessageBoxWarp(18);
|
||||
_gameVariables[GameVariables::kWarnedIncomplete] = 1;
|
||||
return 0;
|
||||
}
|
||||
if (_currentLevel == 3 && _currentPlaceId == 10 && currentGameTime() == 3 &&
|
||||
sequence.hasPrefix("31O_SUIA") && _gameVariables[GameVariables::kWarnedIncomplete] == 0 &&
|
||||
_dialogsMan["CROISSY-ACCEPTE-TEXTE"] == 'Y' &&
|
||||
(!_inventory.inInventoryByNameID(121) || !_inventory.inInventoryByNameID(119) ||
|
||||
!_inventory.inInventoryByNameID(115) ||
|
||||
_gameVariables[GameVariables::kGotMedalsSolution] == 0)) {
|
||||
displayMessageBoxWarp(18);
|
||||
_gameVariables[GameVariables::kWarnedIncomplete] = 1;
|
||||
return 0;
|
||||
}
|
||||
if (_currentLevel == 4 && _currentPlaceId == 10 && currentGameTime() == 3 &&
|
||||
sequence.hasPrefix("42C_BON") && _gameVariables[GameVariables::kWarnedIncomplete] == 0 &&
|
||||
_dialogsMan["{JOUEUR-MONTRE-PAMPHLET-RELIGION}"] == 'Y' &&
|
||||
(!_inventory.inInventoryByNameID(127) ||
|
||||
_gameVariables[GameVariables::kUsedVaubanBlueprint1] == 0 ||
|
||||
_gameVariables[GameVariables::kUsedVaubanBlueprint2] == 0)) {
|
||||
displayMessageBoxWarp(18);
|
||||
_gameVariables[GameVariables::kWarnedIncomplete] = 1;
|
||||
return 0;
|
||||
}
|
||||
if (_currentLevel == 5 && _currentPlaceId == 10 && currentGameTime() == 3 &&
|
||||
sequence.hasPrefix("42C_BON") && _gameVariables[GameVariables::kWarnedIncomplete] == 0 &&
|
||||
_dialogsMan["{JOUEUR-MONTRE-PAMPHLET-RELIGION}"] == 'Y' &&
|
||||
(!_inventory.inInventoryByNameID(127) ||
|
||||
_gameVariables[GameVariables::kUsedVaubanBlueprint1] == 0 ||
|
||||
_gameVariables[GameVariables::kUsedVaubanBlueprint2] == 0)) {
|
||||
displayMessageBoxWarp(18);
|
||||
_gameVariables[GameVariables::kWarnedIncomplete] = 1;
|
||||
return 0;
|
||||
}
|
||||
if (_currentLevel == 6 && _currentPlaceId == 14 && currentGameTime() == 2 &&
|
||||
sequence.hasPrefix("61_BON") && _gameVariables[GameVariables::kWarnedIncomplete] == 0) {
|
||||
displayMessageBoxWarp(19);
|
||||
_gameVariables[GameVariables::kWarnedIncomplete] = 1;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void CryOmni3DEngine_Versailles::postprocessDialog(const Common::String &sequence) {
|
||||
if (_currentLevel == 1) {
|
||||
if (_dialogsMan["{LEVEL1_FINI}"] == 'Y') {
|
||||
playTransitionEndLevel(1);
|
||||
}
|
||||
} else if (_currentLevel == 2) {
|
||||
_dialogsMan["{JOUEUR-PRESENTE-FAUX-CROQUIS}"] = 'N';
|
||||
_dialogsMan["{JOUEUR-PRESENTE-FAUX-CROQUIS2}"] = 'N';
|
||||
_dialogsMan["{JOUEUR-PRESENTE-FAUX-CROQUIS3}"] = 'N';
|
||||
_dialogsMan["{LE JOUEUR-PRESENTE-AUTRES-ESQUISSES-OU-ESQUISSE-NON-TRIEES}"] = 'N';
|
||||
_dialogsMan["{LE JOUEUR-PRESENTE-ESQUISSES-TRIEES}"] = 'N';
|
||||
_dialogsMan["{JOUEUR-MONTRE-TITRE-FABLE-APPARU-SUR-ESQUISSE}"] = 'N';
|
||||
_dialogsMan["{JOUEUR-MONTRE-ESQUISSE-DETRUITE}"] = 'N';
|
||||
if (_dialogsMan["{LEVEL2_FINI}"] == 'Y') {
|
||||
playTransitionEndLevel(2);
|
||||
}
|
||||
} else if (_currentLevel == 3) {
|
||||
if (currentGameTime() == 1 && _dialogsMan["LULLY-DONNE-MISSION1-JOUEUR"] == 'Y') {
|
||||
setGameTime(2, 3);
|
||||
}
|
||||
if (!_gameVariables[GameVariables::kGotMedalsSolution] &&
|
||||
_dialogsMan["MONSIEUR-DONNE-SOLUTION-MEDAILLES"] == 'Y') {
|
||||
playInGameAnimVideo("32M_MR2");
|
||||
_gameVariables[GameVariables::kGotMedalsSolution] = 1;
|
||||
}
|
||||
if (!_gameVariables[GameVariables::kDecipherScore] &&
|
||||
_dialogsMan["LULLY-DIT-CHAT-PENDU-JOUEUR"] == 'Y') {
|
||||
_gameVariables[GameVariables::kDecipherScore] = 1;
|
||||
collectObject(118);
|
||||
setGameTime(3, 3);
|
||||
}
|
||||
if (currentGameTime() == 3 && _dialogsMan["CROISSY-ACCEPTE-TEXTE"] == 'Y') {
|
||||
setGameTime(4, 3);
|
||||
}
|
||||
if (_dialogsMan["{LEVEL3_FINI}"] == 'Y') {
|
||||
playTransitionEndLevel(3);
|
||||
}
|
||||
if (sequence == "32M_MR" && _dialogsMan["MONSIEUR-DONNE-SOLUTION-MEDAILLES"] == 'Y') {
|
||||
_dialogsMan["{JOUEUR-MONTRE-MEDAILLES-MONSIEUR}"] = 'Y';
|
||||
}
|
||||
_dialogsMan["{JOUEUR-MONTRE-PAMPHLET-ARCHITECTURE}"] = 'N';
|
||||
_dialogsMan["{JOUEUR-MONTRE-EPIGRAPHE-MEDAILLES}"] = 'N';
|
||||
_dialogsMan["{JOUEUR-MONTRE-TOUT-AUTRE-CHOSE}"] = 'N';
|
||||
} else if (_currentLevel == 4) {
|
||||
if (_dialogsMan["{LEVEL4_FINI}"] == 'Y') {
|
||||
playTransitionEndLevel(4);
|
||||
}
|
||||
} else if (_currentLevel == 5) {
|
||||
if (sequence == "54I_BON" && _dialogsMan["BONTEMPS-DIT-PROMENADE"] == 'Y') {
|
||||
collectObject(141);
|
||||
playTransitionEndLevel(5);
|
||||
}
|
||||
if (sequence == "52A4_LAC" && _gameVariables[GameVariables::kStateLampoonReligion] != 3 &&
|
||||
_dialogsMan["LACHAIZE-DIT-REFORME"] == 'Y' && _dialogsMan["LACHAIZE-DIT-DRAGONNADES"] == 'Y' &&
|
||||
_dialogsMan["LACHAIZE-TROUVE-ECROUELLES"] == 'Y') {
|
||||
_inventory.removeByNameID(125);
|
||||
_gameVariables[GameVariables::kStateLampoonReligion] = 3;
|
||||
collectObject(125);
|
||||
_inventory.deselectObject();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CryOmni3DEngine_Versailles::updateGameTimeDialVariables() {
|
||||
_dialogsMan["{CURRENT_GAME_TIME1}"] = 'N';
|
||||
_dialogsMan["{CURRENT_GAME_TIME2}"] = 'N';
|
||||
_dialogsMan["{CURRENT_GAME_TIME3}"] = 'N';
|
||||
_dialogsMan["{CURRENT_GAME_TIME4}"] = 'N';
|
||||
_dialogsMan["{CURRENT_GAME_TIME5}"] = 'N';
|
||||
switch (currentGameTime()) {
|
||||
case 1:
|
||||
_dialogsMan["{CURRENT_GAME_TIME1}"] = 'Y';
|
||||
break;
|
||||
case 2:
|
||||
_dialogsMan["{CURRENT_GAME_TIME2}"] = 'Y';
|
||||
break;
|
||||
case 3:
|
||||
_dialogsMan["{CURRENT_GAME_TIME3}"] = 'Y';
|
||||
break;
|
||||
case 4:
|
||||
_dialogsMan["{CURRENT_GAME_TIME4}"] = 'Y';
|
||||
break;
|
||||
case 5:
|
||||
_dialogsMan["{CURRENT_GAME_TIME5}"] = 'Y';
|
||||
break;
|
||||
default:
|
||||
error("Invalid current game time %d", currentGameTime());
|
||||
}
|
||||
}
|
||||
|
||||
void CryOmni3DEngine_Versailles::setupDialogShows() {
|
||||
_dialogsMan.registerShowCallback("(BONTEMPS-MONTRE-TROISIEME-TITRE-DE-FABLE)",
|
||||
&CryOmni3DEngine_Versailles::dialogShowBontempsShowThird);
|
||||
_dialogsMan.registerShowCallback("(HUISSIER DONNE PAMPHLET SUR LA FAMILLE ROYALE)",
|
||||
&CryOmni3DEngine_Versailles::dialogShowHuissierShowPamphlet);
|
||||
_dialogsMan.registerShowCallback("(MONSEIGNEUR TRIE LES ESQUISSES)",
|
||||
&CryOmni3DEngine_Versailles::dialogShowMonseigneurSorts);
|
||||
_dialogsMan.registerShowCallback("(ANIMATION LE BRUN REGARDE LES ESQUISSES)",
|
||||
&CryOmni3DEngine_Versailles::dialogShowLeBrunWatches);
|
||||
_dialogsMan.registerShowCallback("(OUVERTURE DES PORTES)",
|
||||
&CryOmni3DEngine_Versailles::dialogShowDoorsOpen);
|
||||
_dialogsMan.registerShowCallback("(GARDE SUISSE DONNE CLEF PETITE PORTE)",
|
||||
&CryOmni3DEngine_Versailles::dialogShowSwissGuardGives);
|
||||
_dialogsMan.registerShowCallback("(LULLY CORRIGE LA PARTITION.)",
|
||||
&CryOmni3DEngine_Versailles::dialogShowLullyCorrects);
|
||||
_dialogsMan.registerShowCallback("(BONTEMPS DONNE AUTORISATION)",
|
||||
&CryOmni3DEngine_Versailles::dialogShowBontempsGivesAuth);
|
||||
_dialogsMan.registerShowCallback("(CROISSY PART)",
|
||||
&CryOmni3DEngine_Versailles::dialogShowCroissyLeave);
|
||||
_dialogsMan.registerShowCallback("(MAINTENON-DONNE-PAMPHLET-RELIGION)",
|
||||
&CryOmni3DEngine_Versailles::dialogShowMaintenonGives);
|
||||
_dialogsMan.registerShowCallback("(LA CHAIZE REND TEXTE)",
|
||||
&CryOmni3DEngine_Versailles::dialogShowLaChaizeGivesBack);
|
||||
_dialogsMan.registerShowCallback("(LA CHAIZE " "\x83" "CRIT DRAGONNADES)",
|
||||
&CryOmni3DEngine_Versailles::dialogShowLaChaizeWrites);
|
||||
_dialogsMan.registerShowCallback("(LA CHAIZE " "\x8e" "CRIT DRAGONNADES)",
|
||||
&CryOmni3DEngine_Versailles::dialogShowLaChaizeWrites);
|
||||
_dialogsMan.registerShowCallback("(LACHAIZE-DONNE-PAMPHLET-JOUEUR)",
|
||||
&CryOmni3DEngine_Versailles::dialogShowLaChaizeGivesPamphlet);
|
||||
_dialogsMan.registerShowCallback("(BONTEMPS-DONNE-CLEF-DES-COMBLES)",
|
||||
&CryOmni3DEngine_Versailles::dialogShowBontempsGivesKey);
|
||||
_dialogsMan.registerShowCallback("(LE DUC DU MAINE S'EN VA)",
|
||||
&CryOmni3DEngine_Versailles::dialogShowDuMaineLeaves);
|
||||
_dialogsMan.registerShowCallback("(SC" "\xe9" "NE DE TRANSITION)",
|
||||
&CryOmni3DEngine_Versailles::dialogShowTransitionScene);
|
||||
_dialogsMan.registerShowCallback("(FIN DU JEU)", &CryOmni3DEngine_Versailles::dialogShowEndOfGame);
|
||||
_dialogsMan.registerShowCallback("(LEBRUN-DONNE-FAUSSES-ESQUISSES)",
|
||||
&CryOmni3DEngine_Versailles::dialogShowLeBrunGives);
|
||||
_dialogsMan.registerShowCallback("(LEBRUN_S_EN_VA)",
|
||||
&CryOmni3DEngine_Versailles::dialogShowLeBrunLeave);
|
||||
}
|
||||
|
||||
void CryOmni3DEngine_Versailles::dialogShowBontempsShowThird() {
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
void CryOmni3DEngine_Versailles::dialogShowHuissierShowPamphlet() {
|
||||
collectObject(101);
|
||||
_inventory.deselectObject();
|
||||
}
|
||||
|
||||
void CryOmni3DEngine_Versailles::dialogShowMonseigneurSorts() {
|
||||
_inventory.removeByNameID(105);
|
||||
collectObject(106);
|
||||
_gameVariables[GameVariables::kSketchState] = 2; // Sketches sorted
|
||||
_inventory.deselectObject();
|
||||
setGameTime(3, 2);
|
||||
_dialogsMan["MONSEIGNEUR-ATTEND-ESQUISSES"] = 'N';
|
||||
}
|
||||
|
||||
void CryOmni3DEngine_Versailles::dialogShowLeBrunWatches() {
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
void CryOmni3DEngine_Versailles::dialogShowDoorsOpen() {
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
void CryOmni3DEngine_Versailles::dialogShowSwissGuardGives() {
|
||||
collectObject(123);
|
||||
_dialogsMan["{JOUEUR-POSSEDE-CLE}"] = 'Y';
|
||||
}
|
||||
|
||||
void CryOmni3DEngine_Versailles::dialogShowLullyCorrects() {
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
void CryOmni3DEngine_Versailles::dialogShowBontempsGivesAuth() {
|
||||
collectObject(120);
|
||||
}
|
||||
|
||||
void CryOmni3DEngine_Versailles::dialogShowCroissyLeave() {
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
void CryOmni3DEngine_Versailles::dialogShowMaintenonGives() {
|
||||
collectObject(125);
|
||||
_inventory.deselectObject();
|
||||
}
|
||||
|
||||
void CryOmni3DEngine_Versailles::dialogShowLaChaizeGivesBack() {
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
void CryOmni3DEngine_Versailles::dialogShowLaChaizeWrites() {
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
void CryOmni3DEngine_Versailles::dialogShowLaChaizeGivesPamphlet() {
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
void CryOmni3DEngine_Versailles::dialogShowBontempsGivesKey() {
|
||||
collectObject(140);
|
||||
_inventory.deselectObject();
|
||||
}
|
||||
|
||||
void CryOmni3DEngine_Versailles::dialogShowDuMaineLeaves() {
|
||||
playInGameAnimVideo("62S_DUC1");
|
||||
_inventory.removeByNameID(144);
|
||||
setPlaceState(19, 1);
|
||||
}
|
||||
|
||||
void CryOmni3DEngine_Versailles::dialogShowTransitionScene() {
|
||||
playTransitionEndLevel(6);
|
||||
}
|
||||
|
||||
void CryOmni3DEngine_Versailles::dialogShowEndOfGame() {
|
||||
doGameOver();
|
||||
}
|
||||
|
||||
void CryOmni3DEngine_Versailles::dialogShowLeBrunGives() {
|
||||
collectObject(107);
|
||||
_inventory.deselectObject();
|
||||
}
|
||||
|
||||
void CryOmni3DEngine_Versailles::dialogShowLeBrunLeave() {
|
||||
playInGameAnimVideo("11D_LEB3");
|
||||
setGameTime(2, 1);
|
||||
}
|
||||
|
||||
} // End of namespace Versailles
|
||||
} // End of namespace CryOmni3D
|
||||
376
engines/cryomni3d/versailles/dialogs_manager.cpp
Normal file
376
engines/cryomni3d/versailles/dialogs_manager.cpp
Normal file
@@ -0,0 +1,376 @@
|
||||
/* 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/decoders/wave.h"
|
||||
#include "common/file.h"
|
||||
#include "common/system.h"
|
||||
|
||||
#include "video/hnm_decoder.h"
|
||||
|
||||
#include "cryomni3d/versailles/dialogs_manager.h"
|
||||
#include "cryomni3d/versailles/engine.h"
|
||||
|
||||
namespace CryOmni3D {
|
||||
namespace Versailles {
|
||||
|
||||
Versailles_DialogsManager::Versailles_DialogsManager(CryOmni3DEngine_Versailles *engine,
|
||||
bool padAudioFileName) :
|
||||
_engine(engine), _padAudioFileName(padAudioFileName) {
|
||||
}
|
||||
|
||||
bool Versailles_DialogsManager::play(const Common::String &sequence) {
|
||||
// Prepare with specific Versailles stuff
|
||||
if (!_engine->preprocessDialog(sequence)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_engine->musicSetQuiet(true);
|
||||
|
||||
_engine->setCursor(181);
|
||||
// No need to adjust hide cursor counter, there isn't any in ScummVM
|
||||
bool cursorWasVisible = _engine->showMouse(true);
|
||||
|
||||
bool slowStop = false;
|
||||
bool didSth = DialogsManager::play(sequence, slowStop);
|
||||
|
||||
_engine->showMouse(cursorWasVisible);
|
||||
|
||||
if (didSth && slowStop) {
|
||||
if (_engine->showSubtitles()) {
|
||||
bool skip = false;
|
||||
uint end = g_system->getMillis() + 2000;
|
||||
while (!_engine->shouldAbort() && g_system->getMillis() < end && !skip) {
|
||||
g_system->updateScreen();
|
||||
g_system->delayMillis(10);
|
||||
if (_engine->pollEvents() &&
|
||||
(_engine->checkKeysPressed(1, Common::KEYCODE_SPACE) ||
|
||||
_engine->getCurrentMouseButton() == 1)) {
|
||||
skip = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_engine->postprocessDialog(sequence);
|
||||
|
||||
_engine->musicSetQuiet(false);
|
||||
|
||||
_lastImage.free();
|
||||
|
||||
_engine->waitMouseRelease();
|
||||
return didSth;
|
||||
}
|
||||
|
||||
void Versailles_DialogsManager::executeShow(const Common::String &show) {
|
||||
Common::HashMap<Common::String, ShowCallback>::iterator showIt = _shows.find(show);
|
||||
|
||||
if (showIt == _shows.end()) {
|
||||
error("Missing show %s", show.c_str());
|
||||
}
|
||||
|
||||
_lastImage.free();
|
||||
|
||||
ShowCallback cb = showIt->_value;
|
||||
(_engine->*cb)();
|
||||
}
|
||||
|
||||
void Versailles_DialogsManager::playDialog(const Common::String &video, const Common::String &sound,
|
||||
const Common::String &text, const SubtitlesSettings &settings) {
|
||||
Common::String soundFName(sound);
|
||||
if (_padAudioFileName) {
|
||||
while (soundFName.size() < 8) {
|
||||
soundFName += '_';
|
||||
}
|
||||
}
|
||||
|
||||
Common::Path videoPath(_engine->getFilePath(kFileTypeDialAnim, video));
|
||||
Common::Path soundPath(_engine->getFilePath(kFileTypeDialSound, soundFName));
|
||||
|
||||
Video::HNMDecoder *videoDecoder = new Video::HNMDecoder(g_system->getScreenFormat(), true);
|
||||
|
||||
if (!videoDecoder->loadFile(videoPath)) {
|
||||
warning("Failed to open movie file %s/%s", video.c_str(), videoPath.toString(Common::Path::kNativeSeparator).c_str());
|
||||
delete videoDecoder;
|
||||
return;
|
||||
}
|
||||
|
||||
Common::File *audioFile = new Common::File();
|
||||
if (!audioFile->open(soundPath)) {
|
||||
warning("Failed to open sound file %s/%s", sound.c_str(), soundPath.toString(Common::Path::kNativeSeparator).c_str());
|
||||
delete videoDecoder;
|
||||
delete audioFile;
|
||||
return;
|
||||
}
|
||||
|
||||
Audio::SeekableAudioStream *audioDecoder = Audio::makeWAVStream(audioFile, DisposeAfterUse::YES);
|
||||
// We lost ownership of the audioFile just set it to nullptr and don't use it
|
||||
audioFile = nullptr;
|
||||
|
||||
if (!audioDecoder) {
|
||||
delete videoDecoder;
|
||||
return;
|
||||
}
|
||||
|
||||
_engine->showMouse(false);
|
||||
|
||||
uint16 width = videoDecoder->getWidth();
|
||||
uint16 height = videoDecoder->getHeight();
|
||||
|
||||
// Preload first frame to draw subtitles from it
|
||||
const Graphics::Surface *firstFrame = videoDecoder->decodeNextFrame();
|
||||
assert(firstFrame != nullptr);
|
||||
|
||||
if (videoDecoder->hasDirtyPalette()) {
|
||||
const byte *palette = videoDecoder->getPalette();
|
||||
_engine->setupPalette(palette, 0, 256);
|
||||
}
|
||||
|
||||
FontManager &fontManager = _engine->_fontManager;
|
||||
_lastImage.create(firstFrame->w, firstFrame->h, firstFrame->format);
|
||||
_lastImage.blitFrom(*firstFrame);
|
||||
|
||||
fontManager.setCurrentFont(7);
|
||||
fontManager.setTransparentBackground(true);
|
||||
fontManager.setForeColor(241);
|
||||
fontManager.setLineHeight(22);
|
||||
fontManager.setSpaceWidth(2);
|
||||
fontManager.setCharSpacing(1);
|
||||
|
||||
if (_engine->showSubtitles()) {
|
||||
Common::Rect block = settings.textRect;
|
||||
|
||||
uint lines = fontManager.getLinesCount(text, block.width() - 8);
|
||||
if (lines == 0) {
|
||||
lines = 5;
|
||||
}
|
||||
uint blockHeight = fontManager.lineHeight() * lines + 6;
|
||||
block.setHeight(blockHeight);
|
||||
|
||||
if (block.bottom >= 480) {
|
||||
block.bottom = 470;
|
||||
warning("Dialog text is really too long");
|
||||
}
|
||||
|
||||
// Make only the block area translucent inplace
|
||||
Graphics::Surface blockSurface = _lastImage.getSubArea(block);
|
||||
_engine->makeTranslucent(blockSurface, blockSurface);
|
||||
|
||||
fontManager.setSurface(&_lastImage);
|
||||
block.grow(-4);
|
||||
fontManager.setupBlock(block);
|
||||
fontManager.displayBlockText(text);
|
||||
}
|
||||
|
||||
g_system->copyRectToScreen(_lastImage.getPixels(), _lastImage.pitch, 0, 0, width, height);
|
||||
g_system->updateScreen();
|
||||
|
||||
const Common::Rect &drawRect = settings.drawRect;
|
||||
|
||||
if (audioDecoder->getLength() == 0) {
|
||||
// Empty wave file
|
||||
delete audioDecoder;
|
||||
|
||||
uint duration = 100 * text.size();
|
||||
if (duration < 1000) {
|
||||
duration = 1000;
|
||||
}
|
||||
|
||||
bool skipWait = false;
|
||||
uint end = g_system->getMillis() + duration;
|
||||
while (!_engine->shouldAbort() && g_system->getMillis() < end && !skipWait) {
|
||||
g_system->updateScreen();
|
||||
g_system->delayMillis(10);
|
||||
if (_engine->pollEvents() && _engine->checkKeysPressed(1, Common::KEYCODE_SPACE)) {
|
||||
skipWait = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Let start the show!
|
||||
videoDecoder->start();
|
||||
|
||||
Audio::SoundHandle audioHandle;
|
||||
_engine->_mixer->playStream(Audio::Mixer::kSpeechSoundType, &audioHandle, audioDecoder);
|
||||
// We lost ownership of the audioDecoder just set it to nullptr and don't use it
|
||||
audioDecoder = nullptr;
|
||||
|
||||
bool skipVideo = false;
|
||||
while (!_engine->shouldAbort() && _engine->_mixer->isSoundHandleActive(audioHandle) && !skipVideo) {
|
||||
if (_engine->pollEvents() && _engine->checkKeysPressed(1, Common::KEYCODE_SPACE)) {
|
||||
skipVideo = true;
|
||||
}
|
||||
|
||||
if (videoDecoder->needsUpdate()) {
|
||||
const Graphics::Surface *frame = videoDecoder->decodeNextFrame();
|
||||
|
||||
if (frame) {
|
||||
if (videoDecoder->hasDirtyPalette()) {
|
||||
const byte *palette = videoDecoder->getPalette();
|
||||
_engine->setupPalette(palette, 0, 256);
|
||||
}
|
||||
|
||||
// Only refresh the moving part of the animation
|
||||
const Graphics::Surface subFrame = frame->getSubArea(drawRect);
|
||||
g_system->copyRectToScreen(subFrame.getPixels(), subFrame.pitch, drawRect.left, drawRect.top,
|
||||
subFrame.w, subFrame.h);
|
||||
}
|
||||
}
|
||||
g_system->updateScreen();
|
||||
g_system->delayMillis(10);
|
||||
}
|
||||
_engine->_mixer->stopHandle(audioHandle);
|
||||
}
|
||||
|
||||
// It's intentional that _lastImage is set with the first video image
|
||||
|
||||
delete videoDecoder;
|
||||
_engine->showMouse(true);
|
||||
}
|
||||
|
||||
void Versailles_DialogsManager::displayMessage(const Common::String &text) {
|
||||
_engine->displayMessageBoxWarp(text);
|
||||
}
|
||||
|
||||
uint Versailles_DialogsManager::askPlayerQuestions(const Common::String &video,
|
||||
const Common::StringArray &questions) {
|
||||
if (_lastImage.empty()) {
|
||||
loadFrame(video);
|
||||
}
|
||||
|
||||
if (questions.size() == 0 || questions.size() > 5) {
|
||||
return uint(-1);
|
||||
}
|
||||
|
||||
FontManager &fontManager = _engine->_fontManager;
|
||||
fontManager.setCurrentFont(7);
|
||||
fontManager.setTransparentBackground(true);
|
||||
fontManager.setLineHeight(18);
|
||||
fontManager.setSpaceWidth(2);
|
||||
fontManager.setSurface(&_lastImage);
|
||||
|
||||
int16 tops[5];
|
||||
int16 bottoms[5];
|
||||
int16 currentHeight = 0;
|
||||
uint questionId = 0;
|
||||
for (Common::StringArray::const_iterator it = questions.begin(); it != questions.end();
|
||||
it++, questionId++) {
|
||||
tops[questionId] = currentHeight;
|
||||
uint lines = fontManager.getLinesCount(*it, 598);
|
||||
if (lines == 0) {
|
||||
lines = 1;
|
||||
}
|
||||
currentHeight += 18 * lines;
|
||||
bottoms[questionId] = currentHeight;
|
||||
}
|
||||
|
||||
int offsetY = 480 - (bottoms[questions.size() - 1] - tops[0]);
|
||||
if (offsetY > 402) {
|
||||
offsetY = 402;
|
||||
} else if (offsetY < 2) {
|
||||
offsetY = 2;
|
||||
}
|
||||
|
||||
for (questionId = 0; questionId < questions.size(); questionId++) {
|
||||
tops[questionId] += offsetY;
|
||||
bottoms[questionId] += offsetY;
|
||||
}
|
||||
|
||||
_engine->setCursor(181);
|
||||
Graphics::Surface alphaSurface = _lastImage.getSubArea(Common::Rect(0, offsetY - 2, 640, 480));
|
||||
_engine->makeTranslucent(alphaSurface, alphaSurface);
|
||||
|
||||
bool finished = false;
|
||||
bool update = true;
|
||||
uint selectedQuestion = uint(-1);
|
||||
while (!finished) {
|
||||
if (update) {
|
||||
update = false;
|
||||
questionId = 0;
|
||||
for (Common::StringArray::const_iterator it = questions.begin(); it != questions.end();
|
||||
it++, questionId++) {
|
||||
fontManager.setForeColor(selectedQuestion == questionId ? 241 : 245);
|
||||
fontManager.setupBlock(Common::Rect(10, tops[questionId], 608, bottoms[questionId]));
|
||||
fontManager.displayBlockText(*it);
|
||||
}
|
||||
g_system->copyRectToScreen(_lastImage.getPixels(), _lastImage.pitch, 0, 0, _lastImage.w,
|
||||
_lastImage.h);
|
||||
}
|
||||
g_system->updateScreen();
|
||||
g_system->delayMillis(10);
|
||||
|
||||
if (_engine->pollEvents()) {
|
||||
_engine->clearKeys();
|
||||
if (_engine->shouldAbort()) {
|
||||
finished = true;
|
||||
selectedQuestion = uint(-1);
|
||||
break;
|
||||
}
|
||||
Common::Point mousePos = _engine->getMousePos();
|
||||
if (_engine->getDragStatus() == kDragStatus_Finished && selectedQuestion != uint(-1)) {
|
||||
finished = true;
|
||||
} else if (mousePos.x >= 608 || mousePos.y < offsetY) {
|
||||
if (selectedQuestion != uint(-1)) {
|
||||
selectedQuestion = uint(-1);
|
||||
update = true;
|
||||
}
|
||||
} else {
|
||||
for (questionId = 0; questionId < questions.size(); questionId++) {
|
||||
if (mousePos.y > tops[questionId] && mousePos.y < bottoms[questionId]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (questionId < questions.size()) {
|
||||
if (selectedQuestion != questionId) {
|
||||
selectedQuestion = questionId;
|
||||
update = true;
|
||||
}
|
||||
} else {
|
||||
selectedQuestion = uint(-1);
|
||||
update = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return selectedQuestion;
|
||||
}
|
||||
|
||||
void Versailles_DialogsManager::loadFrame(const Common::String &video) {
|
||||
Common::Path videoPath(_engine->getFilePath(kFileTypeDialAnim, video));
|
||||
|
||||
Video::HNMDecoder videoDecoder(g_system->getScreenFormat());
|
||||
|
||||
if (!videoDecoder.loadFile(videoPath)) {
|
||||
warning("Failed to open movie file %s/%s", video.c_str(), videoPath.toString(Common::Path::kNativeSeparator).c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
// Preload first frame to draw questions on it
|
||||
const Graphics::Surface *firstFrame = videoDecoder.decodeNextFrame();
|
||||
_lastImage.create(firstFrame->w, firstFrame->h, firstFrame->format);
|
||||
_lastImage.blitFrom(*firstFrame);
|
||||
|
||||
if (videoDecoder.hasDirtyPalette()) {
|
||||
const byte *palette = videoDecoder.getPalette();
|
||||
_engine->setupPalette(palette, 0, 256);
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Versailles
|
||||
} // End of namespace CryOmni3D
|
||||
68
engines/cryomni3d/versailles/dialogs_manager.h
Normal file
68
engines/cryomni3d/versailles/dialogs_manager.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/* 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 CRYOMNI3D_VERSAILLES_DIALOGS_MANAGER_H
|
||||
#define CRYOMNI3D_VERSAILLES_DIALOGS_MANAGER_H
|
||||
|
||||
#include "common/hashmap.h"
|
||||
#include "common/hash-str.h"
|
||||
#include "graphics/managed_surface.h"
|
||||
|
||||
#include "cryomni3d/dialogs_manager.h"
|
||||
#include "cryomni3d/font_manager.h"
|
||||
|
||||
namespace CryOmni3D {
|
||||
namespace Versailles {
|
||||
|
||||
class CryOmni3DEngine_Versailles;
|
||||
typedef void (CryOmni3DEngine_Versailles::*ShowCallback)();
|
||||
|
||||
class Versailles_DialogsManager : public DialogsManager {
|
||||
public:
|
||||
Versailles_DialogsManager(CryOmni3DEngine_Versailles *engine, bool padAudioFileName);
|
||||
|
||||
// This overload will hide the base one and this is what we want
|
||||
bool play(const Common::String &sequence);
|
||||
|
||||
void registerShowCallback(const Common::String &showName, ShowCallback callback) { _shows[showName] = callback; }
|
||||
|
||||
protected:
|
||||
void executeShow(const Common::String &show) override;
|
||||
void playDialog(const Common::String &video, const Common::String &sound,
|
||||
const Common::String &text, const SubtitlesSettings &settings) override;
|
||||
void displayMessage(const Common::String &text) override;
|
||||
uint askPlayerQuestions(const Common::String &video,
|
||||
const Common::StringArray &questions) override;
|
||||
|
||||
private:
|
||||
CryOmni3DEngine_Versailles *_engine;
|
||||
Common::HashMap<Common::String, ShowCallback> _shows;
|
||||
bool _padAudioFileName;
|
||||
|
||||
void loadFrame(const Common::String &video);
|
||||
|
||||
Graphics::ManagedSurface _lastImage;
|
||||
};
|
||||
|
||||
} // End of namespace Versailles
|
||||
} // End of namespace CryOmni3D
|
||||
|
||||
#endif
|
||||
2124
engines/cryomni3d/versailles/documentation.cpp
Normal file
2124
engines/cryomni3d/versailles/documentation.cpp
Normal file
File diff suppressed because it is too large
Load Diff
146
engines/cryomni3d/versailles/documentation.h
Normal file
146
engines/cryomni3d/versailles/documentation.h
Normal file
@@ -0,0 +1,146 @@
|
||||
/* 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 CRYOMNI3D_VERSAILLES_DOCUMENTATION_H
|
||||
#define CRYOMNI3D_VERSAILLES_DOCUMENTATION_H
|
||||
|
||||
#include "common/hashmap.h"
|
||||
#include "common/hash-str.h"
|
||||
#include "common/rect.h"
|
||||
#include "common/str-array.h"
|
||||
#include "graphics/managed_surface.h"
|
||||
|
||||
namespace CryOmni3D {
|
||||
class FontManager;
|
||||
class MouseBoxes;
|
||||
class Sprites;
|
||||
|
||||
namespace Versailles {
|
||||
class CryOmni3DEngine_Versailles;
|
||||
|
||||
class Versailles_Documentation {
|
||||
public:
|
||||
Versailles_Documentation() : _engine(nullptr), _fontManager(nullptr), _sprites(nullptr),
|
||||
_messages(nullptr), _multilineAttributes(false), _linksData(nullptr), _linksSize(0),
|
||||
_currentInTimeline(false), _currentMapLayout(false), _currentHasMap(false) { }
|
||||
~Versailles_Documentation() { delete [] _linksData; }
|
||||
|
||||
void init(const Sprites *sprites, FontManager *fontManager, const Common::StringArray *messages,
|
||||
CryOmni3DEngine_Versailles *engine, const Common::Path &allDocsFilePath,
|
||||
const Common::Path &linksDocsFilePath);
|
||||
void handleDocArea();
|
||||
void handleDocInGame(const Common::String &record);
|
||||
|
||||
private:
|
||||
Common::String docAreaHandleSummary();
|
||||
Common::String docAreaHandleTimeline();
|
||||
Common::String docAreaHandleGeneralMap();
|
||||
Common::String docAreaHandleCastleMap();
|
||||
uint docAreaHandleRecords(const Common::String &record);
|
||||
|
||||
void docAreaPrepareNavigation();
|
||||
void docAreaPrepareRecord(Graphics::ManagedSurface &surface, MouseBoxes &boxes);
|
||||
uint docAreaHandleRecord(Graphics::ManagedSurface &surface, MouseBoxes &boxes,
|
||||
Common::String &nextRecord);
|
||||
|
||||
void inGamePrepareRecord(Graphics::ManagedSurface &surface, MouseBoxes &boxes);
|
||||
uint inGameHandleRecord(Graphics::ManagedSurface &surface, MouseBoxes &boxes,
|
||||
Common::String &nextRecord);
|
||||
|
||||
void setupRecordBoxes(bool inDocArea, MouseBoxes &boxes);
|
||||
void setupTimelineBoxes(MouseBoxes &boxes);
|
||||
void drawRecordData(Graphics::ManagedSurface &surface,
|
||||
const Common::String &text, const Common::String &title,
|
||||
const Common::String &subtitle, const Common::String &caption);
|
||||
void drawRecordBoxes(Graphics::ManagedSurface &surface, bool inDocArea, MouseBoxes &boxes);
|
||||
|
||||
uint handlePopupMenu(const Graphics::ManagedSurface &surface,
|
||||
const Common::Point &anchor, bool rightAligned, uint itemHeight,
|
||||
const Common::StringArray &items);
|
||||
|
||||
struct RecordInfo {
|
||||
uint id;
|
||||
uint position;
|
||||
uint size;
|
||||
};
|
||||
|
||||
struct LinkInfo {
|
||||
Common::String record;
|
||||
Common::String title;
|
||||
};
|
||||
|
||||
struct TimelineEntry {
|
||||
char year[8];
|
||||
uint x;
|
||||
uint y;
|
||||
};
|
||||
static const TimelineEntry kTimelineEntries[];
|
||||
|
||||
char *getDocPartAddress(char *start, char *end, const char *patterns[]);
|
||||
const char *getDocTextAddress(char *start, char *end);
|
||||
const char *getRecordTitle(char *start, char *end);
|
||||
const char *getRecordSubtitle(char *start, char *end);
|
||||
const char *getRecordCaption(char *start, char *end);
|
||||
void getRecordHyperlinks(char *start, char *end, Common::StringArray &hyperlinks);
|
||||
|
||||
Common::String getRecordTitle(const Common::String &record);
|
||||
Common::String getRecordData(const Common::String &record, Common::String &title,
|
||||
Common::String &subtitle, Common::String &caption,
|
||||
Common::StringArray &hyperlinks);
|
||||
void convertHyperlinks(const Common::StringArray &hyperlinks, Common::Array<LinkInfo> &links);
|
||||
|
||||
void loadLinksFile();
|
||||
void getLinks(const Common::String &record, Common::Array<LinkInfo> &links);
|
||||
|
||||
Common::Path _allDocsFilePath;
|
||||
Common::Path _linksDocsFilePath;
|
||||
|
||||
static const uint kPopupMenuMargin = 5;
|
||||
|
||||
CryOmni3DEngine_Versailles *_engine;
|
||||
FontManager *_fontManager;
|
||||
const Sprites *_sprites;
|
||||
const Common::StringArray *_messages;
|
||||
|
||||
bool _multilineAttributes;
|
||||
|
||||
Common::StringArray _recordsOrdered;
|
||||
Common::HashMap<Common::String, RecordInfo> _records;
|
||||
char *_linksData;
|
||||
uint _linksSize;
|
||||
|
||||
Common::Array<LinkInfo> _allLinks;
|
||||
|
||||
Common::StringArray _visitTrace;
|
||||
Common::String _currentRecord;
|
||||
Common::String _categoryStartRecord;
|
||||
Common::String _categoryEndRecord;
|
||||
Common::String _categoryTitle;
|
||||
Common::Array<LinkInfo> _currentLinks;
|
||||
bool _currentInTimeline;
|
||||
bool _currentMapLayout;
|
||||
bool _currentHasMap;
|
||||
};
|
||||
|
||||
} // End of namespace Versailles
|
||||
} // End of namespace CryOmni3D
|
||||
|
||||
#endif
|
||||
1961
engines/cryomni3d/versailles/engine.cpp
Normal file
1961
engines/cryomni3d/versailles/engine.cpp
Normal file
File diff suppressed because it is too large
Load Diff
687
engines/cryomni3d/versailles/engine.h
Normal file
687
engines/cryomni3d/versailles/engine.h
Normal file
@@ -0,0 +1,687 @@
|
||||
/* 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 CRYOMNI3D_VERSAILLES_ENGINE_H
|
||||
#define CRYOMNI3D_VERSAILLES_ENGINE_H
|
||||
|
||||
#include "common/events.h"
|
||||
#include "common/random.h"
|
||||
#include "common/array.h"
|
||||
#include "common/hashmap.h"
|
||||
#include "common/hash-str.h"
|
||||
#include "common/str.h"
|
||||
|
||||
#include "cryomni3d/cryomni3d.h"
|
||||
#include "cryomni3d/omni3d.h"
|
||||
#include "cryomni3d/sprites.h"
|
||||
#include "cryomni3d/wam_parser.h"
|
||||
|
||||
#include "cryomni3d/versailles/documentation.h"
|
||||
#include "cryomni3d/versailles/toolbar.h"
|
||||
#include "cryomni3d/versailles/dialogs_manager.h"
|
||||
|
||||
namespace Graphics {
|
||||
class ManagedSurface;
|
||||
struct Surface;
|
||||
}
|
||||
|
||||
namespace CryOmni3D {
|
||||
struct FixedImageConfiguration;
|
||||
class ZonFixedImage;
|
||||
}
|
||||
|
||||
namespace CryOmni3D {
|
||||
namespace Versailles {
|
||||
struct PlaceStateActionKey {
|
||||
uint placeId;
|
||||
uint placeState;
|
||||
uint actionId;
|
||||
PlaceStateActionKey(uint placeId_, uint placeState_, uint actionId_) :
|
||||
placeId(placeId_), placeState(placeState_), actionId(actionId_) {}
|
||||
|
||||
bool operator==(const PlaceStateActionKey &other) const {
|
||||
return other.placeId == placeId && other.placeState == placeState && other.actionId == actionId;
|
||||
}
|
||||
};
|
||||
|
||||
struct PlaceActionKey {
|
||||
uint placeId;
|
||||
uint actionId;
|
||||
PlaceActionKey(uint placeId_, uint actionId_) :
|
||||
placeId(placeId_), actionId(actionId_) {}
|
||||
|
||||
bool operator==(const PlaceActionKey &other) const {
|
||||
return other.placeId == placeId && other.actionId == actionId;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
namespace Common {
|
||||
template<>
|
||||
struct Hash<CryOmni3D::Versailles::PlaceStateActionKey> {
|
||||
uint operator()(const CryOmni3D::Versailles::PlaceStateActionKey &k) const {
|
||||
// placeState shouldn't be greater than 8 and placeId shouldn't be greater than 100
|
||||
// originalActionId shouldn't be greater than 65536
|
||||
return (k.placeId << 24 | k.placeState << 16) ^ k.actionId;
|
||||
}
|
||||
};
|
||||
template<>
|
||||
struct Hash<CryOmni3D::Versailles::PlaceActionKey> {
|
||||
uint operator()(const CryOmni3D::Versailles::PlaceActionKey &k) const {
|
||||
// placeId shouldn't be greater than 100
|
||||
// originalActionId shouldn't be greater than 65536
|
||||
return (k.placeId << 16) ^ k.actionId;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace CryOmni3D {
|
||||
namespace Versailles {
|
||||
|
||||
class CryOmni3DEngine_Versailles;
|
||||
|
||||
enum AbortCommand {
|
||||
kAbortNoAbort = 0,
|
||||
kAbortQuit = 1,
|
||||
kAbortLoadGame = 2,
|
||||
kAbortNewGame = 3,
|
||||
kAbortNextLevel = 5,
|
||||
kAbortFinished = 6,
|
||||
kAbortGameOver = 7
|
||||
};
|
||||
|
||||
struct GameVariables {
|
||||
enum Var {
|
||||
kCollectScore = 0, // 0
|
||||
kUnlockHiddenDoor,
|
||||
kAlreadyWent3_19,
|
||||
kMedalsDrawerStatus,
|
||||
kCurrentTime,
|
||||
kGotMedalsSolution,
|
||||
kCabinetDrawerStatus,
|
||||
kDecipherScore,
|
||||
kCollectLampoonArchitecture,
|
||||
kGotRevealedPaper,
|
||||
kCollectKey, // 10
|
||||
kCollectPortfolio,
|
||||
kSketchState,
|
||||
kFakeSketchChatState,
|
||||
kCollectFood,
|
||||
kCollectQuill,
|
||||
kStateLampoonReligion,
|
||||
kCollectSmallKey3,
|
||||
kCollectEngraving,
|
||||
kCollectCord,
|
||||
kCollectVaubanBlueprint1, // 20
|
||||
kCollectVaubanBlueprint2,
|
||||
kLadderState,
|
||||
kOpenedCurtain,
|
||||
kLoweredChandelier,
|
||||
kCombedOrangeTree,
|
||||
kMaineTalked,
|
||||
kUsedLitCandle,
|
||||
kBombState,
|
||||
kInkSpilled,
|
||||
kCollectedPaperOnTable, // 30
|
||||
kSafeUnlocked,
|
||||
//kUselessVar,
|
||||
kCollectedPaperInTrunk = 33,
|
||||
kBrushColor,
|
||||
kUsedScissors,
|
||||
kUnlockedAttic,
|
||||
kHasPlayedLebrun,
|
||||
kWarnedIncomplete,
|
||||
kUsedVaubanBlueprint1,
|
||||
kUsedVaubanBlueprint2, // 40
|
||||
kSeenMemorandum,
|
||||
kCollectScissors,
|
||||
kSavedCountdown,
|
||||
kMax
|
||||
};
|
||||
};
|
||||
|
||||
// For random sounds we set a constant ID and avoid to use it elsewhere
|
||||
struct SoundIds {
|
||||
enum {
|
||||
kOrgue = 0,
|
||||
kLeb001,
|
||||
kMax
|
||||
};
|
||||
};
|
||||
|
||||
struct LocalizedFilenames {
|
||||
enum {
|
||||
kDialogs = 0,
|
||||
kAllDocs,
|
||||
kLinksDocs,
|
||||
kCredits,
|
||||
kLeb001,
|
||||
kMax
|
||||
};
|
||||
};
|
||||
|
||||
enum FileType {
|
||||
kFileTypeAnimacti,
|
||||
kFileTypeDocBg,
|
||||
kFileTypeDialAnim,
|
||||
kFileTypeDialSound,
|
||||
kFileTypeFont,
|
||||
kFileTypeGTO,
|
||||
kFileTypeFixedImg,
|
||||
kFileTypeMenu,
|
||||
kFileTypeMusic,
|
||||
kFileTypeObject,
|
||||
kFileTypeSaveGameVisit,
|
||||
kFileTypeTransScene,
|
||||
kFileTypeTransSceneI,
|
||||
kFileTypeSound,
|
||||
kFileTypeSprite,
|
||||
kFileTypeSpriteBmp,
|
||||
kFileTypeText,
|
||||
kFileTypeWAM,
|
||||
kFileTypeWarpCyclo,
|
||||
kFileTypeWarpHNM
|
||||
};
|
||||
|
||||
struct PlaceState {
|
||||
typedef void (CryOmni3DEngine_Versailles::*InitFunc)();
|
||||
typedef bool (CryOmni3DEngine_Versailles::*FilterEventFunc)(uint *event);
|
||||
|
||||
PlaceState() : initPlace(nullptr), filterEvent(nullptr), docImage(nullptr), state(0) {}
|
||||
PlaceState(InitFunc initPlace_, FilterEventFunc filterEvent_, const char *docImage_) :
|
||||
initPlace(initPlace_), filterEvent(filterEvent_), docImage(docImage_), state(0) {}
|
||||
|
||||
InitFunc initPlace;
|
||||
FilterEventFunc filterEvent;
|
||||
const char *docImage;
|
||||
uint state;
|
||||
};
|
||||
|
||||
struct LevelInitialState {
|
||||
uint placeId;
|
||||
double alpha;
|
||||
double beta;
|
||||
};
|
||||
|
||||
struct FakeTransitionActionPlace {
|
||||
uint actionId;
|
||||
uint placeId;
|
||||
};
|
||||
|
||||
typedef void (CryOmni3DEngine_Versailles::*FixedImgCallback)(ZonFixedImage *);
|
||||
|
||||
struct MsgBoxParameters {
|
||||
int font;
|
||||
byte foreColor;
|
||||
uint lineHeight;
|
||||
uint spaceWidth;
|
||||
uint charSpacing;
|
||||
uint initialWidth;
|
||||
uint incrementWidth;
|
||||
uint initialHeight;
|
||||
uint incrementHeight;
|
||||
uint timeoutChar;
|
||||
};
|
||||
|
||||
struct SubtitleEntry {
|
||||
uint32 frameStart;
|
||||
Common::String text;
|
||||
};
|
||||
|
||||
class CryOmni3DEngine_Versailles : public CryOmni3DEngine {
|
||||
friend class Versailles_DialogsManager;
|
||||
protected:
|
||||
Common::Error run() override;
|
||||
|
||||
public:
|
||||
CryOmni3DEngine_Versailles(OSystem *syst, const CryOmni3DGameDescription *gamedesc);
|
||||
~CryOmni3DEngine_Versailles() override;
|
||||
|
||||
void initializePath(const Common::FSNode &gamePath) override;
|
||||
|
||||
bool hasFeature(EngineFeature f) const override;
|
||||
Common::Error loadGameState(int slot) override;
|
||||
Common::Error saveGameState(int slot, const Common::String &desc, bool isAutosave = false) override;
|
||||
Common::String getSaveStateName(int slot) const override;
|
||||
|
||||
Common::Path getFilePath(FileType fileType, const Common::String &baseName) const;
|
||||
|
||||
void setupPalette(const byte *colors, uint start, uint num) override { setupPalette(colors, start, num, true); }
|
||||
void makeTranslucent(Graphics::Surface &dst, const Graphics::Surface &src) const override;
|
||||
|
||||
bool displayToolbar(const Graphics::Surface *original) override { return _toolbar.displayToolbar(original); };
|
||||
bool hasPlaceDocumentation() override;
|
||||
bool displayPlaceDocumentation() override;
|
||||
uint displayOptions() override;
|
||||
bool shouldAbort() override;
|
||||
|
||||
private:
|
||||
void setupFonts();
|
||||
void setupSprites();
|
||||
void loadCursorsPalette();
|
||||
void calculateTransparentMapping();
|
||||
void setupObjects();
|
||||
void setupDialogVariables();
|
||||
void setupImgScripts();
|
||||
void loadStaticData();
|
||||
|
||||
void syncOmni3DSettings();
|
||||
void syncSoundSettings() override;
|
||||
|
||||
void playTransitionEndLevel(int level);
|
||||
void changeLevel(int level);
|
||||
void initNewLevel(int level);
|
||||
void setupLevelWarps(int level);
|
||||
void initPlacesStates();
|
||||
void initWhoSpeaksWhere();
|
||||
void initDocPeopleRecord();
|
||||
void setupLevelActionsMask();
|
||||
|
||||
uint currentGameTime() const { return _gameVariables[GameVariables::kCurrentTime]; }
|
||||
void setGameTime(uint newTime, uint level);
|
||||
void updateGameTimeDialVariables();
|
||||
|
||||
void gameStep();
|
||||
void doGameOver();
|
||||
|
||||
void setPlaceState(uint placeId, uint newState);
|
||||
void doPlaceChange();
|
||||
void executeTransition(uint nextPlaceId);
|
||||
void fakeTransition(uint dstPlaceId);
|
||||
uint determineTransitionAnimation(uint srcId, uint dstId,
|
||||
const Transition **transition);
|
||||
|
||||
uint getFakeTransition(uint actionId) const;
|
||||
void fixActionId(uint *actionId) const;
|
||||
|
||||
int handleWarp();
|
||||
bool handleWarpMouse(uint *actionId, uint movingCuror);
|
||||
void animateWarpTransition(const Transition *transition);
|
||||
void redrawWarp();
|
||||
|
||||
void handleFixedImg(const FixedImgCallback &callback);
|
||||
void executeSeeAction(uint actionId);
|
||||
|
||||
void executeSpeakAction(uint actionId);
|
||||
void setupDialogShows();
|
||||
bool preprocessDialog(const Common::String &sequence);
|
||||
void postprocessDialog(const Common::String &sequence);
|
||||
|
||||
void executeDocAction(uint actionId);
|
||||
|
||||
void drawMenuTitle(Graphics::ManagedSurface *surface, byte color);
|
||||
uint displayFilePicker(const Graphics::Surface *bgFrame, bool saveMode,
|
||||
Common::String &saveName);
|
||||
uint displayYesNoBox(Graphics::ManagedSurface &surface, const Common::Rect &position,
|
||||
uint msg_id);
|
||||
void displayMessageBox(const MsgBoxParameters ¶ms, const Graphics::Surface *surface,
|
||||
uint msg_id, const Common::Point &position,
|
||||
const Common::Functor0<void> &callback) { displayMessageBox(params, surface, _messages[msg_id], position, callback); }
|
||||
void displayMessageBox(const MsgBoxParameters ¶ms, const Graphics::Surface *surface,
|
||||
const Common::String &msg, const Common::Point &position,
|
||||
const Common::Functor0<void> &callback);
|
||||
void displayMessageBoxWarp(const Common::String &message);
|
||||
void displayMessageBoxWarp(uint msg_id) { displayMessageBoxWarp(_messages[msg_id]); }
|
||||
void displayCredits();
|
||||
|
||||
void warpMsgBoxCB();
|
||||
|
||||
bool canVisit() const;
|
||||
Common::String getSaveFileName(bool visit, uint saveNum) const;
|
||||
void getSavesList(bool visit, Common::Array<Common::String> &saveNames, int &nextSaveNum);
|
||||
void saveGame(bool visit, uint saveNum, const Common::String &saveName);
|
||||
bool loadGame(bool visit, uint saveNum);
|
||||
|
||||
void animateCursor(const Object *object);
|
||||
void collectObject(Object *object, const ZonFixedImage *fimg = nullptr,
|
||||
bool showObject = true);
|
||||
void collectObject(uint nameID, const ZonFixedImage *fimg = nullptr,
|
||||
bool showObject = true) { collectObject(_objects.findObjectByNameID(nameID), fimg, showObject); }
|
||||
typedef void (CryOmni3DEngine_Versailles::*DisplayObjectHook)(Graphics::ManagedSurface &surface);
|
||||
void displayObject(const Common::String &imgName, DisplayObjectHook hook = nullptr);
|
||||
|
||||
void setMainPaletteColor(byte color, byte red, byte green, byte blue);
|
||||
void setupPalette(const byte *colors, uint start, uint num, bool commit);
|
||||
|
||||
bool showSubtitles() const;
|
||||
|
||||
void playInGameAnimVideo(const Common::String &filename) {
|
||||
playInGameVideo(getFilePath(kFileTypeAnimacti, filename));
|
||||
}
|
||||
void playInGameVideo(const Common::Path &filename, bool restoreCursorPalette = true);
|
||||
void playSubtitledVideo(const Common::String &filename);
|
||||
|
||||
void loadBMPs(const char *pattern, Graphics::Surface *bmps, uint count);
|
||||
|
||||
uint getMusicId(uint level, uint placeId) const;
|
||||
bool musicWouldChange(uint level, uint placeId) const;
|
||||
void musicUpdate();
|
||||
void musicPause();
|
||||
void musicResume();
|
||||
void musicStop();
|
||||
void musicSetQuiet(bool quiet);
|
||||
|
||||
Common::StringArray _localizedFilenames;
|
||||
Common::StringArray _messages;
|
||||
static const uint kSpritesMapTable[];
|
||||
static const uint kSpritesMapTableSize;
|
||||
static const LevelInitialState kLevelInitialStates[];
|
||||
static const FakeTransitionActionPlace kFakeTransitions[];
|
||||
Common::HashMap<uint, FixedImgCallback> _imgScripts;
|
||||
Common::Array<Common::String> _paintingsTitles;
|
||||
|
||||
Toolbar _toolbar;
|
||||
|
||||
byte *_mainPalette;
|
||||
byte *_cursorPalette;
|
||||
bool _fadedPalette;
|
||||
bool _forcePaletteUpdate;
|
||||
bool _forceRedrawWarp;
|
||||
|
||||
byte *_transparentPaletteMap;
|
||||
uint _transparentSrcStart;
|
||||
uint _transparentSrcStop;
|
||||
uint _transparentDstStart;
|
||||
uint _transparentDstStop;
|
||||
uint _transparentNewStart;
|
||||
uint _transparentNewStop;
|
||||
|
||||
bool _isPlaying;
|
||||
bool _isVisiting;
|
||||
AbortCommand _abortCommand;
|
||||
uint _loadedSave;
|
||||
|
||||
int _omni3dSpeed;
|
||||
|
||||
uint _currentLevel;
|
||||
Versailles_DialogsManager _dialogsMan;
|
||||
|
||||
Omni3DManager _omni3dMan;
|
||||
ZonFixedImage *_fixedImage;
|
||||
|
||||
Common::Array<uint> _gameVariables;
|
||||
Common::Array<PlaceState> _placeStates;
|
||||
Common::HashMap<PlaceStateActionKey, uint> _actionMasks;
|
||||
Common::HashMap<PlaceActionKey, Common::String> _whoSpeaksWhere;
|
||||
Common::HashMap<uint, const char *> _docPeopleRecord;
|
||||
bool _transitionAnimateWarp;
|
||||
uint _nextPlaceId;
|
||||
WAMParser _wam;
|
||||
uint _currentPlaceId;
|
||||
const Place *_currentPlace;
|
||||
const Image::ImageDecoder *_currentWarpImage;
|
||||
|
||||
const char *_musicCurrentFile;
|
||||
Audio::SoundHandle _musicHandle;
|
||||
float _musicVolumeFactor;
|
||||
static const char *kMusicFiles[8][8];
|
||||
|
||||
Versailles_Documentation _docManager;
|
||||
|
||||
static const MsgBoxParameters kWarpMsgBoxParameters;
|
||||
static const MsgBoxParameters kFixedimageMsgBoxParameters;
|
||||
static const FixedImageConfiguration kFixedImageConfiguration;
|
||||
|
||||
// Countdown
|
||||
void initCountdown();
|
||||
void syncCountdown();
|
||||
inline bool countDown() { if (_countingDown) { return doCountDown(); } else { return false; } }
|
||||
inline void drawCountdown(Graphics::ManagedSurface *surface = nullptr) { if (_countingDown) { doDrawCountdown(surface); } }
|
||||
void drawCountdownVideo(uint frameNum) { drawCountdown(); }
|
||||
|
||||
bool _countingDown;
|
||||
uint _countdownNextEvent;
|
||||
char _countdownValue[6];
|
||||
Graphics::ManagedSurface _countdownSurface;
|
||||
bool doCountDown();
|
||||
void doDrawCountdown(Graphics::ManagedSurface *surface);
|
||||
|
||||
// Video subtitles
|
||||
Common::HashMap<Common::String, Common::Array<SubtitleEntry> > _subtitles;
|
||||
const Common::Array<SubtitleEntry> *_currentSubtitleSet;
|
||||
Common::Array<SubtitleEntry>::const_iterator _currentSubtitle;
|
||||
void drawVideoSubtitles(uint frameNum);
|
||||
|
||||
// Objects
|
||||
template<uint ID>
|
||||
void genericDisplayObject();
|
||||
void obj_105();
|
||||
void obj_106();
|
||||
void obj_107();
|
||||
void obj_118();
|
||||
void obj_121();
|
||||
void obj_125();
|
||||
void obj_126();
|
||||
void obj_126hk(Graphics::ManagedSurface &surface);
|
||||
void obj_129();
|
||||
void obj_129hk(Graphics::ManagedSurface &surface);
|
||||
void obj_142();
|
||||
void obj_142hk(Graphics::ManagedSurface &surface);
|
||||
|
||||
// Fixed image
|
||||
template<uint ID>
|
||||
void genericDumbImage(ZonFixedImage *fimg);
|
||||
template<uint ID>
|
||||
void genericPainting(ZonFixedImage *fimg);
|
||||
#define IMG_CB(name) void img_ ## name(ZonFixedImage *fimg)
|
||||
IMG_CB(31101);
|
||||
IMG_CB(31101b);
|
||||
IMG_CB(31142);
|
||||
IMG_CB(31142b);
|
||||
IMG_CB(31142c);
|
||||
IMG_CB(31142d);
|
||||
IMG_CB(31143);
|
||||
IMG_CB(31143b);
|
||||
IMG_CB(31143c);
|
||||
IMG_CB(31143d);
|
||||
IMG_CB(32120);
|
||||
IMG_CB(32120b);
|
||||
IMG_CB(32120c);
|
||||
IMG_CB(32201);
|
||||
IMG_CB(32202);
|
||||
IMG_CB(32203);
|
||||
IMG_CB(32204);
|
||||
IMG_CB(32204b);
|
||||
IMG_CB(34131);
|
||||
IMG_CB(34132);
|
||||
IMG_CB(34172);
|
||||
IMG_CB(34173);
|
||||
IMG_CB(34173b);
|
||||
IMG_CB(34173c);
|
||||
IMG_CB(34174);
|
||||
IMG_CB(34174b);
|
||||
IMG_CB(34174c);
|
||||
IMG_CB(34174d);
|
||||
IMG_CB(34174e);
|
||||
IMG_CB(34174f);
|
||||
static const uint kSafeDigitsCount = 12;
|
||||
static const uint16 kSafeDigitsX[];
|
||||
static const uint16 kSafeDigitsY[];
|
||||
static const char *kSafeDates[];
|
||||
bool handleSafe(ZonFixedImage *fimg);
|
||||
void drawSafeDigits(Graphics::ManagedSurface &surface, const Graphics::Surface(&bmpDigits)[10],
|
||||
const unsigned char (&safeDigits)[kSafeDigitsCount]);
|
||||
bool checkSafeDigits(unsigned char (&safeDigits)[kSafeDigitsCount]);
|
||||
|
||||
IMG_CB(41202);
|
||||
IMG_CB(41202b);
|
||||
IMG_CB(41801);
|
||||
IMG_CB(41801b);
|
||||
IMG_CB(41801c);
|
||||
IMG_CB(41802);
|
||||
IMG_CB(41802b);
|
||||
IMG_CB(41802c);
|
||||
IMG_CB(41802d);
|
||||
IMG_CB(43143);
|
||||
IMG_CB(43143b);
|
||||
IMG_CB(43145);
|
||||
IMG_CB(43145b);
|
||||
IMG_CB(43145c);
|
||||
IMG_CB(43146);
|
||||
IMG_CB(43146b);
|
||||
IMG_CB(43146c);
|
||||
IMG_CB(43160);
|
||||
IMG_CB(43160b);
|
||||
IMG_CB(43160c);
|
||||
IMG_CB(43160d);
|
||||
IMG_CB(43190);
|
||||
IMG_CB(43190b);
|
||||
IMG_CB(43190c);
|
||||
IMG_CB(43190d);
|
||||
IMG_CB(43190e);
|
||||
IMG_CB(43190f);
|
||||
IMG_CB(44071);
|
||||
IMG_CB(44071b);
|
||||
IMG_CB(44161);
|
||||
IMG_CB(44161b);
|
||||
IMG_CB(44161c);
|
||||
IMG_CB(44161d);
|
||||
IMG_CB(44161e);
|
||||
IMG_CB(44161f);
|
||||
static const uint kEpigraphMaxLetters = 32;
|
||||
Common::String _epigraphContent;
|
||||
Common::String _epigraphPassword;
|
||||
bool handleEpigraph(ZonFixedImage *fimg);
|
||||
void drawEpigraphLetters(Graphics::ManagedSurface &surface,
|
||||
const Graphics::Surface(&bmpLetters)[28], const Common::String &letters);
|
||||
IMG_CB(45130);
|
||||
IMG_CB(45270);
|
||||
IMG_CB(45270b);
|
||||
IMG_CB(45270c);
|
||||
IMG_CB(45270d);
|
||||
IMG_CB(45280);
|
||||
|
||||
IMG_CB(88001);
|
||||
IMG_CB(88001b);
|
||||
IMG_CB(88001c);
|
||||
IMG_CB(88002);
|
||||
IMG_CB(88003);
|
||||
IMG_CB(88003b);
|
||||
IMG_CB(88003c);
|
||||
IMG_CB(88003d);
|
||||
IMG_CB(88003e);
|
||||
IMG_CB(88003f);
|
||||
Common::U32String _bombAlphabet; // For Japanese edition
|
||||
Common::U32String _bombPassword;
|
||||
static const uint kBombPasswordSmallLength = 40;
|
||||
static const uint kBombPasswordMaxLength = 60;
|
||||
static const uint16 kBombLettersPos[2][kBombPasswordMaxLength][2];
|
||||
bool handleBomb(ZonFixedImage *fimg);
|
||||
void handleBombTranslation(Graphics::ManagedSurface &surface);
|
||||
void drawBombLetters(Graphics::ManagedSurface &surface, const Graphics::Surface(&bmpLetters)[28],
|
||||
const uint bombPasswordLength,
|
||||
const uint32(&bombPossibilites)[kBombPasswordMaxLength][5],
|
||||
const byte(&bombCurrentLetters)[kBombPasswordMaxLength]);
|
||||
IMG_CB(88004);
|
||||
IMG_CB(88004b);
|
||||
#undef IMG_CB
|
||||
|
||||
#define FILTER_EVENT(level, place) bool filterEventLevel ## level ## Place ## place(uint *event)
|
||||
#define INIT_PLACE(level, place) void initPlaceLevel ## level ## Place ## place()
|
||||
FILTER_EVENT(1, 1);
|
||||
FILTER_EVENT(1, 2);
|
||||
INIT_PLACE(1, 3);
|
||||
FILTER_EVENT(1, 3);
|
||||
//FILTER_EVENT(1, 7); // Not used
|
||||
FILTER_EVENT(1, 14);
|
||||
|
||||
FILTER_EVENT(2, 1);
|
||||
FILTER_EVENT(2, 2);
|
||||
FILTER_EVENT(2, 5);
|
||||
INIT_PLACE(2, 9);
|
||||
FILTER_EVENT(2, 9);
|
||||
FILTER_EVENT(2, 11);
|
||||
FILTER_EVENT(2, 12);
|
||||
FILTER_EVENT(2, 14);
|
||||
|
||||
FILTER_EVENT(3, 3);
|
||||
FILTER_EVENT(3, 10);
|
||||
FILTER_EVENT(3, 13);
|
||||
FILTER_EVENT(3, 15);
|
||||
FILTER_EVENT(3, 17);
|
||||
FILTER_EVENT(3, 18);
|
||||
FILTER_EVENT(3, 19);
|
||||
FILTER_EVENT(3_5, 20);
|
||||
FILTER_EVENT(3, 22);
|
||||
FILTER_EVENT(3, 23);
|
||||
bool filterEventLevel3Obj23151();
|
||||
void collectLampoonArchitecture(const ZonFixedImage *fimg = nullptr);
|
||||
|
||||
INIT_PLACE(4, 9);
|
||||
FILTER_EVENT(4, 10);
|
||||
FILTER_EVENT(4, 12_13_14);
|
||||
FILTER_EVENT(4, 15);
|
||||
FILTER_EVENT(4, 16);
|
||||
FILTER_EVENT(4, 17);
|
||||
|
||||
INIT_PLACE(5, 6);
|
||||
FILTER_EVENT(5, 9);
|
||||
FILTER_EVENT(5, 14);
|
||||
FILTER_EVENT(5, 15);
|
||||
FILTER_EVENT(5, 16);
|
||||
void filterEventLevel5UpdatePlaceStates();
|
||||
//FILTER_EVENT(3_5, 20);
|
||||
FILTER_EVENT(5, 23);
|
||||
FILTER_EVENT(5, 27);
|
||||
FILTER_EVENT(5, 28);
|
||||
FILTER_EVENT(5, 29);
|
||||
FILTER_EVENT(5, 33);
|
||||
FILTER_EVENT(5, 34);
|
||||
|
||||
FILTER_EVENT(6, 1);
|
||||
FILTER_EVENT(6, 3);
|
||||
FILTER_EVENT(6, Orangery);
|
||||
FILTER_EVENT(6, 19);
|
||||
|
||||
FILTER_EVENT(7, 2);
|
||||
FILTER_EVENT(7, 9);
|
||||
FILTER_EVENT(7, 10_11_13);
|
||||
FILTER_EVENT(7, 20);
|
||||
#undef FILTER_EVENT
|
||||
#undef INIT_PLACE
|
||||
|
||||
// Dialogs shows
|
||||
void dialogShowBontempsShowThird();
|
||||
void dialogShowHuissierShowPamphlet();
|
||||
void dialogShowMonseigneurSorts();
|
||||
void dialogShowLeBrunWatches();
|
||||
void dialogShowDoorsOpen();
|
||||
void dialogShowSwissGuardGives();
|
||||
void dialogShowLullyCorrects();
|
||||
void dialogShowBontempsGivesAuth();
|
||||
void dialogShowCroissyLeave();
|
||||
void dialogShowMaintenonGives();
|
||||
void dialogShowLaChaizeGivesBack();
|
||||
void dialogShowLaChaizeWrites();
|
||||
void dialogShowLaChaizeGivesPamphlet();
|
||||
void dialogShowBontempsGivesKey();
|
||||
void dialogShowDuMaineLeaves();
|
||||
void dialogShowTransitionScene();
|
||||
void dialogShowEndOfGame();
|
||||
void dialogShowLeBrunGives();
|
||||
void dialogShowLeBrunLeave();
|
||||
};
|
||||
|
||||
} // End of namespace Versailles
|
||||
} // End of namespace CryOmni3D
|
||||
|
||||
#endif
|
||||
4852
engines/cryomni3d/versailles/logic.cpp
Normal file
4852
engines/cryomni3d/versailles/logic.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1148
engines/cryomni3d/versailles/menus.cpp
Normal file
1148
engines/cryomni3d/versailles/menus.cpp
Normal file
File diff suppressed because it is too large
Load Diff
280
engines/cryomni3d/versailles/music.cpp
Normal file
280
engines/cryomni3d/versailles/music.cpp
Normal file
@@ -0,0 +1,280 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "audio/audiostream.h"
|
||||
#include "audio/decoders/wave.h"
|
||||
|
||||
#include "common/config-manager.h"
|
||||
#include "common/error.h"
|
||||
#include "common/file.h"
|
||||
#include "common/system.h"
|
||||
|
||||
#include "cryomni3d/versailles/engine.h"
|
||||
|
||||
namespace CryOmni3D {
|
||||
namespace Versailles {
|
||||
|
||||
const char *CryOmni3DEngine_Versailles::kMusicFiles[8][8] = {
|
||||
{ "1amb", }, // Level 1
|
||||
{ "2amb", "2amb2", "2amb1" }, // Level 2
|
||||
{ "3amb", "3amb1", "3amb2" }, // Level 3
|
||||
{ "4amb", "4amb1" }, // Level 4
|
||||
{ "5amb1", "5amb2" }, // Level 5
|
||||
{ "6amb1", "6amb2", "6amb3", "6amb4" }, // Level 6
|
||||
{ "7amb", }, // Level 7
|
||||
{ "3amb", "3amb1", "3amb2", "2amb", "2amb1", "2amb2", "4amb" }, // Level 8
|
||||
};
|
||||
|
||||
void CryOmni3DEngine_Versailles::musicUpdate() {
|
||||
if (!_isPlaying || _currentLevel <= 0 ||
|
||||
_mixer->isSoundTypeMuted(Audio::Mixer::kMusicSoundType) ||
|
||||
_mixer->getVolumeForSoundType(Audio::Mixer::kMusicSoundType) == 0) {
|
||||
// No music in all of these cases
|
||||
musicStop();
|
||||
return;
|
||||
}
|
||||
|
||||
uint musicId = getMusicId(_currentLevel, _currentPlaceId);
|
||||
const char *musicBName = kMusicFiles[_currentLevel - 1][musicId];
|
||||
assert(musicBName != nullptr);
|
||||
|
||||
// Ensure sound is playing in all cases
|
||||
musicResume();
|
||||
|
||||
if (musicBName == _musicCurrentFile) {
|
||||
// Same file, nothing more to do
|
||||
return;
|
||||
}
|
||||
|
||||
// New file, stop the old one first
|
||||
musicStop();
|
||||
|
||||
Common::Path musicPath(getFilePath(kFileTypeMusic, musicBName));
|
||||
|
||||
Common::File *musicFile = new Common::File();
|
||||
if (!musicFile->open(musicPath)) {
|
||||
warning("Failed to open music file %s/%s", musicBName, musicPath.toString(Common::Path::kNativeSeparator).c_str());
|
||||
delete musicFile;
|
||||
return;
|
||||
}
|
||||
|
||||
Audio::SeekableAudioStream *musicDecoder = Audio::makeWAVStream(musicFile, DisposeAfterUse::YES);
|
||||
// We lost ownership of the musicFile just set it to nullptr and don't use it
|
||||
musicFile = nullptr;
|
||||
|
||||
if (!musicDecoder) {
|
||||
warning("Failed to decode music file %s/%s", musicBName, musicPath.toString(Common::Path::kNativeSeparator).c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
Audio::AudioStream *loopStream = Audio::makeLoopingAudioStream(musicDecoder, 0);
|
||||
// We lost ownership of musicDecoder just set it to nullptr and don't use it
|
||||
musicDecoder = nullptr;
|
||||
|
||||
_mixer->playStream(Audio::Mixer::kMusicSoundType, &_musicHandle, loopStream);
|
||||
_musicCurrentFile = musicBName;
|
||||
}
|
||||
|
||||
void CryOmni3DEngine_Versailles::musicPause() {
|
||||
_mixer->pauseHandle(_musicHandle, true);
|
||||
}
|
||||
|
||||
void CryOmni3DEngine_Versailles::musicResume() {
|
||||
_mixer->pauseHandle(_musicHandle, false);
|
||||
}
|
||||
|
||||
void CryOmni3DEngine_Versailles::musicStop() {
|
||||
// Fade the music first
|
||||
if (_mixer->isSoundHandleActive(_musicHandle)) {
|
||||
// We recreate the real channel volume to decrease this one 2 by 2
|
||||
int musicVol = _mixer->getVolumeForSoundType(Audio::Mixer::kMusicSoundType);
|
||||
byte channelVol = _mixer->getChannelVolume(_musicHandle);
|
||||
int realVolume = (musicVol * channelVol) / Audio::Mixer::kMaxChannelVolume;
|
||||
bool skip = false;
|
||||
while (realVolume > 0 && !skip) {
|
||||
realVolume -= 2;
|
||||
channelVol = CLIP((realVolume * Audio::Mixer::kMaxChannelVolume) / musicVol, 0, 255);
|
||||
_mixer->setChannelVolume(_musicHandle, channelVol);
|
||||
if (pollEvents() && checkKeysPressed(1, Common::KEYCODE_SPACE)) {
|
||||
skip = true;
|
||||
}
|
||||
g_system->delayMillis(10);
|
||||
}
|
||||
}
|
||||
_mixer->stopHandle(_musicHandle);
|
||||
_musicCurrentFile = nullptr;
|
||||
}
|
||||
|
||||
void CryOmni3DEngine_Versailles::musicSetQuiet(bool quiet) {
|
||||
float newFactor = quiet ? 3.5f : 1.f;
|
||||
if (newFactor != _musicVolumeFactor) {
|
||||
_musicVolumeFactor = newFactor;
|
||||
syncSoundSettings();
|
||||
}
|
||||
}
|
||||
|
||||
bool CryOmni3DEngine_Versailles::musicWouldChange(uint level, uint placeId) const {
|
||||
uint musicId = getMusicId(level, placeId);
|
||||
const char *musicFile = kMusicFiles[_currentLevel - 1][musicId];
|
||||
|
||||
return musicFile != _musicCurrentFile;
|
||||
}
|
||||
|
||||
uint CryOmni3DEngine_Versailles::getMusicId(uint level,
|
||||
uint placeId) const {
|
||||
// No need of place state
|
||||
switch (level) {
|
||||
case 1:
|
||||
// Only one music
|
||||
return 0;
|
||||
case 2:
|
||||
switch (placeId) {
|
||||
case 4:
|
||||
return 1;
|
||||
case 10:
|
||||
case 11:
|
||||
case 13:
|
||||
return 2;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
case 3:
|
||||
switch (placeId) {
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
return 2;
|
||||
case 6:
|
||||
case 7:
|
||||
case 8:
|
||||
case 12:
|
||||
case 24:
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
case 4:
|
||||
switch (placeId) {
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
case 5:
|
||||
switch (placeId) {
|
||||
case 6:
|
||||
case 7:
|
||||
case 8:
|
||||
case 12:
|
||||
case 26:
|
||||
case 27:
|
||||
case 30:
|
||||
case 31:
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
case 6:
|
||||
switch (placeId) {
|
||||
case 1:
|
||||
return 3;
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
case 8:
|
||||
case 9:
|
||||
case 10:
|
||||
case 11:
|
||||
return 0;
|
||||
case 14:
|
||||
case 16:
|
||||
case 17:
|
||||
case 19:
|
||||
case 20:
|
||||
case 22:
|
||||
case 24:
|
||||
case 26:
|
||||
case 27:
|
||||
case 32:
|
||||
case 34:
|
||||
case 38:
|
||||
case 44:
|
||||
return 2;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
case 7:
|
||||
return 0;
|
||||
case 8:
|
||||
switch (placeId) {
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
return 2;
|
||||
case 6:
|
||||
case 7:
|
||||
case 8:
|
||||
return 1;
|
||||
case 9:
|
||||
case 10:
|
||||
case 11:
|
||||
return 0;
|
||||
case 12:
|
||||
return 1;
|
||||
case 13:
|
||||
case 14:
|
||||
case 15:
|
||||
case 16:
|
||||
return 0;
|
||||
case 24:
|
||||
return 1;
|
||||
case 33:
|
||||
case 34:
|
||||
case 35:
|
||||
return 5;
|
||||
case 36:
|
||||
case 37:
|
||||
case 38:
|
||||
case 39:
|
||||
return 3;
|
||||
case 40:
|
||||
return 4;
|
||||
case 42:
|
||||
case 43:
|
||||
case 44:
|
||||
return 6;
|
||||
default:
|
||||
return 0;
|
||||
|
||||
}
|
||||
default:
|
||||
error("Invalid level %d when choosing music", level);
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Versailles
|
||||
} // End of namespace CryOmni3D
|
||||
337
engines/cryomni3d/versailles/saveload.cpp
Normal file
337
engines/cryomni3d/versailles/saveload.cpp
Normal file
@@ -0,0 +1,337 @@
|
||||
/* 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/archive.h"
|
||||
#include "common/config-manager.h"
|
||||
#include "common/file.h"
|
||||
#include "common/savefile.h"
|
||||
#include "common/system.h"
|
||||
|
||||
#include "cryomni3d/versailles/engine.h"
|
||||
|
||||
namespace CryOmni3D {
|
||||
namespace Versailles {
|
||||
|
||||
Common::Error CryOmni3DEngine_Versailles::loadGameState(int slot) {
|
||||
_loadedSave = slot + 1;
|
||||
_abortCommand = kAbortLoadGame;
|
||||
return Common::kNoError;
|
||||
}
|
||||
|
||||
Common::Error CryOmni3DEngine_Versailles::saveGameState(int slot, const Common::String &desc, bool isAutosave) {
|
||||
saveGame(_isVisiting, slot + 1, desc);
|
||||
return Common::kNoError;
|
||||
}
|
||||
|
||||
Common::String CryOmni3DEngine_Versailles::getSaveFileName(bool visit, uint saveNum) const {
|
||||
return Common::String::format("%s%s.%04u", _targetName.c_str(), visit ? "_visit" : "", saveNum);
|
||||
}
|
||||
|
||||
Common::String CryOmni3DEngine_Versailles::getSaveStateName(int slot) const {
|
||||
return Common::String::format("%s.%04u", _targetName.c_str(), slot);
|
||||
}
|
||||
|
||||
bool CryOmni3DEngine_Versailles::canVisit() const {
|
||||
return Common::File::exists(getFilePath(kFileTypeSaveGameVisit, "game0001.sav"));
|
||||
}
|
||||
|
||||
void CryOmni3DEngine_Versailles::getSavesList(bool visit, Common::StringArray &saveNames,
|
||||
int &nextSaveNum) {
|
||||
nextSaveNum = 1;
|
||||
bool supportsAutoName = (_messages.size() >= 148);
|
||||
|
||||
char saveName[kSaveDescriptionLen + 1];
|
||||
// Terminate saveName here forever (we don't overrun kSaveDescriptionLen)
|
||||
saveName[kSaveDescriptionLen] = '\0';
|
||||
Common::String pattern = Common::String::format("%s%s.####", _targetName.c_str(),
|
||||
visit ? "_visit" : "");
|
||||
Common::StringArray filenames = _saveFileMan->listSavefiles(pattern);
|
||||
sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..)
|
||||
|
||||
saveNames.clear();
|
||||
saveNames.reserve(100);
|
||||
|
||||
int num = 1;
|
||||
int slotNum;
|
||||
|
||||
if (visit) {
|
||||
// Add bootstrap visit
|
||||
Common::Path visitPath(getFilePath(kFileTypeSaveGameVisit, "game0001.sav"));
|
||||
Common::File visitFile;
|
||||
if (visitFile.open(visitPath)) {
|
||||
visitFile.read(saveName, kSaveDescriptionLen);
|
||||
saveNames.push_back(saveName);
|
||||
} else {
|
||||
warning("visiting mode but no bootstrap");
|
||||
// No bootstrap visit, too bad
|
||||
saveNames.push_back(_messages[55]); //Fill with free slot
|
||||
}
|
||||
num++;
|
||||
}
|
||||
|
||||
for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end();
|
||||
++file) {
|
||||
// Obtain the last 4 digits of the filename, since they correspond to the save slot
|
||||
slotNum = atoi(file->c_str() + file->size() - 4);
|
||||
|
||||
if (slotNum >= 1 && slotNum <= 99) {
|
||||
while (num < slotNum) {
|
||||
saveNames.push_back(_messages[55]); //Fill with free slot
|
||||
num++;
|
||||
}
|
||||
|
||||
num++;
|
||||
Common::InSaveFile *in = _saveFileMan->openForLoading(*file);
|
||||
if (in) {
|
||||
if (in->read(saveName, kSaveDescriptionLen) != kSaveDescriptionLen) {
|
||||
warning("getSavesList(): Corrupted save %s", saveName);
|
||||
delete in;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
Common::String saveNameStr = saveName;
|
||||
if (supportsAutoName && saveNameStr.hasPrefix("AUTO")) {
|
||||
int saveNum = atoi(saveName + 4);
|
||||
if (saveNum >= 1 && saveNum <= 9999) {
|
||||
in->seek(436); // Go to current level
|
||||
uint32 level = in->readUint32BE();
|
||||
|
||||
if (level < 8) {
|
||||
saveNameStr = Common::String::format(_messages[146].c_str(), level);
|
||||
} else {
|
||||
saveNameStr = _messages[147];
|
||||
}
|
||||
saveNameStr += Common::String::format(" - %d", saveNum);
|
||||
if (saveNum >= nextSaveNum) {
|
||||
if (saveNum >= 9999) {
|
||||
nextSaveNum = 9999;
|
||||
} else {
|
||||
nextSaveNum = saveNum + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
saveNames.push_back(saveNameStr);
|
||||
delete in;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (uint i = saveNames.size(); i < 100; i++) {
|
||||
saveNames.push_back(_messages[55]);
|
||||
}
|
||||
}
|
||||
|
||||
void CryOmni3DEngine_Versailles::saveGame(bool visit, uint saveNum,
|
||||
const Common::String &saveName) {
|
||||
if (visit && saveNum == 1) {
|
||||
error("Can't erase bootstrap visit");
|
||||
}
|
||||
|
||||
Common::String saveFileName = getSaveFileName(visit, saveNum);
|
||||
|
||||
Common::OutSaveFile *out;
|
||||
|
||||
if (!(out = _saveFileMan->openForSaving(saveFileName))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Sync countdown to game variable before saving it to file
|
||||
syncCountdown();
|
||||
|
||||
// Write save name
|
||||
|
||||
// Allocate one more byte to silence GCC warning
|
||||
// The save name doesn't have to be null terminated in the save file
|
||||
char saveNameC[kSaveDescriptionLen + 1];
|
||||
memset(saveNameC, 0, sizeof(saveNameC));
|
||||
strncpy(saveNameC, saveName.c_str(), kSaveDescriptionLen);
|
||||
out->write(saveNameC, kSaveDescriptionLen);
|
||||
|
||||
// dummy values
|
||||
out->writeUint32LE(0);
|
||||
out->writeUint32BE(0);
|
||||
out->writeUint32BE(0);
|
||||
|
||||
// Dialog variables
|
||||
assert(_dialogsMan.size() < 200);
|
||||
for (uint i = 0; i < _dialogsMan.size(); i++) {
|
||||
out->writeByte(_dialogsMan[i]);
|
||||
}
|
||||
for (uint i = _dialogsMan.size(); i < 200; i++) {
|
||||
out->writeByte(0);
|
||||
}
|
||||
|
||||
// Inventory
|
||||
assert(_inventory.size() == 50);
|
||||
for (Inventory::const_iterator it = _inventory.begin(); it != _inventory.end(); it++) {
|
||||
uint objId = uint(-1);
|
||||
if (*it != nullptr) {
|
||||
// Inventory contains pointers to objects stored in _objects
|
||||
objId = *it - _objects.begin();
|
||||
}
|
||||
out->writeUint32BE(objId);
|
||||
}
|
||||
// Offset of inventory in toolbar
|
||||
out->writeUint32BE(_toolbar.inventoryOffset());
|
||||
|
||||
// Level, place, warp position
|
||||
out->writeUint32BE(_currentLevel);
|
||||
out->writeUint32BE(_currentPlaceId);
|
||||
out->writeDoubleBE(_omni3dMan.getAlpha());
|
||||
out->writeDoubleBE(_omni3dMan.getBeta());
|
||||
|
||||
// Places states
|
||||
assert(_placeStates.size() <= 100);
|
||||
Common::Array<PlaceState>::const_iterator placeIt = _placeStates.begin();
|
||||
for (uint i = 0; placeIt != _placeStates.end(); placeIt++, i++) {
|
||||
out->writeUint32BE(placeIt->state);
|
||||
}
|
||||
for (uint i = _placeStates.size(); i < 100; i++) {
|
||||
out->writeUint32BE(0);
|
||||
}
|
||||
|
||||
// Game variables
|
||||
assert(_gameVariables.size() < 100);
|
||||
for (Common::Array<uint>::const_iterator it = _gameVariables.begin();
|
||||
it != _gameVariables.end(); it++) {
|
||||
out->writeUint32BE(*it);
|
||||
}
|
||||
for (uint i = _gameVariables.size(); i < 100; i++) {
|
||||
out->writeUint32BE(0);
|
||||
}
|
||||
|
||||
out->finalize();
|
||||
|
||||
delete out;
|
||||
}
|
||||
|
||||
bool CryOmni3DEngine_Versailles::loadGame(bool visit, uint saveNum) {
|
||||
Common::SeekableReadStream *in;
|
||||
|
||||
if (visit && saveNum == 1) {
|
||||
// Load bootstrap visit
|
||||
Common::File *visitFile = new Common::File();
|
||||
if (!visitFile->open(getFilePath(kFileTypeSaveGameVisit, "game0001.sav"))) {
|
||||
delete visitFile;
|
||||
error("Can't load visit file");
|
||||
}
|
||||
in = visitFile;
|
||||
} else {
|
||||
Common::String saveFileName = getSaveFileName(visit, saveNum);
|
||||
in = _saveFileMan->openForLoading(saveFileName);
|
||||
}
|
||||
|
||||
if (!in || in->size() != 1260) {
|
||||
return false;
|
||||
}
|
||||
|
||||
musicStop();
|
||||
|
||||
// Load save name but don't use it
|
||||
char saveNameC[kSaveDescriptionLen];
|
||||
in->read(saveNameC, sizeof(saveNameC));
|
||||
|
||||
// dummy values
|
||||
(void) in->readUint32LE();
|
||||
(void) in->readUint32BE();
|
||||
(void) in->readUint32BE();
|
||||
|
||||
// Dialog variables
|
||||
assert(_dialogsMan.size() < 200);
|
||||
for (uint i = 0; i < _dialogsMan.size(); i++) {
|
||||
_dialogsMan[i] = in->readByte();
|
||||
}
|
||||
for (uint i = _dialogsMan.size(); i < 200; i++) {
|
||||
// Read the remaining bytes but don't use them
|
||||
(void) in->readByte();
|
||||
}
|
||||
|
||||
// Inventory
|
||||
assert(_inventory.size() == 50);
|
||||
for (Inventory::iterator it = _inventory.begin(); it != _inventory.end(); it++) {
|
||||
uint objId = in->readUint32BE();
|
||||
if (objId >= _objects.size()) {
|
||||
objId = uint(-1);
|
||||
}
|
||||
if (objId != uint(-1)) {
|
||||
*it = _objects.begin() + objId;
|
||||
} else {
|
||||
*it = nullptr;
|
||||
}
|
||||
}
|
||||
// Offset of inventory in toolbar
|
||||
_toolbar.setInventoryOffset(in->readUint32BE());
|
||||
|
||||
// Level, place, warp position
|
||||
_currentLevel = in->readUint32BE();
|
||||
// Use nextPlace to force place move
|
||||
_nextPlaceId = in->readUint32BE();
|
||||
|
||||
// Store alpha and beta for later use
|
||||
double alpha = in->readDoubleBE();
|
||||
double beta = in->readDoubleBE();
|
||||
|
||||
// Places states
|
||||
// Store them and use them once we called initNewLevel, we can't call it before because it needs _gameVariables (and especially kCurrentTime) to be correctly set
|
||||
uint32 placesStates[100];
|
||||
for (uint i = 0; i < 100; i++) {
|
||||
placesStates[i] = in->readUint32BE();
|
||||
}
|
||||
|
||||
// Game variables
|
||||
assert(_gameVariables.size() < 100);
|
||||
for (Common::Array<uint>::iterator it = _gameVariables.begin(); it != _gameVariables.end();
|
||||
it++) {
|
||||
*it = in->readUint32BE();
|
||||
}
|
||||
for (uint i = _gameVariables.size(); i < 100; i++) {
|
||||
// Read the remaining variables but don't use them
|
||||
(void) in->readUint32BE();
|
||||
}
|
||||
|
||||
delete in;
|
||||
|
||||
if (_gameVariables[GameVariables::kCurrentTime] == 0) {
|
||||
_gameVariables[GameVariables::kCurrentTime] = 1;
|
||||
}
|
||||
initCountdown();
|
||||
|
||||
// Everything has been loaded, setup new level
|
||||
// We will set places states and warp coordinates just after that to avoid them from being reset
|
||||
initNewLevel(_currentLevel);
|
||||
|
||||
_omni3dMan.setAlpha(alpha);
|
||||
_omni3dMan.setBeta(beta);
|
||||
|
||||
// _placeStates has just been resized in initNewLevel
|
||||
uint i = 0;
|
||||
for (Common::Array<PlaceState>::iterator placeIt = _placeStates.begin();
|
||||
placeIt != _placeStates.end() && i < ARRAYSIZE(placesStates); placeIt++, i++) {
|
||||
placeIt->state = placesStates[i];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // End of namespace Versailles
|
||||
} // End of namespace CryOmni3D
|
||||
602
engines/cryomni3d/versailles/toolbar.cpp
Normal file
602
engines/cryomni3d/versailles/toolbar.cpp
Normal file
@@ -0,0 +1,602 @@
|
||||
/* 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/system.h"
|
||||
|
||||
#include "cryomni3d/cryomni3d.h"
|
||||
|
||||
#include "cryomni3d/versailles/toolbar.h"
|
||||
|
||||
namespace CryOmni3D {
|
||||
namespace Versailles {
|
||||
|
||||
void Toolbar::init(const Sprites *sprites, FontManager *fontManager,
|
||||
const Common::Array<Common::String> *messages, Inventory *inventory,
|
||||
CryOmni3DEngine *engine) {
|
||||
_sprites = sprites;
|
||||
_fontManager = fontManager;
|
||||
_messages = messages;
|
||||
_inventory = inventory;
|
||||
_engine = engine;
|
||||
|
||||
_bgSurface.create(640, 60, Graphics::PixelFormat::createFormatCLUT8());
|
||||
_destSurface.create(640, 60, Graphics::PixelFormat::createFormatCLUT8());
|
||||
|
||||
// Inventory
|
||||
addZone(51, 56, Common::Point(211, 8), &Toolbar::callbackInventory<0>);
|
||||
addZone(51, 56, Common::Point(258, 8), &Toolbar::callbackInventory<1>);
|
||||
addZone(51, 56, Common::Point(305, 8), &Toolbar::callbackInventory<2>);
|
||||
addZone(51, 56, Common::Point(352, 8), &Toolbar::callbackInventory<3>);
|
||||
addZone(51, 56, Common::Point(399, 8), &Toolbar::callbackInventory<4>);
|
||||
addZone(51, 56, Common::Point(446, 8), &Toolbar::callbackInventory<5>);
|
||||
addZone(51, 56, Common::Point(493, 8), &Toolbar::callbackInventory<6>);
|
||||
addZone(51, 56, Common::Point(540, 8), &Toolbar::callbackInventory<7>);
|
||||
|
||||
// Documentation
|
||||
const Graphics::Cursor &cursorDoc = _sprites->getCursor(133);
|
||||
Common::Point docPos(627 - cursorDoc.getWidth(), 42 - cursorDoc.getHeight());
|
||||
addZone(133, 137, docPos, &Toolbar::callbackDocumentation);
|
||||
|
||||
// Options
|
||||
const Graphics::Cursor &cursorOpt = _sprites->getCursor(225);
|
||||
Common::Point optPos(0, 60 - cursorOpt.getHeight());
|
||||
addZone(225, 225, optPos, &Toolbar::callbackOptions);
|
||||
|
||||
// Previous or next
|
||||
addZone(183, uint16(-1), Common::Point(190, 18), &Toolbar::callbackInventoryPrev);
|
||||
addZone(240, uint16(-1), Common::Point(574, 18), &Toolbar::callbackInventoryNext);
|
||||
// View
|
||||
addZone(142, uint16(-1), Common::Point(158, 12), &Toolbar::callbackViewObject);
|
||||
}
|
||||
|
||||
Toolbar::~Toolbar() {
|
||||
_bgSurface.free();
|
||||
_destSurface.free();
|
||||
}
|
||||
|
||||
void Toolbar::inventoryChanged(uint newPosition) {
|
||||
if (newPosition != uint(-1) && newPosition > _inventoryOffset) {
|
||||
_inventoryOffset = newPosition - 7;
|
||||
}
|
||||
// Refresh
|
||||
updateZones();
|
||||
}
|
||||
|
||||
void Toolbar::addZone(uint16 cursorMainId, uint16 cursorSecondaryId, Common::Point position,
|
||||
ZoneCallback callback) {
|
||||
const Graphics::Cursor &cursorMain = _sprites->getCursor(cursorMainId);
|
||||
Common::Rect rct(cursorMain.getWidth(), cursorMain.getHeight());
|
||||
rct.moveTo(position);
|
||||
|
||||
// By default it's the secondary image
|
||||
Zone zone = { rct, cursorMainId, cursorSecondaryId, callback, true, false };
|
||||
_zones.push_back(zone);
|
||||
}
|
||||
|
||||
Common::Array<Toolbar::Zone>::const_iterator Toolbar::hitTestZones(const Common::Point &mousePos)
|
||||
const {
|
||||
Common::Array<Zone>::const_iterator it;
|
||||
for (it = _zones.begin(); it != _zones.end(); it++) {
|
||||
if (!it->hidden && it->rect.contains(mousePos) && it->callback) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return it;
|
||||
}
|
||||
|
||||
uint Toolbar::captureEvent(const Common::Point &mousePos, uint dragStatus) {
|
||||
uint result = 0;
|
||||
Common::Array<Zone>::const_iterator it = hitTestZones(mousePos);
|
||||
if (it != _zones.end()) {
|
||||
result = (this->*(it->callback))(dragStatus);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void Toolbar::updateZones() {
|
||||
_zones[8].secondary = !_engine->hasPlaceDocumentation();
|
||||
|
||||
Inventory::const_iterator inventoryIt, inventorySelectedIt;
|
||||
if (!_inventoryEnabled) {
|
||||
_inventoryMaxOffset = 0;
|
||||
_inventoryOffset = 0;
|
||||
_zones[10].secondary = true;
|
||||
_zones[11].secondary = true;
|
||||
inventoryIt = _inventory->end();
|
||||
inventorySelectedIt = _inventory->end();
|
||||
} else {
|
||||
_inventoryMaxOffset = 0;
|
||||
// Find an object in inventory after the 8 first
|
||||
for (inventoryIt = _inventory->begin() + 8; inventoryIt != _inventory->end(); inventoryIt++) {
|
||||
if (*inventoryIt != nullptr) {
|
||||
_inventoryMaxOffset = (inventoryIt - _inventory->begin()) - 7;
|
||||
}
|
||||
}
|
||||
_zones[10].secondary = !_inventoryMaxOffset;
|
||||
_zones[11].secondary = !_inventoryMaxOffset;
|
||||
if (_inventoryOffset > _inventoryMaxOffset) {
|
||||
// Clamp inventory offset to its max
|
||||
_inventoryOffset = _inventoryMaxOffset;
|
||||
}
|
||||
inventoryIt = _inventory->begin() + _inventoryOffset;
|
||||
inventorySelectedIt = _inventory->begin() + _inventorySelected;
|
||||
}
|
||||
// Inventory zones are from 0 to 7
|
||||
for (Common::Array<Zone>::iterator zoneIt = _zones.begin(); zoneIt != _zones.begin() + 8;
|
||||
zoneIt++, inventoryIt++) {
|
||||
if (!_inventoryEnabled) {
|
||||
zoneIt->hidden = true;
|
||||
zoneIt->imageMain = 0;
|
||||
zoneIt->imageSecondary = 0;
|
||||
zoneIt->secondary = false;
|
||||
} else if (inventoryIt >= _inventory->end() || *inventoryIt == nullptr) {
|
||||
// Nothing in inventory at this position
|
||||
zoneIt->hidden = false;
|
||||
zoneIt->imageMain = 51;
|
||||
zoneIt->imageSecondary = 56;
|
||||
zoneIt->secondary = true;
|
||||
} else {
|
||||
// Setup inventory icon
|
||||
zoneIt->hidden = false;
|
||||
zoneIt->imageMain = (*inventoryIt)->idCA();
|
||||
zoneIt->imageSecondary = (*inventoryIt)->idCl();
|
||||
zoneIt->secondary = (inventorySelectedIt != inventoryIt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint Toolbar::callbackInventory(uint invId, uint dragStatus) {
|
||||
if (!_inventoryEnabled) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
invId += _inventoryOffset;
|
||||
Object *obj = nullptr;
|
||||
if (invId < _inventory->size()) {
|
||||
obj = (*_inventory)[invId];
|
||||
}
|
||||
if (obj == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!obj->valid()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (dragStatus) {
|
||||
case kDragStatus_Pressed:
|
||||
_inventorySelected = invId;
|
||||
_engine->setCursor(181);
|
||||
_zones[12].secondary = (obj->viewCallback() == nullptr);
|
||||
_inventoryButtonDragging = true;
|
||||
return 1;
|
||||
case kDragStatus_Dragging:
|
||||
if (_inventorySelected == invId) {
|
||||
return 0;
|
||||
}
|
||||
_inventorySelected = invId;
|
||||
_zones[12].secondary = (obj->viewCallback() == nullptr);
|
||||
_inventoryButtonDragging = true;
|
||||
return 1;
|
||||
case kDragStatus_Finished:
|
||||
_engine->setCursor(obj->idSl());
|
||||
_inventory->setSelectedObject(obj);
|
||||
_inventorySelected = invId;
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
uint Toolbar::callbackInventoryPrev(uint dragStatus) {
|
||||
if (!_inventoryEnabled) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (dragStatus == kDragStatus_Pressed && _inventoryOffset > 0) {
|
||||
// Restart auto repeat only if there could be something
|
||||
_engine->setAutoRepeatClick(150);
|
||||
_inventoryOffset--;
|
||||
return 1;
|
||||
}
|
||||
// In any other case we didn't do anything
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint Toolbar::callbackInventoryNext(uint dragStatus) {
|
||||
if (!_inventoryEnabled) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (dragStatus == kDragStatus_Pressed && _inventoryOffset < _inventoryMaxOffset) {
|
||||
_engine->setAutoRepeatClick(150);
|
||||
_inventoryOffset++;
|
||||
return 1;
|
||||
}
|
||||
// In any other case we didn't do anything
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint Toolbar::callbackViewObject(uint dragStatus) {
|
||||
if (!_inventoryEnabled) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
_mouseInViewObject = true;
|
||||
|
||||
if (_inventorySelected == uint(-1)) {
|
||||
// Nothing selected in toolbar
|
||||
return 0;
|
||||
}
|
||||
Inventory::const_iterator inventorySelectedIt = _inventory->begin() + _inventorySelected;
|
||||
Object *selectedObject = *inventorySelectedIt;
|
||||
if (selectedObject == nullptr || selectedObject->viewCallback() == nullptr) {
|
||||
// Nothing to view, the sprite isn't even displayed
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (dragStatus) {
|
||||
case kDragStatus_NoDrag:
|
||||
_backupSelectedObject = selectedObject;
|
||||
_engine->setCursor(181);
|
||||
return 0;
|
||||
case kDragStatus_Pressed:
|
||||
case kDragStatus_Dragging:
|
||||
return 1;
|
||||
case kDragStatus_Finished:
|
||||
// Just clicked
|
||||
_engine->showMouse(false);
|
||||
(*selectedObject->viewCallback())();
|
||||
_engine->showMouse(true);
|
||||
_parentMustRedraw = true;
|
||||
_shortExit = true;
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint Toolbar::callbackOptions(uint dragStatus) {
|
||||
_mouseInOptions = true;
|
||||
|
||||
switch (dragStatus) {
|
||||
case kDragStatus_NoDrag:
|
||||
_backupSelectedObject = _inventory->selectedObject();
|
||||
_engine->setCursor(181);
|
||||
return 0;
|
||||
case kDragStatus_Pressed:
|
||||
case kDragStatus_Dragging:
|
||||
// Nothing to do, we wait release
|
||||
return 0;
|
||||
case kDragStatus_Finished:
|
||||
// Just clicked
|
||||
_engine->displayOptions();
|
||||
_parentMustRedraw = true;
|
||||
_shortExit = true;
|
||||
_engine->setMousePos(Common::Point(320, 240)); // Center of screen
|
||||
// Displaying options hides the mouse
|
||||
_engine->showMouse(true);
|
||||
return 0;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint Toolbar::callbackDocumentation(uint dragStatus) {
|
||||
_mouseInOptions = true;
|
||||
|
||||
switch (dragStatus) {
|
||||
case kDragStatus_NoDrag:
|
||||
case kDragStatus_Pressed:
|
||||
case kDragStatus_Dragging:
|
||||
// Nothing to do, we wait release
|
||||
return 0;
|
||||
case kDragStatus_Finished:
|
||||
// Just clicked
|
||||
if (_engine->displayPlaceDocumentation()) {
|
||||
_parentMustRedraw = true;
|
||||
_shortExit = true;
|
||||
_engine->setMousePos(Common::Point(320, 240)); // Center of screen
|
||||
}
|
||||
return 0;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Toolbar::drawToolbar(const Graphics::Surface *original) {
|
||||
if (_position > 60) {
|
||||
_position = 60;
|
||||
}
|
||||
|
||||
if (_position != 0) {
|
||||
// Not entirely drawn, we must copy a part of the original image
|
||||
Common::Rect rct(0, 420, 640, 420 + _position);
|
||||
_destSurface.copyRectToSurface(*original, 0, 0, rct);
|
||||
}
|
||||
|
||||
if (_position == 60) {
|
||||
// Entirely hidden, just stop there, we have nothing to draw
|
||||
return;
|
||||
}
|
||||
|
||||
// Not entirely hidden, we must display the transparent background prepared for us
|
||||
Common::Rect rct(0, _position, 640, 60);
|
||||
_destSurface.copyRectToSurface(_bgSurface, 0, _position, rct);
|
||||
|
||||
// Now draw the various zones on the surface
|
||||
for (Common::Array<Zone>::const_iterator it = _zones.begin(); it != _zones.end(); it++) {
|
||||
if (it->hidden) {
|
||||
continue;
|
||||
}
|
||||
|
||||
uint16 spriteId = it->secondary ? it->imageSecondary : it->imageMain;
|
||||
if (spriteId == uint16(-1)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Common::Rect dst = it->rect;
|
||||
dst.translate(0, _position);
|
||||
|
||||
// Clip the rectangle to fit inside the surface
|
||||
dst.clip(Common::Rect(_destSurface.w, _destSurface.h));
|
||||
|
||||
if (dst.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const Graphics::Surface &sprite = _sprites->getSurface(spriteId);
|
||||
_destSurface.transBlitFrom(sprite, Common::Rect(dst.width(), dst.height()), dst,
|
||||
_sprites->getKeyColor(spriteId));
|
||||
}
|
||||
|
||||
// And now draw the object description if needed
|
||||
if (_inventoryEnabled && _inventoryHovered != uint(-1)) {
|
||||
Object *obj = (*_inventory)[_inventoryHovered];
|
||||
|
||||
uint zoneId = _inventoryHovered - _inventoryOffset;
|
||||
if (zoneId >= 8) {
|
||||
// The object is hidden: huh?
|
||||
return;
|
||||
}
|
||||
|
||||
_fontManager->setSurface(&_destSurface);
|
||||
_fontManager->setForeColor(243);
|
||||
_fontManager->setCurrentFont(5);
|
||||
_fontManager->setTransparentBackground(true);
|
||||
const Common::String &objName = (*_messages)[obj->idOBJ()];
|
||||
uint x = 195 - _fontManager->getStrWidth(objName);
|
||||
uint startX = _zones[zoneId].rect.left + kTextOffset;
|
||||
_fontManager->displayStr(x, 38 + _position, objName);
|
||||
_destSurface.hLine(x, 54 + _position, startX - 1, 243); // minus 1 because hLine draws inclusive
|
||||
_destSurface.vLine(startX, 42 + _position, 54 + _position, 243);
|
||||
}
|
||||
}
|
||||
|
||||
bool Toolbar::displayToolbar(const Graphics::Surface *original) {
|
||||
/**
|
||||
* In game there are 2 functions to handle toolbar: one in warp and one in fixed images
|
||||
* This one is the warp one and fixed images have a more asynchronous one during pop-up/down phases
|
||||
* Let's make it simple for now
|
||||
*/
|
||||
|
||||
// WORKAROUND: Set cursor here to be more consistent: it's thumb cursor just before showing until just after showed
|
||||
_engine->setCursor(181);
|
||||
|
||||
_parentMustRedraw = false;
|
||||
_shortExit = false;
|
||||
|
||||
// Prepare the background of the toolbar by making it translucent
|
||||
// Get the lowest part of the image
|
||||
const Graphics::Surface subset = original->getSubArea(Common::Rect(0, original->h - _bgSurface.h,
|
||||
_bgSurface.w, original->h));
|
||||
_engine->makeTranslucent(_bgSurface, subset);
|
||||
|
||||
// WORKAROUND: Reset the inventory status at init to let sprites highlighted until toolbar is hidden
|
||||
_inventorySelected = uint(-1);
|
||||
_inventoryHovered = uint(-1);
|
||||
_zones[12].secondary = true;
|
||||
|
||||
updateZones();
|
||||
|
||||
for (_position = 60; _position > 0; _position--) {
|
||||
// Make the toolbar go up
|
||||
drawToolbar(original);
|
||||
g_system->copyRectToScreen(_destSurface.getPixels(), _destSurface.pitch, 0,
|
||||
original->h - _destSurface.h, _destSurface.w, _destSurface.h);
|
||||
g_system->updateScreen();
|
||||
|
||||
// Slow down animation
|
||||
g_system->delayMillis(10);
|
||||
|
||||
_engine->pollEvents();
|
||||
if (_engine->shouldAbort()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Flush events
|
||||
_engine->clearKeys();
|
||||
_engine->waitMouseRelease();
|
||||
|
||||
handleToolbarEvents(original);
|
||||
if (_engine->shouldAbort()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_shortExit) {
|
||||
return _parentMustRedraw;
|
||||
}
|
||||
|
||||
for (_position = 0; _position <= 60; _position++) {
|
||||
// Make the toolbar go up
|
||||
drawToolbar(original);
|
||||
g_system->copyRectToScreen(_destSurface.getPixels(), _destSurface.pitch, 0,
|
||||
original->h - _destSurface.h, _destSurface.w, _destSurface.h);
|
||||
g_system->updateScreen();
|
||||
|
||||
// Slow down animation
|
||||
g_system->delayMillis(10);
|
||||
|
||||
_engine->pollEvents();
|
||||
if (_engine->shouldAbort()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return _parentMustRedraw;
|
||||
}
|
||||
|
||||
void Toolbar::handleToolbarEvents(const Graphics::Surface *original) {
|
||||
bool mouseInsideToolbar;
|
||||
bool exitToolbar = false;
|
||||
bool redrawToolbar;
|
||||
|
||||
// Don't have anything hovered for now
|
||||
_inventoryHovered = uint(-1);
|
||||
_inventorySelected = uint(-1);
|
||||
_inventory->setSelectedObject(nullptr);
|
||||
_backupSelectedObject = nullptr;
|
||||
|
||||
// Refresh zones because we erased selected object
|
||||
updateZones();
|
||||
|
||||
// No need of original surface because the toolbar is fully displayed
|
||||
drawToolbar(original);
|
||||
|
||||
g_system->copyRectToScreen(_destSurface.getPixels(), _destSurface.pitch, 0,
|
||||
original->h - _destSurface.h, _destSurface.w, _destSurface.h);
|
||||
g_system->updateScreen();
|
||||
|
||||
_engine->setCursor(181);
|
||||
|
||||
mouseInsideToolbar = (_engine->getMousePos().y > 388);
|
||||
|
||||
while (!exitToolbar) {
|
||||
_mouseInOptions = false;
|
||||
_mouseInViewObject = false;
|
||||
|
||||
_engine->pollEvents();
|
||||
if (_engine->shouldAbort()) {
|
||||
exitToolbar = true;
|
||||
break;
|
||||
}
|
||||
|
||||
redrawToolbar = false;
|
||||
if (_engine->checkKeysPressed(2, Common::KEYCODE_ESCAPE, Common::KEYCODE_SPACE) ||
|
||||
_engine->getCurrentMouseButton() == 2) {
|
||||
_engine->waitMouseRelease();
|
||||
exitToolbar = true;
|
||||
break;
|
||||
}
|
||||
|
||||
Common::Point mousePosInToolbar = _engine->getMousePos();
|
||||
mousePosInToolbar -= Common::Point(0, 420);
|
||||
|
||||
if (captureEvent(mousePosInToolbar, _engine->getDragStatus())) {
|
||||
// Something has changed with the zones handling, update zones
|
||||
updateZones();
|
||||
redrawToolbar = true;
|
||||
} else if (_engine->getDragStatus() == kDragStatus_Pressed) {
|
||||
// A click happened and wasn't handled, deselect object
|
||||
_inventorySelected = uint(-1);
|
||||
_inventory->setSelectedObject(nullptr);
|
||||
_engine->setCursor(181);
|
||||
// Reset view object
|
||||
_zones[12].secondary = true;
|
||||
updateZones();
|
||||
redrawToolbar = true;
|
||||
}
|
||||
|
||||
if (!mouseInsideToolbar) {
|
||||
mouseInsideToolbar = (_engine->getMousePos().y > 388);
|
||||
} else if (_engine->getMousePos().y <= 388) {
|
||||
// mouseInsideToolbar is true and the mouse is outside the toolbar
|
||||
exitToolbar = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (_engine->getCurrentMouseButton() == 1) {
|
||||
// When the mouse button is down, nothing is selected
|
||||
// It's selected on release
|
||||
_inventory->setSelectedObject(nullptr);
|
||||
}
|
||||
|
||||
if (_backupSelectedObject != nullptr && !(_mouseInOptions || _mouseInViewObject) &&
|
||||
!_engine->getCurrentMouseButton()) {
|
||||
_inventory->setSelectedObject(_backupSelectedObject);
|
||||
_engine->setCursor(_backupSelectedObject->idSl());
|
||||
_backupSelectedObject = nullptr;
|
||||
}
|
||||
|
||||
// Hover the inventory objects
|
||||
if (_inventory->selectedObject() == nullptr /* || _inventoryButtonDragging */) {
|
||||
// The 2nd above condition is maybe useless because when the mouse button is down the selected object is always null
|
||||
bool shouldHover = false;
|
||||
Common::Array<Zone>::const_iterator zoneIt = hitTestZones(mousePosInToolbar);
|
||||
uint zoneId = zoneIt - _zones.begin();
|
||||
uint inventoryId = zoneId + _inventoryOffset;
|
||||
if (zoneId < 8 && inventoryId < _inventory->size() && (*_inventory)[inventoryId] != nullptr) {
|
||||
// It's the inventory
|
||||
shouldHover = true;
|
||||
if (_inventoryHovered != inventoryId && (*_inventory)[inventoryId]->valid()) {
|
||||
// It's not the one currently hovered and it's a valid object
|
||||
_inventoryHovered = inventoryId;
|
||||
redrawToolbar = true;
|
||||
}
|
||||
}
|
||||
if (!shouldHover && _inventoryHovered != uint(-1) && !_mouseInViewObject) {
|
||||
// Remove hovering
|
||||
_inventoryHovered = uint(-1);
|
||||
_inventorySelected = uint(-1);
|
||||
updateZones();
|
||||
if (!_inventory->selectedObject()) {
|
||||
// Reset back the cursor if nothing is selected
|
||||
_engine->setCursor(181);
|
||||
}
|
||||
// Remove view
|
||||
_zones[12].secondary = true;
|
||||
redrawToolbar = true;
|
||||
}
|
||||
_inventoryButtonDragging = false;
|
||||
}
|
||||
|
||||
if (_parentMustRedraw) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (redrawToolbar) {
|
||||
drawToolbar(original);
|
||||
g_system->copyRectToScreen(_destSurface.getPixels(), _destSurface.pitch, 0,
|
||||
original->h - _destSurface.h, _destSurface.w, _destSurface.h);
|
||||
}
|
||||
|
||||
g_system->updateScreen();
|
||||
g_system->delayMillis(10);
|
||||
}
|
||||
|
||||
// Hide description when finished and selected object
|
||||
// WORKAROUND: moved to the start to keep the selected object hilighted until the toolbar disappearance
|
||||
}
|
||||
|
||||
} // End of namespace Versailles
|
||||
} // End of namespace CryOmni3D
|
||||
117
engines/cryomni3d/versailles/toolbar.h
Normal file
117
engines/cryomni3d/versailles/toolbar.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 CRYOMNI3D_VERSAILLES_TOOLBAR_H
|
||||
#define CRYOMNI3D_VERSAILLES_TOOLBAR_H
|
||||
|
||||
#include "common/array.h"
|
||||
#include "common/rect.h"
|
||||
#include "graphics/managed_surface.h"
|
||||
#include "graphics/surface.h"
|
||||
|
||||
#include "cryomni3d/font_manager.h"
|
||||
#include "cryomni3d/objects.h"
|
||||
#include "cryomni3d/sprites.h"
|
||||
|
||||
namespace CryOmni3D {
|
||||
class CryOmni3DEngine;
|
||||
|
||||
namespace Versailles {
|
||||
|
||||
|
||||
class Toolbar {
|
||||
public:
|
||||
Toolbar() : _sprites(nullptr), _fontManager(nullptr), _inventory(nullptr),
|
||||
_messages(nullptr), _engine(nullptr), _inventoryEnabled(true), _inventoryMaxOffset(0),
|
||||
_inventoryOffset(0), _inventoryHovered(uint(-1)), _inventorySelected(uint(-1)), _backupSelectedObject(nullptr),
|
||||
_mouseInOptions(false), _mouseInViewObject(false), _inventoryButtonDragging(false), _parentMustRedraw(false),
|
||||
_shortExit(false), _position(60) { }
|
||||
~Toolbar();
|
||||
|
||||
void init(const Sprites *sprites, FontManager *fontManager,
|
||||
const Common::Array<Common::String> *messages, Inventory *inventory, CryOmni3DEngine *engine);
|
||||
|
||||
Graphics::Surface &getBackgroundSurface() { return _bgSurface; }
|
||||
bool displayToolbar(const Graphics::Surface *original);
|
||||
void inventoryChanged(uint newPosition);
|
||||
uint inventoryOffset() const { return _inventoryOffset; }
|
||||
void setInventoryOffset(uint offset) { _inventoryOffset = offset; }
|
||||
void setInventoryEnabled(bool enabled) { _inventoryEnabled = enabled; }
|
||||
|
||||
private:
|
||||
typedef uint(Toolbar::*ZoneCallback)(uint dragStatus);
|
||||
struct Zone {
|
||||
Common::Rect rect;
|
||||
uint16 imageMain;
|
||||
uint16 imageSecondary;
|
||||
ZoneCallback callback;
|
||||
bool secondary;
|
||||
bool hidden;
|
||||
};
|
||||
Common::Array<Zone> _zones;
|
||||
const Sprites *_sprites;
|
||||
FontManager *_fontManager;
|
||||
const Common::Array<Common::String> *_messages;
|
||||
Inventory *_inventory;
|
||||
CryOmni3DEngine *_engine;
|
||||
|
||||
static const uint kTextOffset = 13;
|
||||
|
||||
void addZone(uint16 cursorMainId, uint16 cursorSecondaryId, Common::Point position,
|
||||
ZoneCallback callback);
|
||||
void updateZones();
|
||||
Common::Array<Zone>::const_iterator hitTestZones(const Common::Point &mousePos) const;
|
||||
uint captureEvent(const Common::Point &mousePos, uint dragStatus);
|
||||
void drawToolbar(const Graphics::Surface *original);
|
||||
void handleToolbarEvents(const Graphics::Surface *original);
|
||||
|
||||
bool _inventoryEnabled;
|
||||
uint _inventoryMaxOffset;
|
||||
uint _inventoryOffset;
|
||||
uint _inventoryHovered;
|
||||
uint _inventorySelected;
|
||||
|
||||
Object *_backupSelectedObject;
|
||||
bool _mouseInOptions;
|
||||
bool _mouseInViewObject;
|
||||
bool _inventoryButtonDragging;
|
||||
|
||||
bool _parentMustRedraw;
|
||||
bool _shortExit;
|
||||
uint _position;
|
||||
|
||||
Graphics::Surface _bgSurface;
|
||||
Graphics::ManagedSurface _destSurface;
|
||||
|
||||
template<uint N>
|
||||
uint callbackInventory(uint dragStatus) { return callbackInventory(N, dragStatus); }
|
||||
uint callbackInventory(uint invId, uint dragStatus);
|
||||
uint callbackInventoryPrev(uint dragStatus);
|
||||
uint callbackInventoryNext(uint dragStatus);
|
||||
uint callbackViewObject(uint dragStatus);
|
||||
uint callbackOptions(uint dragStatus);
|
||||
uint callbackDocumentation(uint dragStatus);
|
||||
};
|
||||
|
||||
} // End of namespace Versailles
|
||||
} // End of namespace CryOmni3D
|
||||
|
||||
#endif
|
||||
217
engines/cryomni3d/wam_parser.cpp
Normal file
217
engines/cryomni3d/wam_parser.cpp
Normal file
@@ -0,0 +1,217 @@
|
||||
/* 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 "cryomni3d/wam_parser.h"
|
||||
#include "cryomni3d/omni3d.h"
|
||||
|
||||
namespace CryOmni3D {
|
||||
|
||||
void WAMParser::loadStream(Common::ReadStream &stream) {
|
||||
char str[16];
|
||||
|
||||
_places.clear();
|
||||
|
||||
// These are unused and unknown values
|
||||
(void) stream.readByte();
|
||||
(void) stream.readByte();
|
||||
(void) stream.read(str, 16);
|
||||
(void) stream.readUint32LE();
|
||||
|
||||
uint nPlaces = stream.readByte();
|
||||
//debug("nPlaces = %u", nPlaces);
|
||||
for (uint i = 0; i < nPlaces; i++) {
|
||||
Place place;
|
||||
uint nWarps = stream.readByte();
|
||||
//debug("nWarps = %u", nWarps);
|
||||
for (uint k = 0; k < 8; k++) {
|
||||
stream.read(str, 16);
|
||||
//debug("Warp: %.16s", str);
|
||||
if (nWarps > 0) {
|
||||
place.warps.push_back(str);
|
||||
nWarps--;
|
||||
}
|
||||
}
|
||||
place.placeId = stream.readUint32LE();
|
||||
// Normally placeId should be unique but it's not always the case
|
||||
// In original game the last place is considered but we try to be efficient and stop at the first place in findPlaceById
|
||||
// Let's be a little less efficient at startup by removing duplicates
|
||||
Place *oldPlace = findPlaceById_(place.placeId);
|
||||
if (oldPlace) {
|
||||
debug("Found duplicate place %u at %u, removing it", place.placeId,
|
||||
(uint)(oldPlace - _places.begin()));
|
||||
_places.erase(oldPlace);
|
||||
}
|
||||
//debug("nPlaceId = %u", place.placeId);
|
||||
(void) stream.readUint32LE();
|
||||
uint nTransitions = stream.readByte();
|
||||
//debug("nTransitions = %u", nTransitions);
|
||||
uint nZones = stream.readByte();
|
||||
//debug("nZones = %u", nZones);
|
||||
for (uint j = 0; j < nTransitions; j++) {
|
||||
Transition trans;
|
||||
(void) stream.readUint32LE();
|
||||
uint nAnimations = stream.readByte();
|
||||
for (uint k = 0; k < 8; k++) {
|
||||
stream.read(str, 16);
|
||||
if (nAnimations > 0) {
|
||||
trans.animations.push_back(str);
|
||||
nAnimations--;
|
||||
}
|
||||
}
|
||||
(void) stream.readUint32LE();
|
||||
trans.dstId = stream.readUint32LE();
|
||||
// Unused byte
|
||||
(void) stream.readByte();
|
||||
trans.srcAlpha = stream.readDoubleLE();
|
||||
trans.srcBeta = stream.readDoubleLE();
|
||||
trans.dstAlpha = stream.readDoubleLE();
|
||||
trans.dstBeta = stream.readDoubleLE();
|
||||
place.transitions.push_back(trans);
|
||||
}
|
||||
for (uint j = 0; j < nZones; j++) {
|
||||
Zone zone;
|
||||
zone.zoneId = stream.readSint32LE();
|
||||
zone.rct.left = stream.readSint32LE();
|
||||
zone.rct.top = stream.readSint32LE();
|
||||
zone.rct.setWidth(stream.readSint32LE());
|
||||
zone.rct.setHeight(stream.readSint32LE());
|
||||
zone.action = stream.readSint32LE();
|
||||
place.zones.push_back(zone);
|
||||
}
|
||||
_places.push_back(place);
|
||||
}
|
||||
}
|
||||
|
||||
const Place *WAMParser::findPlaceById(uint placeId) const {
|
||||
for (Common::Array<Place>::const_iterator it = _places.begin(); it != _places.end(); it++) {
|
||||
if (it->placeId == placeId) {
|
||||
return it;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Place *WAMParser::findPlaceById_(uint placeId) {
|
||||
for (Common::Array<Place>::iterator it = _places.begin(); it != _places.end(); it++) {
|
||||
if (it->placeId == placeId) {
|
||||
return it;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void Place::setupWarpConstraints(Omni3DManager &omni3d) const {
|
||||
int16 iAlphaMin = -32768, iAlphaMax = 32767;
|
||||
bool alphaConstraint = false;
|
||||
|
||||
omni3d.clearConstraints();
|
||||
for (Common::Array<Zone>::const_iterator it = zones.begin(); it != zones.end(); it++) {
|
||||
if (it->action == 100000) {
|
||||
int16 aMin = it->rct.left;
|
||||
if (aMin < 0) {
|
||||
aMin += 2048;
|
||||
}
|
||||
int16 aMax = aMin + it->rct.width();
|
||||
if (aMax > 2048) {
|
||||
aMax -= 2048;
|
||||
}
|
||||
// debug("x1=%d x2=%d", aMin, aMax);
|
||||
if (aMax < aMin) {
|
||||
int16 tmp = aMax;
|
||||
aMax = aMin;
|
||||
aMin = tmp;
|
||||
}
|
||||
if (alphaConstraint) {
|
||||
if (aMin < iAlphaMax && aMax > iAlphaMax) {
|
||||
iAlphaMax = aMax;
|
||||
}
|
||||
if (aMin < iAlphaMin && aMax > iAlphaMin) {
|
||||
iAlphaMin = aMin;
|
||||
}
|
||||
} else {
|
||||
iAlphaMin = aMin;
|
||||
iAlphaMax = aMax;
|
||||
alphaConstraint = true;
|
||||
}
|
||||
} else if (it->action == 200000) {
|
||||
double betaMin = ((int)it->rct.bottom - (768 / 2)) / 768. * M_PI;
|
||||
omni3d.setBetaMinConstraint(betaMin);
|
||||
} else if (it->action == 300000) {
|
||||
double betaMax = ((int)it->rct.top - (768 / 2)) / 768. * M_PI;
|
||||
omni3d.setBetaMaxConstraint(betaMax);
|
||||
}
|
||||
}
|
||||
if (alphaConstraint) {
|
||||
double alphaMin = (1 - iAlphaMin / 2048.) * M_PI * 2.;
|
||||
alphaMin += 75. / 180. * M_PI_2;
|
||||
if (alphaMin < 0.) {
|
||||
alphaMin += M_PI * 2.;
|
||||
} else if (alphaMin > M_PI * 2.) {
|
||||
alphaMin -= M_PI * 2.;
|
||||
}
|
||||
double alphaMax = (1 - iAlphaMax / 2048.) * M_PI * 2.;
|
||||
alphaMax -= 75. / 180. * M_PI_2;
|
||||
if (alphaMax < 0.) {
|
||||
alphaMax += M_PI * 2.;
|
||||
} else if (alphaMax > M_PI * 2.) {
|
||||
alphaMax -= M_PI * 2.;
|
||||
}
|
||||
omni3d.setAlphaConstraints(alphaMin, alphaMax);
|
||||
}
|
||||
}
|
||||
|
||||
uint Place::hitTest(const Common::Point &point) const {
|
||||
for (Common::Array<Zone>::const_iterator it = zones.begin(); it != zones.end(); it++) {
|
||||
if (it->action) {
|
||||
if (it->rct.contains(point)) {
|
||||
return it->action;
|
||||
}
|
||||
if (it->rct.left < 0) {
|
||||
Common::Rect rct = it->rct;
|
||||
rct.translate(2048, 0);
|
||||
if (rct.contains(point)) {
|
||||
return it->action;
|
||||
}
|
||||
} else if (it->rct.right > 2048) {
|
||||
Common::Rect rct = it->rct;
|
||||
rct.translate(-2048, 0);
|
||||
if (rct.contains(point)) {
|
||||
return it->action;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const Transition *Place::findTransition(uint nextPlaceId) const {
|
||||
for (Common::Array<Transition>::const_iterator it = transitions.begin(); it != transitions.end();
|
||||
it++) {
|
||||
if (it->dstId == nextPlaceId) {
|
||||
return it;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // End of namespace CryOmni3D
|
||||
80
engines/cryomni3d/wam_parser.h
Normal file
80
engines/cryomni3d/wam_parser.h
Normal file
@@ -0,0 +1,80 @@
|
||||
/* 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 CRYOMNI3D_WAM_PARSER_H
|
||||
#define CRYOMNI3D_WAM_PARSER_H
|
||||
|
||||
#include "common/array.h"
|
||||
#include "common/rect.h"
|
||||
#include "common/str.h"
|
||||
|
||||
namespace Common {
|
||||
class ReadStream;
|
||||
}
|
||||
|
||||
namespace CryOmni3D {
|
||||
|
||||
class Omni3DManager;
|
||||
|
||||
struct Zone {
|
||||
uint zoneId;
|
||||
uint action;
|
||||
Common::Rect rct;
|
||||
};
|
||||
|
||||
struct Transition {
|
||||
uint dstId;
|
||||
double srcAlpha;
|
||||
double srcBeta;
|
||||
double dstAlpha;
|
||||
double dstBeta;
|
||||
Common::Array<Common::String> animations;
|
||||
uint getNumAnimations() const { return animations.size(); }
|
||||
};
|
||||
|
||||
struct Place {
|
||||
uint placeId;
|
||||
Common::Array<Common::String> warps;
|
||||
Common::Array<Transition> transitions;
|
||||
Common::Array<Zone> zones;
|
||||
|
||||
uint getNumStates() const { return warps.size(); }
|
||||
uint getNumTransitions() const { return transitions.size(); }
|
||||
void setupWarpConstraints(Omni3DManager &omni3d) const;
|
||||
uint hitTest(const Common::Point &point) const;
|
||||
const Transition *findTransition(uint nextPlaceId) const;
|
||||
};
|
||||
|
||||
class WAMParser {
|
||||
public:
|
||||
void loadStream(Common::ReadStream &stream);
|
||||
const Place *findPlaceById(uint placeId) const;
|
||||
|
||||
private:
|
||||
// For duplicate finding
|
||||
// We use a different name because else it gets chosen before the const one and fails because it's private
|
||||
Place *findPlaceById_(uint placeId);
|
||||
Common::Array<Place> _places;
|
||||
};
|
||||
|
||||
} // End of namespace CryOmni3D
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user